git-svn-id: http://googleappengine.googlecode.com/svn/trunk/python@241 80f5ef21-4148-0410-bacc-cfb02402ada8
diff --git a/RELEASE_NOTES b/RELEASE_NOTES
index 9cd82ad..38fa05e 100644
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -3,6 +3,57 @@
 
 App Engine Python SDK - Release Notes
 
+Version 1.6.3
+===============================
+- In the Admin Console, you can use new the Traffic Splitting feature to send a
+  certain percentage of traffic to a non-default application version. The
+  traffic is split by either cookie or IP address.
+- Emails that are sent from Google Apps domains email addresses where the domain
+  has been set up to use DKIM will be signed: when an email was from a request
+  that originated on that app's domain or any time the email was sent from
+  an app adminstrator, including when that email is sent from a cron job or task
+  queue request.
+- In the Admin Console, you can now choose how much and how long you'd like to
+  store logs.  All apps get 1G for free and eventually will be able to pay for
+  more, while the amount can be increased this release we won't start charging
+  for the additional capacity until the next release at the earliest.
+- The instances screen in the Admin Console now has a button to shut down
+  a specific instance.
+- Each application log has a link to the instance that served the request. If
+  the instance is no longer serving requests, a message will be displayed.
+- The TaskQueue API now supports the ability to tag a Pull Queue task. You may
+  then lease tasks by tag. This feature is experimental.
+- Using Google Apps wildcard domain mappings, you can access alternate
+  versions of your app via a custom domain.
+- Push and Pull Queues are now listed separately in the SDK development console.
+- Developer documentation for the experimental NDB API, the replacement for
+  db.py, is now available.
+- Appcfg now supports OAuth2.
+- webapp 2.5.1 is now available in the Python 2.7 runtime.
+- Django 1.3 is now available in the Python 2.7 runtime.
+- GQL Query now supports custom type casting for list elements for "IN" filters.
+- Fixed an issue where StringProperty's validate() didn't check the 500 byte
+  limit.
+    http://code.google.com/p/googleappengine/issues/detail?id=4030
+- Fixed an issue where the datastore admin didn't work with Federated Login.
+    http://code.google.com/p/googleappengine/issues/detail?id=4111
+- Fixed an issue in the SDK where failing to call _RemoveTxn in the
+  datastore_stub_util caused a memory leak:
+    http://code.google.com/p/googleappengine/issues/detail?id=6157
+- Code that inherits from the deferred library's TaskHandler can now define
+  custom handling of exceptions.
+    http://code.google.com/p/googleappengine/issues/detail?id=6478
+- Fixed an issue where logging in the SDK was broken in Windows 7 using
+  Python 2.7.2.
+    http://code.google.com/p/googleappengine/issues/detail?id=6756
+- Fixed an issue in the SDK where the Conversion API call limited was limited
+  to 1 MB when the production limit is 2 MB.
+    http://code.google.com/p/googleappengine/issues/detail?id=6794
+- Fixed an issue so that a deferred task retries like a push queue task when
+  using the SingularTaskFailure exception:
+    http://code.google.com/p/googleappengine/issues/detail?id=6412
+
+
 Version 1.6.2
 ===============================
 - The Admin Console Datastore Admin has added experimental backup and restore
diff --git a/VERSION b/VERSION
index 2296397..5cd702c 100644
--- a/VERSION
+++ b/VERSION
@@ -1,3 +1,3 @@
-release: "1.6.2"
-timestamp: 1325614538
+release: "1.6.3"
+timestamp: 1328043246
 api_versions: ['1']
diff --git a/api_server.py b/api_server.py
new file mode 100755
index 0000000..0276d25
--- /dev/null
+++ b/api_server.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python
+#
+# Copyright 2007 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+
+
+"""Convenience wrapper for starting an appengine tool."""
+
+
+import os
+import re
+import sys
+
+
+if not hasattr(sys, 'version_info'):
+  sys.stderr.write('Very old versions of Python are not supported. Please '
+                   'use version 2.5 or greater.\n')
+  sys.exit(1)
+version_tuple = tuple(sys.version_info[:2])
+if version_tuple < (2, 5):
+  sys.stderr.write('Error: Python %d.%d is not supported. Please use '
+                   'version 2.5 or greater.\n' % version_tuple)
+  sys.exit(1)
+
+DIR_PATH = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
+SCRIPT_DIR = os.path.join(DIR_PATH, 'google', 'appengine', 'tools')
+GOOGLE_SQL_DIR = os.path.join(
+    DIR_PATH, 'google', 'storage', 'speckle', 'python', 'tool')
+
+
+
+EXTRA_PATHS = [
+  DIR_PATH,
+  os.path.join(DIR_PATH, 'lib', 'antlr3'),
+  os.path.join(DIR_PATH, 'lib', 'django_0_96'),
+  os.path.join(DIR_PATH, 'lib', 'fancy_urllib'),
+  os.path.join(DIR_PATH, 'lib', 'ipaddr'),
+  os.path.join(DIR_PATH, 'lib', 'jinja2'),
+  os.path.join(DIR_PATH, 'lib', 'protorpc'),
+  os.path.join(DIR_PATH, 'lib', 'markupsafe'),
+  os.path.join(DIR_PATH, 'lib', 'webob'),
+  os.path.join(DIR_PATH, 'lib', 'webapp2'),
+  os.path.join(DIR_PATH, 'lib', 'yaml', 'lib'),
+  os.path.join(DIR_PATH, 'lib', 'simplejson'),
+  os.path.join(DIR_PATH, 'lib', 'google.appengine._internal.graphy'),
+]
+
+API_SERVER_EXTRA_PATHS = [
+  os.path.join(DIR_PATH, 'lib', 'argparse'),
+]
+API_SERVER_EXTRA_PATH_SCRIPTS = 'api_server'
+
+
+OAUTH_CLIENT_EXTRA_PATHS = [
+  os.path.join(DIR_PATH, 'lib', 'google-api-python-client'),
+  os.path.join(DIR_PATH, 'lib', 'httplib2'),
+  os.path.join(DIR_PATH, 'lib', 'python-gflags'),
+]
+
+OAUTH_CLIENT_EXTRA_PATH_SCRIPTS = '(appcfg|bulkloader)'
+
+
+GOOGLE_SQL_EXTRA_PATHS = OAUTH_CLIENT_EXTRA_PATHS + [
+  os.path.join(DIR_PATH, 'lib', 'enum'),
+  os.path.join(DIR_PATH, 'lib', 'grizzled'),
+  os.path.join(DIR_PATH, 'lib', 'oauth2'),
+  os.path.join(DIR_PATH, 'lib', 'prettytable'),
+  os.path.join(DIR_PATH, 'lib', 'sqlcmd'),
+]
+
+GOOGLE_SQL_EXTRA_PATH_SCRIPTS = 'google_sql'
+
+
+
+SCRIPT_EXCEPTIONS = {
+  "dev_appserver.py" : "dev_appserver_main.py"
+}
+
+SCRIPT_DIR_EXCEPTIONS = {
+  'google_sql.py': GOOGLE_SQL_DIR,
+}
+
+
+def fix_sys_path(extra_extra_paths=()):
+  """Fix the sys.path to include our extra paths."""
+  extra_paths = EXTRA_PATHS[:]
+  extra_paths.extend(extra_extra_paths)
+  sys.path = extra_paths + sys.path
+
+
+def run_file(file_path, globals_, script_dir=SCRIPT_DIR):
+  """Execute the file at the specified path with the passed-in globals."""
+  script_name = os.path.basename(file_path)
+
+  if re.match(OAUTH_CLIENT_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = OAUTH_CLIENT_EXTRA_PATHS
+  elif re.match(GOOGLE_SQL_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = GOOGLE_SQL_EXTRA_PATHS
+  elif re.match(API_SERVER_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = API_SERVER_EXTRA_PATHS
+  else:
+    extra_extra_paths = []
+  fix_sys_path(extra_extra_paths)
+
+  script_name = SCRIPT_EXCEPTIONS.get(script_name, script_name)
+  script_dir = SCRIPT_DIR_EXCEPTIONS.get(script_name, script_dir)
+  script_path = os.path.join(script_dir, script_name)
+  execfile(script_path, globals_)
+
+
+if __name__ == '__main__':
+  run_file(__file__, globals())
diff --git a/appcfg.py b/appcfg.py
index 88994d1..0276d25 100755
--- a/appcfg.py
+++ b/appcfg.py
@@ -21,6 +21,7 @@
 
 
 import os
+import re
 import sys
 
 
@@ -57,18 +58,32 @@
   os.path.join(DIR_PATH, 'lib', 'google.appengine._internal.graphy'),
 ]
 
+API_SERVER_EXTRA_PATHS = [
+  os.path.join(DIR_PATH, 'lib', 'argparse'),
+]
+API_SERVER_EXTRA_PATH_SCRIPTS = 'api_server'
 
-GOOGLE_SQL_EXTRA_PATHS = [
-  os.path.join(DIR_PATH, 'lib', 'enum'),
+
+OAUTH_CLIENT_EXTRA_PATHS = [
   os.path.join(DIR_PATH, 'lib', 'google-api-python-client'),
-  os.path.join(DIR_PATH, 'lib', 'grizzled'),
   os.path.join(DIR_PATH, 'lib', 'httplib2'),
+  os.path.join(DIR_PATH, 'lib', 'python-gflags'),
+]
+
+OAUTH_CLIENT_EXTRA_PATH_SCRIPTS = '(appcfg|bulkloader)'
+
+
+GOOGLE_SQL_EXTRA_PATHS = OAUTH_CLIENT_EXTRA_PATHS + [
+  os.path.join(DIR_PATH, 'lib', 'enum'),
+  os.path.join(DIR_PATH, 'lib', 'grizzled'),
   os.path.join(DIR_PATH, 'lib', 'oauth2'),
   os.path.join(DIR_PATH, 'lib', 'prettytable'),
-  os.path.join(DIR_PATH, 'lib', 'python-gflags'),
   os.path.join(DIR_PATH, 'lib', 'sqlcmd'),
 ]
 
+GOOGLE_SQL_EXTRA_PATH_SCRIPTS = 'google_sql'
+
+
 
 SCRIPT_EXCEPTIONS = {
   "dev_appserver.py" : "dev_appserver_main.py"
@@ -79,18 +94,27 @@
 }
 
 
-def fix_sys_path(include_google_sql_libs=False):
+def fix_sys_path(extra_extra_paths=()):
   """Fix the sys.path to include our extra paths."""
   extra_paths = EXTRA_PATHS[:]
-  if include_google_sql_libs:
-    extra_paths.extend(GOOGLE_SQL_EXTRA_PATHS)
+  extra_paths.extend(extra_extra_paths)
   sys.path = extra_paths + sys.path
 
 
 def run_file(file_path, globals_, script_dir=SCRIPT_DIR):
   """Execute the file at the specified path with the passed-in globals."""
   script_name = os.path.basename(file_path)
-  fix_sys_path('google_sql' in script_name)
+
+  if re.match(OAUTH_CLIENT_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = OAUTH_CLIENT_EXTRA_PATHS
+  elif re.match(GOOGLE_SQL_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = GOOGLE_SQL_EXTRA_PATHS
+  elif re.match(API_SERVER_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = API_SERVER_EXTRA_PATHS
+  else:
+    extra_extra_paths = []
+  fix_sys_path(extra_extra_paths)
+
   script_name = SCRIPT_EXCEPTIONS.get(script_name, script_name)
   script_dir = SCRIPT_DIR_EXCEPTIONS.get(script_name, script_dir)
   script_path = os.path.join(script_dir, script_name)
diff --git a/bulkload_client.py b/bulkload_client.py
index 88994d1..0276d25 100755
--- a/bulkload_client.py
+++ b/bulkload_client.py
@@ -21,6 +21,7 @@
 
 
 import os
+import re
 import sys
 
 
@@ -57,18 +58,32 @@
   os.path.join(DIR_PATH, 'lib', 'google.appengine._internal.graphy'),
 ]
 
+API_SERVER_EXTRA_PATHS = [
+  os.path.join(DIR_PATH, 'lib', 'argparse'),
+]
+API_SERVER_EXTRA_PATH_SCRIPTS = 'api_server'
 
-GOOGLE_SQL_EXTRA_PATHS = [
-  os.path.join(DIR_PATH, 'lib', 'enum'),
+
+OAUTH_CLIENT_EXTRA_PATHS = [
   os.path.join(DIR_PATH, 'lib', 'google-api-python-client'),
-  os.path.join(DIR_PATH, 'lib', 'grizzled'),
   os.path.join(DIR_PATH, 'lib', 'httplib2'),
+  os.path.join(DIR_PATH, 'lib', 'python-gflags'),
+]
+
+OAUTH_CLIENT_EXTRA_PATH_SCRIPTS = '(appcfg|bulkloader)'
+
+
+GOOGLE_SQL_EXTRA_PATHS = OAUTH_CLIENT_EXTRA_PATHS + [
+  os.path.join(DIR_PATH, 'lib', 'enum'),
+  os.path.join(DIR_PATH, 'lib', 'grizzled'),
   os.path.join(DIR_PATH, 'lib', 'oauth2'),
   os.path.join(DIR_PATH, 'lib', 'prettytable'),
-  os.path.join(DIR_PATH, 'lib', 'python-gflags'),
   os.path.join(DIR_PATH, 'lib', 'sqlcmd'),
 ]
 
+GOOGLE_SQL_EXTRA_PATH_SCRIPTS = 'google_sql'
+
+
 
 SCRIPT_EXCEPTIONS = {
   "dev_appserver.py" : "dev_appserver_main.py"
@@ -79,18 +94,27 @@
 }
 
 
-def fix_sys_path(include_google_sql_libs=False):
+def fix_sys_path(extra_extra_paths=()):
   """Fix the sys.path to include our extra paths."""
   extra_paths = EXTRA_PATHS[:]
-  if include_google_sql_libs:
-    extra_paths.extend(GOOGLE_SQL_EXTRA_PATHS)
+  extra_paths.extend(extra_extra_paths)
   sys.path = extra_paths + sys.path
 
 
 def run_file(file_path, globals_, script_dir=SCRIPT_DIR):
   """Execute the file at the specified path with the passed-in globals."""
   script_name = os.path.basename(file_path)
-  fix_sys_path('google_sql' in script_name)
+
+  if re.match(OAUTH_CLIENT_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = OAUTH_CLIENT_EXTRA_PATHS
+  elif re.match(GOOGLE_SQL_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = GOOGLE_SQL_EXTRA_PATHS
+  elif re.match(API_SERVER_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = API_SERVER_EXTRA_PATHS
+  else:
+    extra_extra_paths = []
+  fix_sys_path(extra_extra_paths)
+
   script_name = SCRIPT_EXCEPTIONS.get(script_name, script_name)
   script_dir = SCRIPT_DIR_EXCEPTIONS.get(script_name, script_dir)
   script_path = os.path.join(script_dir, script_name)
diff --git a/bulkloader.py b/bulkloader.py
index 88994d1..0276d25 100755
--- a/bulkloader.py
+++ b/bulkloader.py
@@ -21,6 +21,7 @@
 
 
 import os
+import re
 import sys
 
 
@@ -57,18 +58,32 @@
   os.path.join(DIR_PATH, 'lib', 'google.appengine._internal.graphy'),
 ]
 
+API_SERVER_EXTRA_PATHS = [
+  os.path.join(DIR_PATH, 'lib', 'argparse'),
+]
+API_SERVER_EXTRA_PATH_SCRIPTS = 'api_server'
 
-GOOGLE_SQL_EXTRA_PATHS = [
-  os.path.join(DIR_PATH, 'lib', 'enum'),
+
+OAUTH_CLIENT_EXTRA_PATHS = [
   os.path.join(DIR_PATH, 'lib', 'google-api-python-client'),
-  os.path.join(DIR_PATH, 'lib', 'grizzled'),
   os.path.join(DIR_PATH, 'lib', 'httplib2'),
+  os.path.join(DIR_PATH, 'lib', 'python-gflags'),
+]
+
+OAUTH_CLIENT_EXTRA_PATH_SCRIPTS = '(appcfg|bulkloader)'
+
+
+GOOGLE_SQL_EXTRA_PATHS = OAUTH_CLIENT_EXTRA_PATHS + [
+  os.path.join(DIR_PATH, 'lib', 'enum'),
+  os.path.join(DIR_PATH, 'lib', 'grizzled'),
   os.path.join(DIR_PATH, 'lib', 'oauth2'),
   os.path.join(DIR_PATH, 'lib', 'prettytable'),
-  os.path.join(DIR_PATH, 'lib', 'python-gflags'),
   os.path.join(DIR_PATH, 'lib', 'sqlcmd'),
 ]
 
+GOOGLE_SQL_EXTRA_PATH_SCRIPTS = 'google_sql'
+
+
 
 SCRIPT_EXCEPTIONS = {
   "dev_appserver.py" : "dev_appserver_main.py"
@@ -79,18 +94,27 @@
 }
 
 
-def fix_sys_path(include_google_sql_libs=False):
+def fix_sys_path(extra_extra_paths=()):
   """Fix the sys.path to include our extra paths."""
   extra_paths = EXTRA_PATHS[:]
-  if include_google_sql_libs:
-    extra_paths.extend(GOOGLE_SQL_EXTRA_PATHS)
+  extra_paths.extend(extra_extra_paths)
   sys.path = extra_paths + sys.path
 
 
 def run_file(file_path, globals_, script_dir=SCRIPT_DIR):
   """Execute the file at the specified path with the passed-in globals."""
   script_name = os.path.basename(file_path)
-  fix_sys_path('google_sql' in script_name)
+
+  if re.match(OAUTH_CLIENT_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = OAUTH_CLIENT_EXTRA_PATHS
+  elif re.match(GOOGLE_SQL_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = GOOGLE_SQL_EXTRA_PATHS
+  elif re.match(API_SERVER_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = API_SERVER_EXTRA_PATHS
+  else:
+    extra_extra_paths = []
+  fix_sys_path(extra_extra_paths)
+
   script_name = SCRIPT_EXCEPTIONS.get(script_name, script_name)
   script_dir = SCRIPT_DIR_EXCEPTIONS.get(script_name, script_dir)
   script_path = os.path.join(script_dir, script_name)
diff --git a/demos/guestbook/guestbook.py b/demos/guestbook/guestbook.py
index fe4b43b..c52a0ee 100755
--- a/demos/guestbook/guestbook.py
+++ b/demos/guestbook/guestbook.py
@@ -16,11 +16,12 @@
 #
 import cgi
 import datetime
-import wsgiref.handlers
+
 
 from google.appengine.ext import db
 from google.appengine.api import users
 from google.appengine.ext import webapp
+from google.appengine.ext.webapp import util
 
 class Greeting(db.Model):
   author = db.UserProperty()
@@ -73,7 +74,7 @@
 
 
 def main():
-  wsgiref.handlers.CGIHandler().run(application)
+  util.run_wsgi_app(application)
 
 
 if __name__ == '__main__':
diff --git a/dev_appserver.py b/dev_appserver.py
index 88994d1..0276d25 100755
--- a/dev_appserver.py
+++ b/dev_appserver.py
@@ -21,6 +21,7 @@
 
 
 import os
+import re
 import sys
 
 
@@ -57,18 +58,32 @@
   os.path.join(DIR_PATH, 'lib', 'google.appengine._internal.graphy'),
 ]
 
+API_SERVER_EXTRA_PATHS = [
+  os.path.join(DIR_PATH, 'lib', 'argparse'),
+]
+API_SERVER_EXTRA_PATH_SCRIPTS = 'api_server'
 
-GOOGLE_SQL_EXTRA_PATHS = [
-  os.path.join(DIR_PATH, 'lib', 'enum'),
+
+OAUTH_CLIENT_EXTRA_PATHS = [
   os.path.join(DIR_PATH, 'lib', 'google-api-python-client'),
-  os.path.join(DIR_PATH, 'lib', 'grizzled'),
   os.path.join(DIR_PATH, 'lib', 'httplib2'),
+  os.path.join(DIR_PATH, 'lib', 'python-gflags'),
+]
+
+OAUTH_CLIENT_EXTRA_PATH_SCRIPTS = '(appcfg|bulkloader)'
+
+
+GOOGLE_SQL_EXTRA_PATHS = OAUTH_CLIENT_EXTRA_PATHS + [
+  os.path.join(DIR_PATH, 'lib', 'enum'),
+  os.path.join(DIR_PATH, 'lib', 'grizzled'),
   os.path.join(DIR_PATH, 'lib', 'oauth2'),
   os.path.join(DIR_PATH, 'lib', 'prettytable'),
-  os.path.join(DIR_PATH, 'lib', 'python-gflags'),
   os.path.join(DIR_PATH, 'lib', 'sqlcmd'),
 ]
 
+GOOGLE_SQL_EXTRA_PATH_SCRIPTS = 'google_sql'
+
+
 
 SCRIPT_EXCEPTIONS = {
   "dev_appserver.py" : "dev_appserver_main.py"
@@ -79,18 +94,27 @@
 }
 
 
-def fix_sys_path(include_google_sql_libs=False):
+def fix_sys_path(extra_extra_paths=()):
   """Fix the sys.path to include our extra paths."""
   extra_paths = EXTRA_PATHS[:]
-  if include_google_sql_libs:
-    extra_paths.extend(GOOGLE_SQL_EXTRA_PATHS)
+  extra_paths.extend(extra_extra_paths)
   sys.path = extra_paths + sys.path
 
 
 def run_file(file_path, globals_, script_dir=SCRIPT_DIR):
   """Execute the file at the specified path with the passed-in globals."""
   script_name = os.path.basename(file_path)
-  fix_sys_path('google_sql' in script_name)
+
+  if re.match(OAUTH_CLIENT_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = OAUTH_CLIENT_EXTRA_PATHS
+  elif re.match(GOOGLE_SQL_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = GOOGLE_SQL_EXTRA_PATHS
+  elif re.match(API_SERVER_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = API_SERVER_EXTRA_PATHS
+  else:
+    extra_extra_paths = []
+  fix_sys_path(extra_extra_paths)
+
   script_name = SCRIPT_EXCEPTIONS.get(script_name, script_name)
   script_dir = SCRIPT_DIR_EXCEPTIONS.get(script_name, script_dir)
   script_path = os.path.join(script_dir, script_name)
diff --git a/gen_protorpc.py b/gen_protorpc.py
index 88994d1..0276d25 100755
--- a/gen_protorpc.py
+++ b/gen_protorpc.py
@@ -21,6 +21,7 @@
 
 
 import os
+import re
 import sys
 
 
@@ -57,18 +58,32 @@
   os.path.join(DIR_PATH, 'lib', 'google.appengine._internal.graphy'),
 ]
 
+API_SERVER_EXTRA_PATHS = [
+  os.path.join(DIR_PATH, 'lib', 'argparse'),
+]
+API_SERVER_EXTRA_PATH_SCRIPTS = 'api_server'
 
-GOOGLE_SQL_EXTRA_PATHS = [
-  os.path.join(DIR_PATH, 'lib', 'enum'),
+
+OAUTH_CLIENT_EXTRA_PATHS = [
   os.path.join(DIR_PATH, 'lib', 'google-api-python-client'),
-  os.path.join(DIR_PATH, 'lib', 'grizzled'),
   os.path.join(DIR_PATH, 'lib', 'httplib2'),
+  os.path.join(DIR_PATH, 'lib', 'python-gflags'),
+]
+
+OAUTH_CLIENT_EXTRA_PATH_SCRIPTS = '(appcfg|bulkloader)'
+
+
+GOOGLE_SQL_EXTRA_PATHS = OAUTH_CLIENT_EXTRA_PATHS + [
+  os.path.join(DIR_PATH, 'lib', 'enum'),
+  os.path.join(DIR_PATH, 'lib', 'grizzled'),
   os.path.join(DIR_PATH, 'lib', 'oauth2'),
   os.path.join(DIR_PATH, 'lib', 'prettytable'),
-  os.path.join(DIR_PATH, 'lib', 'python-gflags'),
   os.path.join(DIR_PATH, 'lib', 'sqlcmd'),
 ]
 
+GOOGLE_SQL_EXTRA_PATH_SCRIPTS = 'google_sql'
+
+
 
 SCRIPT_EXCEPTIONS = {
   "dev_appserver.py" : "dev_appserver_main.py"
@@ -79,18 +94,27 @@
 }
 
 
-def fix_sys_path(include_google_sql_libs=False):
+def fix_sys_path(extra_extra_paths=()):
   """Fix the sys.path to include our extra paths."""
   extra_paths = EXTRA_PATHS[:]
-  if include_google_sql_libs:
-    extra_paths.extend(GOOGLE_SQL_EXTRA_PATHS)
+  extra_paths.extend(extra_extra_paths)
   sys.path = extra_paths + sys.path
 
 
 def run_file(file_path, globals_, script_dir=SCRIPT_DIR):
   """Execute the file at the specified path with the passed-in globals."""
   script_name = os.path.basename(file_path)
-  fix_sys_path('google_sql' in script_name)
+
+  if re.match(OAUTH_CLIENT_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = OAUTH_CLIENT_EXTRA_PATHS
+  elif re.match(GOOGLE_SQL_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = GOOGLE_SQL_EXTRA_PATHS
+  elif re.match(API_SERVER_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = API_SERVER_EXTRA_PATHS
+  else:
+    extra_extra_paths = []
+  fix_sys_path(extra_extra_paths)
+
   script_name = SCRIPT_EXCEPTIONS.get(script_name, script_name)
   script_dir = SCRIPT_DIR_EXCEPTIONS.get(script_name, script_dir)
   script_path = os.path.join(script_dir, script_name)
diff --git a/google/appengine/api/app_identity/app_identity_stub.py b/google/appengine/api/app_identity/app_identity_stub.py
index 22b964e..6323bfc 100644
--- a/google/appengine/api/app_identity/app_identity_stub.py
+++ b/google/appengine/api/app_identity/app_identity_stub.py
@@ -136,5 +136,5 @@
                               (':'.join(request.scope_list()),
                                time.time() % 100))
 
-    response.set_expiration_time(time.time() + 1800)
+    response.set_expiration_time(int(time.time()) + 1800)
 
diff --git a/google/appengine/api/appinfo.py b/google/appengine/api/appinfo.py
index 3bd2e07..c0e72a8 100755
--- a/google/appengine/api/appinfo.py
+++ b/google/appengine/api/appinfo.py
@@ -199,7 +199,7 @@
 
 
 SUPPORTED_LIBRARIES = {
-    'django': ['1.2'],
+    'django': ['1.2', '1.3'],
     'jinja2': ['2.6'],
     'lxml': ['2.3'],
     'markupsafe': ['0.15'],
@@ -207,7 +207,7 @@
     'PIL': ['1.1.7'],
     'pycrypto': ['2.3'],
     'setuptools': ['0.6c11'],
-    'webapp2': ['2.3'],
+    'webapp2': ['2.3', '2.5.1'],
     'webob': ['1.1.1'],
     'yaml': ['3.10'],
 }
diff --git a/google/appengine/api/conversion/conversion_stub.py b/google/appengine/api/conversion/conversion_stub.py
index 2e060c6..54bbe70 100644
--- a/google/appengine/api/conversion/conversion_stub.py
+++ b/google/appengine/api/conversion/conversion_stub.py
@@ -146,7 +146,10 @@
 
   def __init__(self, service_name="conversion"):
     """Constructor."""
-    apiproxy_stub.APIProxyStub.__init__(self, service_name)
+    apiproxy_stub.APIProxyStub.__init__(
+        self, service_name,
+        conversion.CONVERSION_MAX_SIZE_BYTES *
+        conversion.CONVERSION_MAX_NUM_PER_REQUEST)
 
   def _Dynamic_Convert(self, request, response):
     _validate_conversion_request(request)
diff --git a/google/appengine/api/datastore.py b/google/appengine/api/datastore.py
index e3f48d6..401084a 100755
--- a/google/appengine/api/datastore.py
+++ b/google/appengine/api/datastore.py
@@ -248,8 +248,9 @@
         The order of the properties is based on the order in the index.
     """
     argument_error = datastore_errors.BadArgumentError
-    datastore_types.ValidateInteger(index_id, 'index_id', argument_error)
-    datastore_types.ValidateString(kind, 'kind', argument_error)
+    datastore_types.ValidateInteger(index_id, 'index_id', argument_error,
+                                    zero_ok=True)
+    datastore_types.ValidateString(kind, 'kind', argument_error, empty_ok=True)
     if not isinstance(properties, (list, tuple)):
       raise argument_error('properties must be a list or a tuple')
     for idx, index_property in enumerate(properties):
@@ -281,7 +282,7 @@
     return self.__id
 
   def _Kind(self):
-    """Returns the index kind, a string."""
+    """Returns the index kind, a string, or None if none."""
     return self.__kind
 
   def _HasAncestor(self):
@@ -1239,6 +1240,10 @@
   __ancestor_pb = None
   __compile = None
 
+  __index_list_source = None
+  __cursor_source = None
+  __compiled_query_source = None
+
 
   __cursor = None
 
@@ -1528,6 +1533,21 @@
           property_filters)
     return None
 
+  def GetIndexList(self):
+    """Get the index list from the last run of this query.
+
+    Returns:
+      A list of indexes used by the last run of this query.
+
+    Raises:
+      AssertionError: The query has not yet been run.
+    """
+    index_list_function = self.__index_list_source
+    if index_list_function:
+      return index_list_function()
+    raise AssertionError('No index list available because this query has not '
+                         'been executed')
+
   def GetCursor(self):
     """Get the cursor from the last run of this query.
 
@@ -1539,20 +1559,22 @@
       - Count: A cursor that points immediately after the last result counted.
 
     Returns:
-      A datastore_query.Cursor object that can be used in subsiquent query
+      A datastore_query.Cursor object that can be used in subsequent query
       requests.
+
+    Raises:
+      AssertionError: The query has not yet been run or cannot be compiled.
     """
-    try:
 
 
-      cursor = self.__cursor_source()
-      if not cursor:
-        raise AttributeError()
-    except AttributeError:
-      raise AssertionError('No cursor available, either this query has not '
-                           'been executed or there is no compilation '
-                           'available for this kind of query')
-    return cursor
+    cursor_function = self.__cursor_source
+    if cursor_function:
+      cursor = cursor_function()
+      if cursor:
+        return cursor
+    raise AssertionError('No cursor available, either this query has not '
+                         'been executed or there is no compilation '
+                         'available for this kind of query')
 
   def GetBatcher(self, config=None):
     """Runs this query and returns a datastore_query.Batcher.
@@ -1579,7 +1601,7 @@
     invalid, raises BadValueError. If an IN filter is provided, and a sort
     order on another property is provided, raises BadQueryError.
 
-    If you know in advance how many results you want, use Get() instead. It's
+    If you know in advance how many results you want, use limit=#. It's
     more efficient.
 
     Args:
@@ -1593,6 +1615,8 @@
                                   config_class=datastore_query.QueryOptions)
     itr = Iterator(self.GetBatcher(config=config))
 
+    self.__index_list_source = itr.GetIndexList
+
     self.__cursor_source = itr.cursor
 
     self.__compiled_query_source = itr._compiled_query
@@ -1638,6 +1662,8 @@
                                   config_class=datastore_query.QueryOptions)
 
     batch = self.GetBatcher(config=config).next()
+    self.__index_list_source = (
+        lambda: [index for index, state in batch.index_list])
     self.__cursor_source = lambda: batch.cursor(0)
     self.__compiled_query_source = lambda: batch._compiled_query
     return max(0, batch.skipped_results - original_offset)
@@ -1648,10 +1674,9 @@
 
   def __getstate__(self):
     state = self.__dict__.copy()
-    if '_Query__cursor_source' in state:
-      del state['_Query__cursor_source']
-    if '_Query__compiled_query_source' in state:
-      del state['_Query__compiled_query_source']
+    state['_Query__index_list_source'] = None
+    state['_Query__cursor_source'] = None
+    state['_Query__compiled_query_source'] = None
     return state
 
   def __setitem__(self, filter, value):
@@ -1827,18 +1852,18 @@
     """Returns the internal-only pb representation of the last query run.
 
     Do not use.
+
+    Raises:
+      AssertionError: Query not compiled or not yet executed.
     """
-    try:
-
-
-      compiled_query = self.__compiled_query_source()
-      if not compiled_query:
-        raise AttributeError()
-    except AttributeError:
-      raise AssertionError('No compiled query available, either this query has '
-                           'not been executed or there is no compilation '
-                           'available for this kind of query')
-    return compiled_query
+    compiled_query_function = self.__compiled_query_source
+    if compiled_query_function:
+      compiled_query = compiled_query_function()
+      if compiled_query:
+        return compiled_query
+    raise AssertionError('No compiled query available, either this query has '
+                         'not been executed or there is no compilation '
+                         'available for this kind of query')
 
   GetCompiledQuery = _GetCompiledQuery
   GetCompiledCursor = GetCursor
@@ -2229,11 +2254,15 @@
 
     return max(0, len(used_keys) - lower_bound)
 
+  def GetIndexList(self):
+
+    raise AssertionError('No index_list available for a MultiQuery (queries '
+                         'using "IN" or "!=" operators)')
+
   def GetCursor(self):
     raise AssertionError('No cursor available for a MultiQuery (queries '
                          'using "IN" or "!=" operators)')
 
-
   def _GetCompiledQuery(self):
     """Internal only, do not use."""
     raise AssertionError('No compilation available for a MultiQuery (queries '
@@ -2635,6 +2664,7 @@
 
   Deprecated, do not use, only for backwards compatability.
   """
+
   def _Next(self, count=None):
     if count is None:
       count = 20
@@ -2648,10 +2678,19 @@
   def GetCompiledCursor(self, query):
     return self.cursor()
 
+  def GetIndexList(self):
+    """Returns the list of indexes used to perform the query."""
+    tuple_index_list = super(Iterator, self).index_list()
+    return [index for index, state in tuple_index_list]
+
   _Get = _Next
 
 
 
+  index_list = GetIndexList
+
+
+
 DatastoreRPC = apiproxy_stub_map.UserRPC
 GetRpcFromKwargs = _GetConfigFromKwargs
 _CurrentTransactionKey = IsInTransaction
diff --git a/google/appengine/api/datastore_file_stub.py b/google/appengine/api/datastore_file_stub.py
index a1d3d77..faf7c99 100755
--- a/google/appengine/api/datastore_file_stub.py
+++ b/google/appengine/api/datastore_file_stub.py
@@ -309,7 +309,8 @@
                service_name='datastore_v3',
                trusted=False,
                consistency_policy=None,
-               save_changes=True):
+               save_changes=True,
+               root_path=None):
     """Constructor.
 
     Initializes and loads the datastore from the backing files, if they exist.
@@ -329,12 +330,13 @@
         datastore_stub_util.*ConsistencyPolicy
       save_changes: bool, default True. If this stub should modify
         datastore_file when entities are changed.
+      root_path: string, the root path of the app.
     """
     datastore_stub_util.BaseDatastore.__init__(self, require_indexes,
                                                consistency_policy)
     apiproxy_stub.APIProxyStub.__init__(self, service_name)
     datastore_stub_util.DatastoreStub.__init__(self, weakref.proxy(self),
-                                               app_id, trusted)
+                                               app_id, trusted, root_path)
 
 
 
@@ -359,9 +361,6 @@
 
     self.__schema_cache = {}
 
-
-    self.__query_history = {}
-
     self.__next_id = 1L
     self.__id_lock = threading.Lock()
 
@@ -384,7 +383,6 @@
 
       self.__entities_by_kind = collections.defaultdict(dict)
       self.__entities_by_group = collections.defaultdict(dict)
-      self.__query_history = {}
       self.__schema_cache = {}
     finally:
       self.__entities_lock.release()
@@ -506,7 +504,10 @@
 
     try:
       try:
-        if filename and filename != '/dev/null' and os.path.isfile(filename):
+        if (filename and
+            filename != '/dev/null' and
+            os.path.isfile(filename) and
+            os.stat(filename).st_size > 0):
           return pickle.load(open(filename, 'rb'))
         else:
           logging.warning('Could not read datastore data from %s', filename)
@@ -574,13 +575,6 @@
 
     pb.Encode()
 
-  def QueryHistory(self):
-    """Returns a dict that maps Query PBs to times they've been run.
-    """
-
-    return dict((pb, times) for pb, times in self.__query_history.items()
-                if pb.app() == self._app_id)
-
   def _GetSchemaCache(self, kind, usekey):
     if kind in self.__schema_cache and usekey in self.__schema_cache[kind]:
       return self.__schema_cache[kind][usekey]
@@ -637,7 +631,7 @@
     eg_k = datastore_types.ReferenceToKeyValue(entity_group)
     return self.__entities_by_group[eg_k].copy()
 
-  def _GetQueryCursor(self, query, filters, orders):
+  def _GetQueryCursor(self, query, filters, orders, index_list):
     app_id = query.app()
     namespace = query.name_space()
 
@@ -668,7 +662,8 @@
     finally:
       self.__entities_lock.release()
 
-    return datastore_stub_util._ExecuteQuery(results, query, filters, orders)
+    return datastore_stub_util._ExecuteQuery(results, query,
+                                             filters, orders, index_list)
 
   def _AllocateIds(self, reference, size=1, max_id=None):
     datastore_stub_util.Check(not (size and max_id),
@@ -694,18 +689,3 @@
 
   def _OnApply(self):
     self.__WriteDatastore()
-
-  def _Dynamic_RunQuery(self, query, query_result):
-    super(DatastoreFileStub, self)._Dynamic_RunQuery(query, query_result)
-
-
-    clone = datastore_pb.Query()
-    clone.CopyFrom(query)
-    clone.clear_hint()
-    clone.clear_limit()
-    clone.clear_offset()
-    clone.clear_count()
-    if clone in self.__query_history:
-      self.__query_history[clone] += 1
-    else:
-      self.__query_history[clone] = 1
diff --git a/google/appengine/api/files/file.py b/google/appengine/api/files/file.py
index 8eb3bee..5cb5cdd 100755
--- a/google/appengine/api/files/file.py
+++ b/google/appengine/api/files/file.py
@@ -157,6 +157,8 @@
        file_service_pb.FileServiceErrors.EXISTENCE_ERROR_METADATA_NOT_FOUND,
        file_service_pb.FileServiceErrors.EXISTENCE_ERROR_METADATA_FOUND,
        file_service_pb.FileServiceErrors.EXISTENCE_ERROR_SHARDING_MISMATCH,
+       file_service_pb.FileServiceErrors.EXISTENCE_ERROR_OBJECT_NOT_FOUND,
+       file_service_pb.FileServiceErrors.EXISTENCE_ERROR_BUCKET_NOT_FOUND,
        ]):
     raise ExistenceError()
   elif (e.application_error ==
diff --git a/google/appengine/api/files/file_service_pb.py b/google/appengine/api/files/file_service_pb.py
index 4ce7a4e..0fa343b 100755
--- a/google/appengine/api/files/file_service_pb.py
+++ b/google/appengine/api/files/file_service_pb.py
@@ -57,6 +57,9 @@
   EXISTENCE_ERROR_METADATA_NOT_FOUND =  105
   EXISTENCE_ERROR_METADATA_FOUND =  106
   EXISTENCE_ERROR_SHARDING_MISMATCH =  107
+  FINALIZATION_IN_PROGRESS =  108
+  EXISTENCE_ERROR_OBJECT_NOT_FOUND =  109
+  EXISTENCE_ERROR_BUCKET_NOT_FOUND =  110
   SEQUENCE_KEY_OUT_OF_ORDER =  300
   OUT_OF_BOUNDS =  500
   GLOBS_NOT_SUPPORTED =  600
@@ -94,6 +97,9 @@
     105: "EXISTENCE_ERROR_METADATA_NOT_FOUND",
     106: "EXISTENCE_ERROR_METADATA_FOUND",
     107: "EXISTENCE_ERROR_SHARDING_MISMATCH",
+    108: "FINALIZATION_IN_PROGRESS",
+    109: "EXISTENCE_ERROR_OBJECT_NOT_FOUND",
+    110: "EXISTENCE_ERROR_BUCKET_NOT_FOUND",
     300: "SEQUENCE_KEY_OUT_OF_ORDER",
     500: "OUT_OF_BOUNDS",
     600: "GLOBS_NOT_SUPPORTED",
@@ -4768,7 +4774,172 @@
   _STYLE = """"""
   _STYLE_CONTENT_TYPE = """"""
   _PROTO_DESCRIPTOR_NAME = 'apphosting.files.GetCapabilitiesResponse'
+class FinalizeRequest(ProtocolBuffer.ProtocolMessage):
+  has_filename_ = 0
+  filename_ = ""
+
+  def __init__(self, contents=None):
+    if contents is not None: self.MergeFromString(contents)
+
+  def filename(self): return self.filename_
+
+  def set_filename(self, x):
+    self.has_filename_ = 1
+    self.filename_ = x
+
+  def clear_filename(self):
+    if self.has_filename_:
+      self.has_filename_ = 0
+      self.filename_ = ""
+
+  def has_filename(self): return self.has_filename_
+
+
+  def MergeFrom(self, x):
+    assert x is not self
+    if (x.has_filename()): self.set_filename(x.filename())
+
+  def Equals(self, x):
+    if x is self: return 1
+    if self.has_filename_ != x.has_filename_: return 0
+    if self.has_filename_ and self.filename_ != x.filename_: return 0
+    return 1
+
+  def IsInitialized(self, debug_strs=None):
+    initialized = 1
+    if (not self.has_filename_):
+      initialized = 0
+      if debug_strs is not None:
+        debug_strs.append('Required field: filename not set.')
+    return initialized
+
+  def ByteSize(self):
+    n = 0
+    n += self.lengthString(len(self.filename_))
+    return n + 1
+
+  def ByteSizePartial(self):
+    n = 0
+    if (self.has_filename_):
+      n += 1
+      n += self.lengthString(len(self.filename_))
+    return n
+
+  def Clear(self):
+    self.clear_filename()
+
+  def OutputUnchecked(self, out):
+    out.putVarInt32(10)
+    out.putPrefixedString(self.filename_)
+
+  def OutputPartial(self, out):
+    if (self.has_filename_):
+      out.putVarInt32(10)
+      out.putPrefixedString(self.filename_)
+
+  def TryMerge(self, d):
+    while d.avail() > 0:
+      tt = d.getVarInt32()
+      if tt == 10:
+        self.set_filename(d.getPrefixedString())
+        continue
+
+
+      if (tt == 0): raise ProtocolBuffer.ProtocolBufferDecodeError
+      d.skipData(tt)
+
+
+  def __str__(self, prefix="", printElemNumber=0):
+    res=""
+    if self.has_filename_: res+=prefix+("filename: %s\n" % self.DebugFormatString(self.filename_))
+    return res
+
+
+  def _BuildTagLookupTable(sparse, maxtag, default=None):
+    return tuple([sparse.get(i, default) for i in xrange(0, 1+maxtag)])
+
+  kfilename = 1
+
+  _TEXT = _BuildTagLookupTable({
+    0: "ErrorCode",
+    1: "filename",
+  }, 1)
+
+  _TYPES = _BuildTagLookupTable({
+    0: ProtocolBuffer.Encoder.NUMERIC,
+    1: ProtocolBuffer.Encoder.STRING,
+  }, 1, ProtocolBuffer.Encoder.MAX_TYPE)
+
+
+  _STYLE = """"""
+  _STYLE_CONTENT_TYPE = """"""
+  _PROTO_DESCRIPTOR_NAME = 'apphosting.files.FinalizeRequest'
+class FinalizeResponse(ProtocolBuffer.ProtocolMessage):
+
+  def __init__(self, contents=None):
+    pass
+    if contents is not None: self.MergeFromString(contents)
+
+
+  def MergeFrom(self, x):
+    assert x is not self
+
+  def Equals(self, x):
+    if x is self: return 1
+    return 1
+
+  def IsInitialized(self, debug_strs=None):
+    initialized = 1
+    return initialized
+
+  def ByteSize(self):
+    n = 0
+    return n
+
+  def ByteSizePartial(self):
+    n = 0
+    return n
+
+  def Clear(self):
+    pass
+
+  def OutputUnchecked(self, out):
+    pass
+
+  def OutputPartial(self, out):
+    pass
+
+  def TryMerge(self, d):
+    while d.avail() > 0:
+      tt = d.getVarInt32()
+
+
+      if (tt == 0): raise ProtocolBuffer.ProtocolBufferDecodeError
+      d.skipData(tt)
+
+
+  def __str__(self, prefix="", printElemNumber=0):
+    res=""
+    return res
+
+
+  def _BuildTagLookupTable(sparse, maxtag, default=None):
+    return tuple([sparse.get(i, default) for i in xrange(0, 1+maxtag)])
+
+
+  _TEXT = _BuildTagLookupTable({
+    0: "ErrorCode",
+  }, 0)
+
+  _TYPES = _BuildTagLookupTable({
+    0: ProtocolBuffer.Encoder.NUMERIC,
+  }, 0, ProtocolBuffer.Encoder.MAX_TYPE)
+
+
+  _STYLE = """"""
+  _STYLE_CONTENT_TYPE = """"""
+  _PROTO_DESCRIPTOR_NAME = 'apphosting.files.FinalizeResponse'
 if _extension_runtime:
   pass
 
-__all__ = ['FileServiceErrors','KeyValue','KeyValues','FileContentType','CreateRequest_Parameter','CreateRequest','CreateResponse','OpenRequest','OpenResponse','CloseRequest','CloseResponse','FileStat','StatRequest','StatResponse','AppendRequest','AppendResponse','DeleteRequest','DeleteResponse','ReadRequest','ReadResponse','ReadKeyValueRequest','ReadKeyValueResponse_KeyValue','ReadKeyValueResponse','ShuffleEnums','ShuffleInputSpecification','ShuffleOutputSpecification','ShuffleRequest_Callback','ShuffleRequest','ShuffleResponse','GetShuffleStatusRequest','GetShuffleStatusResponse','GetCapabilitiesRequest','GetCapabilitiesResponse']
+__all__ = ['FileServiceErrors','KeyValue','KeyValues','FileContentType','CreateRequest_Parameter','CreateRequest','CreateResponse','OpenRequest','OpenResponse','CloseRequest','CloseResponse','FileStat','StatRequest','StatResponse','AppendRequest','AppendResponse','DeleteRequest','DeleteResponse','ReadRequest','ReadResponse','ReadKeyValueRequest','ReadKeyValueResponse_KeyValue','ReadKeyValueResponse','ShuffleEnums','ShuffleInputSpecification','ShuffleOutputSpecification','ShuffleRequest_Callback','ShuffleRequest','ShuffleResponse','GetShuffleStatusRequest','GetShuffleStatusResponse','GetCapabilitiesRequest','GetCapabilitiesResponse','FinalizeRequest','FinalizeResponse']
diff --git a/google/appengine/api/files/records.py b/google/appengine/api/files/records.py
index 0b90c72..ef54f18 100644
--- a/google/appengine/api/files/records.py
+++ b/google/appengine/api/files/records.py
@@ -117,7 +117,7 @@
   """Base class for exceptions in this module."""
 
 
-class InvalidRecordError(Exception):
+class InvalidRecordError(Error):
   """Raised when invalid record encountered."""
 
 
@@ -327,32 +327,46 @@
     """Reads record from current position in reader."""
     data = None
     while True:
+      last_offset = self.tell()
       try:
         (chunk, record_type) = self.__try_read_record()
         if record_type == RECORD_TYPE_NONE:
           self.__sync()
         elif record_type == RECORD_TYPE_FULL:
+          if data is not None:
+            logging.warning(
+                "Ordering corruption: Got FULL record while already "
+                "in a chunk at offset %d", last_offset)
           return chunk
         elif record_type == RECORD_TYPE_FIRST:
           if data is not None:
-            raise InvalidRecordError()
+            logging.warning(
+                "Ordering corruption: Got FIRST record while already "
+                "in a chunk at offset %d", last_offset)
           data = chunk
         elif record_type == RECORD_TYPE_MIDDLE:
           if data is None:
-            raise InvalidRecordError()
-          data += chunk
+            logging.warning(
+                "Ordering corruption: Got MIDDLE record before FIRST "
+                "record at offset %d", last_offset)
+          else:
+            data += chunk
         elif record_type == RECORD_TYPE_LAST:
           if data is None:
-            raise InvalidRecordError()
-          result = data + chunk
-          data = None
-          return result
+            logging.warning(
+                "Ordering corruption: Got LAST record but no chunk is in "
+                "progress at offset %d", last_offset)
+          else:
+            result = data + chunk
+            data = None
+            return result
         else:
-          raise InvalidRecordError('Unsupported record type: %s' %
-                                   (record_type))
+          raise InvalidRecordError("Unsupported record type: %s" % record_type)
+
       except InvalidRecordError, e:
-        logging.debug("Invalid record encountered at %s (%s). Syncing to "
-                      "the next block", self.tell(), e)
+        logging.warning("Invalid record encountered at %s (%s). Syncing to "
+                        "the next block", last_offset, e)
+        data = None
         self.__sync()
 
   def __iter__(self):
diff --git a/google/appengine/api/logservice/log_service_pb.py b/google/appengine/api/logservice/log_service_pb.py
index 072a385..ca4af07 100755
--- a/google/appengine/api/logservice/log_service_pb.py
+++ b/google/appengine/api/logservice/log_service_pb.py
@@ -3144,7 +3144,749 @@
   _STYLE = """"""
   _STYLE_CONTENT_TYPE = """"""
   _PROTO_DESCRIPTOR_NAME = 'apphosting.LogReadResponse'
+class LogUsageRecord(ProtocolBuffer.ProtocolMessage):
+  has_version_id_ = 0
+  version_id_ = ""
+  has_start_time_ = 0
+  start_time_ = 0
+  has_end_time_ = 0
+  end_time_ = 0
+  has_count_ = 0
+  count_ = 0
+  has_total_size_ = 0
+  total_size_ = 0
+
+  def __init__(self, contents=None):
+    if contents is not None: self.MergeFromString(contents)
+
+  def version_id(self): return self.version_id_
+
+  def set_version_id(self, x):
+    self.has_version_id_ = 1
+    self.version_id_ = x
+
+  def clear_version_id(self):
+    if self.has_version_id_:
+      self.has_version_id_ = 0
+      self.version_id_ = ""
+
+  def has_version_id(self): return self.has_version_id_
+
+  def start_time(self): return self.start_time_
+
+  def set_start_time(self, x):
+    self.has_start_time_ = 1
+    self.start_time_ = x
+
+  def clear_start_time(self):
+    if self.has_start_time_:
+      self.has_start_time_ = 0
+      self.start_time_ = 0
+
+  def has_start_time(self): return self.has_start_time_
+
+  def end_time(self): return self.end_time_
+
+  def set_end_time(self, x):
+    self.has_end_time_ = 1
+    self.end_time_ = x
+
+  def clear_end_time(self):
+    if self.has_end_time_:
+      self.has_end_time_ = 0
+      self.end_time_ = 0
+
+  def has_end_time(self): return self.has_end_time_
+
+  def count(self): return self.count_
+
+  def set_count(self, x):
+    self.has_count_ = 1
+    self.count_ = x
+
+  def clear_count(self):
+    if self.has_count_:
+      self.has_count_ = 0
+      self.count_ = 0
+
+  def has_count(self): return self.has_count_
+
+  def total_size(self): return self.total_size_
+
+  def set_total_size(self, x):
+    self.has_total_size_ = 1
+    self.total_size_ = x
+
+  def clear_total_size(self):
+    if self.has_total_size_:
+      self.has_total_size_ = 0
+      self.total_size_ = 0
+
+  def has_total_size(self): return self.has_total_size_
+
+
+  def MergeFrom(self, x):
+    assert x is not self
+    if (x.has_version_id()): self.set_version_id(x.version_id())
+    if (x.has_start_time()): self.set_start_time(x.start_time())
+    if (x.has_end_time()): self.set_end_time(x.end_time())
+    if (x.has_count()): self.set_count(x.count())
+    if (x.has_total_size()): self.set_total_size(x.total_size())
+
+  def Equals(self, x):
+    if x is self: return 1
+    if self.has_version_id_ != x.has_version_id_: return 0
+    if self.has_version_id_ and self.version_id_ != x.version_id_: return 0
+    if self.has_start_time_ != x.has_start_time_: return 0
+    if self.has_start_time_ and self.start_time_ != x.start_time_: return 0
+    if self.has_end_time_ != x.has_end_time_: return 0
+    if self.has_end_time_ and self.end_time_ != x.end_time_: return 0
+    if self.has_count_ != x.has_count_: return 0
+    if self.has_count_ and self.count_ != x.count_: return 0
+    if self.has_total_size_ != x.has_total_size_: return 0
+    if self.has_total_size_ and self.total_size_ != x.total_size_: return 0
+    return 1
+
+  def IsInitialized(self, debug_strs=None):
+    initialized = 1
+    return initialized
+
+  def ByteSize(self):
+    n = 0
+    if (self.has_version_id_): n += 1 + self.lengthString(len(self.version_id_))
+    if (self.has_start_time_): n += 1 + self.lengthVarInt64(self.start_time_)
+    if (self.has_end_time_): n += 1 + self.lengthVarInt64(self.end_time_)
+    if (self.has_count_): n += 1 + self.lengthVarInt64(self.count_)
+    if (self.has_total_size_): n += 1 + self.lengthVarInt64(self.total_size_)
+    return n
+
+  def ByteSizePartial(self):
+    n = 0
+    if (self.has_version_id_): n += 1 + self.lengthString(len(self.version_id_))
+    if (self.has_start_time_): n += 1 + self.lengthVarInt64(self.start_time_)
+    if (self.has_end_time_): n += 1 + self.lengthVarInt64(self.end_time_)
+    if (self.has_count_): n += 1 + self.lengthVarInt64(self.count_)
+    if (self.has_total_size_): n += 1 + self.lengthVarInt64(self.total_size_)
+    return n
+
+  def Clear(self):
+    self.clear_version_id()
+    self.clear_start_time()
+    self.clear_end_time()
+    self.clear_count()
+    self.clear_total_size()
+
+  def OutputUnchecked(self, out):
+    if (self.has_version_id_):
+      out.putVarInt32(10)
+      out.putPrefixedString(self.version_id_)
+    if (self.has_start_time_):
+      out.putVarInt32(16)
+      out.putVarInt32(self.start_time_)
+    if (self.has_end_time_):
+      out.putVarInt32(24)
+      out.putVarInt32(self.end_time_)
+    if (self.has_count_):
+      out.putVarInt32(32)
+      out.putVarInt64(self.count_)
+    if (self.has_total_size_):
+      out.putVarInt32(40)
+      out.putVarInt64(self.total_size_)
+
+  def OutputPartial(self, out):
+    if (self.has_version_id_):
+      out.putVarInt32(10)
+      out.putPrefixedString(self.version_id_)
+    if (self.has_start_time_):
+      out.putVarInt32(16)
+      out.putVarInt32(self.start_time_)
+    if (self.has_end_time_):
+      out.putVarInt32(24)
+      out.putVarInt32(self.end_time_)
+    if (self.has_count_):
+      out.putVarInt32(32)
+      out.putVarInt64(self.count_)
+    if (self.has_total_size_):
+      out.putVarInt32(40)
+      out.putVarInt64(self.total_size_)
+
+  def TryMerge(self, d):
+    while d.avail() > 0:
+      tt = d.getVarInt32()
+      if tt == 10:
+        self.set_version_id(d.getPrefixedString())
+        continue
+      if tt == 16:
+        self.set_start_time(d.getVarInt32())
+        continue
+      if tt == 24:
+        self.set_end_time(d.getVarInt32())
+        continue
+      if tt == 32:
+        self.set_count(d.getVarInt64())
+        continue
+      if tt == 40:
+        self.set_total_size(d.getVarInt64())
+        continue
+
+
+      if (tt == 0): raise ProtocolBuffer.ProtocolBufferDecodeError
+      d.skipData(tt)
+
+
+  def __str__(self, prefix="", printElemNumber=0):
+    res=""
+    if self.has_version_id_: res+=prefix+("version_id: %s\n" % self.DebugFormatString(self.version_id_))
+    if self.has_start_time_: res+=prefix+("start_time: %s\n" % self.DebugFormatInt32(self.start_time_))
+    if self.has_end_time_: res+=prefix+("end_time: %s\n" % self.DebugFormatInt32(self.end_time_))
+    if self.has_count_: res+=prefix+("count: %s\n" % self.DebugFormatInt64(self.count_))
+    if self.has_total_size_: res+=prefix+("total_size: %s\n" % self.DebugFormatInt64(self.total_size_))
+    return res
+
+
+  def _BuildTagLookupTable(sparse, maxtag, default=None):
+    return tuple([sparse.get(i, default) for i in xrange(0, 1+maxtag)])
+
+  kversion_id = 1
+  kstart_time = 2
+  kend_time = 3
+  kcount = 4
+  ktotal_size = 5
+
+  _TEXT = _BuildTagLookupTable({
+    0: "ErrorCode",
+    1: "version_id",
+    2: "start_time",
+    3: "end_time",
+    4: "count",
+    5: "total_size",
+  }, 5)
+
+  _TYPES = _BuildTagLookupTable({
+    0: ProtocolBuffer.Encoder.NUMERIC,
+    1: ProtocolBuffer.Encoder.STRING,
+    2: ProtocolBuffer.Encoder.NUMERIC,
+    3: ProtocolBuffer.Encoder.NUMERIC,
+    4: ProtocolBuffer.Encoder.NUMERIC,
+    5: ProtocolBuffer.Encoder.NUMERIC,
+  }, 5, ProtocolBuffer.Encoder.MAX_TYPE)
+
+
+  _STYLE = """"""
+  _STYLE_CONTENT_TYPE = """"""
+  _PROTO_DESCRIPTOR_NAME = 'apphosting.LogUsageRecord'
+class LogUsageRequest(ProtocolBuffer.ProtocolMessage):
+  has_app_id_ = 0
+  app_id_ = ""
+  has_start_time_ = 0
+  start_time_ = 0
+  has_end_time_ = 0
+  end_time_ = 0
+  has_resolution_hours_ = 0
+  resolution_hours_ = 1
+  has_combine_versions_ = 0
+  combine_versions_ = 0
+  has_usage_version_ = 0
+  usage_version_ = 0
+  has_versions_only_ = 0
+  versions_only_ = 0
+
+  def __init__(self, contents=None):
+    self.version_id_ = []
+    if contents is not None: self.MergeFromString(contents)
+
+  def app_id(self): return self.app_id_
+
+  def set_app_id(self, x):
+    self.has_app_id_ = 1
+    self.app_id_ = x
+
+  def clear_app_id(self):
+    if self.has_app_id_:
+      self.has_app_id_ = 0
+      self.app_id_ = ""
+
+  def has_app_id(self): return self.has_app_id_
+
+  def version_id_size(self): return len(self.version_id_)
+  def version_id_list(self): return self.version_id_
+
+  def version_id(self, i):
+    return self.version_id_[i]
+
+  def set_version_id(self, i, x):
+    self.version_id_[i] = x
+
+  def add_version_id(self, x):
+    self.version_id_.append(x)
+
+  def clear_version_id(self):
+    self.version_id_ = []
+
+  def start_time(self): return self.start_time_
+
+  def set_start_time(self, x):
+    self.has_start_time_ = 1
+    self.start_time_ = x
+
+  def clear_start_time(self):
+    if self.has_start_time_:
+      self.has_start_time_ = 0
+      self.start_time_ = 0
+
+  def has_start_time(self): return self.has_start_time_
+
+  def end_time(self): return self.end_time_
+
+  def set_end_time(self, x):
+    self.has_end_time_ = 1
+    self.end_time_ = x
+
+  def clear_end_time(self):
+    if self.has_end_time_:
+      self.has_end_time_ = 0
+      self.end_time_ = 0
+
+  def has_end_time(self): return self.has_end_time_
+
+  def resolution_hours(self): return self.resolution_hours_
+
+  def set_resolution_hours(self, x):
+    self.has_resolution_hours_ = 1
+    self.resolution_hours_ = x
+
+  def clear_resolution_hours(self):
+    if self.has_resolution_hours_:
+      self.has_resolution_hours_ = 0
+      self.resolution_hours_ = 1
+
+  def has_resolution_hours(self): return self.has_resolution_hours_
+
+  def combine_versions(self): return self.combine_versions_
+
+  def set_combine_versions(self, x):
+    self.has_combine_versions_ = 1
+    self.combine_versions_ = x
+
+  def clear_combine_versions(self):
+    if self.has_combine_versions_:
+      self.has_combine_versions_ = 0
+      self.combine_versions_ = 0
+
+  def has_combine_versions(self): return self.has_combine_versions_
+
+  def usage_version(self): return self.usage_version_
+
+  def set_usage_version(self, x):
+    self.has_usage_version_ = 1
+    self.usage_version_ = x
+
+  def clear_usage_version(self):
+    if self.has_usage_version_:
+      self.has_usage_version_ = 0
+      self.usage_version_ = 0
+
+  def has_usage_version(self): return self.has_usage_version_
+
+  def versions_only(self): return self.versions_only_
+
+  def set_versions_only(self, x):
+    self.has_versions_only_ = 1
+    self.versions_only_ = x
+
+  def clear_versions_only(self):
+    if self.has_versions_only_:
+      self.has_versions_only_ = 0
+      self.versions_only_ = 0
+
+  def has_versions_only(self): return self.has_versions_only_
+
+
+  def MergeFrom(self, x):
+    assert x is not self
+    if (x.has_app_id()): self.set_app_id(x.app_id())
+    for i in xrange(x.version_id_size()): self.add_version_id(x.version_id(i))
+    if (x.has_start_time()): self.set_start_time(x.start_time())
+    if (x.has_end_time()): self.set_end_time(x.end_time())
+    if (x.has_resolution_hours()): self.set_resolution_hours(x.resolution_hours())
+    if (x.has_combine_versions()): self.set_combine_versions(x.combine_versions())
+    if (x.has_usage_version()): self.set_usage_version(x.usage_version())
+    if (x.has_versions_only()): self.set_versions_only(x.versions_only())
+
+  def Equals(self, x):
+    if x is self: return 1
+    if self.has_app_id_ != x.has_app_id_: return 0
+    if self.has_app_id_ and self.app_id_ != x.app_id_: return 0
+    if len(self.version_id_) != len(x.version_id_): return 0
+    for e1, e2 in zip(self.version_id_, x.version_id_):
+      if e1 != e2: return 0
+    if self.has_start_time_ != x.has_start_time_: return 0
+    if self.has_start_time_ and self.start_time_ != x.start_time_: return 0
+    if self.has_end_time_ != x.has_end_time_: return 0
+    if self.has_end_time_ and self.end_time_ != x.end_time_: return 0
+    if self.has_resolution_hours_ != x.has_resolution_hours_: return 0
+    if self.has_resolution_hours_ and self.resolution_hours_ != x.resolution_hours_: return 0
+    if self.has_combine_versions_ != x.has_combine_versions_: return 0
+    if self.has_combine_versions_ and self.combine_versions_ != x.combine_versions_: return 0
+    if self.has_usage_version_ != x.has_usage_version_: return 0
+    if self.has_usage_version_ and self.usage_version_ != x.usage_version_: return 0
+    if self.has_versions_only_ != x.has_versions_only_: return 0
+    if self.has_versions_only_ and self.versions_only_ != x.versions_only_: return 0
+    return 1
+
+  def IsInitialized(self, debug_strs=None):
+    initialized = 1
+    if (not self.has_app_id_):
+      initialized = 0
+      if debug_strs is not None:
+        debug_strs.append('Required field: app_id not set.')
+    return initialized
+
+  def ByteSize(self):
+    n = 0
+    n += self.lengthString(len(self.app_id_))
+    n += 1 * len(self.version_id_)
+    for i in xrange(len(self.version_id_)): n += self.lengthString(len(self.version_id_[i]))
+    if (self.has_start_time_): n += 1 + self.lengthVarInt64(self.start_time_)
+    if (self.has_end_time_): n += 1 + self.lengthVarInt64(self.end_time_)
+    if (self.has_resolution_hours_): n += 1 + self.lengthVarInt64(self.resolution_hours_)
+    if (self.has_combine_versions_): n += 2
+    if (self.has_usage_version_): n += 1 + self.lengthVarInt64(self.usage_version_)
+    if (self.has_versions_only_): n += 2
+    return n + 1
+
+  def ByteSizePartial(self):
+    n = 0
+    if (self.has_app_id_):
+      n += 1
+      n += self.lengthString(len(self.app_id_))
+    n += 1 * len(self.version_id_)
+    for i in xrange(len(self.version_id_)): n += self.lengthString(len(self.version_id_[i]))
+    if (self.has_start_time_): n += 1 + self.lengthVarInt64(self.start_time_)
+    if (self.has_end_time_): n += 1 + self.lengthVarInt64(self.end_time_)
+    if (self.has_resolution_hours_): n += 1 + self.lengthVarInt64(self.resolution_hours_)
+    if (self.has_combine_versions_): n += 2
+    if (self.has_usage_version_): n += 1 + self.lengthVarInt64(self.usage_version_)
+    if (self.has_versions_only_): n += 2
+    return n
+
+  def Clear(self):
+    self.clear_app_id()
+    self.clear_version_id()
+    self.clear_start_time()
+    self.clear_end_time()
+    self.clear_resolution_hours()
+    self.clear_combine_versions()
+    self.clear_usage_version()
+    self.clear_versions_only()
+
+  def OutputUnchecked(self, out):
+    out.putVarInt32(10)
+    out.putPrefixedString(self.app_id_)
+    for i in xrange(len(self.version_id_)):
+      out.putVarInt32(18)
+      out.putPrefixedString(self.version_id_[i])
+    if (self.has_start_time_):
+      out.putVarInt32(24)
+      out.putVarInt32(self.start_time_)
+    if (self.has_end_time_):
+      out.putVarInt32(32)
+      out.putVarInt32(self.end_time_)
+    if (self.has_resolution_hours_):
+      out.putVarInt32(40)
+      out.putVarUint64(self.resolution_hours_)
+    if (self.has_combine_versions_):
+      out.putVarInt32(48)
+      out.putBoolean(self.combine_versions_)
+    if (self.has_usage_version_):
+      out.putVarInt32(56)
+      out.putVarInt32(self.usage_version_)
+    if (self.has_versions_only_):
+      out.putVarInt32(64)
+      out.putBoolean(self.versions_only_)
+
+  def OutputPartial(self, out):
+    if (self.has_app_id_):
+      out.putVarInt32(10)
+      out.putPrefixedString(self.app_id_)
+    for i in xrange(len(self.version_id_)):
+      out.putVarInt32(18)
+      out.putPrefixedString(self.version_id_[i])
+    if (self.has_start_time_):
+      out.putVarInt32(24)
+      out.putVarInt32(self.start_time_)
+    if (self.has_end_time_):
+      out.putVarInt32(32)
+      out.putVarInt32(self.end_time_)
+    if (self.has_resolution_hours_):
+      out.putVarInt32(40)
+      out.putVarUint64(self.resolution_hours_)
+    if (self.has_combine_versions_):
+      out.putVarInt32(48)
+      out.putBoolean(self.combine_versions_)
+    if (self.has_usage_version_):
+      out.putVarInt32(56)
+      out.putVarInt32(self.usage_version_)
+    if (self.has_versions_only_):
+      out.putVarInt32(64)
+      out.putBoolean(self.versions_only_)
+
+  def TryMerge(self, d):
+    while d.avail() > 0:
+      tt = d.getVarInt32()
+      if tt == 10:
+        self.set_app_id(d.getPrefixedString())
+        continue
+      if tt == 18:
+        self.add_version_id(d.getPrefixedString())
+        continue
+      if tt == 24:
+        self.set_start_time(d.getVarInt32())
+        continue
+      if tt == 32:
+        self.set_end_time(d.getVarInt32())
+        continue
+      if tt == 40:
+        self.set_resolution_hours(d.getVarUint64())
+        continue
+      if tt == 48:
+        self.set_combine_versions(d.getBoolean())
+        continue
+      if tt == 56:
+        self.set_usage_version(d.getVarInt32())
+        continue
+      if tt == 64:
+        self.set_versions_only(d.getBoolean())
+        continue
+
+
+      if (tt == 0): raise ProtocolBuffer.ProtocolBufferDecodeError
+      d.skipData(tt)
+
+
+  def __str__(self, prefix="", printElemNumber=0):
+    res=""
+    if self.has_app_id_: res+=prefix+("app_id: %s\n" % self.DebugFormatString(self.app_id_))
+    cnt=0
+    for e in self.version_id_:
+      elm=""
+      if printElemNumber: elm="(%d)" % cnt
+      res+=prefix+("version_id%s: %s\n" % (elm, self.DebugFormatString(e)))
+      cnt+=1
+    if self.has_start_time_: res+=prefix+("start_time: %s\n" % self.DebugFormatInt32(self.start_time_))
+    if self.has_end_time_: res+=prefix+("end_time: %s\n" % self.DebugFormatInt32(self.end_time_))
+    if self.has_resolution_hours_: res+=prefix+("resolution_hours: %s\n" % self.DebugFormatInt64(self.resolution_hours_))
+    if self.has_combine_versions_: res+=prefix+("combine_versions: %s\n" % self.DebugFormatBool(self.combine_versions_))
+    if self.has_usage_version_: res+=prefix+("usage_version: %s\n" % self.DebugFormatInt32(self.usage_version_))
+    if self.has_versions_only_: res+=prefix+("versions_only: %s\n" % self.DebugFormatBool(self.versions_only_))
+    return res
+
+
+  def _BuildTagLookupTable(sparse, maxtag, default=None):
+    return tuple([sparse.get(i, default) for i in xrange(0, 1+maxtag)])
+
+  kapp_id = 1
+  kversion_id = 2
+  kstart_time = 3
+  kend_time = 4
+  kresolution_hours = 5
+  kcombine_versions = 6
+  kusage_version = 7
+  kversions_only = 8
+
+  _TEXT = _BuildTagLookupTable({
+    0: "ErrorCode",
+    1: "app_id",
+    2: "version_id",
+    3: "start_time",
+    4: "end_time",
+    5: "resolution_hours",
+    6: "combine_versions",
+    7: "usage_version",
+    8: "versions_only",
+  }, 8)
+
+  _TYPES = _BuildTagLookupTable({
+    0: ProtocolBuffer.Encoder.NUMERIC,
+    1: ProtocolBuffer.Encoder.STRING,
+    2: ProtocolBuffer.Encoder.STRING,
+    3: ProtocolBuffer.Encoder.NUMERIC,
+    4: ProtocolBuffer.Encoder.NUMERIC,
+    5: ProtocolBuffer.Encoder.NUMERIC,
+    6: ProtocolBuffer.Encoder.NUMERIC,
+    7: ProtocolBuffer.Encoder.NUMERIC,
+    8: ProtocolBuffer.Encoder.NUMERIC,
+  }, 8, ProtocolBuffer.Encoder.MAX_TYPE)
+
+
+  _STYLE = """"""
+  _STYLE_CONTENT_TYPE = """"""
+  _PROTO_DESCRIPTOR_NAME = 'apphosting.LogUsageRequest'
+class LogUsageResponse(ProtocolBuffer.ProtocolMessage):
+  has_summary_ = 0
+  summary_ = None
+
+  def __init__(self, contents=None):
+    self.usage_ = []
+    self.lazy_init_lock_ = thread.allocate_lock()
+    if contents is not None: self.MergeFromString(contents)
+
+  def usage_size(self): return len(self.usage_)
+  def usage_list(self): return self.usage_
+
+  def usage(self, i):
+    return self.usage_[i]
+
+  def mutable_usage(self, i):
+    return self.usage_[i]
+
+  def add_usage(self):
+    x = LogUsageRecord()
+    self.usage_.append(x)
+    return x
+
+  def clear_usage(self):
+    self.usage_ = []
+  def summary(self):
+    if self.summary_ is None:
+      self.lazy_init_lock_.acquire()
+      try:
+        if self.summary_ is None: self.summary_ = LogUsageRecord()
+      finally:
+        self.lazy_init_lock_.release()
+    return self.summary_
+
+  def mutable_summary(self): self.has_summary_ = 1; return self.summary()
+
+  def clear_summary(self):
+
+    if self.has_summary_:
+      self.has_summary_ = 0;
+      if self.summary_ is not None: self.summary_.Clear()
+
+  def has_summary(self): return self.has_summary_
+
+
+  def MergeFrom(self, x):
+    assert x is not self
+    for i in xrange(x.usage_size()): self.add_usage().CopyFrom(x.usage(i))
+    if (x.has_summary()): self.mutable_summary().MergeFrom(x.summary())
+
+  def Equals(self, x):
+    if x is self: return 1
+    if len(self.usage_) != len(x.usage_): return 0
+    for e1, e2 in zip(self.usage_, x.usage_):
+      if e1 != e2: return 0
+    if self.has_summary_ != x.has_summary_: return 0
+    if self.has_summary_ and self.summary_ != x.summary_: return 0
+    return 1
+
+  def IsInitialized(self, debug_strs=None):
+    initialized = 1
+    for p in self.usage_:
+      if not p.IsInitialized(debug_strs): initialized=0
+    if (self.has_summary_ and not self.summary_.IsInitialized(debug_strs)): initialized = 0
+    return initialized
+
+  def ByteSize(self):
+    n = 0
+    n += 1 * len(self.usage_)
+    for i in xrange(len(self.usage_)): n += self.lengthString(self.usage_[i].ByteSize())
+    if (self.has_summary_): n += 1 + self.lengthString(self.summary_.ByteSize())
+    return n
+
+  def ByteSizePartial(self):
+    n = 0
+    n += 1 * len(self.usage_)
+    for i in xrange(len(self.usage_)): n += self.lengthString(self.usage_[i].ByteSizePartial())
+    if (self.has_summary_): n += 1 + self.lengthString(self.summary_.ByteSizePartial())
+    return n
+
+  def Clear(self):
+    self.clear_usage()
+    self.clear_summary()
+
+  def OutputUnchecked(self, out):
+    for i in xrange(len(self.usage_)):
+      out.putVarInt32(10)
+      out.putVarInt32(self.usage_[i].ByteSize())
+      self.usage_[i].OutputUnchecked(out)
+    if (self.has_summary_):
+      out.putVarInt32(18)
+      out.putVarInt32(self.summary_.ByteSize())
+      self.summary_.OutputUnchecked(out)
+
+  def OutputPartial(self, out):
+    for i in xrange(len(self.usage_)):
+      out.putVarInt32(10)
+      out.putVarInt32(self.usage_[i].ByteSizePartial())
+      self.usage_[i].OutputPartial(out)
+    if (self.has_summary_):
+      out.putVarInt32(18)
+      out.putVarInt32(self.summary_.ByteSizePartial())
+      self.summary_.OutputPartial(out)
+
+  def TryMerge(self, d):
+    while d.avail() > 0:
+      tt = d.getVarInt32()
+      if tt == 10:
+        length = d.getVarInt32()
+        tmp = ProtocolBuffer.Decoder(d.buffer(), d.pos(), d.pos() + length)
+        d.skip(length)
+        self.add_usage().TryMerge(tmp)
+        continue
+      if tt == 18:
+        length = d.getVarInt32()
+        tmp = ProtocolBuffer.Decoder(d.buffer(), d.pos(), d.pos() + length)
+        d.skip(length)
+        self.mutable_summary().TryMerge(tmp)
+        continue
+
+
+      if (tt == 0): raise ProtocolBuffer.ProtocolBufferDecodeError
+      d.skipData(tt)
+
+
+  def __str__(self, prefix="", printElemNumber=0):
+    res=""
+    cnt=0
+    for e in self.usage_:
+      elm=""
+      if printElemNumber: elm="(%d)" % cnt
+      res+=prefix+("usage%s <\n" % elm)
+      res+=e.__str__(prefix + "  ", printElemNumber)
+      res+=prefix+">\n"
+      cnt+=1
+    if self.has_summary_:
+      res+=prefix+"summary <\n"
+      res+=self.summary_.__str__(prefix + "  ", printElemNumber)
+      res+=prefix+">\n"
+    return res
+
+
+  def _BuildTagLookupTable(sparse, maxtag, default=None):
+    return tuple([sparse.get(i, default) for i in xrange(0, 1+maxtag)])
+
+  kusage = 1
+  ksummary = 2
+
+  _TEXT = _BuildTagLookupTable({
+    0: "ErrorCode",
+    1: "usage",
+    2: "summary",
+  }, 2)
+
+  _TYPES = _BuildTagLookupTable({
+    0: ProtocolBuffer.Encoder.NUMERIC,
+    1: ProtocolBuffer.Encoder.STRING,
+    2: ProtocolBuffer.Encoder.STRING,
+  }, 2, ProtocolBuffer.Encoder.MAX_TYPE)
+
+
+  _STYLE = """"""
+  _STYLE_CONTENT_TYPE = """"""
+  _PROTO_DESCRIPTOR_NAME = 'apphosting.LogUsageResponse'
 if _extension_runtime:
   pass
 
-__all__ = ['LogServiceError','UserAppLogLine','UserAppLogGroup','FlushRequest','SetStatusRequest','LogOffset','LogLine','RequestLog','LogReadRequest','LogReadResponse']
+__all__ = ['LogServiceError','UserAppLogLine','UserAppLogGroup','FlushRequest','SetStatusRequest','LogOffset','LogLine','RequestLog','LogReadRequest','LogReadResponse','LogUsageRecord','LogUsageRequest','LogUsageResponse']
diff --git a/google/appengine/api/logservice/logservice.py b/google/appengine/api/logservice/logservice.py
index 5c458cc..bbda3af 100755
--- a/google/appengine/api/logservice/logservice.py
+++ b/google/appengine/api/logservice/logservice.py
@@ -44,6 +44,7 @@
 from google.appengine.api.logservice import log_service_pb
 from google.appengine.api.logservice import logsutil
 from google.appengine.datastore import datastore_rpc
+from google.appengine.runtime import apiproxy_errors
 
 
 AUTOFLUSH_ENABLED = True
@@ -423,8 +424,14 @@
     """
     response = log_service_pb.LogReadResponse()
 
-    apiproxy_stub_map.MakeSyncCall('logservice', 'Read', self._request,
-                                   response)
+    try:
+      apiproxy_stub_map.MakeSyncCall('logservice', 'Read', self._request,
+                                     response)
+    except apiproxy_errors.ApplicationError, e:
+      if e.application_error == log_service_pb.LogServiceError.INVALID_REQUEST:
+        raise InvalidArgumentError(e.error_detail)
+      raise Error(e.error_detail)
+
     self._logs = response.log_list()
     self._request.clear_offset()
     if response.has_offset():
@@ -654,7 +661,7 @@
 
   @property
   def task_name(self):
-    """The request's task name, if this generated via the Task Queue API.
+    """The request's task name, if generated via the Task Queue API.
 
     Returns:
        A string containing the request's task name if relevant, or None.
@@ -778,8 +785,9 @@
       results should be fetched for, in seconds since the Unix epoch.
     end_time: The latest request completion or last-update time that
       results should be fetched for, in seconds since the Unix epoch.
-    offset: A LogOffset protocol buffer previously returned by a query similar
-      to this one indicating a point in the result stream at which to continue.
+    offset: A byte string representing an offset into the log stream, extracted
+      from a previously emitted RequestLog.  This iterator will begin
+      immediately after the record from which the offset came.
     minimum_log_level: An application log level which serves as a filter on the
       requests returned--requests with no application log at or above the
       specified level will be omitted.  Works even if include_app_logs is not
@@ -804,7 +812,7 @@
       correct type.
   """
 
-  args_diff = set(kwargs.iterkeys()) - _FETCH_KWARGS
+  args_diff = set(kwargs) - _FETCH_KWARGS
   if args_diff:
     raise InvalidArgumentError('Invalid arguments: %s' % ', '.join(args_diff))
 
diff --git a/google/appengine/api/logservice/logservice_stub.py b/google/appengine/api/logservice/logservice_stub.py
index 558fa84..38f8f1e 100644
--- a/google/appengine/api/logservice/logservice_stub.py
+++ b/google/appengine/api/logservice/logservice_stub.py
@@ -165,7 +165,8 @@
 
 
     time_seconds = (self.end_time or self.start_time) / 10**6
-    date_string = time.strftime('%d/%b/%Y:%T %z', time.localtime(time_seconds))
+    date_string = time.strftime('%d/%b/%Y:%H:%M:%S %z',
+                                time.localtime(time_seconds))
     log.set_combined('%s - %s [%s] \"%s %s %s\" %d %d - \"%s\"' %
                      (self.ip, self.nickname, date_string, self.method,
                       self.resource, self.http_version, self.status or 0,
@@ -274,7 +275,7 @@
     now_time_usecs = self.get_time_now()
     log.request_id = str(now_time_usecs)
 
-    if start_time:
+    if start_time is not None:
       log.start_time = start_time
     else:
       log.start_time = now_time_usecs
diff --git a/google/appengine/api/queueinfo.py b/google/appengine/api/queueinfo.py
index dc90d9e..5258362 100755
--- a/google/appengine/api/queueinfo.py
+++ b/google/appengine/api/queueinfo.py
@@ -110,8 +110,8 @@
 A queue may optionally specify an acl (Access Control List).
   acl:
   - user_email: a@foo.com
-  - user_email: b@gmail.com
-Each user email must correspond to an account hosted by Google. The acl is
+  - writer_email: b@gmail.com
+Each email must correspond to an account hosted by Google. The acl is
 enforced for queue access from outside AppEngine.
 
 An app's queues are also subject to storage quota limits for their stored tasks,
@@ -173,6 +173,7 @@
 
 ACL = 'acl'
 USER_EMAIL = 'user_email'
+WRITER_EMAIL = 'writer_email'
 
 
 class MalformedQueueConfiguration(Exception):
@@ -193,7 +194,8 @@
 class Acl(validation.Validated):
   """Access control list for a single task queue."""
   ATTRIBUTES = {
-      USER_EMAIL: validation.TYPE_STR,
+      USER_EMAIL: validation.Optional(validation.TYPE_STR),
+      WRITER_EMAIL: validation.Optional(validation.TYPE_STR),
   }
 
 
diff --git a/google/appengine/api/rdbms_mysqldb.py b/google/appengine/api/rdbms_mysqldb.py
index 1beb129..f921db7 100755
--- a/google/appengine/api/rdbms_mysqldb.py
+++ b/google/appengine/api/rdbms_mysqldb.py
@@ -70,6 +70,16 @@
 
 
   __import__('MySQLdb.constants', globals(), locals(), ['*'])
+except ImportError:
+  logging.warning('The rdbms API is not available because the MySQLdb '
+                  'library could not be loaded.')
+
+
+  def connect(instance=None, database=None):
+    raise NotImplementedError(
+        'Unable to find the MySQLdb library. Please see the SDK '
+        'documentation for installation instructions.')
+else:
 
 
   def connect(instance=None, database=None, **kwargs):
@@ -88,17 +98,13 @@
             'Unable to find MySQL socket file.  Use --mysql_socket to '
             'specify its location manually.')
     logging.info('Connecting to MySQL with kwargs %r', merged_kwargs)
-    return MySQLdb.connect(**merged_kwargs)
-
-except ImportError:
-  logging.warning('The rdbms API is not available because the MySQLdb '
-                  'library could not be loaded.')
-
-
-  def connect(instance=None, database=None):
-    raise NotImplementedError(
-        'Unable to find the MySQLdb library. Please see the SDK '
-        'documentation for installation instructions.')
+    try:
+      return MySQLdb.connect(**merged_kwargs)
+    except MySQLdb.Error:
+      logging.critical(
+          'MySQL connection failed! Ensure that you have provided correct '
+          'values for the --mysql_* flags when running dev_appserver.py')
+      raise
 
 
 def set_instance(instance):
diff --git a/google/appengine/api/search/search.py b/google/appengine/api/search/search.py
index 344b7a7..8135c3f 100644
--- a/google/appengine/api/search/search.py
+++ b/google/appengine/api/search/search.py
@@ -77,7 +77,7 @@
 _MAXIMUM_FIELD_ATOM_LENGTH = 500
 _LANGUAGE_LENGTH = 2
 _MAXIMUM_FIELD_NAME_LENGTH = 500
-_MAXIMUM_CURSOR_LENGTH = 1000
+_MAXIMUM_CURSOR_LENGTH = 10000
 _MAXIMUM_DOCUMENT_ID_LENGTH = 500
 _MAXIMUM_STRING_LENGTH = 500
 _MAXIMUM_DOCS_PER_REQUEST = 200
diff --git a/google/appengine/api/user_service_stub.py b/google/appengine/api/user_service_stub.py
index 0a44fbe..030866b 100755
--- a/google/appengine/api/user_service_stub.py
+++ b/google/appengine/api/user_service_stub.py
@@ -49,13 +49,19 @@
                login_url=_DEFAULT_LOGIN_URL,
                logout_url=_DEFAULT_LOGOUT_URL,
                service_name='user',
-               auth_domain=_DEFAULT_AUTH_DOMAIN):
+               auth_domain=_DEFAULT_AUTH_DOMAIN,
+               http_server_address=None,
+               ):
     """Initializer.
 
     Args:
       login_url: String containing the URL to use for logging in.
       logout_url: String containing the URL to use for logging out.
       service_name: Service name expected for all calls.
+      auth_domain: The authentication domain for the service e.g. "gmail.com".
+      http_server_address: The address of the application's HTTP server e.g.
+          "localhost:8080". If this is not set then the SERVER_NAME and
+          SERVER_PORT environment variables are used.
 
     Note: Both the login_url and logout_url arguments must contain one format
     parameter, which will be replaced with the continuation URL where the user
@@ -65,6 +71,8 @@
     self.__num_requests = 0
     self._login_url = login_url
     self._logout_url = logout_url
+    self._http_server_address = http_server_address
+
 
 
 
@@ -133,9 +141,12 @@
     if host:
       return continue_url
 
-    host = os.environ['SERVER_NAME']
-    if os.environ['SERVER_PORT'] != '80':
-      host = host + ":" + os.environ['SERVER_PORT']
+    if self._http_server_address:
+      host = self._http_server_address
+    else:
+      host = os.environ['SERVER_NAME']
+      if os.environ['SERVER_PORT'] != '80':
+        host = host + ":" + os.environ['SERVER_PORT']
 
 
     if path == '':
diff --git a/google/appengine/datastore/datastore_pb.py b/google/appengine/datastore/datastore_pb.py
index 6b49027..02e6340 100644
--- a/google/appengine/datastore/datastore_pb.py
+++ b/google/appengine/datastore/datastore_pb.py
@@ -5698,6 +5698,7 @@
 
   def __init__(self, contents=None):
     self.result_ = []
+    self.index_ = []
     self.lazy_init_lock_ = thread.allocate_lock()
     if contents is not None: self.MergeFromString(contents)
 
@@ -5813,6 +5814,22 @@
 
   def has_compiled_cursor(self): return self.has_compiled_cursor_
 
+  def index_size(self): return len(self.index_)
+  def index_list(self): return self.index_
+
+  def index(self, i):
+    return self.index_[i]
+
+  def mutable_index(self, i):
+    return self.index_[i]
+
+  def add_index(self):
+    x = CompositeIndex()
+    self.index_.append(x)
+    return x
+
+  def clear_index(self):
+    self.index_ = []
 
   def MergeFrom(self, x):
     assert x is not self
@@ -5823,6 +5840,7 @@
     if (x.has_keys_only()): self.set_keys_only(x.keys_only())
     if (x.has_compiled_query()): self.mutable_compiled_query().MergeFrom(x.compiled_query())
     if (x.has_compiled_cursor()): self.mutable_compiled_cursor().MergeFrom(x.compiled_cursor())
+    for i in xrange(x.index_size()): self.add_index().CopyFrom(x.index(i))
 
   def Equals(self, x):
     if x is self: return 1
@@ -5841,6 +5859,9 @@
     if self.has_compiled_query_ and self.compiled_query_ != x.compiled_query_: return 0
     if self.has_compiled_cursor_ != x.has_compiled_cursor_: return 0
     if self.has_compiled_cursor_ and self.compiled_cursor_ != x.compiled_cursor_: return 0
+    if len(self.index_) != len(x.index_): return 0
+    for e1, e2 in zip(self.index_, x.index_):
+      if e1 != e2: return 0
     return 1
 
   def IsInitialized(self, debug_strs=None):
@@ -5854,6 +5875,8 @@
         debug_strs.append('Required field: more_results not set.')
     if (self.has_compiled_query_ and not self.compiled_query_.IsInitialized(debug_strs)): initialized = 0
     if (self.has_compiled_cursor_ and not self.compiled_cursor_.IsInitialized(debug_strs)): initialized = 0
+    for p in self.index_:
+      if not p.IsInitialized(debug_strs): initialized=0
     return initialized
 
   def ByteSize(self):
@@ -5865,6 +5888,8 @@
     if (self.has_keys_only_): n += 2
     if (self.has_compiled_query_): n += 1 + self.lengthString(self.compiled_query_.ByteSize())
     if (self.has_compiled_cursor_): n += 1 + self.lengthString(self.compiled_cursor_.ByteSize())
+    n += 1 * len(self.index_)
+    for i in xrange(len(self.index_)): n += self.lengthString(self.index_[i].ByteSize())
     return n + 2
 
   def ByteSizePartial(self):
@@ -5878,6 +5903,8 @@
     if (self.has_keys_only_): n += 2
     if (self.has_compiled_query_): n += 1 + self.lengthString(self.compiled_query_.ByteSizePartial())
     if (self.has_compiled_cursor_): n += 1 + self.lengthString(self.compiled_cursor_.ByteSizePartial())
+    n += 1 * len(self.index_)
+    for i in xrange(len(self.index_)): n += self.lengthString(self.index_[i].ByteSizePartial())
     return n
 
   def Clear(self):
@@ -5888,6 +5915,7 @@
     self.clear_keys_only()
     self.clear_compiled_query()
     self.clear_compiled_cursor()
+    self.clear_index()
 
   def OutputUnchecked(self, out):
     if (self.has_cursor_):
@@ -5914,6 +5942,10 @@
     if (self.has_skipped_results_):
       out.putVarInt32(56)
       out.putVarInt32(self.skipped_results_)
+    for i in xrange(len(self.index_)):
+      out.putVarInt32(66)
+      out.putVarInt32(self.index_[i].ByteSize())
+      self.index_[i].OutputUnchecked(out)
 
   def OutputPartial(self, out):
     if (self.has_cursor_):
@@ -5941,6 +5973,10 @@
     if (self.has_skipped_results_):
       out.putVarInt32(56)
       out.putVarInt32(self.skipped_results_)
+    for i in xrange(len(self.index_)):
+      out.putVarInt32(66)
+      out.putVarInt32(self.index_[i].ByteSizePartial())
+      self.index_[i].OutputPartial(out)
 
   def TryMerge(self, d):
     while d.avail() > 0:
@@ -5978,6 +6014,12 @@
       if tt == 56:
         self.set_skipped_results(d.getVarInt32())
         continue
+      if tt == 66:
+        length = d.getVarInt32()
+        tmp = ProtocolBuffer.Decoder(d.buffer(), d.pos(), d.pos() + length)
+        d.skip(length)
+        self.add_index().TryMerge(tmp)
+        continue
 
 
       if (tt == 0): raise ProtocolBuffer.ProtocolBufferDecodeError
@@ -6009,6 +6051,14 @@
       res+=prefix+"compiled_cursor <\n"
       res+=self.compiled_cursor_.__str__(prefix + "  ", printElemNumber)
       res+=prefix+">\n"
+    cnt=0
+    for e in self.index_:
+      elm=""
+      if printElemNumber: elm="(%d)" % cnt
+      res+=prefix+("index%s <\n" % elm)
+      res+=e.__str__(prefix + "  ", printElemNumber)
+      res+=prefix+">\n"
+      cnt+=1
     return res
 
 
@@ -6022,6 +6072,7 @@
   kkeys_only = 4
   kcompiled_query = 5
   kcompiled_cursor = 6
+  kindex = 8
 
   _TEXT = _BuildTagLookupTable({
     0: "ErrorCode",
@@ -6032,7 +6083,8 @@
     5: "compiled_query",
     6: "compiled_cursor",
     7: "skipped_results",
-  }, 7)
+    8: "index",
+  }, 8)
 
   _TYPES = _BuildTagLookupTable({
     0: ProtocolBuffer.Encoder.NUMERIC,
@@ -6043,7 +6095,8 @@
     5: ProtocolBuffer.Encoder.STRING,
     6: ProtocolBuffer.Encoder.STRING,
     7: ProtocolBuffer.Encoder.NUMERIC,
-  }, 7, ProtocolBuffer.Encoder.MAX_TYPE)
+    8: ProtocolBuffer.Encoder.STRING,
+  }, 8, ProtocolBuffer.Encoder.MAX_TYPE)
 
 
   _STYLE = """"""
diff --git a/google/appengine/datastore/datastore_query.py b/google/appengine/datastore/datastore_query.py
index b403846..6d3c719 100755
--- a/google/appengine/datastore/datastore_query.py
+++ b/google/appengine/datastore/datastore_query.py
@@ -1782,9 +1782,9 @@
     if not start_cursor and query_options.produce_cursors:
       start_cursor = Cursor()
 
-    batch0 = Batch(query_options, self, conn, start_cursor=start_cursor)
     req = self._to_pb(conn, query_options)
-    return batch0._make_query_result_rpc_call('RunQuery', query_options, req)
+    return Batch.create_async(self, query_options, conn, req,
+                              start_cursor=start_cursor)
 
   @classmethod
   def _from_pb(cls, query_pb):
@@ -2030,11 +2030,10 @@
     if not start_cursor and query_options.produce_cursors:
       start_cursor = Cursor()
 
-    batch0 = _AugmentedBatch(query_options, self, conn,
-                            in_memory_offset=in_memory_offset,
-                            in_memory_limit=in_memory_limit,
-                            start_cursor=start_cursor)
-    return batch0._make_query_result_rpc_call('RunQuery', query_options, req)
+    return _AugmentedBatch.create_async(self, query_options, conn, req,
+                                        in_memory_offset=in_memory_offset,
+                                        in_memory_limit=in_memory_limit,
+                                        start_cursor=start_cursor)
 
 
 @datastore_rpc._positional(1)
@@ -2089,6 +2088,63 @@
                          max_filtered_count=len(overriden_keys))
 
 
+class _BatchShared(object):
+  """Data shared among the batches of a query."""
+
+  def __init__(self, query, query_options, conn, augmented_query=None):
+    self.__query = query
+    self.__query_options = query_options
+    self.__conn = conn
+    self.__augmented_query = augmented_query
+    self.__was_first_result_processed = False
+
+  @property
+  def query(self):
+    return self.__query
+
+  @property
+  def query_options(self):
+    return self.__query_options
+
+  @property
+  def conn(self):
+    return self.__conn
+
+  @property
+  def augmented_query(self):
+    return self.__augmented_query
+
+  @property
+  def keys_only(self):
+    return self.__keys_only
+
+  @property
+  def compiled_query(self):
+    return self.__compiled_query
+
+  @property
+  def index_list(self):
+    """Returns the list of indexes used by the query.
+    Possibly None when the adapter does not implement pb_to_index.
+    """
+    return self.__index_list
+
+  def process_query_result_if_first(self, query_result):
+    if not self.__was_first_result_processed:
+      self.__was_first_result_processed = True
+      self.__keys_only = query_result.keys_only()
+      if query_result.has_compiled_query():
+        self.__compiled_query = query_result.compiled_query
+      else:
+        self.__compiled_query = None
+      try:
+        self.__index_list = [self.__conn.adapter.pb_to_index(index_pb)
+                             for index_pb in query_result.index_list()]
+      except NotImplementedError:
+
+        self.__index_list = None
+
+
 class Batch(object):
   """A batch of results returned by a query.
 
@@ -2125,9 +2181,16 @@
   offset or results needed). The Batcher class hides these limitations.
   """
 
-  @datastore_rpc._positional(4)
-  def __init__(self, query_options, query, conn,
-               start_cursor=Cursor(), _compiled_query=None):
+  @classmethod
+  @datastore_rpc._positional(5)
+  def create_async(cls, query, query_options, conn, req,
+                   start_cursor):
+    batch_shared = _BatchShared(query, query_options, conn)
+    batch0 = cls(batch_shared, start_cursor=start_cursor)
+    return batch0._make_query_result_rpc_call('RunQuery', query_options, req)
+
+  @datastore_rpc._positional(2)
+  def __init__(self, batch_shared, start_cursor=Cursor()):
     """Constructor.
 
     This class is constructed in stages (one when an RPC is sent and another
@@ -2138,28 +2201,23 @@
     This constructor does not perform verification.
 
     Args:
-      query_options: The QueryOptions used to run the given query.
-      query: The Query the batch is derived from.
-      conn: A datastore_rpc.Connection to use.
+      batch_shared: Data shared between batches for a a single query run.
       start_cursor: Optional cursor pointing before this batch.
     """
 
 
-    self.__query = query
-    self._conn = conn
-    self.__query_options = query_options
+    self._batch_shared = batch_shared
     self.__start_cursor = start_cursor
-    self._compiled_query = _compiled_query
 
   @property
   def query_options(self):
     """The QueryOptions used to retrieve the first batch."""
-    return self.__query_options
+    return self._batch_shared.query_options
 
   @property
   def query(self):
     """The query the current batch came from."""
-    return self.__query
+    return self._batch_shared.query
 
   @property
   def results(self):
@@ -2169,7 +2227,14 @@
   @property
   def keys_only(self):
     """Whether the entities in this batch only contain keys."""
-    return self.__keys_only
+    return self._batch_shared.keys_only
+
+  @property
+  def index_list(self):
+    """Returns the list of indexes used to peform this batch's query.
+    Possibly None when the adapter does not implement pb_to_index.
+    """
+    return self._batch_shared.index_list
 
   @property
   def start_cursor(self):
@@ -2212,6 +2277,9 @@
       return None
     return async.get_result()
 
+  def _compiled_query(self):
+    return self._batch_shared.compiled_query
+
   def cursor(self, index):
     """Gets the cursor that points to the result at the given index.
 
@@ -2242,7 +2310,8 @@
       return self.__start_cursor
     else:
       return self.__start_cursor.advance(index + self._skipped_results,
-                                         self.__query, self._conn)
+                                         self._batch_shared.query,
+                                         self._batch_shared.conn)
 
   def next_batch_async(self, fetch_options=None):
     """Asynchronously get the next batch or None if there are no more batches.
@@ -2262,7 +2331,7 @@
     fetch_options, next_batch = self._make_next_batch(fetch_options)
     req = self._to_pb(fetch_options)
 
-    config = self.__query_options.merge(fetch_options)
+    config = self._batch_shared.query_options.merge(fetch_options)
     return next_batch._make_query_result_rpc_call(
         'Next', config, req)
 
@@ -2270,13 +2339,13 @@
     req = datastore_pb.NextRequest()
 
     if FetchOptions.produce_cursors(fetch_options,
-                                    self.__query_options,
-                                    self._conn.config):
+                                    self._batch_shared.query_options,
+                                    self._batch_shared.conn.config):
       req.set_compile(True)
 
     count = FetchOptions.batch_size(fetch_options,
-                                    self.__query_options,
-                                    self._conn.config)
+                                    self._batch_shared.query_options,
+                                    self._batch_shared.conn.config)
     if count is not None:
       req.set_count(count)
 
@@ -2307,14 +2376,14 @@
     Returns:
       A UserRPC object that can be used to fetch the result of the RPC.
     """
-    return self._conn.make_rpc_call(config, name, req,
-                                    datastore_pb.QueryResult(),
-                                    self.__query_result_hook)
+    return self._batch_shared.conn.make_rpc_call(config, name, req,
+                                                 datastore_pb.QueryResult(),
+                                                 self.__query_result_hook)
 
   def __query_result_hook(self, rpc):
     """Internal method used as get_result_hook for RunQuery/Next operation."""
     try:
-      self._conn.check_rpc_success(rpc)
+      self._batch_shared.conn.check_rpc_success(rpc)
     except datastore_errors.NeedIndexError, exc:
 
       if isinstance(rpc.request, datastore_pb.Query):
@@ -2324,10 +2393,9 @@
             str(exc) + '\nThe suggested index for this query is:\n' + yaml)
       raise
     query_result = rpc.response
-    if query_result.has_compiled_query():
-      self._compiled_query = query_result.compiled_query
 
-    self.__keys_only = query_result.keys_only()
+    self._batch_shared.process_query_result_if_first(query_result)
+
     self.__end_cursor = Cursor._from_query_result(query_result)
     self._skipped_results = query_result.skipped_results()
 
@@ -2356,9 +2424,8 @@
       A tuple containing the fetch options that should be used internally and
       the object that should be used to contain the next batch.
     """
-    return fetch_options, Batch(self.__query_options, self.__query, self._conn,
-                                start_cursor=self.__end_cursor,
-                                _compiled_query=self._compiled_query)
+    return fetch_options, Batch(self._batch_shared,
+                                start_cursor=self.__end_cursor)
 
   def _process_results(self, results):
     """Converts the datastore results into results returned to the user.
@@ -2369,7 +2436,9 @@
     Returns:
       A list of results that should be returned to the user.
     """
-    return [self._conn.adapter.pb_to_query_result(result, self.__keys_only)
+    keys_only = self._batch_shared.keys_only
+    pb_to_query_result = self._batch_shared.conn.adapter.pb_to_query_result
+    return [pb_to_query_result(result, keys_only)
             for result in results]
 
   def __getstate__(self):
@@ -2380,21 +2449,33 @@
 class _AugmentedBatch(Batch):
   """A batch produced by a datastore_query._AugmentedQuery."""
 
-  @datastore_rpc._positional(4)
-  def __init__(self, query_options, augmented_query, conn,
-               in_memory_offset=None, in_memory_limit=None,
-               start_cursor=Cursor(), _compiled_query=None,
-               next_index=0):
+  @classmethod
+  @datastore_rpc._positional(5)
+  def create_async(cls, augmented_query, query_options, conn, req,
+                   in_memory_offset, in_memory_limit, start_cursor):
+    batch_shared = _BatchShared(augmented_query._query,
+                                query_options,
+                                conn,
+                                augmented_query)
+    batch0 = cls(batch_shared,
+                 in_memory_offset=in_memory_offset,
+                 in_memory_limit=in_memory_limit,
+                 start_cursor=start_cursor)
+    return batch0._make_query_result_rpc_call('RunQuery', query_options, req)
+
+  @datastore_rpc._positional(2)
+  def __init__(self, batch_shared,
+               in_memory_offset=None,
+               in_memory_limit=None,
+               next_index=0,
+               start_cursor=Cursor()):
     """A Constructor for datastore_query._AugmentedBatch.
 
     Constructed by datastore_query._AugmentedQuery. Should not be called
     directly.
     """
-    super(_AugmentedBatch, self).__init__(query_options, augmented_query._query,
-                                          conn,
-                                          start_cursor=start_cursor,
-                                          _compiled_query=_compiled_query)
-    self.__augmented_query = augmented_query
+    super(_AugmentedBatch, self).__init__(batch_shared,
+                                          start_cursor=start_cursor)
     self.__in_memory_offset = in_memory_offset
     self.__in_memory_limit = in_memory_limit
     self.__next_index = next_index
@@ -2402,7 +2483,7 @@
   @property
   def query(self):
     """The query the current batch came from."""
-    return self.__augmented_query
+    return self._batch_shared.augmented_query
 
   def cursor(self, index):
     raise NotImplementedError
@@ -2415,12 +2496,12 @@
 
   def _process_results(self, results):
 
-    in_memory_filter = self.__augmented_query._in_memory_filter
+    in_memory_filter = self._batch_shared.augmented_query._in_memory_filter
     if in_memory_filter:
       results = filter(in_memory_filter, results)
 
 
-    in_memory_results = self.__augmented_query._in_memory_results
+    in_memory_results = self._batch_shared.augmented_query._in_memory_results
     if in_memory_results and self.__next_index < len(in_memory_results):
 
       original_query = super(_AugmentedBatch, self).query
@@ -2466,18 +2547,17 @@
 
   def _make_next_batch(self, fetch_options):
     in_memory_offset = FetchOptions.offset(fetch_options)
-    if in_memory_offset and (self.__augmented_query._in_memory_filter or
-                             self.__augmented_query._in_memory_results):
+    augmented_query = self._batch_shared.augmented_query
+    if in_memory_offset and (augmented_query._in_memory_filter or
+                             augmented_query._in_memory_results):
       fetch_options = FetchOptions(offset=0)
     else:
       in_memory_offset = None
     return (fetch_options,
-            _AugmentedBatch(self.query_options, self.__augmented_query,
-                            self._conn,
+            _AugmentedBatch(self._batch_shared,
                             in_memory_offset=in_memory_offset,
                             in_memory_limit=self.__in_memory_limit,
                             start_cursor=self.end_cursor,
-                            _compiled_query=self._compiled_query,
                             next_index=self.__next_index))
 
 
@@ -2514,7 +2594,7 @@
     Args:
       query_options: The QueryOptions used to create the first batch.
       first_async_batch: The first batch produced by
-        Query.run_asyn(query_options).
+        Query.run_async(query_options).
     """
     self.__next_batch = first_async_batch
     self.__initial_offset = QueryOptions.offset(query_options) or 0
@@ -2617,7 +2697,7 @@
     """Constructor.
 
     Args:
-      batcher: A datastore_query.Bather
+      batcher: A datastore_query.Batcher
     """
     if not isinstance(batcher, Batcher):
       raise datastore_errors.BadArgumentError(
@@ -2628,13 +2708,21 @@
     self.__current_batch = None
     self.__current_pos = 0
 
+  def index_list(self):
+    """Returns the list of indexes used to perform the query.
+    Possibly None when the adapter does not implement pb_to_index.
+    """
+    return self._ensure_current_batch().index_list
+
   def cursor(self):
     """Returns a cursor that points just after the last result returned."""
+    return self._ensure_current_batch().cursor(self.__current_pos)
 
+  def _ensure_current_batch(self):
     if not self.__current_batch:
       self.__current_batch = self.__batcher.next()
       self.__current_pos = 0
-    return self.__current_batch.cursor(self.__current_pos)
+    return self.__current_batch
 
   def _compiled_query(self):
     """Returns the compiled query associated with the iterator.
@@ -2644,7 +2732,7 @@
     if not self.__current_batch:
       self.__current_batch = self.__batcher.next()
       self.__current_pos = 0
-    return self.__current_batch._compiled_query
+    return self.__current_batch._compiled_query()
 
 
   def next(self):
diff --git a/google/appengine/datastore/datastore_sqlite_stub.py b/google/appengine/datastore/datastore_sqlite_stub.py
index f5a897f..f9b0958 100644
--- a/google/appengine/datastore/datastore_sqlite_stub.py
+++ b/google/appengine/datastore/datastore_sqlite_stub.py
@@ -268,7 +268,7 @@
       for row in c.fetchall():
         kinds.append(MakeEntityForQuery(query, self.name, ToUtf8(row[0])))
 
-      cursor = datastore_stub_util._ExecuteQuery(kinds, query, [], [])
+      cursor = datastore_stub_util._ExecuteQuery(kinds, query, [], [], [])
     finally:
       self.sqlitestub._ReleaseConnection(conn)
 
@@ -389,7 +389,7 @@
       if property_pb:
         properties.append(property_pb)
 
-      cursor = datastore_stub_util._ExecuteQuery(properties, query, [], [])
+      cursor = datastore_stub_util._ExecuteQuery(properties, query, [], [], [])
     finally:
       self.sqlitestub._ReleaseConnection(conn)
 
@@ -446,7 +446,8 @@
           ns_id = datastore_types._EMPTY_NAMESPACE_ID
         namespace_entities.append(MakeEntityForQuery(query, self.name, ns_id))
 
-    return datastore_stub_util._ExecuteQuery(namespace_entities, query, [], [])
+    return datastore_stub_util._ExecuteQuery(namespace_entities, query,
+                                             [], [], [])
 
 
 class DatastoreSqliteStub(datastore_stub_util.BaseDatastore,
@@ -474,7 +475,8 @@
                verbose=False,
                service_name='datastore_v3',
                trusted=False,
-               consistency_policy=None):
+               consistency_policy=None,
+               root_path=None):
     """Constructor.
 
     Initializes the SQLite database if necessary.
@@ -492,12 +494,13 @@
       consistency_policy: The consistency policy to use or None to use the
         default. Consistency policies can be found in
         datastore_stub_util.*ConsistencyPolicy
+      root_path: string, the root path of the app.
     """
     datastore_stub_util.BaseDatastore.__init__(self, require_indexes,
                                                consistency_policy)
     apiproxy_stub.APIProxyStub.__init__(self, service_name)
     datastore_stub_util.DatastoreStub.__init__(self, weakref.proxy(self),
-                                               app_id, trusted)
+                                               app_id, trusted, root_path)
 
     self.__datastore_file = datastore_file
 
@@ -566,7 +569,6 @@
       self._ReleaseConnection(conn)
 
     self.__namespaces = set()
-    self.__query_history = {}
     self.__id_map = {}
     self.__Init()
 
@@ -824,11 +826,6 @@
 
     pb.Encode()
 
-  def QueryHistory(self):
-    """Returns a dict that maps Query PBs to times they've been run."""
-    return dict((pb, times) for pb, times in self.__query_history.items() if
-                pb.app() == self._app_id)
-
   def __GenerateFilterInfo(self, filters, query):
     """Transform a list of filters into a more usable form.
 
@@ -1162,7 +1159,7 @@
 
       self._ReleaseConnection(conn)
 
-  def _GetQueryCursor(self, query, filters, orders):
+  def _GetQueryCursor(self, query, filters, orders, index_list):
     """Returns a query cursor for the provided query.
 
     Args:
@@ -1199,23 +1196,12 @@
         db_cursor = conn.execute(sql_stmt, params)
         dsquery = datastore_stub_util._MakeQuery(query, filters, orders)
         cursor = datastore_stub_util.IteratorCursor(
-            query, dsquery, orders, _DedupingEntityIterator(db_cursor))
+            query, dsquery, orders, index_list,
+            _DedupingEntityIterator(db_cursor))
       finally:
         self._ReleaseConnection(conn)
     return cursor
 
-  def _Dynamic_RunQuery(self, query, query_result):
-    super(DatastoreSqliteStub, self)._Dynamic_RunQuery(query, query_result)
-
-
-    clone = datastore_pb.Query()
-    clone.CopyFrom(query)
-    clone.clear_hint()
-    clone.clear_limit()
-    clone.clear_count()
-    clone.clear_offset()
-    self.__query_history[clone] = self.__query_history.get(clone, 0) + 1
-
   def _AllocateIds(self, reference, size=1, max_id=None):
     conn = self._GetConnection()
     try:
diff --git a/google/appengine/datastore/datastore_stub_index.py b/google/appengine/datastore/datastore_stub_index.py
new file mode 100644
index 0000000..f41f6a7
--- /dev/null
+++ b/google/appengine/datastore/datastore_stub_index.py
@@ -0,0 +1,270 @@
+#!/usr/bin/env python
+#
+# Copyright 2007 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+
+
+
+"""Utilities for generating and updating index.yaml."""
+
+
+
+
+
+
+
+__all__ = ['GenerateIndexFromHistory',
+           'IndexYamlUpdater',
+          ]
+
+import os
+import logging
+
+from google.appengine.api import apiproxy_stub_map
+from google.appengine.api import yaml_errors
+from google.appengine.datastore import datastore_index
+
+import yaml
+
+
+AUTO_MARKER = '\n# AUTOGENERATED\n'
+
+
+AUTO_COMMENT = '''
+# This index.yaml is automatically updated whenever the dev_appserver
+# detects that a new type of query is run.  If you want to manage the
+# index.yaml file manually, remove the above marker line (the line
+# saying "# AUTOGENERATED").  If you want to manage some indexes
+# manually, move them above the marker line.  The index.yaml file is
+# automatically uploaded to the admin console when you next deploy
+# your application using appcfg.py.
+'''
+
+
+def GenerateIndexFromHistory(query_history,
+                             all_indexes=None, manual_indexes=None):
+  """Generate most of the text for index.yaml from the query history.
+
+  Args:
+    query_history: Query history, a dict mapping query
+    all_indexes: Optional datastore_index.IndexDefinitions instance
+      representing all the indexes found in the input file.  May be None.
+    manual_indexes: Optional datastore_index.IndexDefinitions instance
+      containing indexes for which we should not generate output.  May be None.
+
+  Returns:
+    A string representation that can safely be appended to an existing
+    index.yaml file. Returns the empty string if it would generate no output.
+  """
+
+
+
+
+
+  all_keys = datastore_index.IndexDefinitionsToKeys(all_indexes)
+  manual_keys = datastore_index.IndexDefinitionsToKeys(manual_indexes)
+
+
+  indexes = dict((key, 0) for key in all_keys - manual_keys)
+
+
+  for query, count in query_history.iteritems():
+    required, kind, ancestor, props, num_eq_filters = datastore_index.CompositeIndexForQuery(query)
+    if required:
+      key = (kind, ancestor, props)
+      if key not in manual_keys:
+        if key in indexes:
+          indexes[key] += count
+        else:
+          indexes[key] = count
+
+  if not indexes:
+    return ''
+
+
+
+
+  res = []
+  for (kind, ancestor, props), count in sorted(indexes.iteritems()):
+
+    res.append('')
+    res.append(datastore_index.IndexYamlForQuery(kind, ancestor, props))
+
+  res.append('')
+  return '\n'.join(res)
+
+
+class IndexYamlUpdater(object):
+  """Helper class for updating index.yaml.
+
+  This class maintains some state about the query history and the
+  index.yaml file in order to minimize the number of times index.yaml
+  is actually overwritten.
+  """
+
+
+  index_yaml_is_manual = False
+  index_yaml_mtime = None
+  last_history_size = 0
+
+  def __init__(self, root_path):
+    """Constructor.
+
+    Args:
+      root_path: Path to the app's root directory.
+    """
+    self.root_path = root_path
+
+  def UpdateIndexYaml(self, openfile=open):
+    """Update index.yaml.
+
+    Args:
+      openfile: Used for dependency injection.
+
+    We only ever write to index.yaml if either:
+    - it doesn't exist yet; or
+    - it contains an 'AUTOGENERATED' comment.
+
+    All indexes *before* the AUTOGENERATED comment will be written
+    back unchanged.  All indexes *after* the AUTOGENERATED comment
+    will be updated with the latest query counts (query counts are
+    reset by --clear_datastore).  Indexes that aren't yet in the file
+    will be appended to the AUTOGENERATED section.
+
+    We keep track of some data in order to avoid doing repetitive work:
+    - if index.yaml is fully manual, we keep track of its mtime to
+      avoid parsing it over and over;
+    - we keep track of the number of keys in the history dict since
+      the last time we updated index.yaml (or decided there was
+      nothing to update).
+    """
+
+    index_yaml_file = os.path.join(self.root_path, 'index.yaml')
+
+
+    try:
+      index_yaml_mtime = os.path.getmtime(index_yaml_file)
+    except os.error:
+      index_yaml_mtime = None
+
+
+    index_yaml_changed = (index_yaml_mtime != self.index_yaml_mtime)
+    self.index_yaml_mtime = index_yaml_mtime
+
+
+    datastore_stub = apiproxy_stub_map.apiproxy.GetStub('datastore_v3')
+    query_history = datastore_stub.QueryHistory()
+    history_changed = (len(query_history) != self.last_history_size)
+    self.last_history_size = len(query_history)
+
+
+    if not (index_yaml_changed or history_changed):
+      logging.debug('No need to update index.yaml')
+      return
+
+
+    if self.index_yaml_is_manual and not index_yaml_changed:
+      logging.debug('Will not update manual index.yaml')
+      return
+
+
+    if index_yaml_mtime is None:
+      index_yaml_data = None
+    else:
+      try:
+
+
+
+        fh = open(index_yaml_file, 'rU')
+      except IOError:
+        index_yaml_data = None
+      else:
+        try:
+          index_yaml_data = fh.read()
+        finally:
+          fh.close()
+
+
+    self.index_yaml_is_manual = (index_yaml_data is not None and
+                                 AUTO_MARKER not in index_yaml_data)
+    if self.index_yaml_is_manual:
+      logging.info('Detected manual index.yaml, will not update')
+      return
+
+
+
+    if index_yaml_data is None:
+      all_indexes = None
+    else:
+      try:
+        all_indexes = datastore_index.ParseIndexDefinitions(index_yaml_data)
+      except yaml_errors.EventListenerError, e:
+
+        logging.error('Error parsing %s:\n%s', index_yaml_file, e)
+        return
+      except Exception, err:
+
+        logging.error('Error parsing %s:\n%s.%s: %s', index_yaml_file,
+                      err.__class__.__module__, err.__class__.__name__, err)
+        return
+
+
+    if index_yaml_data is None:
+      manual_part, automatic_part = 'indexes:\n', ''
+      manual_indexes = None
+    else:
+      manual_part, automatic_part = index_yaml_data.split(AUTO_MARKER, 1)
+
+      try:
+        manual_indexes = datastore_index.ParseIndexDefinitions(manual_part)
+      except Exception, err:
+        logging.error('Error parsing manual part of %s: %s',
+                      index_yaml_file, err)
+        return
+
+
+    automatic_part = GenerateIndexFromHistory(query_history,
+                                              all_indexes, manual_indexes)
+
+
+
+    if index_yaml_mtime is None and automatic_part == '':
+      logging.debug('No need to update index.yaml')
+      return
+
+
+    try:
+      fh = openfile(index_yaml_file, 'w')
+    except IOError, err:
+      logging.error('Can\'t write index.yaml: %s', err)
+      return
+
+
+    try:
+      logging.info('Updating %s', index_yaml_file)
+      fh.write(manual_part)
+      fh.write(AUTO_MARKER)
+      fh.write(AUTO_COMMENT)
+      fh.write(automatic_part)
+    finally:
+      fh.close()
+
+
+    try:
+      self.index_yaml_mtime = os.path.getmtime(index_yaml_file)
+    except os.error, err:
+      logging.error('Can\'t stat index.yaml we just wrote: %s', err)
+      self.index_yaml_mtime = None
diff --git a/google/appengine/datastore/datastore_stub_util.py b/google/appengine/datastore/datastore_stub_util.py
index a8a9405..3d089a9 100644
--- a/google/appengine/datastore/datastore_stub_util.py
+++ b/google/appengine/datastore/datastore_stub_util.py
@@ -35,15 +35,18 @@
 import datetime
 import itertools
 import logging
+import os
 import random
 import struct
 import threading
 
 from google.appengine.api import api_base_pb
 from google.appengine.api import apiproxy_stub_map
+from google.appengine.api import datastore_admin
 from google.appengine.api import datastore_types
 from google.appengine.api.taskqueue import taskqueue_service_pb
 from google.appengine.datastore import datastore_index
+from google.appengine.datastore import datastore_stub_index
 from google.appengine.datastore import datastore_pb
 from google.appengine.datastore import datastore_query
 from google.appengine.runtime import apiproxy_errors
@@ -700,13 +703,15 @@
   _next_cursor = 1
   _next_cursor_lock = threading.Lock()
 
-  def __init__(self, query, dsquery, orders):
+  def __init__(self, query, dsquery, orders, index_list):
     """Constructor.
 
     Args:
       query: the query request proto.
       dsquery: a datastore_query.Query over query.
       orders: the orders of query as returned by _GuessOrders.
+      index_list: the list of indexes used by the query.
+
     """
 
     self.keys_only = query.keys_only()
@@ -717,8 +722,10 @@
         dsquery._filter_predicate)
     self.__order_property_names = set(
         order.property() for order in orders if order.property() != '__key__')
+    self.__index_list = index_list
 
-  def _PopulateResultMetadata(self, query_result, compile, last_result):
+  def _PopulateResultMetadata(self, query_result, compile,
+                              first_result, last_result):
     query_result.set_keys_only(self.keys_only)
     if query_result.more_results():
       cursor = query_result.mutable_cursor()
@@ -727,6 +734,8 @@
     if compile:
       self._EncodeCompiledCursor(last_result,
                                  query_result.mutable_compiled_cursor())
+    if first_result:
+      query_result.index_list().extend(self.__index_list)
 
   @classmethod
   def _AcquireCursorID(cls):
@@ -807,16 +816,17 @@
 class IteratorCursor(BaseCursor):
   """A query cursor over an entity iterator."""
 
-  def __init__(self, query, dsquery, orders, results):
+  def __init__(self, query, dsquery, orders, index_list, results):
     """Constructor.
 
     Args:
       query: the query request proto
       dsquery: a datastore_query.Query over query.
       orders: the orders of query as returned by _GuessOrders.
+      index_list: A list of indexes used by the query.
       results: iterator over datastore_pb.EntityProto
     """
-    super(IteratorCursor, self).__init__(query, dsquery, orders)
+    super(IteratorCursor, self).__init__(query, dsquery, orders, index_list)
 
     self.__last_result = None
     self.__next_result = None
@@ -885,7 +895,8 @@
     self.__offset += 1
     return self.__last_result
 
-  def PopulateQueryResult(self, result, count, offset, compile=False):
+  def PopulateQueryResult(self, result, count, offset,
+                          compile=False, first_result=False):
     """Populates a QueryResult with this cursor and the given number of results.
 
     Args:
@@ -893,6 +904,7 @@
       count: integer of how many results to return
       offset: integer of how many results to skip
       compile: boolean, whether we are compiling this query
+      first_result: whether the query result is the first for this query
     """
     skipped = 0
     try:
@@ -920,7 +932,8 @@
 
     result.set_more_results(not self.__done)
     result.set_skipped_results(skipped)
-    self._PopulateResultMetadata(result, compile, self.__last_result)
+    self._PopulateResultMetadata(result, compile,
+                                 first_result, self.__last_result)
 
 
 class ListCursor(BaseCursor):
@@ -930,16 +943,17 @@
     keys_only: whether the query is keys_only
   """
 
-  def __init__(self, query, dsquery, orders, results):
+  def __init__(self, query, dsquery, orders, index_list, results):
     """Constructor.
 
     Args:
       query: the query request proto
       dsquery: a datastore_query.Query over query.
       orders: the orders of query as returned by _GuessOrders.
+      index_list: the list of indexes used by the query.
       results: list of datastore_pb.EntityProto
     """
-    super(ListCursor, self).__init__(query, dsquery, orders)
+    super(ListCursor, self).__init__(query, dsquery, orders, index_list)
 
     if query.has_compiled_cursor() and query.compiled_cursor().position_list():
       start_cursor = self._DecodeCompiledCursor(query.compiled_cursor())
@@ -993,7 +1007,8 @@
         hi = mid
     return lo
 
-  def PopulateQueryResult(self, result, count, offset, compile=False):
+  def PopulateQueryResult(self, result, count, offset,
+                          compile=False, first_result=False):
     """Populates a QueryResult with this cursor and the given number of results.
 
     Args:
@@ -1001,6 +1016,7 @@
       count: integer of how many results to return
       offset: integer of how many results to skip
       compile: boolean, whether we are compiling this query
+      first_result: whether the query result is the first for this query
     """
 
     offset = min(offset, self.__count - self.__offset)
@@ -1028,7 +1044,8 @@
       self.__last_result = self.__results[self.__offset - 1]
 
     result.set_more_results(self.__offset < self.__count)
-    self._PopulateResultMetadata(result, compile, self.__last_result)
+    self._PopulateResultMetadata(result, compile,
+                                 first_result, self.__last_result)
 
 
 def _SynchronizeTxn(function):
@@ -1195,7 +1212,7 @@
     return LoadEntity(entity)
 
   @_SynchronizeTxn
-  def GetQueryCursor(self, query, filters, orders):
+  def GetQueryCursor(self, query, filters, orders, index_list):
     """Runs the given datastore_pb.Query and returns a QueryCursor for it.
 
     Does not see any modifications in the current txn.
@@ -1204,6 +1221,7 @@
       query: The datastore_pb.Query to run.
       filters: A list of filters that override the ones found on query.
       orders: A list of orders that override the ones found on query.
+      index_list: A list of indexes used by the query.
 
     Returns:
       A BaseCursor that can be used to fetch query results.
@@ -1211,7 +1229,7 @@
     Check(query.has_ancestor(),
           'Query must have an ancestor when performed in a transaction.')
     snapshot = self._GrabSnapshot(query.ancestor())
-    return _ExecuteQuery(snapshot.values(), query, filters, orders)
+    return _ExecuteQuery(snapshot.values(), query, filters, orders, index_list)
 
   @_SynchronizeTxn
   def Put(self, entity, insert):
@@ -1261,6 +1279,7 @@
             'transaction closed')
       self._state = self.ROLLEDBACK
     finally:
+      self._txn_manager._RemoveTxn(self)
 
       self._lock.release()
 
@@ -1324,6 +1343,7 @@
                           action, e)
       self._actions = []
     finally:
+      self._txn_manager._RemoveTxn(self)
 
       self._txn_manager._ReleaseWriteLocks(meta_data_list)
 
@@ -1774,8 +1794,8 @@
       meta_data._write_lock.release()
 
   def _RemoveTxn(self, txn):
-    """Removes a LiveTxn from the txn_map."""
-    del self._txn_map[id(txn)]
+    """Removes a LiveTxn from the txn_map (if present)."""
+    self._txn_map.pop(id(txn), None)
 
   def _Put(self, entity, insert):
     """Put the given entity.
@@ -2026,21 +2046,52 @@
     self._CheckHasIndex(raw_query, trusted, calling_app)
 
 
+    index_list = self.__IndexListForQuery(raw_query)
+
+
     if raw_query.has_transaction():
 
       Check(raw_query.kind() not in self._pseudo_kinds,
             'transactional queries on "%s" not allowed' % raw_query.kind())
       txn = self.GetTxn(raw_query.transaction(), trusted, calling_app)
-      return txn.GetQueryCursor(raw_query, filters, orders)
+      return txn.GetQueryCursor(raw_query, filters, orders, index_list)
 
     if raw_query.has_ancestor() and raw_query.kind() not in self._pseudo_kinds:
 
       txn = self._BeginTransaction(raw_query.app(), False)
-      return txn.GetQueryCursor(raw_query, filters, orders)
+      return txn.GetQueryCursor(raw_query, filters, orders, index_list)
 
 
     self.Groom()
-    return self._GetQueryCursor(raw_query, filters, orders)
+    return self._GetQueryCursor(raw_query, filters, orders, index_list)
+
+  def __IndexListForQuery(self, query):
+    """Get the single composite index pb used by the query, if any, as a list.
+
+    Args:
+      query: the datastore_pb.Query to compute the index list for
+
+    Returns:
+      A singleton list of the composite index pb used by the query,
+    """
+
+    required, kind, ancestor, props, _ = (
+        datastore_index.CompositeIndexForQuery(query))
+    if not required:
+      return []
+    composite_index_pb = entity_pb.CompositeIndex()
+    composite_index_pb.set_app_id(query.app())
+    composite_index_pb.set_id(0)
+    composite_index_pb.set_state(entity_pb.CompositeIndex.READ_WRITE)
+    index_pb = composite_index_pb.mutable_definition()
+    index_pb.set_entity_type(kind)
+    index_pb.set_ancestor(bool(ancestor))
+    for name, direction in props:
+      prop_pb = entity_pb.Index_Property()
+      prop_pb.set_name(name)
+      prop_pb.set_direction(direction)
+      index_pb.property_list().append(prop_pb)
+    return [composite_index_pb]
 
   def Get(self, raw_keys, transaction=None, eventual_consistency=False,
           trusted=False, calling_app=None):
@@ -2089,6 +2140,7 @@
 
 
       result = [None] * len(raw_keys)
+
       def op(txn, v):
         key, i = v
         result[i] = txn.Get(key)
@@ -2243,8 +2295,8 @@
 
     minimal_index = datastore_index.MinimalCompositeIndexForQuery(query,
         (datastore_index.ProtoToIndexDefinition(index)
-        for index in self.GetIndexes(query.app(), trusted, calling_app)
-        if index.state() == datastore_pb.CompositeIndex.READ_WRITE))
+         for index in self.GetIndexes(query.app(), trusted, calling_app)
+         if index.state() == datastore_pb.CompositeIndex.READ_WRITE))
     if minimal_index is not None:
       msg = ('This query requires a composite index that is not defined. '
           'You must update the index.yaml file in your application root.')
@@ -2260,7 +2312,7 @@
     """Writes the datastore to disk."""
     raise NotImplementedError
 
-  def _GetQueryCursor(self, query, filters, orders):
+  def _GetQueryCursor(self, query, filters, orders, index_list):
     """Runs the given datastore_pb.Query and returns a QueryCursor for it.
 
     This must be implemented by a sub-class. The sub-class does not need to
@@ -2270,6 +2322,7 @@
       query: The datastore_pb.Query to run.
       filters: A list of filters that override the ones found on query.
       orders: A list of orders that override the ones found on query.
+      index_list: A list of indexes used by the query.
 
     Returns:
       A BaseCursor that can be used to fetch query results.
@@ -2304,6 +2357,24 @@
     raise NotImplementedError
 
 
+def _NeedsIndexes(func):
+  """A decorator for DatastoreStub methods that require or affect indexes.
+
+  Updates indexes to match index.yaml before the call and updates index.yaml
+  after the call if require_indexes is False. If root_path is not set, this is a
+  no op.
+  """
+
+  def UpdateIndexesWrapper(self, *args, **kwargs):
+    self._SetupIndexes()
+    try:
+      return func(self, *args, **kwargs)
+    finally:
+      self._UpdateIndexes()
+
+  return UpdateIndexesWrapper
+
+
 class DatastoreStub(object):
   """A stub that maps datastore service calls on to a BaseDatastore.
 
@@ -2313,16 +2384,41 @@
   def __init__(self,
                datastore,
                app_id=None,
-               trusted=None):
+               trusted=None,
+               root_path=None):
     super(DatastoreStub, self).__init__()
     self._datastore = datastore
     self._app_id = datastore_types.ResolveAppId(app_id)
     self._trusted = trusted
+    self._root_path = root_path
+
+
+    self.__query_history = {}
+
+
+
+    self._cached_yaml = (None, None, None)
+
+    if self._require_indexes or root_path is None:
+
+      self._index_yaml_updater = None
+    else:
+
+      self._index_yaml_updater = datastore_stub_index.IndexYamlUpdater(
+          root_path)
+
     DatastoreStub.Clear(self)
 
   def Clear(self):
     """Clears out all stored values."""
     self._query_cursors = {}
+    self.__query_history = {}
+
+  def QueryHistory(self):
+    """Returns a dict that maps Query PBs to times they've been run."""
+
+    return dict((pb, times) for pb, times in self.__query_history.items()
+                if pb.app() == self._app_id)
 
   def SetTrusted(self, trusted):
     """Set/clear the trusted bit in the stub.
@@ -2361,7 +2457,20 @@
   def _Dynamic_Touch(self, req, _):
     self._datastore.Touch(req.key_list(), self._trusted, self._app_id)
 
+  @_NeedsIndexes
   def _Dynamic_RunQuery(self, query, query_result):
+
+    clone = datastore_pb.Query()
+    clone.CopyFrom(query)
+    clone.clear_hint()
+    clone.clear_limit()
+    clone.clear_offset()
+    clone.clear_count()
+    if clone in self.__query_history:
+      self.__query_history[clone] += 1
+    else:
+      self.__query_history[clone] = 1
+
     cursor = self._datastore.GetQueryCursor(query, self._trusted, self._app_id)
 
     if query.has_count():
@@ -2372,7 +2481,7 @@
       count = self._BATCH_SIZE
 
     cursor.PopulateQueryResult(query_result, count, query.offset(),
-                               query.compile())
+                               query.compile(), first_result=True)
     if query_result.has_cursor():
       self._query_cursors[query_result.cursor().cursor()] = cursor
 
@@ -2398,7 +2507,7 @@
       count = next_request.count()
 
     cursor.PopulateQueryResult(query_result, count, next_request.offset(),
-                               next_request.compile())
+                               next_request.compile(), first_result=False)
 
     if not query_result.has_cursor():
       del self._query_cursors[next_request.cursor().cursor()]
@@ -2453,6 +2562,7 @@
                                                       self._trusted,
                                                       self._app_id))
 
+  @_NeedsIndexes
   def _Dynamic_GetIndices(self, app_str, composite_indices):
     composite_indices.index_list().extend(self._datastore.GetIndexes(
         app_str.value(), self._trusted, self._app_id))
@@ -2476,6 +2586,78 @@
     allocate_ids_response.set_start(start)
     allocate_ids_response.set_end(end)
 
+  def _SetupIndexes(self):
+    """Ensure that the set of existing composite indexes matches index.yaml.
+
+    Note: this is similar to the algorithm used by the admin console for
+    the same purpose.
+    """
+    if not self._root_path:
+      return
+    index_yaml_file = os.path.join(self._root_path, 'index.yaml')
+    if (self._cached_yaml[0] == index_yaml_file and
+        os.path.exists(index_yaml_file) and
+        os.path.getmtime(index_yaml_file) == self._cached_yaml[1]):
+      requested_indexes = self._cached_yaml[2]
+    else:
+      try:
+        index_yaml_mtime = os.path.getmtime(index_yaml_file)
+        fh = open(index_yaml_file, 'r')
+      except (OSError, IOError):
+        index_yaml_data = None
+      else:
+        try:
+          index_yaml_data = fh.read()
+        finally:
+          fh.close()
+
+      requested_indexes = []
+      if index_yaml_data is not None:
+
+        index_defs = datastore_index.ParseIndexDefinitions(index_yaml_data)
+        if index_defs is not None and index_defs.indexes is not None:
+
+          requested_indexes = datastore_index.IndexDefinitionsToProtos(
+              self._app_id,
+              index_defs.indexes)
+          self._cached_yaml = (index_yaml_file, index_yaml_mtime,
+                               requested_indexes)
+
+
+    existing_indexes = self._datastore.GetIndexes(
+        self._app_id, self._trusted, self._app_id)
+
+
+    requested = dict((x.definition().Encode(), x) for x in requested_indexes)
+    existing = dict((x.definition().Encode(), x) for x in existing_indexes)
+
+
+    created = 0
+    for key, index in requested.iteritems():
+      if key not in existing:
+        new_index = entity_pb.CompositeIndex()
+        new_index.CopyFrom(index)
+        new_index.set_id(datastore_admin.CreateIndex(new_index))
+        new_index.set_state(entity_pb.CompositeIndex.READ_WRITE)
+        datastore_admin.UpdateIndex(new_index)
+        created += 1
+
+
+    deleted = 0
+    for key, index in existing.iteritems():
+      if key not in requested:
+        datastore_admin.DeleteIndex(index)
+        deleted += 1
+
+
+    if created or deleted:
+      logging.info('Created %d and deleted %d index(es); total %d',
+                   created, deleted, len(requested))
+
+  def _UpdateIndexes(self):
+    if self._index_yaml_updater is not None:
+      self._index_yaml_updater.UpdateIndexYaml()
+
 
 def CompareEntityPbByKey(a, b):
   """Compare two entity protobuf's by key.
@@ -2535,7 +2717,7 @@
   return datastore_query.Query._from_pb(clone)
 
 
-def _ExecuteQuery(results, query, filters, orders):
+def _ExecuteQuery(results, query, filters, orders, index_list):
   """Executes the query on a superset of its results.
 
   Args:
@@ -2543,11 +2725,13 @@
     query: a datastore_pb.Query.
     filters: the filters from query.
     orders: the orders from query.
+    index_list: the list of indexes used by the query.
+
 
   Returns:
     A ListCursor over the results of applying query to results.
   """
   orders = _GuessOrders(filters, orders)
   dsquery = _MakeQuery(query, filters, orders)
-  return ListCursor(query, dsquery, orders,
+  return ListCursor(query, dsquery, orders, index_list,
                     datastore_query.apply_query(dsquery, results))
diff --git a/google/appengine/dist/_library.py b/google/appengine/dist/_library.py
index 7389f9e..289d8c9 100755
--- a/google/appengine/dist/_library.py
+++ b/google/appengine/dist/_library.py
@@ -145,6 +145,37 @@
   pass
 
 
+
+class LooseVersion(object):
+  """Shallow class compatible with distutils.version.LooseVersion."""
+
+  def __init__(self, version):
+    """Create a new instance of LooseVersion.
+
+    Args:
+      version: iterable containing the version values.
+    """
+    self.version = tuple(map(str, version))
+
+  def __repr__(self):
+    return '.'.join(self.version)
+
+  def __str__(self):
+    return '.'.join(self.version)
+
+  @classmethod
+  def parse(cls, string):
+    """Parse a version string and create a new LooseVersion instance.
+
+    Args:
+      string: dot delimited version string.
+
+    Returns:
+      A distutils.version.LooseVersion compatible object.
+    """
+    return cls(string.split('.'))
+
+
 def DjangoVersion():
   """Discover the version of Django installed.
 
@@ -157,7 +188,11 @@
   except ImportError:
     pass
   import django
-  return distutils.version.LooseVersion('.'.join(map(str, django.VERSION)))
+  try:
+    return distutils.version.LooseVersion('.'.join(map(str, django.VERSION)))
+  except AttributeError:
+
+    return LooseVersion(django.VERSION)
 
 
 def PylonsVersion():
@@ -294,7 +329,12 @@
     global _DESIRED_DJANGO_VERSION
     _DESIRED_DJANGO_VERSION = 'v' + desired.replace('.', '_')
   installed_version = find_version()
-  desired_version = distutils.version.LooseVersion(desired)
+  try:
+    desired_version = distutils.version.LooseVersion(desired)
+  except AttributeError:
+
+    desired_version = LooseVersion.parse(desired)
+
   if not EqualVersions(installed_version, desired_version):
     raise UnacceptableVersionError(
         '%s %s was requested, but %s is already in use' %
diff --git a/google/appengine/ext/appstats/static/appstats_js.js b/google/appengine/ext/appstats/static/appstats_js.js
index 79f46c3..ab9333c 100755
--- a/google/appengine/ext/appstats/static/appstats_js.js
+++ b/google/appengine/ext/appstats/static/appstats_js.js
@@ -1,79 +1,77 @@
 /* Copyright 2008-10 Google Inc. All Rights Reserved. */ (function(){function e(a){throw a;}
-var h=void 0,j=!0,k=null,n=!1,o,p=this,aa=function(a,b){var c=a.split("."),d=p;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var f;c.length&&(f=c.shift());)!c.length&&b!==h?d[f]=b:d=d[f]?d[f]:d[f]={}},ba=function(a){a.P=function(){return a.$b||(a.$b=new a)}},ca=function(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==
+var h=void 0,j=!0,k=null,n=!1,o,p=this,aa=function(a,b){var c=a.split("."),d=p;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var f;c.length&&(f=c.shift());)!c.length&&b!==h?d[f]=b:d=d[f]?d[f]:d[f]={}},ba=function(a){a.P=function(){return a.Zb||(a.Zb=new a)}},ca=function(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==
 typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==c||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null";else if("function"==b&&"undefined"==typeof a.call)return"object";return b},da=function(a){return"array"==ca(a)},ea=function(a){var b=ca(a);return"array"==b||"object"==b&&"number"==typeof a.length},
-q=function(a){return"string"==typeof a},r=function(a){return"function"==ca(a)},fa=function(a){a=ca(a);return"object"==a||"array"==a||"function"==a},u=function(a){return a[ga]||(a[ga]=++ha)},ga="closure_uid_"+Math.floor(2147483648*Math.random()).toString(36),ha=0,ia=function(a,b){var c=Array.prototype.slice.call(arguments,1);return function(){var b=Array.prototype.slice.call(arguments);b.unshift.apply(b,c);return a.apply(this,b)}},v=function(a,b){function c(){}c.prototype=b.prototype;a.d=b.prototype;
-a.prototype=new c;a.prototype.constructor=a};var ja=function(a){this.stack=Error().stack||"";if(a)this.message=""+a};v(ja,Error);ja.prototype.name="CustomError";var ka=function(a,b){for(var c=1;c<arguments.length;c++)var d=(""+arguments[c]).replace(/\$/g,"$$$$"),a=a.replace(/\%s/,d);return a},la=function(a){return a.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")},ra=function(a){if(!ma.test(a))return a;-1!=a.indexOf("&")&&(a=a.replace(na,"&amp;"));-1!=a.indexOf("<")&&(a=a.replace(oa,"&lt;"));-1!=a.indexOf(">")&&(a=a.replace(pa,"&gt;"));-1!=a.indexOf('"')&&(a=a.replace(qa,"&quot;"));return a},na=/&/g,oa=/</g,pa=/>/g,qa=/\"/g,ma=/[&<>\"]/;var sa=function(a,b){b.unshift(a);ja.call(this,ka.apply(k,b));b.shift();this.nc=a};v(sa,ja);sa.prototype.name="AssertionError";var w=function(a,b,c){if(!a){var d=Array.prototype.slice.call(arguments,2),f="Assertion failed";if(b)var f=f+(": "+b),g=d;e(new sa(""+f,g||[]))}};var x=Array.prototype,ta=x.indexOf?function(a,b,c){w(a.length!=k);return x.indexOf.call(a,b,c)}:function(a,b,c){c=c==k?0:0>c?Math.max(0,a.length+c):c;if(q(a))return!q(b)||1!=b.length?-1:a.indexOf(b,c);for(;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1},ua=x.forEach?function(a,b,c){w(a.length!=k);x.forEach.call(a,b,c)}:function(a,b,c){for(var d=a.length,f=q(a)?a.split(""):a,g=0;g<d;g++)g in f&&b.call(c,f[g],g,a)},va=x.every?function(a,b,c){w(a.length!=k);return x.every.call(a,b,c)}:function(a,
+q=function(a){return"string"==typeof a},r=function(a){return"function"==ca(a)},fa=function(a){var b=typeof a;return"object"==b&&a!=k||"function"==b},u=function(a){return a[ga]||(a[ga]=++ha)},ga="closure_uid_"+Math.floor(2147483648*Math.random()).toString(36),ha=0,ia=function(a,b){var c=Array.prototype.slice.call(arguments,1);return function(){var b=Array.prototype.slice.call(arguments);b.unshift.apply(b,c);return a.apply(this,b)}},v=function(a,b){function c(){}c.prototype=b.prototype;a.d=b.prototype;
+a.prototype=new c;a.prototype.constructor=a};var ja=function(a){this.stack=Error().stack||"";a&&(this.message=""+a)};v(ja,Error);ja.prototype.name="CustomError";var ka=function(a,b){for(var c=1;c<arguments.length;c++)var d=(""+arguments[c]).replace(/\$/g,"$$$$"),a=a.replace(/\%s/,d);return a},la=function(a){return a.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")},ra=function(a){if(!ma.test(a))return a;-1!=a.indexOf("&")&&(a=a.replace(na,"&amp;"));-1!=a.indexOf("<")&&(a=a.replace(oa,"&lt;"));-1!=a.indexOf(">")&&(a=a.replace(pa,"&gt;"));-1!=a.indexOf('"')&&(a=a.replace(qa,"&quot;"));return a},na=/&/g,oa=/</g,pa=/>/g,qa=/\"/g,ma=/[&<>\"]/;var sa=function(a,b){b.unshift(a);ja.call(this,ka.apply(k,b));b.shift()};v(sa,ja);sa.prototype.name="AssertionError";var w=function(a,b,c){if(!a){var d=Array.prototype.slice.call(arguments,2),f="Assertion failed";if(b)var f=f+(": "+b),g=d;e(new sa(""+f,g||[]))}};var x=Array.prototype,ta=x.indexOf?function(a,b,c){w(a.length!=k);return x.indexOf.call(a,b,c)}:function(a,b,c){c=c==k?0:0>c?Math.max(0,a.length+c):c;if(q(a))return!q(b)||1!=b.length?-1:a.indexOf(b,c);for(;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1},ua=x.forEach?function(a,b,c){w(a.length!=k);x.forEach.call(a,b,c)}:function(a,b,c){for(var d=a.length,f=q(a)?a.split(""):a,g=0;g<d;g++)g in f&&b.call(c,f[g],g,a)},va=x.every?function(a,b,c){w(a.length!=k);return x.every.call(a,b,c)}:function(a,
 b,c){for(var d=a.length,f=q(a)?a.split(""):a,g=0;g<d;g++)if(g in f&&!b.call(c,f[g],g,a))return n;return j},wa=function(a,b){return 0<=ta(a,b)},xa=function(a,b){var c=ta(a,b);0<=c&&(w(a.length!=k),x.splice.call(a,c,1))},ya=function(a){return x.concat.apply(x,arguments)},za=function(a){if(da(a))return ya(a);for(var b=[],c=0,d=a.length;c<d;c++)b[c]=a[c];return b},Ba=function(a,b,c,d){w(a.length!=k);x.splice.apply(a,Aa(arguments,1))},Aa=function(a,b,c){w(a.length!=k);return 2>=arguments.length?x.slice.call(a,
-b):x.slice.call(a,b,c)};var Ca=function(a,b){for(var c in a)b.call(h,a[c],c,a)},Da=function(a,b,c){b in a&&e(Error('The object already contains the key "'+b+'"'));a[b]=c},Ea=function(a){var b={},c;for(c in a)b[a[c]]=c;return b},Fa="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(","),Ga=function(a,b){for(var c,d,f=1;f<arguments.length;f++){d=arguments[f];for(c in d)a[c]=d[c];for(var g=0;g<Fa.length;g++)c=Fa[g],Object.prototype.hasOwnProperty.call(d,c)&&(a[c]=d[c])}};var Ha,Ia,Ja,Ka,La=function(){return p.navigator?p.navigator.userAgent:k};Ka=Ja=Ia=Ha=n;var Ma;if(Ma=La()){var Na=p.navigator;Ha=0==Ma.indexOf("Opera");Ia=!Ha&&-1!=Ma.indexOf("MSIE");Ja=!Ha&&-1!=Ma.indexOf("WebKit");Ka=!Ha&&!Ja&&"Gecko"==Na.product}var Oa=Ha,y=Ia,A=Ka,B=Ja,Pa=p.navigator,Qa=-1!=(Pa&&Pa.platform||"").indexOf("Mac"),Sa;
+b):x.slice.call(a,b,c)};var Ca=function(a,b){for(var c in a)b.call(h,a[c],c,a)},Da=function(a,b,c){b in a&&e(Error('The object already contains the key "'+b+'"'));a[b]=c},Ea=function(a){var b={},c;for(c in a)b[a[c]]=c;return b},Fa="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(","),Ga=function(a,b){for(var c,d,f=1;f<arguments.length;f++){d=arguments[f];for(c in d)a[c]=d[c];for(var g=0;g<Fa.length;g++)c=Fa[g],Object.prototype.hasOwnProperty.call(d,c)&&(a[c]=d[c])}};var Ha,Ia,Ja,Ka,La=function(){return p.navigator?p.navigator.userAgent:k};Ka=Ja=Ia=Ha=n;var Ma;if(Ma=La()){var Na=p.navigator;Ha=0==Ma.indexOf("Opera");Ia=!Ha&&-1!=Ma.indexOf("MSIE");Ja=!Ha&&-1!=Ma.indexOf("WebKit");Ka=!Ha&&!Ja&&"Gecko"==Na.product}var Oa=Ha,y=Ia,A=Ka,B=Ja,Pa=p.navigator,Ra=-1!=(Pa&&Pa.platform||"").indexOf("Mac"),Sa;
 a:{var Ta="",Ua;if(Oa&&p.opera)var Va=p.opera.version,Ta="function"==typeof Va?Va():Va;else if(A?Ua=/rv\:([^\);]+)(\)|;)/:y?Ua=/MSIE\s+([^\);]+)(\)|;)/:B&&(Ua=/WebKit\/(\S+)/),Ua)var Wa=Ua.exec(La()),Ta=Wa?Wa[1]:"";if(y){var Xa,Ya=p.document;Xa=Ya?Ya.documentMode:h;if(Xa>parseFloat(Ta)){Sa=""+Xa;break a}}Sa=Ta}
 var Za=Sa,$a={},C=function(a){var b;if(!(b=$a[a])){b=0;for(var c=la(""+Za).split("."),d=la(""+a).split("."),f=Math.max(c.length,d.length),g=0;0==b&&g<f;g++){var i=c[g]||"",l=d[g]||"",m=RegExp("(\\d*)(\\D*)","g"),s=RegExp("(\\d*)(\\D*)","g");do{var z=m.exec(i)||["","",""],t=s.exec(l)||["","",""];if(0==z[0].length&&0==t[0].length)break;b=((0==z[1].length?0:parseInt(z[1],10))<(0==t[1].length?0:parseInt(t[1],10))?-1:(0==z[1].length?0:parseInt(z[1],10))>(0==t[1].length?0:parseInt(t[1],10))?1:0)||((0==
-z[2].length)<(0==t[2].length)?-1:(0==z[2].length)>(0==t[2].length)?1:0)||(z[2]<t[2]?-1:z[2]>t[2]?1:0)}while(0==b)}b=$a[a]=0<=b}return b},ab={},bb=function(){return ab[9]||(ab[9]=y&&document.documentMode&&9<=document.documentMode)};var cb,db=!y||bb();!A&&!y||y&&bb()||A&&C("1.9.1");var eb=y&&!C("9");var fb=function(a){return(a=a.className)&&"function"==typeof a.split?a.split(/\s+/):[]},D=function(a,b){var c=fb(a),d=Aa(arguments,1),f;f=c;for(var g=0,i=0;i<d.length;i++)wa(f,d[i])||(f.push(d[i]),g++);f=g==d.length;a.className=c.join(" ");return f},gb=function(a,b){var c=fb(a),d=Aa(arguments,1),f;f=c;for(var g=0,i=0;i<f.length;i++)wa(d,f[i])&&(Ba(f,i--,1),g++);f=g==d.length;a.className=c.join(" ");return f};var jb=function(a){return a?new hb(ib(a)):cb||(cb=new hb)},kb=function(a){return q(a)?document.getElementById(a):a},lb=function(a,b,c){c=c||document;a=a&&"*"!=a?a.toUpperCase():"";if(c.querySelectorAll&&c.querySelector&&(!B||"CSS1Compat"==document.compatMode||C("528"))&&(a||b))return c.querySelectorAll(a+(b?"."+b:""));if(b&&c.getElementsByClassName){c=c.getElementsByClassName(b);if(a){for(var d={},f=0,g=0,i;i=c[g];g++)a==i.nodeName&&(d[f++]=i);d.length=f;return d}return c}c=c.getElementsByTagName(a||
+z[2].length)<(0==t[2].length)?-1:(0==z[2].length)>(0==t[2].length)?1:0)||(z[2]<t[2]?-1:z[2]>t[2]?1:0)}while(0==b)}b=$a[a]=0<=b}return b},ab={},bb=function(){return ab[9]||(ab[9]=y&&!!document.documentMode&&9<=document.documentMode)};var cb,db=!y||bb();!A&&!y||y&&bb()||A&&C("1.9.1");var eb=y&&!C("9");var fb=function(a){return(a=a.className)&&"function"==typeof a.split?a.split(/\s+/):[]},D=function(a,b){var c=fb(a),d=Aa(arguments,1),f;f=c;for(var g=0,i=0;i<d.length;i++)wa(f,d[i])||(f.push(d[i]),g++);f=g==d.length;a.className=c.join(" ");return f},gb=function(a,b){var c=fb(a),d=Aa(arguments,1),f;f=c;for(var g=0,i=0;i<f.length;i++)wa(d,f[i])&&(Ba(f,i--,1),g++);f=g==d.length;a.className=c.join(" ");return f};var jb=function(a){return a?new hb(ib(a)):cb||(cb=new hb)},kb=function(a){return q(a)?document.getElementById(a):a},lb=function(a,b,c){c=c||document;a=a&&"*"!=a?a.toUpperCase():"";if(c.querySelectorAll&&c.querySelector&&(!B||"CSS1Compat"==document.compatMode||C("528"))&&(a||b))return c.querySelectorAll(a+(b?"."+b:""));if(b&&c.getElementsByClassName){c=c.getElementsByClassName(b);if(a){for(var d={},f=0,g=0,i;i=c[g];g++)a==i.nodeName&&(d[f++]=i);d.length=f;return d}return c}c=c.getElementsByTagName(a||
 "*");if(b){d={};for(g=f=0;i=c[g];g++)a=i.className,"function"==typeof a.split&&wa(a.split(/\s+/),b)&&(d[f++]=i);d.length=f;return d}return c},nb=function(a,b){Ca(b,function(b,d){"style"==d?a.style.cssText=b:"class"==d?a.className=b:"for"==d?a.htmlFor=b:d in mb?a.setAttribute(mb[d],b):0==d.lastIndexOf("aria-",0)?a.setAttribute(d,b):a[d]=b})},mb={cellpadding:"cellPadding",cellspacing:"cellSpacing",colspan:"colSpan",rowspan:"rowSpan",valign:"vAlign",height:"height",width:"width",usemap:"useMap",frameborder:"frameBorder",
-maxlength:"maxLength",type:"type"},pb=function(a,b,c){return ob(document,arguments)},ob=function(a,b){var c=b[0],d=b[1];if(!db&&d&&(d.name||d.type)){c=["<",c];d.name&&c.push(' name="',ra(d.name),'"');if(d.type){c.push(' type="',ra(d.type),'"');var f={};Ga(f,d);d=f;delete d.type}c.push(">");c=c.join("")}c=a.createElement(c);if(d)q(d)?c.className=d:da(d)?D.apply(k,[c].concat(d)):nb(c,d);2<b.length&&qb(a,c,b);return c},qb=function(a,b,c){function d(c){c&&b.appendChild(q(c)?a.createTextNode(c):c)}for(var f=
+maxlength:"maxLength",type:"type"},pb=function(a,b,c){return ob(document,arguments)},ob=function(a,b){var c=b[0],d=b[1];if(!db&&d&&(d.name||d.type)){c=["<",c];d.name&&c.push(' name="',ra(d.name),'"');if(d.type){c.push(' type="',ra(d.type),'"');var f={};Ga(f,d);d=f;delete d.type}c.push(">");c=c.join("")}c=a.createElement(c);d&&(q(d)?c.className=d:da(d)?D.apply(k,[c].concat(d)):nb(c,d));2<b.length&&qb(a,c,b);return c},qb=function(a,b,c){function d(c){c&&b.appendChild(q(c)?a.createTextNode(c):c)}for(var f=
 2;f<c.length;f++){var g=c[f];if(ea(g)&&!(fa(g)&&0<g.nodeType)){var i;a:{if(g&&"number"==typeof g.length){if(fa(g)){i="function"==typeof g.item||"string"==typeof g.item;break a}if(r(g)){i="function"==typeof g.item;break a}}i=n}ua(i?za(g):g,d)}else d(g)}},rb=function(a){a&&a.parentNode&&a.parentNode.removeChild(a)},sb=function(a){for(;a&&1!=a.nodeType;)a=a.nextSibling;return a},tb=function(a,b){if(a.contains&&1==b.nodeType)return a==b||a.contains(b);if("undefined"!=typeof a.compareDocumentPosition)return a==
 b||Boolean(a.compareDocumentPosition(b)&16);for(;b&&a!=b;)b=b.parentNode;return b==a},ib=function(a){return 9==a.nodeType?a:a.ownerDocument||a.document},ub=function(a,b){if("textContent"in a)a.textContent=b;else if(a.firstChild&&3==a.firstChild.nodeType){for(;a.lastChild!=a.firstChild;)a.removeChild(a.lastChild);a.firstChild.data=b}else{for(var c;c=a.firstChild;)a.removeChild(c);a.appendChild(ib(a).createTextNode(b))}},vb={SCRIPT:1,STYLE:1,HEAD:1,IFRAME:1,OBJECT:1},wb={IMG:" ",BR:"\n"},xb=function(a){var b=
 a.getAttributeNode("tabindex");return b&&b.specified?(a=a.tabIndex,"number"==typeof a&&0<=a&&32768>a):n},yb=function(a,b,c){if(!(a.nodeName in vb))if(3==a.nodeType)c?b.push((""+a.nodeValue).replace(/(\r\n|\r|\n)/g,"")):b.push(a.nodeValue);else if(a.nodeName in wb)b.push(wb[a.nodeName]);else for(a=a.firstChild;a;)yb(a,b,c),a=a.nextSibling},hb=function(a){this.C=a||p.document||document};o=hb.prototype;o.Ia=jb;o.a=function(a){return q(a)?this.C.getElementById(a):a};
-o.l=function(a,b,c){return ob(this.C,arguments)};o.createElement=function(a){return this.C.createElement(a)};o.createTextNode=function(a){return this.C.createTextNode(a)};o.appendChild=function(a,b){a.appendChild(b)};o.contains=tb;var zb=function(a){zb[" "](a);return a};zb[" "]=function(){};var Ab=!y||bb(),Bb=!y||bb(),Cb=y&&!C("8");!B||C("528");A&&C("1.9b")||y&&C("8")||Oa&&C("9.5")||B&&C("528");!A||C("8");var Db=function(){};Db.prototype.bb=n;Db.prototype.I=function(){if(!this.bb)this.bb=j,this.f()};Db.prototype.f=function(){this.hc&&Eb.apply(k,this.hc)};var Fb=function(a){a&&"function"==typeof a.I&&a.I()},Eb=function(a){for(var b=0,c=arguments.length;b<c;++b){var d=arguments[b];ea(d)?Eb.apply(k,d):Fb(d)}};var E=function(a,b){this.type=a;this.currentTarget=this.target=b};v(E,Db);o=E.prototype;o.f=function(){delete this.type;delete this.target;delete this.currentTarget};o.ba=n;o.ua=j;o.stopPropagation=function(){this.ba=j};o.preventDefault=function(){this.ua=n};var F=function(a,b){a&&this.sa(a,b)};v(F,E);var Gb=[1,4,2];o=F.prototype;o.target=k;o.relatedTarget=k;o.offsetX=0;o.offsetY=0;o.clientX=0;o.clientY=0;o.screenX=0;o.screenY=0;o.button=0;o.keyCode=0;o.charCode=0;o.ctrlKey=n;o.altKey=n;o.shiftKey=n;o.metaKey=n;o.cb=n;o.L=k;
-o.sa=function(a,b){var c=this.type=a.type;E.call(this,c);this.target=a.target||a.srcElement;this.currentTarget=b;var d=a.relatedTarget;if(d){if(A){var f;a:{try{zb(d.nodeName);f=j;break a}catch(g){}f=n}f||(d=k)}}else if("mouseover"==c)d=a.fromElement;else if("mouseout"==c)d=a.toElement;this.relatedTarget=d;this.offsetX=B||a.offsetX!==h?a.offsetX:a.layerX;this.offsetY=B||a.offsetY!==h?a.offsetY:a.layerY;this.clientX=a.clientX!==h?a.clientX:a.pageX;this.clientY=a.clientY!==h?a.clientY:a.pageY;this.screenX=
-a.screenX||0;this.screenY=a.screenY||0;this.button=a.button;this.keyCode=a.keyCode||0;this.charCode=a.charCode||("keypress"==c?a.keyCode:0);this.ctrlKey=a.ctrlKey;this.altKey=a.altKey;this.shiftKey=a.shiftKey;this.metaKey=a.metaKey;this.cb=Qa?a.metaKey:a.ctrlKey;this.state=a.state;this.L=a;delete this.ua;delete this.ba};var Hb=function(a){return Ab?0==a.L.button:"click"==a.type?j:!!(a.L.button&Gb[0])};
+o.k=function(a,b,c){return ob(this.C,arguments)};o.createElement=function(a){return this.C.createElement(a)};o.createTextNode=function(a){return this.C.createTextNode(a)};o.appendChild=function(a,b){a.appendChild(b)};o.contains=tb;var zb=function(a){zb[" "](a);return a};zb[" "]=function(){};var Ab=!y||bb(),Bb=!y||bb(),Cb=y&&!C("8");!B||C("528");A&&C("1.9b")||y&&C("8")||Oa&&C("9.5")||B&&C("528");!A||C("8");var Db=function(){};Db.prototype.bb=n;Db.prototype.I=function(){this.bb||(this.bb=j,this.f())};Db.prototype.f=function(){this.gc&&Eb.apply(k,this.gc)};var Fb=function(a){a&&"function"==typeof a.I&&a.I()},Eb=function(a){for(var b=0,c=arguments.length;b<c;++b){var d=arguments[b];ea(d)?Eb.apply(k,d):Fb(d)}};var E=function(a,b){this.type=a;this.currentTarget=this.target=b};v(E,Db);o=E.prototype;o.f=function(){delete this.type;delete this.target;delete this.currentTarget};o.ba=n;o.ua=j;o.stopPropagation=function(){this.ba=j};o.preventDefault=function(){this.ua=n};var F=function(a,b){a&&this.sa(a,b)};v(F,E);var Gb=[1,4,2];o=F.prototype;o.target=k;o.relatedTarget=k;o.offsetX=0;o.offsetY=0;o.clientX=0;o.clientY=0;o.screenX=0;o.screenY=0;o.button=0;o.keyCode=0;o.charCode=0;o.ctrlKey=n;o.altKey=n;o.shiftKey=n;o.metaKey=n;o.cb=n;o.L=k;
+o.sa=function(a,b){var c=this.type=a.type;E.call(this,c);this.target=a.target||a.srcElement;this.currentTarget=b;var d=a.relatedTarget;if(d){if(A){var f;a:{try{zb(d.nodeName);f=j;break a}catch(g){}f=n}f||(d=k)}}else"mouseover"==c?d=a.fromElement:"mouseout"==c&&(d=a.toElement);this.relatedTarget=d;this.offsetX=B||a.offsetX!==h?a.offsetX:a.layerX;this.offsetY=B||a.offsetY!==h?a.offsetY:a.layerY;this.clientX=a.clientX!==h?a.clientX:a.pageX;this.clientY=a.clientY!==h?a.clientY:a.pageY;this.screenX=a.screenX||
+0;this.screenY=a.screenY||0;this.button=a.button;this.keyCode=a.keyCode||0;this.charCode=a.charCode||("keypress"==c?a.keyCode:0);this.ctrlKey=a.ctrlKey;this.altKey=a.altKey;this.shiftKey=a.shiftKey;this.metaKey=a.metaKey;this.cb=Ra?a.metaKey:a.ctrlKey;this.state=a.state;this.L=a;delete this.ua;delete this.ba};var Hb=function(a){return Ab?0==a.L.button:"click"==a.type?j:!!(a.L.button&Gb[0])};
 F.prototype.stopPropagation=function(){F.d.stopPropagation.call(this);this.L.stopPropagation?this.L.stopPropagation():this.L.cancelBubble=j};F.prototype.preventDefault=function(){F.d.preventDefault.call(this);var a=this.L;if(a.preventDefault)a.preventDefault();else if(a.returnValue=n,Cb)try{if(a.ctrlKey||112<=a.keyCode&&123>=a.keyCode)a.keyCode=-1}catch(b){}};F.prototype.f=function(){F.d.f.call(this);this.relatedTarget=this.currentTarget=this.target=this.L=k};var Ib=function(){},Jb=0;o=Ib.prototype;o.key=0;o.aa=n;o.Eb=n;o.sa=function(a,b,c,d,f,g){r(a)?this.Cb=j:a&&a.handleEvent&&r(a.handleEvent)?this.Cb=n:e(Error("Invalid listener argument"));this.fa=a;this.vb=b;this.src=c;this.type=d;this.capture=!!f;this.Da=g;this.Eb=n;this.key=++Jb;this.aa=n};o.handleEvent=function(a){return this.Cb?this.fa.call(this.Da||this.src,a):this.fa.handleEvent.call(this.fa,a)};var Kb={},G={},H={},Lb={},I=function(a,b,c,d,f){if(b){if(da(b)){for(var g=0;g<b.length;g++)I(a,b[g],c,d,f);return k}var d=!!d,i=G;b in i||(i[b]={G:0,w:0});i=i[b];d in i||(i[d]={G:0,w:0},i.G++);var i=i[d],l=u(a),m;i.w++;if(i[l]){m=i[l];for(g=0;g<m.length;g++)if(i=m[g],i.fa==c&&i.Da==f){if(i.aa)break;return m[g].key}}else m=i[l]=[],i.G++;g=Mb();g.src=a;i=new Ib;i.sa(c,g,a,b,d,f);c=i.key;g.key=c;m.push(i);Kb[c]=i;H[l]||(H[l]=[]);H[l].push(i);a.addEventListener?(a==p||!a.ub)&&a.addEventListener(b,g,d):
 a.attachEvent(b in Lb?Lb[b]:Lb[b]="on"+b,g);return c}e(Error("Invalid event type"))},Mb=function(){var a=Nb,b=Bb?function(c){return a.call(b.src,b.key,c)}:function(c){c=a.call(b.src,b.key,c);if(!c)return c};return b},Ob=function(a,b,c,d,f){if(da(b))for(var g=0;g<b.length;g++)Ob(a,b[g],c,d,f);else if(d=!!d,a=Pb(a,b,d))for(g=0;g<a.length;g++)if(a[g].fa==c&&a[g].capture==d&&a[g].Da==f){J(a[g].key);break}},J=function(a){if(!Kb[a])return n;var b=Kb[a];if(b.aa)return n;var c=b.src,d=b.type,f=b.vb,g=b.capture;
 c.removeEventListener?(c==p||!c.ub)&&c.removeEventListener(d,f,g):c.detachEvent&&c.detachEvent(d in Lb?Lb[d]:Lb[d]="on"+d,f);c=u(c);f=G[d][g][c];if(H[c]){var i=H[c];xa(i,b);0==i.length&&delete H[c]}b.aa=j;f.Ab=j;Qb(d,g,c,f);delete Kb[a];return j},Qb=function(a,b,c,d){if(!d.Ja&&d.Ab){for(var f=0,g=0;f<d.length;f++)d[f].aa?d[f].vb.src=k:(f!=g&&(d[g]=d[f]),g++);d.length=g;d.Ab=n;0==g&&(delete G[a][b][c],G[a][b].G--,0==G[a][b].G&&(delete G[a][b],G[a].G--),0==G[a].G&&delete G[a])}},Rb=function(a){var b,
 c=0,d=b==k;b=!!b;if(a==k)Ca(H,function(a){for(var f=a.length-1;0<=f;f--){var g=a[f];if(d||b==g.capture)J(g.key),c++}});else if(a=u(a),H[a])for(var a=H[a],f=a.length-1;0<=f;f--){var g=a[f];if(d||b==g.capture)J(g.key),c++}},Pb=function(a,b,c){var d=G;return b in d&&(d=d[b],c in d&&(d=d[c],a=u(a),d[a]))?d[a]:k},Tb=function(a,b,c,d,f){var g=1,b=u(b);if(a[b]){a.w--;a=a[b];a.Ja?a.Ja++:a.Ja=1;try{for(var i=a.length,l=0;l<i;l++){var m=a[l];m&&!m.aa&&(g&=Sb(m,f)!==n)}}finally{a.Ja--,Qb(c,d,b,a)}}return Boolean(g)},
-Sb=function(a,b){var c=a.handleEvent(b);a.Eb&&J(a.key);return c},Nb=function(a,b){if(!Kb[a])return j;var c=Kb[a],d=c.type,f=G;if(!(d in f))return j;var f=f[d],g,i;if(!Bb){var l;if(!(l=b))a:{l="window.event".split(".");for(var m=p;g=l.shift();)if(m[g]!=k)m=m[g];else{l=k;break a}l=m}g=l;l=j in f;m=n in f;if(l){if(0>g.keyCode||g.returnValue!=h)return j;a:{var s=n;if(0==g.keyCode)try{g.keyCode=-1;break a}catch(z){s=j}if(s||g.returnValue==h)g.returnValue=j}}s=new F;s.sa(g,this);g=j;try{if(l){for(var t=
-[],Ra=s.currentTarget;Ra;Ra=Ra.parentNode)t.push(Ra);i=f[j];i.w=i.G;for(var S=t.length-1;!s.ba&&0<=S&&i.w;S--)s.currentTarget=t[S],g&=Tb(i,t[S],d,j,s);if(m){i=f[n];i.w=i.G;for(S=0;!s.ba&&S<t.length&&i.w;S++)s.currentTarget=t[S],g&=Tb(i,t[S],d,n,s)}}else g=Sb(c,s)}finally{if(t)t.length=0;s.I()}return g}d=new F(b,this);try{g=Sb(c,d)}finally{d.I()}return g};var K=function(a){this.Fb=a;this.La=[]};v(K,Db);var Ub=[],L=function(a,b,c,d){da(c)||(Ub[0]=c,c=Ub);for(var f=0;f<c.length;f++)a.La.push(I(b,c[f],d||a,n,a.Fb||a));return a},M=function(a,b,c,d,f,g){if(da(c))for(var i=0;i<c.length;i++)M(a,b,c[i],d,f,g);else{a:{d=d||a;g=g||a.Fb||a;f=!!f;if(b=Pb(b,c,f))for(c=0;c<b.length;c++)if(!b[c].aa&&b[c].fa==d&&b[c].capture==f&&b[c].Da==g){b=b[c];break a}b=k}if(b)b=b.key,J(b),xa(a.La,b)}return a},Vb=function(a){ua(a.La,J);a.La.length=0};
+Sb=function(a,b){var c=a.handleEvent(b);a.Eb&&J(a.key);return c},Nb=function(a,b){if(!Kb[a])return j;var c=Kb[a],d=c.type,f=G;if(!(d in f))return j;var f=f[d],g,i;if(!Bb){var l;if(!(l=b))a:{l=["window","event"];for(var m=p;g=l.shift();)if(m[g]!=k)m=m[g];else{l=k;break a}l=m}g=l;l=j in f;m=n in f;if(l){if(0>g.keyCode||g.returnValue!=h)return j;a:{var s=n;if(0==g.keyCode)try{g.keyCode=-1;break a}catch(z){s=j}if(s||g.returnValue==h)g.returnValue=j}}s=new F;s.sa(g,this);g=j;try{if(l){for(var t=[],Qa=
+s.currentTarget;Qa;Qa=Qa.parentNode)t.push(Qa);i=f[j];i.w=i.G;for(var S=t.length-1;!s.ba&&0<=S&&i.w;S--)s.currentTarget=t[S],g&=Tb(i,t[S],d,j,s);if(m){i=f[n];i.w=i.G;for(S=0;!s.ba&&S<t.length&&i.w;S++)s.currentTarget=t[S],g&=Tb(i,t[S],d,n,s)}}else g=Sb(c,s)}finally{t&&(t.length=0),s.I()}return g}d=new F(b,this);try{g=Sb(c,d)}finally{d.I()}return g};var K=function(a){this.Fb=a;this.La=[]};v(K,Db);var Ub=[],L=function(a,b,c,d){da(c)||(Ub[0]=c,c=Ub);for(var f=0;f<c.length;f++)a.La.push(I(b,c[f],d||a,n,a.Fb||a));return a},M=function(a,b,c,d,f,g){if(da(c))for(var i=0;i<c.length;i++)M(a,b,c[i],d,f,g);else{a:{d=d||a;g=g||a.Fb||a;f=!!f;if(b=Pb(b,c,f))for(c=0;c<b.length;c++)if(!b[c].aa&&b[c].fa==d&&b[c].capture==f&&b[c].Da==g){b=b[c];break a}b=k}b&&(b=b.key,J(b),xa(a.La,b))}return a},Vb=function(a){ua(a.La,J);a.La.length=0};
 K.prototype.f=function(){K.d.f.call(this);Vb(this)};K.prototype.handleEvent=function(){e(Error("EventHandler.handleEvent not implemented"))};var Wb=function(){};v(Wb,Db);o=Wb.prototype;o.ub=j;o.Ca=k;o.eb=function(a){this.Ca=a};o.addEventListener=function(a,b,c,d){I(this,a,b,c,d)};o.removeEventListener=function(a,b,c,d){Ob(this,a,b,c,d)};
 o.dispatchEvent=function(a){var b=a.type||a,c=G;if(b in c){if(q(a))a=new E(a,this);else if(a instanceof E)a.target=a.target||this;else{var d=a,a=new E(b,this);Ga(a,d)}var d=1,f,c=c[b],b=j in c,g;if(b){f=[];for(g=this;g;g=g.Ca)f.push(g);g=c[j];g.w=g.G;for(var i=f.length-1;!a.ba&&0<=i&&g.w;i--)a.currentTarget=f[i],d&=Tb(g,f[i],a.type,j,a)&&a.ua!=n}if(n in c)if(g=c[n],g.w=g.G,b)for(i=0;!a.ba&&i<f.length&&g.w;i++)a.currentTarget=f[i],d&=Tb(g,f[i],a.type,n,a)&&a.ua!=n;else for(f=this;!a.ba&&f&&g.w;f=f.Ca)a.currentTarget=
-f,d&=Tb(g,f,a.type,n,a)&&a.ua!=n;a=Boolean(d)}else a=j;return a};o.f=function(){Wb.d.f.call(this);Rb(this);this.Ca=k};var Xb=function(a,b){a.style.display=b?"":"none"},Yb=A?"MozUserSelect":B?"WebkitUserSelect":k,Zb=function(a,b,c){c=!c?a.getElementsByTagName("*"):k;if(Yb){if(b=b?"none":"",a.style[Yb]=b,c)for(var a=0,d;d=c[a];a++)d.style[Yb]=b}else if(y||Oa)if(b=b?"on":"",a.setAttribute("unselectable",b),c)for(a=0;d=c[a];a++)d.setAttribute("unselectable",b)};var $b=function(){};ba($b);$b.prototype.Zb=0;$b.P();var N=function(a){this.m=a||jb();this.ra=ac};v(N,Wb);N.prototype.Yb=$b.P();var ac=k,bc=function(a,b){switch(a){case 1:return b?"disable":"enable";case 2:return b?"highlight":"unhighlight";case 4:return b?"activate":"deactivate";case 8:return b?"select":"unselect";case 16:return b?"check":"uncheck";case 32:return b?"focus":"blur";case 64:return b?"open":"close"}e(Error("Invalid component state"))};o=N.prototype;o.ga=k;o.e=n;o.c=k;o.ra=k;o.Nb=k;o.q=k;o.r=k;o.t=k;o.mb=n;
-var cc=function(a){return a.ga||(a.ga=":"+(a.Yb.Zb++).toString(36))},dc=function(a,b){if(a.q&&a.q.t){var c=a.q.t,d=a.ga;d in c&&delete c[d];Da(a.q.t,b,a)}a.ga=b};N.prototype.a=function(){return this.c};var ec=function(a){return a.da||(a.da=new K(a))},gc=function(a,b){a==b&&e(Error("Unable to set parent component"));b&&a.q&&a.ga&&fc(a.q,a.ga)&&a.q!=b&&e(Error("Unable to set parent component"));a.q=b;N.d.eb.call(a,b)};o=N.prototype;o.getParent=function(){return this.q};
-o.eb=function(a){this.q&&this.q!=a&&e(Error("Method not supported"));N.d.eb.call(this,a)};o.Ia=function(){return this.m};o.l=function(){this.c=this.m.createElement("div")};o.K=function(a){this.e&&e(Error("Component already rendered"));if(a&&this.$(a)){this.mb=j;if(!this.m||this.m.C!=ib(a))this.m=jb(a);this.Va(a);this.s()}else e(Error("Invalid element to decorate"))};o.$=function(){return j};o.Va=function(a){this.c=a};o.s=function(){this.e=j;hc(this,function(a){!a.e&&a.a()&&a.s()})};
-o.U=function(){hc(this,function(a){a.e&&a.U()});this.da&&Vb(this.da);this.e=n};o.f=function(){N.d.f.call(this);this.e&&this.U();this.da&&(this.da.I(),delete this.da);hc(this,function(a){a.I()});!this.mb&&this.c&&rb(this.c);this.q=this.Nb=this.c=this.t=this.r=k};o.Ba=function(a,b){this.Sa(a,ic(this),b)};
-o.Sa=function(a,b,c){a.e&&(c||!this.e)&&e(Error("Component already rendered"));(0>b||b>ic(this))&&e(Error("Child component index out of bounds"));if(!this.t||!this.r)this.t={},this.r=[];a.getParent()==this?(this.t[cc(a)]=a,xa(this.r,a)):Da(this.t,cc(a),a);gc(a,this);Ba(this.r,b,0,a);a.e&&this.e&&a.getParent()==this?(c=this.A(),c.insertBefore(a.a(),c.childNodes[b]||k)):c?(this.c||this.l(),c=O(this,b+1),b=this.A(),c=c?c.c:k,a.e&&e(Error("Component already rendered")),a.c||a.l(),b?b.insertBefore(a.c,
+f,d&=Tb(g,f,a.type,n,a)&&a.ua!=n;a=Boolean(d)}else a=j;return a};o.f=function(){Wb.d.f.call(this);Rb(this);this.Ca=k};var Xb=function(a,b){a.style.display=b?"":"none"},Yb=A?"MozUserSelect":B?"WebkitUserSelect":k,Zb=function(a,b,c){c=!c?a.getElementsByTagName("*"):k;if(Yb){if(b=b?"none":"",a.style[Yb]=b,c)for(var a=0,d;d=c[a];a++)d.style[Yb]=b}else if(y||Oa)if(b=b?"on":"",a.setAttribute("unselectable",b),c)for(a=0;d=c[a];a++)d.setAttribute("unselectable",b)};var $b=function(){};ba($b);$b.prototype.Yb=0;$b.P();var N=function(a){this.m=a||jb();this.ra=ac};v(N,Wb);N.prototype.Xb=$b.P();var ac=k,bc=function(a,b){switch(a){case 1:return b?"disable":"enable";case 2:return b?"highlight":"unhighlight";case 4:return b?"activate":"deactivate";case 8:return b?"select":"unselect";case 16:return b?"check":"uncheck";case 32:return b?"focus":"blur";case 64:return b?"open":"close"}e(Error("Invalid component state"))};o=N.prototype;o.ga=k;o.e=n;o.c=k;o.ra=k;o.q=k;o.r=k;o.t=k;o.mb=n;
+var cc=function(a){return a.ga||(a.ga=":"+(a.Xb.Yb++).toString(36))},dc=function(a,b){if(a.q&&a.q.t){var c=a.q.t,d=a.ga;d in c&&delete c[d];Da(a.q.t,b,a)}a.ga=b};N.prototype.a=function(){return this.c};var ec=function(a){return a.da||(a.da=new K(a))},gc=function(a,b){a==b&&e(Error("Unable to set parent component"));b&&a.q&&a.ga&&fc(a.q,a.ga)&&a.q!=b&&e(Error("Unable to set parent component"));a.q=b;N.d.eb.call(a,b)};o=N.prototype;o.getParent=function(){return this.q};
+o.eb=function(a){this.q&&this.q!=a&&e(Error("Method not supported"));N.d.eb.call(this,a)};o.Ia=function(){return this.m};o.k=function(){this.c=this.m.createElement("div")};o.K=function(a){this.e&&e(Error("Component already rendered"));if(a&&this.$(a)){this.mb=j;if(!this.m||this.m.C!=ib(a))this.m=jb(a);this.Va(a);this.s()}else e(Error("Invalid element to decorate"))};o.$=function(){return j};o.Va=function(a){this.c=a};o.s=function(){this.e=j;hc(this,function(a){!a.e&&a.a()&&a.s()})};
+o.U=function(){hc(this,function(a){a.e&&a.U()});this.da&&Vb(this.da);this.e=n};o.f=function(){N.d.f.call(this);this.e&&this.U();this.da&&(this.da.I(),delete this.da);hc(this,function(a){a.I()});!this.mb&&this.c&&rb(this.c);this.q=this.c=this.t=this.r=k};o.Ba=function(a,b){this.Sa(a,ic(this),b)};
+o.Sa=function(a,b,c){a.e&&(c||!this.e)&&e(Error("Component already rendered"));(0>b||b>ic(this))&&e(Error("Child component index out of bounds"));if(!this.t||!this.r)this.t={},this.r=[];a.getParent()==this?(this.t[cc(a)]=a,xa(this.r,a)):Da(this.t,cc(a),a);gc(a,this);Ba(this.r,b,0,a);a.e&&this.e&&a.getParent()==this?(c=this.A(),c.insertBefore(a.a(),c.childNodes[b]||k)):c?(this.c||this.k(),c=O(this,b+1),b=this.A(),c=c?c.c:k,a.e&&e(Error("Component already rendered")),a.c||a.k(),b?b.insertBefore(a.c,
 c||k):a.m.C.body.appendChild(a.c),(!a.q||a.q.e)&&a.s()):this.e&&!a.e&&a.c&&a.s()};o.A=function(){return this.c};var jc=function(a){if(a.ra==k){var b;a:{b=a.e?a.c:a.m.C.body;var c=ib(b);if(c.defaultView&&c.defaultView.getComputedStyle&&(b=c.defaultView.getComputedStyle(b,k))){b=b.direction||b.getPropertyValue("direction");break a}b=""}a.ra="rtl"==(b||((a.e?a.c:a.m.C.body).currentStyle?(a.e?a.c:a.m.C.body).currentStyle.direction:k)||(a.e?a.c:a.m.C.body).style&&(a.e?a.c:a.m.C.body).style.direction)}return a.ra};
 N.prototype.oa=function(a){this.e&&e(Error("Component already rendered"));this.ra=a};var ic=function(a){return a.r?a.r.length:0},fc=function(a,b){return a.t&&b?(b in a.t?a.t[b]:h)||k:k},O=function(a,b){return a.r?a.r[b]||k:k},hc=function(a,b,c){a.r&&ua(a.r,b,c)},kc=function(a,b){return a.r&&b?ta(a.r,b):-1};
-N.prototype.removeChild=function(a,b){if(a){var c=q(a)?a:cc(a),a=fc(this,c);if(c&&a){var d=this.t;c in d&&delete d[c];xa(this.r,a);b&&(a.U(),a.c&&rb(a.c));gc(a,k)}}a||e(Error("Child is not in parent component"));return a};var lc=function(a,b){a.setAttribute("role",b);a.oc=b};var nc=function(a,b,c,d,f){if(!y&&(!B||!C("525")))return j;if(Qa&&f)return mc(a);if(f&&!d)return n;if(!c&&(17==b||18==b))return n;if(y&&d&&b==a)return n;switch(a){case 13:return!(y&&bb());case 27:return!B}return mc(a)},mc=function(a){if(48<=a&&57>=a)return j;if(96<=a&&106>=a)return j;if(65<=a&&90>=a)return j;if(B&&0==a)return j;switch(a){case 32:case 63:case 107:case 109:case 110:case 111:case 186:case 59:case 189:case 187:case 188:case 190:case 191:case 192:case 222:case 219:case 220:case 221:return j;
-default:return n}};var P=function(a,b){a&&oc(this,a,b)};v(P,Wb);o=P.prototype;o.c=k;o.Fa=k;o.Xa=k;o.Ga=k;o.R=-1;o.Q=-1;
+N.prototype.removeChild=function(a,b){if(a){var c=q(a)?a:cc(a),a=fc(this,c);if(c&&a){var d=this.t;c in d&&delete d[c];xa(this.r,a);b&&(a.U(),a.c&&rb(a.c));gc(a,k)}}a||e(Error("Child is not in parent component"));return a};var lc=function(a,b){a.setAttribute("role",b);a.lc=b};var nc=function(a,b,c,d,f){if(!y&&(!B||!C("525")))return j;if(Ra&&f)return mc(a);if(f&&!d||!c&&(17==b||18==b)||y&&d&&b==a)return n;switch(a){case 13:return!(y&&bb());case 27:return!B}return mc(a)},mc=function(a){if(48<=a&&57>=a||96<=a&&106>=a||65<=a&&90>=a||B&&0==a)return j;switch(a){case 32:case 63:case 107:case 109:case 110:case 111:case 186:case 59:case 189:case 187:case 188:case 190:case 191:case 192:case 222:case 219:case 220:case 221:return j;default:return n}};var P=function(a,b){a&&oc(this,a,b)};v(P,Wb);o=P.prototype;o.c=k;o.Fa=k;o.Xa=k;o.Ga=k;o.R=-1;o.Q=-1;
 var pc={3:13,12:144,63232:38,63233:40,63234:37,63235:39,63236:112,63237:113,63238:114,63239:115,63240:116,63241:117,63242:118,63243:119,63244:120,63245:121,63246:122,63247:123,63248:44,63272:46,63273:36,63275:35,63276:33,63277:34,63289:144,63302:45},qc={Up:38,Down:40,Left:37,Right:39,Enter:13,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123,"U+007F":46,Home:36,End:35,PageUp:33,PageDown:34,Insert:45},rc={61:187,59:186},sc=y||B&&C("525");
-P.prototype.Rb=function(a){if(B&&(17==this.R&&!a.ctrlKey||18==this.R&&!a.altKey))this.Q=this.R=-1;sc&&!nc(a.keyCode,this.R,a.shiftKey,a.ctrlKey,a.altKey)?this.handleEvent(a):this.Q=A&&a.keyCode in rc?rc[a.keyCode]:a.keyCode};P.prototype.Sb=function(){this.Q=this.R=-1};
-P.prototype.handleEvent=function(a){var b=a.L,c,d;y&&"keypress"==a.type?(c=this.Q,d=13!=c&&27!=c?b.keyCode:0):B&&"keypress"==a.type?(c=this.Q,d=0<=b.charCode&&63232>b.charCode&&mc(c)?b.charCode:0):Oa?(c=this.Q,d=mc(c)?b.keyCode:0):(c=b.keyCode||this.Q,d=b.charCode||0,Qa&&63==d&&!c&&(c=191));var f=c,g=b.keyIdentifier;c?63232<=c&&c in pc?f=pc[c]:25==c&&a.shiftKey&&(f=9):g&&g in qc&&(f=qc[g]);a=f==this.R;this.R=f;b=new tc(f,d,a,b);try{this.dispatchEvent(b)}finally{b.I()}};P.prototype.a=function(){return this.c};
-var oc=function(a,b,c){a.Ga&&a.detach();a.c=b;a.Fa=I(a.c,"keypress",a,c);a.Xa=I(a.c,"keydown",a.Rb,c,a);a.Ga=I(a.c,"keyup",a.Sb,c,a)};P.prototype.detach=function(){if(this.Fa)J(this.Fa),J(this.Xa),J(this.Ga),this.Ga=this.Xa=this.Fa=k;this.c=k;this.Q=this.R=-1};P.prototype.f=function(){P.d.f.call(this);this.detach()};var tc=function(a,b,c,d){d&&this.sa(d,h);this.type="key";this.keyCode=a;this.charCode=b;this.repeat=c};v(tc,F);var vc=function(a,b){a||e(Error("Invalid class name "+a));r(b)||e(Error("Invalid decorator function "+b));uc[a]=b},wc={},uc={};var Q=function(){},xc;ba(Q);o=Q.prototype;o.M=function(){};o.l=function(a){var b=a.Ia().l("div",this.ta(a).join(" "),a.xa);yc(a,b);return b};o.A=function(a){return a};o.qa=function(a,b,c){if(a=a.a?a.a():a)if(y&&!C("7")){var d=zc(fb(a),b);d.push(b);ia(c?D:gb,a).apply(k,d)}else c?D(a,b):gb(a,b)};o.$=function(){return j};
-o.K=function(a,b){b.id&&dc(a,b.id);var c=this.A(b);a.xa=c&&c.firstChild?c.firstChild.nextSibling?za(c.childNodes):c.firstChild:k;var d=0,f=this.n(),g=this.n(),i=n,l=n,c=n,m=fb(b);ua(m,function(a){if(!i&&a==f)i=j,g==f&&(l=j);else if(!l&&a==g)l=j;else{var b=d;if(!this.sb)this.Ea||Ac(this),this.sb=Ea(this.Ea);a=parseInt(this.sb[a],10);d=b|(isNaN(a)?0:a)}},this);a.g=d;i||(m.push(f),g==f&&(l=j));l||m.push(g);var s=a.D;s&&m.push.apply(m,s);if(y&&!C("7")){var z=zc(m);0<z.length&&(m.push.apply(m,z),c=j)}if(!i||
-!l||s||c)b.className=m.join(" ");yc(a,b);return b};o.Ma=function(a){jc(a)&&this.oa(a.a(),j);a.isEnabled()&&this.la(a,a.H())};var yc=function(a,b){w(a);w(b);a.isEnabled()||Bc(b,1,j);a.g&8&&Bc(b,8,j);a.o&16&&Bc(b,16,!!(a.g&16));a.o&64&&Bc(b,64,!!(a.g&64))};o=Q.prototype;o.ya=function(a,b){Zb(a,!b,!y&&!Oa)};o.oa=function(a,b){this.qa(a,this.n()+"-rtl",b)};o.T=function(a){var b;return a.o&32&&(b=a.k())?xb(b):n};
-o.la=function(a,b){var c;if(a.o&32&&(c=a.k())){if(!b&&a.g&32){try{c.blur()}catch(d){}a.g&32&&a.ma(k)}if(xb(c)!=b)b?c.tabIndex=0:(c.tabIndex=-1,c.removeAttribute("tabIndex"))}};o.ja=function(a,b){Xb(a,b)};o.v=function(a,b,c){var d=a.a();if(d){var f=Cc(this,b);f&&this.qa(a,f,c);Bc(d,b,c)}};var Bc=function(a,b,c){xc||(xc={1:"disabled",8:"selected",16:"checked",64:"expanded"});(b=xc[b])&&a.setAttribute("aria-"+b,c)};Q.prototype.k=function(a){return a.a()};Q.prototype.n=function(){return"goog-control"};
+P.prototype.Qb=function(a){if(B&&(17==this.R&&!a.ctrlKey||18==this.R&&!a.altKey))this.Q=this.R=-1;sc&&!nc(a.keyCode,this.R,a.shiftKey,a.ctrlKey,a.altKey)?this.handleEvent(a):this.Q=A&&a.keyCode in rc?rc[a.keyCode]:a.keyCode};P.prototype.Rb=function(){this.Q=this.R=-1};
+P.prototype.handleEvent=function(a){var b=a.L,c,d;y&&"keypress"==a.type?(c=this.Q,d=13!=c&&27!=c?b.keyCode:0):B&&"keypress"==a.type?(c=this.Q,d=0<=b.charCode&&63232>b.charCode&&mc(c)?b.charCode:0):Oa?(c=this.Q,d=mc(c)?b.keyCode:0):(c=b.keyCode||this.Q,d=b.charCode||0,Ra&&63==d&&!c&&(c=191));var f=c,g=b.keyIdentifier;c?63232<=c&&c in pc?f=pc[c]:25==c&&a.shiftKey&&(f=9):g&&g in qc&&(f=qc[g]);a=f==this.R;this.R=f;b=new tc(f,d,a,b);try{this.dispatchEvent(b)}finally{b.I()}};P.prototype.a=function(){return this.c};
+var oc=function(a,b,c){a.Ga&&a.detach();a.c=b;a.Fa=I(a.c,"keypress",a,c);a.Xa=I(a.c,"keydown",a.Qb,c,a);a.Ga=I(a.c,"keyup",a.Rb,c,a)};P.prototype.detach=function(){this.Fa&&(J(this.Fa),J(this.Xa),J(this.Ga),this.Ga=this.Xa=this.Fa=k);this.c=k;this.Q=this.R=-1};P.prototype.f=function(){P.d.f.call(this);this.detach()};var tc=function(a,b,c,d){d&&this.sa(d,h);this.type="key";this.keyCode=a;this.charCode=b;this.repeat=c};v(tc,F);var vc=function(a,b){a||e(Error("Invalid class name "+a));r(b)||e(Error("Invalid decorator function "+b));uc[a]=b},wc={},uc={};var Q=function(){},xc;ba(Q);o=Q.prototype;o.M=function(){};o.k=function(a){var b=a.Ia().k("div",this.ta(a).join(" "),a.xa);yc(a,b);return b};o.A=function(a){return a};o.qa=function(a,b,c){if(a=a.a?a.a():a)if(y&&!C("7")){var d=zc(fb(a),b);d.push(b);ia(c?D:gb,a).apply(k,d)}else c?D(a,b):gb(a,b)};o.$=function(){return j};
+o.K=function(a,b){b.id&&dc(a,b.id);var c=this.A(b);a.xa=c&&c.firstChild?c.firstChild.nextSibling?za(c.childNodes):c.firstChild:k;var d=0,f=this.n(),g=this.n(),i=n,l=n,c=n,m=fb(b);ua(m,function(a){if(!i&&a==f)i=j,g==f&&(l=j);else if(!l&&a==g)l=j;else{var b=d;this.sb||(this.Ea||Ac(this),this.sb=Ea(this.Ea));a=parseInt(this.sb[a],10);d=b|(isNaN(a)?0:a)}},this);a.g=d;i||(m.push(f),g==f&&(l=j));l||m.push(g);var s=a.D;s&&m.push.apply(m,s);if(y&&!C("7")){var z=zc(m);0<z.length&&(m.push.apply(m,z),c=j)}if(!i||
+!l||s||c)b.className=m.join(" ");yc(a,b);return b};o.Ma=function(a){jc(a)&&this.oa(a.a(),j);a.isEnabled()&&this.la(a,a.H())};var yc=function(a,b){w(a);w(b);a.isEnabled()||Bc(b,1,j);a.g&8&&Bc(b,8,j);a.o&16&&Bc(b,16,!!(a.g&16));a.o&64&&Bc(b,64,!!(a.g&64))};o=Q.prototype;o.ya=function(a,b){Zb(a,!b,!y&&!Oa)};o.oa=function(a,b){this.qa(a,this.n()+"-rtl",b)};o.T=function(a){var b;return a.o&32&&(b=a.j())?xb(b):n};
+o.la=function(a,b){var c;if(a.o&32&&(c=a.j())){if(!b&&a.g&32){try{c.blur()}catch(d){}a.g&32&&a.ma(k)}xb(c)!=b&&(b?c.tabIndex=0:(c.tabIndex=-1,c.removeAttribute("tabIndex")))}};o.ja=function(a,b){Xb(a,b)};o.v=function(a,b,c){var d=a.a();if(d){var f=Cc(this,b);f&&this.qa(a,f,c);Bc(d,b,c)}};var Bc=function(a,b,c){xc||(xc={1:"disabled",8:"selected",16:"checked",64:"expanded"});(b=xc[b])&&a.setAttribute("aria-"+b,c)};Q.prototype.j=function(a){return a.a()};Q.prototype.n=function(){return"goog-control"};
 Q.prototype.ta=function(a){var b=this.n(),c=[b],d=this.n();d!=b&&c.push(d);b=a.g;for(d=[];b;){var f=b&-b;d.push(Cc(this,f));b&=~f}c.push.apply(c,d);(a=a.D)&&c.push.apply(c,a);y&&!C("7")&&c.push.apply(c,zc(c));return c};
-var zc=function(a,b){var c=[];b&&(a=a.concat([b]));ua([],function(d){va(d,ia(wa,a))&&(!b||wa(d,b))&&c.push(d.join("_"))});return c},Cc=function(a,b){a.Ea||Ac(a);return a.Ea[b]},Ac=function(a){var b=a.n();a.Ea={1:b+"-disabled",2:b+"-hover",4:b+"-active",8:b+"-selected",16:b+"-checked",32:b+"-focused",64:b+"-open"}};var R=function(a,b,c){N.call(this,c);if(!b){for(var b=this.constructor,d;b;){d=u(b);if(d=wc[d])break;b=b.d?b.d.constructor:k}b=d?r(d.P)?d.P():new d:k}this.b=b;this.xa=a};v(R,N);o=R.prototype;o.xa=k;o.g=0;o.o=39;o.Xb=255;o.V=0;o.p=j;o.D=k;o.ha=j;o.wa=n;o.ob=k;o.pb=function(){return this.ha};o.Pa=function(a){this.e&&a!=this.ha&&Dc(this,a);this.ha=a};o.k=function(){return this.b.k(this)};o.za=function(){return this.u||(this.u=new P)};o.zb=function(){return this.b};
-o.qa=function(a,b){if(b){if(a)this.D?wa(this.D,a)||this.D.push(a):this.D=[a],this.b.qa(this,a,j)}else if(a&&this.D){xa(this.D,a);if(0==this.D.length)this.D=k;this.b.qa(this,a,n)}};o.l=function(){var a=this.b.l(this);this.c=a;var b=this.ob||this.b.M();b&&lc(a,b);this.wa||this.b.ya(a,n);this.H()||this.b.ja(a,n)};o.A=function(){return this.b.A(this.a())};o.$=function(a){return this.b.$(a)};
-o.Va=function(a){this.c=a=this.b.K(this,a);var b=this.ob||this.b.M();b&&lc(a,b);this.wa||this.b.ya(a,n);this.p="none"!=a.style.display};o.s=function(){R.d.s.call(this);this.b.Ma(this);if(this.o&-2&&(this.pb()&&Dc(this,j),this.o&32)){var a=this.k();if(a){var b=this.za();oc(b,a);L(L(L(ec(this),b,"key",this.N),a,"focus",this.na),a,"blur",this.ma)}}};
-var Dc=function(a,b){var c=ec(a),d=a.a();b?(L(L(L(L(c,d,"mouseover",a.$a),d,"mousedown",a.ka),d,"mouseup",a.ab),d,"mouseout",a.Za),y&&L(c,d,"dblclick",a.wb)):(M(M(M(M(c,d,"mouseover",a.$a),d,"mousedown",a.ka),d,"mouseup",a.ab),d,"mouseout",a.Za),y&&M(c,d,"dblclick",a.wb))};o=R.prototype;o.U=function(){R.d.U.call(this);this.u&&this.u.detach();this.H()&&this.isEnabled()&&this.b.la(this,n)};o.f=function(){R.d.f.call(this);this.u&&(this.u.I(),delete this.u);delete this.b;this.D=this.xa=k};
-o.oa=function(a){R.d.oa.call(this,a);var b=this.a();b&&this.b.oa(b,a)};o.ya=function(a){this.wa=a;var b=this.a();b&&this.b.ya(b,a)};o.H=function(){return this.p};o.ja=function(a,b){if(b||this.p!=a&&this.dispatchEvent(a?"show":"hide")){var c=this.a();c&&this.b.ja(c,a);this.isEnabled()&&this.b.la(this,a);this.p=a;return j}return n};o.isEnabled=function(){return!(this.g&1)};
-o.pa=function(a){var b=this.getParent();if((!b||"function"!=typeof b.isEnabled||b.isEnabled())&&T(this,1,!a))a||(this.setActive(n),this.B(n)),this.H()&&this.b.la(this,a),this.v(1,!a)};o.B=function(a){T(this,2,a)&&this.v(2,a)};o.setActive=function(a){T(this,4,a)&&this.v(4,a)};var Ec=function(a,b){T(a,8,b)&&a.v(8,b)},Fc=function(a,b){T(a,64,b)&&a.v(64,b)};R.prototype.v=function(a,b){if(this.o&a&&b!=!!(this.g&a))this.b.v(this,a,b),this.g=b?this.g|a:this.g&~a};
-var Gc=function(a,b,c){a.e&&a.g&b&&!c&&e(Error("Component already rendered"));!c&&a.g&b&&a.v(b,n);a.o=c?a.o|b:a.o&~b},U=function(a,b){return!!(a.Xb&b)&&!!(a.o&b)},T=function(a,b,c){return!!(a.o&b)&&!!(a.g&b)!=c&&(!(a.V&b)||a.dispatchEvent(bc(b,c)))&&!a.bb};o=R.prototype;o.$a=function(a){(!a.relatedTarget||!tb(this.a(),a.relatedTarget))&&this.dispatchEvent("enter")&&this.isEnabled()&&U(this,2)&&this.B(j)};
-o.Za=function(a){if((!a.relatedTarget||!tb(this.a(),a.relatedTarget))&&this.dispatchEvent("leave"))U(this,4)&&this.setActive(n),U(this,2)&&this.B(n)};o.ka=function(a){if(this.isEnabled()&&(U(this,2)&&this.B(j),Hb(a)&&(!B||!Qa||!a.ctrlKey)))U(this,4)&&this.setActive(j),this.b.T(this)&&this.k().focus();!this.wa&&Hb(a)&&(!B||!Qa||!a.ctrlKey)&&a.preventDefault()};o.ab=function(a){this.isEnabled()&&(U(this,2)&&this.B(j),this.g&4&&Hc(this,a)&&U(this,4)&&this.setActive(n))};
-o.wb=function(a){this.isEnabled()&&Hc(this,a)};var Hc=function(a,b){if(U(a,16)){var c=!(a.g&16);T(a,16,c)&&a.v(16,c)}U(a,8)&&Ec(a,j);U(a,64)&&Fc(a,!(a.g&64));c=new E("action",a);if(b)c.altKey=b.altKey,c.ctrlKey=b.ctrlKey,c.metaKey=b.metaKey,c.shiftKey=b.shiftKey,c.cb=b.cb;return a.dispatchEvent(c)};R.prototype.na=function(){U(this,32)&&T(this,32,j)&&this.v(32,j)};R.prototype.ma=function(){U(this,4)&&this.setActive(n);U(this,32)&&T(this,32,n)&&this.v(32,n)};
-R.prototype.N=function(a){return this.H()&&this.isEnabled()&&this.kb(a)?(a.preventDefault(),a.stopPropagation(),j):n};R.prototype.kb=function(a){return 13==a.keyCode&&Hc(this,a)};r(R)||e(Error("Invalid component class "+R));r(Q)||e(Error("Invalid renderer class "+Q));var Ic=u(R);wc[Ic]=Q;vc("goog-control",function(){return new R(k)});var Jc=function(){};v(Jc,Q);ba(Jc);Jc.prototype.l=function(a){return a.Ia().l("div",this.n())};Jc.prototype.K=function(a,b){b.id&&dc(a,b.id);if("HR"==b.tagName){var c=b,b=this.l(a);c.parentNode&&c.parentNode.insertBefore(b,c);rb(c)}else D(b,this.n());return b};Jc.prototype.n=function(){return"goog-menuseparator"};var Kc=function(a,b){R.call(this,k,a||Jc.P(),b);Gc(this,1,n);Gc(this,2,n);Gc(this,4,n);Gc(this,32,n);this.g=1};v(Kc,R);Kc.prototype.s=function(){Kc.d.s.call(this);lc(this.a(),"separator")};vc("goog-menuseparator",function(){return new Kc});var V=function(){};ba(V);V.prototype.M=function(){};var Lc=function(a,b){if(a)a.tabIndex=b?0:-1};o=V.prototype;o.l=function(a){return a.Ia().l("div",this.ta(a).join(" "))};o.A=function(a){return a};o.$=function(a){return"DIV"==a.tagName};o.K=function(a,b){b.id&&dc(a,b.id);var c=this.n(),d=n,f=fb(b);f&&ua(f,function(b){b==c?d=j:b&&this.Wa(a,b,c)},this);d||D(b,c);Mc(a,this.A(b));return b};o.Wa=function(a,b,c){b==c+"-disabled"?a.pa(n):b==c+"-horizontal"?Nc(a,"horizontal"):b==c+"-vertical"&&Nc(a,"vertical")};
-var Mc=function(a,b){if(b)for(var c=b.firstChild,d;c&&c.parentNode==b;){d=c.nextSibling;if(1==c.nodeType){var f;a:{f=h;for(var g=fb(c),i=0,l=g.length;i<l;i++)if(f=g[i]in uc?uc[g[i]]():k)break a;f=k}if(f)f.c=c,a.isEnabled()||f.pa(n),a.Ba(f),f.K(c)}else(!c.nodeValue||""==la(c.nodeValue))&&b.removeChild(c);c=d}};V.prototype.Ma=function(a){a=a.a();Zb(a,j,A);if(y)a.hideFocus=j;var b=this.M();b&&lc(a,b)};V.prototype.k=function(a){return a.a()};V.prototype.n=function(){return"goog-container"};
-V.prototype.ta=function(a){var b=this.n(),c=[b,"horizontal"==a.O?b+"-horizontal":b+"-vertical"];a.isEnabled()||c.push(b+"-disabled");return c};var W=function(a,b,c){N.call(this,c);this.b=b||V.P();this.O=a||"vertical"};v(W,N);o=W.prototype;o.Oa=k;o.u=k;o.b=k;o.O=k;o.p=j;o.X=j;o.Ya=j;o.i=-1;o.h=k;o.ca=n;o.Qb=n;o.Pb=j;o.J=k;o.k=function(){return this.Oa||this.b.k(this)};o.za=function(){return this.u||(this.u=new P(this.k()))};o.zb=function(){return this.b};o.l=function(){this.c=this.b.l(this)};o.A=function(){return this.b.A(this.a())};o.$=function(a){return this.b.$(a)};
-o.Va=function(a){this.c=this.b.K(this,a);if("none"==a.style.display)this.p=n};o.s=function(){W.d.s.call(this);hc(this,function(a){a.e&&Oc(this,a)},this);var a=this.a();this.b.Ma(this);this.ja(this.p,j);L(L(L(L(L(L(L(L(ec(this),this,"enter",this.Jb),this,"highlight",this.Kb),this,"unhighlight",this.Mb),this,"open",this.Lb),this,"close",this.Hb),a,"mousedown",this.ka),ib(a),"mouseup",this.Ib),a,["mousedown","mouseup","mouseover","mouseout"],this.Gb);this.T()&&Pc(this,j)};
-var Pc=function(a,b){var c=ec(a),d=a.k();b?L(L(L(c,d,"focus",a.na),d,"blur",a.ma),a.za(),"key",a.N):M(M(M(c,d,"focus",a.na),d,"blur",a.ma),a.za(),"key",a.N)};o=W.prototype;o.U=function(){Qc(this,-1);this.h&&Fc(this.h,n);this.ca=n;W.d.U.call(this)};o.f=function(){W.d.f.call(this);if(this.u)this.u.I(),this.u=k;this.b=this.h=this.J=this.Oa=k};o.Jb=function(){return j};
-o.Kb=function(a){var b=kc(this,a.target);if(-1<b&&b!=this.i){var c=O(this,this.i);c&&c.B(n);this.i=b;c=O(this,this.i);this.ca&&c.setActive(j);this.Pb&&this.h&&c!=this.h&&(c.o&64?Fc(c,j):Fc(this.h,n))}this.a().setAttribute("aria-activedescendant",a.target.a().id)};o.Mb=function(a){if(a.target==O(this,this.i))this.i=-1;this.a().setAttribute("aria-activedescendant","")};o.Lb=function(a){if((a=a.target)&&a!=this.h&&a.getParent()==this)this.h&&Fc(this.h,n),this.h=a};
-o.Hb=function(a){if(a.target==this.h)this.h=k};o.ka=function(a){if(this.X)this.ca=j;var b=this.k();b&&xb(b)?b.focus():a.preventDefault()};o.Ib=function(){this.ca=n};o.Gb=function(a){var b;a:{b=a.target;if(this.J)for(var c=this.a();b&&b!==c;){var d=b.id;if(d in this.J){b=this.J[d];break a}b=b.parentNode}b=k}if(b)switch(a.type){case "mousedown":b.ka(a);break;case "mouseup":b.ab(a);break;case "mouseover":b.$a(a);break;case "mouseout":b.Za(a)}};o.na=function(){};
+var zc=function(a,b){var c=[];b&&(a=a.concat([b]));ua([],function(d){va(d,ia(wa,a))&&(!b||wa(d,b))&&c.push(d.join("_"))});return c},Cc=function(a,b){a.Ea||Ac(a);return a.Ea[b]},Ac=function(a){var b=a.n();a.Ea={1:b+"-disabled",2:b+"-hover",4:b+"-active",8:b+"-selected",16:b+"-checked",32:b+"-focused",64:b+"-open"}};var R=function(a,b,c){N.call(this,c);if(!b){for(var b=this.constructor,d;b;){d=u(b);if(d=wc[d])break;b=b.d?b.d.constructor:k}b=d?r(d.P)?d.P():new d:k}this.b=b;this.xa=a};v(R,N);o=R.prototype;o.xa=k;o.g=0;o.o=39;o.Wb=255;o.V=0;o.p=j;o.D=k;o.ha=j;o.wa=n;o.ob=k;o.pb=function(){return this.ha};o.Pa=function(a){this.e&&a!=this.ha&&Dc(this,a);this.ha=a};o.j=function(){return this.b.j(this)};o.za=function(){return this.u||(this.u=new P)};o.zb=function(){return this.b};
+o.qa=function(a,b){b?a&&(this.D?wa(this.D,a)||this.D.push(a):this.D=[a],this.b.qa(this,a,j)):a&&this.D&&(xa(this.D,a),0==this.D.length&&(this.D=k),this.b.qa(this,a,n))};o.k=function(){var a=this.b.k(this);this.c=a;var b=this.ob||this.b.M();b&&lc(a,b);this.wa||this.b.ya(a,n);this.H()||this.b.ja(a,n)};o.A=function(){return this.b.A(this.a())};o.$=function(a){return this.b.$(a)};o.Va=function(a){this.c=a=this.b.K(this,a);var b=this.ob||this.b.M();b&&lc(a,b);this.wa||this.b.ya(a,n);this.p="none"!=a.style.display};
+o.s=function(){R.d.s.call(this);this.b.Ma(this);if(this.o&-2&&(this.pb()&&Dc(this,j),this.o&32)){var a=this.j();if(a){var b=this.za();oc(b,a);L(L(L(ec(this),b,"key",this.N),a,"focus",this.na),a,"blur",this.ma)}}};var Dc=function(a,b){var c=ec(a),d=a.a();b?(L(L(L(L(c,d,"mouseover",a.$a),d,"mousedown",a.ka),d,"mouseup",a.ab),d,"mouseout",a.Za),y&&L(c,d,"dblclick",a.wb)):(M(M(M(M(c,d,"mouseover",a.$a),d,"mousedown",a.ka),d,"mouseup",a.ab),d,"mouseout",a.Za),y&&M(c,d,"dblclick",a.wb))};o=R.prototype;
+o.U=function(){R.d.U.call(this);this.u&&this.u.detach();this.H()&&this.isEnabled()&&this.b.la(this,n)};o.f=function(){R.d.f.call(this);this.u&&(this.u.I(),delete this.u);delete this.b;this.D=this.xa=k};o.oa=function(a){R.d.oa.call(this,a);var b=this.a();b&&this.b.oa(b,a)};o.ya=function(a){this.wa=a;var b=this.a();b&&this.b.ya(b,a)};o.H=function(){return this.p};
+o.ja=function(a,b){if(b||this.p!=a&&this.dispatchEvent(a?"show":"hide")){var c=this.a();c&&this.b.ja(c,a);this.isEnabled()&&this.b.la(this,a);this.p=a;return j}return n};o.isEnabled=function(){return!(this.g&1)};o.pa=function(a){var b=this.getParent();if((!b||"function"!=typeof b.isEnabled||b.isEnabled())&&T(this,1,!a))a||(this.setActive(n),this.B(n)),this.H()&&this.b.la(this,a),this.v(1,!a)};o.B=function(a){T(this,2,a)&&this.v(2,a)};o.setActive=function(a){T(this,4,a)&&this.v(4,a)};
+var Ec=function(a,b){T(a,8,b)&&a.v(8,b)},Fc=function(a,b){T(a,64,b)&&a.v(64,b)};R.prototype.v=function(a,b){this.o&a&&b!=!!(this.g&a)&&(this.b.v(this,a,b),this.g=b?this.g|a:this.g&~a)};var Gc=function(a,b,c){a.e&&a.g&b&&!c&&e(Error("Component already rendered"));!c&&a.g&b&&a.v(b,n);a.o=c?a.o|b:a.o&~b},U=function(a,b){return!!(a.Wb&b)&&!!(a.o&b)},T=function(a,b,c){return!!(a.o&b)&&!!(a.g&b)!=c&&(!(a.V&b)||a.dispatchEvent(bc(b,c)))&&!a.bb};o=R.prototype;
+o.$a=function(a){(!a.relatedTarget||!tb(this.a(),a.relatedTarget))&&this.dispatchEvent("enter")&&this.isEnabled()&&U(this,2)&&this.B(j)};o.Za=function(a){if((!a.relatedTarget||!tb(this.a(),a.relatedTarget))&&this.dispatchEvent("leave"))U(this,4)&&this.setActive(n),U(this,2)&&this.B(n)};o.ka=function(a){if(this.isEnabled()&&(U(this,2)&&this.B(j),Hb(a)&&(!B||!Ra||!a.ctrlKey)))U(this,4)&&this.setActive(j),this.b.T(this)&&this.j().focus();!this.wa&&Hb(a)&&(!B||!Ra||!a.ctrlKey)&&a.preventDefault()};
+o.ab=function(a){this.isEnabled()&&(U(this,2)&&this.B(j),this.g&4&&Hc(this,a)&&U(this,4)&&this.setActive(n))};o.wb=function(a){this.isEnabled()&&Hc(this,a)};var Hc=function(a,b){if(U(a,16)){var c=!(a.g&16);T(a,16,c)&&a.v(16,c)}U(a,8)&&Ec(a,j);U(a,64)&&Fc(a,!(a.g&64));c=new E("action",a);b&&(c.altKey=b.altKey,c.ctrlKey=b.ctrlKey,c.metaKey=b.metaKey,c.shiftKey=b.shiftKey,c.cb=b.cb);return a.dispatchEvent(c)};R.prototype.na=function(){U(this,32)&&T(this,32,j)&&this.v(32,j)};
+R.prototype.ma=function(){U(this,4)&&this.setActive(n);U(this,32)&&T(this,32,n)&&this.v(32,n)};R.prototype.N=function(a){return this.H()&&this.isEnabled()&&this.kb(a)?(a.preventDefault(),a.stopPropagation(),j):n};R.prototype.kb=function(a){return 13==a.keyCode&&Hc(this,a)};r(R)||e(Error("Invalid component class "+R));r(Q)||e(Error("Invalid renderer class "+Q));var Ic=u(R);wc[Ic]=Q;vc("goog-control",function(){return new R(k)});var Jc=function(){};v(Jc,Q);ba(Jc);Jc.prototype.k=function(a){return a.Ia().k("div",this.n())};Jc.prototype.K=function(a,b){b.id&&dc(a,b.id);if("HR"==b.tagName){var c=b,b=this.k(a);c.parentNode&&c.parentNode.insertBefore(b,c);rb(c)}else D(b,this.n());return b};Jc.prototype.n=function(){return"goog-menuseparator"};var Kc=function(a,b){R.call(this,k,a||Jc.P(),b);Gc(this,1,n);Gc(this,2,n);Gc(this,4,n);Gc(this,32,n);this.g=1};v(Kc,R);Kc.prototype.s=function(){Kc.d.s.call(this);lc(this.a(),"separator")};vc("goog-menuseparator",function(){return new Kc});var V=function(){};ba(V);V.prototype.M=function(){};var Lc=function(a,b){a&&(a.tabIndex=b?0:-1)};o=V.prototype;o.k=function(a){return a.Ia().k("div",this.ta(a).join(" "))};o.A=function(a){return a};o.$=function(a){return"DIV"==a.tagName};o.K=function(a,b){b.id&&dc(a,b.id);var c=this.n(),d=n,f=fb(b);f&&ua(f,function(b){b==c?d=j:b&&this.Wa(a,b,c)},this);d||D(b,c);Mc(a,this.A(b));return b};o.Wa=function(a,b,c){b==c+"-disabled"?a.pa(n):b==c+"-horizontal"?Nc(a,"horizontal"):b==c+"-vertical"&&Nc(a,"vertical")};
+var Mc=function(a,b){if(b)for(var c=b.firstChild,d;c&&c.parentNode==b;){d=c.nextSibling;if(1==c.nodeType){var f;a:{f=h;for(var g=fb(c),i=0,l=g.length;i<l;i++)if(f=g[i]in uc?uc[g[i]]():k)break a;f=k}f&&(f.c=c,a.isEnabled()||f.pa(n),a.Ba(f),f.K(c))}else(!c.nodeValue||""==la(c.nodeValue))&&b.removeChild(c);c=d}};V.prototype.Ma=function(a){a=a.a();Zb(a,j,A);y&&(a.hideFocus=j);var b=this.M();b&&lc(a,b)};V.prototype.j=function(a){return a.a()};V.prototype.n=function(){return"goog-container"};
+V.prototype.ta=function(a){var b=this.n(),c=[b,"horizontal"==a.O?b+"-horizontal":b+"-vertical"];a.isEnabled()||c.push(b+"-disabled");return c};var W=function(a,b,c){N.call(this,c);this.b=b||V.P();this.O=a||"vertical"};v(W,N);o=W.prototype;o.Oa=k;o.u=k;o.b=k;o.O=k;o.p=j;o.X=j;o.Ya=j;o.i=-1;o.h=k;o.ca=n;o.Pb=n;o.Ob=j;o.J=k;o.j=function(){return this.Oa||this.b.j(this)};o.za=function(){return this.u||(this.u=new P(this.j()))};o.zb=function(){return this.b};o.k=function(){this.c=this.b.k(this)};o.A=function(){return this.b.A(this.a())};o.$=function(a){return this.b.$(a)};
+o.Va=function(a){this.c=this.b.K(this,a);"none"==a.style.display&&(this.p=n)};o.s=function(){W.d.s.call(this);hc(this,function(a){a.e&&Oc(this,a)},this);var a=this.a();this.b.Ma(this);this.ja(this.p,j);L(L(L(L(L(L(L(L(ec(this),this,"enter",this.Jb),this,"highlight",this.Kb),this,"unhighlight",this.Mb),this,"open",this.Lb),this,"close",this.Hb),a,"mousedown",this.ka),ib(a),"mouseup",this.Ib),a,["mousedown","mouseup","mouseover","mouseout"],this.Gb);this.T()&&Pc(this,j)};
+var Pc=function(a,b){var c=ec(a),d=a.j();b?L(L(L(c,d,"focus",a.na),d,"blur",a.ma),a.za(),"key",a.N):M(M(M(c,d,"focus",a.na),d,"blur",a.ma),a.za(),"key",a.N)};o=W.prototype;o.U=function(){Qc(this,-1);this.h&&Fc(this.h,n);this.ca=n;W.d.U.call(this)};o.f=function(){W.d.f.call(this);this.u&&(this.u.I(),this.u=k);this.b=this.h=this.J=this.Oa=k};o.Jb=function(){return j};
+o.Kb=function(a){var b=kc(this,a.target);if(-1<b&&b!=this.i){var c=O(this,this.i);c&&c.B(n);this.i=b;c=O(this,this.i);this.ca&&c.setActive(j);this.Ob&&this.h&&c!=this.h&&(c.o&64?Fc(c,j):Fc(this.h,n))}this.a().setAttribute("aria-activedescendant",a.target.a().id)};o.Mb=function(a){a.target==O(this,this.i)&&(this.i=-1);this.a().setAttribute("aria-activedescendant","")};o.Lb=function(a){if((a=a.target)&&a!=this.h&&a.getParent()==this)this.h&&Fc(this.h,n),this.h=a};
+o.Hb=function(a){a.target==this.h&&(this.h=k)};o.ka=function(a){this.X&&(this.ca=j);var b=this.j();b&&xb(b)?b.focus():a.preventDefault()};o.Ib=function(){this.ca=n};o.Gb=function(a){var b;a:{b=a.target;if(this.J)for(var c=this.a();b&&b!==c;){var d=b.id;if(d in this.J){b=this.J[d];break a}b=b.parentNode}b=k}if(b)switch(a.type){case "mousedown":b.ka(a);break;case "mouseup":b.ab(a);break;case "mouseover":b.$a(a);break;case "mouseout":b.Za(a)}};o.na=function(){};
 o.ma=function(){Qc(this,-1);this.ca=n;this.h&&Fc(this.h,n)};o.N=function(a){return this.isEnabled()&&this.H()&&(0!=ic(this)||this.Oa)&&this.kb(a)?(a.preventDefault(),a.stopPropagation(),j):n};
-o.kb=function(a){var b=O(this,this.i);if(b&&"function"==typeof b.N&&b.N(a))return j;if(this.h&&this.h!=b&&"function"==typeof this.h.N&&this.h.N(a))return j;if(a.shiftKey||a.ctrlKey||a.metaKey||a.altKey)return n;switch(a.keyCode){case 27:if(this.T())this.k().blur();else return n;break;case 36:Rc(this);break;case 35:Sc(this);break;case 38:if("vertical"==this.O)Tc(this);else return n;break;case 37:if("horizontal"==this.O)jc(this)?Uc(this):Tc(this);else return n;break;case 40:if("vertical"==this.O)Uc(this);
-else return n;break;case 39:if("horizontal"==this.O)jc(this)?Tc(this):Uc(this);else return n;break;default:return n}return j};var Oc=function(a,b){var c=b.a(),c=c.id||(c.id=cc(b));if(!a.J)a.J={};a.J[c]=b};W.prototype.Ba=function(a,b){W.d.Ba.call(this,a,b)};W.prototype.Sa=function(a,b,c){a.V|=2;a.V|=64;(this.T()||!this.Qb)&&Gc(a,32,n);a.Pa(n);W.d.Sa.call(this,a,b,c);a.e&&this.e&&Oc(this,a);b<=this.i&&this.i++};
-W.prototype.removeChild=function(a,b){if(a=q(a)?fc(this,a):a){var c=kc(this,a);-1!=c&&(c==this.i?a.B(n):c<this.i&&this.i--);var d=a.a();if(d&&d.id&&this.J)c=this.J,d=d.id,d in c&&delete c[d]}a=W.d.removeChild.call(this,a,b);a.Pa(j);return a};var Nc=function(a,b){a.a()&&e(Error("Component already rendered"));a.O=b};o=W.prototype;o.H=function(){return this.p};
-o.ja=function(a,b){if(b||this.p!=a&&this.dispatchEvent(a?"show":"hide")){this.p=a;var c=this.a();c&&(Xb(c,a),this.T()&&Lc(this.k(),this.X&&this.p),b||this.dispatchEvent(this.p?"aftershow":"afterhide"));return j}return n};o.isEnabled=function(){return this.X};o.pa=function(a){if(this.X!=a&&this.dispatchEvent(a?"enable":"disable"))a?(this.X=j,hc(this,function(a){a.tb?delete a.tb:a.pa(j)})):(hc(this,function(a){a.isEnabled()?a.pa(n):a.tb=j}),this.ca=this.X=n),this.T()&&Lc(this.k(),a&&this.p)};o.T=function(){return this.Ya};
-o.la=function(a){a!=this.Ya&&this.e&&Pc(this,a);this.Ya=a;this.X&&this.p&&Lc(this.k(),a)};var Qc=function(a,b){var c=O(a,b);c?c.B(j):-1<a.i&&O(a,a.i).B(n)};W.prototype.B=function(a){Qc(this,kc(this,a))};
-var Rc=function(a){Vc(a,function(a,c){return(a+1)%c},ic(a)-1)},Sc=function(a){Vc(a,function(a,c){a--;return 0>a?c-1:a},0)},Uc=function(a){Vc(a,function(a,c){return(a+1)%c},a.i)},Tc=function(a){Vc(a,function(a,c){a--;return 0>a?c-1:a},a.i)},Vc=function(a,b,c){for(var c=0>c?kc(a,a.h):c,d=ic(a),c=b.call(a,c,d),f=0;f<=d;){var g=O(a,c);if(g&&g.H()&&g.isEnabled()&&g.o&2){a.Ua(c);break}f++;c=b.call(a,c,d)}};W.prototype.Ua=function(a){Qc(this,a)};var Wc=function(){};v(Wc,Q);ba(Wc);o=Wc.prototype;o.n=function(){return"goog-tab"};o.M=function(){return"tab"};o.l=function(a){var b=Wc.d.l.call(this,a);(a=a.Ra())&&this.Ta(b,a);return b};o.K=function(a,b){var b=Wc.d.K.call(this,a,b),c=this.Ra(b);if(c)a.qb=c;if(a.g&8&&(c=a.getParent())&&r(c.W))a.v(8,n),c.W(a);return b};o.Ra=function(a){return a.title||""};o.Ta=function(a,b){if(a)a.title=b||""};var Xc=function(a,b,c){R.call(this,a,b||Wc.P(),c);Gc(this,8,j);this.V|=9};v(Xc,R);Xc.prototype.Ra=function(){return this.qb};Xc.prototype.Ta=function(a){this.zb().Ta(this.a(),a);this.qb=a};vc("goog-tab",function(){return new Xc(k)});var X=function(){};v(X,V);ba(X);X.prototype.n=function(){return"goog-tab-bar"};X.prototype.M=function(){return"tablist"};X.prototype.Wa=function(a,b,c){if(!this.yb)this.Ha||Yc(this),this.yb=Ea(this.Ha);var d=this.yb[b];d?(Nc(a,Zc(d)),a.rb=d):X.d.Wa.call(this,a,b,c)};X.prototype.ta=function(a){var b=X.d.ta.call(this,a);this.Ha||Yc(this);b.push(this.Ha[a.rb]);return b};var Yc=function(a){var b=a.n();a.Ha={top:b+"-top",bottom:b+"-bottom",start:b+"-start",end:b+"-end"}};var Y=function(a,b,c){a=a||"top";Nc(this,Zc(a));this.rb=a;W.call(this,this.O,b||X.P(),c);$c(this)};v(Y,W);o=Y.prototype;o.Tb=j;o.F=k;o.s=function(){Y.d.s.call(this);$c(this)};o.f=function(){Y.d.f.call(this);this.F=k};o.removeChild=function(a,b){ad(this,a);return Y.d.removeChild.call(this,a,b)};o.Ua=function(a){Y.d.Ua.call(this,a);this.Tb&&this.W(O(this,a))};o.W=function(a){a?Ec(a,j):this.F&&Ec(this.F,n)};
-var ad=function(a,b){if(b&&b==a.F){for(var c=kc(a,b),d=c-1;b=O(a,d);d--)if(b.H()&&b.isEnabled()){a.W(b);return}for(c+=1;b=O(a,c);c++)if(b.H()&&b.isEnabled()){a.W(b);return}a.W(k)}};o=Y.prototype;o.cc=function(a){this.F&&this.F!=a.target&&Ec(this.F,n);this.F=a.target};o.dc=function(a){if(a.target==this.F)this.F=k};o.ac=function(a){ad(this,a.target)};o.bc=function(a){ad(this,a.target)};o.na=function(){O(this,this.i)||this.B(this.F||O(this,0))};
-var $c=function(a){L(L(L(L(ec(a),a,"select",a.cc),a,"unselect",a.dc),a,"disable",a.ac),a,"hide",a.bc)},Zc=function(a){return"start"==a||"end"==a?"vertical":"horizontal"};vc("goog-tab-bar",function(){return new Y});var Z=function(a,b,c,d,f){function g(a){if(a)a.tabIndex=0,lc(a,i.M()),D(a,"goog-zippy-header"),bd(i,a),a&&L(i.nb,a,"keydown",i.Ob)}this.m=f||jb();this.Y=this.m.a(a)||k;this.Aa=this.m.a(d||k);this.ea=(this.Qa=r(b)?b:k)||!b?k:this.m.a(b);this.j=c==j;this.nb=new K(this);this.Na=new K(this);var i=this;g(this.Y);g(this.Aa);this.Z(this.j)};v(Z,Wb);o=Z.prototype;o.ha=j;o.lc=j;o.f=function(){Z.d.f.call(this);Fb(this.nb);Fb(this.Na)};o.M=function(){return"tab"};o.A=function(){return this.ea};o.toggle=function(){this.Z(!this.j)};
-o.Z=function(a){if(this.ea)Xb(this.ea,a);else if(a&&this.Qa)this.ea=this.Qa();this.ea&&D(this.ea,"goog-zippy-content");if(this.Aa)Xb(this.Y,!a),Xb(this.Aa,a);else if(this.Y){var b=this.Y;a?D(b,"goog-zippy-expanded"):gb(b,"goog-zippy-expanded");b=this.Y;!a?D(b,"goog-zippy-collapsed"):gb(b,"goog-zippy-collapsed");this.Y.setAttribute("aria-expanded",a)}this.j=a;this.dispatchEvent(new cd("toggle",this,this.j))};o.pb=function(){return this.lc};
-o.Pa=function(a){if(this.ha!=a)(this.ha=a)?(bd(this,this.Y),bd(this,this.Aa)):Vb(this.Na)};var bd=function(a,b){b&&L(a.Na,b,"click",a.fc)};Z.prototype.Ob=function(a){if(13==a.keyCode||32==a.keyCode)this.toggle(),this.dispatchEvent(new E("action",this)),a.preventDefault(),a.stopPropagation()};Z.prototype.fc=function(){this.toggle();this.dispatchEvent(new E("action",this))};var cd=function(a,b,c){E.call(this,a,b);this.mc=c};v(cd,E);var ed=function(a,b){this.lb=[];for(var c=kb(a),c=lb("span","ae-zippy",c),d=0,f;f=c[d];d++)this.lb.push(new Z(f,f.parentNode.parentNode.parentNode.nextElementSibling!=h?f.parentNode.parentNode.parentNode.nextElementSibling:sb(f.parentNode.parentNode.parentNode.nextSibling),n));this.ec=new dd(this.lb,kb(b))};ed.prototype.jc=function(){return this.ec};ed.prototype.kc=function(){return this.lb};
-var dd=function(a,b){this.va=a;if(this.va.length)for(var c=0,d;d=this.va[c];c++)I(d,"toggle",this.Vb,n,this);this.Ka=0;this.j=n;c="ae-toggle ae-plus ae-action";this.va.length||(c+=" ae-disabled");this.S=pb("span",{className:c},"Expand All");I(this.S,"click",this.Ub,n,this);b&&b.appendChild(this.S)};dd.prototype.Ub=function(){this.va.length&&this.Z(!this.j)};
-dd.prototype.Vb=function(a){a=a.currentTarget;this.Ka=a.j?this.Ka+1:this.Ka-1;if(a.j!=this.j)if(a.j)this.j=j,fd(this,j);else if(0==this.Ka)this.j=n,fd(this,n)};dd.prototype.Z=function(a){this.j=a;for(var a=0,b;b=this.va[a];a++)b.j!=this.j&&b.Z(this.j);fd(this)};
-var fd=function(a,b){(b!==h?b:a.j)?(gb(a.S,"ae-plus"),D(a.S,"ae-minus"),ub(a.S,"Collapse All")):(gb(a.S,"ae-minus"),D(a.S,"ae-plus"),ub(a.S,"Expand All"))},gd=function(a){this.Wb=a;this.Db={};var b,c=pb("div",{},b=pb("div",{id:"ae-stats-details-tabs",className:"goog-tab-bar goog-tab-bar-top"}),pb("div",{className:"goog-tab-bar-clear"}),a=pb("div",{id:"ae-stats-details-tabs-content",className:"goog-tab-content"})),d=new Y;d.K(b);I(d,"select",this.Bb,n,this);I(d,"unselect",this.Bb,n,this);b=0;for(var f;f=
-this.Wb[b];b++)if(f=kb("ae-stats-details-"+f)){var g=lb("h2",k,f)[0],i;i=g;var l=h;eb&&"innerText"in i?l=i.innerText.replace(/(\r\n|\r|\n)/g,"\n"):(l=[],yb(i,l,j),l=l.join(""));l=l.replace(/ \xAD /g," ").replace(/\xAD/g,"");l=l.replace(/\u200B/g,"");eb||(l=l.replace(/ +/g," "));" "!=l&&(l=l.replace(/^\s*/,""));i=l;rb(g);g=new Xc(i);this.Db[u(g)]=f;d.Ba(g,j);a.appendChild(f);0==b?d.W(g):Xb(f,n)}kb("bd").appendChild(c)};gd.prototype.Bb=function(a){var b=this.Db[u(a.target)];Xb(b,"select"==a.type)};
-aa("ae.Stats.Details.Tabs",gd);aa("goog.ui.Zippy",Z);Z.prototype.setExpanded=Z.prototype.Z;aa("ae.Stats.MakeZippys",ed);ed.prototype.getExpandCollapse=ed.prototype.jc;ed.prototype.getZippys=ed.prototype.kc;dd.prototype.setExpanded=dd.prototype.Z;var $=function(){this.fb=[];this.jb=[]},hd=[[5,0.2,1],[6,0.2,1.2],[5,0.25,1.25],[6,0.25,1.5],[4,0.5,2],[5,0.5,2.5],[6,0.5,3],[4,1,4],[5,1,5],[6,1,6],[4,2,8],[5,2,10]],id=function(a){if(0>=a)return[2,0.5,1];for(var b=1;1>a;)a*=10,b/=10;for(;10<=a;)a/=10,b*=10;for(var c=0;c<hd.length;c++)if(a<=hd[c][2])return[hd[c][0],hd[c][1]*b,hd[c][2]*b];return[5,2*b,10*b]};$.prototype.ib="stats/static/pix.gif";$.prototype.z="ae-stats-gantt-";$.prototype.hb=0;$.prototype.write=function(a){this.jb.push(a)};
+o.kb=function(a){var b=O(this,this.i);if(b&&"function"==typeof b.N&&b.N(a)||this.h&&this.h!=b&&"function"==typeof this.h.N&&this.h.N(a))return j;if(a.shiftKey||a.ctrlKey||a.metaKey||a.altKey)return n;switch(a.keyCode){case 27:if(this.T())this.j().blur();else return n;break;case 36:Rc(this);break;case 35:Sc(this);break;case 38:if("vertical"==this.O)Tc(this);else return n;break;case 37:if("horizontal"==this.O)jc(this)?Uc(this):Tc(this);else return n;break;case 40:if("vertical"==this.O)Uc(this);else return n;
+break;case 39:if("horizontal"==this.O)jc(this)?Tc(this):Uc(this);else return n;break;default:return n}return j};var Oc=function(a,b){var c=b.a(),c=c.id||(c.id=cc(b));a.J||(a.J={});a.J[c]=b};W.prototype.Ba=function(a,b){W.d.Ba.call(this,a,b)};W.prototype.Sa=function(a,b,c){a.V|=2;a.V|=64;(this.T()||!this.Pb)&&Gc(a,32,n);a.Pa(n);W.d.Sa.call(this,a,b,c);a.e&&this.e&&Oc(this,a);b<=this.i&&this.i++};
+W.prototype.removeChild=function(a,b){if(a=q(a)?fc(this,a):a){var c=kc(this,a);-1!=c&&(c==this.i?a.B(n):c<this.i&&this.i--);var d=a.a();d&&d.id&&this.J&&(c=this.J,d=d.id,d in c&&delete c[d])}a=W.d.removeChild.call(this,a,b);a.Pa(j);return a};var Nc=function(a,b){a.a()&&e(Error("Component already rendered"));a.O=b};o=W.prototype;o.H=function(){return this.p};
+o.ja=function(a,b){if(b||this.p!=a&&this.dispatchEvent(a?"show":"hide")){this.p=a;var c=this.a();c&&(Xb(c,a),this.T()&&Lc(this.j(),this.X&&this.p),b||this.dispatchEvent(this.p?"aftershow":"afterhide"));return j}return n};o.isEnabled=function(){return this.X};o.pa=function(a){if(this.X!=a&&this.dispatchEvent(a?"enable":"disable"))a?(this.X=j,hc(this,function(a){a.tb?delete a.tb:a.pa(j)})):(hc(this,function(a){a.isEnabled()?a.pa(n):a.tb=j}),this.ca=this.X=n),this.T()&&Lc(this.j(),a&&this.p)};o.T=function(){return this.Ya};
+o.la=function(a){a!=this.Ya&&this.e&&Pc(this,a);this.Ya=a;this.X&&this.p&&Lc(this.j(),a)};var Qc=function(a,b){var c=O(a,b);c?c.B(j):-1<a.i&&O(a,a.i).B(n)};W.prototype.B=function(a){Qc(this,kc(this,a))};
+var Rc=function(a){Vc(a,function(a,c){return(a+1)%c},ic(a)-1)},Sc=function(a){Vc(a,function(a,c){a--;return 0>a?c-1:a},0)},Uc=function(a){Vc(a,function(a,c){return(a+1)%c},a.i)},Tc=function(a){Vc(a,function(a,c){a--;return 0>a?c-1:a},a.i)},Vc=function(a,b,c){for(var c=0>c?kc(a,a.h):c,d=ic(a),c=b.call(a,c,d),f=0;f<=d;){var g=O(a,c);if(g&&g.H()&&g.isEnabled()&&g.o&2){a.Ua(c);break}f++;c=b.call(a,c,d)}};W.prototype.Ua=function(a){Qc(this,a)};var Wc=function(){};v(Wc,Q);ba(Wc);o=Wc.prototype;o.n=function(){return"goog-tab"};o.M=function(){return"tab"};o.k=function(a){var b=Wc.d.k.call(this,a);(a=a.Ra())&&this.Ta(b,a);return b};o.K=function(a,b){var b=Wc.d.K.call(this,a,b),c=this.Ra(b);c&&(a.qb=c);if(a.g&8&&(c=a.getParent())&&r(c.W))a.v(8,n),c.W(a);return b};o.Ra=function(a){return a.title||""};o.Ta=function(a,b){a&&(a.title=b||"")};var Xc=function(a,b,c){R.call(this,a,b||Wc.P(),c);Gc(this,8,j);this.V|=9};v(Xc,R);Xc.prototype.Ra=function(){return this.qb};Xc.prototype.Ta=function(a){this.zb().Ta(this.a(),a);this.qb=a};vc("goog-tab",function(){return new Xc(k)});var X=function(){};v(X,V);ba(X);X.prototype.n=function(){return"goog-tab-bar"};X.prototype.M=function(){return"tablist"};X.prototype.Wa=function(a,b,c){this.yb||(this.Ha||Yc(this),this.yb=Ea(this.Ha));var d=this.yb[b];d?(Nc(a,Zc(d)),a.rb=d):X.d.Wa.call(this,a,b,c)};X.prototype.ta=function(a){var b=X.d.ta.call(this,a);this.Ha||Yc(this);b.push(this.Ha[a.rb]);return b};var Yc=function(a){var b=a.n();a.Ha={top:b+"-top",bottom:b+"-bottom",start:b+"-start",end:b+"-end"}};var Y=function(a,b,c){a=a||"top";Nc(this,Zc(a));this.rb=a;W.call(this,this.O,b||X.P(),c);$c(this)};v(Y,W);o=Y.prototype;o.Sb=j;o.F=k;o.s=function(){Y.d.s.call(this);$c(this)};o.f=function(){Y.d.f.call(this);this.F=k};o.removeChild=function(a,b){ad(this,a);return Y.d.removeChild.call(this,a,b)};o.Ua=function(a){Y.d.Ua.call(this,a);this.Sb&&this.W(O(this,a))};o.W=function(a){a?Ec(a,j):this.F&&Ec(this.F,n)};
+var ad=function(a,b){if(b&&b==a.F){for(var c=kc(a,b),d=c-1;b=O(a,d);d--)if(b.H()&&b.isEnabled()){a.W(b);return}for(c+=1;b=O(a,c);c++)if(b.H()&&b.isEnabled()){a.W(b);return}a.W(k)}};o=Y.prototype;o.bc=function(a){this.F&&this.F!=a.target&&Ec(this.F,n);this.F=a.target};o.cc=function(a){a.target==this.F&&(this.F=k)};o.$b=function(a){ad(this,a.target)};o.ac=function(a){ad(this,a.target)};o.na=function(){O(this,this.i)||this.B(this.F||O(this,0))};
+var $c=function(a){L(L(L(L(ec(a),a,"select",a.bc),a,"unselect",a.cc),a,"disable",a.$b),a,"hide",a.ac)},Zc=function(a){return"start"==a||"end"==a?"vertical":"horizontal"};vc("goog-tab-bar",function(){return new Y});var Z=function(a,b,c,d,f){function g(a){a&&(a.tabIndex=0,lc(a,i.M()),D(a,"goog-zippy-header"),bd(i,a),a&&L(i.nb,a,"keydown",i.Nb))}this.m=f||jb();this.Y=this.m.a(a)||k;this.Aa=this.m.a(d||k);this.ea=(this.Qa=r(b)?b:k)||!b?k:this.m.a(b);this.l=c==j;this.nb=new K(this);this.Na=new K(this);var i=this;g(this.Y);g(this.Aa);this.Z(this.l)};v(Z,Wb);o=Z.prototype;o.ha=j;o.kc=j;o.f=function(){Z.d.f.call(this);Fb(this.nb);Fb(this.Na)};o.M=function(){return"tab"};o.A=function(){return this.ea};o.toggle=function(){this.Z(!this.l)};
+o.Z=function(a){this.ea?Xb(this.ea,a):a&&this.Qa&&(this.ea=this.Qa());this.ea&&D(this.ea,"goog-zippy-content");if(this.Aa)Xb(this.Y,!a),Xb(this.Aa,a);else if(this.Y){var b=this.Y;a?D(b,"goog-zippy-expanded"):gb(b,"goog-zippy-expanded");b=this.Y;!a?D(b,"goog-zippy-collapsed"):gb(b,"goog-zippy-collapsed");this.Y.setAttribute("aria-expanded",a)}this.l=a;this.dispatchEvent(new cd("toggle",this))};o.pb=function(){return this.kc};
+o.Pa=function(a){this.ha!=a&&((this.ha=a)?(bd(this,this.Y),bd(this,this.Aa)):Vb(this.Na))};var bd=function(a,b){b&&L(a.Na,b,"click",a.ec)};Z.prototype.Nb=function(a){if(13==a.keyCode||32==a.keyCode)this.toggle(),this.dispatchEvent(new E("action",this)),a.preventDefault(),a.stopPropagation()};Z.prototype.ec=function(){this.toggle();this.dispatchEvent(new E("action",this))};var cd=function(a,b){E.call(this,a,b)};v(cd,E);var ed=function(a,b){this.lb=[];for(var c=kb(a),c=lb("span","ae-zippy",c),d=0,f;f=c[d];d++)this.lb.push(new Z(f,f.parentNode.parentNode.parentNode.nextElementSibling!=h?f.parentNode.parentNode.parentNode.nextElementSibling:sb(f.parentNode.parentNode.parentNode.nextSibling),n));this.dc=new dd(this.lb,kb(b))};ed.prototype.ic=function(){return this.dc};ed.prototype.jc=function(){return this.lb};
+var dd=function(a,b){this.va=a;if(this.va.length)for(var c=0,d;d=this.va[c];c++)I(d,"toggle",this.Ub,n,this);this.Ka=0;this.l=n;c="ae-toggle ae-plus ae-action";this.va.length||(c+=" ae-disabled");this.S=pb("span",{className:c},"Expand All");I(this.S,"click",this.Tb,n,this);b&&b.appendChild(this.S)};dd.prototype.Tb=function(){this.va.length&&this.Z(!this.l)};
+dd.prototype.Ub=function(a){a=a.currentTarget;this.Ka=a.l?this.Ka+1:this.Ka-1;a.l!=this.l&&(a.l?(this.l=j,fd(this,j)):0==this.Ka&&(this.l=n,fd(this,n)))};dd.prototype.Z=function(a){this.l=a;for(var a=0,b;b=this.va[a];a++)b.l!=this.l&&b.Z(this.l);fd(this)};
+var fd=function(a,b){(b!==h?b:a.l)?(gb(a.S,"ae-plus"),D(a.S,"ae-minus"),ub(a.S,"Collapse All")):(gb(a.S,"ae-minus"),D(a.S,"ae-plus"),ub(a.S,"Expand All"))},gd=function(a){this.Vb=a;this.Db={};var b,c=pb("div",{},b=pb("div",{id:"ae-stats-details-tabs",className:"goog-tab-bar goog-tab-bar-top"}),pb("div",{className:"goog-tab-bar-clear"}),a=pb("div",{id:"ae-stats-details-tabs-content",className:"goog-tab-content"})),d=new Y;d.K(b);I(d,"select",this.Bb,n,this);I(d,"unselect",this.Bb,n,this);b=0;for(var f;f=
+this.Vb[b];b++)if(f=kb("ae-stats-details-"+f)){var g=lb("h2",k,f)[0],i;i=g;var l=h;eb&&"innerText"in i?l=i.innerText.replace(/(\r\n|\r|\n)/g,"\n"):(l=[],yb(i,l,j),l=l.join(""));l=l.replace(/ \xAD /g," ").replace(/\xAD/g,"");l=l.replace(/\u200B/g,"");eb||(l=l.replace(/ +/g," "));" "!=l&&(l=l.replace(/^\s*/,""));i=l;rb(g);g=new Xc(i);this.Db[u(g)]=f;d.Ba(g,j);a.appendChild(f);0==b?d.W(g):Xb(f,n)}kb("bd").appendChild(c)};gd.prototype.Bb=function(a){var b=this.Db[u(a.target)];Xb(b,"select"==a.type)};
+aa("ae.Stats.Details.Tabs",gd);aa("goog.ui.Zippy",Z);Z.prototype.setExpanded=Z.prototype.Z;aa("ae.Stats.MakeZippys",ed);ed.prototype.getExpandCollapse=ed.prototype.ic;ed.prototype.getZippys=ed.prototype.jc;dd.prototype.setExpanded=dd.prototype.Z;var $=function(){this.fb=[];this.jb=[]},hd=[[5,0.2,1],[6,0.2,1.2],[5,0.25,1.25],[6,0.25,1.5],[4,0.5,2],[5,0.5,2.5],[6,0.5,3],[4,1,4],[5,1,5],[6,1,6],[4,2,8],[5,2,10]],id=function(a){if(0>=a)return[2,0.5,1];for(var b=1;1>a;)a*=10,b/=10;for(;10<=a;)a/=10,b*=10;for(var c=0;c<hd.length;c++)if(a<=hd[c][2])return[hd[c][0],hd[c][1]*b,hd[c][2]*b];return[5,2*b,10*b]};$.prototype.ib="stats/static/pix.gif";$.prototype.z="ae-stats-gantt-";$.prototype.hb=0;$.prototype.write=function(a){this.jb.push(a)};
 var jd=function(a,b,c,d){a.write('<tr class="'+a.z+'axisrow"><td width="20%"></td><td>');a.write('<div class="'+a.z+'axis">');for(var f=0;f<=b;f++)a.write('<img class="'+a.z+'tick" src="'+a.ib+'" alt="" '),a.write('style="left:'+f*c*d+'%"\n>'),a.write('<span class="'+a.z+'scale" style="left:'+f*c*d+'%">'),a.write("&nbsp;"+f*c+"</span>");a.write("</div></td></tr>\n")};
-$.prototype.ic=function(){this.jb=[];var a=id(this.hb),b=a[0],c=a[1],a=100/a[2];this.write('<table class="'+this.z+'table">\n');jd(this,b,c,a);for(var d=0;d<this.fb.length;d++){var f=this.fb[d];this.write('<tr class="'+this.z+'datarow"><td width="20%">');0<f.label.length&&(0<f.ia.length&&this.write('<a class="'+this.z+'link" href="'+f.ia+'">'),this.write(f.label),0<f.ia.length&&this.write("</a>"));this.write("</td>\n<td>");this.write('<div class="'+this.z+'container">');0<f.ia.length&&this.write('<a class="'+
+$.prototype.hc=function(){this.jb=[];var a=id(this.hb),b=a[0],c=a[1],a=100/a[2];this.write('<table class="'+this.z+'table">\n');jd(this,b,c,a);for(var d=0;d<this.fb.length;d++){var f=this.fb[d];this.write('<tr class="'+this.z+'datarow"><td width="20%">');0<f.label.length&&(0<f.ia.length&&this.write('<a class="'+this.z+'link" href="'+f.ia+'">'),this.write(f.label),0<f.ia.length&&this.write("</a>"));this.write("</td>\n<td>");this.write('<div class="'+this.z+'container">');0<f.ia.length&&this.write('<a class="'+
 this.z+'link" href="'+f.ia+'"\n>');this.write('<img class="'+this.z+'bar" src="'+this.ib+'" alt="" ');this.write('style="left:'+f.start*a+"%;width:"+f.duration*a+'%;min-width:1px"\n>');0<f.gb&&(this.write('<img class="'+this.z+'extra" src="'+this.ib+'" alt="" '),this.write('style="left:'+f.start*a+"%;width:"+f.gb*a+'%"\n>'));0<f.xb.length&&(this.write('<span class="'+this.z+'inline" style="left:'+(f.start+Math.max(f.duration,f.gb))*a+'%">&nbsp;'),this.write(f.xb),this.write("</span>"));0<f.ia.length&&
-this.write("</a>");this.write("</div></td></tr>\n")}jd(this,b,c,a);this.write("</table>\n");return this.jb.join("")};$.prototype.gc=function(a,b,c,d,f,g){this.hb=Math.max(this.hb,Math.max(b+c,b+d));this.fb.push({label:a,start:b,duration:c,gb:d,xb:f,ia:g})};aa("Gantt",$);$.prototype.add_bar=$.prototype.gc;$.prototype.draw=$.prototype.ic;})();
+this.write("</a>");this.write("</div></td></tr>\n")}jd(this,b,c,a);this.write("</table>\n");return this.jb.join("")};$.prototype.fc=function(a,b,c,d,f,g){this.hb=Math.max(this.hb,Math.max(b+c,b+d));this.fb.push({label:a,start:b,duration:c,gb:d,xb:f,ia:g})};aa("Gantt",$);$.prototype.add_bar=$.prototype.fc;$.prototype.draw=$.prototype.hc;})();
diff --git a/google/appengine/ext/datastore_admin/backup_handler.py b/google/appengine/ext/datastore_admin/backup_handler.py
index adf8f88..59e9a3f 100644
--- a/google/appengine/ext/datastore_admin/backup_handler.py
+++ b/google/appengine/ext/datastore_admin/backup_handler.py
@@ -43,10 +43,12 @@
 from google.appengine.api import capabilities
 from google.appengine.api import datastore
 from google.appengine.api import files
+from google.appengine.api import taskqueue
 from google.appengine.api.taskqueue import taskqueue_service_pb
 from google.appengine.datastore import datastore_rpc
 from google.appengine.ext import blobstore
 from google.appengine.ext import db
+from google.appengine.ext import deferred
 from google.appengine.ext import webapp
 from google.appengine.ext.datastore_admin import utils
 from google.appengine.ext.mapreduce import input_readers
@@ -169,11 +171,13 @@
     Status of executed jobs is displayed.
     """
     jobs = self.request.get('job', allow_multiple=True)
+    tasks = self.request.get('task', allow_multiple=True)
     error = self.request.get('error', '')
     xsrf_error = self.request.get('xsrf_error', '')
 
     template_params = {
         'job_list': jobs,
+        'task_list': tasks,
         'mapreduce_detail': self.MAPREDUCE_DETAIL,
         'error': error,
         'xsrf_error': xsrf_error,
@@ -230,7 +234,7 @@
     Returns:
       The exception error string.
     """
-    return str(type(e)) + ": " + str(e)
+    return str(type(e)) + ': ' + str(e)
 
 
 class DoBackupHandler(BaseDoHandler):
@@ -255,8 +259,7 @@
 
     kinds = self.request.get('kind', allow_multiple=True)
     queue = self.request.get('queue')
-
-    job_name = 'datastore_backup_%s' % re.sub(r'[^\w]', '_', backup)
+    job_name = 'datastore_backup_%s_%%(kind)s' % re.sub(r'[^\w]', '_', backup)
     try:
       job_operation = utils.StartOperation('Backup: %s' % backup)
       backup_info = BackupInformation(parent=job_operation)
@@ -268,23 +271,50 @@
           'backup_info_pk': str(backup_info.key()),
           'force_ops_writes': True
       }
-      jobs = utils.RunMapForKinds(
-          job_operation.key(),
-          kinds,
-          job_name,
-          self.BACKUP_HANDLER,
-          self.INPUT_READER,
-          self.OUTPUT_WRITER,
-          self._GetBasicMapperParams(),
-          mapreduce_params,
-          queue_name=queue)
-      backup_info.active_jobs = jobs
-      backup_info.put(config=datastore_rpc.Configuration(force_writes=True))
-      return [('job', job) for job in jobs]
-    except Exception, e:
-      logging.exception('Failed to start a datastore backup job "%s".',
+      if len(kinds) <= 10:
+        return [('job', job) for job in _run_map_jobs(
+            job_operation.key(), backup_info.key(), kinds, job_name,
+            self.BACKUP_HANDLER, self.INPUT_READER, self.OUTPUT_WRITER,
+            self._GetBasicMapperParams(), mapreduce_params, queue)]
+      else:
+        retry_options = taskqueue.TaskRetryOptions(task_retry_limit=1)
+        return [('task', deferred.defer(_run_map_jobs, job_operation.key(),
+                                        backup_info.key(), kinds, job_name,
+                                        self.BACKUP_HANDLER, self.INPUT_READER,
+                                        self.OUTPUT_WRITER,
+                                        self._GetBasicMapperParams(),
+                                        mapreduce_params,
+                                        queue, _queue=queue,
+                                        _url=utils.ConfigDefaults.DEFERRED_PATH,
+                                        _retry_options=retry_options).name)]
+    except Exception:
+      logging.exception('Failed to start a datastore backup job[s] for "%s".',
                         job_name)
-      raise e
+      if job_operation:
+        job_operation.status = utils.DatastoreAdminOperation.STATUS_FAILED
+        job_operation.put(config=datastore_rpc.Configuration(force_writes=True))
+      raise
+
+
+def _run_map_jobs(job_operation_key, backup_info_key, kinds, job_name,
+                  backup_handler, input_reader, output_writer, mapper_params,
+                  mapreduce_params, queue):
+  backup_info = BackupInformation.get(backup_info_key)
+  if not backup_info:
+    return []
+  jobs = utils.RunMapForKinds(
+      job_operation_key,
+      kinds,
+      job_name,
+      backup_handler,
+      input_reader,
+      output_writer,
+      mapper_params,
+      mapreduce_params,
+      queue_name=queue)
+  backup_info.active_jobs = jobs
+  backup_info.put(config=datastore_rpc.Configuration(force_writes=True))
+  return jobs
 
 
 class DoBackupDeleteHandler(BaseDoHandler):
@@ -342,6 +372,7 @@
 
     queue = self.request.get('queue')
     job_name = 'datastore_backup_%s' % re.sub(r'[^\w]', '_', backup.name)
+    job_operation = None
     try:
       job_operation = utils.StartOperation('Restore from backup: %s'
                                            % backup.name)
@@ -360,10 +391,13 @@
           mapper_params,
           mapreduce_params,
           queue_name=queue))]
-    except Exception, e:
+    except Exception:
       logging.exception('Failed to start a restore from backup job "%s".',
                         job_name)
-      raise e
+      if job_operation:
+        job_operation.status = utils.DatastoreAdminOperation.STATUS_FAILED
+        job_operation.put(config=datastore_rpc.Configuration(force_writes=True))
+      raise
 
 
 class BackupInformation(db.Model):
@@ -394,15 +428,47 @@
   mapreduce_spec = mapreduce_state.mapreduce_spec
   backup_info = BackupInformation.get(mapreduce_spec.params['backup_info_pk'])
   if backup_info:
-    backup_info.blob_files = list(
-        set(backup_info.blob_files + mapreduce_state.writer_state['filenames']))
+    filenames = mapreduce_state.writer_state['filenames']
+
+
+    backup_info.blob_files = list(set(backup_info.blob_files + filenames))
     if job_id in backup_info.active_jobs:
       backup_info.active_jobs.remove(job_id)
       backup_info.completed_jobs = list(
           set(backup_info.completed_jobs + [job_id]))
-    if operation.status == utils.DatastoreAdminOperation.STATUS_COMPLETED:
-      backup_info.complete_time = datetime.datetime.now()
     backup_info.put(config=datastore_rpc.Configuration(force_writes=True))
+    if operation.status == utils.DatastoreAdminOperation.STATUS_COMPLETED:
+      deferred.defer(finalize_backup_info, backup_info.key(),
+                     _url=utils.ConfigDefaults.DEFERRED_PATH)
+  else:
+    logging.warn('BackupInfo was not found for %s',
+                 mapreduce_spec.params['backup_info_pk'])
+
+
+def finalize_backup_info(backup_info_key):
+  backup_info = BackupInformation.get(backup_info_key)
+  backup_info.complete_time = datetime.datetime.now()
+
+
+  backup_info.blob_files = drop_empty_files(backup_info.blob_files)
+  backup_info.put(config=datastore_rpc.Configuration(force_writes=True))
+  logging.info('Backup %s completed', backup_info.name)
+
+
+def drop_empty_files(filenames):
+  """Deletes empty files and returns filenames minus the deleted ones."""
+  non_empty_filenames = []
+  empty_file_keys = []
+  blobs_info = blobstore.BlobInfo.get([files.blobstore.get_blob_key(fn)
+                                       for fn in filenames])
+  for filename, blob_info in zip(filenames, blobs_info):
+    if blob_info:
+      if blob_info.size > 0:
+        non_empty_filenames.append(filename)
+      else:
+        empty_file_keys.append(blob_info.key())
+  blobstore_api.delete(empty_file_keys)
+  return non_empty_filenames
 
 
 class BackupEntity(object):
@@ -437,6 +503,7 @@
     yield op.db.Put(entity)
 
 
+
 def get_queue_names(app_id=None):
   """Returns a list with all non-special queue names for app_id."""
   rpc = apiproxy_stub_map.UserRPC('taskqueue')
diff --git a/google/appengine/ext/datastore_admin/main.py b/google/appengine/ext/datastore_admin/main.py
index 772c1f4..aeadd79 100755
--- a/google/appengine/ext/datastore_admin/main.py
+++ b/google/appengine/ext/datastore_admin/main.py
@@ -31,6 +31,7 @@
 
 from google.appengine.api import datastore_errors
 from google.appengine.api import users
+from google.appengine.ext import deferred
 from google.appengine.ext import webapp
 from google.appengine.ext.datastore_admin import backup_handler
 from google.appengine.ext.datastore_admin import copy_handler
@@ -192,9 +193,11 @@
     """Obtain a list of operation, ordered by last_updated."""
     query = utils.DatastoreAdminOperation.all()
     if active:
-      query.filter('active_jobs > ', 0)
+      query.filter('status = ', utils.DatastoreAdminOperation.STATUS_ACTIVE)
     else:
-      query.filter('active_jobs = ', 0)
+      query.filter('status IN ', [
+          utils.DatastoreAdminOperation.STATUS_COMPLETED,
+          utils.DatastoreAdminOperation.STATUS_FAILED])
     operations = query.fetch(max(10000, limit) if limit else 1000)
     operations = sorted(operations, key=operator.attrgetter('last_updated'),
                         reverse=True)
@@ -277,7 +280,8 @@
        delete_handler.DoDeleteHandler),
       (r'%s/%s' % (utils.config.BASE_PATH,
                    utils.MapreduceDoneHandler.SUFFIX),
-      utils.MapreduceDoneHandler)]
+       utils.MapreduceDoneHandler),
+      (utils.config.DEFERRED_PATH, deferred.TaskHandler)]
       + copy_handler.handlers_list(utils.config.BASE_PATH)
       + backup_handler.handlers_list(utils.config.BASE_PATH)
       + [(r'%s/static.*' % utils.config.BASE_PATH, StaticResourceHandler),
diff --git a/google/appengine/ext/datastore_admin/static/css/compiled.css b/google/appengine/ext/datastore_admin/static/css/compiled.css
index 53f70ed..164e81a 100755
--- a/google/appengine/ext/datastore_admin/static/css/compiled.css
+++ b/google/appengine/ext/datastore_admin/static/css/compiled.css
@@ -1,2 +1,2 @@
 /* Copyright 2012 Google Inc. All Rights Reserved. */
-html,body,div,h1,h2,h3,h4,h5,h6,p,img,dl,dt,dd,ol,ul,li,table,caption,tbody,tfoot,thead,tr,th,td,form,fieldset,embed,object,applet{margin:0;padding:0;border:0;}body{font-size:62.5%;font-family:Arial,sans-serif;color:#000;background:#fff}a{color:#00c}a:active{color:#f00}a:visited{color:#551a8b}table{border-collapse:collapse;border-width:0;empty-cells:show}ul{padding:0 0 1em 1em}ol{padding:0 0 1em 1.3em}li{line-height:1.5em;padding:0 0 .5em 0}p{padding:0 0 1em 0}h1,h2,h3,h4,h5{padding:0 0 1em 0}h1,h2{font-size:1.3em}h3{font-size:1.1em}h4,h5,table{font-size:1em}sup,sub{font-size:.7em}input,select,textarea,option{font-family:inherit;font-size:inherit}.g-doc,.g-doc-1024,.g-doc-800{font-size:130%}.g-doc{width:100%;text-align:left}.g-section{width:100%;vertical-align:top;display:inline-block}*:first-child+html .g-section{display:block}* html .g-section{overflow:hidden}@-moz-document url-prefix(''){.g-section{overflow:hidden}}@-moz-document url-prefix(''){.g-section,tt:default{overflow:visible}}.g-section,.g-unit{zoom:1}.g-split .g-unit{text-align:right}.g-split .g-first{text-align:left}.g-doc-1024{width:73.074em;min-width:950px;margin:0 auto;text-align:left}* html .g-doc-1024{width:71.313em}*+html .g-doc-1024{width:71.313em}.g-doc-800{width:57.69em;min-width:750px;margin:0 auto;text-align:left}* html .g-doc-800{width:56.3em}*+html .g-doc-800{width:56.3em}.g-tpl-160 .g-unit,.g-unit .g-tpl-160 .g-unit,.g-unit .g-unit .g-tpl-160 .g-unit,.g-unit .g-unit .g-unit .g-tpl-160 .g-unit{margin:0 0 0 160px;width:auto;float:none}.g-unit .g-unit .g-unit .g-tpl-160 .g-first,.g-unit .g-unit .g-tpl-160 .g-first,.g-unit .g-tpl-160 .g-first,.g-tpl-160 .g-first{margin:0;width:160px;float:left}.g-tpl-160-alt .g-unit,.g-unit .g-tpl-160-alt .g-unit,.g-unit .g-unit .g-tpl-160-alt .g-unit,.g-unit .g-unit .g-unit .g-tpl-160-alt .g-unit{margin:0 160px 0 0;width:auto;float:none}.g-unit .g-unit .g-unit .g-tpl-160-alt .g-first,.g-unit .g-unit .g-tpl-160-alt .g-first,.g-unit .g-tpl-160-alt .g-first,.g-tpl-160-alt .g-first{margin:0;width:160px;float:right}.g-tpl-180 .g-unit,.g-unit .g-tpl-180 .g-unit,.g-unit .g-unit .g-tpl-180 .g-unit,.g-unit .g-unit .g-unit .g-tpl-180 .g-unit{margin:0 0 0 180px;width:auto;float:none}.g-unit .g-unit .g-unit .g-tpl-180 .g-first,.g-unit .g-unit .g-tpl-180 .g-first,.g-unit .g-tpl-180 .g-first,.g-tpl-180 .g-first{margin:0;width:180px;float:left}.g-tpl-180-alt .g-unit,.g-unit .g-tpl-180-alt .g-unit,.g-unit .g-unit .g-tpl-180-alt .g-unit,.g-unit .g-unit .g-unit .g-tpl-180-alt .g-unit{margin:0 180px 0 0;width:auto;float:none}.g-unit .g-unit .g-unit .g-tpl-180-alt .g-first,.g-unit .g-unit .g-tpl-180-alt .g-first,.g-unit .g-tpl-180-alt .g-first,.g-tpl-180-alt .g-first{margin:0;width:180px;float:right}.g-tpl-300 .g-unit,.g-unit .g-tpl-300 .g-unit,.g-unit .g-unit .g-tpl-300 .g-unit,.g-unit .g-unit .g-unit .g-tpl-300 .g-unit{margin:0 0 0 300px;width:auto;float:none}.g-unit .g-unit .g-unit .g-tpl-300 .g-first,.g-unit .g-unit .g-tpl-300 .g-first,.g-unit .g-tpl-300 .g-first,.g-tpl-300 .g-first{margin:0;width:300px;float:left}.g-tpl-300-alt .g-unit,.g-unit .g-tpl-300-alt .g-unit,.g-unit .g-unit .g-tpl-300-alt .g-unit,.g-unit .g-unit .g-unit .g-tpl-300-alt .g-unit{margin:0 300px 0 0;width:auto;float:none}.g-unit .g-unit .g-unit .g-tpl-300-alt .g-first,.g-unit .g-unit .g-tpl-300-alt .g-first,.g-unit .g-tpl-300-alt .g-first,.g-tpl-300-alt .g-first{margin:0;width:300px;float:right}.g-tpl-25-75 .g-unit,.g-unit .g-tpl-25-75 .g-unit,.g-unit .g-unit .g-tpl-25-75 .g-unit,.g-unit .g-unit .g-unit .g-tpl-25-75 .g-unit{width:74.999%;float:right;margin:0}.g-unit .g-unit .g-unit .g-tpl-25-75 .g-first,.g-unit .g-unit .g-tpl-25-75 .g-first,.g-unit .g-tpl-25-75 .g-first,.g-tpl-25-75 .g-first{width:24.999%;float:left;margin:0}.g-tpl-25-75-alt .g-unit,.g-unit .g-tpl-25-75-alt .g-unit,.g-unit .g-unit .g-tpl-25-75-alt .g-unit,.g-unit .g-unit .g-unit .g-tpl-25-75-alt .g-unit{width:24.999%;float:left;margin:0}.g-unit .g-unit .g-unit .g-tpl-25-75-alt .g-first,.g-unit .g-unit .g-tpl-25-75-alt .g-first,.g-unit .g-tpl-25-75-alt .g-first,.g-tpl-25-75-alt .g-first{width:74.999%;float:right;margin:0}.g-tpl-75-25 .g-unit,.g-unit .g-tpl-75-25 .g-unit,.g-unit .g-unit .g-tpl-75-25 .g-unit,.g-unit .g-unit .g-unit .g-tpl-75-25 .g-unit{width:24.999%;float:right;margin:0}.g-unit .g-unit .g-unit .g-tpl-75-25 .g-first,.g-unit .g-unit .g-tpl-75-25 .g-first,.g-unit .g-tpl-75-25 .g-first,.g-tpl-75-25 .g-first{width:74.999%;float:left;margin:0}.g-tpl-75-25-alt .g-unit,.g-unit .g-tpl-75-25-alt .g-unit,.g-unit .g-unit .g-tpl-75-25-alt .g-unit,.g-unit .g-unit .g-unit .g-tpl-75-25-alt .g-unit{width:74.999%;float:left;margin:0}.g-unit .g-unit .g-unit .g-tpl-75-25-alt .g-first,.g-unit .g-unit .g-tpl-75-25-alt .g-first,.g-unit .g-tpl-75-25-alt .g-first,.g-tpl-75-25-alt .g-first{width:24.999%;float:right;margin:0}.g-tpl-33-67 .g-unit,.g-unit .g-tpl-33-67 .g-unit,.g-unit .g-unit .g-tpl-33-67 .g-unit,.g-unit .g-unit .g-unit .g-tpl-33-67 .g-unit{width:66.999%;float:right;margin:0}.g-unit .g-unit .g-unit .g-tpl-33-67 .g-first,.g-unit .g-unit .g-tpl-33-67 .g-first,.g-unit .g-tpl-33-67 .g-first,.g-tpl-33-67 .g-first{width:32.999%;float:left;margin:0}.g-tpl-33-67-alt .g-unit,.g-unit .g-tpl-33-67-alt .g-unit,.g-unit .g-unit .g-tpl-33-67-alt .g-unit,.g-unit .g-unit .g-unit .g-tpl-33-67-alt .g-unit{width:32.999%;float:left;margin:0}.g-unit .g-unit .g-unit .g-tpl-33-67-alt .g-first,.g-unit .g-unit .g-tpl-33-67-alt .g-first,.g-unit .g-tpl-33-67-alt .g-first,.g-tpl-33-67-alt .g-first{width:66.999%;float:right;margin:0}.g-tpl-67-33 .g-unit,.g-unit .g-tpl-67-33 .g-unit,.g-unit .g-unit .g-tpl-67-33 .g-unit,.g-unit .g-unit .g-unit .g-tpl-67-33 .g-unit{width:32.999%;float:right;margin:0}.g-unit .g-unit .g-unit .g-tpl-67-33 .g-first,.g-unit .g-unit .g-tpl-67-33 .g-first,.g-unit .g-tpl-67-33 .g-first,.g-tpl-67-33 .g-first{width:66.999%;float:left;margin:0}.g-tpl-67-33-alt .g-unit,.g-unit .g-tpl-67-33-alt .g-unit,.g-unit .g-unit .g-tpl-67-33-alt .g-unit,.g-unit .g-unit .g-unit .g-tpl-67-33-alt .g-unit{width:66.999%;float:left;margin:0}.g-unit .g-unit .g-unit .g-tpl-67-33-alt .g-first,.g-unit .g-unit .g-tpl-67-33-alt .g-first,.g-unit .g-tpl-67-33-alt .g-first,.g-tpl-67-33-alt .g-first{width:32.999%;float:right;margin:0}.g-tpl-50-50 .g-unit,.g-unit .g-tpl-50-50 .g-unit,.g-unit .g-unit .g-tpl-50-50 .g-unit,.g-unit .g-unit .g-unit .g-tpl-50-50 .g-unit{width:49.999%;float:right;margin:0}.g-unit .g-unit .g-unit .g-tpl-50-50 .g-first,.g-unit .g-unit .g-tpl-50-50 .g-first,.g-unit .g-tpl-50-50 .g-first,.g-tpl-50-50 .g-first{width:49.999%;float:left;margin:0}.g-tpl-50-50-alt .g-unit,.g-unit .g-tpl-50-50-alt .g-unit,.g-unit .g-unit .g-tpl-50-50-alt .g-unit,.g-unit .g-unit .g-unit .g-tpl-50-50-alt .g-unit{width:49.999%;float:left;margin:0}.g-unit .g-unit .g-unit .g-tpl-50-50-alt .g-first,.g-unit .g-unit .g-tpl-50-50-alt .g-first,.g-unit .g-tpl-50-50-alt .g-first,.g-tpl-50-50-alt .g-first{width:49.999%;float:right;margin:0}.g-tpl-nest{width:auto}.g-tpl-nest .g-section{display:inline}.g-tpl-nest .g-unit,.g-unit .g-tpl-nest .g-unit,.g-unit .g-unit .g-tpl-nest .g-unit,.g-unit .g-unit .g-unit .g-tpl-nest .g-unit{float:left;width:auto;margin:0}.g-tpl-nest-alt .g-unit,.g-unit .g-tpl-nest-alt .g-unit,.g-unit .g-unit .g-tpl-nest-alt .g-unit,.g-unit .g-unit .g-unit .g-tpl-nest-alt .g-unit{float:right;width:auto;margin:0}.goog-button{border-width:1px;border-style:solid;border-color:#bbb #999 #999 #bbb;border-radius:2px;-webkit-border-radius:2px;-moz-border-radius:2px;font:normal normal normal 13px/13px Arial,sans-serif;color:#000;text-align:middle;text-decoration:none;text-shadow:0 1px 1px rgba(255,255,255,1);background:#eee;background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#ddd));background:-moz-linear-gradient(top,#fff,#ddd);filter:progid:DXImageTransform.Microsoft.Gradient(EndColorstr='#dddddd',StartColorstr='#ffffff',GradientType=0);cursor:pointer;margin:0;display:inline;display:-moz-inline-box;display:inline-block;*overflow:visible;padding:4px 8px 5px}a.goog-button,span.goog-button,div.goog-button{padding:4px 8px 5px}.goog-button:visited{color:#000}.goog-button{*display:inline}.goog-button:focus,.goog-button:hover{border-color:#000}.goog-button:active,.goog-button-active{color:#000;background-color:#bbb;border-color:#999 #bbb #bbb #999;background-image:-webkit-gradient(linear,0 0,0 100%,from(#ddd),to(#fff));background-image:-moz-linear-gradient(top,#ddd,#fff);filter:progid:DXImageTransform.Microsoft.Gradient(EndColorstr='#ffffff',StartColorstr='#dddddd',GradientType=0)}.goog-button[disabled],.goog-button[disabled]:active,.goog-button[disabled]:hover{color:#666;border-color:#ddd;background-color:#f3f3f3;background-image:none;text-shadow:none;cursor:auto}.goog-button{padding:5px 8px 4px	}.goog-button{*padding:4px 7px 2px}html>body input.goog-button,x:-moz-any-link,x:default,html>body button.goog-button,x:-moz-any-link,x:default{padding-top:3px;padding-bottom:2px}a.goog-button,x:-moz-any-link,x:default,span.goog-button,x:-moz-any-link,x:default,div.goog-button,x:-moz-any-link,x:default{padding:4px 8px 5px}.goog-button-fixed{padding-left:0!important;padding-right:0!important;width:100%}button.goog-button-icon-c{padding-top:1px;padding-bottom:1px}button.goog-button-icon-c{padding-top:3px	;padding-bottom:2px	}button.goog-button-icon-c{*padding-top:0;*padding-bottom:0}html>body button.goog-button-icon-c,x:-moz-any-link,x:default{padding-top:1px;padding-bottom:1px}.goog-button-icon{display:block;margin:0 auto;height:18px;width:18px}html>body .goog-inline-block{display:-moz-inline-box;display:inline-block;}.goog-inline-block{position:relative;display:inline-block}* html .goog-inline-block{display:inline}*:first-child+html .goog-inline-block{display:inline}.goog-custom-button{margin:0 2px 2px;border:0;padding:0;font:normal Tahoma,Arial,sans-serif;color:#000;text-decoration:none;list-style:none;vertical-align:middle;cursor:pointer;outline:none;background:#eee;background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#ddd));background:-moz-linear-gradient(top,#fff,#ddd);filter:progid:DXImageTransform.Microsoft.Gradient(EndColorstr='#dddddd',StartColorstr='#ffffff',GradientType=0)}.goog-custom-button-outer-box,.goog-custom-button-inner-box{border-style:solid;border-color:#bbb #999 #999 #bbb;vertical-align:top}.goog-custom-button-outer-box{margin:0;border-width:1px 0;padding:0}.goog-custom-button-inner-box{margin:0 -1px;border-width:0 1px;padding:3px 4px}* html .goog-custom-button-inner-box{left:-1px}* html .goog-custom-button-rtl .goog-custom-button-outer-box{left:-1px}* html .goog-custom-button-rtl .goog-custom-button-inner-box{left:0}*:first-child+html .goog-custom-button-inner-box{left:-1px}*:first-child+html .goog-custom-button-collapse-right .goog-custom-button-inner-box{border-left-width:2px}*:first-child+html .goog-custom-button-collapse-left .goog-custom-button-inner-box{border-right-width:2px}*:first-child+html .goog-custom-button-collapse-right.goog-custom-button-collapse-left .goog-custom-button-inner-box{border-width:0 1px}*:first-child+html .goog-custom-button-rtl .goog-custom-button-inner-box{left:1px}::root .goog-custom-button,::root .goog-custom-button-outer-box{line-height:0}::root .goog-custom-button-inner-box{line-height:normal}.goog-custom-button-disabled{background-image:none!important;opacity:0.4;-moz-opacity:0.4;filter:alpha(opacity=40)}.goog-custom-button-disabled .goog-custom-button-outer-box,.goog-custom-button-disabled .goog-custom-button-inner-box{color:#333!important;border-color:#999!important}* html .goog-custom-button-disabled{margin:2px 1px!important;padding:0 1px!important}*:first-child+html .goog-custom-button-disabled{margin:2px 1px!important;padding:0 1px!important}.goog-custom-button-hover .goog-custom-button-outer-box,.goog-custom-button-hover .goog-custom-button-inner-box{border-color:#000!important;}.goog-custom-button-active,.goog-custom-button-checked{background-color:#bbb;background-position:bottom left;background-image:-webkit-gradient(linear,0 0,0 100%,from(#ddd),to(#fff));background:-moz-linear-gradient(top,#ddd,#fff);filter:progid:DXImageTransform.Microsoft.Gradient(EndColorstr='#ffffff',StartColorstr='#dddddd',GradientType=0)}.goog-custom-button-focused .goog-custom-button-outer-box,.goog-custom-button-focused .goog-custom-button-inner-box,.goog-custom-button-focused.goog-custom-button-collapse-left .goog-custom-button-inner-box,.goog-custom-button-focused.goog-custom-button-collapse-left.goog-custom-button-checked .goog-custom-button-inner-box{border-color:#000}.goog-custom-button-collapse-right,.goog-custom-button-collapse-right .goog-custom-button-outer-box,.goog-custom-button-collapse-right .goog-custom-button-inner-box{margin-right:0}.goog-custom-button-collapse-left,.goog-custom-button-collapse-left .goog-custom-button-outer-box,.goog-custom-button-collapse-left .goog-custom-button-inner-box{margin-left:0}.goog-custom-button-collapse-left .goog-custom-button-inner-box{border-left:1px solid #fff}.goog-custom-button-collapse-left.goog-custom-button-checked .goog-custom-button-inner-box{border-left:1px solid #ddd}* html .goog-custom-button-collapse-left .goog-custom-button-inner-box{left:0}*:first-child+html .goog-custom-button-collapse-left .goog-custom-button-inner-box{left:0}.goog-date-picker th,.goog-date-picker td{font-family:arial,sans-serif;text-align:center}.goog-date-picker th{font-size:.9em;font-weight:bold;color:#666667;background-color:#c3d9ff}.goog-date-picker td{vertical-align:middle;padding:2px 3px}.goog-date-picker{-moz-user-focus:normal;-moz-user-select:none;position:absolute;border:1px solid gray;float:left;font-family:arial,sans-serif;padding-left:1px;background:white}.goog-date-picker-menu{position:absolute;background:threedface;border:1px solid gray;-moz-user-focus:normal}.goog-date-picker-menu ul{list-style:none;margin:0;padding:0}.goog-date-picker-menu ul li{cursor:default}.goog-date-picker-menu-selected{background-color:#aaccee}.goog-date-picker td div{float:left}.goog-date-picker button{padding:0;margin:1px;border:1px outset gray}.goog-date-picker-week{padding:1px 3px}.goog-date-picker-wday{padding:1px 3px}.goog-date-picker-today-cont{text-align:left!important}.goog-date-picker-none-cont{text-align:right!important}.goog-date-picker-head td{text-align:center}.goog-date-picker-month{width:12ex}.goog-date-picker-year{width:6ex}.goog-date-picker table{border-collapse:collapse}.goog-date-picker-selected{background-color:#aaccee!important;color:blue!important}.goog-date-picker-today{font-weight:bold!important}.goog-date-picker-other-month{-moz-opacity:0.3;filter:Alpha(Opacity=30)}.sat,.sun{background:#eee}#button1,#button2{display:block;width:60px;text-align:center;margin:10px;padding:10px;font:normal .8em arial,sans-serif;border:1px solid #000}.goog-menu{position:absolute;color:#000;border:1px solid #b5b6b5;background-color:#f3f3f7;cursor:default;font:normal small arial,helvetica,sans-serif;margin:0;padding:0;outline:none}.goog-menuitem{padding:2px 5px;margin:0;list-style:none}.goog-menuitem-highlight{background-color:#4279a5;color:#fff}.goog-menuitem-disabled{color:#999}.goog-option{padding-left:15px!important}.goog-option-selected{background-image:url('/img/check.gif');background-position:4px 50%;background-repeat:no-repeat}.goog-menuseparator{position:relative;margin:2px 0;border-top:1px solid #999;padding:0;outline:none}.goog-submenu{position:relative}.goog-submenu-arrow{position:absolute;display:block;width:11px;height:11px;right:3px;top:4px;background-image:url('/img/menu-arrows.gif');background-repeat:no-repeat;background-position:0 0;font-size:1px}.goog-menuitem-highlight .goog-submenu-arrow{background-position:0 -11px}.goog-menuitem-disabled .goog-submenu-arrow{display:none}.goog-menu-filter{margin:2px;border:1px solid silver;background:white;overflow:hidden}.goog-menu-filter div{color:gray;position:absolute;padding:1px}.goog-menu-filter input{margin:0;border:0;background:transparent;width:100%}.goog-menuitem-partially-checked{background-image:url('/img/check-outline.gif');background-position:4px 50%;background-repeat:no-repeat}.goog-menuitem-fully-checked{background-image:url('/img/check.gif');background-position:4px 50%;background-repeat:no-repeat}.goog-menu-button{margin:0 2px 2px 2px;border:0;padding:0;font:normal Tahoma,Arial,sans-serif;color:#000;background:#ddd url("/img/button-bg.gif") repeat-x top left;text-decoration:none;list-style:none;vertical-align:middle;cursor:pointer;outline:none}.goog-menu-button-outer-box,.goog-menu-button-inner-box{border-style:solid;border-color:#aaa;vertical-align:middle}.goog-menu-button-outer-box{margin:0;border-width:1px 0;padding:0}.goog-menu-button-inner-box{margin:0 -1px;border-width:0 1px;padding:0 4px 2px 4px}* html .goog-menu-button-inner-box{left:-1px}* html .goog-menu-button-rtl .goog-menu-button-outer-box{left:-1px}* html .goog-menu-button-rtl .goog-menu-button-inner-box{left:0}*:first-child+html .goog-menu-button-inner-box{left:-1px}*:first-child+html .goog-menu-button-rtl .goog-menu-button-inner-box{left:1px}::root .goog-menu-button,::root .goog-menu-button-outer-box,::root .goog-menu-button-inner-box{line-height:0}::root .goog-menu-button-caption,::root .goog-menu-button-dropdown{line-height:normal}.goog-menu-button-disabled{background-image:none!important;opacity:0.4;-moz-opacity:0.4;filter:alpha(opacity=40)}.goog-menu-button-disabled .goog-menu-button-outer-box,.goog-menu-button-disabled .goog-menu-button-inner-box,.goog-menu-button-disabled .goog-menu-button-caption,.goog-menu-button-disabled .goog-menu-button-dropdown{color:#333!important;border-color:#999!important}* html .goog-menu-button-disabled{margin:2px 1px!important;padding:0 1px!important}*:first-child+html .goog-menu-button-disabled{margin:2px 1px!important;padding:0 1px!important}.goog-menu-button-hover .goog-menu-button-outer-box,.goog-menu-button-hover .goog-menu-button-inner-box{border-color:#9cf #69e #69e #7af!important;}.goog-menu-button-active,.goog-menu-button-open{background-color:#bbb;background-position:bottom left}.goog-menu-button-focused .goog-menu-button-outer-box,.goog-menu-button-focused .goog-menu-button-inner-box{border-color:#3366cc}.goog-menu-button-caption{padding:0 4px 0 0;vertical-align:middle}.goog-menu-button-rtl .goog-menu-button-caption{padding:0 0 0 4px}.goog-menu-button-dropdown{width:7px;background:url('/img/toolbar_icons.gif') no-repeat -176px;vertical-align:middle}.goog-flat-menu-button{margin:0 2px;padding:1px 4px;font:normal 95% Tahoma,Arial,sans-serif;color:#333;text-decoration:none;list-style:none;vertical-align:middle;cursor:pointer;outline:none;-moz-outline:none;border-width:1px;border-style:solid;border-color:#c9c9c9;background-color:#fff}.goog-flat-menu-button-disabled *{color:#999;border-color:#ccc;cursor:default}.goog-flat-menu-button-hover,.goog-flat-menu-button-hover{border-color:#9cf #69e #69e #7af!important;}.goog-flat-menu-button-active{background-color:#bbb;background-position:bottom left}.goog-flat-menu-button-focused{border-color:#3366cc}.goog-flat-menu-button-caption{padding-right:10px;vertical-align:middle}.goog-flat-menu-button-dropdown{width:7px;background:url('/img/toolbar_icons.gif') no-repeat -176px;vertical-align:middle}h1{font-size:1.8em}.g-doc{width:auto;margin:0 10px}.g-doc-1024{margin-left:10px}#ae-logo{background:url('//www.google.com/images/logos/app_engine_logo_sm.gif') 0 0 no-repeat;display:block;width:178px;height:30px;margin:4px 0 0 0}.ae-ir span{position:absolute;display:block;width:0;height:0;overflow:hidden}.ae-noscript{position:absolute;left:-5000px}#ae-lhs-nav{border-right:3px solid #e5ecf9}.ae-notification{margin-bottom:.6em;text-align:center}.ae-notification strong{display:block;width:55%;margin:0 auto;text-align:center;padding:.6em;background-color:#fff1a8;font-weight:bold}.ae-alert{font-weight:bold;background:url('/img/icn/warning.png') no-repeat;margin-bottom:.5em;padding-left:1.8em}.ae-info{background:url('/img/icn/icn-info.gif') no-repeat;margin-bottom:.5em;padding-left:1.8em}.ae-promo{padding:.5em .8em;margin:.6em 0;background-color:#fffbe8;border:1px solid #fff1a9;text-align:left}.ae-promo strong{position:relative;top:.3em}.ae-alert-text,.ae-warning-text{background-color:transparent;background-position:right 1px;padding:0 18px 0 0}.ae-alert-text{color:#c00}.ae-warning-text{color:#f90}.ae-alert-c span{display:inline-block}.ae-message{border:1px solid #e5ecf9;background-color:#f6f9ff;margin-bottom:1em;padding:.5em}.ae-errorbox{border:1px solid #f00;background-color:#fee;margin-bottom:1em;padding:1em}#bd .ae-errorbox ul{padding-bottom:0}.ae-form dt{font-weight:bold}.ae-form dt em,.ae-field-hint{margin-top:.2em;color:#666667;font-size:.85em}.ae-field-yyyymmdd,.ae-field-hhmmss{width:6em}.ae-field-hint-hhmmss{margin-left:2.3em}.ae-form label{display:block;margin:0 0 .2em 0;font-weight:bold}.ae-radio{margin-bottom:.3em}.ae-radio label{display:inline}.ae-form dd,.ae-input-row{margin-bottom:.6em}.ae-input-row-group{border:1px solid #fff1a9;background:#fffbe8;padding:8px}.ae-btn-row{margin-top:1.4em;margin-bottom:1em}.ae-btn-row-note{padding:5px 0 6px 0}.ae-btn-row-note span{padding-left:18px;padding-right:.5em;background:transparent url('/img/icn/icn-info.gif') 0 0 no-repeat}.ae-btn-primary{font-weight:bold}form .ae-cancel{margin-left:.5em}.ae-submit-inline{margin-left:.8em}.ae-radio-bullet{width:20px;float:left}.ae-label-hanging-indent{margin-left:5px}.ae-divider{margin:0 .6em 0 .5em}.ae-nowrap{white-space:nowrap}.ae-pre-wrap{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;_white-space:pre;}wbr:after{content:"\00200b"}a button{text-decoration:none}.ae-alert ul{margin-bottom:.75em;margin-top:.25em;line-height:1.5em}.ae-alert h4{color:#000;font-weight:bold;padding:0 0 .5em}.ae-form-simple-list{list-style-type:none;padding:0;margin-bottom:1em}.ae-form-simple-list li{padding:.3em 0 .5em .5em;border-bottom:1px solid #c3d9ff}div.ae-datastore-index-to-delete,div.ae-datastore-index-to-build{color:#aaa}#hd p{padding:0}#hd li{display:inline}ul{padding:0 0 1em 1.2em}#ae-userinfo{text-align:right;white-space:nowrap;}#ae-userinfo ul{padding-bottom:0;padding-top:5px}#ae-appbar-lrg{margin:0 0 1.25em 0;padding:.25em .5em;background-color:#e5ecf9;border-top:1px solid #36c}#ae-appbar-lrg h1{font-size:1.2em;padding:0}#ae-appbar-lrg h1 span{font-size:80%;font-weight:normal}#ae-appbar-lrg form{display:inline;padding-right:.1em;margin-right:.5em}#ae-appbar-lrg strong{white-space:nowrap}#ae-appbar-sml{margin:0 0 1.25em 0;height:8px;padding:0 .5em;background:#e5ecf9}.ae-rounded-sml{border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px}#ae-appbar-lrg a{margin-top:.3em}a.ae-ext-link,a span.ae-ext-link{background:url('/img/icn/icn-open-in-new-window.png') no-repeat right;padding-right:18px;margin-right:8px}.ae-no-pad{padding-left:1em}.ae-message h4{margin-bottom:.3em;padding-bottom:0}#ft{text-align:center;margin:2.5em 0 1em;padding-top:.5em;border-top:2px solid #c3d9ff}#bd h3{font-weight:bold;font-size:1.4em}#bd h3 .ae-apps-switch{font-weight:normal;font-size:.7em;margin-left:2em}#bd p{padding:0 0 1em 0}#ae-content{padding-left:1em}.ae-unimportant{color:#666}.ae-new-usr td{border-top:1px solid #ccccce;background-color:#ffe}.ae-error-td td{border:2px solid #f00;background-color:#fee}.ae-delete{cursor:pointer;border:none;background:transparent;}.ae-btn-large{background:#039 url('/img/icn/button_back.png') repeat-x;color:#fff;font-weight:bold;font-size:1.2em;padding:.5em;border:2px outset #000;cursor:pointer}.ae-breadcrumb{margin:0 0 1em}.ae-disabled,a.ae-disabled,a.ae-disabled:hover,a.ae-disabled:active{color:#666!important;text-decoration:none!important;cursor:default!important;opacity:.4!important;-moz-opacity:.4!important;filter:alpha(opacity=40)!important}input.ae-readonly{border:2px solid transparent;border-left:0;background-color:transparent}span.ae-text-input-clone{padding:5px 5px 5px 0}.ae-loading{opacity:.4;-moz-opacity:.4;filter:alpha(opacity=40)}.ae-tip{margin:1em 0;background:url('/img/tip.png') top left no-repeat;padding:2px 0 0 25px}sup.ae-new-sup{color:red}.ae-action{color:#00c;cursor:pointer;text-decoration:underline}.ae-toggle{padding-left:16px;background-position:left center;background-repeat:no-repeat;cursor:pointer}.ae-minus{background-image:url('/img/wgt/minus.gif')}.ae-plus{background-image:url('/img/wgt/plus.gif')}.ae-print{background-image:url('/img/print.gif');padding-left:19px}.ae-currency,.ae-table thead th.ae-currency{text-align:right;white-space:nowrap}#ae-loading{font-size:1.2em;position:absolute;text-align:center;top:0;width:100%}#ae-loading div{margin:0 auto;background:#fff1a9;width:5em;font-weight:bold;padding:4px 10px;-moz-border-radius-bottomleft:3px;-moz-border-radius-bottomright:3px;-webkit-border-radius-bottomleft:3px;-webkit-border-radius-bottomright:3px}.ae-occlude{filter:alpha(opacity=0);position:absolute}.g-tpl-66-34 .g-unit,.g-unit .g-tpl-66-34 .g-unit,.g-unit .g-unit .g-tpl-66-34 .g-unit,.g-unit .g-unit .g-unit .g-tpl-66-34 .g-unit{display:inline;margin:0;width:33.999%;float:right}.g-unit .g-unit .g-unit .g-tpl-66-34 .g-first,.g-unit .g-unit .g-tpl-66-34 .g-first,.g-unit .g-tpl-66-34 .g-first,.g-tpl-66-34 .g-first{display:inline;margin:0;width:65.999%;float:left}.ae-ie6-c{_margin-right:-2000px;_position:relative;_width:100%;background:#fff}h2.ae-section-header{background:#e5ecf9;padding:.2em .4em;margin-bottom:.5em}.ae-field-span{padding:3px 0}ul.ae-admin-list li{margin:0 0;padding:.1em 0}select{font:13px/13px Arial,sans-serif;color:#000;border-width:1px;border-style:solid;border-color:#bbb #999 #999 #bbb;-webkit-border-radius:2px;-moz-border-radius:2px;background:#eee;background:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#ddd));background:-moz-linear-gradient(top,#fff,#ddd);filter:progid:DXImageTransform.Microsoft.Gradient(EndColorstr='#dddddd',StartColorstr='#ffffff',GradientType=0);cursor:pointer;padding:2px 1px;margin:0}select:hover{border-color:#000}select[disabled],select[disabled]:active{color:#666;border-color:#ddd;background-color:#f3f3f3;background-image:none;text-shadow:none;cursor:auto}.ae-table-plain{border-collapse:collapse;width:100%}.ae-table{border:1px solid #c5d7ef;border-collapse:collapse;width:100%}#bd h2.ae-table-title{background:#e5ecf9;margin:0;color:#000;font-size:1em;padding:3px 0 3px 5px;border-left:1px solid #c5d7ef;border-right:1px solid #c5d7ef;border-top:1px solid #c5d7ef}.ae-table-caption,.ae-table caption{border:1px solid #c5d7ef;background:#e5ecf9;-moz-margin-start:-1px}.ae-table caption{padding:3px 5px;text-align:left}.ae-table th,.ae-table td{background-color:#fff;padding:.35em 1em .25em .35em;margin:0}.ae-table thead th{font-weight:bold;text-align:left;background:#c5d7ef;vertical-align:bottom}.ae-table thead th .ae-no-bold{font-weight:normal}.ae-table tfoot tr td{border-top:1px solid #c5d7ef;background-color:#e5ecf9}.ae-table td{border-top:1px solid #c5d7ef;border-bottom:1px solid #c5d7ef}.ae-even>td,.ae-even th,.ae-even-top td,.ae-even-tween td,.ae-even-bottom td,ol.ae-even{background-color:#e9e9e9;border-top:1px solid #c5d7ef;border-bottom:1px solid #c5d7ef}.ae-even-top td{border-bottom:0}.ae-even-bottom td{border-top:0}.ae-even-tween td{border:0}.ae-table .ae-tween td{border:0}.ae-table .ae-tween-top td{border-bottom:0}.ae-table .ae-tween-bottom td{border-top:0}#bd .ae-table .cbc{width:1.5em;padding-right:0}.ae-table #ae-live td{background-color:#ffeac0}.ae-table-fixed{table-layout:fixed}.ae-table-fixed td,.ae-table-nowrap{overflow:hidden;white-space:nowrap}.ae-paginate strong{margin:0 .5em}tfoot .ae-paginate{text-align:right}.ae-table-caption .ae-paginate,.ae-table-caption .ae-orderby{padding:2px 5px}.modal-dialog{background:#c1d9ff;border:1px solid #3a5774;color:#000;padding:4px;position:absolute;font-size:1.3em;-moz-box-shadow:0 1px 4px #333;-webkit-box-shadow:0 1px 4px #333;box-shadow:0 1px 4px #333}.modal-dialog a,.modal-dialog a:link,.modal-dialog a:visited{color:#06c;cursor:pointer}.modal-dialog-bg{background:#666;left:0;position:absolute;top:0}.modal-dialog-title{background:#e0edfe;color:#000;cursor:pointer;font-size:120%;font-weight:bold;padding:8px 15px 8px 8px;position:relative;_zoom:1;}.modal-dialog-title-close{background:#e0edfe url('https://ssl.gstatic.com/editor/editortoolbar.png') no-repeat -528px 0;cursor:default;height:15px;position:absolute;right:10px;top:8px;width:15px;vertical-align:middle}.modal-dialog-buttons,.modal-dialog-content{background-color:#fff;padding:8px}.modal-dialog-buttons button{margin-right:.75em}.goog-buttonset-default{font-weight:bold}.goog-tab{position:relative;border:1px solid #8ac;padding:4px 9px;color:#000;background:#e5ecf9;border-top-left-radius:2px;border-top-right-radius:2px;-moz-border-radius-topleft:2px;-webkit-border-top-left-radius:2px;-moz-border-radius-topright:2px;-webkit-border-top-right-radius:2px}.goog-tab-bar-top .goog-tab{margin:1px 4px 0 0;border-bottom:0;float:left}.goog-tab-bar-bottom .goog-tab{margin:0 4px 1px 0;border-top:0;float:left}.goog-tab-bar-start .goog-tab{margin:0 0 4px 1px;border-right:0}.goog-tab-bar-end .goog-tab{margin:0 1px 4px 0;border-left:0}.goog-tab-hover{text-decoration:underline;cursor:pointer}.goog-tab-disabled{color:#fff;background:#ccc;border-color:#ccc}.goog-tab-selected{background:#fff!important;color:black;font-weight:bold}.goog-tab-bar-top .goog-tab-selected{top:1px;margin-top:0;padding-bottom:5px}.goog-tab-bar-bottom .goog-tab-selected{top:-1px;margin-bottom:0;padding-top:5px}.goog-tab-bar-start .goog-tab-selected{left:1px;margin-left:0;padding-right:9px}.goog-tab-bar-end .goog-tab-selected{left:-1px;margin-right:0;padding-left:9px}.goog-tab-content{padding:.1em .8em .8em .8em;border:1px solid #8ac;border-top:none}.goog-tab-bar{position:relative;margin:0 0 0 5px;border:0;padding:0;list-style:none;cursor:default;outline:none}.goog-tab-bar-clear{border-top:1px solid #8ac;clear:both;height:0;overflow:hidden}.goog-tab-bar-start{float:left}.goog-tab-bar-end{float:right}* html .goog-tab-bar-start{margin-right:-3px}* html .goog-tab-bar-end{margin-left:-3px}#ae-nav ul{list-style-type:none;margin:0;padding:1em 0}#ae-nav ul li{padding-left:.5em}#ae-nav .ae-nav-selected{color:#000;display:block;font-weight:bold;background-color:#e5ecf9;margin-right:-1px;border-top-left-radius:4px;-moz-border-radius-topleft:4px;-webkit-border-top-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;-webkit-border-bottom-left-radius:4px}#ae-nav .ae-nav-bold{font-weight:bold}#ae-nav ul li span.ae-nav-disabled{color:#666}#ae-nav ul ul{margin:0;padding:0 0 0 .5em}#ae-nav ul ul li{padding-left:.5em}#ae-nav ul li a,#ae-nav ul li span,#ae-nav ul ul li a{padding-left:.5em}#ae-nav li a:link,#ae-nav li a:visited{color:#00c}.ae-nav-group{padding:.5em;margin:0 .75em 0 0;background-color:#fffbe8;border:1px solid #fff1a9}.ae-nav-group h4{font-weight:bold;padding:auto auto .5em .5em;padding-left:.4em;margin-bottom:.5em;padding-bottom:0}.ae-nav-group ul{margin:0 0 .5em 0;padding:0 0 0 1.3em;list-style-type:none}.ae-nav-group ul li{padding-bottom:.5em}.ae-nav-group li a:link,.ae-nav-group li a:visited{color:#00c}.ae-nav-group li a:hover{color:#00c}@media print{body{font-size:13px;width:8.5in;background:#fff}table,.ae-table-fixed{table-layout:automatic}tr{display:table-row!important}.g-doc-1024{width:8.5in}#ae-appbar-lrg,.ae-table-caption,.ae-table-nowrap,.ae-nowrap,th,td{overflow:visible!important;white-space:normal!important;background:#fff!important}.ae-print,.ae-toggle{display:none}#ae-lhs-nav-c{display:none}#ae-content{margin:0;padding:0}.goog-zippy-collapsed,.goog-zippy-expanded{background:none!important;padding:0!important}}#ae-admin-dev-table{margin:0 0 1em 0}.ae-admin-dev-tip,.ae-admin-dev-tip.ae-tip{margin:-0.31em 0 2.77em}#ae-sms-countryselect{margin-right:.5em}#ae-admin-enable-form{margin-bottom:1em}#ae-admin-services-c{margin-top:2em}#ae-admin-services{padding:0 0 0 3em;margin-bottom:1em;font-weight:bold}#ae-admin-logs-table-c{_margin-right:-2000px;_position:relative;_width:100%;background:#fff}#ae-admin-logs-table{margin:0;padding:0}#ae-admin-logs-filters{padding:3px 0 3px 5px}#ae-admin-logs-pagination{padding:6px 5px 0 0;text-align:right;width:45%}#ae-admin-logs-pagination span.ae-disabled{color:#666;background-color:transparent}#ae-admin-logs-table td{white-space:nowrap}#ae-storage-content div.ae-alert{padding-bottom:5px}#ae-admin-performance-form input[type=text]{width:2em}.ae-admin-performance-value{font-weight:normal}.ae-admin-performance-static-value{color:#666}#ae-admin-performance-frontend-class{margin-left:0.5em}.goog-slider-horizontal,.goog-twothumbslider-horizontal{position:relative;width:502px;height:7px;display:block;outline:0;margin:1.0em 0 0.9em 3em}.ae-slider-rail:before{position:relative;top:-0.462em;float:left;content:'Min';margin:0 0 0 -3em;color:#999}.ae-slider-rail{position:absolute;background-color:#d9d9d9;top:0;right:8px;bottom:0;left:8px;border:solid 1px;border-color:#a6a6a6 #b3b3b3 #bfbfbf;border-radius:5px}.ae-slider-rail:after{position:relative;top:-0.462em;float:right;content:'Max';margin:0 -3em 0 0;color:#999}.goog-slider-horizontal .goog-slider-thumb,.goog-twothumbslider-horizontal .goog-twothumbslider-value-thumb,.goog-twothumbslider-horizontal .goog-twothumbslider-extent-thumb{position:absolute;width:17px;height:17px;background:transparent url('/img/slider_thumb-down.png') no-repeat;outline:0}.goog-slider-horizontal .goog-slider-thumb{top:-5px}.goog-twothumbslider-horizontal .goog-twothumbslider-value-thumb{top:-11px}.goog-twothumbslider-horizontal .goog-twothumbslider-extent-thumb{top:2px;background-image:url('/img/slider_thumb-up.png')}.ae-admin-performance-scale{position:relative;display:inline-block;width:502px;margin:0 0 2.7em 3em}.ae-admin-performance-scale .ae-admin-performance-scale-start{position:absolute;display:inline-block;top:0;width:100%;text-align:left}.ae-admin-performance-scale .ae-admin-performance-scale-mid{position:absolute;display:inline-block;top:0;width:100%;text-align:center}.ae-admin-performance-scale .ae-admin-performance-scale-end{position:absolute;display:inline-block;top:0;width:100%;text-align:right}.ae-absolute-container{display:inline-block;width:100%}.ae-hidden-range{display:none}.ae-default-version-radio-column{width:1em}#ae-settings-builtins-change{margin-bottom:1em}#ae-billing-form-c{_margin-right:-3000px;_position:relative;_width:100%}.ae-rounded-top-small{-moz-border-radius-topleft:3px;-webkit-border-top-left-radius:3px;-moz-border-radius-topright:3px;-webkit-border-top-right-radius:3px}.ae-progress-content{height:400px}#ae-billing-tos{text-align:left;width:100%;margin-bottom:.5em}.ae-billing-budget-section{margin-bottom:1.5em}.ae-billing-budget-section .g-unit,.g-unit .ae-billing-budget-section .g-unit,.g-unit .g-unit .ae-billing-budget-section .g-unit{margin:0 0 0 11em;width:auto;float:none}.g-unit .g-unit .ae-billing-budget-section .g-first,.g-unit .ae-billing-budget-section .g-first,.ae-billing-budget-section .g-first{margin:0;width:11em;float:left}#ae-billing-form .ae-btn-row{margin-left:11em}#ae-billing-form .ae-btn-row .ae-info{margin-top:10px}#ae-billing-checkout{width:150px;float:left}#ae-billing-alloc-table{border:1px solid #c5d7ef;border-bottom:none;width:100%;margin-top:.5em}#ae-billing-alloc-table th,#ae-billing-alloc-table td{padding:.35em 1em .25em .35em;border-bottom:1px solid #c5d7ef;color:#000;white-space:nowrap}.ae-billing-resource{background-color:transparent;font-weight:normal}#ae-billing-alloc-table tr th span{font-weight:normal}#ae-billing-alloc-table tr{vertical-align:baseline}#ae-billing-alloc-table th{white-space:nowrap}#ae-billing-alloc-table .ae-editable span.ae-text-input-clone,#ae-billing-alloc-table .ae-readonly input{display:none}#ae-billing-alloc-table .ae-readonly span.ae-text-input-clone,#ae-billing-alloc-table .ae-editable input{display:inline}#ae-billing-alloc-table td span.ae-billing-warn-note,#ae-billing-table-errors .ae-billing-warn-note{margin:0;background-repeat:no-repeat;display:inline-block;background-image:url('/img/icn/warning.png');text-align:right;padding-left:16px;padding-right:.1em;height:16px;font-weight:bold}#ae-billing-alloc-table td span.ae-billing-warn-note span,#ae-billing-table-errors .ae-billing-warn-note span{vertical-align:super;font-size:80%}#ae-billing-alloc-table td span.ae-billing-error-hidden,#ae-billing-table-errors .ae-billing-error-hidden{display:none}.ae-billing-percent{font-size:80%;color:#666;margin-left:3px}#ae-billing-week-info{margin-top:5px;line-height:1.4}#ae-billing-table-errors{margin-top:.3em}#ae-billing-allocation-noscript{margin-top:1.5em}#ae-billing-allocation-custom-opts{margin-left:2.2em}#ae-billing-settings h2{font-size:1em;display:inline}#ae-billing-settings p{padding:.3em 0 .5em}#ae-billing-settings-table{margin:.4em 0 .5em}#ae-settings-resource-col{width:19%}#ae-settings-budget-col{width:11%}#ae-billing-settings-table .ae-settings-budget-col{padding-right:2em}.ae-table th.ae-settings-unit-cell,.ae-table td.ae-settings-unit-cell,.ae-table th.ae-total-unit-cell,.ae-table td.ae-total-unit-cell{padding-left:1.2em}#ae-settings-unit-col{width:18%}#ae-settings-paid-col{width:15%}#ae-settings-free-col{width:15%}#ae-settings-total-col{width:22%}.ae-billing-inline-link{margin-left:.5em}.ae-billing-settings-section{margin-bottom:2em}#ae-billing-settings form{display:inline-block}#ae-billing-settings .ae-btn-row{margin-top:0.5em}#ae-billing-budget-setup-checkout{margin-bottom:0}#ae-billing-vat-c .ae-field-hint{width:85%}#ae-billing-checkout-note{margin-top:.8em}.ae-drachma-preset{background-color:#f6f9ff;margin-left:11em}.ae-drachma-preset p{margin-top:.5em}.ae-table thead th.ae-currency-th{text-align:right}#ae-billing-logs-date{width:15%}#ae-billing-logs-event{width:69%}#ae-billing-logs-amount{text-align:right;width:8%}#ae-billing-logs-balance{text-align:right;width:8%}#ae-billing-history-expand .ae-action{margin-left:1em}.ae-table .ae-billing-usage-premier,.ae-table .ae-billing-usage-report{width:100%;*width:auto;margin:0 0 1em 0}.ae-table .ae-billing-usage-report th,.ae-table .ae-billing-usage-premier th,.ae-billing-charges th{color:#666;border-top:0}.ae-table .ae-billing-usage-report th,.ae-table .ae-billing-usage-report td,.ae-table .ae-billing-usage-premier th,.ae-table .ae-billing-usage-premier td,.ae-billing-charges th,.ae-billing-charges td{background-color:transparent;padding:.4em 0;border-bottom:1px solid #ddd}.ae-table .ae-billing-usage-report tfoot td,.ae-billing-charges tfoot td{border-bottom:none}table.ae-billing-usage-report col.ae-billing-report-resource{width:30%}table.ae-billing-usage-report col.ae-billing-report-used{width:20%}table.ae-billing-usage-report col.ae-billing-report-free{width:16%}table.ae-billing-usage-report col.ae-billing-report-paid{width:17%}table.ae-billing-usage-report col.ae-billing-report-charge{width:17%}table.ae-billing-usage-premier col.ae-billing-report-resource{width:50%}table.ae-billing-usage-premier col.ae-billing-report-used{width:30%}table.ae-billing-usage-premier col.ae-billing-report-unit{width:20%}.ae-billing-change-resource{width:85%}.ae-billing-change-budget{width:15%}#ae-billing-always-on-label{display:inline}#ae-billing-budget-buffer-label{display:inline}.ae-billing-charges{width:50%}.ae-billing-charges-charge{text-align:right}.ae-billing-usage-report-container{padding:1em 1em 0 1em}#ae-billing-new-usage{background-color:#f6f9ff}.goog-zippy-expanded{background-image:url('/img/wgt/minus.gif');cursor:pointer;background-repeat:no-repeat;padding-left:17px}.goog-zippy-collapsed{background-image:url('/img/wgt/plus.gif');cursor:pointer;background-repeat:no-repeat;padding-left:17px}#ae-admin-logs-pagination{width:auto}.ae-usage-cycle-note{color:#555}#ae-createapp-start{background-color:#c6d5f1;padding:1em;padding-bottom:2em;text-align:center}#ae-admin-app_id_alias-check,#ae-createapp-id-check{margin:0 0 0 1em}#ae-admin-app_id_alias-message{display:block;margin:.4em 0}#ae-createapp-id-content{width:100%}#ae-createapp-id-content td{vertical-align:top}#ae-createapp-id-td{white-space:nowrap;width:1%}#ae-createapp-id-td #ae-createapp-id-error{position:absolute;width:24em;padding-left:1em;white-space:normal}#ae-createapp-id-error-td{padding-left:1em}#ae-admin-dev-invite label{float:left;width:3.6em;position:relative;top:.3em}#ae-admin-dev-invite .ae-radio{margin-left:3.6em}#ae-admin-dev-invite .ae-radio label{float:none;width:auto;font-weight:normal;position:static}#ae-admin-dev-invite .goog-button{margin-left:3.6em}#ae-admin-dev-invite .ae-field-hint{margin-left:4.2em}#ae-admin-dev-invite .ae-radio .ae-field-hint{margin-left:0}.ae-you{color:#008000}#ae-authdomain-opts{margin-bottom:1em}#ae-authdomain-content .ae-input-text,#ae-authdomain-content .ae-field-hint{margin:.3em 0 .4em 2.5em}#ae-authdomain-opts a{margin-left:1em}#ae-authdomain-opts-hint{margin-top:.2em;color:#666667;font-size:.85em}#ae-authdomain-content #ae-authdomain-desc .ae-field-hint{margin-left:0}#ae-storage-opts{margin-bottom:1em}#ae-storage-content .ae-input-text,#ae-storage-content .ae-field-hint{margin:.3em 0 .4em 2.5em}#ae-storage-opts a{margin-left:1em}#ae-storage-opts-hint{margin-top:.2em;color:#666667;font-size:.85em}#ae-storage-content #ae-storage-desc .ae-field-hint{margin-left:0}#ae-dash .g-section{margin:0 0 1em}#ae-dash * .g-section{margin:0}#ae-dash-quota .ae-alert{padding-left:1.5em}.ae-dash-email-disabled{background:url('/img/icn/exclamation_circle.png') no-repeat;margin-top:.5em;margin-bottom:.5em;min-height:16px;padding-left:1.5em}#ae-dash-email-disabled-footnote{padding-left:1.5em;margin:5px 0 0;font-weight:normal}#ae-dash-graph-c{border:1px solid #c5d7ef;padding:5px 0}#ae-dash-graph-change{margin:0 0 0 5px}#ae-dash-graph-img{padding:5px;margin-top:.5em;background-color:#fff;display:block}#ae-dash-graph-nodata{text-align:center}#ae-dash .ae-logs-severity{margin-right:.5em}#ae-dash .g-c{padding:0 0 0 .1em}#ae-dash .g-tpl-50-50 .g-unit .g-c{padding:0 0 0 1em}#ae-dash .g-tpl-50-50 .g-first .g-c{padding:0 1em 0 .1em}.ae-quota-warnings{background-color:#fffbe8;margin:0;padding:.5em .5em 0;text-align:left}.ae-quota-warnings div{padding:0 0 .5em}#ae-dash-quota-refresh-info{font-size:85%}#ae-dash #ae-dash-dollar-bucket-c #ae-dash-dollar-bucket{width:100%;float:none}#ae-dash #ae-dash-quota-bar-col,#ae-dash .ae-dash-quota-bar{width:100px}#ae-dash-quotadetails #ae-dash-quota-bar-col,#ae-dash-quotadetails .ae-dash-quota-bar{width:200px}#ae-dash-quota-percent-col{width:3.5em}#ae-dash-quota-cost-col{width:15%}#ae-dash-quota-alert-col{width:3.5em}#ae-dash .ae-dash-quota-alert-td{padding:0}.ae-dash-quota-alert-td a{display:block;width:16px;height:16px}#ae-dash .ae-dash-quota-alert-td .ae-alert{display:block;width:16px;height:16px;margin:0;padding:0}#ae-dash .ae-dash-quota-alert-td .ae-dash-email-disabled{display:block;width:16px;height:16px;margin:0;padding:0}#ae-dash-quota tbody th{font-weight:normal}#ae-dash-quota caption{padding:0}#ae-dash-quota caption .g-c{padding:3px}.ae-dash-quota-bar{float:left;background-color:#c0c0c0;height:13px;margin:.1em 0 0 0;position:relative}.ae-dash-quota-footnote{margin:5px 0 0;font-weight:normal}.ae-quota-warning{background-color:#f90}.ae-quota-alert{background-color:#c00}.ae-quota-normal{background-color:#0b0}.ae-quota-alert-text{color:#c00}.ae-favicon-text{font-size:.85em}#ae-dash-popular{width:97%}#ae-dash-popular-reqsec-col{width:6.5em}#ae-dash-popular-req-col{width:7em}#ae-dash-popular-cpu-avg-col{width:9.5em}#ae-dash-popular-cpu-percent-col{width:7em}#ae-dash-popular .ae-unimportant{font-size:80%}#ae-dash-popular .ae-nowrap,#ae-dash-errors .ae-nowrap{margin-right:5px;overflow:hidden}#ae-dash-popular th span,#ae-dash-errors th span{font-size:.8em;font-weight:normal;display:block}#ae-dash-errors caption .g-unit{width:9em}#ae-dash-errors-count-col{width:5em}#ae-dash-errors-percent-col{width:7em}#ae-dash-graph-chart-type{float:left;margin-right:1em}#ae-apps-all strong.ae-disabled{color:#000;background:#eee}.ae-quota-resource{width:30%}.ae-quota-safety-limit{width:10%}#ae-quota-details h3{padding-bottom:0;margin-bottom:.25em}#ae-quota-details table{margin-bottom:1.75em}#ae-quota-details table.ae-quota-requests{margin-bottom:.5em}#ae-quota-refresh-note p{text-align:right;padding-top:.5em;padding-bottom:0;margin-bottom:0}#ae-quota-first-api.g-section{padding-bottom:0;margin-bottom:.25em}#ae-instances-summary-table,#ae-instances-details-table{margin-bottom:1em}.ae-instances-details-availability-image{float:left;margin-right:.5em}.ae-instances-small-text{font-size:80%}.ae-instances-small-text .ae-separator{color:#666}.ae-appbar-superuser-message strong{color:red}#ae-backends-table tr{vertical-align:baseline}.ae-backends-class-reminder{font-size:80%;color:#666;margin-left:3px}.ac-renderer{font:normal 13px Arial,sans-serif;position:absolute;background:#fff;border:1px solid #666;-moz-box-shadow:2px 2px 2px rgba(102,102,102,.4);-webkit-box-shadow:2px 2px 2px rgba(102,102,102,.4);width:202px}.ac-row{cursor:pointer;padding:.4em}.ac-highlighted{font-weight:bold}.ac-active{background-color:#b2b4bf}#ae-datastore-explorer-c{_margin-right:-3000px;_position:relative;_width:100%}#ae-datastore-explorer form dt{margin:1em 0 0 0}#ae-datastore-explorer #ae-datastore-explorer-labels{margin:0 0 3px}#ae-datastore-explorer-header .ae-action{margin-left:1em}#ae-datastore-explorer .id{white-space:nowrap}#ae-datastore-explorer caption{text-align:right;padding:5px}#ae-datastore-explorer-submit{margin-top:5px}#ae-datastore-explorer-namespace{margin-top:7px;margin-right:5px}#ae-datastore-stats-namespace-input,#ae-datastore-explorer-namespace-query,#ae-datastore-explorer-namespace-create{width:200px}#ae-datastore-explorer-gql-spacer{margin-top:22px}h4 #ae-datastore-explorer-gql-label{font-weight:normal}#ae-datastore-form em{font-style:normal;font-weight:normal;margin:0 0 0 .2em;color:#666}#ae-datastore-form dt{font-weight:bold}#ae-datastore-form dd{margin:.4em 0 .3em 1.5em;overflow:auto;zoom:1}#ae-datastore-form dd em{width:4em;float:left}#ae-datastore-form dd.ae-last{margin-bottom:1em}#ae-datastore-explorer-tabs-content{margin-bottom:1em}#ae-datastore-explorer-list .ae-label-row,#ae-datastore-explorer-new .ae-label-row{float:left;padding-top:.2em}#ae-datastore-explorer-list .ae-input-row,#ae-datastore-explorer-list .ae-btn-row,#ae-datastore-explorer-new .ae-input-row,#ae-datastore-explorer-new .ae-btn-row{margin-left:6em}#ae-datastore-explorer-list .ae-btn-row,#ae-datastore-explorer-new .ae-btn-row{margin-bottom:0}.ae-datastore-index-name{font-size:1.2em;font-weight:bold}.ae-table .ae-datastore-index-defs{padding-left:20px}.ae-datastore-index-defs-row{border-top:1px solid #ddd}.ae-datastore-index-defs .ae-unimportant{font-size:.8em}.ae-datastore-index-status{border:1px solid #c0dfbf;background:#f3f7f3;margin:0 25px 0 0;padding:3px}#ae-datastore-index-status-col{width:20%}#ae-datastore-index-stat-col{width:20%}.ae-datastore-index-status-Building{border-color:#edebcd;background:#fefdec}.ae-datastore-index-status-Deleting{border-color:#ccc;background:#eee}.ae-datastore-index-status-Error{border-color:#ffd3b4;background:#ffeae0}.ae-datastore-pathlink{font-size:.9em}#ae-datastore-stats-top-level-c{padding-bottom:1em;margin-bottom:1em;border-bottom:1px solid #e5ecf9}#ae-datastore-stats-top-level{width:100%}#ae-datastore-stats-piecharts-c{margin-bottom:1em}.ae-datastore-stats-piechart-label{font-size:.85em;font-weight:normal;text-align:center;padding:0}#ae-datastore-stats-property-type{width:60%}#ae-datastore-stats-size-all{width:20%}#ae-datastore-stats-index-size-all{width:20%}#ae-datastore-stats-property-name{width:40%}#ae-datastore-stats-type{width:10%}#ae-datastore-stats-size-entity{width:15%}#ae-datastore-stats-index-size-entity{width:15%}#ae-datastore-stats-percentage-size-entity{width:20%}#ae-datastore-blob-filter-form{margin-bottom:1em}#ae-datastore-blob-query-filter-label{padding-right:.5em}#ae-datastore-blob-filter-contents{padding-top:.5em}#ae-datastore-blob-date-after,#ae-datastore-blob-date-before{float:left}#ae-datastore-blob-date-after{margin-right:1em}#ae-datastore-blob-order label{font-weight:normal}#ae-datastore-blob-col-check{width:2%}#ae-datastore-blob-col-file{width:45%}#ae-datastore-blob-col-type{width:14%}#ae-datastore-blob-col-size{width:16%}#ae-blobstore-col-date{width:18%}#ae-blob-detail-filename{padding-bottom:0}#ae-blob-detail-filename span{font-weight:normal}#ae-blob-detail-key{font-size:85%}#ae-blob-detail-preview{margin-top:1em}#ae-blob-detail-dl{text-align:right}.ae-deployment-add-labels{padding:0 5px 0 20px}.ae-deployment-button-cell{width:95px}#ae-deployment-dm-dialog{width:400px}.ae-deployment-dm-selector{margin:20px 2px 20px 5px}#ae-deployment-exp-add{margin-top:5px}#ae-deployment-exp-contents{margin-top:5px;overflow:hidden}#ae-deployment-exp-desc{margin-bottom:15px}#ae-deployment-exp-div{background-color:#e5ecf9;border:1px solid #c5d7ef;margin:20px 0;padding:7px 4px}#ae-deployment-exp-hdr{font-weight:bold;margin:5px 0 5px}#ae-deployment-exp-tbl{width:400px}#ae-deployment-exp-toggle{font-weight:bold}.ae-deployment-set-button{width:22px}.ae-deployment-traffic-input{width:30px}#ae-domain-admins-list li{margin-bottom:.3em}#ae-domain-admins-list button{margin-left:.5em}#ae-new-app-dialog-c{width:500px}#ae-new-app-dialog-c .g-section{margin-bottom:1em}p.light-note{color:#555}.ae-bottom-message{margin-top:1em}#domsettings-form div.ae-radio{margin-left:1.7em}#domsettings-form div.ae-radio input{margin-left:-1.47em;float:left}#ae-logs-c{_margin-right:-2000px;_position:relative;_width:100%;background:#fff}#ae-logs{background-color:#c5d7ef;padding:1px;line-height:1.65}#ae-logs .ae-table-caption{border:0}#ae-logs-c ol,#ae-logs-c li{list-style:none;padding:0;margin:0}#ae-logs-c li li{margin:0 0 0 3px;padding:0 0 0 17px}.ae-log-noerror{padding-left:23px}#ae-logs-form .goog-inline-block{margin-top:0}.ae-logs-reqlog .snippet{margin:.1em}.ae-logs-applog .snippet{color:#666}.ae-logs-severity{display:block;float:left;height:1.2em;width:1.2em;line-height:1.2;text-align:center;text-transform:capitalize;font-weight:bold;border-radius:2px;-moz-border-radius:2px;-webkit-border-radius:2px}.ae-logs-severity-4{background-color:#f22;color:#000}.ae-logs-severity-3{background-color:#f90;color:#000}.ae-logs-severity-2{background-color:#fd0}.ae-logs-severity-1{background-color:#3c0;color:#000}.ae-logs-severity-0{background-color:#09f;color:#000}#ae-logs-legend{margin:1em 0 0 0}#ae-logs-legend ul{list-style:none;margin:0;padding:0}#ae-logs-legend li,#ae-logs-legend strong{float:left;margin:0 1em 0 0}#ae-logs-legend li span{margin-right:.3em}.ae-logs-timestamp{padding:0 5px;font-size:85%}#ae-logs-form-c{margin-bottom:5px;padding-bottom:.5em;padding-left:1em}#ae-logs-form{padding:.3em 0 0}#ae-logs-form .ae-label-row{float:left;padding-top:.2em;margin-right:0.539em}#ae-logs-form .ae-input-row,#ae-logs-form .ae-btn-row{margin-left:4em}#ae-logs-form .ae-btn-row{margin-bottom:0}#ae-logs-requests-c{margin-bottom:.1em}#ae-logs-requests-c input{margin:0}#ae-logs-requests-all-label{margin-right:0.539em}#ae-logs-form-options{margin-top:8px}#ae-logs-tip{margin:.2em 0}#ae-logs-expand{margin-right:.2em}#ae-logs-severity-level-label{margin-top:.3em;display:block}#ae-logs-filter-hint-labels-list{margin:2px 0}#ae-logs-filter-hint-labels-list span{position:absolute}#ae-logs-filter-hint-labels-list ul{margin-left:5.5em;padding:0}#ae-logs-filter-hint-labels-list li{float:left;margin-right:.4em;line-height:1.2}.ae-toggle .ae-logs-getdetails,.ae-toggle pre{display:none}.ae-log-expanded .ae-toggle pre{display:block}#ae-logs-c .ae-log .ae-toggle{cursor:default;background:none;padding-left:0}#ae-logs-c .ae-log .ae-toggle h5{cursor:pointer;background-position:0 .55em;background-repeat:no-repeat;padding-left:17px}.ae-log .ae-plus h5{background-image:url('/img/wgt/plus.gif')}.ae-log .ae-minus h5{background-image:url('/img/wgt/minus.gif')}.ae-log{overflow:hidden;background-color:#fff;padding:.3em 0;line-height:1.65;border-bottom:1px solid #c5d7ef}.ae-log .ae-even{background-color:#e9e9e9;border:0}.ae-log h5{font-weight:normal;white-space:nowrap;padding:.4em 0 0 0}.ae-log span,.ae-log strong{margin:0 .3em}.ae-log .ae-logs-snippet{color:#666}.ae-log pre,.ae-logs-expanded{padding:.3em 0 .5em 1.5em;margin:0;font-family:"Courier New"}.ae-log .file{font-weight:bold}.ae-log.ae-log-expanded .file{white-space:pre-wrap;word-wrap:break-word}.ae-logs-app .ae-logs-req{display:none}.ae-logs-req .ae-app,.ae-logs-both .ae-app{padding-left:1em}#ae-dos-blacklist-rejects-table{text-align:left}#ae-dash-quota-percent-col{width:3.5em}.ae-cron-status-ok{color:#008000;font-size:90%;font-weight:bold}.ae-cron-status-error{color:#a03;font-size:90%;font-weight:bold}#ae-cronjobs-table .ae-table td{vertical-align:top}#ae-tasks-table td{vertical-align:top}#ae-tasks-quota{margin:0 0 1em 0}#ae-tasks-quota .ae-dash-quota-bar{width:150px}#ae-tasks-quota #ae-dash-quota-bar-col,#ae-tasks-quota .ae-dash-quota-bar{width:200px}.ae-tasks-paused-row{color:#666;font-style:italic;font-weight:bold}#ae-tasks-quota .ae-quota-safety-limit{width:30%}#ae-tasks-table{margin-top:1em}#ae-tasks-queuecontrols{margin-top:1em;margin-bottom:1em}#ae-tasks-delete-col{width:1em}#ae-tasks-eta-col,#ae-tasks-creation-col{width:11em}#ae-tasks-actions-col{width:7em}#ae-tasks-retry-col{width:4em}#ae-tasks-body-col{width:6em}#ae-tasks-headers-col{width:7em}.ae-tasks-hex-column,.ae-tasks-ascii-column{width:16em}#ae-tasks-table .ae-tasks-arrow{text-align:center}
\ No newline at end of file
+html,body,div,h1,h2,h3,h4,h5,h6,p,img,dl,dt,dd,ol,ul,li,table,caption,tbody,tfoot,thead,tr,th,td,form,fieldset,embed,object,applet{margin:0;padding:0;border:0;}body{font-size:62.5%;font-family:Arial,sans-serif;color:#000;background:#fff}a{color:#00c}a:active{color:#f00}a:visited{color:#551a8b}table{border-collapse:collapse;border-width:0;empty-cells:show}ul{padding:0 0 1em 1em}ol{padding:0 0 1em 1.3em}li{line-height:1.5em;padding:0 0 .5em 0}p{padding:0 0 1em 0}h1,h2,h3,h4,h5{padding:0 0 1em 0}h1,h2{font-size:1.3em}h3{font-size:1.1em}h4,h5,table{font-size:1em}sup,sub{font-size:.7em}input,select,textarea,option{font-family:inherit;font-size:inherit}.g-doc,.g-doc-1024,.g-doc-800{font-size:130%}.g-doc{width:100%;text-align:left}.g-section{width:100%;vertical-align:top;display:inline-block}*:first-child+html .g-section{display:block}* html .g-section{overflow:hidden}@-moz-document url-prefix(''){.g-section{overflow:hidden}}@-moz-document url-prefix(''){.g-section,tt:default{overflow:visible}}.g-section,.g-unit{zoom:1}.g-split .g-unit{text-align:right}.g-split .g-first{text-align:left}.g-doc-1024{width:73.074em;min-width:950px;margin:0 auto;text-align:left}* html .g-doc-1024{width:71.313em}*+html .g-doc-1024{width:71.313em}.g-doc-800{width:57.69em;min-width:750px;margin:0 auto;text-align:left}* html .g-doc-800{width:56.3em}*+html .g-doc-800{width:56.3em}.g-tpl-160 .g-unit,.g-unit .g-tpl-160 .g-unit,.g-unit .g-unit .g-tpl-160 .g-unit,.g-unit .g-unit .g-unit .g-tpl-160 .g-unit{margin:0 0 0 160px;width:auto;float:none}.g-unit .g-unit .g-unit .g-tpl-160 .g-first,.g-unit .g-unit .g-tpl-160 .g-first,.g-unit .g-tpl-160 .g-first,.g-tpl-160 .g-first{margin:0;width:160px;float:left}.g-tpl-160-alt .g-unit,.g-unit .g-tpl-160-alt .g-unit,.g-unit .g-unit .g-tpl-160-alt .g-unit,.g-unit .g-unit .g-unit .g-tpl-160-alt .g-unit{margin:0 160px 0 0;width:auto;float:none}.g-unit .g-unit .g-unit .g-tpl-160-alt .g-first,.g-unit .g-unit .g-tpl-160-alt .g-first,.g-unit .g-tpl-160-alt .g-first,.g-tpl-160-alt .g-first{margin:0;width:160px;float:right}.g-tpl-180 .g-unit,.g-unit .g-tpl-180 .g-unit,.g-unit .g-unit .g-tpl-180 .g-unit,.g-unit .g-unit .g-unit .g-tpl-180 .g-unit{margin:0 0 0 180px;width:auto;float:none}.g-unit .g-unit .g-unit .g-tpl-180 .g-first,.g-unit .g-unit .g-tpl-180 .g-first,.g-unit .g-tpl-180 .g-first,.g-tpl-180 .g-first{margin:0;width:180px;float:left}.g-tpl-180-alt .g-unit,.g-unit .g-tpl-180-alt .g-unit,.g-unit .g-unit .g-tpl-180-alt .g-unit,.g-unit .g-unit .g-unit .g-tpl-180-alt .g-unit{margin:0 180px 0 0;width:auto;float:none}.g-unit .g-unit .g-unit .g-tpl-180-alt .g-first,.g-unit .g-unit .g-tpl-180-alt .g-first,.g-unit .g-tpl-180-alt .g-first,.g-tpl-180-alt .g-first{margin:0;width:180px;float:right}.g-tpl-300 .g-unit,.g-unit .g-tpl-300 .g-unit,.g-unit .g-unit .g-tpl-300 .g-unit,.g-unit .g-unit .g-unit .g-tpl-300 .g-unit{margin:0 0 0 300px;width:auto;float:none}.g-unit .g-unit .g-unit .g-tpl-300 .g-first,.g-unit .g-unit .g-tpl-300 .g-first,.g-unit .g-tpl-300 .g-first,.g-tpl-300 .g-first{margin:0;width:300px;float:left}.g-tpl-300-alt .g-unit,.g-unit .g-tpl-300-alt .g-unit,.g-unit .g-unit .g-tpl-300-alt .g-unit,.g-unit .g-unit .g-unit .g-tpl-300-alt .g-unit{margin:0 300px 0 0;width:auto;float:none}.g-unit .g-unit .g-unit .g-tpl-300-alt .g-first,.g-unit .g-unit .g-tpl-300-alt .g-first,.g-unit .g-tpl-300-alt .g-first,.g-tpl-300-alt .g-first{margin:0;width:300px;float:right}.g-tpl-25-75 .g-unit,.g-unit .g-tpl-25-75 .g-unit,.g-unit .g-unit .g-tpl-25-75 .g-unit,.g-unit .g-unit .g-unit .g-tpl-25-75 .g-unit{width:74.999%;float:right;margin:0}.g-unit .g-unit .g-unit .g-tpl-25-75 .g-first,.g-unit .g-unit .g-tpl-25-75 .g-first,.g-unit .g-tpl-25-75 .g-first,.g-tpl-25-75 .g-first{width:24.999%;float:left;margin:0}.g-tpl-25-75-alt .g-unit,.g-unit .g-tpl-25-75-alt .g-unit,.g-unit .g-unit .g-tpl-25-75-alt .g-unit,.g-unit .g-unit .g-unit .g-tpl-25-75-alt .g-unit{width:24.999%;float:left;margin:0}.g-unit .g-unit .g-unit .g-tpl-25-75-alt .g-first,.g-unit .g-unit .g-tpl-25-75-alt .g-first,.g-unit .g-tpl-25-75-alt .g-first,.g-tpl-25-75-alt .g-first{width:74.999%;float:right;margin:0}.g-tpl-75-25 .g-unit,.g-unit .g-tpl-75-25 .g-unit,.g-unit .g-unit .g-tpl-75-25 .g-unit,.g-unit .g-unit .g-unit .g-tpl-75-25 .g-unit{width:24.999%;float:right;margin:0}.g-unit .g-unit .g-unit .g-tpl-75-25 .g-first,.g-unit .g-unit .g-tpl-75-25 .g-first,.g-unit .g-tpl-75-25 .g-first,.g-tpl-75-25 .g-first{width:74.999%;float:left;margin:0}.g-tpl-75-25-alt .g-unit,.g-unit .g-tpl-75-25-alt .g-unit,.g-unit .g-unit .g-tpl-75-25-alt .g-unit,.g-unit .g-unit .g-unit .g-tpl-75-25-alt .g-unit{width:74.999%;float:left;margin:0}.g-unit .g-unit .g-unit .g-tpl-75-25-alt .g-first,.g-unit .g-unit .g-tpl-75-25-alt .g-first,.g-unit .g-tpl-75-25-alt .g-first,.g-tpl-75-25-alt .g-first{width:24.999%;float:right;margin:0}.g-tpl-33-67 .g-unit,.g-unit .g-tpl-33-67 .g-unit,.g-unit .g-unit .g-tpl-33-67 .g-unit,.g-unit .g-unit .g-unit .g-tpl-33-67 .g-unit{width:66.999%;float:right;margin:0}.g-unit .g-unit .g-unit .g-tpl-33-67 .g-first,.g-unit .g-unit .g-tpl-33-67 .g-first,.g-unit .g-tpl-33-67 .g-first,.g-tpl-33-67 .g-first{width:32.999%;float:left;margin:0}.g-tpl-33-67-alt .g-unit,.g-unit .g-tpl-33-67-alt .g-unit,.g-unit .g-unit .g-tpl-33-67-alt .g-unit,.g-unit .g-unit .g-unit .g-tpl-33-67-alt .g-unit{width:32.999%;float:left;margin:0}.g-unit .g-unit .g-unit .g-tpl-33-67-alt .g-first,.g-unit .g-unit .g-tpl-33-67-alt .g-first,.g-unit .g-tpl-33-67-alt .g-first,.g-tpl-33-67-alt .g-first{width:66.999%;float:right;margin:0}.g-tpl-67-33 .g-unit,.g-unit .g-tpl-67-33 .g-unit,.g-unit .g-unit .g-tpl-67-33 .g-unit,.g-unit .g-unit .g-unit .g-tpl-67-33 .g-unit{width:32.999%;float:right;margin:0}.g-unit .g-unit .g-unit .g-tpl-67-33 .g-first,.g-unit .g-unit .g-tpl-67-33 .g-first,.g-unit .g-tpl-67-33 .g-first,.g-tpl-67-33 .g-first{width:66.999%;float:left;margin:0}.g-tpl-67-33-alt .g-unit,.g-unit .g-tpl-67-33-alt .g-unit,.g-unit .g-unit .g-tpl-67-33-alt .g-unit,.g-unit .g-unit .g-unit .g-tpl-67-33-alt .g-unit{width:66.999%;float:left;margin:0}.g-unit .g-unit .g-unit .g-tpl-67-33-alt .g-first,.g-unit .g-unit .g-tpl-67-33-alt .g-first,.g-unit .g-tpl-67-33-alt .g-first,.g-tpl-67-33-alt .g-first{width:32.999%;float:right;margin:0}.g-tpl-50-50 .g-unit,.g-unit .g-tpl-50-50 .g-unit,.g-unit .g-unit .g-tpl-50-50 .g-unit,.g-unit .g-unit .g-unit .g-tpl-50-50 .g-unit{width:49.999%;float:right;margin:0}.g-unit .g-unit .g-unit .g-tpl-50-50 .g-first,.g-unit .g-unit .g-tpl-50-50 .g-first,.g-unit .g-tpl-50-50 .g-first,.g-tpl-50-50 .g-first{width:49.999%;float:left;margin:0}.g-tpl-50-50-alt .g-unit,.g-unit .g-tpl-50-50-alt .g-unit,.g-unit .g-unit .g-tpl-50-50-alt .g-unit,.g-unit .g-unit .g-unit .g-tpl-50-50-alt .g-unit{width:49.999%;float:left;margin:0}.g-unit .g-unit .g-unit .g-tpl-50-50-alt .g-first,.g-unit .g-unit .g-tpl-50-50-alt .g-first,.g-unit .g-tpl-50-50-alt .g-first,.g-tpl-50-50-alt .g-first{width:49.999%;float:right;margin:0}.g-tpl-nest{width:auto}.g-tpl-nest .g-section{display:inline}.g-tpl-nest .g-unit,.g-unit .g-tpl-nest .g-unit,.g-unit .g-unit .g-tpl-nest .g-unit,.g-unit .g-unit .g-unit .g-tpl-nest .g-unit{float:left;width:auto;margin:0}.g-tpl-nest-alt .g-unit,.g-unit .g-tpl-nest-alt .g-unit,.g-unit .g-unit .g-tpl-nest-alt .g-unit,.g-unit .g-unit .g-unit .g-tpl-nest-alt .g-unit{float:right;width:auto;margin:0}.goog-button{border-width:1px;border-style:solid;border-color:#bbb #999 #999 #bbb;border-radius:2px;-webkit-border-radius:2px;-moz-border-radius:2px;font:normal normal normal 13px/13px Arial,sans-serif;color:#000;text-align:middle;text-decoration:none;text-shadow:0 1px 1px rgba(255,255,255,1);background:#eee;background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#ddd));background:-moz-linear-gradient(top,#fff,#ddd);filter:progid:DXImageTransform.Microsoft.Gradient(EndColorstr='#dddddd',StartColorstr='#ffffff',GradientType=0);cursor:pointer;margin:0;display:inline;display:-moz-inline-box;display:inline-block;*overflow:visible;padding:4px 8px 5px}a.goog-button,span.goog-button,div.goog-button{padding:4px 8px 5px}.goog-button:visited{color:#000}.goog-button{*display:inline}.goog-button:focus,.goog-button:hover{border-color:#000}.goog-button:active,.goog-button-active{color:#000;background-color:#bbb;border-color:#999 #bbb #bbb #999;background-image:-webkit-gradient(linear,0 0,0 100%,from(#ddd),to(#fff));background-image:-moz-linear-gradient(top,#ddd,#fff);filter:progid:DXImageTransform.Microsoft.Gradient(EndColorstr='#ffffff',StartColorstr='#dddddd',GradientType=0)}.goog-button[disabled],.goog-button[disabled]:active,.goog-button[disabled]:hover{color:#666;border-color:#ddd;background-color:#f3f3f3;background-image:none;text-shadow:none;cursor:auto}.goog-button{padding:5px 8px 4px	}.goog-button{*padding:4px 7px 2px}html>body input.goog-button,x:-moz-any-link,x:default,html>body button.goog-button,x:-moz-any-link,x:default{padding-top:3px;padding-bottom:2px}a.goog-button,x:-moz-any-link,x:default,span.goog-button,x:-moz-any-link,x:default,div.goog-button,x:-moz-any-link,x:default{padding:4px 8px 5px}.goog-button-fixed{padding-left:0!important;padding-right:0!important;width:100%}button.goog-button-icon-c{padding-top:1px;padding-bottom:1px}button.goog-button-icon-c{padding-top:3px	;padding-bottom:2px	}button.goog-button-icon-c{*padding-top:0;*padding-bottom:0}html>body button.goog-button-icon-c,x:-moz-any-link,x:default{padding-top:1px;padding-bottom:1px}.goog-button-icon{display:block;margin:0 auto;height:18px;width:18px}html>body .goog-inline-block{display:-moz-inline-box;display:inline-block;}.goog-inline-block{position:relative;display:inline-block}* html .goog-inline-block{display:inline}*:first-child+html .goog-inline-block{display:inline}.goog-custom-button{margin:0 2px 2px;border:0;padding:0;font:normal Tahoma,Arial,sans-serif;color:#000;text-decoration:none;list-style:none;vertical-align:middle;cursor:pointer;outline:none;background:#eee;background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#ddd));background:-moz-linear-gradient(top,#fff,#ddd);filter:progid:DXImageTransform.Microsoft.Gradient(EndColorstr='#dddddd',StartColorstr='#ffffff',GradientType=0)}.goog-custom-button-outer-box,.goog-custom-button-inner-box{border-style:solid;border-color:#bbb #999 #999 #bbb;vertical-align:top}.goog-custom-button-outer-box{margin:0;border-width:1px 0;padding:0}.goog-custom-button-inner-box{margin:0 -1px;border-width:0 1px;padding:3px 4px}* html .goog-custom-button-inner-box{left:-1px}* html .goog-custom-button-rtl .goog-custom-button-outer-box{left:-1px}* html .goog-custom-button-rtl .goog-custom-button-inner-box{left:0}*:first-child+html .goog-custom-button-inner-box{left:-1px}*:first-child+html .goog-custom-button-collapse-right .goog-custom-button-inner-box{border-left-width:2px}*:first-child+html .goog-custom-button-collapse-left .goog-custom-button-inner-box{border-right-width:2px}*:first-child+html .goog-custom-button-collapse-right.goog-custom-button-collapse-left .goog-custom-button-inner-box{border-width:0 1px}*:first-child+html .goog-custom-button-rtl .goog-custom-button-inner-box{left:1px}::root .goog-custom-button,::root .goog-custom-button-outer-box{line-height:0}::root .goog-custom-button-inner-box{line-height:normal}.goog-custom-button-disabled{background-image:none!important;opacity:0.4;-moz-opacity:0.4;filter:alpha(opacity=40)}.goog-custom-button-disabled .goog-custom-button-outer-box,.goog-custom-button-disabled .goog-custom-button-inner-box{color:#333!important;border-color:#999!important}* html .goog-custom-button-disabled{margin:2px 1px!important;padding:0 1px!important}*:first-child+html .goog-custom-button-disabled{margin:2px 1px!important;padding:0 1px!important}.goog-custom-button-hover .goog-custom-button-outer-box,.goog-custom-button-hover .goog-custom-button-inner-box{border-color:#000!important;}.goog-custom-button-active,.goog-custom-button-checked{background-color:#bbb;background-position:bottom left;background-image:-webkit-gradient(linear,0 0,0 100%,from(#ddd),to(#fff));background:-moz-linear-gradient(top,#ddd,#fff);filter:progid:DXImageTransform.Microsoft.Gradient(EndColorstr='#ffffff',StartColorstr='#dddddd',GradientType=0)}.goog-custom-button-focused .goog-custom-button-outer-box,.goog-custom-button-focused .goog-custom-button-inner-box,.goog-custom-button-focused.goog-custom-button-collapse-left .goog-custom-button-inner-box,.goog-custom-button-focused.goog-custom-button-collapse-left.goog-custom-button-checked .goog-custom-button-inner-box{border-color:#000}.goog-custom-button-collapse-right,.goog-custom-button-collapse-right .goog-custom-button-outer-box,.goog-custom-button-collapse-right .goog-custom-button-inner-box{margin-right:0}.goog-custom-button-collapse-left,.goog-custom-button-collapse-left .goog-custom-button-outer-box,.goog-custom-button-collapse-left .goog-custom-button-inner-box{margin-left:0}.goog-custom-button-collapse-left .goog-custom-button-inner-box{border-left:1px solid #fff}.goog-custom-button-collapse-left.goog-custom-button-checked .goog-custom-button-inner-box{border-left:1px solid #ddd}* html .goog-custom-button-collapse-left .goog-custom-button-inner-box{left:0}*:first-child+html .goog-custom-button-collapse-left .goog-custom-button-inner-box{left:0}.goog-date-picker th,.goog-date-picker td{font-family:arial,sans-serif;text-align:center}.goog-date-picker th{font-size:.9em;font-weight:bold;color:#666667;background-color:#c3d9ff}.goog-date-picker td{vertical-align:middle;padding:2px 3px}.goog-date-picker{-moz-user-focus:normal;-moz-user-select:none;position:absolute;border:1px solid gray;float:left;font-family:arial,sans-serif;padding-left:1px;background:white}.goog-date-picker-menu{position:absolute;background:threedface;border:1px solid gray;-moz-user-focus:normal}.goog-date-picker-menu ul{list-style:none;margin:0;padding:0}.goog-date-picker-menu ul li{cursor:default}.goog-date-picker-menu-selected{background-color:#aaccee}.goog-date-picker td div{float:left}.goog-date-picker button{padding:0;margin:1px;border:1px outset gray}.goog-date-picker-week{padding:1px 3px}.goog-date-picker-wday{padding:1px 3px}.goog-date-picker-today-cont{text-align:left!important}.goog-date-picker-none-cont{text-align:right!important}.goog-date-picker-head td{text-align:center}.goog-date-picker-month{width:12ex}.goog-date-picker-year{width:6ex}.goog-date-picker table{border-collapse:collapse}.goog-date-picker-selected{background-color:#aaccee!important;color:blue!important}.goog-date-picker-today{font-weight:bold!important}.goog-date-picker-other-month{-moz-opacity:0.3;filter:Alpha(Opacity=30)}.sat,.sun{background:#eee}#button1,#button2{display:block;width:60px;text-align:center;margin:10px;padding:10px;font:normal .8em arial,sans-serif;border:1px solid #000}.goog-menu{position:absolute;color:#000;border:1px solid #b5b6b5;background-color:#f3f3f7;cursor:default;font:normal small arial,helvetica,sans-serif;margin:0;padding:0;outline:none}.goog-menuitem{padding:2px 5px;margin:0;list-style:none}.goog-menuitem-highlight{background-color:#4279a5;color:#fff}.goog-menuitem-disabled{color:#999}.goog-option{padding-left:15px!important}.goog-option-selected{background-image:url('/img/check.gif');background-position:4px 50%;background-repeat:no-repeat}.goog-menuseparator{position:relative;margin:2px 0;border-top:1px solid #999;padding:0;outline:none}.goog-submenu{position:relative}.goog-submenu-arrow{position:absolute;display:block;width:11px;height:11px;right:3px;top:4px;background-image:url('/img/menu-arrows.gif');background-repeat:no-repeat;background-position:0 0;font-size:1px}.goog-menuitem-highlight .goog-submenu-arrow{background-position:0 -11px}.goog-menuitem-disabled .goog-submenu-arrow{display:none}.goog-menu-filter{margin:2px;border:1px solid silver;background:white;overflow:hidden}.goog-menu-filter div{color:gray;position:absolute;padding:1px}.goog-menu-filter input{margin:0;border:0;background:transparent;width:100%}.goog-menuitem-partially-checked{background-image:url('/img/check-outline.gif');background-position:4px 50%;background-repeat:no-repeat}.goog-menuitem-fully-checked{background-image:url('/img/check.gif');background-position:4px 50%;background-repeat:no-repeat}.goog-menu-button{margin:0 2px 2px 2px;border:0;padding:0;font:normal Tahoma,Arial,sans-serif;color:#000;background:#ddd url("/img/button-bg.gif") repeat-x top left;text-decoration:none;list-style:none;vertical-align:middle;cursor:pointer;outline:none}.goog-menu-button-outer-box,.goog-menu-button-inner-box{border-style:solid;border-color:#aaa;vertical-align:middle}.goog-menu-button-outer-box{margin:0;border-width:1px 0;padding:0}.goog-menu-button-inner-box{margin:0 -1px;border-width:0 1px;padding:0 4px 2px 4px}* html .goog-menu-button-inner-box{left:-1px}* html .goog-menu-button-rtl .goog-menu-button-outer-box{left:-1px}* html .goog-menu-button-rtl .goog-menu-button-inner-box{left:0}*:first-child+html .goog-menu-button-inner-box{left:-1px}*:first-child+html .goog-menu-button-rtl .goog-menu-button-inner-box{left:1px}::root .goog-menu-button,::root .goog-menu-button-outer-box,::root .goog-menu-button-inner-box{line-height:0}::root .goog-menu-button-caption,::root .goog-menu-button-dropdown{line-height:normal}.goog-menu-button-disabled{background-image:none!important;opacity:0.4;-moz-opacity:0.4;filter:alpha(opacity=40)}.goog-menu-button-disabled .goog-menu-button-outer-box,.goog-menu-button-disabled .goog-menu-button-inner-box,.goog-menu-button-disabled .goog-menu-button-caption,.goog-menu-button-disabled .goog-menu-button-dropdown{color:#333!important;border-color:#999!important}* html .goog-menu-button-disabled{margin:2px 1px!important;padding:0 1px!important}*:first-child+html .goog-menu-button-disabled{margin:2px 1px!important;padding:0 1px!important}.goog-menu-button-hover .goog-menu-button-outer-box,.goog-menu-button-hover .goog-menu-button-inner-box{border-color:#9cf #69e #69e #7af!important;}.goog-menu-button-active,.goog-menu-button-open{background-color:#bbb;background-position:bottom left}.goog-menu-button-focused .goog-menu-button-outer-box,.goog-menu-button-focused .goog-menu-button-inner-box{border-color:#3366cc}.goog-menu-button-caption{padding:0 4px 0 0;vertical-align:middle}.goog-menu-button-rtl .goog-menu-button-caption{padding:0 0 0 4px}.goog-menu-button-dropdown{width:7px;background:url('/img/toolbar_icons.gif') no-repeat -176px;vertical-align:middle}.goog-flat-menu-button{margin:0 2px;padding:1px 4px;font:normal 95% Tahoma,Arial,sans-serif;color:#333;text-decoration:none;list-style:none;vertical-align:middle;cursor:pointer;outline:none;-moz-outline:none;border-width:1px;border-style:solid;border-color:#c9c9c9;background-color:#fff}.goog-flat-menu-button-disabled *{color:#999;border-color:#ccc;cursor:default}.goog-flat-menu-button-hover,.goog-flat-menu-button-hover{border-color:#9cf #69e #69e #7af!important;}.goog-flat-menu-button-active{background-color:#bbb;background-position:bottom left}.goog-flat-menu-button-focused{border-color:#3366cc}.goog-flat-menu-button-caption{padding-right:10px;vertical-align:middle}.goog-flat-menu-button-dropdown{width:7px;background:url('/img/toolbar_icons.gif') no-repeat -176px;vertical-align:middle}h1{font-size:1.8em}.g-doc{width:auto;margin:0 10px}.g-doc-1024{margin-left:10px}#ae-logo{background:url('//www.google.com/images/logos/app_engine_logo_sm.gif') 0 0 no-repeat;display:block;width:178px;height:30px;margin:4px 0 0 0}.ae-ir span{position:absolute;display:block;width:0;height:0;overflow:hidden}.ae-noscript{position:absolute;left:-5000px}#ae-lhs-nav{border-right:3px solid #e5ecf9}.ae-notification{margin-bottom:.6em;text-align:center}.ae-notification strong{display:block;width:55%;margin:0 auto;text-align:center;padding:.6em;background-color:#fff1a8;font-weight:bold}.ae-alert{font-weight:bold;background:url('/img/icn/warning.png') no-repeat;margin-bottom:.5em;padding-left:1.8em}.ae-info{background:url('/img/icn/icn-info.gif') no-repeat;margin-bottom:.5em;padding-left:1.8em}.ae-promo{padding:.5em .8em;margin:.6em 0;background-color:#fffbe8;border:1px solid #fff1a9;text-align:left}.ae-promo strong{position:relative;top:.3em}.ae-alert-text,.ae-warning-text{background-color:transparent;background-position:right 1px;padding:0 18px 0 0}.ae-alert-text{color:#c00}.ae-warning-text{color:#f90}.ae-alert-c span{display:inline-block}.ae-message{border:1px solid #e5ecf9;background-color:#f6f9ff;margin-bottom:1em;padding:.5em}.ae-errorbox{border:1px solid #f00;background-color:#fee;margin-bottom:1em;padding:1em}#bd .ae-errorbox ul{padding-bottom:0}.ae-form dt{font-weight:bold}.ae-form dt em,.ae-field-hint{margin-top:.2em;color:#666667;font-size:.85em}.ae-field-yyyymmdd,.ae-field-hhmmss{width:6em}.ae-field-hint-hhmmss{margin-left:2.3em}.ae-form label{display:block;margin:0 0 .2em 0;font-weight:bold}.ae-radio{margin-bottom:.3em}.ae-radio label{display:inline}.ae-form dd,.ae-input-row{margin-bottom:.6em}.ae-input-row-group{border:1px solid #fff1a9;background:#fffbe8;padding:8px}.ae-btn-row{margin-top:1.4em;margin-bottom:1em}.ae-btn-row-note{padding:5px 0 6px 0}.ae-btn-row-note span{padding-left:18px;padding-right:.5em;background:transparent url('/img/icn/icn-info.gif') 0 0 no-repeat}.ae-btn-primary{font-weight:bold}form .ae-cancel{margin-left:.5em}.ae-submit-inline{margin-left:.8em}.ae-radio-bullet{width:20px;float:left}.ae-label-hanging-indent{margin-left:5px}.ae-divider{margin:0 .6em 0 .5em}.ae-nowrap{white-space:nowrap}.ae-pre-wrap{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;_white-space:pre;}wbr:after{content:"\00200b"}a button{text-decoration:none}.ae-alert ul{margin-bottom:.75em;margin-top:.25em;line-height:1.5em}.ae-alert h4{color:#000;font-weight:bold;padding:0 0 .5em}.ae-form-simple-list{list-style-type:none;padding:0;margin-bottom:1em}.ae-form-simple-list li{padding:.3em 0 .5em .5em;border-bottom:1px solid #c3d9ff}div.ae-datastore-index-to-delete,div.ae-datastore-index-to-build{color:#aaa}#hd p{padding:0}#hd li{display:inline}ul{padding:0 0 1em 1.2em}#ae-userinfo{text-align:right;white-space:nowrap;}#ae-userinfo ul{padding-bottom:0;padding-top:5px}#ae-appbar-lrg{margin:0 0 1.25em 0;padding:.25em .5em;background-color:#e5ecf9;border-top:1px solid #36c}#ae-appbar-lrg h1{font-size:1.2em;padding:0}#ae-appbar-lrg h1 span{font-size:80%;font-weight:normal}#ae-appbar-lrg form{display:inline;padding-right:.1em;margin-right:.5em}#ae-appbar-lrg strong{white-space:nowrap}#ae-appbar-sml{margin:0 0 1.25em 0;height:8px;padding:0 .5em;background:#e5ecf9}.ae-rounded-sml{border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px}#ae-appbar-lrg a{margin-top:.3em}a.ae-ext-link,a span.ae-ext-link{background:url('/img/icn/icn-open-in-new-window.png') no-repeat right;padding-right:18px;margin-right:8px}.ae-no-pad{padding-left:1em}.ae-message h4{margin-bottom:.3em;padding-bottom:0}#ft{text-align:center;margin:2.5em 0 1em;padding-top:.5em;border-top:2px solid #c3d9ff}#bd h3{font-weight:bold;font-size:1.4em}#bd h3 .ae-apps-switch{font-weight:normal;font-size:.7em;margin-left:2em}#bd p{padding:0 0 1em 0}#ae-content{padding-left:1em}.ae-unimportant{color:#666}.ae-new-usr td{border-top:1px solid #ccccce;background-color:#ffe}.ae-error-td td{border:2px solid #f00;background-color:#fee}.ae-delete{cursor:pointer;border:none;background:transparent;}.ae-btn-large{background:#039 url('/img/icn/button_back.png') repeat-x;color:#fff;font-weight:bold;font-size:1.2em;padding:.5em;border:2px outset #000;cursor:pointer}.ae-breadcrumb{margin:0 0 1em}.ae-disabled,a.ae-disabled,a.ae-disabled:hover,a.ae-disabled:active{color:#666!important;text-decoration:none!important;cursor:default!important;opacity:.4!important;-moz-opacity:.4!important;filter:alpha(opacity=40)!important}input.ae-readonly{border:2px solid transparent;border-left:0;background-color:transparent}span.ae-text-input-clone{padding:5px 5px 5px 0}.ae-loading{opacity:.4;-moz-opacity:.4;filter:alpha(opacity=40)}.ae-tip{margin:1em 0;background:url('/img/tip.png') top left no-repeat;padding:2px 0 0 25px}sup.ae-new-sup{color:red}.ae-action{color:#00c;cursor:pointer;text-decoration:underline}.ae-toggle{padding-left:16px;background-position:left center;background-repeat:no-repeat;cursor:pointer}.ae-minus{background-image:url('/img/wgt/minus.gif')}.ae-plus{background-image:url('/img/wgt/plus.gif')}.ae-print{background-image:url('/img/print.gif');padding-left:19px}.ae-currency,.ae-table thead th.ae-currency{text-align:right;white-space:nowrap}#ae-loading{font-size:1.2em;position:absolute;text-align:center;top:0;width:100%}#ae-loading div{margin:0 auto;background:#fff1a9;width:5em;font-weight:bold;padding:4px 10px;-moz-border-radius-bottomleft:3px;-moz-border-radius-bottomright:3px;-webkit-border-radius-bottomleft:3px;-webkit-border-radius-bottomright:3px}.ae-occlude{filter:alpha(opacity=0);position:absolute}.g-tpl-66-34 .g-unit,.g-unit .g-tpl-66-34 .g-unit,.g-unit .g-unit .g-tpl-66-34 .g-unit,.g-unit .g-unit .g-unit .g-tpl-66-34 .g-unit{display:inline;margin:0;width:33.999%;float:right}.g-unit .g-unit .g-unit .g-tpl-66-34 .g-first,.g-unit .g-unit .g-tpl-66-34 .g-first,.g-unit .g-tpl-66-34 .g-first,.g-tpl-66-34 .g-first{display:inline;margin:0;width:65.999%;float:left}.ae-ie6-c{_margin-right:-2000px;_position:relative;_width:100%;background:#fff}h2.ae-section-header{background:#e5ecf9;padding:.2em .4em;margin-bottom:.5em}.ae-field-span{padding:3px 0}ul.ae-admin-list li{margin:0 0;padding:.1em 0}select{font:13px/13px Arial,sans-serif;color:#000;border-width:1px;border-style:solid;border-color:#bbb #999 #999 #bbb;-webkit-border-radius:2px;-moz-border-radius:2px;background:#eee;background:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#ddd));background:-moz-linear-gradient(top,#fff,#ddd);filter:progid:DXImageTransform.Microsoft.Gradient(EndColorstr='#dddddd',StartColorstr='#ffffff',GradientType=0);cursor:pointer;padding:2px 1px;margin:0}select:hover{border-color:#000}select[disabled],select[disabled]:active{color:#666;border-color:#ddd;background-color:#f3f3f3;background-image:none;text-shadow:none;cursor:auto}.ae-table-plain{border-collapse:collapse;width:100%}.ae-table{border:1px solid #c5d7ef;border-collapse:collapse;width:100%}#bd h2.ae-table-title{background:#e5ecf9;margin:0;color:#000;font-size:1em;padding:3px 0 3px 5px;border-left:1px solid #c5d7ef;border-right:1px solid #c5d7ef;border-top:1px solid #c5d7ef}.ae-table-caption,.ae-table caption{border:1px solid #c5d7ef;background:#e5ecf9;-moz-margin-start:-1px}.ae-table caption{padding:3px 5px;text-align:left}.ae-table th,.ae-table td{background-color:#fff;padding:.35em 1em .25em .35em;margin:0}.ae-table thead th{font-weight:bold;text-align:left;background:#c5d7ef;vertical-align:bottom}.ae-table thead th .ae-no-bold{font-weight:normal}.ae-table tfoot tr td{border-top:1px solid #c5d7ef;background-color:#e5ecf9}.ae-table td{border-top:1px solid #c5d7ef;border-bottom:1px solid #c5d7ef}.ae-even>td,.ae-even th,.ae-even-top td,.ae-even-tween td,.ae-even-bottom td,ol.ae-even{background-color:#e9e9e9;border-top:1px solid #c5d7ef;border-bottom:1px solid #c5d7ef}.ae-even-top td{border-bottom:0}.ae-even-bottom td{border-top:0}.ae-even-tween td{border:0}.ae-table .ae-tween td{border:0}.ae-table .ae-tween-top td{border-bottom:0}.ae-table .ae-tween-bottom td{border-top:0}#bd .ae-table .cbc{width:1.5em;padding-right:0}.ae-table #ae-live td{background-color:#ffeac0}.ae-table-fixed{table-layout:fixed}.ae-table-fixed td,.ae-table-nowrap{overflow:hidden;white-space:nowrap}.ae-paginate strong{margin:0 .5em}tfoot .ae-paginate{text-align:right}.ae-table-caption .ae-paginate,.ae-table-caption .ae-orderby{padding:2px 5px}.modal-dialog{background:#c1d9ff;border:1px solid #3a5774;color:#000;padding:4px;position:absolute;font-size:1.3em;-moz-box-shadow:0 1px 4px #333;-webkit-box-shadow:0 1px 4px #333;box-shadow:0 1px 4px #333}.modal-dialog a,.modal-dialog a:link,.modal-dialog a:visited{color:#06c;cursor:pointer}.modal-dialog-bg{background:#666;left:0;position:absolute;top:0}.modal-dialog-title{background:#e0edfe;color:#000;cursor:pointer;font-size:120%;font-weight:bold;padding:8px 15px 8px 8px;position:relative;_zoom:1;}.modal-dialog-title-close{background:#e0edfe url('https://ssl.gstatic.com/editor/editortoolbar.png') no-repeat -528px 0;cursor:default;height:15px;position:absolute;right:10px;top:8px;width:15px;vertical-align:middle}.modal-dialog-buttons,.modal-dialog-content{background-color:#fff;padding:8px}.modal-dialog-buttons button{margin-right:.75em}.goog-buttonset-default{font-weight:bold}.goog-tab{position:relative;border:1px solid #8ac;padding:4px 9px;color:#000;background:#e5ecf9;border-top-left-radius:2px;border-top-right-radius:2px;-moz-border-radius-topleft:2px;-webkit-border-top-left-radius:2px;-moz-border-radius-topright:2px;-webkit-border-top-right-radius:2px}.goog-tab-bar-top .goog-tab{margin:1px 4px 0 0;border-bottom:0;float:left}.goog-tab-bar-bottom .goog-tab{margin:0 4px 1px 0;border-top:0;float:left}.goog-tab-bar-start .goog-tab{margin:0 0 4px 1px;border-right:0}.goog-tab-bar-end .goog-tab{margin:0 1px 4px 0;border-left:0}.goog-tab-hover{text-decoration:underline;cursor:pointer}.goog-tab-disabled{color:#fff;background:#ccc;border-color:#ccc}.goog-tab-selected{background:#fff!important;color:black;font-weight:bold}.goog-tab-bar-top .goog-tab-selected{top:1px;margin-top:0;padding-bottom:5px}.goog-tab-bar-bottom .goog-tab-selected{top:-1px;margin-bottom:0;padding-top:5px}.goog-tab-bar-start .goog-tab-selected{left:1px;margin-left:0;padding-right:9px}.goog-tab-bar-end .goog-tab-selected{left:-1px;margin-right:0;padding-left:9px}.goog-tab-content{padding:.1em .8em .8em .8em;border:1px solid #8ac;border-top:none}.goog-tab-bar{position:relative;margin:0 0 0 5px;border:0;padding:0;list-style:none;cursor:default;outline:none}.goog-tab-bar-clear{border-top:1px solid #8ac;clear:both;height:0;overflow:hidden}.goog-tab-bar-start{float:left}.goog-tab-bar-end{float:right}* html .goog-tab-bar-start{margin-right:-3px}* html .goog-tab-bar-end{margin-left:-3px}#ae-nav ul{list-style-type:none;margin:0;padding:1em 0}#ae-nav ul li{padding-left:.5em}#ae-nav .ae-nav-selected{color:#000;display:block;font-weight:bold;background-color:#e5ecf9;margin-right:-1px;border-top-left-radius:4px;-moz-border-radius-topleft:4px;-webkit-border-top-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;-webkit-border-bottom-left-radius:4px}#ae-nav .ae-nav-bold{font-weight:bold}#ae-nav ul li span.ae-nav-disabled{color:#666}#ae-nav ul ul{margin:0;padding:0 0 0 .5em}#ae-nav ul ul li{padding-left:.5em}#ae-nav ul li a,#ae-nav ul li span,#ae-nav ul ul li a{padding-left:.5em}#ae-nav li a:link,#ae-nav li a:visited{color:#00c}.ae-nav-group{padding:.5em;margin:0 .75em 0 0;background-color:#fffbe8;border:1px solid #fff1a9}.ae-nav-group h4{font-weight:bold;padding:auto auto .5em .5em;padding-left:.4em;margin-bottom:.5em;padding-bottom:0}.ae-nav-group ul{margin:0 0 .5em 0;padding:0 0 0 1.3em;list-style-type:none}.ae-nav-group ul li{padding-bottom:.5em}.ae-nav-group li a:link,.ae-nav-group li a:visited{color:#00c}.ae-nav-group li a:hover{color:#00c}@media print{body{font-size:13px;width:8.5in;background:#fff}table,.ae-table-fixed{table-layout:automatic}tr{display:table-row!important}.g-doc-1024{width:8.5in}#ae-appbar-lrg,.ae-table-caption,.ae-table-nowrap,.ae-nowrap,th,td{overflow:visible!important;white-space:normal!important;background:#fff!important}.ae-print,.ae-toggle{display:none}#ae-lhs-nav-c{display:none}#ae-content{margin:0;padding:0}.goog-zippy-collapsed,.goog-zippy-expanded{background:none!important;padding:0!important}}#ae-admin-dev-table{margin:0 0 1em 0}.ae-admin-dev-tip,.ae-admin-dev-tip.ae-tip{margin:-0.31em 0 2.77em}#ae-sms-countryselect{margin-right:.5em}#ae-admin-enable-form{margin-bottom:1em}#ae-admin-services-c{margin-top:2em}#ae-admin-services{padding:0 0 0 3em;margin-bottom:1em;font-weight:bold}#ae-admin-logs-table-c{_margin-right:-2000px;_position:relative;_width:100%;background:#fff}#ae-admin-logs-table{margin:0;padding:0}#ae-admin-logs-filters{padding:3px 0 3px 5px}#ae-admin-logs-pagination{padding:6px 5px 0 0;text-align:right;width:45%}#ae-admin-logs-pagination span.ae-disabled{color:#666;background-color:transparent}#ae-admin-logs-table td{white-space:nowrap}#ae-storage-content div.ae-alert{padding-bottom:5px}#ae-admin-performance-form input[type=text]{width:2em}.ae-admin-performance-value{font-weight:normal}.ae-admin-performance-static-value{color:#666}#ae-admin-performance-frontend-class{margin-left:0.5em}.goog-slider-horizontal,.goog-twothumbslider-horizontal{position:relative;width:502px;height:7px;display:block;outline:0;margin:1.0em 0 0.9em 3em}.ae-slider-rail:before{position:relative;top:-0.462em;float:left;content:'Min';margin:0 0 0 -3em;color:#999}.ae-slider-rail{position:absolute;background-color:#d9d9d9;top:0;right:8px;bottom:0;left:8px;border:solid 1px;border-color:#a6a6a6 #b3b3b3 #bfbfbf;border-radius:5px}.ae-slider-rail:after{position:relative;top:-0.462em;float:right;content:'Max';margin:0 -3em 0 0;color:#999}.goog-slider-horizontal .goog-slider-thumb,.goog-twothumbslider-horizontal .goog-twothumbslider-value-thumb,.goog-twothumbslider-horizontal .goog-twothumbslider-extent-thumb{position:absolute;width:17px;height:17px;background:transparent url('/img/slider_thumb-down.png') no-repeat;outline:0}.goog-slider-horizontal .goog-slider-thumb{top:-5px}.goog-twothumbslider-horizontal .goog-twothumbslider-value-thumb{top:-11px}.goog-twothumbslider-horizontal .goog-twothumbslider-extent-thumb{top:2px;background-image:url('/img/slider_thumb-up.png')}.ae-admin-performance-scale{position:relative;display:inline-block;width:502px;margin:0 0 2.7em 3em}.ae-admin-performance-scale .ae-admin-performance-scale-start{position:absolute;display:inline-block;top:0;width:100%;text-align:left}.ae-admin-performance-scale .ae-admin-performance-scale-mid{position:absolute;display:inline-block;top:0;width:100%;text-align:center}.ae-admin-performance-scale .ae-admin-performance-scale-end{position:absolute;display:inline-block;top:0;width:100%;text-align:right}.ae-absolute-container{display:inline-block;width:100%}.ae-hidden-range{display:none}.ae-default-version-radio-column{width:1em}#ae-settings-builtins-change{margin-bottom:1em}#ae-billing-form-c{_margin-right:-3000px;_position:relative;_width:100%}.ae-rounded-top-small{-moz-border-radius-topleft:3px;-webkit-border-top-left-radius:3px;-moz-border-radius-topright:3px;-webkit-border-top-right-radius:3px}.ae-progress-content{height:400px}#ae-billing-tos{text-align:left;width:100%;margin-bottom:.5em}.ae-billing-budget-section{margin-bottom:1.5em}.ae-billing-budget-section .g-unit,.g-unit .ae-billing-budget-section .g-unit,.g-unit .g-unit .ae-billing-budget-section .g-unit{margin:0 0 0 11em;width:auto;float:none}.g-unit .g-unit .ae-billing-budget-section .g-first,.g-unit .ae-billing-budget-section .g-first,.ae-billing-budget-section .g-first{margin:0;width:11em;float:left}#ae-billing-form .ae-btn-row{margin-left:11em}#ae-billing-form .ae-btn-row .ae-info{margin-top:10px}#ae-billing-checkout{width:150px;float:left}#ae-billing-alloc-table{border:1px solid #c5d7ef;border-bottom:none;width:100%;margin-top:.5em}#ae-billing-alloc-table th,#ae-billing-alloc-table td{padding:.35em 1em .25em .35em;border-bottom:1px solid #c5d7ef;color:#000;white-space:nowrap}.ae-billing-resource{background-color:transparent;font-weight:normal}#ae-billing-alloc-table tr th span{font-weight:normal}#ae-billing-alloc-table tr{vertical-align:baseline}#ae-billing-alloc-table th{white-space:nowrap}#ae-billing-alloc-table .ae-editable span.ae-text-input-clone,#ae-billing-alloc-table .ae-readonly input{display:none}#ae-billing-alloc-table .ae-readonly span.ae-text-input-clone,#ae-billing-alloc-table .ae-editable input{display:inline}#ae-billing-alloc-table td span.ae-billing-warn-note,#ae-billing-table-errors .ae-billing-warn-note{margin:0;background-repeat:no-repeat;display:inline-block;background-image:url('/img/icn/warning.png');text-align:right;padding-left:16px;padding-right:.1em;height:16px;font-weight:bold}#ae-billing-alloc-table td span.ae-billing-warn-note span,#ae-billing-table-errors .ae-billing-warn-note span{vertical-align:super;font-size:80%}#ae-billing-alloc-table td span.ae-billing-error-hidden,#ae-billing-table-errors .ae-billing-error-hidden{display:none}.ae-billing-percent{font-size:80%;color:#666;margin-left:3px}#ae-billing-week-info{margin-top:5px;line-height:1.4}#ae-billing-table-errors{margin-top:.3em}#ae-billing-allocation-noscript{margin-top:1.5em}#ae-billing-allocation-custom-opts{margin-left:2.2em}#ae-billing-settings h2{font-size:1em;display:inline}#ae-billing-settings p{padding:.3em 0 .5em}#ae-billing-settings-table{margin:.4em 0 .5em}#ae-settings-resource-col{width:19%}#ae-settings-budget-col{width:11%}#ae-billing-settings-table .ae-settings-budget-col{padding-right:2em}.ae-table th.ae-settings-unit-cell,.ae-table td.ae-settings-unit-cell,.ae-table th.ae-total-unit-cell,.ae-table td.ae-total-unit-cell{padding-left:1.2em}#ae-settings-unit-col{width:18%}#ae-settings-paid-col{width:15%}#ae-settings-free-col{width:15%}#ae-settings-total-col{width:22%}.ae-billing-inline-link{margin-left:.5em}.ae-billing-settings-section{margin-bottom:2em}#ae-billing-settings form{display:inline-block}#ae-billing-settings .ae-btn-row{margin-top:0.5em}#ae-billing-budget-setup-checkout{margin-bottom:0}#ae-billing-vat-c .ae-field-hint{width:85%}#ae-billing-checkout-note{margin-top:.8em}.ae-drachma-preset{background-color:#f6f9ff;margin-left:11em}.ae-drachma-preset p{margin-top:.5em}.ae-table thead th.ae-currency-th{text-align:right}#ae-billing-logs-date{width:15%}#ae-billing-logs-event{width:69%}#ae-billing-logs-amount{text-align:right;width:8%}#ae-billing-logs-balance{text-align:right;width:8%}#ae-billing-history-expand .ae-action{margin-left:1em}.ae-table .ae-billing-usage-premier,.ae-table .ae-billing-usage-report{width:100%;*width:auto;margin:0 0 1em 0}.ae-table .ae-billing-usage-report th,.ae-table .ae-billing-usage-premier th,.ae-billing-charges th{color:#666;border-top:0}.ae-table .ae-billing-usage-report th,.ae-table .ae-billing-usage-report td,.ae-table .ae-billing-usage-premier th,.ae-table .ae-billing-usage-premier td,.ae-billing-charges th,.ae-billing-charges td{background-color:transparent;padding:.4em 0;border-bottom:1px solid #ddd}.ae-table .ae-billing-usage-report tfoot td,.ae-billing-charges tfoot td{border-bottom:none}table.ae-billing-usage-report col.ae-billing-report-resource{width:30%}table.ae-billing-usage-report col.ae-billing-report-used{width:20%}table.ae-billing-usage-report col.ae-billing-report-free{width:16%}table.ae-billing-usage-report col.ae-billing-report-paid{width:17%}table.ae-billing-usage-report col.ae-billing-report-charge{width:17%}table.ae-billing-usage-premier col.ae-billing-report-resource{width:50%}table.ae-billing-usage-premier col.ae-billing-report-used{width:30%}table.ae-billing-usage-premier col.ae-billing-report-unit{width:20%}.ae-billing-change-resource{width:85%}.ae-billing-change-budget{width:15%}#ae-billing-always-on-label{display:inline}#ae-billing-budget-buffer-label{display:inline}.ae-billing-charges{width:50%}.ae-billing-charges-charge{text-align:right}.ae-billing-usage-report-container{padding:1em 1em 0 1em}#ae-billing-new-usage{background-color:#f6f9ff}.goog-zippy-expanded{background-image:url('/img/wgt/minus.gif');cursor:pointer;background-repeat:no-repeat;padding-left:17px}.goog-zippy-collapsed{background-image:url('/img/wgt/plus.gif');cursor:pointer;background-repeat:no-repeat;padding-left:17px}#ae-admin-logs-pagination{width:auto}.ae-usage-cycle-note{color:#555}#ae-createapp-start{background-color:#c6d5f1;padding:1em;padding-bottom:2em;text-align:center}#ae-admin-app_id_alias-check,#ae-createapp-id-check{margin:0 0 0 1em}#ae-admin-app_id_alias-message{display:block;margin:.4em 0}#ae-createapp-id-content{width:100%}#ae-createapp-id-content td{vertical-align:top}#ae-createapp-id-td{white-space:nowrap;width:1%}#ae-createapp-id-td #ae-createapp-id-error{position:absolute;width:24em;padding-left:1em;white-space:normal}#ae-createapp-id-error-td{padding-left:1em}#ae-admin-dev-invite label{float:left;width:3.6em;position:relative;top:.3em}#ae-admin-dev-invite .ae-radio{margin-left:3.6em}#ae-admin-dev-invite .ae-radio label{float:none;width:auto;font-weight:normal;position:static}#ae-admin-dev-invite .goog-button{margin-left:3.6em}#ae-admin-dev-invite .ae-field-hint{margin-left:4.2em}#ae-admin-dev-invite .ae-radio .ae-field-hint{margin-left:0}.ae-you{color:#008000}#ae-authdomain-opts{margin-bottom:1em}#ae-authdomain-content .ae-input-text,#ae-authdomain-content .ae-field-hint{margin:.3em 0 .4em 2.5em}#ae-authdomain-opts a{margin-left:1em}#ae-authdomain-opts-hint{margin-top:.2em;color:#666667;font-size:.85em}#ae-authdomain-content #ae-authdomain-desc .ae-field-hint{margin-left:0}#ae-storage-opts{margin-bottom:1em}#ae-storage-content .ae-input-text,#ae-storage-content .ae-field-hint{margin:.3em 0 .4em 2.5em}#ae-storage-opts a{margin-left:1em}#ae-storage-opts-hint{margin-top:.2em;color:#666667;font-size:.85em}#ae-storage-content #ae-storage-desc .ae-field-hint{margin-left:0}#ae-dash .g-section{margin:0 0 1em}#ae-dash * .g-section{margin:0}#ae-dash-quota .ae-alert{padding-left:1.5em}.ae-dash-email-disabled{background:url('/img/icn/exclamation_circle.png') no-repeat;margin-top:.5em;margin-bottom:.5em;min-height:16px;padding-left:1.5em}#ae-dash-email-disabled-footnote{padding-left:1.5em;margin:5px 0 0;font-weight:normal}#ae-dash-graph-c{border:1px solid #c5d7ef;padding:5px 0}#ae-dash-graph-change{margin:0 0 0 5px}#ae-dash-graph-img{padding:5px;margin-top:.5em;background-color:#fff;display:block}#ae-dash-graph-nodata{text-align:center}#ae-dash .ae-logs-severity{margin-right:.5em}#ae-dash .g-c{padding:0 0 0 .1em}#ae-dash .g-tpl-50-50 .g-unit .g-c{padding:0 0 0 1em}#ae-dash .g-tpl-50-50 .g-first .g-c{padding:0 1em 0 .1em}.ae-quota-warnings{background-color:#fffbe8;margin:0;padding:.5em .5em 0;text-align:left}.ae-quota-warnings div{padding:0 0 .5em}#ae-dash-quota-refresh-info{font-size:85%}#ae-dash #ae-dash-dollar-bucket-c #ae-dash-dollar-bucket{width:100%;float:none}#ae-dash #ae-dash-quota-bar-col,#ae-dash .ae-dash-quota-bar{width:100px}#ae-dash-quotadetails #ae-dash-quota-bar-col,#ae-dash-quotadetails .ae-dash-quota-bar{width:200px}#ae-dash-quota-percent-col{width:3.5em}#ae-dash-quota-cost-col{width:15%}#ae-dash-quota-alert-col{width:3.5em}#ae-dash .ae-dash-quota-alert-td{padding:0}.ae-dash-quota-alert-td a{display:block;width:16px;height:16px}#ae-dash .ae-dash-quota-alert-td .ae-alert{display:block;width:16px;height:16px;margin:0;padding:0}#ae-dash .ae-dash-quota-alert-td .ae-dash-email-disabled{display:block;width:16px;height:16px;margin:0;padding:0}#ae-dash-quota tbody th{font-weight:normal}#ae-dash-quota caption{padding:0}#ae-dash-quota caption .g-c{padding:3px}.ae-dash-quota-bar{float:left;background-color:#c0c0c0;height:13px;margin:.1em 0 0 0;position:relative}.ae-dash-quota-footnote{margin:5px 0 0;font-weight:normal}.ae-quota-warning{background-color:#f90}.ae-quota-alert{background-color:#c00}.ae-quota-normal{background-color:#0b0}.ae-quota-alert-text{color:#c00}.ae-favicon-text{font-size:.85em}#ae-dash-popular{width:97%}#ae-dash-popular-reqsec-col{width:6.5em}#ae-dash-popular-req-col{width:7em}#ae-dash-popular-cpu-avg-col{width:9.5em}#ae-dash-popular-cpu-percent-col{width:7em}#ae-dash-popular .ae-unimportant{font-size:80%}#ae-dash-popular .ae-nowrap,#ae-dash-errors .ae-nowrap{margin-right:5px;overflow:hidden}#ae-dash-popular th span,#ae-dash-errors th span{font-size:.8em;font-weight:normal;display:block}#ae-dash-errors caption .g-unit{width:9em}#ae-dash-errors-count-col{width:5em}#ae-dash-errors-percent-col{width:7em}#ae-dash-graph-chart-type{float:left;margin-right:1em}#ae-apps-all strong.ae-disabled{color:#000;background:#eee}.ae-quota-resource{width:30%}.ae-quota-safety-limit{width:10%}#ae-quota-details h3{padding-bottom:0;margin-bottom:.25em}#ae-quota-details table{margin-bottom:1.75em}#ae-quota-details table.ae-quota-requests{margin-bottom:.5em}#ae-quota-refresh-note p{text-align:right;padding-top:.5em;padding-bottom:0;margin-bottom:0}#ae-quota-first-api.g-section{padding-bottom:0;margin-bottom:.25em}#ae-instances-summary-table,#ae-instances-details-table{margin-bottom:1em}.ae-instances-details-availability-image{float:left;margin-right:.5em}.ae-instances-small-text{font-size:80%}.ae-instances-small-text .ae-separator{color:#666}.ae-instances-highlight td{background-color:#fff1a8}.ae-appbar-superuser-message strong{color:red}#ae-backends-table tr{vertical-align:baseline}.ae-backends-class-reminder{font-size:80%;color:#666;margin-left:3px}.ac-renderer{font:normal 13px Arial,sans-serif;position:absolute;background:#fff;border:1px solid #666;-moz-box-shadow:2px 2px 2px rgba(102,102,102,.4);-webkit-box-shadow:2px 2px 2px rgba(102,102,102,.4);width:202px}.ac-row{cursor:pointer;padding:.4em}.ac-highlighted{font-weight:bold}.ac-active{background-color:#b2b4bf}#ae-datastore-explorer-c{_margin-right:-3000px;_position:relative;_width:100%}#ae-datastore-explorer form dt{margin:1em 0 0 0}#ae-datastore-explorer #ae-datastore-explorer-labels{margin:0 0 3px}#ae-datastore-explorer-header .ae-action{margin-left:1em}#ae-datastore-explorer .id{white-space:nowrap}#ae-datastore-explorer caption{text-align:right;padding:5px}#ae-datastore-explorer-submit{margin-top:5px}#ae-datastore-explorer-namespace{margin-top:7px;margin-right:5px}#ae-datastore-stats-namespace-input,#ae-datastore-explorer-namespace-query,#ae-datastore-explorer-namespace-create{width:200px}#ae-datastore-explorer-gql-spacer{margin-top:22px}h4 #ae-datastore-explorer-gql-label{font-weight:normal}#ae-datastore-form em{font-style:normal;font-weight:normal;margin:0 0 0 .2em;color:#666}#ae-datastore-form dt{font-weight:bold}#ae-datastore-form dd{margin:.4em 0 .3em 1.5em;overflow:auto;zoom:1}#ae-datastore-form dd em{width:4em;float:left}#ae-datastore-form dd.ae-last{margin-bottom:1em}#ae-datastore-explorer-tabs-content{margin-bottom:1em}#ae-datastore-explorer-list .ae-label-row,#ae-datastore-explorer-new .ae-label-row{float:left;padding-top:.2em}#ae-datastore-explorer-list .ae-input-row,#ae-datastore-explorer-list .ae-btn-row,#ae-datastore-explorer-new .ae-input-row,#ae-datastore-explorer-new .ae-btn-row{margin-left:6em}#ae-datastore-explorer-list .ae-btn-row,#ae-datastore-explorer-new .ae-btn-row{margin-bottom:0}.ae-datastore-index-name{font-size:1.2em;font-weight:bold}.ae-table .ae-datastore-index-defs{padding-left:20px}.ae-datastore-index-defs-row{border-top:1px solid #ddd}.ae-datastore-index-defs .ae-unimportant{font-size:.8em}.ae-datastore-index-status{border:1px solid #c0dfbf;background:#f3f7f3;margin:0 25px 0 0;padding:3px}#ae-datastore-index-status-col{width:20%}#ae-datastore-index-stat-col{width:20%}.ae-datastore-index-status-Building{border-color:#edebcd;background:#fefdec}.ae-datastore-index-status-Deleting{border-color:#ccc;background:#eee}.ae-datastore-index-status-Error{border-color:#ffd3b4;background:#ffeae0}.ae-datastore-pathlink{font-size:.9em}#ae-datastore-stats-top-level-c{padding-bottom:1em;margin-bottom:1em;border-bottom:1px solid #e5ecf9}#ae-datastore-stats-top-level{width:100%}#ae-datastore-stats-piecharts-c{margin-bottom:1em}.ae-datastore-stats-piechart-label{font-size:.85em;font-weight:normal;text-align:center;padding:0}#ae-datastore-stats-property-type{width:60%}#ae-datastore-stats-size-all{width:20%}#ae-datastore-stats-index-size-all{width:20%}#ae-datastore-stats-property-name{width:40%}#ae-datastore-stats-type{width:10%}#ae-datastore-stats-size-entity{width:15%}#ae-datastore-stats-index-size-entity{width:15%}#ae-datastore-stats-percentage-size-entity{width:20%}#ae-datastore-blob-filter-form{margin-bottom:1em}#ae-datastore-blob-query-filter-label{padding-right:.5em}#ae-datastore-blob-filter-contents{padding-top:.5em}#ae-datastore-blob-date-after,#ae-datastore-blob-date-before{float:left}#ae-datastore-blob-date-after{margin-right:1em}#ae-datastore-blob-order label{font-weight:normal}#ae-datastore-blob-col-check{width:2%}#ae-datastore-blob-col-file{width:45%}#ae-datastore-blob-col-type{width:14%}#ae-datastore-blob-col-size{width:16%}#ae-blobstore-col-date{width:18%}#ae-blob-detail-filename{padding-bottom:0}#ae-blob-detail-filename span{font-weight:normal}#ae-blob-detail-key{font-size:85%}#ae-blob-detail-preview{margin-top:1em}#ae-blob-detail-dl{text-align:right}.ae-deployment-add-labels{padding:0 5px 0 20px}.ae-deployment-button-cell{width:95px}#ae-deployment-dm-dialog{width:400px}.ae-deployment-dm-selector{margin:20px 2px 20px 5px}#ae-deployment-exp-add{margin-top:5px}#ae-deployment-exp-contents{margin-top:5px;overflow:hidden}#ae-deployment-exp-desc{margin-bottom:15px}#ae-deployment-exp-div{background-color:#e5ecf9;border:1px solid #c5d7ef;margin:20px 0;padding:7px 4px}#ae-deployment-exp-hdr{font-weight:bold;margin:5px 0 5px}#ae-deployment-exp-tbl{width:400px}#ae-deployment-exp-toggle{font-weight:bold}.ae-deployment-set-button{width:22px}.ae-deployment-traffic-input{width:30px}#ae-domain-admins-list li{margin-bottom:.3em}#ae-domain-admins-list button{margin-left:.5em}#ae-new-app-dialog-c{width:500px}#ae-new-app-dialog-c .g-section{margin-bottom:1em}p.light-note{color:#555}.ae-bottom-message{margin-top:1em}#domsettings-form div.ae-radio{margin-left:1.7em}#domsettings-form div.ae-radio input{margin-left:-1.47em;float:left}#ae-logs-c{_margin-right:-2000px;_position:relative;_width:100%;background:#fff}#ae-logs{background-color:#c5d7ef;padding:1px;line-height:1.65}#ae-logs .ae-table-caption{border:0}#ae-logs-c ol,#ae-logs-c li{list-style:none;padding:0;margin:0}#ae-logs-c li li{margin:0 0 0 3px;padding:0 0 0 17px}.ae-log-noerror{padding-left:23px}#ae-logs-form .goog-inline-block{margin-top:0}.ae-logs-usage-info{padding-left:.5em}.ae-logs-reqlog .snippet{margin:.1em}.ae-logs-applog .snippet{color:#666}.ae-logs-severity{display:block;float:left;height:1.2em;width:1.2em;line-height:1.2;text-align:center;text-transform:capitalize;font-weight:bold;border-radius:2px;-moz-border-radius:2px;-webkit-border-radius:2px}.ae-logs-severity-4{background-color:#f22;color:#000}.ae-logs-severity-3{background-color:#f90;color:#000}.ae-logs-severity-2{background-color:#fd0}.ae-logs-severity-1{background-color:#3c0;color:#000}.ae-logs-severity-0{background-color:#09f;color:#000}#ae-logs-legend{margin:1em 0 0 0}#ae-logs-legend ul{list-style:none;margin:0;padding:0}#ae-logs-legend li,#ae-logs-legend strong{float:left;margin:0 1em 0 0}#ae-logs-legend li span{margin-right:.3em}.ae-logs-timestamp{padding:0 5px;font-size:85%}#ae-logs-form-c{margin-bottom:5px;padding-bottom:.5em;padding-left:1em}#ae-logs-form{padding:.3em 0 0}#ae-logs-form .ae-label-row{float:left;padding-top:.2em;margin-right:0.539em}#ae-logs-form .ae-input-row,#ae-logs-form .ae-btn-row{margin-left:4em}#ae-logs-form .ae-btn-row{margin-bottom:0}#ae-logs-requests-c{margin-bottom:.1em}#ae-logs-requests-c input{margin:0}#ae-logs-requests-all-label{margin-right:0.539em}#ae-logs-form-options{margin-top:8px}#ae-logs-tip{margin:.2em 0}#ae-logs-expand{margin-right:.2em}#ae-logs-severity-level-label{margin-top:.3em;display:block}#ae-logs-filter-hint-labels-list{margin:2px 0}#ae-logs-filter-hint-labels-list span{position:absolute}#ae-logs-filter-hint-labels-list ul{margin-left:5.5em;padding:0}#ae-logs-filter-hint-labels-list li{float:left;margin-right:.4em;line-height:1.2}.ae-toggle .ae-logs-getdetails,.ae-toggle pre{display:none}.ae-log-expanded .ae-toggle pre{display:block}#ae-logs-c .ae-log .ae-toggle{cursor:default;background:none;padding-left:0}#ae-logs-c .ae-log .ae-toggle h5{cursor:pointer;background-position:0 .55em;background-repeat:no-repeat;padding-left:17px}.ae-log .ae-plus h5{background-image:url('/img/wgt/plus.gif')}.ae-log .ae-minus h5{background-image:url('/img/wgt/minus.gif')}.ae-log{overflow:hidden;background-color:#fff;padding:.3em 0;line-height:1.65;border-bottom:1px solid #c5d7ef}.ae-log .ae-even{background-color:#e9e9e9;border:0}.ae-log h5{font-weight:normal;white-space:nowrap;padding:.4em 0 0 0}.ae-log span,.ae-log strong{margin:0 .3em}.ae-log .ae-logs-snippet{color:#666}.ae-log pre,.ae-logs-expanded{padding:.3em 0 .5em 1.5em;margin:0;font-family:"Courier New"}.ae-log .file{font-weight:bold}.ae-log.ae-log-expanded .file{white-space:pre-wrap;word-wrap:break-word}.ae-logs-app .ae-logs-req{display:none}.ae-logs-req .ae-app,.ae-logs-both .ae-app{padding-left:1em}#ae-dos-blacklist-rejects-table{text-align:left}#ae-dash-quota-percent-col{width:3.5em}.ae-cron-status-ok{color:#008000;font-size:90%;font-weight:bold}.ae-cron-status-error{color:#a03;font-size:90%;font-weight:bold}#ae-cronjobs-table .ae-table td{vertical-align:top}#ae-tasks-table td{vertical-align:top}#ae-tasks-quota{margin:0 0 1em 0}#ae-tasks-quota .ae-dash-quota-bar{width:150px}#ae-tasks-quota #ae-dash-quota-bar-col,#ae-tasks-quota .ae-dash-quota-bar{width:200px}.ae-tasks-paused-row{color:#666;font-style:italic;font-weight:bold}#ae-tasks-quota .ae-quota-safety-limit{width:30%}#ae-tasks-table{margin-top:1em}#ae-tasks-queuecontrols{margin-top:1em;margin-bottom:1em}#ae-tasks-delete-col{width:1em}#ae-tasks-eta-col,#ae-tasks-creation-col{width:11em}#ae-tasks-actions-col{width:7em}#ae-tasks-retry-col{width:4em}#ae-tasks-body-col{width:6em}#ae-tasks-headers-col{width:7em}.ae-tasks-hex-column,.ae-tasks-ascii-column{width:16em}#ae-tasks-table .ae-tasks-arrow{text-align:center}
\ No newline at end of file
diff --git a/google/appengine/ext/datastore_admin/static/js/compiled.js b/google/appengine/ext/datastore_admin/static/js/compiled.js
index 8e9c81c..3ea3fad 100755
--- a/google/appengine/ext/datastore_admin/static/js/compiled.js
+++ b/google/appengine/ext/datastore_admin/static/js/compiled.js
@@ -1,18 +1,18 @@
 var h=void 0,j=!0,k=null,l=!1,n=document;function aa(a,b){return a.length=b}function p(a,b){return a.disabled=b}function q(a,b){return a.currentTarget=b}function ba(a,b){return a.target=b}
-var s="push",t="length",ca="propertyIsEnumerable",u="prototype",w="slice",x="replace",y="split",z="indexOf",A="target",B="call",da="keyCode",ea="handleEvent",C="type",D="apply",fa="name",F,G=this,H=function(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var d=Object[u].toString[B](a);if("[object Window]"==d)return"object";if("[object Array]"==d||"number"==typeof a[t]&&"undefined"!=typeof a.splice&&"undefined"!=typeof a[ca]&&!a[ca]("splice"))return"array";
-if("[object Function]"==d||"undefined"!=typeof a[B]&&"undefined"!=typeof a[ca]&&!a[ca]("call"))return"function"}else return"null";else if("function"==b&&"undefined"==typeof a[B])return"object";return b},ga=function(a){var b=H(a);return"array"==b||"object"==b&&"number"==typeof a[t]},I=function(a){return"string"==typeof a},ha=function(a){a=H(a);return"object"==a||"array"==a||"function"==a},K="closure_uid_"+Math.floor(2147483648*Math.random()).toString(36),ia=0,ja=function(a,b){function d(){}d.prototype=
-b[u];a.F=b[u];a.prototype=new d};var ka=function(a){this.stack=Error().stack||"";if(a)this.message=""+a};ja(ka,Error);ka[u].name="CustomError";var la=function(a,b){for(var d=1;d<arguments[t];d++)var e=(""+arguments[d])[x](/\$/g,"$$$$"),a=a[x](/\%s/,e);return a},ra=function(a,b){if(b)return a[x](ma,"&amp;")[x](na,"&lt;")[x](oa,"&gt;")[x](pa,"&quot;");if(!qa.test(a))return a;-1!=a[z]("&")&&(a=a[x](ma,"&amp;"));-1!=a[z]("<")&&(a=a[x](na,"&lt;"));-1!=a[z](">")&&(a=a[x](oa,"&gt;"));-1!=a[z]('"')&&(a=a[x](pa,"&quot;"));return a},ma=/&/g,na=/</g,oa=/>/g,pa=/\"/g,qa=/[&<>\"]/;Math.random();var sa=function(a,b){b.unshift(a);ka[B](this,la[D](k,b));b.shift();this.H=a};ja(sa,ka);sa[u].name="AssertionError";var ta=function(a,b,d){if(!a){var e=Array[u][w][B](arguments,2),f="Assertion failed";if(b)var f=f+(": "+b),c=e;throw new sa(""+f,c||[]);}return a};var L=Array[u],ua=L[z]?function(a,b,d){ta(a[t]!=k);return L[z][B](a,b,d)}:function(a,b,d){d=d==k?0:0>d?Math.max(0,a[t]+d):d;if(I(a))return!I(b)||1!=b[t]?-1:a[z](b,d);for(;d<a[t];d++)if(d in a&&a[d]===b)return d;return-1},va=L.forEach?function(a,b,d){ta(a[t]!=k);L.forEach[B](a,b,d)}:function(a,b,d){for(var e=a[t],f=I(a)?a[y](""):a,c=0;c<e;c++)c in f&&b[B](d,f[c],c,a)},wa=function(a){return L.concat[D](L,arguments)},xa=function(a){if("array"==H(a))return wa(a);for(var b=[],d=0,e=a[t];d<e;d++)b[d]=a[d];
-return b},ya=function(a,b,d){ta(a[t]!=k);return 2>=arguments[t]?L[w][B](a,b):L[w][B](a,b,d)};var za=function(a,b,d){for(var e in a)b[B](d,a[e],e,a)},Aa="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(","),Ba=function(a,b){for(var d,e,f=1;f<arguments[t];f++){e=arguments[f];for(d in e)a[d]=e[d];for(var c=0;c<Aa[t];c++)d=Aa[c],Object[u].hasOwnProperty[B](e,d)&&(a[d]=e[d])}};var M,Ca,Da,Ea,Fa,Ga=function(){return G.navigator?G.navigator.userAgent:k},Ha=function(){return G.navigator};Ea=Da=Ca=M=l;var N;if(N=Ga()){var Ia=Ha();M=0==N[z]("Opera");Ca=!M&&-1!=N[z]("MSIE");(Da=!M&&-1!=N[z]("WebKit"))&&N[z]("Mobile");Ea=!M&&!Da&&"Gecko"==Ia.product}var Ja=M,O=Ca,P=Ea,Q=Da,Ka=Ha(),La=Ka&&Ka.platform||"";Fa=-1!=La[z]("Mac");La[z]("Win");La[z]("Linux");Ha()&&(Ha().appVersion||"")[z]("X11");var Ma;
-a:{var Na="",R;if(Ja&&G.opera)var Oa=G.opera.version,Na="function"==typeof Oa?Oa():Oa;else if(P?R=/rv\:([^\);]+)(\)|;)/:O?R=/MSIE\s+([^\);]+)(\)|;)/:Q&&(R=/WebKit\/(\S+)/),R)var Pa=R.exec(Ga()),Na=Pa?Pa[1]:"";if(O){var Qa,Ra=G.document;Qa=Ra?Ra.documentMode:h;if(Qa>parseFloat(Na)){Ma=""+Qa;break a}}Ma=Na}
-var Sa=Ma,Ta={},S=function(a){var b;if(!(b=Ta[a])){var d=0;b=(""+Sa)[x](/^[\s\xa0]+|[\s\xa0]+$/g,"")[y](".");for(var e=(""+a)[x](/^[\s\xa0]+|[\s\xa0]+$/g,"")[y]("."),f=Math.max(b[t],e[t]),c=0;0==d&&c<f;c++){var g=b[c]||"",i=e[c]||"",m=RegExp("(\\d*)(\\D*)","g"),o=RegExp("(\\d*)(\\D*)","g");do{var v=m.exec(g)||["","",""],r=o.exec(i)||["","",""];if(0==v[0][t]&&0==r[0][t])break;var d=0==v[1][t]?0:parseInt(v[1],10),J=0==r[1][t]?0:parseInt(r[1],10),d=(d<J?-1:d>J?1:0)||((0==v[2][t])<(0==r[2][t])?-1:(0==
-v[2][t])>(0==r[2][t])?1:0)||(v[2]<r[2]?-1:v[2]>r[2]?1:0)}while(0==d)}b=Ta[a]=0<=d}return b},Ua={},Va=function(a){return Ua[a]||(Ua[a]=O&&n.documentMode&&n.documentMode>=a)};var Wa=!O||Va(9);!P&&!O||O&&Va(9)||P&&S("1.9.1");O&&S("9");var Xa=function(a,b){var d;d=(d=a.className)&&"function"==typeof d[y]?d[y](/\s+/):[];var e=ya(arguments,1),f;f=d;for(var c=0,g=0;g<e[t];g++)0<=ua(f,e[g])||(f[s](e[g]),c++);f=c==e[t];a.className=d.join(" ");return f};var Ya=function(a,b,d,e){var a=e||a,f=b&&"*"!=b?b.toUpperCase():"";if(a.querySelectorAll&&a.querySelector&&(!Q||"CSS1Compat"==n.compatMode||S("528"))&&(f||d))return a.querySelectorAll(f+(d?"."+d:""));if(d&&a.getElementsByClassName){b=a.getElementsByClassName(d);if(f){for(var a={},c=e=0,g;g=b[c];c++)f==g.nodeName&&(a[e++]=g);aa(a,e);return a}return b}b=a.getElementsByTagName(f||"*");if(d){a={};for(c=e=0;g=b[c];c++){var f=g.className,i;if(i="function"==typeof f[y])f=f[y](/\s+/),i=0<=ua(f,d);i&&(a[e++]=
-g)}aa(a,e);return a}return b},$a=function(a,b){za(b,function(b,e){"style"==e?a.style.cssText=b:"class"==e?a.className=b:"for"==e?a.htmlFor=b:e in Za?a.setAttribute(Za[e],b):0==e.lastIndexOf("aria-",0)?a.setAttribute(e,b):a[e]=b})},Za={cellpadding:"cellPadding",cellspacing:"cellSpacing",colspan:"colSpan",rowspan:"rowSpan",valign:"vAlign",height:"height",width:"width",usemap:"useMap",frameborder:"frameBorder",maxlength:"maxLength",type:"type"},bb=function(a,b,d,e){function f(c){c&&b.appendChild(I(c)?
-a.createTextNode(c):c)}for(;e<d[t];e++){var c=d[e];ga(c)&&!(ha(c)&&0<c.nodeType)?va(ab(c)?xa(c):c,f):f(c)}},cb=function(a,b,d){var e=n,f=arguments,c=f[0],g=f[1];if(!Wa&&g&&(g[fa]||g[C])){c=["<",c];g[fa]&&c[s](' name="',ra(g[fa]),'"');if(g[C]){c[s](' type="',ra(g[C]),'"');var i={};Ba(i,g);g=i;delete g[C]}c[s](">");c=c.join("")}c=e.createElement(c);if(g)I(g)?c.className=g:"array"==H(g)?Xa[D](k,[c].concat(g)):$a(c,g);2<f[t]&&bb(e,c,f,2);return c},ab=function(a){if(a&&"number"==typeof a[t]){if(ha(a))return"function"==
-typeof a.item||"string"==typeof a.item;if("function"==H(a))return"function"==typeof a.item}return l};var db=function(a){db[" "](a);return a};db[" "]=function(){};!O||Va(9);var eb=!O||Va(9);O&&S("8");!Q||S("528");P&&S("1.9b")||O&&S("8")||Ja&&S("9.5")||Q&&S("528");!P||S("8");var fb=function(){};fb[u].v=l;fb[u].m=function(){if(!this.v)this.v=j,this.n()};fb[u].n=function(){this.G&&gb[D](k,this.G)};var gb=function(a){for(var b=0,d=arguments[t];b<d;++b){var e=arguments[b];ga(e)?gb[D](k,e):e&&"function"==typeof e.m&&e.m()}};var T=function(a,b){this.type=a;ba(this,b);q(this,this[A])};ja(T,fb);T[u].n=function(){delete this[C];delete this[A];delete this.currentTarget};T[u].o=l;T[u].D=j;var U=function(a,b){a&&this.i(a,b)};ja(U,T);F=U[u];ba(F,k);F.relatedTarget=k;F.offsetX=0;F.offsetY=0;F.clientX=0;F.clientY=0;F.screenX=0;F.screenY=0;F.button=0;F.keyCode=0;F.charCode=0;F.ctrlKey=l;F.altKey=l;F.shiftKey=l;F.metaKey=l;F.C=l;F.u=k;
-F.i=function(a,b){var d=this.type=a[C];T[B](this,d);ba(this,a[A]||a.srcElement);q(this,b);var e=a.relatedTarget;if(e){if(P){var f;a:{try{db(e.nodeName);f=j;break a}catch(c){}f=l}f||(e=k)}}else if("mouseover"==d)e=a.fromElement;else if("mouseout"==d)e=a.toElement;this.relatedTarget=e;this.offsetX=Q||a.offsetX!==h?a.offsetX:a.layerX;this.offsetY=Q||a.offsetY!==h?a.offsetY:a.layerY;this.clientX=a.clientX!==h?a.clientX:a.pageX;this.clientY=a.clientY!==h?a.clientY:a.pageY;this.screenX=a.screenX||0;this.screenY=
-a.screenY||0;this.button=a.button;this.keyCode=a[da]||0;this.charCode=a.charCode||("keypress"==d?a[da]:0);this.ctrlKey=a.ctrlKey;this.altKey=a.altKey;this.shiftKey=a.shiftKey;this.metaKey=a.metaKey;this.C=Fa?a.metaKey:a.ctrlKey;this.state=a.state;this.u=a;delete this.D;delete this.o};F.n=function(){U.F.n[B](this);this.u=k;ba(this,k);q(this,k);this.relatedTarget=k};var hb=function(){},ib=0;F=hb[u];F.b=0;F.e=l;F.s=l;F.i=function(a,b,d,e,f,c){if("function"==H(a))this.t=j;else if(a&&a[ea]&&"function"==H(a[ea]))this.t=l;else throw Error("Invalid listener argument");this.h=a;this.q=b;this.src=d;this.type=e;this.z=!!f;this.p=c;this.s=l;this.b=++ib;this.e=l};F.handleEvent=function(a){return this.t?this.h[B](this.p||this.src,a):this.h[ea][B](this.h,a)};var V={},W={},X={},Y={},jb=function(a,b,d,e,f){if(b){if("array"==H(b)){for(var c=0;c<b[t];c++)jb(a,b[c],d,e,f);return k}var e=!!e,g=W;b in g||(g[b]={a:0,c:0});g=g[b];e in g||(g[e]={a:0,c:0},g.a++);var g=g[e],i=a[K]||(a[K]=++ia),m;g.c++;if(g[i]){m=g[i];for(c=0;c<m[t];c++)if(g=m[c],g.h==d&&g.p==f){if(g.e)break;return m[c].b}}else m=g[i]=[],g.a++;c=kb();c.src=a;g=new hb;g.i(d,c,a,b,e,f);d=g.b;c.b=d;m[s](g);V[d]=g;X[i]||(X[i]=[]);X[i][s](g);a.addEventListener?(a==G||!a.w)&&a.addEventListener(b,c,e):a.attachEvent(b in
-Y?Y[b]:Y[b]="on"+b,c);return d}throw Error("Invalid event type");},kb=function(){var a=lb,b=eb?function(d){return a[B](b.src,b.b,d)}:function(d){d=a[B](b.src,b.b,d);if(!d)return d};return b},mb=function(a,b,d,e){if(!e.l&&e.r){for(var f=0,c=0;f<e[t];f++)e[f].e?e[f].q.src=k:(f!=c&&(e[c]=e[f]),c++);aa(e,c);e.r=l;0==c&&(delete W[a][b][d],W[a][b].a--,0==W[a][b].a&&(delete W[a][b],W[a].a--),0==W[a].a&&delete W[a])}},ob=function(a,b,d,e,f){var c=1,b=b[K]||(b[K]=++ia);if(a[b]){a.c--;a=a[b];a.l?a.l++:a.l=
-1;try{for(var g=a[t],i=0;i<g;i++){var m=a[i];m&&!m.e&&(c&=nb(m,f)!==l)}}finally{a.l--,mb(d,e,b,a)}}return Boolean(c)},nb=function(a,b){var d=a[ea](b);if(a.s){var e=a.b;if(V[e]){var f=V[e];if(!f.e){var c=f.src,g=f[C],i=f.q,m=f.z;c.removeEventListener?(c==G||!c.w)&&c.removeEventListener(g,i,m):c.detachEvent&&c.detachEvent(g in Y?Y[g]:Y[g]="on"+g,i);c=c[K]||(c[K]=++ia);i=W[g][m][c];if(X[c]){var o=X[c],v=ua(o,f);0<=v&&(ta(o[t]!=k),L.splice[B](o,v,1));0==o[t]&&delete X[c]}f.e=j;i.r=j;mb(g,m,c,i);delete V[e]}}}return d},
-lb=function(a,b){if(!V[a])return j;var d=V[a],e=d[C],f=W;if(!(e in f))return j;var f=f[e],c,g;if(!eb){var i;if(!(i=b))a:{i="window.event"[y](".");for(var m=G;c=i.shift();)if(m[c]!=k)m=m[c];else{i=k;break a}i=m}c=i;i=j in f;m=l in f;if(i){if(0>c[da]||c.returnValue!=h)return j;a:{var o=l;if(0==c[da])try{c.keyCode=-1;break a}catch(v){o=j}if(o||c.returnValue==h)c.returnValue=j}}o=new U;o.i(c,this);c=j;try{if(i){for(var r=[],J=o.currentTarget;J;J=J.parentNode)r[s](J);g=f[j];g.c=g.a;for(var E=r[t]-1;!o.o&&
-0<=E&&g.c;E--)q(o,r[E]),c&=ob(g,r[E],e,j,o);if(m){g=f[l];g.c=g.a;for(E=0;!o.o&&E<r[t]&&g.c;E++)q(o,r[E]),c&=ob(g,r[E],e,l,o)}}else c=nb(d,o)}finally{r&&aa(r,0),o.m()}return c}e=new U(b,this);try{c=nb(d,e)}finally{e.m()}return c};var pb=function(a,b){var d=[];1<arguments[t]&&(d=Array[u][w][B](arguments)[w](1));var e=Ya(n,"th","tct-selectall",a);if(0!=e[t]){var e=e[0],f=0,c=Ya(n,"tbody",k,a);c[t]&&(f=c[0].rows[t]);this.f=cb("input",{type:"checkbox"});e.appendChild(this.f);f?jb(this.f,"click",this.B,l,this):p(this.f,j);this.g=[];this.j=[];this.k=[];e=Ya(n,"input",k,a);for(f=0;c=e[f];f++)"checkbox"==c[C]&&c!=this.f?(this.g[s](c),jb(c,"click",this.A,l,this)):"action"==c[fa]&&(0<=d[z](c.value)?this.k[s](c):this.j[s](c),p(c,j))}};
-F=pb[u];F.g=k;F.d=0;F.f=k;F.j=k;F.k=k;F.B=function(a){for(var b=a[A].checked,d=a=0,e;e=this.g[d];d++)e.checked=b,a+=1;this.d=b?this.g[t]:0;for(d=0;b=this.j[d];d++)p(b,!this.d);for(d=0;b=this.k[d];d++)p(b,1!=a?j:l)};F.A=function(a){this.d+=a[A].checked?1:-1;this.f.checked=this.d==this.g[t];for(var a=0,b;b=this.j[a];a++)p(b,!this.d);for(a=0;b=this.k[a];a++)p(b,1!=this.d?j:l)};var qb=function(){var a=I("kinds")?n.getElementById("kinds"):"kinds";a&&new pb(a);(a=I("backups")?n.getElementById("backups"):"backups")&&new pb(a,"Restore")},Z="ae.Datastore.Admin.init"[y]("."),$=G;!(Z[0]in $)&&$.execScript&&$.execScript("var "+Z[0]);for(var rb;Z[t]&&(rb=Z.shift());)!Z[t]&&qb!==h?$[rb]=qb:$=$[rb]?$[rb]:$[rb]={};
+var s="push",t="length",ca="propertyIsEnumerable",u="prototype",w="slice",x="replace",y="split",z="indexOf",A="target",B="call",da="keyCode",ea="handleEvent",C="type",E="apply",fa="name",F,G=this,H=function(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var d=Object[u].toString[B](a);if("[object Window]"==d)return"object";if("[object Array]"==d||"number"==typeof a[t]&&"undefined"!=typeof a.splice&&"undefined"!=typeof a[ca]&&!a[ca]("splice"))return"array";
+if("[object Function]"==d||"undefined"!=typeof a[B]&&"undefined"!=typeof a[ca]&&!a[ca]("call"))return"function"}else return"null";else if("function"==b&&"undefined"==typeof a[B])return"object";return b},ga=function(a){var b=H(a);return"array"==b||"object"==b&&"number"==typeof a[t]},I=function(a){return"string"==typeof a},ha=function(a){var b=typeof a;return"object"==b&&a!=k||"function"==b},K="closure_uid_"+Math.floor(2147483648*Math.random()).toString(36),ia=0,ja=function(a,b){function d(){}d.prototype=
+b[u];a.B=b[u];a.prototype=new d};var ka=function(a){this.stack=Error().stack||"";a&&(this.message=""+a)};ja(ka,Error);ka[u].name="CustomError";var la=function(a,b){for(var d=1;d<arguments[t];d++)var e=(""+arguments[d])[x](/\$/g,"$$$$"),a=a[x](/\%s/,e);return a},ra=function(a,b){if(b)return a[x](ma,"&amp;")[x](na,"&lt;")[x](oa,"&gt;")[x](pa,"&quot;");if(!qa.test(a))return a;-1!=a[z]("&")&&(a=a[x](ma,"&amp;"));-1!=a[z]("<")&&(a=a[x](na,"&lt;"));-1!=a[z](">")&&(a=a[x](oa,"&gt;"));-1!=a[z]('"')&&(a=a[x](pa,"&quot;"));return a},ma=/&/g,na=/</g,oa=/>/g,pa=/\"/g,qa=/[&<>\"]/;Math.random();var sa=function(a,b){b.unshift(a);ka[B](this,la[E](k,b));b.shift()};ja(sa,ka);sa[u].name="AssertionError";var ta=function(a,b,d){if(!a){var e=Array[u][w][B](arguments,2),f="Assertion failed";if(b)var f=f+(": "+b),c=e;throw new sa(""+f,c||[]);}return a};var L=Array[u],ua=L[z]?function(a,b,d){ta(a[t]!=k);return L[z][B](a,b,d)}:function(a,b,d){d=d==k?0:0>d?Math.max(0,a[t]+d):d;if(I(a))return!I(b)||1!=b[t]?-1:a[z](b,d);for(;d<a[t];d++)if(d in a&&a[d]===b)return d;return-1},va=L.forEach?function(a,b,d){ta(a[t]!=k);L.forEach[B](a,b,d)}:function(a,b,d){for(var e=a[t],f=I(a)?a[y](""):a,c=0;c<e;c++)c in f&&b[B](d,f[c],c,a)},wa=function(a){return L.concat[E](L,arguments)},xa=function(a){if("array"==H(a))return wa(a);for(var b=[],d=0,e=a[t];d<e;d++)b[d]=a[d];
+return b},ya=function(a,b,d){ta(a[t]!=k);return 2>=arguments[t]?L[w][B](a,b):L[w][B](a,b,d)};var za=function(a,b,d){for(var e in a)b[B](d,a[e],e,a)},Aa="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(","),Ba=function(a,b){for(var d,e,f=1;f<arguments[t];f++){e=arguments[f];for(d in e)a[d]=e[d];for(var c=0;c<Aa[t];c++)d=Aa[c],Object[u].hasOwnProperty[B](e,d)&&(a[d]=e[d])}};var M,Ca,Da,Ea,Fa=function(){return G.navigator?G.navigator.userAgent:k},Ga=function(){return G.navigator};Ea=Da=Ca=M=l;var N;if(N=Fa()){var Ha=Ga();M=0==N[z]("Opera");Ca=!M&&-1!=N[z]("MSIE");(Da=!M&&-1!=N[z]("WebKit"))&&N[z]("Mobile");Ea=!M&&!Da&&"Gecko"==Ha.product}var Ia=M,O=Ca,P=Ea,Q=Da,Ja=Ga(),Ka=Ja&&Ja.platform||"";Ka[z]("Mac");Ka[z]("Win");Ka[z]("Linux");Ga()&&(Ga().appVersion||"")[z]("X11");var La;
+a:{var Ma="",R;if(Ia&&G.opera)var Na=G.opera.version,Ma="function"==typeof Na?Na():Na;else if(P?R=/rv\:([^\);]+)(\)|;)/:O?R=/MSIE\s+([^\);]+)(\)|;)/:Q&&(R=/WebKit\/(\S+)/),R)var Oa=R.exec(Fa()),Ma=Oa?Oa[1]:"";if(O){var Pa,Qa=G.document;Pa=Qa?Qa.documentMode:h;if(Pa>parseFloat(Ma)){La=""+Pa;break a}}La=Ma}
+var Ra=La,Sa={},S=function(a){var b;if(!(b=Sa[a])){var d=0;b=(""+Ra)[x](/^[\s\xa0]+|[\s\xa0]+$/g,"")[y](".");for(var e=(""+a)[x](/^[\s\xa0]+|[\s\xa0]+$/g,"")[y]("."),f=Math.max(b[t],e[t]),c=0;0==d&&c<f;c++){var g=b[c]||"",i=e[c]||"",m=RegExp("(\\d*)(\\D*)","g"),o=RegExp("(\\d*)(\\D*)","g");do{var v=m.exec(g)||["","",""],r=o.exec(i)||["","",""];if(0==v[0][t]&&0==r[0][t])break;var d=0==v[1][t]?0:parseInt(v[1],10),J=0==r[1][t]?0:parseInt(r[1],10),d=(d<J?-1:d>J?1:0)||((0==v[2][t])<(0==r[2][t])?-1:(0==
+v[2][t])>(0==r[2][t])?1:0)||(v[2]<r[2]?-1:v[2]>r[2]?1:0)}while(0==d)}b=Sa[a]=0<=d}return b},Ta={},Ua=function(a){return Ta[a]||(Ta[a]=O&&!!n.documentMode&&n.documentMode>=a)};var Va=!O||Ua(9);!P&&!O||O&&Ua(9)||P&&S("1.9.1");O&&S("9");var Wa=function(a,b){var d;d=(d=a.className)&&"function"==typeof d[y]?d[y](/\s+/):[];var e=ya(arguments,1),f;f=d;for(var c=0,g=0;g<e[t];g++)0<=ua(f,e[g])||(f[s](e[g]),c++);f=c==e[t];a.className=d.join(" ");return f};var Xa=function(a,b,d,e){var a=e||a,f=b&&"*"!=b?b.toUpperCase():"";if(a.querySelectorAll&&a.querySelector&&(!Q||"CSS1Compat"==n.compatMode||S("528"))&&(f||d))return a.querySelectorAll(f+(d?"."+d:""));if(d&&a.getElementsByClassName){b=a.getElementsByClassName(d);if(f){for(var a={},c=e=0,g;g=b[c];c++)f==g.nodeName&&(a[e++]=g);aa(a,e);return a}return b}b=a.getElementsByTagName(f||"*");if(d){a={};for(c=e=0;g=b[c];c++){var f=g.className,i;if(i="function"==typeof f[y])f=f[y](/\s+/),i=0<=ua(f,d);i&&(a[e++]=
+g)}aa(a,e);return a}return b},Za=function(a,b){za(b,function(b,e){"style"==e?a.style.cssText=b:"class"==e?a.className=b:"for"==e?a.htmlFor=b:e in Ya?a.setAttribute(Ya[e],b):0==e.lastIndexOf("aria-",0)?a.setAttribute(e,b):a[e]=b})},Ya={cellpadding:"cellPadding",cellspacing:"cellSpacing",colspan:"colSpan",rowspan:"rowSpan",valign:"vAlign",height:"height",width:"width",usemap:"useMap",frameborder:"frameBorder",maxlength:"maxLength",type:"type"},ab=function(a,b,d,e){function f(c){c&&b.appendChild(I(c)?
+a.createTextNode(c):c)}for(;e<d[t];e++){var c=d[e];ga(c)&&!(ha(c)&&0<c.nodeType)?va($a(c)?xa(c):c,f):f(c)}},bb=function(a,b,d){var e=n,f=arguments,c=f[0],g=f[1];if(!Va&&g&&(g[fa]||g[C])){c=["<",c];g[fa]&&c[s](' name="',ra(g[fa]),'"');if(g[C]){c[s](' type="',ra(g[C]),'"');var i={};Ba(i,g);g=i;delete g[C]}c[s](">");c=c.join("")}c=e.createElement(c);g&&(I(g)?c.className=g:"array"==H(g)?Wa[E](k,[c].concat(g)):Za(c,g));2<f[t]&&ab(e,c,f,2);return c},$a=function(a){if(a&&"number"==typeof a[t]){if(ha(a))return"function"==
+typeof a.item||"string"==typeof a.item;if("function"==H(a))return"function"==typeof a.item}return l};var cb=function(a){cb[" "](a);return a};cb[" "]=function(){};!O||Ua(9);var db=!O||Ua(9);O&&S("8");!Q||S("528");P&&S("1.9b")||O&&S("8")||Ia&&S("9.5")||Q&&S("528");!P||S("8");var eb=function(){};eb[u].u=l;eb[u].m=function(){this.u||(this.u=j,this.n())};eb[u].n=function(){this.D&&fb[E](k,this.D)};var fb=function(a){for(var b=0,d=arguments[t];b<d;++b){var e=arguments[b];ga(e)?fb[E](k,e):e&&"function"==typeof e.m&&e.m()}};var T=function(a,b){this.type=a;ba(this,b);q(this,this[A])};ja(T,eb);T[u].n=function(){delete this[C];delete this[A];delete this.currentTarget};T[u].o=l;T[u].C=j;var U=function(a,b){a&&this.i(a,b)};ja(U,T);F=U[u];ba(F,k);F.relatedTarget=k;F.offsetX=0;F.offsetY=0;F.clientX=0;F.clientY=0;F.screenX=0;F.screenY=0;F.button=0;F.keyCode=0;F.charCode=0;F.ctrlKey=l;F.altKey=l;F.shiftKey=l;F.metaKey=l;
+F.i=function(a,b){var d=this.type=a[C];T[B](this,d);ba(this,a[A]||a.srcElement);q(this,b);var e=a.relatedTarget;if(e){if(P){var f;a:{try{cb(e.nodeName);f=j;break a}catch(c){}f=l}f||(e=k)}}else"mouseover"==d?e=a.fromElement:"mouseout"==d&&(e=a.toElement);this.relatedTarget=e;this.offsetX=Q||a.offsetX!==h?a.offsetX:a.layerX;this.offsetY=Q||a.offsetY!==h?a.offsetY:a.layerY;this.clientX=a.clientX!==h?a.clientX:a.pageX;this.clientY=a.clientY!==h?a.clientY:a.pageY;this.screenX=a.screenX||0;this.screenY=
+a.screenY||0;this.button=a.button;this.keyCode=a[da]||0;this.charCode=a.charCode||("keypress"==d?a[da]:0);this.ctrlKey=a.ctrlKey;this.altKey=a.altKey;this.shiftKey=a.shiftKey;this.metaKey=a.metaKey;this.state=a.state;delete this.C;delete this.o};F.n=function(){U.B.n[B](this);ba(this,k);q(this,k);this.relatedTarget=k};var gb=function(){},hb=0;F=gb[u];F.b=0;F.e=l;F.s=l;F.i=function(a,b,d,e,f,c){if("function"==H(a))this.t=j;else if(a&&a[ea]&&"function"==H(a[ea]))this.t=l;else throw Error("Invalid listener argument");this.h=a;this.q=b;this.src=d;this.type=e;this.w=!!f;this.p=c;this.s=l;this.b=++hb;this.e=l};F.handleEvent=function(a){return this.t?this.h[B](this.p||this.src,a):this.h[ea][B](this.h,a)};var V={},W={},X={},Y={},ib=function(a,b,d,e,f){if(b){if("array"==H(b)){for(var c=0;c<b[t];c++)ib(a,b[c],d,e,f);return k}var e=!!e,g=W;b in g||(g[b]={a:0,c:0});g=g[b];e in g||(g[e]={a:0,c:0},g.a++);var g=g[e],i=a[K]||(a[K]=++ia),m;g.c++;if(g[i]){m=g[i];for(c=0;c<m[t];c++)if(g=m[c],g.h==d&&g.p==f){if(g.e)break;return m[c].b}}else m=g[i]=[],g.a++;c=jb();c.src=a;g=new gb;g.i(d,c,a,b,e,f);d=g.b;c.b=d;m[s](g);V[d]=g;X[i]||(X[i]=[]);X[i][s](g);a.addEventListener?(a==G||!a.v)&&a.addEventListener(b,c,e):a.attachEvent(b in
+Y?Y[b]:Y[b]="on"+b,c);return d}throw Error("Invalid event type");},jb=function(){var a=kb,b=db?function(d){return a[B](b.src,b.b,d)}:function(d){d=a[B](b.src,b.b,d);if(!d)return d};return b},lb=function(a,b,d,e){if(!e.l&&e.r){for(var f=0,c=0;f<e[t];f++)e[f].e?e[f].q.src=k:(f!=c&&(e[c]=e[f]),c++);aa(e,c);e.r=l;0==c&&(delete W[a][b][d],W[a][b].a--,0==W[a][b].a&&(delete W[a][b],W[a].a--),0==W[a].a&&delete W[a])}},nb=function(a,b,d,e,f){var c=1,b=b[K]||(b[K]=++ia);if(a[b]){a.c--;a=a[b];a.l?a.l++:a.l=
+1;try{for(var g=a[t],i=0;i<g;i++){var m=a[i];m&&!m.e&&(c&=mb(m,f)!==l)}}finally{a.l--,lb(d,e,b,a)}}return Boolean(c)},mb=function(a,b){var d=a[ea](b);if(a.s){var e=a.b;if(V[e]){var f=V[e];if(!f.e){var c=f.src,g=f[C],i=f.q,m=f.w;c.removeEventListener?(c==G||!c.v)&&c.removeEventListener(g,i,m):c.detachEvent&&c.detachEvent(g in Y?Y[g]:Y[g]="on"+g,i);c=c[K]||(c[K]=++ia);i=W[g][m][c];if(X[c]){var o=X[c],v=ua(o,f);0<=v&&(ta(o[t]!=k),L.splice[B](o,v,1));0==o[t]&&delete X[c]}f.e=j;i.r=j;lb(g,m,c,i);delete V[e]}}}return d},
+kb=function(a,b){if(!V[a])return j;var d=V[a],e=d[C],f=W;if(!(e in f))return j;var f=f[e],c,g;if(!db){var i;if(!(i=b))a:{i=["window","event"];for(var m=G;c=i.shift();)if(m[c]!=k)m=m[c];else{i=k;break a}i=m}c=i;i=j in f;m=l in f;if(i){if(0>c[da]||c.returnValue!=h)return j;a:{var o=l;if(0==c[da])try{c.keyCode=-1;break a}catch(v){o=j}if(o||c.returnValue==h)c.returnValue=j}}o=new U;o.i(c,this);c=j;try{if(i){for(var r=[],J=o.currentTarget;J;J=J.parentNode)r[s](J);g=f[j];g.c=g.a;for(var D=r[t]-1;!o.o&&
+0<=D&&g.c;D--)q(o,r[D]),c&=nb(g,r[D],e,j,o);if(m){g=f[l];g.c=g.a;for(D=0;!o.o&&D<r[t]&&g.c;D++)q(o,r[D]),c&=nb(g,r[D],e,l,o)}}else c=mb(d,o)}finally{r&&aa(r,0),o.m()}return c}e=new U(b,this);try{c=mb(d,e)}finally{e.m()}return c};var ob=function(a,b){var d=[];1<arguments[t]&&(d=Array[u][w][B](arguments)[w](1));var e=Xa(n,"th","tct-selectall",a);if(0!=e[t]){var e=e[0],f=0,c=Xa(n,"tbody",k,a);c[t]&&(f=c[0].rows[t]);this.f=bb("input",{type:"checkbox"});e.appendChild(this.f);f?ib(this.f,"click",this.A,l,this):p(this.f,j);this.g=[];this.j=[];this.k=[];e=Xa(n,"input",k,a);for(f=0;c=e[f];f++)"checkbox"==c[C]&&c!=this.f?(this.g[s](c),ib(c,"click",this.z,l,this)):"action"==c[fa]&&(0<=d[z](c.value)?this.k[s](c):this.j[s](c),p(c,j))}};
+F=ob[u];F.g=k;F.d=0;F.f=k;F.j=k;F.k=k;F.A=function(a){for(var b=a[A].checked,d=a=0,e;e=this.g[d];d++)e.checked=b,a+=1;this.d=b?this.g[t]:0;for(d=0;b=this.j[d];d++)p(b,!this.d);for(d=0;b=this.k[d];d++)p(b,1!=a?j:l)};F.z=function(a){this.d+=a[A].checked?1:-1;this.f.checked=this.d==this.g[t];for(var a=0,b;b=this.j[a];a++)p(b,!this.d);for(a=0;b=this.k[a];a++)p(b,1!=this.d?j:l)};var pb=function(){var a=I("kinds")?n.getElementById("kinds"):"kinds";a&&new ob(a);(a=I("backups")?n.getElementById("backups"):"backups")&&new ob(a,"Restore")},Z=["ae","Datastore","Admin","init"],$=G;!(Z[0]in $)&&$.execScript&&$.execScript("var "+Z[0]);for(var qb;Z[t]&&(qb=Z.shift());)!Z[t]&&pb!==h?$[qb]=pb:$=$[qb]?$[qb]:$[qb]={};
diff --git a/google/appengine/ext/datastore_admin/templates/do_backup.html b/google/appengine/ext/datastore_admin/templates/do_backup.html
index a1b4ac9..0246ee6 100644
--- a/google/appengine/ext/datastore_admin/templates/do_backup.html
+++ b/google/appengine/ext/datastore_admin/templates/do_backup.html
@@ -24,20 +24,33 @@
         information.
         </p>
       </div>
+      {% for id in job_list %}
+        <p>Backup <a href="{{mapreduce_detail|escape}}{{id|escape}}">job with id
+          {{id|escape}}</a>
+            kicked off.</p>
+      {% endfor %}
     {% endif %}
-    {% for id in job_list %}
-      <p>Backup <a href="{{mapreduce_detail|escape}}{{id|escape}}">job with id
-        {{id|escape}}</a>
-          kicked off.</p>
-    {% endfor %}
-
+    {% if task_list %}
+      <div class="ae-message">
+        <div class="ae-alert">
+          The followings tasks were submitted and will initiate MapReduce jobs.
+        </div>
+        <ul>
+          {% for task_name in task_list %}
+            <li>{{ task_name }}</li>
+          {% endfor %}
+        </ul>
+        <p>Once job's are created their status will only be available for as
+        long as the job takes to complete. Once the job is complete, it will
+        remove the status objects from your datastore.
+        Click a job's id for status information.
+        </p>
+      </div>
+    {% endif %}
     {% if error %}
-      <p>There was a problem kicking off the jobs.
-      {% if job_list %}The above jobs did start successfully.  The error
-        starting the remaining jobs was:
-      {% else %}The error was:
-      {% endif %}</p>
-      <pre><code>{{error|escape}}</code></pre>
+      <p>There was a problem kicking some off the jobs/tasks:
+        <pre><code>{{error|escape}}</code></pre>
+      </p>
     {% endif %}
   {% endif %}
   <a href="{{datastore_admin_home}}">Back to Datastore Admin</a>
diff --git a/google/appengine/ext/datastore_admin/templates/list_actions.html b/google/appengine/ext/datastore_admin/templates/list_actions.html
index b0df3c5..45ac9ea 100644
--- a/google/appengine/ext/datastore_admin/templates/list_actions.html
+++ b/google/appengine/ext/datastore_admin/templates/list_actions.html
@@ -201,6 +201,7 @@
         <tr>
           <th scope="col" class="id">Description</th>
           <th scope="col" class="id">Completed steps</th>
+          <th scope="col" class="id">Status</th>
         </tr>
       </thead>
       <tbody>
@@ -212,6 +213,9 @@
             <td class="id">
               {{operation.completed_jobs}} steps
             </td>
+            <td class="id">
+              {{operation.status}}
+            </td>
           </tr>
         {% endfor %}
       </tbody>
diff --git a/google/appengine/ext/datastore_admin/utils.py b/google/appengine/ext/datastore_admin/utils.py
index 19aa32e..14e3107 100755
--- a/google/appengine/ext/datastore_admin/utils.py
+++ b/google/appengine/ext/datastore_admin/utils.py
@@ -57,6 +57,7 @@
 
   BASE_PATH = '/_ah/datastore_admin'
   MAPREDUCE_PATH = '/_ah/mapreduce'
+  DEFERRED_PATH = BASE_PATH + '/queue/deferred'
   CLEANUP_MAPREDUCE_STATE = True
 
 
@@ -360,7 +361,8 @@
               operation.completed_jobs += 1
               operation.active_job_ids.remove(mapreduce_id)
             if not operation.active_jobs:
-              operation.status = DatastoreAdminOperation.STATUS_COMPLETED
+              if operation.status == DatastoreAdminOperation.STATUS_ACTIVE:
+                operation.status = DatastoreAdminOperation.STATUS_COMPLETED
               db.delete(DatastoreAdminOperationJob.all().ancestor(operation),
                         config=db_config)
             operation.put(config=db_config)
@@ -369,6 +371,9 @@
                   mapreduce_params['done_callback_handler'])
               if done_callback_handler:
                 done_callback_handler(operation, mapreduce_id, mapreduce_state)
+              else:
+                logging.error('done_callbackup_handler %s was not found',
+                              mapreduce_params['done_callback_handler'])
           db.run_in_transaction(tx)
         if config.CLEANUP_MAPREDUCE_STATE:
 
@@ -377,23 +382,25 @@
           db.delete(keys, config=db_config)
           logging.info('State for successful job %s was deleted.', mapreduce_id)
       else:
-        logging.info('Job %s was not successful so no state was deleted.', (
-            mapreduce_id))
+        logging.info('Job %s was not successful so no state was deleted.',
+                     mapreduce_id)
     else:
       logging.error('Done callback called without Mapreduce Id.')
 
 
 class DatastoreAdminOperation(db.Model):
   """An entity to keep progress and status of datastore admin operation."""
-  STATUS_ACTIVE = "Active"
-  STATUS_COMPLETED = "Completed"
+  STATUS_CREATED = 'Created'
+  STATUS_ACTIVE = 'Active'
+  STATUS_COMPLETED = 'Completed'
+  STATUS_FAILED = 'Failed'
 
 
   PARAM_DATASTORE_ADMIN_OPERATION = 'datastore_admin_operation'
   DEFAULT_LAST_UPDATED_VALUE = datetime.datetime(1970, 1, 1)
 
   description = db.TextProperty()
-  status = db.StringProperty()
+  status = db.StringProperty(default=STATUS_CREATED)
   active_jobs = db.IntegerProperty(default=0)
   active_job_ids = db.StringListProperty()
   completed_jobs = db.IntegerProperty(default=0)
@@ -402,7 +409,7 @@
 
   @classmethod
   def kind(cls):
-    return "_AE_DatastoreAdmin_Operation"
+    return '_AE_DatastoreAdmin_Operation'
 
 
 class DatastoreAdminOperationJob(db.Model):
@@ -429,7 +436,6 @@
 
   operation = DatastoreAdminOperation(
       description=description,
-      status=DatastoreAdminOperation.STATUS_ACTIVE,
       id=db.allocate_ids(
           db.Key.from_path(DatastoreAdminOperation.kind(), 1), 1)[0])
   operation.put(config=_CreateDatastoreConfig())
@@ -483,7 +489,9 @@
         base_path=config.MAPREDUCE_PATH,
         shard_count=32,
         transactional=True,
-        queue_name=queue_name)
+        queue_name=queue_name,
+        transactional_parent=operation)
+    operation.status = DatastoreAdminOperation.STATUS_ACTIVE
     operation.active_jobs += 1
     operation.active_job_ids = list(set(operation.active_job_ids + [job_id]))
     operation.put(config=_CreateDatastoreConfig())
@@ -521,11 +529,20 @@
     Ids of all started mapper jobs as list of strings.
   """
   jobs = []
-  for kind in kinds:
-    mapper_params['entity_kind'] = kind
-    job_name = job_name_template % {'kind': kind, 'namespace':
-                                    mapper_params.get('namespaces', '')}
-    jobs.append(StartMap(operation_key, job_name, handler_spec, reader_spec,
-                         writer_spec, mapper_params, mapreduce_params,
-                         queue_name=queue_name))
-  return jobs
+  try:
+    for kind in kinds:
+      mapper_params['entity_kind'] = kind
+      job_name = job_name_template % {'kind': kind, 'namespace':
+                                      mapper_params.get('namespaces', '')}
+      jobs.append(StartMap(operation_key, job_name, handler_spec, reader_spec,
+                           writer_spec, mapper_params, mapreduce_params,
+                           queue_name=queue_name))
+    return jobs
+
+  except BaseException:
+    operation = DatastoreAdminOperation.get(operation_key)
+    operation.status = DatastoreAdminOperation.STATUS_FAILED
+    operation.put(config=_CreateDatastoreConfig())
+    for job in jobs:
+      model.MapreduceControl.abort(job)
+    raise
diff --git a/google/appengine/ext/db/__init__.py b/google/appengine/ext/db/__init__.py
index 27fbf47..803e9f0 100755
--- a/google/appengine/ext/db/__init__.py
+++ b/google/appengine/ext/db/__init__.py
@@ -1680,6 +1680,13 @@
     return KEY_RANGE_EMPTY
 
 
+def _index_converter(index):
+  return Index(index.Id(),
+               index.Kind(),
+               index.HasAncestor(),
+               index.Properties())
+
+
 def get_indexes_async(**kwargs):
   """Asynchronously retrieves the application indexes and their states.
 
@@ -1687,8 +1694,7 @@
   get_result() on the return value to block on the call and get the results.
   """
   def extra_hook(indexes):
-    return [(Index(index.Id(), index.Kind(), index.HasAncestor(),
-                  index.Properties()), state) for index, state in indexes]
+    return [(_index_converter(index), state) for index, state in indexes]
 
   return datastore.GetIndexesAsync(extra_hook=extra_hook, **kwargs)
 
@@ -1948,7 +1954,9 @@
 
 class _BaseQuery(object):
   """Base class for both Query and GqlQuery."""
-  _compile = False
+
+  _last_raw_query = None
+  _last_index_list = None
 
   def __init__(self, model_class=None, keys_only=False, compile=True,
                cursor=None, namespace=None):
@@ -2021,8 +2029,7 @@
 
   def __getstate__(self):
     state = self.__dict__.copy()
-    if '_last_raw_query' in state:
-      del state['_last_raw_query']
+    state['_last_raw_query'] = None
     return state
 
   def get(self, **kwargs):
@@ -2083,6 +2090,23 @@
       kwargs.setdefault('batch_size', datastore._MAX_INT_32)
     return list(self.run(limit=limit, offset=offset, **kwargs))
 
+  def index_list(self):
+    """Get the index list for an already executed query.
+
+    Returns:
+      A list of indexes used by the query.
+
+    Raises:
+      AssertionError: If the query has not been executed.
+    """
+    if self._last_raw_query is None:
+      raise AssertionError('No index list because query has not been run.')
+    if self._last_index_list is None:
+      raw_index_list = self._last_raw_query.GetIndexList()
+      self._last_index_list = [_index_converter(raw_index)
+                               for raw_index in raw_index_list]
+    return self._last_index_list
+
   def cursor(self):
     """Get a serialized cursor for an already executed query.
 
@@ -2092,15 +2116,17 @@
 
     Returns:
       A base64-encoded serialized cursor.
+
+    Raises:
+      AssertionError: If the query has not been executed.
     """
     if not self._compile:
       raise AssertionError(
           'Query must be created with compile=True to produce cursors')
-    try:
-      return websafe_encode_cursor(
-          self._last_raw_query.GetCompiledCursor())
-    except AttributeError:
+    if self._last_raw_query is None:
       raise AssertionError('No cursor available.')
+    cursor = self._last_raw_query.GetCursor()
+    return websafe_encode_cursor(cursor)
 
   def with_cursor(self, start_cursor=None, end_cursor=None):
     """Set the start and end of this query using serialized cursors.
@@ -2712,8 +2738,13 @@
           % (self.name, type(value).__name__))
     if not self.multiline and value and value.find('\n') != -1:
       raise BadValueError('Property %s is not multi-line' % self.name)
+    if value is not None and len(value) > self.MAX_LENGTH:
+      raise BadValueError(
+          'Property %s is %d characters long; it must be %d or less.'
+          % (self.name, len(value), self.MAX_LENGTH))
     return value
 
+  MAX_LENGTH = 500
   data_type = basestring
 
 
@@ -2828,8 +2859,13 @@
     if value is not None and not isinstance(value, ByteString):
       raise BadValueError('Property %s must be a ByteString instance'
                           % self.name)
+    if value is not None and len(value) > self.MAX_LENGTH:
+      raise BadValueError(
+          'Property %s is %d bytes long; it must be %d or less.'
+          % (self.name, len(value), self.MAX_LENGTH))
     return value
 
+  MAX_LENGTH = 500
   data_type = ByteString
 
 
diff --git a/google/appengine/ext/deferred/deferred.py b/google/appengine/ext/deferred/deferred.py
index d01464a..3db30bb 100755
--- a/google/appengine/ext/deferred/deferred.py
+++ b/google/appengine/ext/deferred/deferred.py
@@ -236,15 +236,16 @@
   Args:
     obj: The callable to execute. See module docstring for restrictions.
         _countdown, _eta, _headers, _name, _target, _transactional, _url,
-        _queue: Passed through to the task queue - see the task queue
-        documentation for details.
+        _retry_options, _queue: Passed through to the task queue - see the
+        task queue documentation for details.
     args: Positional arguments to call the callable with.
     kwargs: Any other keyword arguments are passed through to the callable.
   Returns:
     A taskqueue.Task object which represents an enqueued callable.
   """
   taskargs = dict((x, kwargs.pop(("_%s" % x), None))
-                  for x in ("countdown", "eta", "name", "target"))
+                  for x in ("countdown", "eta", "name", "target",
+                            "retry_options"))
   taskargs["url"] = kwargs.pop("_url", _DEFAULT_URL)
   transactional = kwargs.pop("_transactional", False)
   taskargs["headers"] = dict(_TASKQUEUE_HEADERS)
diff --git a/google/appengine/ext/django/main.py b/google/appengine/ext/django/main.py
index 5bc283d..a65aa21 100644
--- a/google/appengine/ext/django/main.py
+++ b/google/appengine/ext/django/main.py
@@ -35,7 +35,16 @@
 
 
 
-_config_handle = lib_config.register('django', {'settings_module': 'settings'})
+
+
+
+
+
+
+
+_config_handle = lib_config.register(
+    'django', {'settings_module': os.getenv('DJANGO_SETTINGS_MODULE',
+                                            'settings')})
 settings_path = _config_handle.settings_module
 
 from google.appengine.ext.webapp import util
diff --git a/google/appengine/ext/go/__init__.py b/google/appengine/ext/go/__init__.py
index c290858..3a3f72f 100644
--- a/google/appengine/ext/go/__init__.py
+++ b/google/appengine/ext/go/__init__.py
@@ -90,7 +90,9 @@
 }
 
 
-ENV_PASSTHROUGH = re.compile(r'^(BACKEND_PORT\..*|INSTANCE_ID)$')
+ENV_PASSTHROUGH = re.compile(
+    r'^(BACKEND_PORT\..*|INSTANCE_ID|SERVER_SOFTWARE)$'
+)
 
 
 APP_CONFIG = None
diff --git a/google/appengine/ext/gql/__init__.py b/google/appengine/ext/gql/__init__.py
index 181b0ed..e438010 100755
--- a/google/appengine/ext/gql/__init__.py
+++ b/google/appengine/ext/gql/__init__.py
@@ -199,7 +199,7 @@
     ,|
     \*|
     -?\d+(?:\.\d+)?|
-    \w+|
+    \w+(?:\.\w+)*|
     (?:"[^"\s]+")+|
     \(|\)|
     \S+
@@ -252,8 +252,6 @@
 
       raise datastore_errors.BadQueryError(
           'Unable to parse query')
-    else:
-      pass
 
   def Bind(self, args, keyword_args, cursor=None, end_cursor=None):
     """Bind the existing query to the argument list.
@@ -580,7 +578,7 @@
       if isinstance(param, Literal):
         value = param.Get()
       else:
-        value = self.__GetParam(param, args, keyword_args)
+        value = self.__GetParam(param, args, keyword_args, used_args=used_args)
         if isinstance(param, int):
           used_args.add(param - 1)
         logging.log(LOG_LEVEL, 'found param for bind: %s value: %s',
@@ -601,41 +599,50 @@
     """Return whether or not this condition could require multiple queries."""
     return condition.lower() in ('in', '!=')
 
-  def __GetParam(self, reference, args, keyword_args):
+  def __GetParam(self, param, args, keyword_args, used_args=None):
     """Get the specified parameter from the input arguments.
 
+    If param is an index or named reference, args and keyword_args are used. If
+    param is a cast operator tuple, will use __Operate to return the cast value.
+
     Args:
-      reference: id for a filter reference in the filter list (string or
-          number)
+      param: represents either an id for a filter reference in the filter list
+          (string or number) or a tuple (cast operator, params)
       args: positional args passed in by the user (tuple of arguments, indexed
-          numerically by "reference")
-      keyword_args: dict of keyword based arguments (strings in "reference")
+          numerically by "param")
+      keyword_args: dict of keyword based arguments (strings in "param")
+      used_args: Index arguments passed from __Operate to determine which index
+          references have been used. Default is None.
 
     Returns:
       The specified param from the input list.
 
     Raises:
-      BadArgumentError if the referenced argument doesn't exist.
+      BadArgumentError: if the referenced argument doesn't exist or no type cast
+      operator is present.
     """
     num_args = len(args)
-    if isinstance(reference, int):
+    if isinstance(param, int):
 
-      if reference <= num_args:
-        return args[reference - 1]
+      if param <= num_args:
+        return args[param - 1]
       else:
         raise datastore_errors.BadArgumentError(
             'Missing argument for bind, requires argument #%i, '
-            'but only has %i args.' % (reference, num_args))
-    elif isinstance(reference, basestring):
-      if reference in keyword_args:
-        return keyword_args[reference]
+            'but only has %i args.' % (param, num_args))
+    elif isinstance(param, basestring):
+      if param in keyword_args:
+        return keyword_args[param]
       else:
         raise datastore_errors.BadArgumentError(
             'Missing named arguments for bind, requires argument %s' %
-            reference)
+            param)
+    elif isinstance(param, tuple) and len(param) == 2:
+      cast_op, params = param
+      return self.__Operate(args, keyword_args, used_args, cast_op, params)
     else:
 
-      assert False, 'Unknown reference %s' % reference
+      assert False, 'Unknown parameter %s' % param
 
   def __AddMultiQuery(self, identifier, condition, value, enumerated_queries):
     """Helper function to add a multi-query to previously enumerated queries.
@@ -822,7 +829,7 @@
   __quoted_string_regex = re.compile(r'((?:\'[^\'\n\r]*\')+)')
   __ordinal_regex = re.compile(r':(\d+)$')
   __named_regex = re.compile(r':(\w+)$')
-  __identifier_regex = re.compile(r'(\w+)$')
+  __identifier_regex = re.compile(r'(\w+(?:\.\w+)*)$')
 
 
 
@@ -951,7 +958,6 @@
         self._kind = kind
       else:
         self.__Error('Identifier Expected')
-        return False
     else:
       self._kind = None
     return self.__Where()
@@ -974,12 +980,10 @@
     identifier = self.__Identifier()
     if not identifier:
       self.__Error('Invalid WHERE Identifier')
-      return False
 
     condition = self.__AcceptRegex(self.__conditions_regex)
     if not condition:
       self.__Error('Invalid WHERE Condition')
-      return False
     self.__CheckFilterSyntax(identifier, condition)
 
     if not self.__AddSimpleFilter(identifier, condition, self.__Reference()):
@@ -990,7 +994,7 @@
         if (not type_cast or
             not self.__AddProcessedParameterFilter(identifier, condition,
                                                    *type_cast)):
-          self.__Error('Invalid WHERE condition')
+          self.__Error('Invalid WHERE Condition')
 
 
     if self.__Accept('AND'):
@@ -998,17 +1002,27 @@
 
     return self.__OrderBy()
 
-  def __GetValueList(self):
+  def __GetValueList(self, values_intended_for_list=False):
     """Read in a list of parameters from the tokens and return the list.
 
-    Reads in a set of tokens, but currently only accepts literals, positional
-    parameters, or named parameters. Or empty list if nothing was parsed.
+    Reads in a set of tokens by consuming symbols. If the returned list of
+    values is not intended to be used within a list, only accepts literals,
+    positional parameters, or named parameters. If the returned list of
+    values is intended to be used within a list, also accepts values
+    (cast operator, params) which represent a custom GAE Type and are
+    returned by __TypeCast.
+
+    Args:
+      values_intended_for_list: Boolean to determine if the returned value list
+          is intended to be used as values in a list or as values in a custom
+          GAE Type. Defaults to False.
 
     Returns:
       A list of values parsed from the input, with values taking the form of
       strings (unbound, named reference), integers (unbound, positional
-      reference), or Literal() (bound value usable directly as part of a filter
-      with no additional information).
+      reference), Literal() (bound value usable directly as part of a filter
+      with no additional information), or a tuple (cast operator, params)
+      representing a custom GAE Type. Or empty list if nothing was parsed.
     """
     params = []
 
@@ -1020,6 +1034,12 @@
         literal = self.__Literal()
         if literal:
           params.append(literal)
+        elif values_intended_for_list:
+          type_cast = self.__TypeCast(can_cast_list=False)
+          if type_cast is None:
+            self.__Error('Filter list value could not be cast '
+                         'to a datastore type')
+          params.append(type_cast)
         else:
           self.__Error('Parameter list requires literal or reference parameter')
 
@@ -1199,18 +1219,25 @@
     else:
       return None
 
-  def __TypeCast(self):
+  def __TypeCast(self, can_cast_list=True):
     """Check if the next operation is a type-cast and return the cast if so.
 
     Casting operators look like simple function calls on their parameters. This
     code returns the cast operator found and the list of parameters provided by
     the user to complete the cast operation.
 
+    In the case of a list, we allow the call to __GetValueList to also accept
+    custom GAE Types as values.
+
+    Args:
+      can_cast_list: Boolean to determine if list can be returned as one of the
+          cast operators. Default value is True.
+
     Returns:
       A tuple (cast operator, params) which represents the cast operation
       requested and the parameters parsed from the cast clause.
 
-      None - if there is no TypeCast function.
+      None - if there is no TypeCast function or list is not allowed to be cast.
     """
 
 
@@ -1218,7 +1245,7 @@
     logging.log(LOG_LEVEL, 'Try Type Cast')
     cast_op = self.__AcceptRegex(self.__cast_regex)
     if not cast_op:
-      if self.__Accept('('):
+      if can_cast_list and self.__Accept('('):
 
         cast_op = 'list'
       else:
@@ -1227,7 +1254,7 @@
       cast_op = cast_op.lower()
       self.__Expect('(')
 
-    params = self.__GetValueList()
+    params = self.__GetValueList(values_intended_for_list=(cast_op == 'list'))
     self.__Expect(')')
 
     logging.log(LOG_LEVEL, 'Got casting operator %s with params %s',
@@ -1336,7 +1363,6 @@
         self.__hint = 'ANCESTOR_FIRST'
       else:
         self.__Error('Unknown HINT')
-        return False
     return self.__AcceptTerminal()
 
 
diff --git a/google/appengine/ext/mapreduce/context.py b/google/appengine/ext/mapreduce/context.py
index 837691e..4152cfa 100755
--- a/google/appengine/ext/mapreduce/context.py
+++ b/google/appengine/ext/mapreduce/context.py
@@ -52,6 +52,8 @@
            "MAX_POOL_SIZE",
            ]
 
+import threading
+
 from google.appengine.api import datastore
 from google.appengine.ext import db
 
@@ -255,7 +257,7 @@
   """
 
 
-  _context_instance = None
+  _local = threading.local()
 
   def __init__(self, mapreduce_spec, shard_state, task_retry_count=0):
     """Constructor.
@@ -327,7 +329,7 @@
     Args:
       context: new context as Context or None.
     """
-    cls._context_instance = context
+    cls._local._context_instance = context
 
 
 def get():
@@ -336,4 +338,6 @@
   Returns:
     current context as Context.
   """
-  return Context._context_instance
+  if not hasattr(Context._local, '_context_instance') :
+    return None
+  return Context._local._context_instance
diff --git a/google/appengine/ext/mapreduce/control.py b/google/appengine/ext/mapreduce/control.py
index f55063c..28312ab 100755
--- a/google/appengine/ext/mapreduce/control.py
+++ b/google/appengine/ext/mapreduce/control.py
@@ -37,6 +37,7 @@
 
 
 
+import logging
 import google
 
 from google.appengine.ext.mapreduce import base_handler
@@ -60,7 +61,8 @@
               countdown=None,
               hooks_class_name=None,
               _app=None,
-              transactional=False):
+              transactional=False,
+              transactional_parent=None):
   """Start a new, mapper-only mapreduce.
 
   Args:
@@ -77,14 +79,17 @@
     queue_name: executor queue name to be used for mapreduce tasks. If
       unspecified it will be the "default" queue or inherit the queue of
       the currently running request.
-    eta: Absolute time when the MR should execute. May not be specified
+    eta: absolute time when the MR should execute. May not be specified
       if 'countdown' is also supplied. This may be timezone-aware or
       timezone-naive.
-    countdown: Time in seconds into the future that this MR should execute.
+    countdown: time in seconds into the future that this MR should execute.
       Defaults to zero.
     hooks_class_name: fully qualified name of a hooks.Hooks subclass.
-    transactional: Specifies if job should be started as a part of already
+    transactional: specifies if job should be started as a part of already
       opened transaction.
+    transactional_parent: specifies the entity which is already a part of
+      transaction. Child entity will be used to store task payload if mapreduce
+      specification is too big.
 
   Returns:
     mapreduce id as string.
@@ -105,6 +110,14 @@
                                  shard_count,
                                  output_writer_spec=output_writer_spec)
 
+  if transactional and not transactional_parent:
+
+
+
+    logging.error(
+        "transactional_parent should be specified for transactional starts."
+        "Your job will fail to start if mapreduce specification is too big.")
+
   return handlers.StartJobHandler._start_map(
       name,
       mapper_spec,
@@ -115,5 +128,6 @@
       countdown=countdown,
       hooks_class_name=hooks_class_name,
       _app=_app,
-      transactional=transactional)
+      transactional=transactional,
+      parent_entity=transactional_parent)
 
diff --git a/google/appengine/ext/mapreduce/errors.py b/google/appengine/ext/mapreduce/errors.py
index 0e8bf49..a0b64c6 100755
--- a/google/appengine/ext/mapreduce/errors.py
+++ b/google/appengine/ext/mapreduce/errors.py
@@ -34,6 +34,7 @@
 
 
 __all__ = [
+    "BadCombinerOutputError",
     "BadParamsError",
     "BadReaderParamsError",
     "BadWriterParamsError",
@@ -75,3 +76,7 @@
 class ShuffleServiceError(Error):
   """Error doing shuffle through shuffle service."""
 
+
+class BadCombinerOutputError(Error):
+  """Combiner outputs data instead of yielding it."""
+
diff --git a/google/appengine/ext/mapreduce/handlers.py b/google/appengine/ext/mapreduce/handlers.py
index 328767a..5068c54 100755
--- a/google/appengine/ext/mapreduce/handlers.py
+++ b/google/appengine/ext/mapreduce/handlers.py
@@ -275,7 +275,7 @@
       else:
         result = handler(data)
 
-      if util.is_generator_function(handler):
+      if util.is_generator(handler):
         for output in result:
           if isinstance(output, operation.Operation):
             output(ctx)
@@ -844,7 +844,9 @@
     return value
 
   @classmethod
-  def _start_map(cls, name, mapper_spec,
+  def _start_map(cls,
+                 name,
+                 mapper_spec,
                  mapreduce_params,
                  base_path=None,
                  queue_name=None,
@@ -852,13 +854,18 @@
                  countdown=None,
                  hooks_class_name=None,
                  _app=None,
-                 transactional=False):
+                 transactional=False,
+                 parent_entity=None):
     queue_name = queue_name or os.environ.get("HTTP_X_APPENGINE_QUEUENAME",
                                               "default")
     if queue_name[0] == "_":
 
       queue_name = "default"
 
+    if not transactional and parent_entity:
+      raise Exception("Parent shouldn't be specfied "
+                      "for non-transactional starts.")
+
 
     mapper_spec.get_handler()
 
@@ -891,7 +898,7 @@
     config = util.create_datastore_write_config(mapreduce_spec)
 
     def start_mapreduce():
-      parent = None
+      parent = parent_entity
       if not transactional:
 
 
diff --git a/google/appengine/ext/mapreduce/input_readers.py b/google/appengine/ext/mapreduce/input_readers.py
index 9b5d819..af77639 100755
--- a/google/appengine/ext/mapreduce/input_readers.py
+++ b/google/appengine/ext/mapreduce/input_readers.py
@@ -48,20 +48,25 @@
     "DatastoreKeyInputReader",
     "Error",
     "InputReader",
+    "LogInputReader",
     "NamespaceInputReader",
     "RecordsReader",
     ]
 
 
 
+import base64
 import copy
 import StringIO
 import time
 import zipfile
 
+from google.net.proto import ProtocolBuffer
 from google.appengine.api import datastore
 from google.appengine.api import files
+from google.appengine.api import logservice
 from google.appengine.api.files import records
+from google.appengine.api.logservice import log_service_pb
 from google.appengine.datastore import datastore_query
 from google.appengine.datastore import datastore_rpc
 from google.appengine.ext import blobstore
@@ -1012,7 +1017,7 @@
 
 
 class BlobstoreZipLineInputReader(InputReader):
-  """Input reader for newline delimited files in zip archives from  Blobstore.
+  """Input reader for newline delimited files in zip archives from Blobstore.
 
   This has the same external interface as the BlobstoreLineInputReader, in that
   it takes a list of blobs as its input and yields lines to the reader.
@@ -1632,7 +1637,7 @@
 
 
     batch_list.sort(reverse=True, key=lambda x: len(x))
-    return [RecordsReader(batch, 0) for batch in batch_list]
+    return [cls(batch, 0) for batch in batch_list]
 
   @classmethod
   def validate(cls, mapper_spec):
@@ -1658,3 +1663,224 @@
     if self._reader:
       position = self._reader.tell()
     return "%s:%s" % (self._filenames, position)
+
+
+class LogInputReader(InputReader):
+  """Input reader for a time range of logs via the Logs Reader API.
+
+  The number of input shards may be specified by the SHARDS_PARAM mapper
+  parameter.  A starting and ending time (in seconds since the Unix epoch) are
+  required to generate time ranges over which to shard the input.
+  """
+
+  START_TIME_PARAM = "start_time"
+  END_TIME_PARAM = "end_time"
+  MINIMUM_LOG_LEVEL_PARAM = "minimum_log_level"
+  INCLUDE_INCOMPLETE_PARAM = "include_incomplete"
+  INCLUDE_APP_LOGS_PARAM = "include_app_logs"
+  VERSION_IDS_PARAM = "version_ids"
+
+
+  _OFFSET_PARAM = "offset"
+  _PROTOTYPE_REQUEST_PARAM = "prototype_request"
+
+  _PARAMS = frozenset([START_TIME_PARAM, END_TIME_PARAM, _OFFSET_PARAM,
+                       MINIMUM_LOG_LEVEL_PARAM, INCLUDE_INCOMPLETE_PARAM,
+                       INCLUDE_APP_LOGS_PARAM, VERSION_IDS_PARAM,
+                       _PROTOTYPE_REQUEST_PARAM])
+  _KWARGS = frozenset([_OFFSET_PARAM, _PROTOTYPE_REQUEST_PARAM])
+
+  def __init__(self,
+               start_time=None,
+               end_time=None,
+               minimum_log_level=None,
+               include_incomplete=False,
+               include_app_logs=False,
+               version_ids=None,
+               **kwargs):
+    """Constructor.
+
+    Args:
+      start_time: The earliest request completion or last-update time of logs
+        that should be mapped over, in seconds since the Unix epoch.
+      end_time: The latest request completion or last-update time that logs
+        should be mapped over, in seconds since the Unix epoch.
+      minimum_log_level: An application log level which serves as a filter on
+        the requests mapped over--requests with no application log at or above
+        the specified level will be omitted, even if include_app_logs is False.
+      include_incomplete: Whether or not to include requests that have started
+        but not yet finished, as a boolean.  Defaults to False.
+      include_app_logs: Whether or not to include application level logs in the
+        mapped logs, as a boolean.  Defaults to False.
+      version_ids: A list of version ids whose logs should be mapped against.
+    """
+    InputReader.__init__(self)
+
+
+
+    self.__params = dict(kwargs)
+
+    if start_time is not None:
+      self.__params[self.START_TIME_PARAM] = start_time
+    if end_time is not None:
+      self.__params[self.END_TIME_PARAM] = end_time
+    if minimum_log_level is not None:
+      self.__params[self.MINIMUM_LOG_LEVEL_PARAM] = minimum_log_level
+    if include_incomplete is not None:
+      self.__params[self.INCLUDE_INCOMPLETE_PARAM] = include_incomplete
+    if include_app_logs is not None:
+      self.__params[self.INCLUDE_APP_LOGS_PARAM] = include_app_logs
+    if version_ids:
+      self.__params[self.VERSION_IDS_PARAM] = version_ids
+
+
+    if self._PROTOTYPE_REQUEST_PARAM in self.__params:
+      prototype_request = log_service_pb.LogReadRequest(
+          self.__params[self._PROTOTYPE_REQUEST_PARAM])
+      self.__params[self._PROTOTYPE_REQUEST_PARAM] = prototype_request
+
+  @staticmethod
+  def __kwargs(args):
+    """Return a new dictionary with all keys converted to type 'str'."""
+    return dict((str(name), value) for name, value in args.iteritems())
+
+  def __iter__(self):
+    """Iterates over logs in a given range of time.
+
+    Yields:
+      A RequestLog containing all the information for a single request.
+    """
+    for log in logservice.fetch(**self.__params):
+      self.__params[self._OFFSET_PARAM] = log.offset
+      yield log
+
+  @classmethod
+  def from_json(cls, json):
+    """Creates an instance of the InputReader for the given input shard's state.
+
+    Args:
+      json: The InputReader state as a dict-like object.
+
+    Returns:
+      An instance of the InputReader configured using the given JSON parameters.
+    """
+    params = cls.__kwargs(json)
+
+
+    params = dict((k, v) for k, v in params.iteritems() if k in cls._PARAMS)
+
+
+
+
+    if cls._OFFSET_PARAM in params:
+      params[cls._OFFSET_PARAM] = base64.b64decode(params[cls._OFFSET_PARAM])
+    return cls(**params)
+
+  def to_json(self):
+    """Returns an input shard state for the remaining inputs.
+
+    Returns:
+      A JSON serializable version of the remaining input to read.
+    """
+
+    params = dict(self.__params)
+    if self._PROTOTYPE_REQUEST_PARAM in params:
+      prototype_request = params[self._PROTOTYPE_REQUEST_PARAM]
+      params[self._PROTOTYPE_REQUEST_PARAM] = prototype_request.Encode()
+    if self._OFFSET_PARAM in params:
+      params[self._OFFSET_PARAM] = base64.b64encode(params[self._OFFSET_PARAM])
+    return params
+
+  @classmethod
+  def split_input(cls, mapper_spec):
+    """Returns a list of input readers for the given input specification.
+
+    Args:
+      mapper_spec: The MapperSpec for this InputReader.
+
+    Returns:
+      A list of InputReaders.
+    """
+    params = cls.__kwargs(mapper_spec.params)
+    shard_count = mapper_spec.shard_count
+
+
+    start_time = params[cls.START_TIME_PARAM]
+    end_time = params[cls.END_TIME_PARAM]
+    seconds_per_shard = (end_time - start_time) / shard_count
+
+
+    shards = []
+    for _ in xrange(shard_count - 1):
+      params[cls.END_TIME_PARAM] = (params[cls.START_TIME_PARAM] +
+                                    seconds_per_shard)
+      shards.append(LogInputReader(**params))
+      params[cls.START_TIME_PARAM] = params[cls.END_TIME_PARAM]
+
+
+    params[cls.END_TIME_PARAM] = end_time
+    return shards + [LogInputReader(**params)]
+
+  @classmethod
+  def validate(cls, mapper_spec):
+    """Validates the mapper's specification and all necessary parameters.
+
+    Args:
+      mapper_spec: The MapperSpec to be used with this InputReader.
+
+    Raises:
+      BadReaderParamsError: If the user fails to specify both a starting time
+        and an ending time, or if the starting time is later than the ending
+        time.
+    """
+    if mapper_spec.input_reader_class() != cls:
+      raise errors.BadReaderParamsError("Input reader class mismatch")
+
+    params = cls.__kwargs(mapper_spec.params)
+    params_diff = set(params.keys()) - cls._PARAMS
+    if params_diff:
+      raise errors.BadReaderParamsError("Invalid mapper parameters: %s" %
+                                        ",".join(params_diff))
+    if cls.VERSION_IDS_PARAM not in params:
+      raise errors.BadReaderParamsError("Must specify a list of version ids "
+                                        "for mapper input")
+    if (cls.START_TIME_PARAM not in params or
+        params[cls.START_TIME_PARAM] is None):
+      raise errors.BadReaderParamsError("Must specify a starting time for "
+                                        "mapper input")
+    if cls.END_TIME_PARAM not in params or params[cls.END_TIME_PARAM] is None:
+      params[cls.END_TIME_PARAM] = time.time()
+
+    if params[cls.START_TIME_PARAM] >= params[cls.END_TIME_PARAM]:
+      raise errors.BadReaderParamsError("The starting time cannot be later "
+                                        "than or the same as the ending time.")
+
+    if cls._PROTOTYPE_REQUEST_PARAM in params:
+      try:
+        params[cls._PROTOTYPE_REQUEST_PARAM] = log_service_pb.LogReadRequest(
+            params[cls._PROTOTYPE_REQUEST_PARAM])
+      except (TypeError, ProtocolBuffer.ProtocolBufferDecodeError):
+        raise errors.BadReaderParamsError("The prototype request must be "
+                                          "parseable as a LogReadRequest.")
+
+
+
+
+    try:
+      logservice.fetch(**params)
+    except logservice.InvalidArgumentError, e:
+      raise errors.BadReaderParamsError("One or more parameters are not valid "
+                                        "inputs to logservice.fetch(): %s" % e)
+
+  def __str__(self):
+    """Returns the string representation of this LogInputReader."""
+    params = []
+    for key, value in self.__params.iteritems():
+      if key is self._PROTOTYPE_REQUEST_PARAM:
+        params.append("%s='%s'" % (key, value))
+      elif key is self._OFFSET_PARAM:
+        params.append("%s='%s'" % (key, value))
+      else:
+        params.append("%s=%s" % (key, value))
+
+    return "LogInputReader(%s)" % ", ".join(params)
diff --git a/google/appengine/ext/mapreduce/mapper_pipeline.py b/google/appengine/ext/mapreduce/mapper_pipeline.py
index 00b615a..9455756 100644
--- a/google/appengine/ext/mapreduce/mapper_pipeline.py
+++ b/google/appengine/ext/mapreduce/mapper_pipeline.py
@@ -33,6 +33,9 @@
 """Pipelines for mapreduce library."""
 
 
+__all__ = [
+    "MapperPipeline",
+    ]
 
 import google
 
diff --git a/google/appengine/ext/mapreduce/mapreduce_pipeline.py b/google/appengine/ext/mapreduce/mapreduce_pipeline.py
index 3d5cbc4..f2e4717 100644
--- a/google/appengine/ext/mapreduce/mapreduce_pipeline.py
+++ b/google/appengine/ext/mapreduce/mapreduce_pipeline.py
@@ -35,6 +35,13 @@
 from __future__ import with_statement
 
 
+__all__ = [
+    "MapPipeline",
+    "MapperPipeline",
+    "MapreducePipeline",
+    "ReducePipeline",
+    "ShufflePipeline",
+    ]
 
 import google
 
@@ -42,12 +49,15 @@
 from appengine_pipeline.src.pipeline import common as pipeline_common
 from google.appengine.api import files
 from google.appengine.api.files import file_service_pb
-from google.appengine.ext.mapreduce import output_writers
 from google.appengine.ext.mapreduce import base_handler
+from google.appengine.ext.mapreduce import context
+from google.appengine.ext.mapreduce import errors
 from google.appengine.ext.mapreduce import input_readers
 from google.appengine.ext.mapreduce import mapper_pipeline
+from google.appengine.ext.mapreduce import operation
 from google.appengine.ext.mapreduce import output_writers
 from google.appengine.ext.mapreduce import shuffler
+from google.appengine.ext.mapreduce import util
 
 
 
@@ -90,31 +100,95 @@
         shards=shards)
 
 
-class KeyValuesReader(input_readers.RecordsReader):
+class _ReducerReader(input_readers.RecordsReader):
   """Reader to read KeyValues records files from Files API."""
 
   expand_parameters = True
 
-  def __iter__(self):
-    current_key = None
-    current_values = None
+  def __init__(self, filenames, position):
+    super(_ReducerReader, self).__init__(filenames, position)
+    self.current_key = None
+    self.current_values = None
 
-    for binary_record in input_readers.RecordsReader.__iter__(self):
+  def __iter__(self):
+    ctx = context.get()
+    combiner = None
+
+    if ctx:
+      combiner_spec = ctx.mapreduce_spec.mapper.params.get("combiner_spec")
+      if combiner_spec:
+        combiner = util.handler_for_name(combiner_spec)
+
+    self.current_key = None
+    self.current_values = None
+
+    for binary_record in super(_ReducerReader, self).__iter__():
       proto = file_service_pb.KeyValues()
       proto.ParseFromString(binary_record)
-      if current_key is None:
-        current_key = proto.key()
-        current_values = proto.value_list()
+
+      if self.current_key is None:
+        self.current_key = proto.key()
+        self.current_values = []
       else:
-        assert proto.key() == current_key
-        current_values.extend(proto.value_list())
+        assert proto.key() == self.current_key, (
+            "inconsistent key sequence. Expected %s but got %s" %
+            (self.current_key, proto.key()))
+
+      if combiner:
+        combiner_result = combiner(
+            self.current_key, proto.value_list(), self.current_values)
+
+        if not util.is_generator(combiner_result):
+          raise errors.BadCombinerOutputError(
+              "Combiner %s should yield values instead of returning them (%s)" %
+              (combiner, combiner_result))
+
+        self.current_values = []
+        for value in combiner_result:
+          if isinstance(value, operation.Operation):
+            value(ctx)
+          else:
+
+            self.current_values.append(value)
+      else:
+
+        self.current_values.extend(proto.value_list())
 
       if not proto.partial():
+        key = self.current_key
+        values = self.current_values
 
+        self.current_key = None
+        self.current_values = None
+        yield (key, values)
+      else:
+        yield input_readers.ALLOW_CHECKPOINT
 
-        yield (current_key, current_values)
-        current_key = None
-        current_values = None
+  def to_json(self):
+    """Returns an input shard state for the remaining inputs.
+
+    Returns:
+      A json-izable version of the remaining InputReader.
+    """
+    result = super(_ReducerReader, self).to_json()
+    result["current_key"] = self.current_key
+    result["current_values"] = self.current_values
+    return result
+
+  @classmethod
+  def from_json(cls, json):
+    """Creates an instance of the InputReader for the given input shard state.
+
+    Args:
+      json: The InputReader state as a dict-like object.
+
+    Returns:
+      An instance of the InputReader configured using the values of json.
+    """
+    result = super(_ReducerReader, cls).from_json(json)
+    result.current_key = json["current_key"]
+    result.current_values = json["current_values"]
+    return result
 
 
 class ReducePipeline(base_handler.PipelineBase):
@@ -129,6 +203,12 @@
       function.
     params: mapper parameters to use as dict.
     filenames: list of filenames to reduce.
+    combiner_spec: Optional. Specification of a combine function. If not
+      supplied, no combine step will take place. The combine function takes a
+      key, list of values and list of previously combined results. It yields
+      combined values that might be processed by another combiner call, but will
+      eventually end up in reducer. The combiner output key is assumed to be the
+      same as the input key.
 
   Returns:
     filenames from output writer.
@@ -139,15 +219,21 @@
           reducer_spec,
           output_writer_spec,
           params,
-          filenames):
+          filenames,
+          combiner_spec=None):
     new_params = dict(params or {})
     new_params.update({
         "files": filenames
         })
+    if combiner_spec:
+      new_params.update({
+          "combiner_spec": combiner_spec,
+          })
+
     yield mapper_pipeline.MapperPipeline(
         job_name + "-reduce",
         reducer_spec,
-        __name__ + ".KeyValuesReader",
+        __name__ + "._ReducerReader",
         output_writer_spec,
         new_params)
 
@@ -158,12 +244,18 @@
   Args:
     job_name: job name as string.
     mapper_spec: specification of mapper to use.
-    reader_spec: specification of reducer to use.
+    reducer_spec: specification of reducer to use.
     input_reader_spec: specification of input reader to read data from.
     output_writer_spec: specification of output writer to save reduce output to.
     mapper_params: parameters to use for mapper phase.
     reducer_params: parameters to use for reduce phase.
     shards: number of shards to use as int.
+    combiner_spec: Optional. Specification of a combine function. If not
+      supplied, no combine step will take place. The combine function takes a
+      key, list of values and list of previously combined results. It yields
+      combined values that might be processed by another combiner call, but will
+      eventually end up in reducer. The combiner output key is assumed to be the
+      same as the input key.
 
   Returns:
     filenames from output writer.
@@ -177,18 +269,22 @@
           output_writer_spec=None,
           mapper_params=None,
           reducer_params=None,
-          shards=None):
+          shards=None,
+          combiner_spec=None):
     map_pipeline = yield MapPipeline(job_name,
                                      mapper_spec,
                                      input_reader_spec,
                                      params=mapper_params,
                                      shards=shards)
-    shuffler_pipeline = yield ShufflePipeline(job_name, map_pipeline)
-    reducer_pipeline = yield ReducePipeline(job_name,
-                                            reducer_spec,
-                                            output_writer_spec,
-                                            reducer_params,
-                                            shuffler_pipeline)
+    shuffler_pipeline = yield ShufflePipeline(
+        job_name, map_pipeline)
+    reducer_pipeline = yield ReducePipeline(
+        job_name,
+        reducer_spec,
+        output_writer_spec,
+        reducer_params,
+        shuffler_pipeline,
+        combiner_spec=combiner_spec)
     with pipeline.After(reducer_pipeline):
       all_temp_files = yield pipeline_common.Extend(
           map_pipeline, shuffler_pipeline)
diff --git a/google/appengine/ext/mapreduce/model.py b/google/appengine/ext/mapreduce/model.py
index 5ca2881..bbe41dd 100644
--- a/google/appengine/ext/mapreduce/model.py
+++ b/google/appengine/ext/mapreduce/model.py
@@ -56,7 +56,6 @@
 except ImportError:
   import simplejson
 import time
-import types
 
 from google.appengine.api import datastore_errors
 from google.appengine.api import datastore_types
@@ -399,16 +398,7 @@
       cached handler instance as callable.
     """
     if self.__handler is None:
-      resolved_spec = util.for_name(self.handler_spec)
-      if isinstance(resolved_spec, type):
-
-        self.__handler = resolved_spec()
-      elif isinstance(resolved_spec, types.MethodType):
-
-        self.__handler = getattr(resolved_spec.im_class(),
-                                 resolved_spec.__name__)
-      else:
-        self.__handler = resolved_spec
+      self.__handler = util.handler_for_name(self.handler_spec)
     return self.__handler
 
   handler = property(get_handler)
diff --git a/google/appengine/ext/mapreduce/shuffler.py b/google/appengine/ext/mapreduce/shuffler.py
index a53d297..8bf0343 100644
--- a/google/appengine/ext/mapreduce/shuffler.py
+++ b/google/appengine/ext/mapreduce/shuffler.py
@@ -36,6 +36,10 @@
 
 
 
+__all__ = [
+    "ShufflePipeline",
+    ]
+
 import gc
 import heapq
 import logging
@@ -55,7 +59,6 @@
 from google.appengine.ext.mapreduce import mapper_pipeline
 from google.appengine.ext.mapreduce import operation
 from google.appengine.ext.mapreduce import output_writers
-from google.appengine.ext.mapreduce import util
 
 
 class _OutputFile(db.Model):
@@ -276,6 +279,9 @@
       readers.append((None, None, i, reader))
 
 
+
+
+
     current_result = None
     current_count = 0
     current_size = 0
@@ -288,19 +294,25 @@
 
         should_yield = False
         if current_result:
-          should_yield = key != current_result[0]
-          if (self._max_values_count != -1 and
-              current_count >= self._max_values_count):
+          if key != current_result[0]:
+
             should_yield = True
-          if (self._max_values_size != -1 and
+          elif (self._max_values_count != -1 and
+              current_count >= self._max_values_count):
+
+            current_result[2] = True
+            should_yield = True
+          elif (self._max_values_size != -1 and
               current_size >= self._max_values_size):
+
+            current_result[2] = True
             should_yield = True
 
         if should_yield:
 
           yield current_result
         if not current_result or should_yield:
-          current_result = (key, [])
+          current_result = [key, [], False]
           current_count = 0
           current_size = 0
         current_result[1].append(value)
@@ -498,31 +510,6 @@
     ctx.get_pool(pool_name).append(proto.Encode())
 
 
-class _CombineMap(object):
-  """A map function used in the combine phase.
-
-  Uses a combine function to merge N values for a single key into one value
-  for that same key. Outputs encoded KeyValue protos (the singular kind).
-  """
-
-  def __init__(self):
-    self._initialized = False
-    self._combiner = None
-
-  def run(self, key, values):
-    if not self._combiner:
-      ctx = context.get()
-      params = ctx.mapreduce_spec.mapper.params
-      combine_spec = params.get(_CombinePipeline.COMBINE_SPEC_PARAM)
-      self._combiner = util.for_name(combine_spec)
-
-    for combined_value in self._combiner(key, values, []):
-      proto = file_service_pb.KeyValue()
-      proto.set_key(key)
-      proto.set_value(combined_value)
-      yield proto.Encode()
-
-
 class _ShardOutputs(base_handler.PipelineBase):
   """Takes a flat list of filenames, returns a list of lists, each with
   one member each.
@@ -535,50 +522,20 @@
     return result
 
 
-class _CombinePipeline(base_handler.PipelineBase):
-  """Pipeline to combine sorted output.
-
-  Args:
-    filenames: list of lists of filenames. Each list will correspond to a single
-      shard. Each file in the list should have keys sorted and should contain
-      records with KeyValue serialized entity.
-    combine_spec: Specification of a combine function. The combine function
-      takes a key and list of values and yields a single value or no values. The
-      combiner output key is assumed to be the same as the input key.
-
-  Returns:
-    A list of filenames lists, where each filename contains records with
-    KeyValue serialized entities.
-  """
-
-  COMBINE_SPEC_PARAM = "combine_spec"
-
-  def run(self, job_name, filenames, combine_spec):
-    max_values_count = 100000
-    max_values_size = 1000000
-    combined_result = yield mapper_pipeline.MapperPipeline(
-            job_name + "-combine",
-            __name__ + "._CombineMap.run",
-            __name__ + "._MergingReader",
-            output_writer_spec=
-                output_writers.__name__ + ".BlobstoreRecordsOutputWriter",
-            params={
-                _MergingReader.FILES_PARAM: filenames,
-                _MergingReader.MAX_VALUES_COUNT_PARAM: max_values_count,
-                _MergingReader.MAX_VALUES_SIZE_PARAM: max_values_size,
-                _CombinePipeline.COMBINE_SPEC_PARAM: combine_spec},
-            shards=len(filenames))
-    yield _ShardOutputs(combined_result)
-
-
-def _merge_map(k, values):
+def _merge_map(key, values, partial):
   """A map function used in merge phase.
 
-  Stores (k, values) into KeyValues proto and yields its serialization.
+  Stores (key, values) into KeyValues proto and yields its serialization.
+
+  Args:
+    key: values key.
+    values: values themselves.
+    partial: True if more values for this key will follow. False otherwise.
   """
   proto = file_service_pb.KeyValues()
-  proto.set_key(k)
+  proto.set_key(key)
   proto.value_list().extend(values)
+  proto.set_partial(partial)
   yield proto.Encode()
 
 
@@ -591,25 +548,30 @@
     filenames: list of lists of filenames. Each list will correspond to a single
       shard. Each file in the list should have keys sorted and should contain
       records with KeyValue serialized entity.
-    combine_spec: Specification of a combine function. If not supplied,
-      no combine step will take place. The combine function takes a key and
-      list of values and yields one value or no values. The combiner output key
-      is assumed to be the same as the input key.
 
   Returns:
     The list of filenames, where each filename is fully merged and will contain
     records with KeyValues serialized entity.
   """
 
+
+  _MAX_VALUES_COUNT = 100000
+
+  _MAX_VALUES_SIZE = 1000000
+
   def run(self, job_name, filenames):
     yield mapper_pipeline.MapperPipeline(
-            job_name + "-shuffle-merge",
-            __name__ + "._merge_map",
-            __name__ + "._MergingReader",
-            output_writer_spec=
-                output_writers.__name__ + ".BlobstoreRecordsOutputWriter",
-            params={_MergingReader.FILES_PARAM: filenames},
-            shards=len(filenames))
+        job_name + "-shuffle-merge",
+        __name__ + "._merge_map",
+        __name__ + "._MergingReader",
+        output_writer_spec=
+        output_writers.__name__ + ".BlobstoreRecordsOutputWriter",
+        params={
+          _MergingReader.FILES_PARAM: filenames,
+          _MergingReader.MAX_VALUES_COUNT_PARAM: self._MAX_VALUES_COUNT,
+          _MergingReader.MAX_VALUES_SIZE_PARAM: self._MAX_VALUES_SIZE,
+          },
+        shards=len(filenames))
 
 
 def _hashing_map(binary_record):
@@ -714,30 +676,20 @@
       protocol messages.
     shards: Optional. Number of output shards to generate. Defaults
       to the number of input files.
-    combine_spec: Optional. Specification of a combine function. If not
-      supplied, no combine step will take place. The combine function takes a
-      key and list of values and yields a single value or no values. The
-      combiner output key is assumed to be the same as the input key.
 
   Returns:
     The list of filenames as string. Resulting files contain serialized
     file_service_pb.KeyValues protocol messages with all values collated
     to a single key.
   """
-  def run(self, job_name, filenames, shards=None, combine_spec=None):
+  def run(self, job_name, filenames, shards=None):
     if files.shuffler.available():
-      assert not combine_spec
       yield _ShuffleServicePipeline(job_name, filenames)
     else:
       hashed_files = yield _HashPipeline(job_name, filenames, shards=shards)
       sorted_files = yield _SortChunksPipeline(job_name, hashed_files)
       temp_files = [hashed_files, sorted_files]
 
-      if combine_spec:
-        sorted_files = yield _CombinePipeline(
-            job_name, sorted_files, combine_spec)
-        temp_files.append(sorted_files)
-
       merged_files = yield _MergePipeline(job_name, sorted_files)
 
       with pipeline.After(merged_files):
diff --git a/google/appengine/ext/mapreduce/static/status.js b/google/appengine/ext/mapreduce/static/status.js
index d8fed8f..1fc6304 100644
--- a/google/appengine/ext/mapreduce/static/status.js
+++ b/google/appengine/ext/mapreduce/static/status.js
@@ -20,19 +20,19 @@
 function setButter(message, error) {
   var butter = getButterBar();
   // Prevent flicker on butter update by hiding it first.
-  butter.css('display', 'none');
+  butter.hide();
   if (error) {
     butter.removeClass('info').addClass('error').text(message);
   } else {
     butter.removeClass('error').addClass('info').text(message);
   }
-  butter.css('display', null)
+  butter.show();
   $(document).scrollTop(0);
 }
 
 // Hides the butter bar.
 function hideButter() {
-  getButterBar().css('display', 'none');
+  getButterBar().hide();
 }
 
 // Fetches the butter bar dom element.
@@ -69,7 +69,7 @@
       .attr('href', '');
   toggle.click(function(e) {
       e.preventDefault();
-      if (moreSpan.css('display') == 'none') {
+      if (moreSpan.is(':hidden')) {
         betweenSpan.text(' ');
         toggle.text('Collapse');
       } else {
@@ -307,7 +307,7 @@
   }
 
   // Show header.
-  $('#running-list > thead').css('display', null);
+  $('#running-list > thead').show();
 
   // Populate the table.
   $.each(jobs, function(index, job) {
@@ -355,7 +355,7 @@
 
   // Set up the next/first page links.
   $('#running-first-page')
-    .css('display', null)
+    .show()
     .unbind('click')
     .click(function() {
     listJobs(null, initJobOverview);
@@ -364,15 +364,15 @@
   $('#running-next-page').unbind('click');
   if (cursor) {
     $('#running-next-page')
-      .css('display', null)
+      .show()
       .click(function() {
         listJobs(cursor, initJobOverview);
         return false;
       });
   } else {
-    $('#running-next-page').css('display', 'none');
+    $('#running-next-page').hide();
   }
-  $('#running-list > tfoot').css('display', null);
+  $('#running-list > tfoot').show();
 }
 
 //////// Launching jobs.
@@ -395,10 +395,10 @@
     if ($(jobForm).find('input[name="name"]').val() == name) {
       matchedForm = jobForm;
     } else {
-      $(jobForm).css('display', 'none');
+      $(jobForm).hide();
     }
   });
-  $(matchedForm).css('display', null);
+  $(matchedForm).show();
 }
 
 function runJobDone(name, error, data) {
@@ -442,7 +442,7 @@
         runJob(config.name);
         return false;
       })
-      .css('display', 'none')
+      .hide()
       .appendTo('#launch-container');
 
     // Fixed job config values.
diff --git a/google/appengine/ext/mapreduce/util.py b/google/appengine/ext/mapreduce/util.py
index 0e403c6..4401165 100644
--- a/google/appengine/ext/mapreduce/util.py
+++ b/google/appengine/ext/mapreduce/util.py
@@ -33,9 +33,16 @@
 """Utility functions for use with the mapreduce library."""
 
 
-__all__ = ["for_name", "is_generator_function", "get_short_name", "parse_bool",
-           "create_datastore_write_config",
-           "HugeTask", "HugeTaskHandler"]
+__all__ = [
+    "create_datastore_write_config",
+    "for_name",
+    "get_short_name",
+    "handler_for_name",
+    "is_generator",
+    "parse_bool",
+    "HugeTask",
+    "HugeTaskHandler",
+    ]
 
 
 import base64
@@ -43,6 +50,7 @@
 import inspect
 import logging
 import zlib
+import types
 import urllib
 
 from google.appengine.api import files
@@ -124,8 +132,32 @@
     raise
 
 
-def is_generator_function(obj):
-  """Return true if the object is a user-defined generator function.
+def handler_for_name(fq_name):
+  """Resolves and instantiates handler by fully qualified name.
+
+  First resolves the name using for_name call. Then if it resolves to a class,
+  instantiates a class, if it resolves to a method - instantiates the class and
+  binds method to the instance.
+
+  Args:
+    fq_name: fully qualified name of something to find.
+
+  Returns:
+    handler instance which is ready to be called.
+  """
+  resolved_name = for_name(fq_name)
+  if isinstance(resolved_name, (type, types.ClassType)):
+
+    return resolved_name()
+  elif isinstance(resolved_name, types.MethodType):
+
+    return getattr(resolved_name.im_class(), resolved_name.__name__)
+  else:
+    return resolved_name
+
+
+def is_generator(obj):
+  """Return true if the object is generator or generator function.
 
   Generator function objects provides same attributes as functions.
   See isfunction.__doc__ for attributes listing.
@@ -138,6 +170,9 @@
   Returns:
     true if the object is generator function.
   """
+  if isinstance(obj, types.GeneratorType):
+    return True
+
   CO_GENERATOR = 0x20
   return bool(((inspect.isfunction(obj) or inspect.ismethod(obj)) and
                obj.func_code.co_flags & CO_GENERATOR))
diff --git a/google/appengine/ext/ndb/__init__.py b/google/appengine/ext/ndb/__init__.py
index 45efc0a..5d3602e 100644
--- a/google/appengine/ext/ndb/__init__.py
+++ b/google/appengine/ext/ndb/__init__.py
@@ -1,6 +1,6 @@
 """NDB -- A new datastore API for the Google App Engine Python runtime."""
 
-__version__ = '0.9.6'
+__version__ = '0.9.7+'
 
 __all__ = []
 
diff --git a/google/appengine/ext/ndb/blobstore.py b/google/appengine/ext/ndb/blobstore.py
new file mode 100644
index 0000000..e4444dd
--- /dev/null
+++ b/google/appengine/ext/ndb/blobstore.py
@@ -0,0 +1,459 @@
+"""NDB interface for Blobstore.
+
+This currently builds on google.appengine.ext.blobstore and provides a
+similar API.  The main API differences:
+
+- BlobInfo is an actual Model subclass rather than a pseudo-model class.
+  To query, use BlobInfo.query() and its documented properties.  Other
+  changes:
+  - The kind is '__BlobInfo__' (BLOB_INFO_KIND).
+  - key() is a method returning a BlobKey instance.
+  - put() and friends are disabled.
+  - Added class methods get() and friends.
+  - Added instance methods delete() and friends, and open().
+
+- Instead of BlobReferenceProperty, there's BlobKeyProperty.
+
+- There is no create_rpc() function.  Instead, functions and methods
+  take keyword arguments to specify deadline, callback, and (in some
+  case) datastore options.
+
+- APIs (get() and delete()) that in ext.blobstore take either a blob
+  key or a list of blob keys are split into two: one that takes a blob
+  key and one that takes a list of blob keys, the latter having a name
+  ending in _multi.
+
+- The following APIs have a synchronous and an async version:
+  - BlobInfo.get()
+  - BlobInfo.delete()
+  - create_upload_url()
+  - get()
+  - get_multi()
+  - delete()
+  - delete_multi()
+  - fetch_data()
+"""
+
+# TODO: Should delete() and friends accept BlobInfos too?
+# TODO: Don't have redundant function/method versions of APIs?
+# TODO: Refactor ext.blobstore to reduce duplication of code.
+
+import base64
+import email
+
+from .google_imports import api_blobstore as blobstore
+from .google_imports import ext_blobstore
+
+from . import model
+from . import tasklets
+
+__all__ = ['BLOB_INFO_KIND',
+           'BLOB_KEY_HEADER',
+           'BLOB_MIGRATION_KIND',
+           'BLOB_RANGE_HEADER',
+           'BlobFetchSizeTooLargeError',
+           'BlobInfo',
+           'BlobInfoParseError',
+           'BlobKey',
+           'BlobNotFoundError',
+           'BlobKeyProperty',
+           'BlobReader',
+           'DataIndexOutOfRangeError',
+           'PermissionDeniedError',
+           'Error',
+           'InternalError',
+           'MAX_BLOB_FETCH_SIZE',
+           'UPLOAD_INFO_CREATION_HEADER',
+           'create_upload_url',
+           'create_upload_url_async',
+           'delete',
+           'delete_async',
+           'delete_multi',
+           'delete_multi_async',
+           'fetch_data',
+           'fetch_data_async',
+           'get',
+           'get_async',
+           'get_multi',
+           'get_multi_async',
+           'parse_blob_info']
+
+# Exceptions are all imported.
+Error = blobstore.Error
+InternalError = blobstore.InternalError
+BlobFetchSizeTooLargeError = blobstore.BlobFetchSizeTooLargeError
+BlobNotFoundError = blobstore.BlobNotFoundError
+_CreationFormatError = blobstore._CreationFormatError
+DataIndexOutOfRangeError = blobstore.DataIndexOutOfRangeError
+PermissionDeniedError = blobstore.PermissionDeniedError
+BlobInfoParseError = ext_blobstore.BlobInfoParseError
+
+# So is BlobKey.
+BlobKey = blobstore.BlobKey
+
+# And the constants.
+BLOB_INFO_KIND = blobstore.BLOB_INFO_KIND
+BLOB_MIGRATION_KIND = blobstore.BLOB_MIGRATION_KIND
+BLOB_KEY_HEADER = blobstore.BLOB_KEY_HEADER
+BLOB_RANGE_HEADER = blobstore.BLOB_RANGE_HEADER
+MAX_BLOB_FETCH_SIZE = blobstore.MAX_BLOB_FETCH_SIZE
+UPLOAD_INFO_CREATION_HEADER = blobstore.UPLOAD_INFO_CREATION_HEADER
+
+# Re-export BlobKeyProperty from ndb.model for completeness.
+BlobKeyProperty = model.BlobKeyProperty
+
+
+class BlobInfo(model.Model):
+  """Information about blobs in Blobstore.
+
+  This is a Model subclass that has been doctored to be unwritable.
+
+  Properties:
+  - content_type: Content type of blob.
+  - creation: Creation date of blob, when it was uploaded.
+  - filename: Filename user selected from their machine.
+  - size: Size of uncompressed blob.
+  - md5_hash: The md5 hash value of the uploaded blob (in hex).
+
+  Additional API:
+
+  Class methods:
+  - get(): retrieve a BlobInfo by key
+  - get_multi(): retrieve a list of BlobInfos by keys
+  - get_async(), get_multi_async(): async version of get() and get_multi()
+
+  Instance methods:
+  - delete(): delete this blob
+  - delete_async(): async version of delete()
+  - key(): return the BlobKey for this blob
+  - open(): return a BlobReader instance for this blob
+
+  Because BlobInfo instances are synchronized with Blobstore, the class
+  cache policies are off.
+
+  Do not subclass this class.
+  """
+
+  _use_cache = False
+  _use_memcache = False
+
+  content_type = model.StringProperty()
+  creation = model.DateTimeProperty()
+  filename = model.StringProperty()
+  size = model.IntegerProperty()
+  md5_hash = model.StringProperty()
+
+  @classmethod
+  def _get_kind(cls):
+    """Override this to match the datastore entities written by Blobstore."""
+    return BLOB_INFO_KIND  # __BlobInfo__
+
+  @classmethod
+  def get(cls, blob_key, **ctx_options):
+    """Retrieve a BlobInfo by key.
+
+    Args:
+      blob_key: A blob key.  This may be a str, unicode or BlobKey instance.
+      **ctx_options: Context options for Model().get_by_id().
+
+    Returns:
+      A BlobInfo entity associated with the provided key,  If there was
+      no such entity, returns None.
+    """
+    fut = cls.get_async(blob_key, **ctx_options)
+    return fut.get_result()
+
+  @classmethod
+  def get_async(cls, blob_key, **ctx_options):
+    """Async version of get()."""
+    if not isinstance(blob_key, (BlobKey, basestring)):
+      raise TypeError('Expected blob key, got %r' % (blob_key,))
+    if 'parent' in ctx_options:
+      raise TypeError('Parent is not supported')
+    return cls.get_by_id_async(str(blob_key), **ctx_options)
+
+  @classmethod
+  def get_multi(cls, blob_keys, **ctx_options):
+    """Multi-key version of get().
+
+    Args:
+      blob_keys: A list of blob keys.
+      **ctx_options: Context options for Model().get_by_id().
+
+    Returns:
+      A list whose items are each either a BlobInfo entity or None.
+    """
+    futs = cls.get_multi_async(blob_keys, **ctx_options)
+    return [fut.get_result() for fut in futs]
+
+  @classmethod
+  def get_multi_async(cls, blob_keys, **ctx_options):
+    """Async version of get_multi()."""
+    for blob_key in blob_keys:
+      if not isinstance(blob_key, (BlobKey, basestring)):
+        raise TypeError('Expected blob key, got %r' % (blob_key,))
+    if 'parent' in ctx_options:
+      raise TypeError('Parent is not supported')
+    blob_key_strs = map(str, blob_keys)
+    keys = [model.Key(BLOB_INFO_KIND, id) for id in blob_key_strs]
+    return model.get_multi_async(keys, **ctx_options)
+
+  def _put_async(self, **ctx_options):
+    """Cheap way to make BlobInfo entities read-only."""
+    raise TypeError('BlobInfo is read-only')
+  put_async = _put_async
+
+  def key(self):
+    """Get key for blob.
+
+    Returns:
+      BlobKey instance that identifies this blob.
+    """
+    # TODO: Cache this?
+    return BlobKey(self._key.id())
+
+  def delete(self, **options):
+    """Permanently delete this blob from Blobstore.
+
+    Args:
+      **options: Options for create_rpc().
+    """
+    fut = delete_async(self.key(), **options)
+    fut.get_result()
+
+  def delete_async(self, **options):
+    """Async version of delete()."""
+    return delete_async(self.key(), **options)  # A Future!
+
+  def open(self, *args, **kwds):
+    """Returns a BlobReader for this blob.
+
+    Args:
+      *args, **kwargs: Passed to BlobReader constructor.
+
+    Returns:
+      A BlobReader instance.
+    """
+    return BlobReader(self, *args, **kwds)
+
+
+get = BlobInfo.get
+get_async = BlobInfo.get_async
+get_multi = BlobInfo.get_multi
+get_multi_async = BlobInfo.get_multi_async
+
+
+def delete(blob_key, **options):
+  """Delete a blob from Blobstore.
+
+  Args:
+    blob_key: A blob key.  This may be a str, unicode or BlobKey instance.
+    **options: Options for create_rpc().
+  """
+  fut = delete_async(blob_key, **options)
+  return fut.get_result()
+
+
+@tasklets.tasklet
+def delete_async(blob_key, **options):
+  """Async version of delete()."""
+  if not isinstance(blob_key, (basestring, BlobKey)):
+    raise TypeError('Expected blob key, got %r' % (blob_key,))
+  rpc = blobstore.create_rpc(**options)
+  yield blobstore.delete_async(blob_key, rpc=rpc)
+
+
+def delete_multi(blob_keys, **options):
+  """Delete blobs from Blobstore.
+
+  Args:
+    blob_keys: A list of blob keys.
+    **options: Options for create_rpc().
+  """
+  fut = delete_multi_async(blob_keys, **options)
+  fut.get_result()
+
+
+@tasklets.tasklet
+def delete_multi_async(blob_keys, **options):
+  """Async version of delete_multi()."""
+  if isinstance(blob_keys, (basestring, BlobKey)):
+    raise TypeError('Expected a list, got %r' % (blob_key,))
+  rpc = blobstore.create_rpc(**options)
+  yield blobstore.delete_async(blob_keys, rpc=rpc)
+
+
+def create_upload_url(success_path,
+                      max_bytes_per_blob=None,
+                      max_bytes_total=None,
+                      **options):
+  """Create upload URL for POST form.
+
+  Args:
+    success_path: Path within application to call when POST is successful
+      and upload is complete.
+    max_bytes_per_blob: The maximum size in bytes that any one blob in the
+      upload can be or None for no maximum size.
+    max_bytes_total: The maximum size in bytes that the aggregate sizes of all
+      of the blobs in the upload can be or None for no maximum size.
+    **options: Options for create_rpc().
+
+  Returns:
+    The upload URL.
+
+  Raises:
+    TypeError: If max_bytes_per_blob or max_bytes_total are not integral types.
+    ValueError: If max_bytes_per_blob or max_bytes_total are not
+      positive values.
+  """
+  fut = create_upload_url_async(success_path,
+                                max_bytes_per_blob=max_bytes_per_blob,
+                                max_bytes_total=max_bytes_total,
+                                **options)
+  return fut.get_result()
+
+
+@tasklets.tasklet
+def create_upload_url_async(success_path,
+                      max_bytes_per_blob=None,
+                      max_bytes_total=None,
+                      **options):
+  """Async version of create_upload_url()."""
+  rpc = blobstore.create_rpc(**options)
+  rpc = blobstore.create_upload_url_async(success_path,
+                                          max_bytes_per_blob=max_bytes_per_blob,
+                                          max_bytes_total=max_bytes_total,
+                                          rpc=rpc)
+  result = yield rpc
+  raise tasklets.Return(result)
+
+
+def parse_blob_info(field_storage):
+  """Parse a BlobInfo record from file upload field_storage.
+
+  Args:
+    field_storage: cgi.FieldStorage that represents uploaded blob.
+
+  Returns:
+    BlobInfo record as parsed from the field-storage instance.
+    None if there was no field_storage.
+
+  Raises:
+    BlobInfoParseError when provided field_storage does not contain enough
+    information to construct a BlobInfo object.
+  """
+  if field_storage is None:
+    return None
+
+  field_name = field_storage.name
+
+  def get_value(dct, name):
+    value = dct.get(name, None)
+    if value is None:
+      raise BlobInfoParseError(
+          'Field %s has no %s.' % (field_name, name))
+    return value
+
+  filename = get_value(field_storage.disposition_options, 'filename')
+  blob_key_str = get_value(field_storage.type_options, 'blob-key')
+  blob_key = BlobKey(blob_key_str)
+
+  upload_content = email.message_from_file(field_storage.file)
+  content_type = get_value(upload_content, 'content-type')
+  size = get_value(upload_content, 'content-length')
+  creation_string = get_value(upload_content, UPLOAD_INFO_CREATION_HEADER)
+  md5_hash_encoded = get_value(upload_content, 'content-md5')
+  md5_hash = base64.urlsafe_b64decode(md5_hash_encoded)
+
+  try:
+    size = int(size)
+  except (TypeError, ValueError):
+    raise BlobInfoParseError(
+        '%s is not a valid value for %s size.' % (size, field_name))
+
+  try:
+    creation = blobstore._parse_creation(creation_string, field_name)
+  except blobstore._CreationFormatError, err:
+    raise BlobInfoParseError(str(err))
+
+  return BlobInfo(id=blob_key_str,
+                  content_type=content_type,
+                  creation=creation,
+                  filename=filename,
+                  size=size,
+                  md5_hash=md5_hash,
+                  )
+
+
+def fetch_data(blob, start_index, end_index, **options):
+  """Fetch data for blob.
+
+  Fetches a fragment of a blob up to MAX_BLOB_FETCH_SIZE in length.  Attempting
+  to fetch a fragment that extends beyond the boundaries of the blob will return
+  the amount of data from start_index until the end of the blob, which will be
+  a smaller size than requested.  Requesting a fragment which is entirely
+  outside the boundaries of the blob will return empty string.  Attempting
+  to fetch a negative index will raise an exception.
+
+  Args:
+    blob: BlobInfo, BlobKey, str or unicode representation of BlobKey of
+      blob to fetch data from.
+    start_index: Start index of blob data to fetch.  May not be negative.
+    end_index: End index (inclusive) of blob data to fetch.  Must be
+      >= start_index.
+    **options: Options for create_rpc().
+
+  Returns:
+    str containing partial data of blob.  If the indexes are legal but outside
+    the boundaries of the blob, will return empty string.
+
+  Raises:
+    TypeError if start_index or end_index are not indexes.  Also when blob
+      is not a string, BlobKey or BlobInfo.
+    DataIndexOutOfRangeError when start_index < 0 or end_index < start_index.
+    BlobFetchSizeTooLargeError when request blob fragment is larger than
+      MAX_BLOB_FETCH_SIZE.
+    BlobNotFoundError when blob does not exist.
+  """
+  fut = fetch_data_async(blob, start_index, end_index, **options)
+  return fut.get_result()
+
+
+@tasklets.tasklet
+def fetch_data_async(blob, start_index, end_index, **options):
+  """Async version of fetch_data()."""
+  if isinstance(blob, BlobInfo):
+    blob = blob.key()
+  rpc = blobstore.create_rpc(**options)
+  rpc = blobstore.fetch_data_async(blob, start_index, end_index, rpc=rpc)
+  result = yield rpc
+  raise tasklets.Return(result)
+
+
+class BlobReader(ext_blobstore.BlobReader):
+  """Provides a read-only file-like interface to a blobstore blob."""
+
+  # This just overrides two methods to use the proper versions.
+  # Hack alert: this can access private attributes of the parent class
+  # because it has the same class name.  (This is a Python feature.)
+
+  def __fill_buffer(self, size=0):
+    """Fills the internal buffer.
+
+    Args:
+      size: Number of bytes to read. Will be clamped to
+        [self.__buffer_size, MAX_BLOB_FETCH_SIZE].
+    """
+    read_size = min(max(size, self.__buffer_size), MAX_BLOB_FETCH_SIZE)
+
+    self.__buffer = fetch_data(self.__blob_key, self.__position,
+                               self.__position + read_size - 1)
+    self.__buffer_position = 0
+    self.__eof = len(self.__buffer) < read_size
+
+  @property
+  def blob_info(self):
+    """Returns the BlobInfo for this file."""
+    if not self.__blob_info:
+      self.__blob_info = BlobInfo.get(self.__blob_key)
+    return self.__blob_info
diff --git a/google/appengine/ext/ndb/context.py b/google/appengine/ext/ndb/context.py
index b9bc143..d2325a0 100644
--- a/google/appengine/ext/ndb/context.py
+++ b/google/appengine/ext/ndb/context.py
@@ -3,14 +3,15 @@
 import logging
 import sys
 
-from google.appengine.api import datastore  # For taskqueue coordination
-from google.appengine.api import datastore_errors
-from google.appengine.api import memcache
-from google.appengine.api import namespace_manager
-from google.appengine.datastore import datastore_rpc
-from google.appengine.datastore import entity_pb
+from .google_imports import datastore  # For taskqueue coordination
+from .google_imports import datastore_errors
+from .google_imports import memcache
+from .google_imports import namespace_manager
+from .google_imports import urlfetch
+from .google_imports import datastore_rpc
+from .google_imports import entity_pb
 
-from google.net.proto import ProtocolBuffer
+from .google_imports import ProtocolBuffer
 
 from . import key as key_module
 from . import model
@@ -18,14 +19,18 @@
 from . import eventloop
 from . import utils
 
-__all__ = ['toplevel', 'Context', 'ContextOptions', 'AutoBatcher']
-
-logging_debug = utils.logging_debug
+__all__ = ['Context', 'ContextOptions', 'AutoBatcher',
+           'EVENTUAL_CONSISTENCY',
+           ]
 
 _LOCK_TIME = 32  # Time to lock out memcache.add() after datastore updates.
 _LOCKED = 0  # Special value to store in memcache indicating locked value.
 
 
+# Constant for read_policy.
+EVENTUAL_CONSISTENCY = datastore_rpc.Configuration.EVENTUAL_CONSISTENCY
+
+
 class ContextOptions(datastore_rpc.TransactionOptions):
   """Configuration options that may be passed along with get/put/delete."""
 
@@ -110,8 +115,8 @@
     return '%s(%s)' % (self.__class__.__name__, self._todo_tasklet.__name__)
 
   def run_queue(self, options, todo):
-    logging_debug('AutoBatcher(%s): %d items',
-                  self._todo_tasklet.__name__, len(todo))
+    utils.logging_debug('AutoBatcher(%s): %d items',
+                        self._todo_tasklet.__name__, len(todo))
     fut = self._todo_tasklet(todo, options)
     self._running.append(fut)
     # Add a callback when we're done.
@@ -126,8 +131,8 @@
     fut = tasklets.Future('%s.add(%s, %s)' % (self, arg, options))
     todo = self._queues.get(options)
     if todo is None:
-      logging_debug('AutoBatcher(%s): creating new queue for %r',
-                    self._todo_tasklet.__name__, options)
+      utils.logging_debug('AutoBatcher(%s): creating new queue for %r',
+                          self._todo_tasklet.__name__, options)
       if not self._queues:
         eventloop.add_idle(self._on_idle)
       todo = self._queues[options] = []
@@ -711,8 +716,15 @@
     lo_hi = yield self._conn.async_allocate_ids(options, key, size, max)
     raise tasklets.Return(lo_hi)
 
+  @tasklets.tasklet
+  def get_indexes(self, **ctx_options):
+    options = _make_ctx_options(ctx_options)
+    index_list = yield self._conn.async_get_indexes(options)
+    raise tasklets.Return(index_list)
+
   @utils.positional(3)
-  def map_query(self, query, callback, options=None, merge_future=None):
+  def map_query(self, query, callback, pass_batch_into_callback=None,
+                options=None, merge_future=None):
     mfut = merge_future
     if mfut is None:
       mfut = tasklets.MultiFuture('map_query')
@@ -750,7 +762,7 @@
             val = ent
           else:
             # TODO: If the callback raises, log and ignore.
-            if options is not None and options.produce_cursors:
+            if pass_batch_into_callback:
               val = callback(batch, i, ent)
             else:
               val = callback(ent)
@@ -768,8 +780,10 @@
     return mfut
 
   @utils.positional(2)
-  def iter_query(self, query, callback=None, options=None):
+  def iter_query(self, query, callback=None, pass_batch_into_callback=None,
+                 options=None):
     return self.map_query(query, callback=callback, options=options,
+                          pass_batch_into_callback=pass_batch_into_callback,
                           merge_future=tasklets.SerialQueueFuture())
 
   @tasklets.tasklet
@@ -816,6 +830,7 @@
           t, e, tb = sys.exc_info()
           yield tconn.async_rollback(options)  # TODO: Don't block???
           if issubclass(t, datastore_errors.Rollback):
+            # TODO: Raise value using tasklets.get_return_value(t)?
             return
           else:
             raise t, e, tb
@@ -1036,7 +1051,6 @@
   def urlfetch(self, url, payload=None, method='GET', headers={},
                allow_truncated=False, follow_redirects=True,
                validate_certificate=None, deadline=None, callback=None):
-    from google.appengine.api import urlfetch
     rpc = urlfetch.create_rpc(deadline=deadline, callback=callback)
     urlfetch.make_fetch_call(rpc, url,
                              payload=payload,
@@ -1047,25 +1061,3 @@
                              validate_certificate=validate_certificate)
     result = yield rpc
     raise tasklets.Return(result)
-
-
-def toplevel(func):
-  """A sync tasklet that sets a fresh default Context.
-
-  Use this for toplevel view functions such as
-  webapp.RequestHandler.get() or Django view functions.
-  """
-  @utils.wrapping(func)
-  def add_context_wrapper(*args, **kwds):
-    __ndb_debug__ = utils.func_info(func)
-    tasklets._state.clear_all_pending()
-    # Create and install a new context.
-    ctx = tasklets.make_default_context()
-    try:
-      tasklets.set_context(ctx)
-      return tasklets.synctasklet(func)(*args, **kwds)
-    finally:
-      tasklets.set_context(None)
-      ctx.flush().check_success()
-      eventloop.run()  # Ensure writes are flushed, etc.
-  return add_context_wrapper
diff --git a/google/appengine/ext/ndb/eventloop.py b/google/appengine/ext/ndb/eventloop.py
index 518584f..468d37f 100644
--- a/google/appengine/ext/ndb/eventloop.py
+++ b/google/appengine/ext/ndb/eventloop.py
@@ -15,16 +15,22 @@
 import os
 import time
 
-from google.appengine.api.apiproxy_rpc import RPC
-from google.appengine.datastore import datastore_rpc
+from .google_imports import apiproxy_rpc
+from .google_imports import datastore_rpc
 
 from . import utils
 
-logging_debug = utils.logging_debug
+__all__ = ['EventLoop',
+           'add_idle', 'queue_call', 'queue_rpc',
+           'get_event_loop',
+           'run', 'run0', 'run1',
+           ]
 
-IDLE = RPC.IDLE
-RUNNING = RPC.RUNNING
-FINISHING = RPC.FINISHING
+_logging_debug = utils.logging_debug
+
+_IDLE = apiproxy_rpc.RPC.IDLE
+_RUNNING = apiproxy_rpc.RPC.RUNNING
+_FINISHING = apiproxy_rpc.RPC.FINISHING
 
 
 class EventLoop(object):
@@ -45,21 +51,21 @@
       idlers = self.idlers
       queue = self.queue
       rpcs = self.rpcs
-      logging_debug('Clearing stale EventLoop instance...')
+      _logging_debug('Clearing stale EventLoop instance...')
       if current:
-        logging_debug('  current = %s', current)
+        _logging_debug('  current = %s', current)
       if idlers:
-        logging_debug('  idlers = %s', idlers)
+        _logging_debug('  idlers = %s', idlers)
       if queue:
-        logging_debug('  queue = %s', queue)
+        _logging_debug('  queue = %s', queue)
       if rpcs:
-        logging_debug('  rpcs = %s', rpcs)
+        _logging_debug('  rpcs = %s', rpcs)
       self.__init__()
       current.clear()
       idlers.clear()
       queue[:] = []
       rpcs.clear()
-      logging_debug('Cleared')
+      _logging_debug('Cleared')
 
   def insort_event_right(self, event, lo=0, hi=None):
     """Insert event in queue, and keep it sorted assuming queue is sorted.
@@ -81,7 +87,6 @@
         else: lo = mid + 1
     self.queue.insert(lo, event)
 
-  # TODO: Rename to queue_callback?
   def queue_call(self, delay, callback, *args, **kwds):
     """Schedule a function call at a specific time in the future."""
     if delay is None:
@@ -105,7 +110,7 @@
     """
     if rpc is None:
       return
-    if rpc.state not in (RUNNING, FINISHING):
+    if rpc.state not in (_RUNNING, _FINISHING):
       raise RuntimeError('rpc must be sent to service before queueing')
     if isinstance(rpc, datastore_rpc.MultiRpc):
       rpcs = rpc.rpcs
@@ -113,7 +118,7 @@
         # Don't call the callback until all sub-rpcs have completed.
         rpc.__done = False
         def help_multi_rpc_along(r=rpc, c=callback, a=args, k=kwds):
-          if r.state == FINISHING and not r.__done:
+          if r.state == _FINISHING and not r.__done:
             r.__done = True
             c(*a, **k)
             # TODO: And again, what about exceptions?
@@ -149,7 +154,7 @@
       return False
     idler = self.idlers.popleft()
     callback, args, kwds = idler
-    logging_debug('idler: %s', callback.__name__)
+    _logging_debug('idler: %s', callback.__name__)
     res = callback(*args, **kwds)
     # See add_idle() for the meaning of the callback return value.
     if res is not None:
@@ -159,7 +164,7 @@
         self.inactive += 1
       self.idlers.append(idler)
     else:
-      logging_debug('idler %s removed', callback.__name__)
+      _logging_debug('idler %s removed', callback.__name__)
     return True
 
   def run0(self):
@@ -172,7 +177,7 @@
     if self.current:
       self.inactive = 0
       callback, args, kwds = self.current.popleft()
-      logging_debug('nowevent: %s', callback.__name__)
+      _logging_debug('nowevent: %s', callback.__name__)
       callback(*args, **kwds)
       return 0
     if self.run_idle():
@@ -183,7 +188,7 @@
       if delay <= 0:
         self.inactive = 0
         _, callback, args, kwds = self.queue.pop(0)
-        logging_debug('event: %s', callback.__name__)
+        _logging_debug('event: %s', callback.__name__)
         callback(*args, **kwds)
         # TODO: What if it raises an exception?
         return 0
@@ -191,7 +196,7 @@
       self.inactive = 0
       rpc = datastore_rpc.MultiRpc.wait_any(self.rpcs)
       if rpc is not None:
-        logging_debug('rpc: %s.%s', rpc.service, rpc.method)
+        _logging_debug('rpc: %s.%s', rpc.service, rpc.method)
         # Yes, wait_any() may return None even for a non-empty argument.
         # But no, it won't ever return an RPC not in its argument.
         if rpc not in self.rpcs:
@@ -243,7 +248,6 @@
   that we're in a new request by inspecting os.environ, which is reset
   at the start of each request.  Also, each thread gets its own loop.
   """
-  # TODO: Make sure this works with the multithreaded Python 2.7 runtime.
   ev = _state.event_loop
   if not os.getenv(_EVENT_LOOP_KEY) and ev is not None:
     ev.clear()
diff --git a/google/appengine/ext/ndb/google_imports.py b/google/appengine/ext/ndb/google_imports.py
new file mode 100644
index 0000000..e024696
--- /dev/null
+++ b/google/appengine/ext/ndb/google_imports.py
@@ -0,0 +1,61 @@
+"""Dynamically decide from where to import Google App Engine modules.
+
+All other NDB code should import its Google App Engine modules from
+this module.  If necessary, add new imports here (in both places).
+"""
+
+try:
+  from google.appengine import api
+  normal_environment = True
+except ImportError:
+  from google3.apphosting import api
+  normal_environment = False
+
+if normal_environment:
+  from google.appengine.api.blobstore import blobstore as api_blobstore
+  from google.appengine.api import apiproxy_rpc
+  from google.appengine.api import apiproxy_stub_map
+  from google.appengine.api import datastore
+  from google.appengine.api import datastore_errors
+  from google.appengine.api import datastore_types
+  from google.appengine.api import memcache
+  from google.appengine.api import namespace_manager
+  from google.appengine.api import prospective_search
+  from google.appengine.api import taskqueue
+  from google.appengine.api import urlfetch
+  from google.appengine.api import users
+  from google.appengine.api.prospective_search import prospective_search_pb
+  from google.appengine.datastore import datastore_query
+  from google.appengine.datastore import datastore_rpc
+  from google.appengine.datastore import entity_pb
+  from google.appengine.ext.blobstore import blobstore as ext_blobstore
+  from google.appengine.ext import db
+  from google.appengine.ext import gql
+  from google.appengine.runtime import apiproxy_errors
+  from google.net.proto import ProtocolBuffer
+else:
+  from google3.apphosting.api.blobstore import blobstore as api_blobstore
+  from google3.apphosting.api import apiproxy_rpc
+  from google3.apphosting.api import apiproxy_stub_map
+  from google3.apphosting.api import datastore
+  from google3.apphosting.api import datastore_errors
+  from google3.apphosting.api import datastore_types
+  from google3.apphosting.api import memcache
+  from google3.apphosting.api import namespace_manager
+  from google3.apphosting.api import taskqueue
+  from google3.apphosting.api import urlfetch
+  from google3.apphosting.api import users
+  from google3.apphosting.datastore import datastore_query
+  from google3.apphosting.datastore import datastore_rpc
+  from google3.storage.onestore.v3 import entity_pb
+  from google3.apphosting.ext.blobstore import blobstore as ext_blobstore
+  from google3.apphosting.ext import db
+  from google3.apphosting.ext import gql
+  from google3.apphosting.runtime import apiproxy_errors
+  from google3.net.proto import ProtocolBuffer
+  # Prospective search is optional.
+  try:
+    from google3.apphosting.api import prospective_search
+    from google3.apphosting.api.prospective_search import prospective_search_pb
+  except ImportError:
+    pass
diff --git a/google/appengine/ext/ndb/key.py b/google/appengine/ext/ndb/key.py
index 181fca6..3352afd 100644
--- a/google/appengine/ext/ndb/key.py
+++ b/google/appengine/ext/ndb/key.py
@@ -73,10 +73,10 @@
 import base64
 import os
 
-from google.appengine.api import datastore_errors
-from google.appengine.api import datastore_types
-from google.appengine.api import namespace_manager
-from google.appengine.datastore import entity_pb
+from .google_imports import datastore_errors
+from .google_imports import datastore_types
+from .google_imports import namespace_manager
+from .google_imports import entity_pb
 
 from . import utils
 
@@ -201,7 +201,8 @@
         kwargs = _args[0]
       else:
         if 'flat' in kwargs:
-          raise TypeError('Key() cannot accept flat as a keyword argument.')
+          raise TypeError('Key() with positional arguments '
+                          'cannot accept flat as a keyword argument.')
         kwargs['flat'] = _args
     self = super(Key, cls).__new__(cls)
     # Either __reference or (__pairs, __app, __namespace) must be set.
@@ -554,6 +555,7 @@
 
 
 # The remaining functions in this module are private.
+# TODO: Conform to PEP 8 naming, e.g. _construct_reference() etc.
 
 @utils.positional(1)
 def _ConstructReference(cls, pairs=None, flat=None,
diff --git a/google/appengine/ext/ndb/metadata.py b/google/appengine/ext/ndb/metadata.py
index 6c841c6..1b6d452 100644
--- a/google/appengine/ext/ndb/metadata.py
+++ b/google/appengine/ext/ndb/metadata.py
@@ -20,6 +20,11 @@
 
 from . import model
 
+__all__ = ['Namespace', 'Kind', 'Property',
+           'get_namespaces', 'get_kinds',
+           'get_properties_of_kind', 'get_representations_of_kind',
+           ]
+
 
 class _BaseMetadata(model.Model):
   """Base class for all metadata models."""
diff --git a/google/appengine/ext/ndb/model.py b/google/appengine/ext/ndb/model.py
index 6b01a40..745e84d 100644
--- a/google/appengine/ext/ndb/model.py
+++ b/google/appengine/ext/ndb/model.py
@@ -285,12 +285,12 @@
 import datetime
 import zlib
 
-from google.appengine.api import datastore_errors
-from google.appengine.api import datastore_types
-from google.appengine.api import users
-from google.appengine.datastore import datastore_query
-from google.appengine.datastore import datastore_rpc
-from google.appengine.datastore import entity_pb
+from .google_imports import datastore_errors
+from .google_imports import datastore_types
+from .google_imports import users
+from .google_imports import datastore_query
+from .google_imports import datastore_rpc
+from .google_imports import entity_pb
 
 from . import utils
 
@@ -300,14 +300,17 @@
 _MAX_LONG = key_module._MAX_LONG
 
 # NOTE: Property and Error classes are added later.
-__all__ = ['Key', 'ModelAdapter', 'ModelAttribute',
+__all__ = ['Key', 'BlobKey', 'GeoPt', 'Rollback',
+           'Index', 'IndexState', 'IndexProperty',
+           'ModelAdapter', 'ModelAttribute',
            'ModelKey', 'MetaModel', 'Model', 'Expando',
-           'BlobKey', 'GeoPt', 'Rollback',
            'transaction', 'transaction_async',
            'in_transaction', 'transactional',
            'get_multi', 'get_multi_async',
            'put_multi', 'put_multi_async',
            'delete_multi', 'delete_multi_async',
+           'get_indexes', 'get_indexes_async',
+           'make_connection',
            ]
 
 
@@ -328,6 +331,166 @@
   """Raised when attempting to assign a value to a computed property."""
 
 
+# Map index directions to human-readable strings.
+_DIR_MAP = {
+  entity_pb.Index_Property.ASCENDING: 'asc',
+  entity_pb.Index_Property.DESCENDING: 'desc',
+  }
+
+# Map index states to human-readable strings.
+_STATE_MAP = {
+  entity_pb.CompositeIndex.ERROR: 'error',
+  entity_pb.CompositeIndex.DELETED: 'deleting',
+  entity_pb.CompositeIndex.READ_WRITE: 'serving',
+  entity_pb.CompositeIndex.WRITE_ONLY: 'building',
+  }
+
+
+class _NotEqualMixin(object):
+  """Mix-in class that implements __ne__ in terms of __eq__."""
+
+  def __ne__(self, other):
+    """Implement self != other as not(self == other)."""
+    eq = self.__eq__(other)
+    if eq is NotImplemented:
+      return NotImplemented
+    return not eq
+
+
+class IndexProperty(_NotEqualMixin):
+  """Immutable object representing a single property in an index."""
+
+  @utils.positional(1)
+  def __new__(cls, name, direction):
+    """Constructor."""
+    obj = object.__new__(cls)
+    obj.__name = name
+    obj.__direction = direction
+    return obj
+
+  @property
+  def name(self):
+    """The property name being indexed, a string."""
+    return self.__name
+
+  @property
+  def direction(self):
+    """The direction in the index for this property, 'asc' or 'desc'."""
+    return self.__direction
+
+  def __repr__(self):
+    """Return a string representation."""
+    return '%s(name=%r, direction=%r)' % (self.__class__.__name__,
+                                          self.name,
+                                          self.direction)
+
+  def __eq__(self, other):
+    """Compare two index properties for equality."""
+    if not isinstance(other, IndexProperty):
+      return NotImplemented
+    return self.name == other.name and self.direction == other.direction
+
+  def __hash__(self):
+    return hash((self.name, self.direction))
+
+
+class Index(_NotEqualMixin):
+  """Immutable object representing an index."""
+
+  @utils.positional(1)
+  def __new__(cls, kind, properties, ancestor):
+    """Constructor."""
+    obj = object.__new__(cls)
+    obj.__kind = kind
+    obj.__properties = properties
+    obj.__ancestor = ancestor
+    return obj
+
+  @property
+  def kind(self):
+    """The kind being indexed, a string."""
+    return self.__kind
+
+  @property
+  def properties(self):
+    """A list of PropertyIndex objects giving the properties being indexed."""
+    return self.__properties
+
+  @property
+  def ancestor(self):
+    """Whether this is an ancestor index, a bool."""
+    return self.__ancestor
+
+  def __repr__(self):
+    """Return a string representation."""
+    parts = []
+    parts.append('kind=%r' % self.kind)
+    parts.append('properties=%r' % self.properties)
+    parts.append('ancestor=%s' % self.ancestor)
+    return '%s(%s)' % (self.__class__.__name__, ', '.join(parts))
+
+  def __eq__(self, other):
+    """Compare two indexes."""
+    if not isinstance(other, Index):
+      return NotImplemented
+    return (self.kind == other.kind and
+            self.properties == other.properties and
+            self.ancestor == other.ancestor)
+
+  def __hash__(self):
+    return hash((self.kind, self.properties, self.ancestor))
+
+
+class IndexState(_NotEqualMixin):
+  """Immutable object representing and index and its state."""
+
+  @utils.positional(1)
+  def __new__(cls, definition, state, id):
+    """Constructor."""
+    obj = object.__new__(cls)
+    obj.__definition = definition
+    obj.__state = state
+    obj.__id = id
+    return obj
+
+  @property
+  def definition(self):
+    """An Index object describing the index."""
+    return self.__definition
+
+  @property
+  def state(self):
+    """The index state, a string.
+
+    Possible values are 'error', 'deleting', 'serving' or 'building'.
+    """
+    return self.__state
+
+  @property
+  def id(self):
+    """The index ID, an integer."""
+    return self.__id
+
+  def __repr__(self):
+    """Return a string representation."""
+    parts = []
+    parts.append('definition=%r' % self.definition)
+    parts.append('state=%r' % self.state)
+    parts.append('id=%d' % self.id)
+    return '%s(%s)' % (self.__class__.__name__, ', '.join(parts))
+
+  def __eq__(self, other):
+    """Compare two index states."""
+    if not isinstance(other, IndexState):
+      return NotImplemented
+    return (self.definition == other.definition and
+            self.state == other.state and
+            self.id == other.id)
+
+  def __hash__(self):
+    return hash((self.definition, self.state, self.id))
+
+
 class ModelAdapter(datastore_rpc.AbstractAdapter):
   """Conversions between 'our' Key and Model classes and protobufs.
 
@@ -371,7 +534,9 @@
       kind = key.kind()
     modelclass = Model._kind_map.get(kind, self.default_model)
     if modelclass is None:
-      raise KindError("No implementation found for kind '%s'" % kind)
+      raise KindError(
+        "No model class found for kind '%s'. Did you forget to import it?" %
+        kind)
     entity = modelclass._from_pb(pb, key=key, set_key=False)
     if self.want_pbs:
       entity._orig_pb = pb
@@ -381,6 +546,21 @@
     pb = ent._to_pb()
     return pb
 
+  def pb_to_index(self, pb):
+    index_def = pb.definition()
+    properties = [IndexProperty(name=prop.name(),
+                                direction=_DIR_MAP[prop.direction()])
+                  for prop in index_def.property_list()]
+    index = Index(kind=index_def.entity_type(),
+                  properties=properties,
+                  ancestor=bool(index_def.ancestor()),
+                  )
+    index_state = IndexState(definition=index,
+                             state=_STATE_MAP[pb.state()],
+                             id=pb.id(),
+                             )
+    return index_state
+
 
 def make_connection(config=None, default_model=None):
   """Create a new Connection object with the right adapter.
@@ -399,7 +579,7 @@
     pass
 
 
-class _BaseValue(object):
+class _BaseValue(_NotEqualMixin):
   """A marker object wrapping a 'base type' value.
 
   This is used to be able to tell whether ent._values[name] is a
@@ -425,10 +605,8 @@
       return NotImplemented
     return self.b_val == other.b_val
 
-  def __ne__(self, other):
-    if not isinstance(other, _BaseValue):
-      return NotImplemented
-    return self.b_val != other.b_val
+  def __hash__(self):
+    raise TypeError('_BaseValue is not immutable')
 
 
 class Property(ModelAttribute):
@@ -556,7 +734,7 @@
                  '_choices', '_validator', '_verbose_name']
   _positional = 1  # Only name is a positional argument.
 
-  @utils.positional(1 + _positional)
+  @utils.positional(1 + _positional)  # Add 1 for self.
   def __init__(self, name=None, indexed=None, repeated=None,
                required=None, default=None, choices=None, validator=None,
                verbose_name=None):
@@ -564,8 +742,10 @@
     if name is not None:
       if isinstance(name, unicode):
         name = name.encode('utf-8')
+      if not isinstance(name, str):
+        raise TypeError('Name %r is not a string' % (name,))
       if '.' in name:
-        raise ValueError('name cannot contain period characters' % name)
+        raise ValueError('Name %r cannot contain period characters' % (name,))
       self._name = name
     if indexed is not None:
       self._indexed = indexed
@@ -637,6 +817,7 @@
     Returns:
       A FilterNode instance representing the requested comparison.
     """
+    # NOTE: This is also used by query.gql().
     if not self._indexed:
       raise datastore_errors.BadFilterError(
         'Cannot query for unindexed property %s' % self._name)
@@ -1227,7 +1408,7 @@
 _MEANING_URI_COMPRESSED = 'ZLIB'
 
 
-class _CompressedValue(object):
+class _CompressedValue(_NotEqualMixin):
   """A marker object wrapping compressed values."""
 
   __slots__ = ['z_val']
@@ -1245,10 +1426,8 @@
       return NotImplemented
     return self.z_val == other.z_val
 
-  def __ne__(self, other):
-    if not isinstance(other, _CompressedValue):
-      return NotImplemented
-    return self.z_val != other.z_val
+  def __hash__(self):
+    raise TypeError('_CompressedValue is not immutable')
 
 
 class BlobProperty(Property):
@@ -1484,10 +1663,40 @@
 
   _kind = None
 
-  @utils.positional(1 + Property._positional)
+  @utils.positional(2 + Property._positional)
   def __init__(self, *args, **kwds):
-    kind = kwds.pop('kind', None)
-    super(KeyProperty, self).__init__(*args, **kwds)
+    # Support several positional signatures:
+    # ()  =>  name=None, kind from kwds
+    # (None)  =>  name=None, kind from kwds
+    # (name)  =>  name=arg 0, kind from kwds
+    # (kind)  =>  name=None, kind=arg 0
+    # (name, kind)  => name=arg 0, kind=arg 1
+    # (kind, name)  => name=arg 1, kind=arg 0
+    # The positional kind must be a Model subclass; it cannot be a string.
+    name = kind = None
+
+    for arg in args:
+      if isinstance(arg, basestring):
+        if name is not None:
+          raise TypeError('You can only specify one name')
+        name = arg
+      elif isinstance(arg, type) and issubclass(arg, Model):
+        if kind is not None:
+          raise TypeError('You can only specify one kind')
+        kind = arg
+      elif arg is not None:
+        raise TypeError('Unexpected positional argument: %r' % (arg,))
+
+    if name is None:
+      name = kwds.pop('name', None)
+    elif 'name' in kwds:
+      raise TypeError('You can only specify name once')
+
+    if kind is None:
+      kind = kwds.pop('kind', None)
+    elif 'kind' in kwds:
+      raise TypeError('You can only specify kind once')
+
     if kind is not None:
       if isinstance(kind, type) and issubclass(kind, Model):
         kind = kind._get_kind()
@@ -1495,6 +1704,9 @@
         kind = kind.encode('utf-8')
       if not isinstance(kind, str):
         raise TypeError('kind must be a Model class or a string')
+
+    super(KeyProperty, self).__init__(name, **kwds)
+
     self._kind = kind
 
   def _datastore_type(self, value):
@@ -1702,7 +1914,7 @@
     return datetime.datetime.now().time()
 
 
-class StructuredGetForDictMixin(Property):
+class _StructuredGetForDictMixin(Property):
   """Mixin class so *StructuredProperty can share _get_for_dict().
 
   The behavior here is that sub-entities are converted to dictionaries
@@ -1719,7 +1931,7 @@
     return value
 
 
-class StructuredProperty(StructuredGetForDictMixin):
+class StructuredProperty(_StructuredGetForDictMixin):
   """A Property whose value is itself an entity.
 
   The values of the sub-entity are indexed and can be queried.
@@ -1775,7 +1987,10 @@
     # Import late to avoid circular imports.
     from .query import ConjunctionNode, PostFilterNode
     from .query import RepeatedStructuredPropertyPredicate
-    value = self._do_validate(value)  # None is not allowed!
+    if value is None:
+      from .query import FilterNode  # Import late to avoid circular imports.
+      return FilterNode(self._name, op, value)
+    value = self._do_validate(value)
     value = self._call_to_base_type(value)
     filters = []
     match_keys = []
@@ -1861,7 +2076,7 @@
         for unused_name, prop in sorted(value._properties.iteritems()):
           prop._serialize(value, pb, prefix + self._name + '.',
                           self._repeated or parent_repeated)
-      elif parent_repeated:
+      else:
         # Serialize a single None
         super(StructuredProperty, self)._serialize(
           entity, pb, prefix=prefix, parent_repeated=parent_repeated)
@@ -1930,7 +2145,7 @@
         value._prepare_for_put()
 
 
-class LocalStructuredProperty(StructuredGetForDictMixin, BlobProperty):
+class LocalStructuredProperty(_StructuredGetForDictMixin, BlobProperty):
   """Substructure that is serialized to an opaque blob.
 
   This looks like StructuredProperty on the Python side, but is
@@ -2166,7 +2381,7 @@
     return '%s<%s>' % (cls.__name__, ', '.join(props))
 
 
-class Model(object):
+class Model(_NotEqualMixin):
   """A class describing datastore entities.
 
   Model instances are usually called entities.  All model classes
@@ -2229,6 +2444,8 @@
     through the constructor, but can be assigned to entity attributes
     after the entity has been created.
     """
+    # TODO: Use the same signature hacks as in get_or_insert() to
+    # fully support properties named id, parent or key?
     if key is not None:
       if id is not None:
         raise datastore_errors.BadArgumentError(
@@ -2382,13 +2599,6 @@
         return False
     return True
 
-  def __ne__(self, other):
-    """Implement self != other as not(self == other)."""
-    eq = self.__eq__(other)
-    if eq is NotImplemented:
-      return NotImplemented
-    return not eq
-
   def _to_pb(self, pb=None, allow_partial=False, set_key=True):
     """Internal helper to turn an entity into an EntityProto protobuf."""
     if not allow_partial:
@@ -2581,6 +2791,7 @@
     Returns:
       A Query object.
     """
+    # TODO: Disallow non-empty args and filter=.
     from .query import Query  # Import late to avoid circular imports.
     qry = Query(kind=cls._get_kind(), **kwds)
     if args:
@@ -2588,6 +2799,14 @@
     return qry
   query = _query
 
+  @classmethod
+  def _gql(cls, query_string, *args, **kwds):
+    """Run a GQL query."""
+    from .query import gql  # Import late to avoid circular imports.
+    return gql('SELECT * FROM %s %s' % (cls._get_kind(), query_string),
+               *args, **kwds)
+  gql = _gql
+
   def _put(self, **ctx_options):
     """Write this entity to the datastore.
 
@@ -2680,7 +2899,7 @@
         def txn():
           ent = yield key.get_async(options=context_options)
           if ent is None:
-            ent = cls(**kwds)  # TODO: Check for forbidden keys
+            ent = cls(**kwds)  # TODO: Use _populate().
             ent._key = key
             yield ent.put_async(options=context_options)
           raise tasklets.Return(ent)
@@ -2922,22 +3141,39 @@
 
 
 @utils.positional(1)
-def transactional(func):
+def transactional(func=None, **ctx_options):
   """Decorator to make a function automatically run in a transaction.
 
   If we're already in a transaction this is a no-op.
 
-  Note: If you need to override the retry count, or want some kind of
-  async behavior, or pass Context options, use the transaction()
-  function above.
+  This supports two forms:
+
+  (1) Vanilla:
+      @transactional
+      def callback(arg):
+        ...
+
+  (2) With options:
+      @transactional(retries=1)
+      def callback(arg):
+        ...
   """
-  @utils.wrapping(func)
-  def transactional_wrapper(*args, **kwds):
-    if in_transaction():
-      return func(*args, **kwds)
-    else:
-      return transaction(lambda: func(*args, **kwds))
-  return transactional_wrapper
+  if func is not None:
+    # Form (1), vanilla.
+    if ctx_options:
+      raise TypeError('@transactional() does not take positional arguments')
+    return transactional()(func)
+
+  # Form (2), with options.
+  def outer_transactional_wrapper(func):
+    @utils.wrapping(func)
+    def transactional_wrapper(*args, **kwds):
+      if in_transaction():
+        return func(*args, **kwds)
+      else:
+        return transaction(lambda: func(*args, **kwds), **ctx_options)
+    return transactional_wrapper
+  return outer_transactional_wrapper
 
 
 def get_multi_async(keys, **ctx_options):
@@ -3022,6 +3258,32 @@
           for future in delete_multi_async(keys, **ctx_options)]
 
 
+def get_indexes_async(**ctx_options):
+  """Get a data structure representing the configured indexes.
+
+  Args:
+    **ctx_options: Context options.
+
+  Returns:
+    A future.
+  """
+  from . import tasklets
+  ctx = tasklets.get_context()
+  return ctx.get_indexes(**ctx_options)
+
+
+def get_indexes(**ctx_options):
+  """Get a data structure representing the configured indexes.
+
+  Args:
+    **ctx_options: Context options.
+
+  Returns:
+    A list of Index objects.
+  """
+  return get_indexes_async(**ctx_options).get_result()
+
+
 # Update __all__ to contain all Property and Exception subclasses.
 for _name, _object in globals().items():
   if ((_name.endswith('Property') and issubclass(_object, Property)) or
diff --git a/google/appengine/ext/ndb/prospective_search.py b/google/appengine/ext/ndb/prospective_search.py
index 8a0a234..e93859c 100644
--- a/google/appengine/ext/ndb/prospective_search.py
+++ b/google/appengine/ext/ndb/prospective_search.py
@@ -17,11 +17,11 @@
 
 import base64
 
-from google.appengine.api import datastore
-from google.appengine.api import datastore_types
-from google.appengine.api import prospective_search
-from google.appengine.api.prospective_search import prospective_search_pb
-from google.appengine.datastore import entity_pb
+from .google_imports import datastore
+from .google_imports import datastore_types
+from .google_imports import prospective_search
+from .google_imports import prospective_search_pb
+from .google_imports import entity_pb
 
 from . import model
 from . import tasklets
diff --git a/google/appengine/ext/ndb/query.py b/google/appengine/ext/ndb/query.py
index 4406097..a62d5f0 100644
--- a/google/appengine/ext/ndb/query.py
+++ b/google/appengine/ext/ndb/query.py
@@ -123,24 +123,30 @@
 """
 
 from __future__ import with_statement
+del with_statement  # No need to export this.
 
 __author__ = 'guido@google.com (Guido van Rossum)'
 
+import datetime
 import heapq
 import itertools
 import sys
 
-from google.appengine.api import datastore_errors
-from google.appengine.api import datastore_types
-from google.appengine.datastore import datastore_query
-from google.appengine.ext import gql
+from .google_imports import datastore_errors
+from .google_imports import datastore_types
+from .google_imports import datastore_query
 
 from . import model
 from . import tasklets
 from . import utils
 
-__all__ = ['Binding', 'AND', 'OR', 'parse_gql', 'Query',
-           'QueryOptions', 'Cursor']
+__all__ = ['Query', 'QueryOptions', 'Cursor', 'QueryIterator',
+           'RepeatedStructuredPropertyPredicate',
+           'AND', 'OR', 'ConjunctionNode', 'DisjunctionNode',
+           'FilterNode', 'PostFilterNode', 'FalseNode', 'Node',
+           'ParameterNode', 'ParameterizedThing', 'Parameter',
+           'ParameterizedFunction', 'gql',
+           ]
 
 # Re-export some useful classes from the lower-level module.
 QueryOptions = datastore_query.QueryOptions
@@ -159,27 +165,8 @@
 _MAX_LIMIT = 2 ** 31 - 1
 
 
-# TODO: Once CL/21689469 is submitted, get rid of this and its callers.
-def _make_unsorted_key_value_map(pb, property_names):
-  """Like _make_key_value_map() but doesn't sort the values."""
-  value_map = dict((name, []) for name in property_names)
-
-  # Building comparable values from pb properties.
-  # NOTE: Unindexed properties are skipped.
-  for prop in pb.property_list():
-    prop_name = prop.name()
-    if prop_name in value_map:
-      value_map[prop_name].append(
-        datastore_types.PropertyValueToKeyValue(prop.value()))
-
-  # Adding special key property (if requested).
-  if _KEY in value_map:
-    value_map[_KEY] = [datastore_types.ReferenceToKeyValue(pb.key())]
-
-  return value_map
-
-
 class RepeatedStructuredPropertyPredicate(datastore_query.FilterPredicate):
+  # Used by model.py.
 
   def __init__(self, match_keys, pb, key_prefix):
     super(RepeatedStructuredPropertyPredicate, self).__init__()
@@ -190,15 +177,12 @@
         raise ValueError('key %r does not begin with the specified prefix of %s'
                          % (key, key_prefix))
       stripped_keys.append(key[len(key_prefix):])
-    value_map = _make_unsorted_key_value_map(pb, stripped_keys)
+    value_map = datastore_query._make_key_value_map(pb, stripped_keys)
     self.match_values = tuple(value_map[key][0] for key in stripped_keys)
 
   def _get_prop_names(self):
     return frozenset(self.match_keys)
 
-  def __call__(self, pb):
-    return self._apply(_make_unsorted_key_value_map(pb, self.match_keys))
-
   def _apply(self, key_value_map):
     """Apply the filter to values extracted from an entity.
 
@@ -254,44 +238,127 @@
   # within columns.
 
 
-class CompositePostFilter(datastore_query.CompositeFilter):
+class ParameterizedThing(object):
+  """Base class for Parameter and ParameterizedFunction.
 
-  def __call__(self, pb):
-    key_value_map = _make_unsorted_key_value_map(pb, self._get_prop_names())
-    return self._apply(key_value_map)
-
-
-class Binding(object):
-  """Used with GQL; for now unsupported."""
-
-  def __init__(self, value=None, key=None):
-    """Constructor.  The value may be changed later."""
-    self.value = value
-    self.key = key
-
-  def __repr__(self):
-    return '%s(%r, %r)' % (self.__class__.__name__, self.value, self.key)
+  This exists purely for isinstance() checks.
+  """
 
   def __eq__(self, other):
-    # TODO: When comparing tree nodes containing Bindings, Bindings
-    # should be compared by object identity?
-    if not isinstance(other, Binding):
-      return NotImplemented
-    return self.value == other.value and self.key == other.key
+    raise NotImplementedError
 
-  def resolve(self):
-    """Return the value currently associated with this Binding."""
-    value = self.value
-    if isinstance(value, Binding):
-      raise RuntimeError('Recursive Binding.')
+  def __ne__(self, other):
+    eq = self.__eq__(other)
+    if eq is not NotImplemented:
+      eq = not eq
+    return eq
+
+class Parameter(ParameterizedThing):
+  """Represents a bound variable in a GQL query.
+
+  Parameter(1) corresponds to a slot labeled ":1" in a GQL query.
+  Parameter('xyz') corresponds to a slot labeled ":xyz".
+
+  The value must be set (bound) separately by calling .set(value).
+  """
+
+  def __init__(self, key):
+    """Constructor.
+
+    Args:
+      key: The Parameter key, must be either an integer or a string.
+    """
+    if not isinstance(key, (int, long, basestring)):
+      raise TypeError('Parameter key must be an integer or string, not %s' %
+                      (key,))
+    self.__key = key
+
+  def __repr__(self):
+    return '%s(%r)' % (self.__class__.__name__, self.__key)
+
+  def __eq__(self, other):
+    if not isinstance(other, Parameter):
+      return NotImplemented
+    return self.__key == other.__key
+
+  @property
+  def key(self):
+    """Retrieve the key."""
+    return self.__key
+
+  def resolve(self, bindings, used):
+    key = self.__key
+    if key not in bindings:
+      raise datastore_errors.BadArgumentError(
+        'Parameter :%s is not bound.' % key)
+    value = bindings[key]
+    used[key] = True
     return value
 
 
+class ParameterizedFunction(ParameterizedThing):
+  """Represents a GQL function with parameterized arguments.
+
+  For example, ParameterizedFunction('key', [Parameter(1)]) stands for
+  the GQL syntax KEY(:1).
+  """
+
+  def __init__(self, func, values):
+    from .google_imports import gql  # Late import, to avoid name conflict.
+    self.__func = func
+    self.__values = values
+    # NOTE: A horrible hack using GQL private variables so we can
+    # reuse GQL's implementations of its built-in functions.
+    gqli = gql.GQL('SELECT * FROM Dummy')
+    gql_method = gqli._GQL__cast_operators[func]
+    self.__method = getattr(gqli, '_GQL' + gql_method.__name__)
+
+  def __repr__(self):
+    return 'ParameterizedFunction(%r, %r)' % (self.__func, self.__values)
+
+  def __eq__(self, other):
+    if not isinstance(other, ParameterizedFunction):
+      return NotImplemented
+    return (self.__func == other.__func and
+            self.__values == other.__values)
+
+  @property
+  def func(self):
+    return self.__func
+
+  @property
+  def values(self):
+    return self.__values
+
+  def is_parameterized(self):
+    for val in self.__values:
+      if isinstance(val, Parameter):
+        return True
+    return False
+
+  def resolve(self, bindings, used):
+    values = []
+    for val in self.__values:
+      if isinstance(val, Parameter):
+        val = val.resolve(bindings, used)
+      values.append(val)
+    result = self.__method(values)
+    # The gql module returns slightly different types in some cases.
+    if self.__func == 'key' and isinstance(result, datastore_types.Key):
+      result = model.Key.from_old_key(result)
+    elif self.__func == 'time' and isinstance(result, datetime.datetime):
+      result = datetime.time(result.hour, result.minute,
+                             result.second, result.microsecond)
+    elif self.__func == 'date' and isinstance(result, datetime.datetime):
+      result = datetime.date(result.year, result.month, result.day)
+    return result
+
+
 class Node(object):
   """Base class for filter expression tree nodes.
 
   Tree nodes are considered immutable, even though they can contain
-  Binding instances, which are not.  In particular, two identical
+  Parameter instances, which are not.  In particular, two identical
   trees may be represented by the same Node object in different
   contexts.
   """
@@ -314,7 +381,7 @@
     raise TypeError('Nodes cannot be ordered')
   __le__ = __lt__ = __ge__ = __gt__ = __unordered
 
-  def _to_filter(self, bindings, post=False):
+  def _to_filter(self, post=False):
     """Helper to convert to datastore_query.Filter, or None."""
     raise NotImplementedError
 
@@ -322,23 +389,28 @@
     """Helper to extract post-filter Nodes, if any."""
     return None
 
-  def resolve(self):
-    """Extract the Binding's value if necessary."""
-    raise NotImplementedError
+  def resolve(self, bindings, used):
+    """Return a Node with Parameters replaced by the selected values.
+
+    Args:
+      bindings: A dict mapping integers and strings to values.
+      used: A dict into which use of use of a binding is recorded.
+
+    Returns:
+      A Node instance.
+    """
+    return self
 
 
 class FalseNode(Node):
   """Tree node for an always-failing filter."""
 
-  def __new__(cls):
-    return super(Node, cls).__new__(cls)
-
   def __eq__(self, other):
     if not isinstance(other, FalseNode):
       return NotImplemented
     return True
 
-  def _to_filter(self, unused_bindings, post=False):
+  def _to_filter(self, post=False):
     if post:
       return None
     # Because there's no point submitting a query that will never
@@ -346,8 +418,43 @@
     raise datastore_errors.BadQueryError(
       'Cannot convert FalseNode to predicate')
 
-  def resolve(self):
-    return self
+
+class ParameterNode(Node):
+  """Tree node for a parameterized filter."""
+
+  def __new__(cls, prop, op, param):
+    if not isinstance(prop, model.Property):
+      raise TypeError('Expected a Property, got %r' % (prop,))
+    if op not in _OPS:
+      raise TypeError('Expected a valid operator, got %r' % (op,))
+    if not isinstance(param, ParameterizedThing):
+      raise TypeError('Expected a ParameterizedThing, got %r' % (param,))
+    obj = super(ParameterNode, cls).__new__(cls)
+    obj.__prop = prop
+    obj.__op = op
+    obj.__param = param
+    return obj
+
+  def __repr__(self):
+    return 'ParameterNode(%r, %r, %r)' % (self.__prop, self.__op, self.__param)
+
+  def __eq__(self, other):
+    if not isinstance(other, ParameterNode):
+      return NotImplemented
+    return (self.__prop._name == other.__prop._name and
+            self.__op == other.__op and
+            self.__param == other.__param)
+
+  def _to_filter(self, post=False):
+    raise datastore_errors.BadArgumentError(
+      'Parameter :%s is not bound.' % (self.__param.key,))
+
+  def resolve(self, bindings, used):
+    value = self.__param.resolve(bindings, used)
+    if self.__op == 'in':
+      return self.__prop._IN(value)
+    else:
+      return self.__prop._comparison(self.__op, value)
 
 
 class FilterNode(Node):
@@ -360,7 +467,7 @@
       n1 = FilterNode(name, '<', value)
       n2 = FilterNode(name, '>', value)
       return DisjunctionNode(n1, n2)
-    if opsymbol == 'in' and not isinstance(value, Binding):
+    if opsymbol == 'in':
       if not isinstance(value, (list, tuple, set, frozenset)):
         raise TypeError('in expected a list, tuple or set of values; '
                         'received %r' % value)
@@ -376,9 +483,6 @@
     self.__value = value
     return self
 
-  def _sort_key(self):
-    return self.__name, self.__opsymbol, self.__value
-
   def __repr__(self):
     return '%s(%r, %r, %r)' % (self.__class__.__name__,
                                self.__name, self.__opsymbol, self.__value)
@@ -393,7 +497,7 @@
             self.__opsymbol == other.__opsymbol and
             self.__value == other.__value)
 
-  def _to_filter(self, bindings, post=False):
+  def _to_filter(self, post=False):
     if post:
       return None
     if self.__opsymbol in ('!=', 'in'):
@@ -401,21 +505,9 @@
                                 'expressions and therefore cannot be converted '
                                 'to a single filter (%r)' % self.__opsymbol)
     value = self.__value
-    if isinstance(value, Binding):
-      bindings[value.key] = value
-      value = value.resolve()
-      # TODO: validate the resolved value.
     return datastore_query.make_filter(self.__name.decode('utf-8'),
                                        self.__opsymbol, value)
 
-  def resolve(self):
-    if self.__opsymbol == 'in':
-      if isinstance(self.__value, Binding):
-        raise RuntimeError('Unexpanded non-Binding IN.')
-      return FilterNode(self.__name, self.__opsymbol, self.__value.resolve())
-    else:
-      return self
-
 
 class PostFilterNode(Node):
   """Tree node representing an in-memory filtering operation.
@@ -437,15 +529,12 @@
       return NotImplemented
     return self is other
 
-  def _to_filter(self, unused_bindings, post=False):
+  def _to_filter(self, post=False):
     if post:
       return self.predicate
     else:
       return None
 
-  def resolve(self):
-    return self
-
 
 class ConjunctionNode(Node):
   """Tree node representing a Boolean AND operator on two or more nodes."""
@@ -498,17 +587,15 @@
       return NotImplemented
     return self.__nodes == other.__nodes
 
-  def _to_filter(self, bindings, post=False):
+  def _to_filter(self, post=False):
     filters = filter(None,
-                     (node._to_filter(bindings, post=post)
+                     (node._to_filter(post=post)
                       for node in self.__nodes
                       if isinstance(node, PostFilterNode) == post))
     if not filters:
       return None
     if len(filters) == 1:
       return filters[0]
-    if post:
-      return CompositePostFilter(_AND, filters)
     return datastore_query.CompositeFilter(_AND, filters)
 
   def _post_filters(self):
@@ -522,8 +609,8 @@
       return self
     return ConjunctionNode(*post_filters)
 
-  def resolve(self):
-    nodes = [node.resolve() for node in self.__nodes]
+  def resolve(self, bindings, used):
+    nodes = [node.resolve(bindings, used) for node in self.__nodes]
     if nodes == self.__nodes:
       return self
     return ConjunctionNode(*nodes)
@@ -561,8 +648,8 @@
       return NotImplemented
     return self.__nodes == other.__nodes
 
-  def resolve(self):
-    nodes = [node.resolve() for node in self.__nodes]
+  def resolve(self, bindings, used):
+    nodes = [node.resolve(bindings, used) for node in self.__nodes]
     if nodes == self.__nodes:
       return self
     return DisjunctionNode(*nodes)
@@ -573,16 +660,22 @@
 OR = DisjunctionNode
 
 
-def _args_to_val(func, args, bindings):
-  """Helper for GQL parsing."""
+def _args_to_val(func, args):
+  """Helper for GQL parsing to extract values from GQL expressions.
+
+  This can extract the value from a GQL literal, return a Parameter
+  for a GQL bound parameter (:1 or :foo), and interprets casts like
+  KEY(...) and plain lists of values like (1, 2, 3).
+
+  Args:
+    func: A string indicating what kind of thing this is.
+    args: One or more GQL values, each integer, string, or GQL literal.
+  """
+  from .google_imports import gql  # Late import, to avoid name conflict.
   vals = []
   for arg in args:
     if isinstance(arg, (int, long, basestring)):
-      if arg in bindings:
-        val = bindings[arg]
-      else:
-        val = Binding(None, arg)
-        bindings[arg] = val
+      val = Parameter(arg)
     elif isinstance(arg, gql.Literal):
       val = arg.Get()
     else:
@@ -591,67 +684,65 @@
   if func == 'nop':
     if len(vals) != 1:
       raise TypeError('"nop" requires exactly one value')
-    return vals[0]
-  if func == 'list':
-    return vals
-  if func == 'key':
-    if len(vals) == 1 and isinstance(vals[0], basestring):
-      return model.Key(urlsafe=vals[0])
-    raise TypeError('Unexpected key args (%r)' % vals)
-  raise ValueError('Unexpected func (%r)' % func)
+    return vals[0]  # May be a Parameter
+  pfunc = ParameterizedFunction(func, vals)
+  if pfunc.is_parameterized():
+    return pfunc
+  else:
+    return pfunc.resolve({}, {})
 
 
-# TODO: Not everybody likes GQL.
-
-# TODO: GQL doesn't support querying for structured property values.
-
-def parse_gql(query_string):
-  """Parse a GQL query string.
+def _get_prop_from_modelclass(modelclass, name):
+  """Helper for FQL parsing to turn a property name into a property object.
 
   Args:
-    query_string: Full GQL query, e.g. 'SELECT * FROM Kind WHERE prop = 1'.
+    modelclass: The model class specified in the query.
+    name: The property name.  This may contain dots which indicate
+      sub-properties of structured properties.
 
   Returns:
-    A tuple (query, options, bindings) where query is a Query instance,
-    options a datastore_query.QueryOptions instance, and bindings a dict
-    mapping integers and strings to Binding instances.
+    A Property object.
+
+  Raises:
+    KeyError if the property doesn't exist and the model clas doesn't
+    derive from Expando.
   """
-  gql_qry = gql.GQL(query_string)
-  ancestor = None
-  flt = gql_qry.filters()
-  bindings = {}
-  filters = []
-  for ((name, op), values) in flt.iteritems():
-    op = op.lower()
-    if op == 'is' and name == gql.GQL._GQL__ANCESTOR:
-      if len(values) != 1:
-        raise ValueError('"is" requires exactly one value')
-      [(func, args)] = values
-      ancestor = _args_to_val(func, args, bindings)
-      continue
-    if op not in _OPS:
-      raise NotImplementedError('Operation %r is not supported.' % op)
-    for (func, args) in values:
-      val = _args_to_val(func, args, bindings)
-      filters.append(FilterNode(name, op, val))
-  if filters:
-    filters.sort(key=lambda x: x._sort_key())  # For predictable tests.
-    filters = ConjunctionNode(*filters)
-  else:
-    filters = None
-  orders = _orderings_to_orders(gql_qry.orderings())
-  qry = Query(kind=gql_qry._kind,
-              ancestor=ancestor,
-              filters=filters,
-              orders=orders)
-  offset = gql_qry.offset()
-  if offset < 0:
-    offset = None
-  limit = gql_qry.limit()
-  if limit < 0:
-    limit = None
-  options = QueryOptions(offset=offset, limit=limit)
-  return qry, options, bindings
+  if name == '__key__':
+    return modelclass._key
+
+  parts = name.split('.')
+  part, more = parts[0], parts[1:]
+  prop = modelclass._properties.get(part)
+  if prop is None:
+    if issubclass(modelclass, model.Expando):
+      prop = model.GenericProperty(part)
+    else:
+      raise TypeError('Model %s has no property named %r' %
+                      (modelclass._get_kind(), part))
+
+  while more:
+    part = more.pop(0)
+    if not isinstance(prop, model.StructuredProperty):
+      raise TypeError('Model %s has no property named %r' %
+                      (modelclass._get_kind(), part))
+    maybe = getattr(prop, part, None)
+    if isinstance(maybe, model.Property) and maybe._name == part:
+      prop = maybe
+    else:
+      maybe = prop._modelclass._properties.get(part)
+      if maybe is not None:
+        # Must get it this way to get the copy with the long name.
+        # (See StructuredProperty.__getattr__() for details.)
+        prop = getattr(prop, maybe._code_name)
+      else:
+        if issubclass(prop._modelclass, model.Expando) and not more:
+          prop = model.GenericProperty()
+          prop._name = name  # Bypass the restriction on dots.
+        else:
+          raise KeyError('Model %s has no property named %r' %
+                         (prop._modelclass._get_kind(), part))
+
+  return prop
 
 
 class Query(object):
@@ -668,7 +759,7 @@
 
   @utils.positional(1)
   def __init__(self, kind=None, ancestor=None, filters=None, orders=None,
-               app=None, namespace=None):
+               app=None, namespace=None, default_options=None):
     """Constructor.
 
     Args:
@@ -678,18 +769,24 @@
       orders: Optional datastore_query.Order object.
       app: Optional app id.
       namespace: Optional namespace.
+      default_options: Optional QueryOptions object.
     """
-    if ancestor is not None and not isinstance(ancestor, Binding):
-      if not isinstance(ancestor, model.Key):
-        raise TypeError('ancestor must be a Key')
-      if not ancestor.id():
-        raise ValueError('ancestor cannot be an incomplete key')
-      if app is not None:
-        if app != ancestor.app():
-          raise TypeError('app/ancestor mismatch')
-      if namespace is not None:
-        if namespace != ancestor.namespace():
-          raise TypeError('namespace/ancestor mismatch')
+    if ancestor is not None:
+      if isinstance(ancestor, ParameterizedThing):
+        if isinstance(ancestor, ParameterizedFunction):
+          if ancestor.func != 'key':
+            raise TypeError('ancestor cannot be a GQL function other than KEY')
+      else:
+        if not isinstance(ancestor, model.Key):
+          raise TypeError('ancestor must be a Key')
+        if not ancestor.id():
+          raise ValueError('ancestor cannot be an incomplete key')
+        if app is not None:
+          if app != ancestor.app():
+            raise TypeError('app/ancestor mismatch')
+        if namespace is not None:
+          if namespace != ancestor.namespace():
+            raise TypeError('namespace/ancestor mismatch')
     if filters is not None:
       if not isinstance(filters, Node):
         raise TypeError('filters must be a query Node or None; received %r' %
@@ -704,47 +801,48 @@
     self.__orders = orders  # None or datastore_query.Order instance
     self.__app = app
     self.__namespace = namespace
+    self.__default_options = default_options
 
   def __repr__(self):
     args = []
-    if self.__kind is not None:
-      args.append('kind=%r' % self.__kind)
-    if self.__ancestor is not None:
-      args.append('ancestor=%r' % self.__ancestor)
-    if self.__filters is not None:
-      args.append('filters=%r' % self.__filters)
-    if self.__orders is not None:
+    if self.kind is not None:
+      args.append('kind=%r' % self.kind)
+    if self.ancestor is not None:
+      args.append('ancestor=%r' % self.ancestor)
+    if self.filters is not None:
+      args.append('filters=%r' % self.filters)
+    if self.orders is not None:
+      # TODO: Format orders better.
       args.append('orders=...')  # PropertyOrder doesn't have a good repr().
-    if self.__app is not None:
-      args.append('app=%r' % self.__app)
-    if self.__namespace is not None:
-      args.append('namespace=%r' % self.__namespace)
+    if self.app is not None:
+      args.append('app=%r' % self.app)
+    if self.namespace is not None:
+      args.append('namespace=%r' % self.namespace)
+    if self.default_options is not None:
+      args.append('default_options=%r' % self.default_options)
     return '%s(%s)' % (self.__class__.__name__, ', '.join(args))
 
   def _get_query(self, connection):
-    kind = self.__kind
-    ancestor = self.__ancestor
-    bindings = {}
-    if isinstance(ancestor, Binding):
-      bindings[ancestor.key] = ancestor
-      ancestor = ancestor.resolve()
+    self.bind()  #  Raises an exception if there are unbound parameters.
+    kind = self.kind
+    ancestor = self.ancestor
     if ancestor is not None:
       ancestor = connection.adapter.key_to_pb(ancestor)
-    filters = self.__filters
+    filters = self.filters
     post_filters = None
     if filters is not None:
       post_filters = filters._post_filters()
-      filters = filters._to_filter(bindings)
-    dsquery = datastore_query.Query(app=self.__app,
-                                    namespace=self.__namespace,
+      filters = filters._to_filter()
+    dsquery = datastore_query.Query(app=self.app,
+                                    namespace=self.namespace,
                                     kind=kind.decode('utf-8') if kind else None,
                                     ancestor=ancestor,
                                     filter_predicate=filters,
-                                    order=self.__orders)
+                                    order=self.orders)
     if post_filters is not None:
       dsquery = datastore_query._AugmentedQuery(
         dsquery,
-        in_memory_filter=post_filters._to_filter(bindings, post=True))
+        in_memory_filter=post_filters._to_filter(post=True))
     return dsquery
 
   @tasklets.tasklet
@@ -800,26 +898,22 @@
     raise tasklets.Return(results)
 
   def _needs_multi_query(self):
-    filters = self.__filters
-    if filters is not None:
-      filters = filters.resolve()
-      if isinstance(filters, DisjunctionNode):
-        return True
-    return False
+    filters = self.filters
+    return filters is not None and isinstance(filters, DisjunctionNode)
 
   def _maybe_multi_query(self):
-    filters = self.__filters
-    if filters is not None:
-      filters = filters.resolve()
-      if isinstance(filters, DisjunctionNode):
-        # Switch to a _MultiQuery.
-        subqueries = []
-        for subfilter in filters:
-          subquery = Query(kind=self.__kind, ancestor=self.__ancestor,
-                           filters=subfilter, orders=self.__orders)
-          subqueries.append(subquery)
-        return _MultiQuery(subqueries)
-    return None
+    if not self._needs_multi_query():
+      return None
+    # Switch to a _MultiQuery.
+    filters = self.filters
+    subqueries = []
+    for subfilter in filters:
+      subquery = self.__class__(kind=self.kind, ancestor=self.ancestor,
+                                filters=subfilter, orders=self.orders,
+                                app=self.app, namespace=self.namespace,
+                                default_options=self.default_options)
+      subqueries.append(subquery)
+    return _MultiQuery(subqueries)
 
   @property
   def kind(self):
@@ -827,11 +921,6 @@
     return self.__kind
 
   @property
-  def namespace(self):
-    """Accessor for the namespace (a string or None)."""
-    return self.__namespace
-
-  @property
   def ancestor(self):
     """Accessor for the ancestor (a Key or None)."""
     return self.__ancestor
@@ -846,6 +935,21 @@
     """Accessor for the filters (a datastore_query.Order or None)."""
     return self.__orders
 
+  @property
+  def app(self):
+    """Accessor for the app (a string or None)."""
+    return self.__app
+
+  @property
+  def namespace(self):
+    """Accessor for the namespace (a string or None)."""
+    return self.__namespace
+
+  @property
+  def default_options(self):
+    """Accessor for the default_options (a QueryOptions instance or None)."""
+    return self.__default_options
+
   def filter(self, *args):
     """Return a new Query with additional filter(s) applied."""
     if not args:
@@ -865,8 +969,9 @@
     else:
       pred = ConjunctionNode(*preds)
     return self.__class__(kind=self.kind, ancestor=self.ancestor,
-                          orders=self.orders, filters=pred,
-                          namespace=self.namespace)
+                          filters=pred, orders=self.orders,
+                          app=self.app, namespace=self.namespace,
+                          default_options=self.default_options)
 
   def order(self, *args):
     """Return a new Query with additional sort order(s) applied."""
@@ -874,7 +979,7 @@
     if not args:
       return self
     orders = []
-    o = self.__orders
+    o = self.orders
     if o:
       orders.append(o)
     for arg in args:
@@ -893,7 +998,8 @@
       orders = datastore_query.CompositeOrder(orders)
     return self.__class__(kind=self.kind, ancestor=self.ancestor,
                           filters=self.filters, orders=orders,
-                          namespace=self.namespace)
+                          app=self.app, namespace=self.namespace,
+                          default_options=self.default_options)
 
   # Datastore API using the default context.
 
@@ -906,12 +1012,14 @@
     Returns:
       A QueryIterator object.
     """
+    self.bind()  #  Raises an exception if there are unbound parameters.
     return QueryIterator(self, **q_options)
 
   __iter__ = iter
 
   @utils.positional(2)
-  def map(self, callback, merge_future=None, **q_options):
+  def map(self, callback, pass_batch_into_callback=None,
+          merge_future=None, **q_options):
     """Map a callback function or tasklet over the query results.
 
     Args:
@@ -921,7 +1029,7 @@
 
     Callback signature: The callback is normally called with an entity
     as argument.  However if keys_only=True is given, it is called
-    with a Key.  Also, when produce_cursors=True is given, it is
+    with a Key.  Also, when pass_batch_into_callback is True, it is
     called with three arguments: the current batch, the index within
     the batch, and the entity or Key at that index.  The callback can
     return whatever it wants.  If the callback is None, a trivial
@@ -943,18 +1051,24 @@
       returned, map() returns a list of the results of all callbacks.
       (But see 'optional merge future' above.)
     """
-    return self.map_async(callback, merge_future=merge_future,
+    return self.map_async(callback,
+                          pass_batch_into_callback=pass_batch_into_callback,
+                          merge_future=merge_future,
                           **q_options).get_result()
 
   @utils.positional(2)
-  def map_async(self, callback, merge_future=None, **q_options):
+  def map_async(self, callback, pass_batch_into_callback=None,
+                merge_future=None, **q_options):
     """Map a callback function or tasklet over the query results.
 
     This is the asynchronous version of Query.map().
     """
-    return tasklets.get_context().map_query(self, callback,
-                                            options=_make_options(q_options),
-                                            merge_future=merge_future)
+    return tasklets.get_context().map_query(
+      self,
+      callback,
+      pass_batch_into_callback=pass_batch_into_callback,
+      options=self._make_options(q_options),
+      merge_future=merge_future)
 
   @utils.positional(2)
   def fetch(self, limit=None, **q_options):
@@ -975,17 +1089,18 @@
 
     This is the asynchronous version of Query.fetch().
     """
-    if 'limit' in q_options:
-      raise TypeError('Cannot specify limit as a non-keyword argument and as a '
-                      'keyword argument simultaneously.')
-    elif limit is None:
-      limit = _MAX_LIMIT
+    if limit is None:
+      default_options = self._make_options(q_options)
+      if default_options is not None and default_options.limit is not None:
+        limit = default_options.limit
+      else:
+        limit = _MAX_LIMIT
     q_options['limit'] = limit
     q_options.setdefault('batch_size', limit)
     if self._needs_multi_query():
       return self.map_async(None, **q_options)
     # Optimization using direct batches.
-    options = _make_options(q_options)
+    options = self._make_options(q_options)
     return self._run_to_list([], options=options)
 
   def get(self, **q_options):
@@ -1061,7 +1176,7 @@
     # before that offset without fetching the items.
     q_options['offset'] = limit
     q_options['limit'] = 0
-    options = _make_options(q_options)
+    options = self._make_options(q_options)
     conn = tasklets.get_context()._conn
     dsquery = self._get_query(conn)
     rpc = dsquery.run_async(conn, options)
@@ -1120,28 +1235,168 @@
       cursor = None
     raise tasklets.Return(results, cursor, it.probably_has_next())
 
+  def _make_options(self, q_options):
+    """Helper to construct a QueryOptions object from keyword arguents.
 
-def _make_options(q_options):
-  """Helper to construct a QueryOptions object from keyword arguents.
+    Args:
+      q_options: a dict of keyword arguments.
+
+    Note that either 'options' or 'config' can be used to pass another
+    QueryOptions object, but not both.  If another QueryOptions object is
+    given it provides default values.
+
+    If self.default_options is set, it is used to provide defaults,
+    which have a lower precedence than options set in q_options.
+
+    Returns:
+      A QueryOptions object, or None if q_options is empty.
+    """
+    if not q_options:
+      return self.default_options
+    if 'options' in q_options:
+      # Move 'options' to 'config' since that is what QueryOptions() uses.
+      if 'config' in q_options:
+        raise TypeError('You cannot use config= and options= at the same time')
+      q_options['config'] = q_options.pop('options')
+    options = QueryOptions(**q_options)
+    if self.default_options is not None:
+      options = self.default_options.merge(options)
+    return options
+
+  def analyze(self):
+    """Return a list giving the parameters required by a query."""
+    class MockBindings(dict):
+      def __contains__(self, key):
+        self[key] = None
+        return True
+    bindings = MockBindings()
+    used = {}
+    ancestor = self.ancestor
+    if isinstance(ancestor, ParameterizedThing):
+      ancestor = ancestor.resolve(bindings, used)
+    filters = self.filters
+    if filters is not None:
+      filters = filters.resolve(bindings, used)
+    return sorted(used)  # Returns only the keys.
+
+  def bind(self, *args, **kwds):
+    """Bind parameter values.  Returns a new Query object."""
+    return self._bind(args, kwds)
+
+  def _bind(self, args, kwds):
+    """Bind parameter values.  Returns a new Query object."""
+    bindings = dict(kwds)
+    for i, arg in enumerate(args):
+      bindings[i + 1] = arg
+    used = {}
+    ancestor = self.ancestor
+    if isinstance(ancestor, ParameterizedThing):
+      ancestor = ancestor.resolve(bindings, used)
+    filters = self.filters
+    if filters is not None:
+      filters = filters.resolve(bindings, used)
+    unused = []
+    for i in xrange(1, 1 + len(args)):
+      if i not in used:
+        unused.append(i)
+    if unused:
+      raise datastore_errors.BadArgumentError(
+        'Positional arguments %s were given but not used.' %
+        ', '.join(str(i) for i in unused))
+    return self.__class__(kind=self.kind, ancestor=ancestor,
+                          filters=filters, orders=self.orders,
+                          app=self.app, namespace=self.namespace,
+                          default_options=self.default_options)
+
+
+def gql(query_string, *args, **kwds):
+  """Parse a GQL query string.
 
   Args:
-    q_options: a dict of keyword arguments.
-
-  Note that either 'options' or 'config' can be used to pass another
-  QueryOptions object, but not both.  If another QueryOptions object is
-  given it provides default values.
+    query_string: Full GQL query, e.g. 'SELECT * FROM Kind WHERE prop = 1'.
+    *args, **kwds: If present, used to call bind().
 
   Returns:
-    A QueryOptions object, or None if q_options is empty.
+    An instance of query_class.
   """
-  if not q_options:
-    return None
-  if 'options' in q_options:
-    # Move 'options' to 'config' since that is what QueryOptions() uses.
-    if 'config' in q_options:
-      raise TypeError('You cannot use config= and options= at the same time')
-    q_options['config'] = q_options.pop('options')
-  return QueryOptions(**q_options)
+  qry = _gql(query_string)
+  if args or kwds:
+    qry = qry._bind(args, kwds)
+  return qry
+
+
+@utils.positional(1)
+def _gql(query_string, query_class=Query):
+  """Parse a GQL query string (internal version).
+
+  Args:
+    query_string: Full GQL query, e.g. 'SELECT * FROM Kind WHERE prop = 1'.
+    query_class: Optional class to use, default Query.
+
+  Returns:
+    An instance of query_class.
+  """
+  from .google_imports import gql  # Late import, to avoid name conflict.
+  gql_qry = gql.GQL(query_string)
+  kind = gql_qry.kind()
+  if kind is None:
+    modelclass = model.Expando
+  else:
+    ctx = tasklets.get_context()
+    default_model = ctx._conn.adapter.default_model
+    modelclass = model.Model._kind_map.get(kind, default_model)
+    if modelclass is None:
+      raise datastore_errors.BadQueryError(
+        "No model class found for kind %r. Did you forget to import it?" %
+        (kind,))
+  ancestor = None
+  flt = gql_qry.filters()
+  filters = []
+  for name_op in sorted(flt):
+    name, op = name_op
+    values = flt[name_op]
+    op = op.lower()
+    if op == 'is' and name == gql.GQL._GQL__ANCESTOR:
+      if len(values) != 1:
+        raise ValueError('"is" requires exactly one value')
+      [(func, args)] = values
+      ancestor = _args_to_val(func, args)
+      continue
+    if op not in _OPS:
+      raise NotImplementedError('Operation %r is not supported.' % op)
+    for (func, args) in values:
+      val = _args_to_val(func, args)
+      prop = _get_prop_from_modelclass(modelclass, name)
+      if prop._name != name:
+        raise RuntimeError('Whoa! _get_prop_from_modelclass(%s, %r) '
+                           'returned a property whose name is %r?!' %
+                           (modelclass.__name__, name, prop._name))
+      if isinstance(val, ParameterizedThing):
+        node = ParameterNode(prop, op, val)
+      elif op == 'in':
+        node = prop._IN(val)
+      else:
+        node = prop._comparison(op, val)
+      filters.append(node)
+  if filters:
+    filters = ConjunctionNode(*filters)
+  else:
+    filters = None
+  orders = _orderings_to_orders(gql_qry.orderings(), modelclass)
+  offset = gql_qry.offset()
+  limit = gql_qry.limit()
+  if limit < 0:
+    limit = None
+  keys_only = gql_qry._keys_only
+  if not keys_only:
+    keys_only = None
+  options = QueryOptions(offset=offset, limit=limit, keys_only=keys_only)
+  qry = query_class(kind=kind,
+                    ancestor=ancestor,
+                    filters=filters,
+                    orders=orders,
+                    default_options=options)
+  return qry
 
 
 class QueryIterator(object):
@@ -1199,10 +1454,12 @@
     """
     ctx = tasklets.get_context()
     callback = None
-    options = _make_options(q_options)
-    if options is not None and options.produce_cursors:
-      callback = self._extended_callback
-    self._iter = ctx.iter_query(query, callback=callback, options=options)
+    options = query._make_options(q_options)
+    callback = self._extended_callback
+    self._iter = ctx.iter_query(query,
+                                callback=callback,
+                                pass_batch_into_callback=True,
+                                options=options)
     self._fut = None
 
   def _extended_callback(self, batch, index, ent):
@@ -1235,6 +1492,8 @@
     # TODO: if cursor_after() was called for the previous item
     # reuse that result instead of computing it from scratch.
     # (Some cursor() calls make a datastore roundtrip.)
+    # TODO: reimplement the cursor() call to use NDB async I/O;
+    # perhaps even add async versions of cursor_before/after.
     return self._batch.cursor(self._index + self._exhausted)
 
   def cursor_after(self):
@@ -1251,6 +1510,39 @@
       raise datastore_errors.BadArgumentError('There is no cursor currently')
     return self._batch.cursor(self._index + 1)  # TODO: inline this as async.
 
+  def index_list(self):
+    """Return the list of indexes used for this query.
+
+    This returns a list of index representations, where an index
+    representation is the same as what is returned by get_indexes().
+
+    Before the first result, the information is unavailable, and then
+    None is returned.  This is not the same as an empty list -- the
+    empty list means that no index was used to execute the query.  (In
+    the dev_appserver, an empty list may also mean that only built-in
+    indexes were used; metadata queries also return an empty list
+    here.)
+
+    Proper use is as follows:
+      q = <modelclass>.query(<filters>)
+      i = q.iter()
+      try:
+        i.next()
+      except Stopiteration:
+        pass
+      indexes = i.index_list()
+      assert isinstance(indexes, list)
+
+    Notes:
+    - Forcing produce_cursors=False makes this always return None.
+    - This always returns None for a multi-query.
+    """
+    # TODO: Technically it is possible to implement this for
+    # multi-query by merging all the index lists from each subquery.
+    # Return None if the batch has no attribute index_list.
+    # This also applies when the batch itself is None.
+    return getattr(self._batch, 'index_list', None)
+
   def __iter__(self):
     """Iterator protocol: get the iterator for this iterator, i.e. self."""
     return self
@@ -1387,10 +1679,17 @@
     self.__orders = orders
     self.ancestor = None  # Hack for map_query().
 
+  def _make_options(self, q_options):
+    return self.__subqueries[0].default_options
+
   @property
   def orders(self):
     return self.__orders
 
+  @property
+  def default_options(self):
+    return self.__subqueries[0].default_options
+
   @tasklets.tasklet
   def run_to_queue(self, queue, conn, options=None):
     """Run this query, putting entities into the given queue."""
@@ -1561,13 +1860,18 @@
   raise ValueError('Bad order: %r' % (orders,))
 
 
-def _ordering_to_order(ordering):
+def _ordering_to_order(ordering, modelclass):
   name, direction = ordering
+  prop = _get_prop_from_modelclass(modelclass, name)
+  if prop._name != name:
+    raise RuntimeError('Whoa! _get_prop_from_modelclass(%s, %r) '
+                       'returned a property whose name is %r?!' %
+                       (modelclass.__name__, name, prop._name))
   return datastore_query.PropertyOrder(name, direction)
 
 
-def _orderings_to_orders(orderings):
-  orders = [_ordering_to_order(o) for o in orderings]
+def _orderings_to_orders(orderings, modelclass):
+  orders = [_ordering_to_order(o, modelclass) for o in orderings]
   if not orders:
     return None
   if len(orders) == 1:
diff --git a/google/appengine/ext/ndb/stats.py b/google/appengine/ext/ndb/stats.py
index 4cade85..fb020e3 100644
--- a/google/appengine/ext/ndb/stats.py
+++ b/google/appengine/ext/ndb/stats.py
@@ -9,6 +9,29 @@
 
 from . import model
 
+__all__ = ['BaseKindStatistic',
+           'BaseStatistic',
+           'GlobalStat',
+           'KindCompositeIndexStat',
+           'KindNonRootEntityStat',
+           'KindPropertyNamePropertyTypeStat',
+           'KindPropertyNameStat',
+           'KindPropertyTypeStat',
+           'KindRootEntityStat',
+           'KindStat',
+           'NamespaceGlobalStat',
+           'NamespaceKindCompositeIndexStat',
+           'NamespaceKindNonRootEntityStat',
+           'NamespaceKindPropertyNamePropertyTypeStat',
+           'NamespaceKindPropertyNameStat',
+           'NamespaceKindPropertyTypeStat',
+           'NamespaceKindRootEntityStat',
+           'NamespaceKindStat',
+           'NamespacePropertyTypeStat',
+           'NamespaceStat',
+           'PropertyTypeStat',
+           ]
+
 
 class BaseStatistic(model.Model):
   """Base Statistic Model class.
diff --git a/google/appengine/ext/ndb/tasklets.py b/google/appengine/ext/ndb/tasklets.py
index 9093303..ba5e973 100644
--- a/google/appengine/ext/ndb/tasklets.py
+++ b/google/appengine/ext/ndb/tasklets.py
@@ -65,23 +65,25 @@
 import sys
 import types
 
-from google.appengine.api.apiproxy_stub_map import UserRPC
-from google.appengine.api.apiproxy_rpc import RPC
-from google.appengine.datastore import datastore_rpc
+from .google_imports import apiproxy_stub_map
+from .google_imports import apiproxy_rpc
+from .google_imports import datastore_rpc
 
 from . import eventloop
 from . import utils
 
-__all__ = ['Return', 'tasklet', 'get_context', 'set_context', 'sleep',
-           'synctasklet',
+__all__ = ['Return', 'tasklet', 'synctasklet', 'toplevel', 'sleep',
+           'add_flow_exception', 'get_return_value',
+           'get_context', 'set_context',
+           'make_default_context', 'make_context',
            'Future', 'MultiFuture', 'QueueFuture', 'SerialQueueFuture',
            'ReducingFuture',
            ]
 
-logging_debug = utils.logging_debug
+_logging_debug = utils.logging_debug
 
 
-def is_generator(obj):
+def _is_generator(obj):
   """Helper to test for a generator object.
 
   NOTE: This tests for the (iterable) object returned by calling a
@@ -100,22 +102,22 @@
     self.all_pending = set()
 
   def add_pending(self, fut):
-    logging_debug('all_pending: add %s', fut)
+    _logging_debug('all_pending: add %s', fut)
     self.all_pending.add(fut)
 
   def remove_pending(self, fut, status='success'):
     if fut in self.all_pending:
-      logging_debug('all_pending: %s: remove %s', status, fut)
+      _logging_debug('all_pending: %s: remove %s', status, fut)
       self.all_pending.remove(fut)
     else:
-      logging_debug('all_pending: %s: not found %s', status, fut)
+      _logging_debug('all_pending: %s: not found %s', status, fut)
 
   def clear_all_pending(self):
     if self.all_pending:
       logging.info('all_pending: clear %s', self.all_pending)
       self.all_pending.clear()
     else:
-      logging_debug('all_pending: clear no-op')
+      _logging_debug('all_pending: clear no-op')
 
   def dump_all_pending(self, verbose=False):
     pending = []
@@ -179,9 +181,9 @@
   # TODO: Compare to Monocle's much simpler Callback class.
 
   # Constants for state property.
-  IDLE = RPC.IDLE  # Not yet running (unused)
-  RUNNING = RPC.RUNNING  # Not yet completed.
-  FINISHING = RPC.FINISHING  # Completed.
+  IDLE = apiproxy_rpc.RPC.IDLE  # Not yet running (unused)
+  RUNNING = apiproxy_rpc.RPC.RUNNING  # Not yet completed.
+  FINISHING = apiproxy_rpc.RPC.FINISHING  # Completed.
 
   # XXX Add docstrings to all methods.  Separate PEP 3148 API from RPC API.
 
@@ -297,7 +299,7 @@
       if not ev.run1():
         logging.info('Deadlock in %s', self)
         logging.info('All pending Futures:\n%s', _state.dump_all_pending())
-        logging_debug('All pending Futures (verbose):\n%s',
+        _logging_debug('All pending Futures (verbose):\n%s',
                       _state.dump_all_pending(verbose=True))
         self.set_exception(RuntimeError('Deadlock waiting for %s' % self))
 
@@ -350,11 +352,11 @@
       try:
         set_context(self._context)
         if exc is not None:
-          logging_debug('Throwing %s(%s) into %s',
+          _logging_debug('Throwing %s(%s) into %s',
                         exc.__class__.__name__, exc, info)
           value = gen.throw(exc.__class__, exc, tb)
         else:
-          logging_debug('Sending %r to %s', val, info)
+          _logging_debug('Sending %r to %s', val, info)
           value = gen.send(val)
           self._context = get_context()
       finally:
@@ -362,7 +364,7 @@
 
     except StopIteration, err:
       result = get_return_value(err)
-      logging_debug('%s returned %r', info, result)
+      _logging_debug('%s returned %r', info, result)
       self.set_result(result)
       return
 
@@ -376,7 +378,7 @@
     except Exception, err:
       _, _, tb = sys.exc_info()
       if isinstance(err, _flow_exceptions):
-        logging_debug('%s raised %s(%s)',
+        _logging_debug('%s raised %s(%s)',
                       info, err.__class__.__name__, err)
       elif logging.getLogger().level > logging.INFO:
         logging.warning('%s raised %s(%s)',
@@ -388,8 +390,9 @@
       return
 
     else:
-      logging_debug('%s yielded %r', info, value)
-      if isinstance(value, (UserRPC, datastore_rpc.MultiRpc)):
+      _logging_debug('%s yielded %r', info, value)
+      if isinstance(value, (apiproxy_stub_map.UserRPC,
+                            datastore_rpc.MultiRpc)):
         # TODO: Tail recursion if the RPC is already complete.
         eventloop.queue_rpc(value, self._on_rpc_completion, value, gen)
         return
@@ -400,7 +403,7 @@
                              self._next)
         self._next = value
         self._geninfo = utils.gen_info(gen)
-        logging_debug('%s is now blocked waiting for %s', self, value)
+        _logging_debug('%s is now blocked waiting for %s', self, value)
         value.add_callback(self._on_future_completion, value, gen)
         return
       if isinstance(value, (tuple, list)):
@@ -418,7 +421,7 @@
           mfut.set_exception(err, tb)
         mfut.add_callback(self._on_future_completion, mfut, gen)
         return
-      if is_generator(value):
+      if _is_generator(value):
         # TODO: emulate PEP 380 here?
         raise NotImplementedError('Cannot defer to another generator.')
       raise RuntimeError('A tasklet should not yield plain values.')
@@ -438,7 +441,7 @@
     if self._next is future:
       self._next = None
       self._geninfo = None
-      logging_debug('%s is no longer blocked waiting for %s', self, future)
+      _logging_debug('%s is no longer blocked waiting for %s', self, future)
     exc = future.get_exception()
     if exc is not None:
       self._help_tasklet_along(gen, exc=exc, tb=future.get_traceback())
@@ -957,6 +960,7 @@
     result = err.args
   return result
 
+
 def tasklet(func):
   # XXX Docstring
 
@@ -976,7 +980,7 @@
       # Just in case the function is not a generator but still uses
       # the "raise Return(...)" idiom, we'll extract the return value.
       result = get_return_value(err)
-    if is_generator(result):
+    if _is_generator(result):
       eventloop.queue_call(None, fut._help_tasklet_along, result)
     else:
       fut.set_result(result)
@@ -984,6 +988,7 @@
 
   return tasklet_wrapper
 
+
 def synctasklet(func):
   """Decorator to run a function as a tasklet when called.
 
@@ -999,9 +1004,33 @@
   return synctasklet_wrapper
 
 
+def toplevel(func):
+  """A sync tasklet that sets a fresh default Context.
+
+  Use this for toplevel view functions such as
+  webapp.RequestHandler.get() or Django view functions.
+  """
+  @utils.wrapping(func)
+  def add_context_wrapper(*args, **kwds):
+    __ndb_debug__ = utils.func_info(func)
+    _state.clear_all_pending()
+    # Create and install a new context.
+    ctx = make_default_context()
+    try:
+      set_context(ctx)
+      return synctasklet(func)(*args, **kwds)
+    finally:
+      set_context(None)
+      ctx.flush().check_success()
+      eventloop.run()  # Ensure writes are flushed, etc.
+  return add_context_wrapper
+
+
 _CONTEXT_KEY = '__CONTEXT__'
 
+
 def get_context():
+  # XXX Docstring
   ctx = None
   if os.getenv(_CONTEXT_KEY):
     ctx = _state.current_context
@@ -1010,14 +1039,25 @@
     set_context(ctx)
   return ctx
 
+
 def make_default_context():
+  # XXX Docstring
+  return make_context()
+
+
+@utils.positional(0)
+def make_context(conn=None, config=None):
+  # XXX Docstring
   from . import context  # Late import to deal with circular imports.
-  return context.Context()
+  return context.Context(conn=conn, config=config)
+
 
 def set_context(new_context):
+  # XXX Docstring
   os.environ[_CONTEXT_KEY] = '1'
   _state.current_context = new_context
 
+
 # TODO: Rework the following into documentation.
 
 # A tasklet/coroutine/generator can yield the following things:
diff --git a/google/appengine/ext/ndb/utils.py b/google/appengine/ext/ndb/utils.py
index 55a6c8e..c78b782 100644
--- a/google/appengine/ext/ndb/utils.py
+++ b/google/appengine/ext/ndb/utils.py
@@ -24,18 +24,23 @@
   # A decorator to decorate a decorator's wrapper.  Following the lead
   # of Twisted and Monocle, this is supposed to make debugging heavily
   # decorated code easier.  We'll see...
-  # TODO: Evaluate; so far it hasn't helped (nor hurt).
+  # TODO: Evaluate; so far it hasn't helped, and it has hurt some.
   def wrapping_wrapper(wrapper):
-    wrapper.__name__ = wrapped.__name__
-    wrapper.__doc__ = wrapped.__doc__
-    wrapper.__dict__.update(wrapped.__dict__)
-    wrapper.__wrapped__ = wrapped
+    try:
+      wrapper.__wrapped__ = wrapped
+      wrapper.__name__ = wrapped.__name__
+      wrapper.__doc__ = wrapped.__doc__
+      wrapper.__dict__.update(wrapped.__dict__)
+    except Exception:
+      pass
     return wrapper
   return wrapping_wrapper
 
 
 # Define a base class for classes that need to be thread-local.
-if os.getenv('wsgi.multithread'):
+# This is pretty subtle; we want to use threading.local if threading
+# is supported, but object if it is not.
+if threading.local.__module__ == 'thread':
   logging_debug('Using threading.local')
   threading_local = threading.local
 else:
@@ -65,7 +70,7 @@
   if not DEBUG:
     return None
   func = getattr(func, '__wrapped__', func)
-  code = func.func_code
+  code = getattr(func, 'func_code', None)
   return code_info(code, lineno)
 
 
@@ -97,8 +102,8 @@
 
 
 def code_info(code, lineno=None):
-  if not DEBUG:
-    return None
+  if not DEBUG or not code:
+    return ''
   funcname = code.co_name
   # TODO: Be cleverer about stripping filename,
   # e.g. strip based on sys.path.
diff --git a/google/appengine/ext/remote_api/remote_api_services.py b/google/appengine/ext/remote_api/remote_api_services.py
index da3accf..67d1b7e 100755
--- a/google/appengine/ext/remote_api/remote_api_services.py
+++ b/google/appengine/ext/remote_api/remote_api_services.py
@@ -26,6 +26,7 @@
 import sys
 
 from google.appengine.api import api_base_pb
+from google.appengine.api.app_identity import app_identity_service_pb
 from google.appengine.api.channel import channel_service_pb
 from google.appengine.api import mail_service_pb
 from google.appengine.api import urlfetch_service_pb
@@ -37,6 +38,7 @@
 from google.appengine.api.images import images_service_pb
 from google.appengine.api.logservice import log_service_pb
 from google.appengine.api.memcache import memcache_service_pb
+from google.appengine.api.search import search_service_pb
 from google.appengine.api.system import system_service_pb
 from google.appengine.api.taskqueue import taskqueue_service_pb
 from google.appengine.api.xmpp import xmpp_service_pb
@@ -45,6 +47,18 @@
 
 
 SERVICE_PB_MAP = {
+    'app_identity_service': {
+        'SignForApp': (app_identity_service_pb.SignForAppRequest,
+                       app_identity_service_pb.SignForAppResponse),
+        'GetPublicCertificatesForApp': (
+            app_identity_service_pb.GetPublicCertificateForAppRequest,
+            app_identity_service_pb.GetPublicCertificateForAppResponse),
+        'GetServiceAccountName': (
+            app_identity_service_pb.GetServiceAccountNameRequest,
+            app_identity_service_pb.GetServiceAccountNameResponse),
+        'GetAccessToken': (app_identity_service_pb.GetAccessTokenRequest,
+                           app_identity_service_pb.GetAccessTokenResponse),
+    },
     'blobstore': {
         'CreateUploadURL': (blobstore_service_pb.CreateUploadURLRequest,
                             blobstore_service_pb.CreateUploadURLResponse),
@@ -52,6 +66,8 @@
                             api_base_pb.VoidProto),
         'FetchData':       (blobstore_service_pb.FetchDataRequest,
                             blobstore_service_pb.FetchDataResponse),
+        'DecodeBlobKey':   (blobstore_service_pb.DecodeBlobKeyRequest,
+                            blobstore_service_pb.DecodeBlobKeyResponse),
     },
     'capability_service': {
         'IsEnabled': (capability_service_pb.IsEnabledRequest,
@@ -72,7 +88,6 @@
         'Put':        (datastore_pb.PutRequest, datastore_pb.PutResponse),
         'Delete':     (datastore_pb.DeleteRequest, datastore_pb.DeleteResponse),
         'Count':      (datastore_pb.Query, api_base_pb.Integer64Proto),
-        'GetIndices': (api_base_pb.StringProto, datastore_pb.CompositeIndices),
         'AllocateIds':(datastore_pb.AllocateIdsRequest,
                        datastore_pb.AllocateIdsResponse),
         'RunQuery':   (datastore_pb.Query,
@@ -86,6 +101,8 @@
                             datastore_pb.CommitResponse),
         'Rollback':        (datastore_pb.Transaction,
                             api_base_pb.VoidProto),
+        'GetIndices':      (api_base_pb.StringProto,
+                            datastore_pb.CompositeIndices),
     },
     'file': {
         'Create': (file_service_pb.CreateRequest,
@@ -108,6 +125,8 @@
                     file_service_pb.ShuffleResponse),
         'GetShuffleStatus': (file_service_pb.GetShuffleStatusRequest,
                              file_service_pb.GetShuffleStatusResponse),
+        'GetCapabilities': (file_service_pb.GetCapabilitiesRequest,
+                            file_service_pb.GetCapabilitiesResponse),
     },
     'images': {
         'Transform': (images_service_pb.ImagesTransformRequest,
@@ -116,8 +135,12 @@
                       images_service_pb.ImagesCompositeResponse),
         'Histogram': (images_service_pb.ImagesHistogramRequest,
                       images_service_pb.ImagesHistogramResponse),
+        'GetUrlBase': (images_service_pb.ImagesGetUrlBaseRequest,
+                       images_service_pb.ImagesGetUrlBaseResponse),
     },
     'logservice': {
+        'Flush': (log_service_pb.FlushRequest, api_base_pb.VoidProto),
+        'SetStatus': (log_service_pb.SetStatusRequest, api_base_pb.VoidProto),
         'Read': (log_service_pb.LogReadRequest, log_service_pb.LogReadResponse),
     },
     'mail': {
@@ -133,6 +156,8 @@
                       memcache_service_pb.MemcacheDeleteResponse),
         'Increment': (memcache_service_pb.MemcacheIncrementRequest,
                       memcache_service_pb.MemcacheIncrementResponse),
+        'BatchIncrement': (memcache_service_pb.MemcacheBatchIncrementRequest,
+                           memcache_service_pb.MemcacheBatchIncrementResponse),
         'FlushAll':  (memcache_service_pb.MemcacheFlushRequest,
                       memcache_service_pb.MemcacheFlushResponse),
         'Stats':     (memcache_service_pb.MemcacheStatsRequest,
@@ -144,6 +169,18 @@
                         datastore_pb.PutResponse),
         'GetIDs':      (datastore_pb.PutRequest, datastore_pb.PutResponse),
     },
+    'search': {
+        'IndexDocument': (search_service_pb.IndexDocumentRequest,
+                          search_service_pb.IndexDocumentResponse),
+        'DeleteDocument': (search_service_pb.DeleteDocumentRequest,
+                           search_service_pb.DeleteDocumentResponse),
+        'ListDocuments': (search_service_pb.ListDocumentsRequest,
+                          search_service_pb.ListDocumentsResponse),
+        'ListIndexes': (search_service_pb.ListIndexesRequest,
+                        search_service_pb.ListIndexesResponse),
+        'Search': (search_service_pb.SearchRequest,
+                   search_service_pb.SearchResponse),
+    },
     'system': {
         'GetSystemStats': (system_service_pb.GetSystemStatsRequest,
                            system_service_pb.GetSystemStatsResponse),
@@ -162,16 +199,31 @@
             taskqueue_service_pb.TaskQueueFetchQueueStatsResponse),
         'Delete': (taskqueue_service_pb.TaskQueueDeleteRequest,
                    taskqueue_service_pb.TaskQueueDeleteResponse),
+        'ForceRun': (taskqueue_service_pb.TaskQueueForceRunRequest,
+                     taskqueue_service_pb.TaskQueueForceRunResponse),
+        'UpdateQueue': (taskqueue_service_pb.TaskQueueUpdateQueueRequest,
+                        taskqueue_service_pb.TaskQueueUpdateQueueResponse),
+        'PauseQueue': (taskqueue_service_pb.TaskQueuePauseQueueRequest,
+                       taskqueue_service_pb.TaskQueuePauseQueueResponse),
         'PurgeQueue': (taskqueue_service_pb.TaskQueuePurgeQueueRequest,
                        taskqueue_service_pb.TaskQueuePurgeQueueResponse),
+        'DeleteQueue': (taskqueue_service_pb.TaskQueueDeleteQueueRequest,
+                        taskqueue_service_pb.TaskQueueDeleteQueueRequest),
+        'DeleteGroup': (taskqueue_service_pb.TaskQueueDeleteGroupRequest,
+                        taskqueue_service_pb.TaskQueueDeleteGroupRequest),
         'QueryTasks': (taskqueue_service_pb.TaskQueueQueryTasksRequest,
                        taskqueue_service_pb.TaskQueueQueryTasksResponse),
+        'FetchTasks': (taskqueue_service_pb.TaskQueueFetchTaskRequest,
+                       taskqueue_service_pb.TaskQueueFetchTaskRequest),
         'QueryAndOwnTasks': (
             taskqueue_service_pb.TaskQueueQueryAndOwnTasksRequest,
             taskqueue_service_pb.TaskQueueQueryAndOwnTasksResponse),
         'ModifyTaskLease': (
             taskqueue_service_pb.TaskQueueModifyTaskLeaseRequest,
             taskqueue_service_pb.TaskQueueModifyTaskLeaseResponse),
+        'UpdateStorageLimit': (
+            taskqueue_service_pb.TaskQueueUpdateStorageLimitRequest,
+            taskqueue_service_pb.TaskQueueUpdateStorageLimitResponse),
     },
     'urlfetch': {
         'Fetch': (urlfetch_service_pb.URLFetchRequest,
@@ -182,6 +234,8 @@
                            user_service_pb.CreateLoginURLResponse),
         'CreateLogoutURL': (user_service_pb.CreateLogoutURLRequest,
                             user_service_pb.CreateLogoutURLResponse),
+        'GetOAuthUser': (user_service_pb.GetOAuthUserRequest,
+                         user_service_pb.GetOAuthUserResponse),
     },
     'xmpp': {
         'GetPresence': (xmpp_service_pb.PresenceRequest,
@@ -192,5 +246,9 @@
                         xmpp_service_pb.XmppInviteResponse),
         'SendPresence':  (xmpp_service_pb.XmppSendPresenceRequest,
                         xmpp_service_pb.XmppSendPresenceResponse),
+        'CreateChannel': (channel_service_pb.CreateChannelRequest,
+                          channel_service_pb.CreateChannelResponse),
+        'SendChannelMessage': (channel_service_pb.SendMessageRequest,
+                               api_base_pb.VoidProto),
     },
 }
diff --git a/google/appengine/ext/remote_api/remote_api_stub.py b/google/appengine/ext/remote_api/remote_api_stub.py
index fda441d..c73e877 100755
--- a/google/appengine/ext/remote_api/remote_api_stub.py
+++ b/google/appengine/ext/remote_api/remote_api_stub.py
@@ -516,7 +516,8 @@
 
 
 def ConfigureRemoteApiFromServer(server, path, app_id, services=None,
-                                 default_auth_domain=None):
+                                 default_auth_domain=None,
+                                 use_remote_datastore=True):
   """Does necessary setup to allow easy remote access to App Engine APIs.
 
   Args:
@@ -527,6 +528,10 @@
     services: A list of services to set up stubs for. If specified, only those
       services are configured; by default all supported services are configured.
     default_auth_domain: The authentication domain to use by default.
+    use_remote_datastore: Whether to use RemoteDatastoreStub instead of passing
+      through datastore requests. RemoteDatastoreStub batches transactional
+      datastore requests since, in production, datastore requires are scoped to
+      a single request.
 
   Raises:
     urllib2.HTTPError: if app_id is not provided and there is an error while
@@ -545,7 +550,7 @@
   os.environ['APPLICATION_ID'] = app_id
   os.environ.setdefault('AUTH_DOMAIN', default_auth_domain or 'gmail.com')
   apiproxy_stub_map.apiproxy = apiproxy_stub_map.APIProxyStubMap()
-  if 'datastore_v3' in services:
+  if 'datastore_v3' in services and use_remote_datastore:
     services.remove('datastore_v3')
     datastore_stub = RemoteDatastoreStub(server, path)
     apiproxy_stub_map.apiproxy.RegisterStub('datastore_v3', datastore_stub)
@@ -600,7 +605,8 @@
                        secure=False,
                        services=None,
                        default_auth_domain=None,
-                       save_cookies=False):
+                       save_cookies=False,
+                       use_remote_datastore=True):
   """Does necessary setup to allow easy remote access to App Engine APIs.
 
   Either servername must be provided or app_id must not be None.  If app_id
@@ -630,6 +636,10 @@
       services are configured; by default all supported services are configured.
     default_auth_domain: The authentication domain to use by default.
     save_cookies: Forwarded to rpc_server_factory function.
+    use_remote_datastore: Whether to use RemoteDatastoreStub instead of passing
+      through datastore requests. RemoteDatastoreStub batches transactional
+      datastore requests since, in production, datastore requires are scoped to
+      a single request.
 
   Returns:
     server, the server created by rpc_server_factory, which may be useful for
@@ -651,7 +661,7 @@
     app_id = GetRemoteAppIdFromServer(server, path, rtok)
 
   ConfigureRemoteApiFromServer(server, path, app_id, services,
-                               default_auth_domain)
+                               default_auth_domain, use_remote_datastore)
   return server
 
 
diff --git a/google/appengine/runtime/apiproxy.py b/google/appengine/runtime/apiproxy.py
index 77b5c47..b247c66 100755
--- a/google/appengine/runtime/apiproxy.py
+++ b/google/appengine/runtime/apiproxy.py
@@ -156,12 +156,9 @@
             sys.modules,
             sys.path)
 
-    if isinstance(self.request, ProtocolBuffer.ProtocolMessage):
-      e = ProtocolBuffer.Encoder()
-      self.request.Output(e)
-      request_data = e.buffer()
-    else:
-      request_data = self.request.SerializeToString()
+
+
+    request_data = self.request.SerializeToString()
 
     self.__state = RPC.RUNNING
 
diff --git a/google/appengine/tools/api_server.py b/google/appengine/tools/api_server.py
new file mode 100644
index 0000000..7beca32
--- /dev/null
+++ b/google/appengine/tools/api_server.py
@@ -0,0 +1,765 @@
+#!/usr/bin/env python
+#
+# Copyright 2007 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+
+
+
+"""Serves the stub App Engine APIs (e.g. memcache, datastore) over HTTP.
+
+The Remote API protocol is used for communication.
+"""
+
+from __future__ import with_statement
+
+
+import BaseHTTPServer
+import httplib
+import logging
+import os
+import os.path
+import pickle
+import socket
+import SocketServer
+import subprocess
+import sys
+import tempfile
+import threading
+import time
+import traceback
+import urllib2
+import urlparse
+
+import google
+import yaml
+
+
+from google.appengine.api import mail_stub
+from google.appengine.api import urlfetch_stub
+from google.appengine.api import user_service_stub
+from google.appengine.api.app_identity import app_identity_stub
+from google.appengine.api.blobstore import blobstore_stub
+from google.appengine.api.blobstore import file_blob_storage
+from google.appengine.api.capabilities import capability_stub
+from google.appengine.api.conversion import conversion_stub
+from google.appengine.api.channel import channel_service_stub
+from google.appengine.api.files import file_service_stub
+from google.appengine.api.logservice import logservice_stub
+from google.appengine.api.search import simple_search_stub
+from google.appengine.api.taskqueue import taskqueue_stub
+from google.appengine.api.prospective_search import prospective_search_stub
+from google.appengine.api.memcache import memcache_stub
+from google.appengine.api.system import system_stub
+from google.appengine.api.xmpp import xmpp_service_stub
+from google.appengine.api import datastore_file_stub
+from google.appengine.datastore import datastore_sqlite_stub
+from google.appengine.datastore import datastore_stub_util
+
+from google.appengine.api import apiproxy_stub_map
+from google.appengine.ext.remote_api import remote_api_pb
+from google.appengine.ext.remote_api import remote_api_services
+from google.appengine.runtime import apiproxy_errors
+
+
+QUIT_PATH = '/quit'
+
+
+GLOBAL_API_LOCK = threading.RLock()
+
+
+class Error(Exception):
+  pass
+
+
+def _ClearDatastoreStorage(datastore_path):
+  """Delete the datastore storage file at the given path."""
+
+  if os.path.lexists(datastore_path):
+    try:
+      os.remove(datastore_path)
+    except OSError, e:
+      logging.warning('Failed to remove datastore file %r: %s',
+                      datastore_path,
+                      e)
+
+
+def _ClearProspectiveSearchStorage(prospective_search_path):
+  """Delete the perspective search storage file at the given path."""
+
+  if os.path.lexists(prospective_search_path):
+    try:
+      os.remove(prospective_search_path)
+    except OSError, e:
+      logging.warning('Failed to remove prospective search file %r: %s',
+                      prospective_search_path,
+                      e)
+
+
+def _ExecuteRequest(request):
+  """Executes an API method call and returns the response object.
+
+  Args:
+    request: A remote_api.Request object representing the API call e.g. a call
+        to memcache.Get.
+
+  Returns:
+    A ProtocolBuffer.ProtocolMessage representing the API response e.g. a
+    memcache_service_pb.MemcacheGetResponse.
+
+  Raises:
+    apiproxy_errors.CallNotFoundError: if the requested method doesn't exist.
+    apiproxy_errors.ApplicationError: if the API method calls fails.
+  """
+  service = request.service_name()
+  method = request.method()
+  service_methods = remote_api_services.SERVICE_PB_MAP.get(service, {})
+  request_class, response_class = service_methods.get(method, (None, None))
+  if not request_class:
+    raise apiproxy_errors.CallNotFoundError('%s.%s does not exist' % (service,
+                                                                      method))
+
+  request_data = request_class()
+  request_data.ParseFromString(request.request())
+  response_data = response_class()
+
+  with GLOBAL_API_LOCK:
+    apiproxy_stub_map.MakeSyncCall(service, method, request_data,
+                                   response_data)
+  return response_data
+
+
+class APIRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+  """Handler for all API server HTTP requests."""
+
+  def log_message(self, format, *args):
+    logging.debug(format, *args)
+
+  def do_GET(self):
+    if self.path == QUIT_PATH:
+      self._HandleShutdown()
+    else:
+      params = urlparse.parse_qs(urlparse.urlparse(self.path).query)
+      rtok = params.get('rtok', ['0'])[0]
+
+      self.send_response(httplib.OK)
+      self.send_header('Content-Type', 'text/plain')
+      self.end_headers()
+      self.wfile.write(yaml.dump({
+          'app_id': self.server.app_id,
+          'rtok': rtok,
+          }))
+
+  def _HandleShutdown(self):
+    """Handles a request for the API Server to exit."""
+    self.send_response(httplib.OK)
+    self.send_header('Content-Type', 'text/plain')
+    self.end_headers()
+    self.wfile.write('API Server Quitting')
+    self.server.shutdown()
+
+  def do_POST(self):
+    """Handles a single API request e.g. memcache.Get()."""
+    self.send_response(httplib.OK)
+    self.send_header('Content-Type', 'application/octet-stream')
+    self.end_headers()
+
+    response = remote_api_pb.Response()
+    try:
+      request = remote_api_pb.Request()
+
+
+
+      request.ParseFromString(
+          self.rfile.read(int(self.headers['content-length'])))
+      api_response = _ExecuteRequest(request).Encode()
+      response.set_response(api_response)
+    except Exception, e:
+      logging.debug('Exception while handling %s\n%s',
+                    request,
+                    traceback.format_exc())
+      response.set_exception(pickle.dumps(e))
+      if isinstance(e, apiproxy_errors.ApplicationError):
+        application_error = response.mutable_application_error()
+        application_error.set_code(e.application_error)
+        application_error.set_detail(e.error_detail)
+    self.wfile.write(response.Encode())
+
+
+class APIServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
+  """Serves API calls over HTTP."""
+
+  def __init__(self, server_address, app_id):
+    BaseHTTPServer.HTTPServer.__init__(self, server_address, APIRequestHandler)
+    self.app_id = app_id
+
+
+def _SetupStubs(
+    app_id,
+    application_root,
+    trusted,
+    blobstore_path,
+    use_sqlite,
+    high_replication,
+    datastore_path,
+    datastore_require_indexes,
+    images_host_prefix,
+    persist_logs,
+    mail_smtp_host,
+    mail_smtp_port,
+    mail_smtp_user,
+    mail_smtp_password,
+    mail_enable_sendmail,
+    mail_show_mail_body,
+    matcher_prospective_search_path,
+    taskqueue_auto_run_tasks,
+    taskqueue_task_retry_seconds,
+    taskqueue_default_http_server,
+    user_login_url,
+    user_logout_url):
+  """Configures the APIs hosted by this server.
+
+  Args:
+    app_id: The str application id e.g. "guestbook".
+    application_root: The path to the directory containing the user's
+        application e.g. "/home/bquinlan/myapp".
+    trusted: A bool indicating if privileged APIs should be made available.
+    blobstore_path: The path to the file that should be used for blobstore
+        storage.
+    use_sqlite: A bool indicating whether DatastoreSqliteStub or
+        DatastoreFileStub should be used.
+    high_replication: A bool indicating whether to use the high replication
+        consistency model.
+    datastore_path: The path to the file that should be used for datastore
+        storage.
+    datastore_require_indexes: A bool indicating if the same production
+        datastore indexes requirements should be enforced i.e. if True then
+        a google.appengine.ext.db.NeedIndexError will be be raised if a query
+        is executed without the required indexes.
+    images_host_prefix: The URL prefix (protocol://host:port) to preprend to
+        image urls on calls to images.GetUrlBase.
+    persist_logs: A bool indicating if request and application logs should be
+         persisted for later access.
+    mail_smtp_host: The SMTP hostname that should be used when sending e-mails.
+        If None then the mail_enable_sendmail argument is considered.
+    mail_smtp_port: The SMTP port number that should be used when sending
+        e-mails. If this value is None then mail_smtp_host must also be None.
+    mail_smtp_user: The username to use when authenticating with the
+        SMTP server. This value may be None if mail_smtp_host is also None or if
+        the SMTP server does not require authentication.
+    mail_smtp_password: The password to use when authenticating with the
+        SMTP server. This value may be None if mail_smtp_host or mail_smtp_user
+        is also None.
+    mail_enable_sendmail: A bool indicating if sendmail should be used when
+        sending e-mails. This argument is ignored if mail_smtp_host is not None.
+    mail_show_mail_body: A bool indicating whether the body of sent e-mails
+        should be written to the logs.
+    matcher_prospective_search_path: The path to the file that should be used to
+        save prospective search subscriptions.
+    taskqueue_auto_run_tasks: A bool indicating whether taskqueue tasks should
+        be run automatically or it the must be manually triggered.
+    taskqueue_task_retry_seconds: An int representing the number of seconds to
+        wait before a retrying a failed taskqueue task.
+    taskqueue_default_http_server: A str containing the address of the http
+        server that should be used to execute tasks.
+    user_login_url: A str containing the url that should be used for user login.
+    user_logout_url: A str containing the url that should be used for user
+        logout.
+  """
+
+
+
+  apiproxy_stub_map.apiproxy.RegisterStub(
+      'app_identity_service',
+      app_identity_stub.AppIdentityServiceStub())
+
+  blob_storage = file_blob_storage.FileBlobStorage(blobstore_path, app_id)
+  apiproxy_stub_map.apiproxy.RegisterStub(
+      'blobstore',
+      blobstore_stub.BlobstoreServiceStub(blob_storage))
+
+  apiproxy_stub_map.apiproxy.RegisterStub(
+      'capability_service',
+      capability_stub.CapabilityServiceStub())
+
+
+
+
+
+
+
+
+  apiproxy_stub_map.apiproxy.RegisterStub(
+      'channel',
+      channel_service_stub.ChannelServiceStub())
+
+  apiproxy_stub_map.apiproxy.RegisterStub(
+      'conversion',
+      conversion_stub.ConversionServiceStub())
+
+  if use_sqlite:
+    datastore = datastore_sqlite_stub.DatastoreSqliteStub(
+        app_id,
+        datastore_path,
+        datastore_require_indexes,
+        trusted,
+        root_path=application_root)
+  else:
+    datastore = datastore_file_stub.DatastoreFileStub(
+        app_id,
+        datastore_path,
+        datastore_require_indexes,
+        trusted,
+        root_path=application_root)
+
+  if high_replication:
+    datastore.SetConsistencyPolicy(
+        datastore_stub_util.TimeBasedHRConsistencyPolicy())
+
+  apiproxy_stub_map.apiproxy.RegisterStub(
+      'datastore_v3', datastore)
+
+  apiproxy_stub_map.apiproxy.RegisterStub(
+      'file',
+      file_service_stub.FileServiceStub(blob_storage))
+
+  try:
+    from google.appengine.api.images import images_stub
+  except ImportError:
+
+
+    logging.warning('Could not initialize images API; you are likely missing '
+                    'the Python "PIL" module.')
+
+    from google.appengine.api.images import images_not_implemented_stub
+    apiproxy_stub_map.apiproxy.RegisterStub(
+        'images',
+        images_not_implemented_stub.ImagesNotImplementedServiceStub())
+  else:
+    apiproxy_stub_map.apiproxy.RegisterStub(
+        'images',
+        images_stub.ImagesServiceStub(host_prefix=images_host_prefix))
+
+  apiproxy_stub_map.apiproxy.RegisterStub(
+      'logservice',
+      logservice_stub.LogServiceStub(persist_logs))
+
+  apiproxy_stub_map.apiproxy.RegisterStub(
+      'mail',
+      mail_stub.MailServiceStub(mail_smtp_host,
+                                mail_smtp_port,
+                                mail_smtp_user,
+                                mail_smtp_password,
+                                enable_sendmail=mail_enable_sendmail,
+                                show_mail_body=mail_show_mail_body))
+
+  apiproxy_stub_map.apiproxy.RegisterStub(
+      'memcache',
+      memcache_stub.MemcacheServiceStub())
+
+  apiproxy_stub_map.apiproxy.RegisterStub(
+      'search',
+      simple_search_stub.SearchServiceStub())
+
+  apiproxy_stub_map.apiproxy.RegisterStub('system',
+                                          system_stub.SystemServiceStub())
+
+  apiproxy_stub_map.apiproxy.RegisterStub(
+      'taskqueue',
+      taskqueue_stub.TaskQueueServiceStub(
+          root_path=application_root,
+          auto_task_running=taskqueue_auto_run_tasks,
+          task_retry_seconds=taskqueue_task_retry_seconds,
+          default_http_server=taskqueue_default_http_server))
+  apiproxy_stub_map.apiproxy.GetStub('taskqueue').StartBackgroundExecution()
+
+  apiproxy_stub_map.apiproxy.RegisterStub(
+      'urlfetch',
+      urlfetch_stub.URLFetchServiceStub())
+
+  apiproxy_stub_map.apiproxy.RegisterStub(
+      'user',
+      user_service_stub.UserServiceStub(login_url=user_login_url,
+                                        logout_url=user_logout_url))
+
+  apiproxy_stub_map.apiproxy.RegisterStub(
+      'xmpp',
+      xmpp_service_stub.XmppServiceStub())
+
+  apiproxy_stub_map.apiproxy.RegisterStub(
+      'matcher',
+      prospective_search_stub.ProspectiveSearchStub(
+          matcher_prospective_search_path,
+          apiproxy_stub_map.apiproxy.GetStub('taskqueue')))
+
+
+def ParseCommandArguments(args):
+  """Parses and the application's command line arguments.
+
+  Args:
+    args: A list of command line arguments *not* including the executable or
+        script e.g. ['-A' 'myapp', '--api_port=8000'].
+
+  Returns:
+    An object containing the values passed in the commandline as attributes.
+
+  Raises:
+    SystemExit: if the argument parsing fails.
+  """
+
+
+
+  import argparse
+  from google.appengine.tools import boolean_action
+
+  parser = argparse.ArgumentParser()
+  parser.add_argument('-A', '--application', required=True)
+  parser.add_argument('--api_host', default='')
+
+  parser.add_argument('--api_port', default=8000, type=int)
+  parser.add_argument('--trusted',
+                      action=boolean_action.BooleanAction,
+                      const=True,
+                      default=False)
+  parser.add_argument('--application_root', default=None)
+  parser.add_argument('--application_host', default='localhost')
+  parser.add_argument('--application_port', default=None)
+
+
+  parser.add_argument('--blobstore_path', default=None)
+
+
+  parser.add_argument('--datastore_path', default=None)
+  parser.add_argument('--use_sqlite',
+                      action=boolean_action.BooleanAction,
+                      const=True,
+                      default=False)
+  parser.add_argument('--high_replication',
+                      action=boolean_action.BooleanAction,
+                      const=True,
+                      default=False)
+  parser.add_argument('--require_indexes',
+                      action=boolean_action.BooleanAction,
+                      const=True,
+                      default=False)
+  parser.add_argument('--clear_datastore',
+                      action=boolean_action.BooleanAction,
+                      const=True,
+                      default=False)
+
+
+  parser.add_argument('--persist_logs',
+                      action=boolean_action.BooleanAction,
+                      const=True,
+                      default=False)
+
+
+  parser.add_argument('--enable_sendmail',
+                      action=boolean_action.BooleanAction,
+                      const=True,
+                      default=False)
+  parser.add_argument('--smtp_host', default='')
+
+  parser.add_argument('--smtp_port', default=25, type=int)
+  parser.add_argument('--smtp_user', default='')
+  parser.add_argument('--smtp_password', default='')
+  parser.add_argument('--show_mail_body',
+                      action=boolean_action.BooleanAction,
+                      const=True,
+                      default=False)
+
+
+  parser.add_argument('--prospective_search_path', default=None)
+  parser.add_argument('--clear_prospective_search',
+                      action=boolean_action.BooleanAction,
+                      const=True,
+                      default=False)
+
+
+  parser.add_argument('--enable_task_running',
+                      action=boolean_action.BooleanAction,
+                      const=True,
+                      default=True)
+
+  parser.add_argument('--task_retry_seconds', default=30, type=int)
+
+
+  parser.add_argument('--user_login_url', default=None)
+  parser.add_argument('--user_logout_url', default=None)
+
+  return parser.parse_args(args)
+
+
+class APIServerProcess(object):
+  """Manages an API Server running as a seperate process."""
+
+
+
+
+
+
+  def __init__(self,
+               executable,
+               host,
+               port,
+               app_id,
+               script=None,
+               application_host=None,
+               application_port=None,
+               application_root=None,
+               blobstore_path=None,
+               clear_datastore=None,
+               clear_prospective_search=None,
+               datastore_path=None,
+               enable_sendmail=None,
+               enable_task_running=None,
+               high_replication=None,
+               persist_logs=None,
+               prospective_search_path=None,
+               require_indexes=None,
+               show_mail_body=None,
+               smtp_host=None,
+               smtp_password=None,
+               smtp_port=None,
+               smtp_user=None,
+               task_retry_seconds=None,
+               trusted=None,
+               use_sqlite=None):
+    """Configures the APIs hosted by this server.
+
+    Args:
+      executable: The path of the executable to use when running the API Server
+          e.g. "/usr/bin/python".
+      host: The host name that should be used by the API Server e.g.
+          "localhost".
+      port: The port number that should be used by the API Server e.g. 8080.
+      app_id: The str application id e.g. "guestbook".
+      script: The name of the script that should be used, along with the
+          executable argument, to run the API Server e.g. "api_server.py".
+          If None then the executable is run without a script argument.
+      application_host: The name of the host where the development application
+          server is running e.g. "localhost".
+      application_port: The port where the application server is running e.g.
+          8000.
+      application_root: The path to the directory containing the user's
+          application e.g. "/home/bquinlan/myapp".
+      blobstore_path: The path to the file that should be used for blobstore
+          storage.
+      clear_datastore: Clears the file at datastore_path, emptying the
+          datastore from previous runs.
+      clear_prospective_search: Clears the file at prospective_search_path,
+          emptying the perspective search state from previous runs.
+      datastore_path: The path to the file that should be used for datastore
+          storage.
+      enable_sendmail: A bool indicating if sendmail should be used when sending
+          e-mails. This argument is ignored if mail_smtp_host is not None.
+      enable_task_running: A bool indicating whether taskqueue tasks should
+          be run automatically or it the must be manually triggered.
+      high_replication: A bool indicating whether to use the high replication
+          consistency model.
+      persist_logs: A bool indicating if request and application logs should be
+           persisted for later access.
+      prospective_search_path: The path to the file that should be used to
+          save prospective search subscriptions.
+      require_indexes: A bool indicating if the same production
+          datastore indexes requirements should be enforced i.e. if True then
+          a google.appengine.ext.db.NeedIndexError will be be raised if a query
+          is executed without the required indexes.
+      show_mail_body: A bool indicating whether the body of sent e-mails
+        should be written to the logs.
+      smtp_host: The SMTP hostname that should be used when sending e-mails.
+          If None then the enable_sendmail argument is considered.
+      smtp_password: The password to use when authenticating with the
+          SMTP server. This value may be None if smtp_host or smtp_user
+          is also None.
+      smtp_port: The SMTP port number that should be used when sending
+          e-mails. If this value is None then smtp_host must also be None.
+      smtp_user: The username to use when authenticating with the
+          SMTP server. This value may be None if smtp_host is also None or if
+          the SMTP server does not require authentication.
+      task_retry_seconds: An int representing the number of seconds to
+          wait before a retrying a failed taskqueue task.
+      trusted: A bool indicating if privileged APIs should be made available.
+      use_sqlite: A bool indicating whether DatastoreSqliteStub or
+          DatastoreFileStub should be used.
+    """
+    self._process = None
+    self._host = host
+    self._port = port
+    if script:
+      self._args = [executable, script]
+    else:
+      self._args = [executable]
+    self._BindArgument('--api_host', host)
+    self._BindArgument('--api_port', port)
+    self._BindArgument('--application_host', application_host)
+    self._BindArgument('--application_port', application_port)
+    self._BindArgument('--application_root', application_root)
+    self._BindArgument('--application', app_id)
+    self._BindArgument('--blobstore_path', blobstore_path)
+    self._BindArgument('--clear_datastore', clear_datastore)
+    self._BindArgument('--clear_prospective_search', clear_prospective_search)
+    self._BindArgument('--datastore_path', datastore_path)
+    self._BindArgument('--enable_sendmail', enable_sendmail)
+    self._BindArgument('--enable_task_running', enable_task_running)
+    self._BindArgument('--high_replication', high_replication)
+    self._BindArgument('--persist_logs', persist_logs)
+    self._BindArgument('--prospective_search_path', prospective_search_path)
+    self._BindArgument('--require_indexes', require_indexes)
+    self._BindArgument('--show_mail_body', show_mail_body)
+    self._BindArgument('--smtp_host', smtp_host)
+    self._BindArgument('--smtp_password', smtp_password)
+    self._BindArgument('--smtp_port', smtp_port)
+    self._BindArgument('--smtp_user', smtp_user)
+    self._BindArgument('--task_retry_seconds', task_retry_seconds)
+    self._BindArgument('--trusted', trusted)
+    self._BindArgument('--use_sqlite', use_sqlite)
+
+  @property
+  def url(self):
+    """Returns the URL that should be used to communicate with the server."""
+    return 'http://%s:%d' % (self._host, self._port)
+
+  def __repr__(self):
+    return '<APIServerProcess command=%r>' % ' '.join(self.args)
+
+  def Start(self):
+    """Starts the API Server process."""
+
+
+
+    assert not self._process, 'Start() can only be called once'
+    self._process = subprocess.Popen(self._args)
+
+  def _CanConnect(self):
+    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    try:
+      s.connect((self._host, self._port))
+    except socket.error:
+      connected = False
+    else:
+      connected = True
+    s.close()
+    return connected
+
+  def WaitUntilServing(self, timeout=30.0):
+    """Waits until the API Server is ready to handle requests.
+
+    Args:
+      timeout: The maximum number of seconds to wait for the server to be ready.
+
+    Raises:
+      Error: if the server process exits or is not ready in "timeout" seconds.
+    """
+    assert self._process, 'server was not started'
+    finish_time = time.time() + timeout
+    while time.time() < finish_time:
+      if self._process.poll() is not None:
+        raise Error('server has already exited with return: %r',
+                    self._process.returncode)
+      if self._CanConnect():
+        return
+      time.sleep(0.2)
+    raise Error('server did not start after %f seconds', timeout)
+
+  def _BindArgument(self, argument, value):
+    if value is not None:
+      self._args.append('%s=%s' % (argument, value))
+
+  def Quit(self, timeout=5.0):
+    """Causes the API Server process to exit.
+
+    Args:
+      timeout: The maximum number of seconds to wait for an orderly shutdown
+          before forceably killing the process.
+    """
+    assert self._process, 'server was not started'
+    if self._process.poll() is None:
+      try:
+        urllib2.urlopen(self.url + QUIT_PATH)
+      except urllib2.URLError:
+
+
+        pass
+
+      finish_time = time.time() + timeout
+      while time.time() < finish_time and self._process.poll() is None:
+        time.sleep(0.2)
+      if self._process.returncode is None:
+        logging.warning('api_server did not quit cleanly, killing')
+        self._process.kill()
+
+
+def main():
+  args = ParseCommandArguments(sys.argv[1:])
+
+  if args.clear_datastore:
+    _ClearDatastoreStorage(args.datastore_path)
+
+  if args.clear_prospective_search:
+    _ClearProspectiveSearchStorage(args.prospective_search_path)
+
+  if args.blobstore_path is None:
+    _, blobstore_temp_filename = tempfile.mkstemp(prefix='ae-blobstore')
+    args.blobstore_path = blobstore_temp_filename
+
+  if args.datastore_path is None:
+    _, datastore_temp_filename = tempfile.mkstemp(prefix='ae-datastore')
+    args.datastore_path = datastore_temp_filename
+
+  if args.prospective_search_path is None:
+    _, prospective_search_temp_filename = tempfile.mkstemp(
+        prefix='ae-prospective_search')
+    args.prospective_search_path = prospective_search_temp_filename
+
+  if args.application_host:
+    application_address = args.application_host
+    if args.application_port and args.application_port != 80:
+      application_address += ':' + str(args.application_port)
+  else:
+    application_address = None
+
+  _SetupStubs(app_id=args.application,
+              application_root=args.application_root,
+              trusted=args.trusted,
+              blobstore_path=args.blobstore_path,
+              datastore_path=args.datastore_path,
+              use_sqlite=args.use_sqlite,
+              high_replication=args.high_replication,
+              datastore_require_indexes=args.require_indexes,
+              images_host_prefix=application_address,
+              persist_logs=args.persist_logs,
+              mail_smtp_host=args.smtp_host,
+              mail_smtp_port=args.smtp_port,
+              mail_smtp_user=args.smtp_user,
+              mail_smtp_password=args.smtp_password,
+              mail_enable_sendmail=args.enable_sendmail,
+              mail_show_mail_body=args.show_mail_body,
+              matcher_prospective_search_path=args.prospective_search_path,
+              taskqueue_auto_run_tasks=args.enable_task_running,
+              taskqueue_task_retry_seconds=args.task_retry_seconds,
+              taskqueue_default_http_server=application_address,
+              user_login_url=args.user_login_url,
+              user_logout_url=args.user_logout_url)
+
+  server = APIServer((args.api_host, args.api_port), args.application)
+  server.serve_forever()
+
+
+if __name__ == '__main__':
+  try:
+    main()
+  except KeyboardInterrupt:
+    pass
diff --git a/google/appengine/tools/appcfg.py b/google/appengine/tools/appcfg.py
index d23c610..c11198d 100755
--- a/google/appengine/tools/appcfg.py
+++ b/google/appengine/tools/appcfg.py
@@ -66,6 +66,12 @@
 from google.appengine.api import yaml_object
 from google.appengine.datastore import datastore_index
 from google.appengine.tools import appengine_rpc
+try:
+
+
+  from google.appengine.tools import appengine_rpc_httplib2
+except ImportError:
+  appengine_rpc_httplib2 = None
 from google.appengine.tools import bulkloader
 
 
@@ -125,6 +131,24 @@
     'max_file_count': 10000,
 }
 
+# Client ID and secrets are managed in the Google API console.
+
+
+
+
+
+APPCFG_CLIENT_ID = '550516889912.apps.googleusercontent.com'
+APPCFG_CLIENT_NOTSOSECRET = 'ykPq-0UYfKNprLRjVx1hBBar'
+APPCFG_SCOPES = ['https://www.googleapis.com/auth/appengine.admin']
+
+
+class Error(Exception):
+  pass
+
+
+class OAuthNotAvailable(Error):
+  """The appengine_rpc_httplib2 module could not be imported."""
+
 
 def PrintUpdate(msg):
   """Print a message to stderr.
@@ -202,10 +226,7 @@
         else:
           regex = handler.upload
         if re.match(regex, filename):
-          if handler.mime_type is not None:
-            return handler.mime_type
-          else:
-            return FileClassification.__MimeType(filename)
+          return handler.mime_type or FileClassification.__MimeType(filename)
     return None
 
   @staticmethod
@@ -230,9 +251,8 @@
     for error_handler in config.error_handlers:
       if error_handler.file == filename:
         error_code = error_handler.error_code
-        if not error_code:
-          error_code = 'default'
-        if error_handler.mime_type is not None:
+        error_code = error_code or  'default'
+        if error_handler.mime_type:
           return (error_handler.mime_type, error_code)
         else:
           return (FileClassification.__MimeType(filename), error_code)
@@ -248,16 +268,16 @@
     return guess
 
   def IsApplicationFile(self):
-    return self.__static_mime_type is None and self.__error_mime_type is None
+    return not self.IsStaticFile() and not self.IsErrorFile()
 
   def IsStaticFile(self):
-    return self.__static_mime_type is not None
+    return bool(self.__static_mime_type)
 
   def StaticMimeType(self):
     return self.__static_mime_type
 
   def IsErrorFile(self):
-    return self.__error_mime_type is not None
+    return bool(self.__error_mime_type)
 
   def ErrorMimeType(self):
     return self.__error_mime_type
@@ -2088,7 +2108,7 @@
           file_length = GetFileLength(file_handle)
 
 
-          if max_size_override is not None:
+          if max_size_override:
             max_size = max_size_override
           elif file_classification.IsApplicationFile():
             max_size = resource_limits['max_file_size']
@@ -2327,7 +2347,7 @@
   """
 
   def __init__(self, argv, parser_class=optparse.OptionParser,
-               rpc_server_class=appengine_rpc.HttpRpcServer,
+               rpc_server_class=None,
                raw_input_fn=raw_input,
                password_input_fn=getpass.getpass,
                out_fh=sys.stdout,
@@ -2480,6 +2500,10 @@
     verbosity = self.options.verbose
 
 
+    if self.options.oauth2_refresh_token:
+      self.options.oauth2 = True
+
+
 
 
     self.opener = opener
@@ -2587,6 +2611,17 @@
     parser.add_option('-R', '--allow_any_runtime', action='store_true',
                       dest='allow_any_runtime', default=False,
                       help='Do not validate the runtime in app.yaml')
+    parser.add_option('--oauth2', action='store_true', dest='oauth2',
+                      default=False,
+                      help='Use OAuth2 instead of password auth.')
+    parser.add_option('--oauth2_refresh_token', action='store',
+                      dest='oauth2_refresh_token', default=None,
+                      help='An existing OAuth2 refresh token to use. Will '
+                      'not attempt interactive OAuth approval.')
+    parser.add_option('--noauth_local_webserver', action='store_false',
+                      dest='auth_local_webserver', default=True,
+                      help='Do not run a local web server to handle redirects '
+                      'during OAuth authorization.')
     return parser
 
   def _MakeSpecificParser(self, action):
@@ -2621,6 +2656,9 @@
 
     Returns:
       A new AbstractRpcServer, on which RPC calls can be made.
+
+    Raises:
+      OAuthNotAvailable: Oauth is requested but the dependecies aren't imported.
     """
 
     def GetUserCredentials():
@@ -2642,7 +2680,29 @@
     StatusUpdate('Host: %s' % self.options.server)
 
 
-    if self.options.host and self.options.host == 'localhost':
+
+    dev_appserver = self.options.host == 'localhost'
+    if self.options.oauth2 and not dev_appserver:
+      if not appengine_rpc_httplib2:
+
+        raise OAuthNotAvailable()
+      if not self.rpc_server_class:
+        self.rpc_server_class = appengine_rpc_httplib2.HttpRpcServerOauth2
+
+      get_user_credentials = self.options.oauth2_refresh_token
+
+      source = (APPCFG_CLIENT_ID, APPCFG_CLIENT_NOTSOSECRET, APPCFG_SCOPES)
+
+      appengine_rpc_httplib2.tools.FLAGS.auth_local_webserver = (
+          self.options.auth_local_webserver)
+    else:
+      if not self.rpc_server_class:
+        self.rpc_server_class = appengine_rpc.HttpRpcServer
+      get_user_credentials = GetUserCredentials
+      source = GetSourceName()
+
+
+    if dev_appserver:
       email = self.options.email
       if email is None:
         email = 'test@example.com'
@@ -2651,7 +2711,7 @@
           self.options.server,
           lambda: (email, 'password'),
           GetUserAgent(),
-          GetSourceName(),
+          source,
           host_override=self.options.host,
           save_cookies=self.options.save_cookies,
 
@@ -2666,8 +2726,8 @@
     else:
       auth_tries = 3
 
-    return self.rpc_server_class(self.options.server, GetUserCredentials,
-                                 GetUserAgent(), GetSourceName(),
+    return self.rpc_server_class(self.options.server, get_user_credentials,
+                                 GetUserAgent(), source,
                                  host_override=self.options.host,
                                  save_cookies=self.options.save_cookies,
                                  auth_tries=auth_tries,
@@ -3634,7 +3694,11 @@
                       ' is to be written. (Required)')
 
   def ResourceLimitsInfo(self, output=None):
-    """Outputs the current resource limits."""
+    """Outputs the current resource limits.
+
+    Args:
+      output: The file handle to write the output to (used for testing).
+    """
     appyaml = self._ParseAppYaml(self.basepath, includes=True)
     resource_limits = GetResourceLimits(self._GetRpcServer(), appyaml)
 
diff --git a/google/appengine/tools/appengine_rpc.py b/google/appengine/tools/appengine_rpc.py
index 5dcb34f..7934d17 100755
--- a/google/appengine/tools/appengine_rpc.py
+++ b/google/appengine/tools/appengine_rpc.py
@@ -124,6 +124,7 @@
       auth_tries: The number of times to attempt auth_function before failing.
       account_type: One of GOOGLE, HOSTED_OR_GOOGLE, or None for automatic.
       debug_data: Whether debugging output should include data contents.
+      secure: If the requests sent using Send should be sent over HTTPS.
       rpc_tries: The number of rpc retries upon http server error (i.e.
         Response code >= 500 and < 600) before failing.
     """
diff --git a/google/appengine/tools/appengine_rpc_httplib2.py b/google/appengine/tools/appengine_rpc_httplib2.py
new file mode 100644
index 0000000..a0e9524
--- /dev/null
+++ b/google/appengine/tools/appengine_rpc_httplib2.py
@@ -0,0 +1,375 @@
+#!/usr/bin/env python
+#
+# Copyright 2007 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+
+
+
+"""Library with a variant of appengine_rpc using httplib2.
+
+The httplib2 module offers some of the features in appengine_rpc, with
+one important one being a simple integration point for OAuth2 integration.
+"""
+
+
+
+
+import cStringIO
+import logging
+import os
+import re
+import urllib
+import urllib2
+
+
+import httplib2
+
+try:
+  from oauth2client import client
+  from oauth2client import file as oauth2client_file
+  from oauth2client import tools
+except ImportError:
+
+  from apiclient.oauth2client import client
+  from apiclient.oauth2client import file as oauth2client_file
+  from apiclient.oauth2client import tools
+
+logger = logging.getLogger('google.appengine.tools.appengine_rpc')
+
+
+class Error(Exception):
+  pass
+
+
+class AuthPermanentFail(Error):
+  """Authentication will not succeed in the current context."""
+
+
+class MemoryCache(object):
+  """httplib2 Cache implementation which only caches locally."""
+
+  def __init__(self):
+    self.cache = {}
+
+  def get(self, key):
+    return self.cache.get(key)
+
+  def set(self, key, value):
+    self.cache[key] = value
+
+  def delete(self, key):
+    self.cache.pop(key, None)
+
+
+def RaiseHttpError(url, response_info, response_body, extra_msg=''):
+  """Raise a urllib2.HTTPError based on an httplib2 response tuple."""
+  if response_body is not None:
+    stream = cStringIO.StringIO()
+    stream.write(response_body)
+    stream.seek(0)
+  else:
+    stream = None
+  if not extra_msg:
+    msg = response_info.reason
+  else:
+    msg = response_info.reason + ' ' + extra_msg
+  raise urllib2.HTTPError(url, response_info.status, msg, response_info, stream)
+
+
+class HttpRpcServerHttpLib2(object):
+  """A variant of HttpRpcServer which uses httplib2.
+
+  This follows the same interface as appengine_rpc.AbstractRpcServer,
+  but is a totally separate implementation.
+  """
+
+  def __init__(self, host, auth_function, user_agent, source,
+               host_override=None, extra_headers=None, save_cookies=False,
+               auth_tries=None, account_type=None, debug_data=True, secure=True,
+               rpc_tries=3):
+    """Creates a new HttpRpcServerHttpLib2.
+
+    Args:
+      host: The host to send requests to.
+      auth_function: Saved but ignored; may be used by subclasses.
+      user_agent: The user-agent string to send to the server. Specify None to
+        omit the user-agent header.
+      source: Saved but ignored; may be used by subclasses.
+      host_override: The host header to send to the server (defaults to host).
+      extra_headers: A dict of extra headers to append to every request. Values
+        supplied here will override other default headers that are supplied.
+      save_cookies: Saved but ignored; may be used by subclasses.
+      auth_tries: The number of times to attempt auth_function before failing.
+      account_type: Saved but ignored; may be used by subclasses.
+      debug_data: Whether debugging output should include data contents.
+      secure: If the requests sent using Send should be sent over HTTPS.
+      rpc_tries: The number of rpc retries upon http server error (i.e.
+        Response code >= 500 and < 600) before failing.
+    """
+    self.host = host
+    self.auth_function = auth_function
+    self.user_agent = user_agent
+    self.source = source
+    self.host_override = host_override
+    self.extra_headers = extra_headers
+    self.save_cookies = save_cookies
+    self.auth_tries = auth_tries
+    self.account_type = account_type
+    self.debug_data = debug_data
+    self.secure = secure
+    self.rpc_tries = rpc_tries
+    self.scheme = secure and 'https' or 'http'
+
+
+
+
+    self.certpath = os.path.normpath(os.path.join(
+        os.path.dirname(__file__), '..', '..', '..', 'lib', 'cacerts',
+        'cacerts.txt'))
+    self.cert_file_available = os.path.exists(self.certpath)
+
+    self.memory_cache = MemoryCache()
+
+  def _Authenticate(self, http, saw_error):
+    """Pre or Re-auth stuff...
+
+    Args:
+      http: An 'Http' object from httplib2.
+      saw_error: If the user has already tried to contact the server.
+        If they have, it's OK to prompt them. If not, we should not be asking
+        them for auth info--it's possible it'll suceed w/o auth.
+    """
+
+
+    raise NotImplementedError()
+
+  def Send(self, request_path, payload='',
+           content_type='application/octet-stream',
+           timeout=None,
+           **kwargs):
+    """Sends an RPC and returns the response.
+
+    Args:
+      request_path: The path to send the request to, eg /api/appversion/create.
+      payload: The body of the request, or None to send an empty request.
+      content_type: The Content-Type header to use.
+      timeout: timeout in seconds; default None i.e. no timeout.
+        (Note: for large requests on OS X, the timeout doesn't work right.)
+      Any keyword arguments are converted into query string parameters.
+
+    Returns:
+      The response body, as a string.
+
+    Raises:
+      AuthPermanentFail: If authorization failed in a permanent way.
+      urllib2.HTTPError: On most HTTP errors.
+    """
+
+
+
+
+
+
+
+
+
+    self.http = httplib2.Http(cache=self.memory_cache, ca_certs=self.certpath)
+    self.http.follow_redirects = False
+    self.http.timeout = timeout
+    url = '%s://%s%s' % (self.scheme, self.host, request_path)
+    if kwargs:
+      url += '?' + urllib.urlencode(kwargs)
+    headers = {}
+    if self.extra_headers:
+      headers.update(self.extra_headers)
+    headers['Content-Type'] = content_type
+
+
+
+    headers['X-appcfg-api-version'] = '1'
+
+    headers['content-length'] = str(len(payload))
+    if self.host_override:
+      headers['Host'] = self.host_override
+
+    tries = 0
+    auth_tries = [0]
+
+    def NeedAuth():
+      """Marker that we need auth; it'll actually be tried next time around."""
+      auth_tries[0] += 1
+      if auth_tries[0] > self.auth_tries:
+        RaiseHttpError(url, response_info, response, 'Too many auth attempts.')
+
+    while tries < self.rpc_tries:
+      tries += 1
+      self._Authenticate(self.http, auth_tries[0] > 0)
+      logger.debug('Sending request to %s headers=%s body=%s',
+                   url, headers,
+                   self.debug_data and payload or payload and 'ELIDED' or '')
+      try:
+        response_info, response = self.http.request(url, 'POST', body=payload,
+                                                    headers=headers)
+      except client.AccessTokenRefreshError, e:
+
+        logger.info('Got access token error', exc_info=1)
+        response_info = httplib2.Response({'status': 401})
+        response_info.reason = str(e)
+        response = ''
+
+      status = response_info.status
+      if status == 200:
+        return response
+      logger.debug('Got http error %s, this is try #%s',
+                   response_info.status, tries)
+      if status == 401:
+        NeedAuth()
+        continue
+      elif status >= 500 and status < 600:
+
+        continue
+      elif status == 302:
+
+
+        loc = response_info.get('location')
+        logger.debug('Got 302 redirect. Location: %s', loc)
+        if (loc.startswith('https://www.google.com/accounts/ServiceLogin') or
+            re.match(r'https://www.google.com/a/[a-z0-9.-]+/ServiceLogin',
+                     loc)):
+          NeedAuth()
+          continue
+        elif loc.startswith('http://%s/_ah/login' % (self.host,)):
+
+          RaiseHttpError(url, response_info, response,
+                         'dev_appserver login not supported')
+        else:
+          RaiseHttpError(url, response_info, response,
+                         'Unexpected redirect to %s' % loc)
+      else:
+        logger.debug('Unexpected results: %s', response_info)
+        RaiseHttpError(url, response_info, response,
+                       'Unexpected HTTP status %s' % status)
+    logging.info('Too many retries for url %s', url)
+    RaiseHttpError(url, response_info, response)
+
+
+class NoStorage(client.Storage):
+  """A no-op implementation of storage."""
+
+  def locked_get(self):
+    return None
+
+  def locked_put(self, credentials):
+    pass
+
+
+class HttpRpcServerOauth2(HttpRpcServerHttpLib2):
+  """A variant of HttpRpcServer which uses oauth2.
+
+  This variant is specifically meant for interactive command line usage,
+  as it will attempt to open a browser and ask the user to enter
+  information from the resulting web page.
+  """
+
+  def __init__(self, host, refresh_token, user_agent, source,
+               host_override=None, extra_headers=None, save_cookies=False,
+               auth_tries=None, account_type=None, debug_data=True, secure=True,
+               rpc_tries=3):
+    """Creates a new HttpRpcServerOauth2.
+
+    Args:
+      host: The host to send requests to.
+      refresh_token: A string refresh token to use, or None to guide the user
+        through the auth flow. (Replaces auth_function on parent class.)
+      user_agent: The user-agent string to send to the server. Specify None to
+        omit the user-agent header.
+      source: Tuple, (client_id, client_secret, scope), for oauth credentials.
+      host_override: The host header to send to the server (defaults to host).
+      extra_headers: A dict of extra headers to append to every request. Values
+        supplied here will override other default headers that are supplied.
+      save_cookies: If the refresh token should be saved.
+      auth_tries: The number of times to attempt auth_function before failing.
+      account_type: Ignored.
+      debug_data: Whether debugging output should include data contents.
+      secure: If the requests sent using Send should be sent over HTTPS.
+      rpc_tries: The number of rpc retries upon http server error (i.e.
+        Response code >= 500 and < 600) before failing.
+    """
+    super(HttpRpcServerOauth2, self).__init__(
+        host, None, user_agent, None, host_override=host_override,
+        extra_headers=extra_headers, auth_tries=auth_tries,
+        debug_data=debug_data, secure=secure, rpc_tries=rpc_tries)
+
+    if save_cookies:
+      self.storage = oauth2client_file.Storage(
+          os.path.expanduser('~/.appcfg_oauth2_tokens'))
+    else:
+      self.storage = NoStorage()
+
+    if not isinstance(source, tuple) or len(source) != 3:
+      raise TypeError('Source must be tuple (client_id, client_secret, scope).')
+
+    self.client_id = source[0]
+    self.client_secret = source[1]
+    self.scope = source[2]
+
+    self.refresh_token = refresh_token
+    if refresh_token:
+      self.credentials = client.OAuth2Credentials(
+          None, self.client_id, self.client_secret, refresh_token,
+          None, 'https://accounts.google.com/o/oauth2/token', self.user_agent)
+    else:
+      self.credentials = self.storage.get()
+
+  def _Authenticate(self, http, needs_auth):
+    """Pre or Re-auth stuff...
+
+    This will attempt to avoid making any OAuth related HTTP connections or
+    user interactions unless it's needed.
+
+    Args:
+      http: An 'Http' object from httplib2.
+      needs_auth: If the user has already tried to contact the server.
+        If they have, it's OK to prompt them. If not, we should not be asking
+        them for auth info--it's possible it'll suceed w/o auth, but if we have
+        some credentials we'll use them anyway.
+
+    Raises:
+      AuthPermanentFail: The user has requested non-interactive auth but
+        the token is invalid.
+    """
+    if needs_auth and (not self.credentials or self.credentials.invalid):
+      if self.refresh_token:
+
+        logger.debug('_Authenticate and skipping auth because user explicitly '
+                     'supplied a refresh token.')
+        raise AuthPermanentFail('Refresh token is invalid.')
+      logger.debug('_Authenticate and requesting auth')
+      flow = client.OAuth2WebServerFlow(
+          client_id=self.client_id,
+          client_secret=self.client_secret,
+          scope=self.scope,
+          user_agent=self.user_agent)
+      self.credentials = tools.run(flow, self.storage)
+    if self.credentials and not self.credentials.invalid:
+
+
+      if not self.credentials.access_token_expired or needs_auth:
+        logger.debug('_Authenticate configuring auth; needs_auth=%s',
+                     needs_auth)
+        self.credentials.authorize(http)
+        return
+    logger.debug('_Authenticate skipped auth; needs_auth=%s', needs_auth)
diff --git a/google/appengine/tools/boolean_action.py b/google/appengine/tools/boolean_action.py
new file mode 100644
index 0000000..59591fa
--- /dev/null
+++ b/google/appengine/tools/boolean_action.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+#
+# Copyright 2007 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+
+
+
+"""Provides a flexible way of configuring Boolean flags using argparse.
+
+This action behaves like the "store_const" action but allows the flag to accept
+an optional value.
+
+These syntaxes result a True value being assigned for the argument:
+--boolean_flag=yes    # "yes" is not case sensitive.
+--boolean_flag=true   # "true" is not case sensitive.
+
+These syntaxes result a False value being assigned for the argument:
+--boolean_flag=no     # "no" is not case sensitive.
+--boolean_flag=false  # "false" is not case sensitive.
+"""
+
+import google
+import argparse
+
+
+class BooleanAction(argparse.Action):
+
+  def __init__(self,
+               option_strings,
+               dest,
+               const,
+               default=None,
+               required=False,
+               help=None,
+               metavar=None):
+    super(BooleanAction, self).__init__(
+        option_strings=option_strings,
+        dest=dest,
+        nargs='?',
+        const=const,
+        default=default,
+        required=required,
+        help=help)
+
+  def __call__(self, parser, namespace, values, option_string=None):
+    if isinstance(values, bool):
+      value = values
+    elif values:
+      value = values.lower()
+      if value in ['true', 'yes']:
+        value = True
+      elif value in ['false', 'no']:
+        value = False
+      else:
+        raise ValueError('must be "yes" or "no", not %r' % values)
+    else:
+      value = True
+
+    setattr(namespace, self.dest, value)
diff --git a/google/appengine/tools/dev-channel-js.js b/google/appengine/tools/dev-channel-js.js
index dc1f99a..73ad08b 100755
--- a/google/appengine/tools/dev-channel-js.js
+++ b/google/appengine/tools/dev-channel-js.js
@@ -83,19 +83,6 @@
   }
   return s
 };
-goog.propertyIsEnumerableCustom_ = function(object, propName) {
-  if(propName in object) {
-    for(var key in object) {
-      if(key == propName && Object.prototype.hasOwnProperty.call(object, propName)) {
-        return!0
-      }
-    }
-  }
-  return!1
-};
-goog.propertyIsEnumerable_ = function(object, propName) {
-  return object instanceof Object ? Object.prototype.propertyIsEnumerable.call(object, propName) : goog.propertyIsEnumerableCustom_(object, propName)
-};
 goog.isDef = function(val) {
   return void 0 !== val
 };
@@ -128,8 +115,8 @@
   return"function" == goog.typeOf(val)
 };
 goog.isObject = function(val) {
-  var type = goog.typeOf(val);
-  return"object" == type || "array" == type || "function" == type
+  var type = typeof val;
+  return"object" == type && null != val || "function" == type
 };
 goog.getUid = function(obj) {
   return obj[goog.UID_PROPERTY_] || (obj[goog.UID_PROPERTY_] = ++goog.uidCounter_)
@@ -203,10 +190,7 @@
     goog.global.execScript(script, "JavaScript")
   }else {
     if(goog.global.eval) {
-      if(null == goog.evalWorksForGlobals_) {
-        goog.global.eval("var _et_ = 1;"), "undefined" != typeof goog.global._et_ ? (delete goog.global._et_, goog.evalWorksForGlobals_ = !0) : goog.evalWorksForGlobals_ = !1
-      }
-      if(goog.evalWorksForGlobals_) {
+      if(null == goog.evalWorksForGlobals_ && (goog.global.eval("var _et_ = 1;"), "undefined" != typeof goog.global._et_ ? (delete goog.global._et_, goog.evalWorksForGlobals_ = !0) : goog.evalWorksForGlobals_ = !1), goog.evalWorksForGlobals_) {
         goog.global.eval(script)
       }else {
         var doc = goog.global.document, scriptElt = doc.createElement("script");
@@ -284,30 +268,26 @@
   fn.call(goog.global)
 };
 goog.MODIFY_FUNCTION_PROTOTYPES = !0;
-if(goog.MODIFY_FUNCTION_PROTOTYPES) {
-  Function.prototype.bind = Function.prototype.bind || function(selfObj, var_args) {
-    if(1 < arguments.length) {
-      var args = Array.prototype.slice.call(arguments, 1);
-      args.unshift(this, selfObj);
-      return goog.bind.apply(null, args)
-    }
-    return goog.bind(this, selfObj)
-  }, Function.prototype.partial = function(var_args) {
-    var args = Array.prototype.slice.call(arguments);
-    args.unshift(this, null);
+goog.MODIFY_FUNCTION_PROTOTYPES && (Function.prototype.bind = Function.prototype.bind || function(selfObj, var_args) {
+  if(1 < arguments.length) {
+    var args = Array.prototype.slice.call(arguments, 1);
+    args.unshift(this, selfObj);
     return goog.bind.apply(null, args)
-  }, Function.prototype.inherits = function(parentCtor) {
-    goog.inherits(this, parentCtor)
-  }, Function.prototype.mixin = function(source) {
-    goog.mixin(this.prototype, source)
   }
-}
-;goog.debug = {};
+  return goog.bind(this, selfObj)
+}, Function.prototype.partial = function(var_args) {
+  var args = Array.prototype.slice.call(arguments);
+  args.unshift(this, null);
+  return goog.bind.apply(null, args)
+}, Function.prototype.inherits = function(parentCtor) {
+  goog.inherits(this, parentCtor)
+}, Function.prototype.mixin = function(source) {
+  goog.mixin(this.prototype, source)
+});
+goog.debug = {};
 goog.debug.Error = function(opt_msg) {
   this.stack = Error().stack || "";
-  if(opt_msg) {
-    this.message = "" + opt_msg
-  }
+  opt_msg && (this.message = "" + opt_msg)
 };
 goog.inherits(goog.debug.Error, Error);
 goog.debug.Error.prototype.name = "CustomError";
@@ -456,9 +436,7 @@
       var n = Number("0" + entity.substr(1));
       isNaN(n) || (value = String.fromCharCode(n))
     }
-    if(!value) {
-      div.innerHTML = s + " ", value = div.firstChild.nodeValue.slice(0, -1)
-    }
+    value || (div.innerHTML = s + " ", value = div.firstChild.nodeValue.slice(0, -1));
     return seen[s] = value
   })
 };
@@ -516,7 +494,7 @@
   opt_protectEscapedCharacters && (str = goog.string.htmlEscape(str));
   return str
 };
-goog.string.specialEscapeChars_ = {"\x00":"\\0", "\u0008":"\\b", "\u000c":"\\f", "\n":"\\n", "\r":"\\r", "\t":"\\t", "\u000b":"\\x0B", '"':'\\"', "\\":"\\\\"};
+goog.string.specialEscapeChars_ = {"\x00":"\\0", "\u0008":"\\b", "\u000c":"\\f", "\n":"\\n", "\r":"\\r", "\t":"\\t", "\x0B":"\\x0B", '"':'\\"', "\\":"\\\\"};
 goog.string.jsEscapeCache_ = {"'":"\\'"};
 goog.string.quote = function(s) {
   s = "" + s;
@@ -591,9 +569,7 @@
 };
 goog.string.padNumber = function(num, length, opt_precision) {
   var s = goog.isDef(opt_precision) ? num.toFixed(opt_precision) : "" + num, index = s.indexOf(".");
-  if(-1 == index) {
-    index = s.length
-  }
+  -1 == index && (index = s.length);
   return goog.string.repeat("0", Math.max(0, length - index)) + s
 };
 goog.string.makeSafe = function(obj) {
@@ -652,8 +628,7 @@
 goog.asserts.AssertionError = function(messagePattern, messageArgs) {
   messageArgs.unshift(messagePattern);
   goog.debug.Error.call(this, goog.string.subs.apply(null, messageArgs));
-  messageArgs.shift();
-  this.messagePattern = messagePattern
+  messageArgs.shift()
 };
 goog.inherits(goog.asserts.AssertionError, goog.debug.Error);
 goog.asserts.AssertionError.prototype.name = "AssertionError";
@@ -1067,11 +1042,9 @@
 goog.math.Coordinate.prototype.clone = function() {
   return new goog.math.Coordinate(this.x, this.y)
 };
-if(goog.DEBUG) {
-  goog.math.Coordinate.prototype.toString = function() {
-    return"(" + this.x + ", " + this.y + ")"
-  }
-}
+goog.DEBUG && (goog.math.Coordinate.prototype.toString = function() {
+  return"(" + this.x + ", " + this.y + ")"
+});
 goog.math.Coordinate.equals = function(a, b) {
   return a == b ? !0 : !a || !b ? !1 : a.x == b.x && a.y == b.y
 };
@@ -1099,11 +1072,9 @@
 goog.math.Size.prototype.clone = function() {
   return new goog.math.Size(this.width, this.height)
 };
-if(goog.DEBUG) {
-  goog.math.Size.prototype.toString = function() {
-    return"(" + this.width + " x " + this.height + ")"
-  }
-}
+goog.DEBUG && (goog.math.Size.prototype.toString = function() {
+  return"(" + this.width + " x " + this.height + ")"
+});
 goog.math.Size.prototype.area = function() {
   return this.width * this.height
 };
@@ -1410,7 +1381,7 @@
 };
 goog.userAgent.isDocumentModeCache_ = {};
 goog.userAgent.isDocumentMode = function(documentMode) {
-  return goog.userAgent.isDocumentModeCache_[documentMode] || (goog.userAgent.isDocumentModeCache_[documentMode] = goog.userAgent.IE && document.documentMode && document.documentMode >= documentMode)
+  return goog.userAgent.isDocumentModeCache_[documentMode] || (goog.userAgent.isDocumentModeCache_[documentMode] = goog.userAgent.IE && !!document.documentMode && document.documentMode >= documentMode)
 };
 goog.dom = {};
 goog.dom.BrowserFeature = {CAN_ADD_NAME_OR_TYPE_ATTRIBUTES:!goog.userAgent.IE || goog.userAgent.isDocumentMode(9), CAN_USE_CHILDREN_ATTRIBUTE:!goog.userAgent.GECKO && !goog.userAgent.IE || goog.userAgent.IE && goog.userAgent.isDocumentMode(9) || goog.userAgent.GECKO && goog.userAgent.isVersion("1.9.1"), CAN_USE_INNER_TEXT:goog.userAgent.IE && !goog.userAgent.isVersion("9"), CAN_USE_PARENT_ELEMENT_PROPERTY:goog.userAgent.IE || goog.userAgent.OPERA || goog.userAgent.WEBKIT, INNER_HTML_NEEDS_SCOPED_ELEMENT:goog.userAgent.IE};
@@ -1448,9 +1419,7 @@
   for(var classes = goog.dom.classes.get(element), removed = !1, i = 0;i < classes.length;i++) {
     classes[i] == fromClass && (goog.array.splice(classes, i--, 1), removed = !0)
   }
-  if(removed) {
-    classes.push(toClass), element.className = classes.join(" ")
-  }
+  removed && (classes.push(toClass), element.className = classes.join(" "));
   return removed
 };
 goog.dom.classes.addRemove = function(element, classesToRemove, classesToAdd) {
@@ -1470,9 +1439,9 @@
   goog.dom.classes.enable(element, className, add);
   return add
 };
-goog.dom.TagName = {A:"A", ABBR:"ABBR", ACRONYM:"ACRONYM", ADDRESS:"ADDRESS", APPLET:"APPLET", AREA:"AREA", B:"B", BASE:"BASE", BASEFONT:"BASEFONT", BDO:"BDO", BIG:"BIG", BLOCKQUOTE:"BLOCKQUOTE", BODY:"BODY", BR:"BR", BUTTON:"BUTTON", CANVAS:"CANVAS", CAPTION:"CAPTION", CENTER:"CENTER", CITE:"CITE", CODE:"CODE", COL:"COL", COLGROUP:"COLGROUP", DD:"DD", DEL:"DEL", DFN:"DFN", DIR:"DIR", DIV:"DIV", DL:"DL", DT:"DT", EM:"EM", FIELDSET:"FIELDSET", FONT:"FONT", FORM:"FORM", FRAME:"FRAME", FRAMESET:"FRAMESET", 
-H1:"H1", H2:"H2", H3:"H3", H4:"H4", H5:"H5", H6:"H6", HEAD:"HEAD", HR:"HR", HTML:"HTML", I:"I", IFRAME:"IFRAME", IMG:"IMG", INPUT:"INPUT", INS:"INS", ISINDEX:"ISINDEX", KBD:"KBD", LABEL:"LABEL", LEGEND:"LEGEND", LI:"LI", LINK:"LINK", MAP:"MAP", MENU:"MENU", META:"META", NOFRAMES:"NOFRAMES", NOSCRIPT:"NOSCRIPT", OBJECT:"OBJECT", OL:"OL", OPTGROUP:"OPTGROUP", OPTION:"OPTION", P:"P", PARAM:"PARAM", PRE:"PRE", Q:"Q", S:"S", SAMP:"SAMP", SCRIPT:"SCRIPT", SELECT:"SELECT", SMALL:"SMALL", SPAN:"SPAN", STRIKE:"STRIKE", 
-STRONG:"STRONG", STYLE:"STYLE", SUB:"SUB", SUP:"SUP", TABLE:"TABLE", TBODY:"TBODY", TD:"TD", TEXTAREA:"TEXTAREA", TFOOT:"TFOOT", TH:"TH", THEAD:"THEAD", TITLE:"TITLE", TR:"TR", TT:"TT", U:"U", UL:"UL", VAR:"VAR"};
+goog.dom.TagName = {A:"A", ABBR:"ABBR", ACRONYM:"ACRONYM", ADDRESS:"ADDRESS", APPLET:"APPLET", AREA:"AREA", AUDIO:"AUDIO", B:"B", BASE:"BASE", BASEFONT:"BASEFONT", BDO:"BDO", BIG:"BIG", BLOCKQUOTE:"BLOCKQUOTE", BODY:"BODY", BR:"BR", BUTTON:"BUTTON", CANVAS:"CANVAS", CAPTION:"CAPTION", CENTER:"CENTER", CITE:"CITE", CODE:"CODE", COL:"COL", COLGROUP:"COLGROUP", DD:"DD", DEL:"DEL", DFN:"DFN", DIR:"DIR", DIV:"DIV", DL:"DL", DT:"DT", EM:"EM", FIELDSET:"FIELDSET", FONT:"FONT", FORM:"FORM", FRAME:"FRAME", 
+FRAMESET:"FRAMESET", H1:"H1", H2:"H2", H3:"H3", H4:"H4", H5:"H5", H6:"H6", HEAD:"HEAD", HR:"HR", HTML:"HTML", I:"I", IFRAME:"IFRAME", IMG:"IMG", INPUT:"INPUT", INS:"INS", ISINDEX:"ISINDEX", KBD:"KBD", LABEL:"LABEL", LEGEND:"LEGEND", LI:"LI", LINK:"LINK", MAP:"MAP", MENU:"MENU", META:"META", NOFRAMES:"NOFRAMES", NOSCRIPT:"NOSCRIPT", OBJECT:"OBJECT", OL:"OL", OPTGROUP:"OPTGROUP", OPTION:"OPTION", P:"P", PARAM:"PARAM", PRE:"PRE", Q:"Q", S:"S", SAMP:"SAMP", SCRIPT:"SCRIPT", SELECT:"SELECT", SMALL:"SMALL", 
+SPAN:"SPAN", STRIKE:"STRIKE", STRONG:"STRONG", STYLE:"STYLE", SUB:"SUB", SUP:"SUP", TABLE:"TABLE", TBODY:"TBODY", TD:"TD", TEXTAREA:"TEXTAREA", TFOOT:"TFOOT", TH:"TH", THEAD:"THEAD", TITLE:"TITLE", TR:"TR", TT:"TT", U:"U", UL:"UL", VAR:"VAR", VIDEO:"VIDEO"};
 goog.dom.ASSUME_QUIRKS_MODE = !1;
 goog.dom.ASSUME_STANDARDS_MODE = !1;
 goog.dom.COMPAT_MODE_KNOWN_ = goog.dom.ASSUME_QUIRKS_MODE || goog.dom.ASSUME_STANDARDS_MODE;
@@ -1562,9 +1531,7 @@
       height = docEl.scrollHeight != vh ? docEl.scrollHeight : docEl.offsetHeight
     }else {
       var sh = docEl.scrollHeight, oh = docEl.offsetHeight;
-      if(docEl.clientHeight != oh) {
-        sh = body.scrollHeight, oh = body.offsetHeight
-      }
+      docEl.clientHeight != oh && (sh = body.scrollHeight, oh = body.offsetHeight);
       height = sh > vh ? sh > oh ? sh : oh : sh < oh ? sh : oh
     }
   }
@@ -1612,9 +1579,7 @@
     tagName = tagNameArr.join("")
   }
   var element = doc.createElement(tagName);
-  if(attributes) {
-    goog.isString(attributes) ? element.className = attributes : goog.isArray(attributes) ? goog.dom.classes.add.apply(null, [element].concat(attributes)) : goog.dom.setProperties(element, attributes)
-  }
+  attributes && (goog.isString(attributes) ? element.className = attributes : goog.isArray(attributes) ? goog.dom.classes.add.apply(null, [element].concat(attributes)) : goog.dom.setProperties(element, attributes));
   2 < args.length && goog.dom.append_(doc, element, args, 2);
   return element
 };
@@ -1949,10 +1914,7 @@
 goog.dom.findNodes_ = function(root, p, rv, findOne) {
   if(null != root) {
     for(var child = root.firstChild;child;) {
-      if(p(child) && (rv.push(child), findOne)) {
-        return!0
-      }
-      if(goog.dom.findNodes_(child, p, rv, findOne)) {
+      if(p(child) && (rv.push(child), findOne) || goog.dom.findNodes_(child, p, rv, findOne)) {
         return!0
       }
       child = child.nextSibling
@@ -2036,9 +1998,7 @@
       }
     }
   }
-  if(goog.isObject(opt_result)) {
-    opt_result.remainder = cur ? cur.nodeValue.length + offset - pos - 1 : 0, opt_result.node = cur
-  }
+  goog.isObject(opt_result) && (opt_result.remainder = cur ? cur.nodeValue.length + offset - pos - 1 : 0, opt_result.node = cur);
   return cur
 };
 goog.dom.isNodeList = function(val) {
@@ -2062,9 +2022,7 @@
   return goog.dom.getAncestorByTagNameAndClass(element, null, opt_class)
 };
 goog.dom.getAncestor = function(element, matcher, opt_includeNode, opt_maxSearchSteps) {
-  if(!opt_includeNode) {
-    element = element.parentNode
-  }
+  opt_includeNode || (element = element.parentNode);
   for(var ignoreSearchSteps = null == opt_maxSearchSteps, steps = 0;element && (ignoreSearchSteps || steps <= opt_maxSearchSteps);) {
     if(matcher(element)) {
       return element
@@ -2918,9 +2876,7 @@
 };
 goog.debug.enhanceError = function(err, opt_message) {
   var error = "string" == typeof err ? Error(err) : err;
-  if(!error.stack) {
-    error.stack = goog.debug.getStacktrace(arguments.callee.caller)
-  }
+  error.stack || (error.stack = goog.debug.getStacktrace(arguments.callee.caller));
   if(opt_message) {
     for(var x = 0;error["message" + x];) {
       ++x
@@ -3029,19 +2985,15 @@
 goog.debug.LogRecord = function(level, msg, loggerName, opt_time, opt_sequenceNumber) {
   this.reset(level, msg, loggerName, opt_time, opt_sequenceNumber)
 };
-goog.debug.LogRecord.prototype.sequenceNumber_ = 0;
 goog.debug.LogRecord.prototype.exception_ = null;
 goog.debug.LogRecord.prototype.exceptionText_ = null;
 goog.debug.LogRecord.ENABLE_SEQUENCE_NUMBERS = !0;
 goog.debug.LogRecord.nextSequenceNumber_ = 0;
 goog.debug.LogRecord.prototype.reset = function(level, msg, loggerName, opt_time, opt_sequenceNumber) {
-  if(goog.debug.LogRecord.ENABLE_SEQUENCE_NUMBERS) {
-    this.sequenceNumber_ = "number" == typeof opt_sequenceNumber ? opt_sequenceNumber : goog.debug.LogRecord.nextSequenceNumber_++
-  }
-  this.time_ = opt_time || goog.now();
+  goog.debug.LogRecord.ENABLE_SEQUENCE_NUMBERS && ("number" == typeof opt_sequenceNumber || goog.debug.LogRecord.nextSequenceNumber_++);
+  opt_time || goog.now();
   this.level_ = level;
   this.msg_ = msg;
-  this.loggerName_ = loggerName;
   delete this.exception_;
   delete this.exceptionText_
 };
@@ -3062,9 +3014,7 @@
   this.clear()
 };
 goog.debug.LogBuffer.getInstance = function() {
-  if(!goog.debug.LogBuffer.instance_) {
-    goog.debug.LogBuffer.instance_ = new goog.debug.LogBuffer
-  }
+  goog.debug.LogBuffer.instance_ || (goog.debug.LogBuffer.instance_ = new goog.debug.LogBuffer);
   return goog.debug.LogBuffer.instance_
 };
 goog.debug.LogBuffer.CAPACITY = 0;
@@ -3095,9 +3045,7 @@
 goog.debug.Logger.prototype.children_ = null;
 goog.debug.Logger.prototype.handlers_ = null;
 goog.debug.Logger.ENABLE_HIERARCHY = !0;
-if(!goog.debug.Logger.ENABLE_HIERARCHY) {
-  goog.debug.Logger.rootHandlers_ = []
-}
+goog.debug.Logger.ENABLE_HIERARCHY || (goog.debug.Logger.rootHandlers_ = []);
 goog.debug.Logger.Level = function(name, value) {
   this.name = name;
   this.value = value
@@ -3151,9 +3099,7 @@
   return this.parent_
 };
 goog.debug.Logger.prototype.getChildren = function() {
-  if(!this.children_) {
-    this.children_ = {}
-  }
+  this.children_ || (this.children_ = {});
   return this.children_
 };
 goog.debug.Logger.prototype.setLevel = function(level) {
@@ -3221,9 +3167,7 @@
 goog.debug.LogManager.loggers_ = {};
 goog.debug.LogManager.rootLogger_ = null;
 goog.debug.LogManager.initialize = function() {
-  if(!goog.debug.LogManager.rootLogger_) {
-    goog.debug.LogManager.rootLogger_ = new goog.debug.Logger(""), goog.debug.LogManager.loggers_[""] = goog.debug.LogManager.rootLogger_, goog.debug.LogManager.rootLogger_.setLevel(goog.debug.Logger.Level.CONFIG)
-  }
+  goog.debug.LogManager.rootLogger_ || (goog.debug.LogManager.rootLogger_ = new goog.debug.Logger(""), goog.debug.LogManager.loggers_[""] = goog.debug.LogManager.rootLogger_, goog.debug.LogManager.rootLogger_.setLevel(goog.debug.Logger.Level.CONFIG))
 };
 goog.debug.LogManager.getLoggers = function() {
   return goog.debug.LogManager.loggers_
@@ -3360,7 +3304,6 @@
 goog.events.BrowserEvent.prototype.altKey = !1;
 goog.events.BrowserEvent.prototype.shiftKey = !1;
 goog.events.BrowserEvent.prototype.metaKey = !1;
-goog.events.BrowserEvent.prototype.platformModifierKey = !1;
 goog.events.BrowserEvent.prototype.event_ = null;
 goog.events.BrowserEvent.prototype.init = function(e, opt_currentTarget) {
   var type = this.type = e.type;
@@ -3368,17 +3311,7 @@
   this.target = e.target || e.srcElement;
   this.currentTarget = opt_currentTarget;
   var relatedTarget = e.relatedTarget;
-  if(relatedTarget) {
-    goog.userAgent.GECKO && (goog.reflect.canAccessProperty(relatedTarget, "nodeName") || (relatedTarget = null))
-  }else {
-    if(type == goog.events.EventType.MOUSEOVER) {
-      relatedTarget = e.fromElement
-    }else {
-      if(type == goog.events.EventType.MOUSEOUT) {
-        relatedTarget = e.toElement
-      }
-    }
-  }
+  relatedTarget ? goog.userAgent.GECKO && (goog.reflect.canAccessProperty(relatedTarget, "nodeName") || (relatedTarget = null)) : type == goog.events.EventType.MOUSEOVER ? relatedTarget = e.fromElement : type == goog.events.EventType.MOUSEOUT && (relatedTarget = e.toElement);
   this.relatedTarget = relatedTarget;
   this.offsetX = goog.userAgent.WEBKIT || void 0 !== e.offsetX ? e.offsetX : e.layerX;
   this.offsetY = goog.userAgent.WEBKIT || void 0 !== e.offsetY ? e.offsetY : e.layerY;
@@ -3393,7 +3326,6 @@
   this.altKey = e.altKey;
   this.shiftKey = e.shiftKey;
   this.metaKey = e.metaKey;
-  this.platformModifierKey = goog.userAgent.MAC ? e.metaKey : e.ctrlKey;
   this.state = e.state;
   this.event_ = e;
   delete this.returnValue_;
@@ -3776,10 +3708,7 @@
         retval = goog.events.fireListener(listener, evt)
       }
     }finally {
-      if(ancestors) {
-        ancestors.length = 0
-      }
-      evt.dispose()
+      ancestors && (ancestors.length = 0), evt.dispose()
     }
     return retval
   }
@@ -3901,7 +3830,7 @@
       throw Error("Unknown type: " + typeof object);
   }
 };
-goog.json.Serializer.charToJsonCharCache_ = {'"':'\\"', "\\":"\\\\", "/":"\\/", "\u0008":"\\b", "\u000c":"\\f", "\n":"\\n", "\r":"\\r", "\t":"\\t", "\u000b":"\\u000b"};
+goog.json.Serializer.charToJsonCharCache_ = {'"':'\\"', "\\":"\\\\", "/":"\\/", "\u0008":"\\b", "\u000c":"\\f", "\n":"\\n", "\r":"\\r", "\t":"\\t", "\x0B":"\\u000b"};
 goog.json.Serializer.charsToReplace_ = /\uffff/.test("\uffff") ? /[\\\"\x00-\x1f\x7f-\uffff]/g : /[\\\"\x00-\x1f\x7f-\xff]/g;
 goog.json.Serializer.prototype.serializeString_ = function(s, sb) {
   sb.push('"', s.replace(goog.json.Serializer.charsToReplace_, function(c) {
@@ -3958,13 +3887,7 @@
 goog.Timer.prototype.tick_ = function() {
   if(this.enabled) {
     var elapsed = goog.now() - this.last_;
-    if(0 < elapsed && elapsed < this.interval_ * goog.Timer.intervalScale) {
-      this.timer_ = this.timerObject_.setTimeout(this.boundTick_, this.interval_ - elapsed)
-    }else {
-      if(this.dispatchTick(), this.enabled) {
-        this.timer_ = this.timerObject_.setTimeout(this.boundTick_, this.interval_), this.last_ = goog.now()
-      }
-    }
+    0 < elapsed && elapsed < this.interval_ * goog.Timer.intervalScale ? this.timer_ = this.timerObject_.setTimeout(this.boundTick_, this.interval_ - elapsed) : (this.dispatchTick(), this.enabled && (this.timer_ = this.timerObject_.setTimeout(this.boundTick_, this.interval_), this.last_ = goog.now()))
   }
 };
 goog.Timer.prototype.dispatchTick = function() {
@@ -3972,15 +3895,11 @@
 };
 goog.Timer.prototype.start = function() {
   this.enabled = !0;
-  if(!this.timer_) {
-    this.timer_ = this.timerObject_.setTimeout(this.boundTick_, this.interval_), this.last_ = goog.now()
-  }
+  this.timer_ || (this.timer_ = this.timerObject_.setTimeout(this.boundTick_, this.interval_), this.last_ = goog.now())
 };
 goog.Timer.prototype.stop = function() {
   this.enabled = !1;
-  if(this.timer_) {
-    this.timerObject_.clearTimeout(this.timer_), this.timer_ = null
-  }
+  this.timer_ && (this.timerObject_.clearTimeout(this.timer_), this.timer_ = null)
 };
 goog.Timer.prototype.disposeInternal = function() {
   goog.Timer.superClass_.disposeInternal.call(this);
@@ -4018,8 +3937,25 @@
 goog.uri.utils.splitRe_ = RegExp("^(?:([^:/?#.]+):)?(?://(?:([^/?#]*)@)?([\\w\\d\\-\\u0100-\\uffff.%]*)(?::([0-9]+))?)?([^?#]+)?(?:\\?([^#]*))?(?:#(.*))?$");
 goog.uri.utils.ComponentIndex = {SCHEME:1, USER_INFO:2, DOMAIN:3, PORT:4, PATH:5, QUERY_DATA:6, FRAGMENT:7};
 goog.uri.utils.split = function(uri) {
+  goog.uri.utils.phishingProtection_();
   return uri.match(goog.uri.utils.splitRe_)
 };
+goog.uri.utils.needsPhishingProtection_ = goog.userAgent.WEBKIT;
+goog.uri.utils.phishingProtection_ = function() {
+  if(goog.uri.utils.needsPhishingProtection_) {
+    goog.uri.utils.needsPhishingProtection_ = !1;
+    var location = goog.global.location;
+    if(location) {
+      var href = location.href;
+      if(href) {
+        var domain = goog.uri.utils.getDomain(href);
+        if(domain && domain != location.hostname) {
+          throw goog.uri.utils.needsPhishingProtection_ = !0, Error();
+        }
+      }
+    }
+  }
+};
 goog.uri.utils.decodeIfPossible_ = function(uri) {
   return uri && decodeURIComponent(uri)
 };
@@ -4346,7 +4282,6 @@
 goog.net.XhrIo.prototype.xhrOptions_ = null;
 goog.net.XhrIo.prototype.lastUri_ = "";
 goog.net.XhrIo.prototype.lastMethod_ = "";
-goog.net.XhrIo.prototype.lastErrorCode_ = goog.net.ErrorCode.NO_ERROR;
 goog.net.XhrIo.prototype.lastError_ = "";
 goog.net.XhrIo.prototype.errorDispatched_ = !1;
 goog.net.XhrIo.prototype.inSend_ = !1;
@@ -4366,7 +4301,6 @@
   var method = opt_method ? opt_method.toUpperCase() : "GET";
   this.lastUri_ = url;
   this.lastError_ = "";
-  this.lastErrorCode_ = goog.net.ErrorCode.NO_ERROR;
   this.lastMethod_ = method;
   this.errorDispatched_ = !1;
   this.active_ = !0;
@@ -4388,23 +4322,10 @@
   goog.structs.forEach(headers, function(value, key) {
     this.xhr_.setRequestHeader(key, value)
   }, this);
-  if(this.responseType_) {
-    this.xhr_.responseType = this.responseType_
-  }
-  if(goog.object.containsKey(this.xhr_, "withCredentials")) {
-    this.xhr_.withCredentials = this.withCredentials_
-  }
+  this.responseType_ && (this.xhr_.responseType = this.responseType_);
+  goog.object.containsKey(this.xhr_, "withCredentials") && (this.xhr_.withCredentials = this.withCredentials_);
   try {
-    if(this.timeoutId_) {
-      goog.Timer.defaultTimerObject.clearTimeout(this.timeoutId_), this.timeoutId_ = null
-    }
-    if(0 < this.timeoutInterval_) {
-      this.logger_.fine(this.formatMsg_("Will abort after " + this.timeoutInterval_ + "ms if incomplete")), this.timeoutId_ = goog.Timer.defaultTimerObject.setTimeout(goog.bind(this.timeout_, this), this.timeoutInterval_)
-    }
-    this.logger_.fine(this.formatMsg_("Sending request"));
-    this.inSend_ = !0;
-    this.xhr_.send(content);
-    this.inSend_ = !1
+    this.timeoutId_ && (goog.Timer.defaultTimerObject.clearTimeout(this.timeoutId_), this.timeoutId_ = null), 0 < this.timeoutInterval_ && (this.logger_.fine(this.formatMsg_("Will abort after " + this.timeoutInterval_ + "ms if incomplete")), this.timeoutId_ = goog.Timer.defaultTimerObject.setTimeout(goog.bind(this.timeout_, this), this.timeoutInterval_)), this.logger_.fine(this.formatMsg_("Sending request")), this.inSend_ = !0, this.xhr_.send(content), this.inSend_ = !1
   }catch(err$$0) {
     this.logger_.fine(this.formatMsg_("Send error: " + err$$0.message)), this.error_(goog.net.ErrorCode.EXCEPTION, err$$0)
   }
@@ -4413,37 +4334,23 @@
   return this.xmlHttpFactory_ ? this.xmlHttpFactory_.createInstance() : goog.net.XmlHttp()
 };
 goog.net.XhrIo.prototype.timeout_ = function() {
-  if("undefined" != typeof goog && this.xhr_) {
-    this.lastError_ = "Timed out after " + this.timeoutInterval_ + "ms, aborting", this.lastErrorCode_ = goog.net.ErrorCode.TIMEOUT, this.logger_.fine(this.formatMsg_(this.lastError_)), this.dispatchEvent(goog.net.EventType.TIMEOUT), this.abort(goog.net.ErrorCode.TIMEOUT)
-  }
+  "undefined" != typeof goog && this.xhr_ && (this.lastError_ = "Timed out after " + this.timeoutInterval_ + "ms, aborting", this.logger_.fine(this.formatMsg_(this.lastError_)), this.dispatchEvent(goog.net.EventType.TIMEOUT), this.abort(goog.net.ErrorCode.TIMEOUT))
 };
 goog.net.XhrIo.prototype.error_ = function(errorCode, err) {
   this.active_ = !1;
-  if(this.xhr_) {
-    this.inAbort_ = !0, this.xhr_.abort(), this.inAbort_ = !1
-  }
+  this.xhr_ && (this.inAbort_ = !0, this.xhr_.abort(), this.inAbort_ = !1);
   this.lastError_ = err;
-  this.lastErrorCode_ = errorCode;
   this.dispatchErrors_();
   this.cleanUpXhr_()
 };
 goog.net.XhrIo.prototype.dispatchErrors_ = function() {
-  if(!this.errorDispatched_) {
-    this.errorDispatched_ = !0, this.dispatchEvent(goog.net.EventType.COMPLETE), this.dispatchEvent(goog.net.EventType.ERROR)
-  }
+  this.errorDispatched_ || (this.errorDispatched_ = !0, this.dispatchEvent(goog.net.EventType.COMPLETE), this.dispatchEvent(goog.net.EventType.ERROR))
 };
-goog.net.XhrIo.prototype.abort = function(opt_failureCode) {
-  if(this.xhr_ && this.active_) {
-    this.logger_.fine(this.formatMsg_("Aborting")), this.active_ = !1, this.inAbort_ = !0, this.xhr_.abort(), this.inAbort_ = !1, this.lastErrorCode_ = opt_failureCode || goog.net.ErrorCode.ABORT, this.dispatchEvent(goog.net.EventType.COMPLETE), this.dispatchEvent(goog.net.EventType.ABORT), this.cleanUpXhr_()
-  }
+goog.net.XhrIo.prototype.abort = function() {
+  this.xhr_ && this.active_ && (this.logger_.fine(this.formatMsg_("Aborting")), this.active_ = !1, this.inAbort_ = !0, this.xhr_.abort(), this.inAbort_ = !1, this.dispatchEvent(goog.net.EventType.COMPLETE), this.dispatchEvent(goog.net.EventType.ABORT), this.cleanUpXhr_())
 };
 goog.net.XhrIo.prototype.disposeInternal = function() {
-  if(this.xhr_) {
-    if(this.active_) {
-      this.active_ = !1, this.inAbort_ = !0, this.xhr_.abort(), this.inAbort_ = !1
-    }
-    this.cleanUpXhr_(!0)
-  }
+  this.xhr_ && (this.active_ && (this.active_ = !1, this.inAbort_ = !0, this.xhr_.abort(), this.inAbort_ = !1), this.cleanUpXhr_(!0));
   goog.net.XhrIo.superClass_.disposeInternal.call(this)
 };
 goog.net.XhrIo.prototype.onReadyStateChange_ = function() {
@@ -4457,27 +4364,14 @@
   this.onReadyStateChangeHelper_()
 };
 goog.net.XhrIo.prototype.onReadyStateChangeHelper_ = function() {
-  if(this.active_ && "undefined" != typeof goog) {
-    if(this.xhrOptions_[goog.net.XmlHttp.OptionType.LOCAL_REQUEST_ERROR] && this.getReadyState() == goog.net.XmlHttp.ReadyState.COMPLETE && 2 == this.getStatus()) {
-      this.logger_.fine(this.formatMsg_("Local request error detected and ignored"))
-    }else {
-      if(this.inSend_ && this.getReadyState() == goog.net.XmlHttp.ReadyState.COMPLETE) {
-        goog.Timer.defaultTimerObject.setTimeout(goog.bind(this.onReadyStateChange_, this), 0)
-      }else {
-        if(this.dispatchEvent(goog.net.EventType.READY_STATE_CHANGE), this.isComplete()) {
-          this.logger_.fine(this.formatMsg_("Request complete")), this.active_ = !1, this.isSuccess() ? (this.dispatchEvent(goog.net.EventType.COMPLETE), this.dispatchEvent(goog.net.EventType.SUCCESS)) : (this.lastErrorCode_ = goog.net.ErrorCode.HTTP_ERROR, this.lastError_ = this.getStatusText() + " [" + this.getStatus() + "]", this.dispatchErrors_()), this.cleanUpXhr_()
-        }
-      }
-    }
-  }
+  this.active_ && "undefined" != typeof goog && (this.xhrOptions_[goog.net.XmlHttp.OptionType.LOCAL_REQUEST_ERROR] && this.getReadyState() == goog.net.XmlHttp.ReadyState.COMPLETE && 2 == this.getStatus() ? this.logger_.fine(this.formatMsg_("Local request error detected and ignored")) : this.inSend_ && this.getReadyState() == goog.net.XmlHttp.ReadyState.COMPLETE ? goog.Timer.defaultTimerObject.setTimeout(goog.bind(this.onReadyStateChange_, this), 0) : (this.dispatchEvent(goog.net.EventType.READY_STATE_CHANGE), 
+  this.isComplete() && (this.logger_.fine(this.formatMsg_("Request complete")), this.active_ = !1, this.isSuccess() ? (this.dispatchEvent(goog.net.EventType.COMPLETE), this.dispatchEvent(goog.net.EventType.SUCCESS)) : (this.lastError_ = this.getStatusText() + " [" + this.getStatus() + "]", this.dispatchErrors_()), this.cleanUpXhr_())))
 };
 goog.net.XhrIo.prototype.cleanUpXhr_ = function(opt_fromDispose) {
   if(this.xhr_) {
     var xhr = this.xhr_, clearedOnReadyStateChange = this.xhrOptions_[goog.net.XmlHttp.OptionType.USE_NULL_FUNCTION] ? goog.nullFunction : null;
     this.xhrOptions_ = this.xhr_ = null;
-    if(this.timeoutId_) {
-      goog.Timer.defaultTimerObject.clearTimeout(this.timeoutId_), this.timeoutId_ = null
-    }
+    this.timeoutId_ && (goog.Timer.defaultTimerObject.clearTimeout(this.timeoutId_), this.timeoutId_ = null);
     opt_fromDispose || this.dispatchEvent(goog.net.EventType.READY);
     try {
       xhr.onreadystatechange = clearedOnReadyStateChange
@@ -4937,9 +4831,7 @@
   return this.encodedQuery_ = sb.join("")
 };
 goog.Uri.QueryData.prototype.toDecodedString = function() {
-  if(!this.decodedQuery_) {
-    this.decodedQuery_ = goog.Uri.decodeOrEmpty_(this.toString())
-  }
+  this.decodedQuery_ || (this.decodedQuery_ = goog.Uri.decodeOrEmpty_(this.toString()));
   return this.decodedQuery_
 };
 goog.Uri.QueryData.prototype.invalidateCache_ = function() {
@@ -4949,15 +4841,9 @@
 };
 goog.Uri.QueryData.prototype.clone = function() {
   var rv = new goog.Uri.QueryData;
-  if(this.decodedQuery_) {
-    rv.decodedQuery_ = this.decodedQuery_
-  }
-  if(this.encodedQuery_) {
-    rv.encodedQuery_ = this.encodedQuery_
-  }
-  if(this.keyMap_) {
-    rv.keyMap_ = this.keyMap_.clone()
-  }
+  this.decodedQuery_ && (rv.decodedQuery_ = this.decodedQuery_);
+  this.encodedQuery_ && (rv.encodedQuery_ = this.encodedQuery_);
+  this.keyMap_ && (rv.keyMap_ = this.keyMap_.clone());
   return rv
 };
 goog.Uri.QueryData.prototype.getKeyName_ = function(arg) {
@@ -4998,7 +4884,6 @@
   this.onmessage = handler.onmessage;
   this.onerror = handler.onerror;
   this.onclose = handler.onclose;
-  this.doc_ = goog.dom.getDocument();
   this.win_ = goog.dom.getWindow();
   goog.net.XhrIo.send(this.getUrl_("connect"), goog.bind(this.connect_, this));
   goog.events.listen(this.win_, "beforeunload", goog.bind(this.beforeunload_, this));
diff --git a/google/appengine/tools/dev_appserver.py b/google/appengine/tools/dev_appserver.py
index 66b9535..9566ee1 100755
--- a/google/appengine/tools/dev_appserver.py
+++ b/google/appengine/tools/dev_appserver.py
@@ -142,7 +142,6 @@
 from google.appengine.tools import dev_appserver_channel
 from google.appengine.tools import dev_appserver_blobimage
 from google.appengine.tools import dev_appserver_import_hook
-from google.appengine.tools import dev_appserver_index
 from google.appengine.tools import dev_appserver_login
 from google.appengine.tools import dev_appserver_oauth
 from google.appengine.tools import dev_appserver_multiprocess as multiprocess
@@ -2464,7 +2463,6 @@
 
 def CreateRequestHandler(root_path,
                          login_url,
-                         require_indexes=False,
                          static_caching=True,
                          default_partition=None,
                          persist_logs=False):
@@ -2480,7 +2478,6 @@
   Args:
     root_path: Path to the root of the application running on the server.
     login_url: Relative URL which should be used for handling user logins.
-    require_indexes: True if index.yaml is read-only gospel; default False.
     static_caching: True if browser caching of static files should be allowed.
     default_partition: Default partition to use in the application id.
 
@@ -2510,14 +2507,6 @@
   application_module_dict = SetupSharedModules(sys.modules)
 
 
-  if require_indexes:
-
-    index_yaml_updater = None
-  else:
-
-    index_yaml_updater = dev_appserver_index.IndexYamlUpdater(root_path)
-
-
   application_config_cache = AppConfigCache()
 
   class DevAppServerRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
@@ -2756,9 +2745,6 @@
                                        [implicit_matcher, explicit_matcher])
 
 
-        dev_appserver_index.SetupIndexes(config.application, root_path)
-
-
 
 
         if multiprocess.GlobalProcess().HandleRequest(self):
@@ -2864,11 +2850,6 @@
         except socket.error, e:
           if len(e.args) >= 1 and e.args[0] != errno.EPIPE:
             raise e
-        else:
-          if index_yaml_updater is not None:
-
-
-            index_yaml_updater.UpdateIndexYaml()
 
     def log_error(self, format, *args):
       """Redirect error messages through the logging module."""
@@ -3288,11 +3269,11 @@
     if use_sqlite:
       datastore = datastore_sqlite_stub.DatastoreSqliteStub(
           app_id, datastore_path, require_indexes=require_indexes,
-          trusted=trusted)
+          trusted=trusted, root_path=root_path)
     else:
       datastore = datastore_file_stub.DatastoreFileStub(
           app_id, datastore_path, require_indexes=require_indexes,
-          trusted=trusted)
+          trusted=trusted, root_path=root_path)
 
     if high_replication:
       datastore.SetConsistencyPolicy(
@@ -3312,17 +3293,15 @@
             task_retry_seconds=task_retry_seconds,
             default_http_server='%s:%s' % (serve_address, serve_port)))
 
-    if mysql_user:
 
 
 
-      from google.appengine import api
-      sys.modules['google.appengine.api.rdbms'] = rdbms_mysqldb
-      api.rdbms = rdbms_mysqldb
-      rdbms_mysqldb.SetConnectKwargs(host=mysql_host, port=mysql_port,
-                                     user=mysql_user, passwd=mysql_password,
-                                     unix_socket=mysql_socket)
-      rdbms_mysqldb.connect(database='')
+  from google.appengine import api
+  sys.modules['google.appengine.api.rdbms'] = rdbms_mysqldb
+  api.rdbms = rdbms_mysqldb
+  rdbms_mysqldb.SetConnectKwargs(host=mysql_host, port=mysql_port,
+                                 user=mysql_user, passwd=mysql_password,
+                                 unix_socket=mysql_socket)
 
   fixed_login_url = '%s?%s=%%s' % (login_url,
                                    dev_appserver_login.CONTINUE_PARAM)
@@ -3449,17 +3428,6 @@
   path_adjuster = create_path_adjuster(root_path)
 
 
-  if multiprocess.GlobalProcess().IsApiServer():
-    remote_api_dispatcher = create_cgi_dispatcher(
-        config, module_dict, root_path, path_adjuster)
-    url_matcher.AddURL(multiprocess.PATH_DEV_API_SERVER,
-                       remote_api_dispatcher,
-                       REMOTE_API_PATH,
-                       False,
-                       False,
-                       appinfo.AUTH_FAIL_ACTION_REDIRECT)
-
-
 
 
   login_dispatcher = create_local_dispatcher(config, sys.modules, path_adjuster,
@@ -3534,7 +3502,6 @@
                  port,
                  template_dir=None,
                  serve_address='',
-                 require_indexes=False,
                  allow_skipped_files=False,
                  static_caching=True,
                  python_path_list=sys.path,
@@ -3555,7 +3522,6 @@
     port: Port to start the application server on.
     template_dir: Unused.
     serve_address: Address on which the server should serve.
-    require_indexes: True if index.yaml is read-only gospel; default False.
     allow_skipped_files: True if skipped files should be accessible.
     static_caching: True if browser caching of static files should be allowed.
     python_path_list: Used for dependency injection.
@@ -3577,7 +3543,6 @@
 
   handler_class = CreateRequestHandler(absolute_root_path,
                                        login_url,
-                                       require_indexes,
                                        static_caching,
                                        default_partition,
                                        persist_logs)
diff --git a/google/appengine/tools/dev_appserver_index.py b/google/appengine/tools/dev_appserver_index.py
index 3856f28..a64e7fd 100755
--- a/google/appengine/tools/dev_appserver_index.py
+++ b/google/appengine/tools/dev_appserver_index.py
@@ -26,313 +26,8 @@
 
 
 
-import os
-import logging
-
 from google.appengine.api import apiproxy_stub_map
-from google.appengine.api import datastore_admin
-from google.appengine.api import yaml_errors
-from google.appengine.datastore import datastore_index
-from google.appengine.datastore import entity_pb
+from google.appengine.datastore.datastore_stub_index import *
 
-import yaml
-
-
-AUTO_MARKER = '\n# AUTOGENERATED\n'
-
-
-AUTO_COMMENT = '''
-# This index.yaml is automatically updated whenever the dev_appserver
-# detects that a new type of query is run.  If you want to manage the
-# index.yaml file manually, remove the above marker line (the line
-# saying "# AUTOGENERATED").  If you want to manage some indexes
-# manually, move them above the marker line.  The index.yaml file is
-# automatically uploaded to the admin console when you next deploy
-# your application using appcfg.py.
-'''
-
-
-def GenerateIndexFromHistory(query_history,
-                             all_indexes=None, manual_indexes=None):
-  """Generate most of the text for index.yaml from the query history.
-
-  Args:
-    query_history: Query history, a dict mapping query
-    all_indexes: Optional datastore_index.IndexDefinitions instance
-      representing all the indexes found in the input file.  May be None.
-    manual_indexes: Optional datastore_index.IndexDefinitions instance
-      containing indexes for which we should not generate output.  May be None.
-
-  Returns:
-    A string representation that can safely be appended to an existing
-    index.yaml file. Returns the empty string if it would generate no output.
-  """
-
-
-
-
-
-  all_keys = datastore_index.IndexDefinitionsToKeys(all_indexes)
-  manual_keys = datastore_index.IndexDefinitionsToKeys(manual_indexes)
-
-
-  indexes = dict((key, 0) for key in all_keys - manual_keys)
-
-
-  for query, count in query_history.iteritems():
-    required, kind, ancestor, props, num_eq_filters = datastore_index.CompositeIndexForQuery(query)
-    if required:
-      key = (kind, ancestor, props)
-      if key not in manual_keys:
-        if key in indexes:
-          indexes[key] += count
-        else:
-          indexes[key] = count
-
-  if not indexes:
-    return ''
-
-
-
-
-  res = []
-  for (kind, ancestor, props), count in sorted(indexes.iteritems()):
-
-    res.append('')
-    res.append(datastore_index.IndexYamlForQuery(kind, ancestor, props))
-
-  res.append('')
-  return '\n'.join(res)
-
-
-class IndexYamlUpdater(object):
-  """Helper class for updating index.yaml.
-
-  This class maintains some state about the query history and the
-  index.yaml file in order to minimize the number of times index.yaml
-  is actually overwritten.
-  """
-
-
-  index_yaml_is_manual = False
-  index_yaml_mtime = None
-  last_history_size = 0
-
-  def __init__(self, root_path):
-    """Constructor.
-
-    Args:
-      root_path: Path to the app's root directory.
-    """
-    self.root_path = root_path
-
-  def UpdateIndexYaml(self, openfile=open):
-    """Update index.yaml.
-
-    Args:
-      openfile: Used for dependency injection.
-
-    We only ever write to index.yaml if either:
-    - it doesn't exist yet; or
-    - it contains an 'AUTOGENERATED' comment.
-
-    All indexes *before* the AUTOGENERATED comment will be written
-    back unchanged.  All indexes *after* the AUTOGENERATED comment
-    will be updated with the latest query counts (query counts are
-    reset by --clear_datastore).  Indexes that aren't yet in the file
-    will be appended to the AUTOGENERATED section.
-
-    We keep track of some data in order to avoid doing repetitive work:
-    - if index.yaml is fully manual, we keep track of its mtime to
-      avoid parsing it over and over;
-    - we keep track of the number of keys in the history dict since
-      the last time we updated index.yaml (or decided there was
-      nothing to update).
-    """
-
-    index_yaml_file = os.path.join(self.root_path, 'index.yaml')
-
-
-    try:
-      index_yaml_mtime = os.path.getmtime(index_yaml_file)
-    except os.error:
-      index_yaml_mtime = None
-
-
-    index_yaml_changed = (index_yaml_mtime != self.index_yaml_mtime)
-    self.index_yaml_mtime = index_yaml_mtime
-
-
-    datastore_stub = apiproxy_stub_map.apiproxy.GetStub('datastore_v3')
-    query_history = datastore_stub.QueryHistory()
-    history_changed = (len(query_history) != self.last_history_size)
-    self.last_history_size = len(query_history)
-
-
-    if not (index_yaml_changed or history_changed):
-      logging.debug('No need to update index.yaml')
-      return
-
-
-    if self.index_yaml_is_manual and not index_yaml_changed:
-      logging.debug('Will not update manual index.yaml')
-      return
-
-
-    if index_yaml_mtime is None:
-      index_yaml_data = None
-    else:
-      try:
-
-
-
-        fh = open(index_yaml_file, 'rU')
-      except IOError:
-        index_yaml_data = None
-      else:
-        try:
-          index_yaml_data = fh.read()
-        finally:
-          fh.close()
-
-
-    self.index_yaml_is_manual = (index_yaml_data is not None and
-                                 AUTO_MARKER not in index_yaml_data)
-    if self.index_yaml_is_manual:
-      logging.info('Detected manual index.yaml, will not update')
-      return
-
-
-
-    if index_yaml_data is None:
-      all_indexes = None
-    else:
-      try:
-        all_indexes = datastore_index.ParseIndexDefinitions(index_yaml_data)
-      except yaml_errors.EventListenerError, e:
-
-        logging.error('Error parsing %s:\n%s', index_yaml_file, e)
-        return
-      except Exception, err:
-
-        logging.error('Error parsing %s:\n%s.%s: %s', index_yaml_file,
-                      err.__class__.__module__, err.__class__.__name__, err)
-        return
-
-
-    if index_yaml_data is None:
-      manual_part, automatic_part = 'indexes:\n', ''
-      manual_indexes = None
-    else:
-      manual_part, automatic_part = index_yaml_data.split(AUTO_MARKER, 1)
-
-      try:
-        manual_indexes = datastore_index.ParseIndexDefinitions(manual_part)
-      except Exception, err:
-        logging.error('Error parsing manual part of %s: %s',
-                      index_yaml_file, err)
-        return
-
-
-    automatic_part = GenerateIndexFromHistory(query_history,
-                                              all_indexes, manual_indexes)
-
-
-
-    if index_yaml_mtime is None and automatic_part == '':
-      logging.debug('No need to update index.yaml')
-      return
-
-
-    try:
-      fh = openfile(index_yaml_file, 'w')
-    except IOError, err:
-      logging.error('Can\'t write index.yaml: %s', err)
-      return
-
-
-    try:
-      logging.info('Updating %s', index_yaml_file)
-      fh.write(manual_part)
-      fh.write(AUTO_MARKER)
-      fh.write(AUTO_COMMENT)
-      fh.write(automatic_part)
-    finally:
-      fh.close()
-
-
-    try:
-      self.index_yaml_mtime = os.path.getmtime(index_yaml_file)
-    except os.error, err:
-      logging.error('Can\'t stat index.yaml we just wrote: %s', err)
-      self.index_yaml_mtime = None
-
-
-_cached_yaml = (None, None, None)
-
-def SetupIndexes(app_id, root_path):
-  """Ensure that the set of existing composite indexes matches index.yaml.
-
-  Note: this is similar to the algorithm used by the admin console for
-  the same purpose.
-
-  Args:
-    app_id: Application ID being served.
-    root_path: Path to the root of the application.
-  """
-  index_yaml_file = os.path.join(root_path, 'index.yaml')
-  global _cached_yaml
-  if _cached_yaml[0] == index_yaml_file and os.path.exists(index_yaml_file) and os.path.getmtime(index_yaml_file) == _cached_yaml[1]:
-    requested_indexes = _cached_yaml[2]
-  else:
-    try:
-      index_yaml_mtime = os.path.getmtime(index_yaml_file)
-      fh = open(index_yaml_file, 'r')
-    except (OSError, IOError):
-      index_yaml_data = None
-    else:
-      try:
-        index_yaml_data = fh.read()
-      finally:
-        fh.close()
-
-    requested_indexes = []
-    if index_yaml_data is not None:
-
-      index_defs = datastore_index.ParseIndexDefinitions(index_yaml_data)
-      if index_defs is not None and index_defs.indexes is not None:
-
-        requested_indexes = datastore_index.IndexDefinitionsToProtos(app_id,
-            index_defs.indexes)
-        _cached_yaml = (index_yaml_file, index_yaml_mtime, requested_indexes)
-
-
-  existing_indexes = datastore_admin.GetIndices(app_id)
-
-
-  requested = dict((x.definition().Encode(), x) for x in requested_indexes)
-  existing = dict((x.definition().Encode(), x) for x in existing_indexes)
-
-
-  created = 0
-  for key, index in requested.iteritems():
-    if key not in existing:
-      new_index = entity_pb.CompositeIndex()
-      new_index.CopyFrom(index)
-      id = datastore_admin.CreateIndex(new_index)
-      new_index.set_id(id)
-      new_index.set_state(entity_pb.CompositeIndex.READ_WRITE)
-      datastore_admin.UpdateIndex(new_index)
-      created += 1
-
-
-  deleted = 0
-  for key, index in existing.iteritems():
-    if key not in requested:
-      datastore_admin.DeleteIndex(index)
-      deleted += 1
-
-
-  if created or deleted:
-    logging.info("Created %d and deleted %d index(es); total %d",
-                 created, deleted, len(requested))
+def SetupIndexes(unused_app_id, unused_root_path):
+  apiproxy_stub_map.apiproxy.GetStub('datastore_v3')._SetupIndexes()
diff --git a/google/appengine/tools/dev_appserver_main.py b/google/appengine/tools/dev_appserver_main.py
index 979e889..fd31020 100755
--- a/google/appengine/tools/dev_appserver_main.py
+++ b/google/appengine/tools/dev_appserver_main.py
@@ -613,7 +613,6 @@
   port = option_dict[ARG_PORT]
   login_url = option_dict[ARG_LOGIN_URL]
   address = option_dict[ARG_ADDRESS]
-  require_indexes = option_dict[ARG_REQUIRE_INDEXES]
   allow_skipped_files = option_dict[ARG_ALLOW_SKIPPED_FILES]
   static_caching = option_dict[ARG_STATIC_CACHING]
   persist_logs = option_dict[ARG_PERSIST_LOGS]
@@ -649,7 +648,6 @@
       port,
       sdk_dir=SDK_PATH,
       serve_address=address,
-      require_indexes=require_indexes,
       allow_skipped_files=allow_skipped_files,
       static_caching=static_caching,
       default_partition=default_partition,
diff --git a/google/appengine/tools/dev_appserver_multiprocess.py b/google/appengine/tools/dev_appserver_multiprocess.py
index d4168d3..0d22232 100644
--- a/google/appengine/tools/dev_appserver_multiprocess.py
+++ b/google/appengine/tools/dev_appserver_multiprocess.py
@@ -55,6 +55,7 @@
 from google.appengine.api import backendinfo
 from google.appengine.api.backends import backends as backends_api
 from google.appengine.ext.remote_api import remote_api_stub
+from google.appengine.tools import api_server
 
 ARG_ADDRESS = 'address'
 ARG_PORT = 'port'
@@ -103,7 +104,6 @@
   def __init__(self,
                host,
                port,
-               api_server=False,
                app_instance=None,
                backend_id=None,
                instance_id=None):
@@ -113,13 +113,11 @@
     backend_id is specified).
 
     Args:
-      api_server: (bool) The process represents the multiprocess API Server.
       app_instance: (int) The process represents the indicated app instance.
       backend_id: (string) The process represents a backend.
       instance_id: (int) The process represents the given backend instance.
     """
 
-    self.api_server = api_server
     self.app_instance = app_instance
     self.backend_id = backend_id
     self.instance_id = instance_id
@@ -130,9 +128,7 @@
     self.SetHostPort(host, port)
 
   def __str__(self):
-    if self.api_server:
-      string = 'Remote API Server'
-    elif self.app_instance is not None:
+    if self.app_instance is not None:
       string = 'App Instance'
     elif self.instance_id is not None:
       string = 'Backend Instance: %s.%d' % (self.backend_id, self.instance_id)
@@ -177,8 +173,6 @@
     self.SetFlag('--port', short_flag='-p', value=self.port)
     self.SetFlag('--multiprocess_api_port', value=self.api_port)
 
-    if self.api_server:
-      self.SetFlag('--multiprocess_api_server')
     if self.app_instance is not None:
       self.SetFlag('--multiprocess_app_instance_id', value=0)
     if self.backend_id is not None:
@@ -326,12 +320,10 @@
   """Represents a process in the multiprocess dev_appserver."""
 
   TYPE_MASTER = 'Master'
-  TYPE_API_SERVER = 'Remote API Server'
   TYPE_APP_INSTANCE = 'App Instance'
   TYPE_BACKEND_BALANCER = 'Backend Balancer'
   TYPE_BACKEND_INSTANCE = 'Backend Instance'
   TYPES = frozenset([TYPE_MASTER,
-                     TYPE_API_SERVER,
                      TYPE_APP_INSTANCE,
                      TYPE_BACKEND_BALANCER,
                      TYPE_BACKEND_INSTANCE])
@@ -412,8 +404,6 @@
     self.port = options[ARG_PORT]
 
 
-    if ARG_MULTIPROCESS_API_SERVER in options:
-      self.SetType(DevProcess.TYPE_API_SERVER)
     if ARG_MULTIPROCESS_APP_INSTANCE_ID in options:
       self.SetType(DevProcess.TYPE_APP_INSTANCE)
       self.app_instance = options[ARG_MULTIPROCESS_APP_INSTANCE_ID]
@@ -433,9 +423,6 @@
     if ARG_MULTIPROCESS_MIN_PORT in options:
       self.multiprocess_min_port = int(options[ARG_MULTIPROCESS_MIN_PORT])
 
-    if self.IsApiServer():
-      assert self.port == self.api_port
-
     if self.IsBackend():
       self.InitBackendEntry()
 
@@ -470,7 +457,7 @@
     self.handle_requests = HandleRequestThread()
     self.handle_requests.start()
 
-  def StartChildren(self, argv):
+  def StartChildren(self, argv, options):
     """Starts the set of child processes."""
     self.children = []
 
@@ -504,18 +491,42 @@
     next_port = base_port
 
 
-    self.child_api_server = ChildProcess(self.host, next_port, api_server=True)
-    self.children.append(self.child_api_server)
+    self.child_api_server = api_server.APIServerProcess(
+        executable=sys.executable,
+        script=os.path.join(os.path.dirname(argv[0]), 'api_server.py'),
+        host=self.host,
+        port=next_port,
+        app_id=self.app_id,
+        application_host=options['address'],
+        application_port=options['port'],
+        application_root=options['root_path'],
+        blobstore_path=options['blobstore_path'],
+        clear_datastore=options['clear_datastore'],
+        clear_prospective_search=options['clear_prospective_search'],
+        datastore_path=options['datastore_path'],
+        enable_sendmail=options['enable_sendmail'],
+        enable_task_running=not options['disable_task_running'],
+        high_replication=options['high_replication'],
+        persist_logs=options['persist_logs'],
+        prospective_search_path=options['prospective_search_path'],
+        require_indexes=options['require_indexes'],
+        show_mail_body=options['show_mail_body'],
+        smtp_host=options['smtp_host'],
+        smtp_password=options['smtp_password'],
+        smtp_port=options['smtp_port'],
+        smtp_user=options['smtp_user'],
+        task_retry_seconds=options['task_retry_seconds'],
+        trusted=options['trusted'],
+        use_sqlite=options['use_sqlite'],
+        )
+    self.child_api_server.Start()
 
 
     if self.multiprocess_min_port == 0:
       self.AssignPortsRandomly()
 
 
-    self.child_api_server.host = API_SERVER_HOST
-
-
-    self.api_port = self.child_api_server.port
+    self.api_port = next_port
 
 
 
@@ -523,12 +534,16 @@
       child.Start(argv, self.api_port)
 
 
-    for child in self.children:
+    self.child_api_server.WaitUntilServing()
 
+    for child in self.children:
       child.WaitForConnection()
 
 
+
+
     message = '\n\nMultiprocess Setup Complete:'
+    message += '\n  Remote API Server [%s]' % self.child_api_server.url
     for child in self.children:
       message += '\n  %s' % child
     message += '\n'
@@ -577,10 +592,6 @@
     """Indicates that this is a subprocessess of the dev_appserver."""
     return not (self.IsDefault() or self.IsMaster())
 
-  def IsApiServer(self):
-    """Indicates whether this is the api server process."""
-    return self.Type() == DevProcess.TYPE_API_SERVER
-
   def IsAppInstance(self):
     """Indicates whether this process represents an application instance."""
     return self.Type() == DevProcess.TYPE_APP_INSTANCE
@@ -651,14 +662,15 @@
     Otherwise, set up the stubs for data based APIs as remote stubs pointing at
     the to the API server and return True.
     """
-    if self.IsDefault() or self.IsApiServer():
+    if self.IsDefault():
       return False
 
+
     services = ['datastore_v3', 'memcache', 'taskqueue']
     remote_api_stub.ConfigureRemoteApi(
         self.app_id, PATH_DEV_API_SERVER, lambda: ('', ''),
         servername='%s:%d' % (API_SERVER_HOST, self.api_port),
-        services=services)
+        services=services, use_remote_datastore=False)
     return True
 
   def NewAppInfo(self, appinfo):
@@ -719,10 +731,6 @@
 
       ForwardRequestThread(request, client_address).start()
       return
-    elif self.IsApiServer():
-
-      HandleRequestDirectly(request, client_address)
-      return
 
     assert self.IsAppInstance() or self.IsBackendInstance()
 
@@ -1003,6 +1011,8 @@
   else:
     PosixShutdown()
 
+  dev_process.child_api_server.Quit()
+
 
 def SetLogPrefix(prefix):
   """Adds a prefix to the log handler to identify the process.
@@ -1087,7 +1097,7 @@
 
   SetLogPrefix(process)
   if process.IsMaster():
-    process.StartChildren(argv)
+    process.StartChildren(argv, options)
 
   process.InitBalanceSet()
 
diff --git a/google/net/proto2/proto/descriptor_pb2.py b/google/net/proto2/proto/descriptor_pb2.py
index fa1a07e..826f8b7 100755
--- a/google/net/proto2/proto/descriptor_pb2.py
+++ b/google/net/proto2/proto/descriptor_pb2.py
@@ -27,7 +27,7 @@
 DESCRIPTOR = descriptor.FileDescriptor(
   name='net/proto2/proto/descriptor.proto',
   package='proto2',
-  serialized_pb='\n!net/proto2/proto/descriptor.proto\x12\x06proto2\">\n\x11\x46ileDescriptorSet\x12)\n\x04\x66ile\x18\x01 \x03(\x0b\x32\x1b.proto2.FileDescriptorProto\"\xfc\x02\n\x13\x46ileDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07package\x18\x02 \x01(\t\x12\x12\n\ndependency\x18\x03 \x03(\t\x12\x19\n\x11public_dependency\x18\n \x03(\x05\x12-\n\x0cmessage_type\x18\x04 \x03(\x0b\x32\x17.proto2.DescriptorProto\x12.\n\tenum_type\x18\x05 \x03(\x0b\x32\x1b.proto2.EnumDescriptorProto\x12/\n\x07service\x18\x06 \x03(\x0b\x32\x1e.proto2.ServiceDescriptorProto\x12/\n\textension\x18\x07 \x03(\x0b\x32\x1c.proto2.FieldDescriptorProto\x12$\n\x07options\x18\x08 \x01(\x0b\x32\x13.proto2.FileOptions\x12\x30\n\x10source_code_info\x18\t \x01(\x0b\x32\x16.proto2.SourceCodeInfo\"\xf3\x02\n\x0f\x44\x65scriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12+\n\x05\x66ield\x18\x02 \x03(\x0b\x32\x1c.proto2.FieldDescriptorProto\x12/\n\textension\x18\x06 \x03(\x0b\x32\x1c.proto2.FieldDescriptorProto\x12,\n\x0bnested_type\x18\x03 \x03(\x0b\x32\x17.proto2.DescriptorProto\x12.\n\tenum_type\x18\x04 \x03(\x0b\x32\x1b.proto2.EnumDescriptorProto\x12?\n\x0f\x65xtension_range\x18\x05 \x03(\x0b\x32&.proto2.DescriptorProto.ExtensionRange\x12\'\n\x07options\x18\x07 \x01(\x0b\x32\x16.proto2.MessageOptions\x1a,\n\x0e\x45xtensionRange\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\"\xf9\x04\n\x14\x46ieldDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x03 \x01(\x05\x12\x31\n\x05label\x18\x04 \x01(\x0e\x32\".proto2.FieldDescriptorProto.Label\x12/\n\x04type\x18\x05 \x01(\x0e\x32!.proto2.FieldDescriptorProto.Type\x12\x11\n\ttype_name\x18\x06 \x01(\t\x12\x10\n\x08\x65xtendee\x18\x02 \x01(\t\x12\x15\n\rdefault_value\x18\x07 \x01(\t\x12%\n\x07options\x18\x08 \x01(\x0b\x32\x14.proto2.FieldOptions\"\xb6\x02\n\x04Type\x12\x0f\n\x0bTYPE_DOUBLE\x10\x01\x12\x0e\n\nTYPE_FLOAT\x10\x02\x12\x0e\n\nTYPE_INT64\x10\x03\x12\x0f\n\x0bTYPE_UINT64\x10\x04\x12\x0e\n\nTYPE_INT32\x10\x05\x12\x10\n\x0cTYPE_FIXED64\x10\x06\x12\x10\n\x0cTYPE_FIXED32\x10\x07\x12\r\n\tTYPE_BOOL\x10\x08\x12\x0f\n\x0bTYPE_STRING\x10\t\x12\x0e\n\nTYPE_GROUP\x10\n\x12\x10\n\x0cTYPE_MESSAGE\x10\x0b\x12\x0e\n\nTYPE_BYTES\x10\x0c\x12\x0f\n\x0bTYPE_UINT32\x10\r\x12\r\n\tTYPE_ENUM\x10\x0e\x12\x11\n\rTYPE_SFIXED32\x10\x0f\x12\x11\n\rTYPE_SFIXED64\x10\x10\x12\x0f\n\x0bTYPE_SINT32\x10\x11\x12\x0f\n\x0bTYPE_SINT64\x10\x12\"C\n\x05Label\x12\x12\n\x0eLABEL_OPTIONAL\x10\x01\x12\x12\n\x0eLABEL_REQUIRED\x10\x02\x12\x12\n\x0eLABEL_REPEATED\x10\x03\"z\n\x13\x45numDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12/\n\x05value\x18\x02 \x03(\x0b\x32 .proto2.EnumValueDescriptorProto\x12$\n\x07options\x18\x03 \x01(\x0b\x32\x13.proto2.EnumOptions\"c\n\x18\x45numValueDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x02 \x01(\x05\x12)\n\x07options\x18\x03 \x01(\x0b\x32\x18.proto2.EnumValueOptions\"\xad\x01\n\x16ServiceDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12-\n\x06method\x18\x02 \x03(\x0b\x32\x1d.proto2.MethodDescriptorProto\x12-\n\x06stream\x18\x04 \x03(\x0b\x32\x1d.proto2.StreamDescriptorProto\x12\'\n\x07options\x18\x03 \x01(\x0b\x32\x16.proto2.ServiceOptions\"v\n\x15MethodDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\ninput_type\x18\x02 \x01(\t\x12\x13\n\x0boutput_type\x18\x03 \x01(\t\x12&\n\x07options\x18\x04 \x01(\x0b\x32\x15.proto2.MethodOptions\"\x87\x01\n\x15StreamDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x1b\n\x13\x63lient_message_type\x18\x02 \x01(\t\x12\x1b\n\x13server_message_type\x18\x03 \x01(\t\x12&\n\x07options\x18\x04 \x01(\x0b\x32\x15.proto2.StreamOptions\"\xd0\x07\n\x0b\x46ileOptions\x12\x19\n\x0e\x63\x63_api_version\x18\x02 \x01(\x05:\x01\x32\x12V\n\x14\x63\x63_api_compatibility\x18\x0f \x01(\x0e\x32&.proto2.FileOptions.CompatibilityLevel:\x10NO_COMPATIBILITY\x12\x14\n\x0cjava_package\x18\x01 \x01(\t\x12\x19\n\x0epy_api_version\x18\x04 \x01(\x05:\x01\x32\x12\x1b\n\x10java_api_version\x18\x05 \x01(\x05:\x01\x32\x12!\n\x13java_use_javaproto2\x18\x06 \x01(\x08:\x04true\x12\x1e\n\x10java_java5_enums\x18\x07 \x01(\x08:\x04true\x12)\n\x1ajava_generate_rpc_baseimpl\x18\r \x01(\x08:\x05\x66\x61lse\x12#\n\x14java_use_javastrings\x18\x15 \x01(\x08:\x05\x66\x61lse\x12\x1c\n\x14java_alt_api_package\x18\x13 \x01(\t\x12\x1c\n\x14java_outer_classname\x18\x08 \x01(\t\x12\"\n\x13java_multiple_files\x18\n \x01(\x08:\x05\x66\x61lse\x12,\n\x1djava_generate_equals_and_hash\x18\x14 \x01(\x08:\x05\x66\x61lse\x12=\n\x0coptimize_for\x18\t \x01(\x0e\x32 .proto2.FileOptions.OptimizeMode:\x05SPEED\x12\x12\n\ngo_package\x18\x0b \x01(\t\x12\x1a\n\x12javascript_package\x18\x0c \x01(\t\x12\x1a\n\x0fszl_api_version\x18\x0e \x01(\x05:\x01\x31\x12\"\n\x13\x63\x63_generic_services\x18\x10 \x01(\x08:\x05\x66\x61lse\x12$\n\x15java_generic_services\x18\x11 \x01(\x08:\x05\x66\x61lse\x12\"\n\x13py_generic_services\x18\x12 \x01(\x08:\x05\x66\x61lse\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption\"c\n\x12\x43ompatibilityLevel\x12\x14\n\x10NO_COMPATIBILITY\x10\x00\x12\x15\n\x11PROTO1_COMPATIBLE\x10\x64\x12 \n\x1c\x44\x45PRECATED_PROTO1_COMPATIBLE\x10\x32\":\n\x0cOptimizeMode\x12\t\n\x05SPEED\x10\x01\x12\r\n\tCODE_SIZE\x10\x02\x12\x10\n\x0cLITE_RUNTIME\x10\x03*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xaf\x01\n\x0eMessageOptions\x12&\n\x17message_set_wire_format\x18\x01 \x01(\x08:\x05\x66\x61lse\x12.\n\x1fno_standard_descriptor_accessor\x18\x02 \x01(\x08:\x05\x66\x61lse\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xee\x03\n\x0c\x46ieldOptions\x12\x31\n\x05\x63type\x18\x01 \x01(\x0e\x32\x1a.proto2.FieldOptions.CType:\x06STRING\x12\x0e\n\x06packed\x18\x02 \x01(\x08\x12\x31\n\x05jtype\x18\x04 \x01(\x0e\x32\x1a.proto2.FieldOptions.JType:\x06NORMAL\x12\x36\n\x06jstype\x18\x06 \x01(\x0e\x32\x1b.proto2.FieldOptions.JSType:\tJS_NORMAL\x12\x13\n\x04lazy\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x1c\n\x14\x65xperimental_map_key\x18\t \x01(\t\x12\x13\n\x04weak\x18\n \x01(\x08:\x05\x66\x61lse\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption\"/\n\x05\x43Type\x12\n\n\x06STRING\x10\x00\x12\x08\n\x04\x43ORD\x10\x01\x12\x10\n\x0cSTRING_PIECE\x10\x02\"\x1e\n\x05JType\x12\n\n\x06NORMAL\x10\x00\x12\t\n\x05\x42YTES\x10\x01\"5\n\x06JSType\x12\r\n\tJS_NORMAL\x10\x00\x12\r\n\tJS_STRING\x10\x01\x12\r\n\tJS_NUMBER\x10\x02*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x84\x01\n\x0b\x45numOptions\x12\x13\n\x0bproto1_name\x18\x01 \x01(\t\x12\x19\n\x0b\x61llow_alias\x18\x02 \x01(\x08:\x04true\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"Y\n\x10\x45numValueOptions\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x9b\x01\n\x0eServiceOptions\x12\x1d\n\x0emulticast_stub\x18\x14 \x01(\x08:\x05\x66\x61lse\x12#\n\x17\x66\x61ilure_detection_delay\x18\x10 \x01(\x01:\x02-1\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xcd\x05\n\rMethodOptions\x12\x35\n\x08protocol\x18\x07 \x01(\x0e\x32\x1e.proto2.MethodOptions.Protocol:\x03TCP\x12\x14\n\x08\x64\x65\x61\x64line\x18\x08 \x01(\x01:\x02-1\x12$\n\x15\x64uplicate_suppression\x18\t \x01(\x08:\x05\x66\x61lse\x12\x18\n\tfail_fast\x18\n \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0e\x63lient_logging\x18\x0b \x01(\x11:\x03\x32\x35\x36\x12\x1b\n\x0eserver_logging\x18\x0c \x01(\x11:\x03\x32\x35\x36\x12\x41\n\x0esecurity_level\x18\r \x01(\x0e\x32#.proto2.MethodOptions.SecurityLevel:\x04NONE\x12\x43\n\x0fresponse_format\x18\x0f \x01(\x0e\x32\x1c.proto2.MethodOptions.Format:\x0cUNCOMPRESSED\x12\x42\n\x0erequest_format\x18\x11 \x01(\x0e\x32\x1c.proto2.MethodOptions.Format:\x0cUNCOMPRESSED\x12\x13\n\x0bstream_type\x18\x12 \x01(\t\x12\x16\n\x0esecurity_label\x18\x13 \x01(\t\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption\"\x1c\n\x08Protocol\x12\x07\n\x03TCP\x10\x00\x12\x07\n\x03UDP\x10\x01\"e\n\rSecurityLevel\x12\x08\n\x04NONE\x10\x00\x12\r\n\tINTEGRITY\x10\x01\x12\x19\n\x15PRIVACY_AND_INTEGRITY\x10\x02\x12 \n\x1cSTRONG_PRIVACY_AND_INTEGRITY\x10\x03\"0\n\x06\x46ormat\x12\x10\n\x0cUNCOMPRESSED\x10\x00\x12\x14\n\x10ZIPPY_COMPRESSED\x10\x01*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x9e\x01\n\rStreamOptions\x12\"\n\x15\x63lient_initial_tokens\x18\x01 \x01(\x03:\x03\x31\x30\x30\x12\"\n\x15server_initial_tokens\x18\x02 \x01(\x03:\x03\x31\x30\x30\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x95\x02\n\x13UninterpretedOption\x12\x32\n\x04name\x18\x02 \x03(\x0b\x32$.proto2.UninterpretedOption.NamePart\x12\x18\n\x10identifier_value\x18\x03 \x01(\t\x12\x1a\n\x12positive_int_value\x18\x04 \x01(\x04\x12\x1a\n\x12negative_int_value\x18\x05 \x01(\x03\x12\x14\n\x0c\x64ouble_value\x18\x06 \x01(\x01\x12\x14\n\x0cstring_value\x18\x07 \x01(\x0c\x12\x17\n\x0f\x61ggregate_value\x18\x08 \x01(\t\x1a\x33\n\x08NamePart\x12\x11\n\tname_part\x18\x01 \x02(\t\x12\x14\n\x0cis_extension\x18\x02 \x02(\x08\"s\n\x0eSourceCodeInfo\x12\x31\n\x08location\x18\x01 \x03(\x0b\x32\x1f.proto2.SourceCodeInfo.Location\x1a.\n\x08Location\x12\x10\n\x04path\x18\x01 \x03(\x05\x42\x02\x10\x01\x12\x10\n\x04span\x18\x02 \x03(\x05\x42\x02\x10\x01\x42)\n\x13\x63om.google.protobufB\x10\x44\x65scriptorProtosH\x01')
+  serialized_pb='\n!net/proto2/proto/descriptor.proto\x12\x06proto2\">\n\x11\x46ileDescriptorSet\x12)\n\x04\x66ile\x18\x01 \x03(\x0b\x32\x1b.proto2.FileDescriptorProto\"\x95\x03\n\x13\x46ileDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07package\x18\x02 \x01(\t\x12\x12\n\ndependency\x18\x03 \x03(\t\x12\x19\n\x11public_dependency\x18\n \x03(\x05\x12\x17\n\x0fweak_dependency\x18\x0b \x03(\x05\x12-\n\x0cmessage_type\x18\x04 \x03(\x0b\x32\x17.proto2.DescriptorProto\x12.\n\tenum_type\x18\x05 \x03(\x0b\x32\x1b.proto2.EnumDescriptorProto\x12/\n\x07service\x18\x06 \x03(\x0b\x32\x1e.proto2.ServiceDescriptorProto\x12/\n\textension\x18\x07 \x03(\x0b\x32\x1c.proto2.FieldDescriptorProto\x12$\n\x07options\x18\x08 \x01(\x0b\x32\x13.proto2.FileOptions\x12\x30\n\x10source_code_info\x18\t \x01(\x0b\x32\x16.proto2.SourceCodeInfo\"\xf3\x02\n\x0f\x44\x65scriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12+\n\x05\x66ield\x18\x02 \x03(\x0b\x32\x1c.proto2.FieldDescriptorProto\x12/\n\textension\x18\x06 \x03(\x0b\x32\x1c.proto2.FieldDescriptorProto\x12,\n\x0bnested_type\x18\x03 \x03(\x0b\x32\x17.proto2.DescriptorProto\x12.\n\tenum_type\x18\x04 \x03(\x0b\x32\x1b.proto2.EnumDescriptorProto\x12?\n\x0f\x65xtension_range\x18\x05 \x03(\x0b\x32&.proto2.DescriptorProto.ExtensionRange\x12\'\n\x07options\x18\x07 \x01(\x0b\x32\x16.proto2.MessageOptions\x1a,\n\x0e\x45xtensionRange\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\"\xf9\x04\n\x14\x46ieldDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x03 \x01(\x05\x12\x31\n\x05label\x18\x04 \x01(\x0e\x32\".proto2.FieldDescriptorProto.Label\x12/\n\x04type\x18\x05 \x01(\x0e\x32!.proto2.FieldDescriptorProto.Type\x12\x11\n\ttype_name\x18\x06 \x01(\t\x12\x10\n\x08\x65xtendee\x18\x02 \x01(\t\x12\x15\n\rdefault_value\x18\x07 \x01(\t\x12%\n\x07options\x18\x08 \x01(\x0b\x32\x14.proto2.FieldOptions\"\xb6\x02\n\x04Type\x12\x0f\n\x0bTYPE_DOUBLE\x10\x01\x12\x0e\n\nTYPE_FLOAT\x10\x02\x12\x0e\n\nTYPE_INT64\x10\x03\x12\x0f\n\x0bTYPE_UINT64\x10\x04\x12\x0e\n\nTYPE_INT32\x10\x05\x12\x10\n\x0cTYPE_FIXED64\x10\x06\x12\x10\n\x0cTYPE_FIXED32\x10\x07\x12\r\n\tTYPE_BOOL\x10\x08\x12\x0f\n\x0bTYPE_STRING\x10\t\x12\x0e\n\nTYPE_GROUP\x10\n\x12\x10\n\x0cTYPE_MESSAGE\x10\x0b\x12\x0e\n\nTYPE_BYTES\x10\x0c\x12\x0f\n\x0bTYPE_UINT32\x10\r\x12\r\n\tTYPE_ENUM\x10\x0e\x12\x11\n\rTYPE_SFIXED32\x10\x0f\x12\x11\n\rTYPE_SFIXED64\x10\x10\x12\x0f\n\x0bTYPE_SINT32\x10\x11\x12\x0f\n\x0bTYPE_SINT64\x10\x12\"C\n\x05Label\x12\x12\n\x0eLABEL_OPTIONAL\x10\x01\x12\x12\n\x0eLABEL_REQUIRED\x10\x02\x12\x12\n\x0eLABEL_REPEATED\x10\x03\"z\n\x13\x45numDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12/\n\x05value\x18\x02 \x03(\x0b\x32 .proto2.EnumValueDescriptorProto\x12$\n\x07options\x18\x03 \x01(\x0b\x32\x13.proto2.EnumOptions\"c\n\x18\x45numValueDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x02 \x01(\x05\x12)\n\x07options\x18\x03 \x01(\x0b\x32\x18.proto2.EnumValueOptions\"\xad\x01\n\x16ServiceDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12-\n\x06method\x18\x02 \x03(\x0b\x32\x1d.proto2.MethodDescriptorProto\x12-\n\x06stream\x18\x04 \x03(\x0b\x32\x1d.proto2.StreamDescriptorProto\x12\'\n\x07options\x18\x03 \x01(\x0b\x32\x16.proto2.ServiceOptions\"v\n\x15MethodDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\ninput_type\x18\x02 \x01(\t\x12\x13\n\x0boutput_type\x18\x03 \x01(\t\x12&\n\x07options\x18\x04 \x01(\x0b\x32\x15.proto2.MethodOptions\"\x87\x01\n\x15StreamDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x1b\n\x13\x63lient_message_type\x18\x02 \x01(\t\x12\x1b\n\x13server_message_type\x18\x03 \x01(\t\x12&\n\x07options\x18\x04 \x01(\x0b\x32\x15.proto2.StreamOptions\"\xd0\x07\n\x0b\x46ileOptions\x12\x19\n\x0e\x63\x63_api_version\x18\x02 \x01(\x05:\x01\x32\x12V\n\x14\x63\x63_api_compatibility\x18\x0f \x01(\x0e\x32&.proto2.FileOptions.CompatibilityLevel:\x10NO_COMPATIBILITY\x12\x14\n\x0cjava_package\x18\x01 \x01(\t\x12\x19\n\x0epy_api_version\x18\x04 \x01(\x05:\x01\x32\x12\x1b\n\x10java_api_version\x18\x05 \x01(\x05:\x01\x32\x12!\n\x13java_use_javaproto2\x18\x06 \x01(\x08:\x04true\x12\x1e\n\x10java_java5_enums\x18\x07 \x01(\x08:\x04true\x12)\n\x1ajava_generate_rpc_baseimpl\x18\r \x01(\x08:\x05\x66\x61lse\x12#\n\x14java_use_javastrings\x18\x15 \x01(\x08:\x05\x66\x61lse\x12\x1c\n\x14java_alt_api_package\x18\x13 \x01(\t\x12\x1c\n\x14java_outer_classname\x18\x08 \x01(\t\x12\"\n\x13java_multiple_files\x18\n \x01(\x08:\x05\x66\x61lse\x12,\n\x1djava_generate_equals_and_hash\x18\x14 \x01(\x08:\x05\x66\x61lse\x12=\n\x0coptimize_for\x18\t \x01(\x0e\x32 .proto2.FileOptions.OptimizeMode:\x05SPEED\x12\x12\n\ngo_package\x18\x0b \x01(\t\x12\x1a\n\x12javascript_package\x18\x0c \x01(\t\x12\x1a\n\x0fszl_api_version\x18\x0e \x01(\x05:\x01\x31\x12\"\n\x13\x63\x63_generic_services\x18\x10 \x01(\x08:\x05\x66\x61lse\x12$\n\x15java_generic_services\x18\x11 \x01(\x08:\x05\x66\x61lse\x12\"\n\x13py_generic_services\x18\x12 \x01(\x08:\x05\x66\x61lse\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption\"c\n\x12\x43ompatibilityLevel\x12\x14\n\x10NO_COMPATIBILITY\x10\x00\x12\x15\n\x11PROTO1_COMPATIBLE\x10\x64\x12 \n\x1c\x44\x45PRECATED_PROTO1_COMPATIBLE\x10\x32\":\n\x0cOptimizeMode\x12\t\n\x05SPEED\x10\x01\x12\r\n\tCODE_SIZE\x10\x02\x12\x10\n\x0cLITE_RUNTIME\x10\x03*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xaf\x01\n\x0eMessageOptions\x12&\n\x17message_set_wire_format\x18\x01 \x01(\x08:\x05\x66\x61lse\x12.\n\x1fno_standard_descriptor_accessor\x18\x02 \x01(\x08:\x05\x66\x61lse\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xee\x03\n\x0c\x46ieldOptions\x12\x31\n\x05\x63type\x18\x01 \x01(\x0e\x32\x1a.proto2.FieldOptions.CType:\x06STRING\x12\x0e\n\x06packed\x18\x02 \x01(\x08\x12\x31\n\x05jtype\x18\x04 \x01(\x0e\x32\x1a.proto2.FieldOptions.JType:\x06NORMAL\x12\x36\n\x06jstype\x18\x06 \x01(\x0e\x32\x1b.proto2.FieldOptions.JSType:\tJS_NORMAL\x12\x13\n\x04lazy\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x1c\n\x14\x65xperimental_map_key\x18\t \x01(\t\x12\x13\n\x04weak\x18\n \x01(\x08:\x05\x66\x61lse\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption\"/\n\x05\x43Type\x12\n\n\x06STRING\x10\x00\x12\x08\n\x04\x43ORD\x10\x01\x12\x10\n\x0cSTRING_PIECE\x10\x02\"\x1e\n\x05JType\x12\n\n\x06NORMAL\x10\x00\x12\t\n\x05\x42YTES\x10\x01\"5\n\x06JSType\x12\r\n\tJS_NORMAL\x10\x00\x12\r\n\tJS_STRING\x10\x01\x12\r\n\tJS_NUMBER\x10\x02*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x84\x01\n\x0b\x45numOptions\x12\x13\n\x0bproto1_name\x18\x01 \x01(\t\x12\x19\n\x0b\x61llow_alias\x18\x02 \x01(\x08:\x04true\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"Y\n\x10\x45numValueOptions\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x9b\x01\n\x0eServiceOptions\x12\x1d\n\x0emulticast_stub\x18\x14 \x01(\x08:\x05\x66\x61lse\x12#\n\x17\x66\x61ilure_detection_delay\x18\x10 \x01(\x01:\x02-1\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xcd\x05\n\rMethodOptions\x12\x35\n\x08protocol\x18\x07 \x01(\x0e\x32\x1e.proto2.MethodOptions.Protocol:\x03TCP\x12\x14\n\x08\x64\x65\x61\x64line\x18\x08 \x01(\x01:\x02-1\x12$\n\x15\x64uplicate_suppression\x18\t \x01(\x08:\x05\x66\x61lse\x12\x18\n\tfail_fast\x18\n \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0e\x63lient_logging\x18\x0b \x01(\x11:\x03\x32\x35\x36\x12\x1b\n\x0eserver_logging\x18\x0c \x01(\x11:\x03\x32\x35\x36\x12\x41\n\x0esecurity_level\x18\r \x01(\x0e\x32#.proto2.MethodOptions.SecurityLevel:\x04NONE\x12\x43\n\x0fresponse_format\x18\x0f \x01(\x0e\x32\x1c.proto2.MethodOptions.Format:\x0cUNCOMPRESSED\x12\x42\n\x0erequest_format\x18\x11 \x01(\x0e\x32\x1c.proto2.MethodOptions.Format:\x0cUNCOMPRESSED\x12\x13\n\x0bstream_type\x18\x12 \x01(\t\x12\x16\n\x0esecurity_label\x18\x13 \x01(\t\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption\"\x1c\n\x08Protocol\x12\x07\n\x03TCP\x10\x00\x12\x07\n\x03UDP\x10\x01\"e\n\rSecurityLevel\x12\x08\n\x04NONE\x10\x00\x12\r\n\tINTEGRITY\x10\x01\x12\x19\n\x15PRIVACY_AND_INTEGRITY\x10\x02\x12 \n\x1cSTRONG_PRIVACY_AND_INTEGRITY\x10\x03\"0\n\x06\x46ormat\x12\x10\n\x0cUNCOMPRESSED\x10\x00\x12\x14\n\x10ZIPPY_COMPRESSED\x10\x01*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x9e\x01\n\rStreamOptions\x12\"\n\x15\x63lient_initial_tokens\x18\x01 \x01(\x03:\x03\x31\x30\x30\x12\"\n\x15server_initial_tokens\x18\x02 \x01(\x03:\x03\x31\x30\x30\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x95\x02\n\x13UninterpretedOption\x12\x32\n\x04name\x18\x02 \x03(\x0b\x32$.proto2.UninterpretedOption.NamePart\x12\x18\n\x10identifier_value\x18\x03 \x01(\t\x12\x1a\n\x12positive_int_value\x18\x04 \x01(\x04\x12\x1a\n\x12negative_int_value\x18\x05 \x01(\x03\x12\x14\n\x0c\x64ouble_value\x18\x06 \x01(\x01\x12\x14\n\x0cstring_value\x18\x07 \x01(\x0c\x12\x17\n\x0f\x61ggregate_value\x18\x08 \x01(\t\x1a\x33\n\x08NamePart\x12\x11\n\tname_part\x18\x01 \x02(\t\x12\x14\n\x0cis_extension\x18\x02 \x02(\x08\"s\n\x0eSourceCodeInfo\x12\x31\n\x08location\x18\x01 \x03(\x0b\x32\x1f.proto2.SourceCodeInfo.Location\x1a.\n\x08Location\x12\x10\n\x04path\x18\x01 \x03(\x05\x42\x02\x10\x01\x12\x10\n\x04span\x18\x02 \x03(\x05\x42\x02\x10\x01\x42)\n\x13\x63om.google.protobufB\x10\x44\x65scriptorProtosH\x01')
 
 
 
@@ -112,8 +112,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=1121,
-  serialized_end=1431,
+  serialized_start=1146,
+  serialized_end=1456,
 )
 
 _FIELDDESCRIPTORPROTO_LABEL = descriptor.EnumDescriptor(
@@ -137,8 +137,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=1433,
-  serialized_end=1500,
+  serialized_start=1458,
+  serialized_end=1525,
 )
 
 _FILEOPTIONS_COMPATIBILITYLEVEL = descriptor.EnumDescriptor(
@@ -162,8 +162,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=2968,
-  serialized_end=3067,
+  serialized_start=2993,
+  serialized_end=3092,
 )
 
 _FILEOPTIONS_OPTIMIZEMODE = descriptor.EnumDescriptor(
@@ -187,8 +187,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=3069,
-  serialized_end=3127,
+  serialized_start=3094,
+  serialized_end=3152,
 )
 
 _FIELDOPTIONS_CTYPE = descriptor.EnumDescriptor(
@@ -212,8 +212,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=3668,
-  serialized_end=3715,
+  serialized_start=3693,
+  serialized_end=3740,
 )
 
 _FIELDOPTIONS_JTYPE = descriptor.EnumDescriptor(
@@ -233,8 +233,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=3717,
-  serialized_end=3747,
+  serialized_start=3742,
+  serialized_end=3772,
 )
 
 _FIELDOPTIONS_JSTYPE = descriptor.EnumDescriptor(
@@ -258,8 +258,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=3749,
-  serialized_end=3802,
+  serialized_start=3774,
+  serialized_end=3827,
 )
 
 _METHODOPTIONS_PROTOCOL = descriptor.EnumDescriptor(
@@ -279,8 +279,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=4725,
-  serialized_end=4753,
+  serialized_start=4750,
+  serialized_end=4778,
 )
 
 _METHODOPTIONS_SECURITYLEVEL = descriptor.EnumDescriptor(
@@ -308,8 +308,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=4755,
-  serialized_end=4856,
+  serialized_start=4780,
+  serialized_end=4881,
 )
 
 _METHODOPTIONS_FORMAT = descriptor.EnumDescriptor(
@@ -329,8 +329,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=4858,
-  serialized_end=4906,
+  serialized_start=4883,
+  serialized_end=4931,
 )
 
 
@@ -398,42 +398,49 @@
       is_extension=False, extension_scope=None,
       options=None),
     descriptor.FieldDescriptor(
-      name='message_type', full_name='proto2.FileDescriptorProto.message_type', index=4,
+      name='weak_dependency', full_name='proto2.FileDescriptorProto.weak_dependency', index=4,
+      number=11, type=5, cpp_type=1, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    descriptor.FieldDescriptor(
+      name='message_type', full_name='proto2.FileDescriptorProto.message_type', index=5,
       number=4, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       options=None),
     descriptor.FieldDescriptor(
-      name='enum_type', full_name='proto2.FileDescriptorProto.enum_type', index=5,
+      name='enum_type', full_name='proto2.FileDescriptorProto.enum_type', index=6,
       number=5, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       options=None),
     descriptor.FieldDescriptor(
-      name='service', full_name='proto2.FileDescriptorProto.service', index=6,
+      name='service', full_name='proto2.FileDescriptorProto.service', index=7,
       number=6, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       options=None),
     descriptor.FieldDescriptor(
-      name='extension', full_name='proto2.FileDescriptorProto.extension', index=7,
+      name='extension', full_name='proto2.FileDescriptorProto.extension', index=8,
       number=7, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       options=None),
     descriptor.FieldDescriptor(
-      name='options', full_name='proto2.FileDescriptorProto.options', index=8,
+      name='options', full_name='proto2.FileDescriptorProto.options', index=9,
       number=8, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       options=None),
     descriptor.FieldDescriptor(
-      name='source_code_info', full_name='proto2.FileDescriptorProto.source_code_info', index=9,
+      name='source_code_info', full_name='proto2.FileDescriptorProto.source_code_info', index=10,
       number=9, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
@@ -449,7 +456,7 @@
   is_extendable=False,
   extension_ranges=[],
   serialized_start=110,
-  serialized_end=490,
+  serialized_end=515,
 )
 
 
@@ -483,8 +490,8 @@
   options=None,
   is_extendable=False,
   extension_ranges=[],
-  serialized_start=820,
-  serialized_end=864,
+  serialized_start=845,
+  serialized_end=889,
 )
 
 _DESCRIPTORPROTO = descriptor.Descriptor(
@@ -552,8 +559,8 @@
   options=None,
   is_extendable=False,
   extension_ranges=[],
-  serialized_start=493,
-  serialized_end=864,
+  serialized_start=518,
+  serialized_end=889,
 )
 
 
@@ -631,8 +638,8 @@
   options=None,
   is_extendable=False,
   extension_ranges=[],
-  serialized_start=867,
-  serialized_end=1500,
+  serialized_start=892,
+  serialized_end=1525,
 )
 
 
@@ -673,8 +680,8 @@
   options=None,
   is_extendable=False,
   extension_ranges=[],
-  serialized_start=1502,
-  serialized_end=1624,
+  serialized_start=1527,
+  serialized_end=1649,
 )
 
 
@@ -715,8 +722,8 @@
   options=None,
   is_extendable=False,
   extension_ranges=[],
-  serialized_start=1626,
-  serialized_end=1725,
+  serialized_start=1651,
+  serialized_end=1750,
 )
 
 
@@ -764,8 +771,8 @@
   options=None,
   is_extendable=False,
   extension_ranges=[],
-  serialized_start=1728,
-  serialized_end=1901,
+  serialized_start=1753,
+  serialized_end=1926,
 )
 
 
@@ -813,8 +820,8 @@
   options=None,
   is_extendable=False,
   extension_ranges=[],
-  serialized_start=1903,
-  serialized_end=2021,
+  serialized_start=1928,
+  serialized_end=2046,
 )
 
 
@@ -862,8 +869,8 @@
   options=None,
   is_extendable=False,
   extension_ranges=[],
-  serialized_start=2024,
-  serialized_end=2159,
+  serialized_start=2049,
+  serialized_end=2184,
 )
 
 
@@ -1032,8 +1039,8 @@
   options=None,
   is_extendable=True,
   extension_ranges=[(1000, 536870912), ],
-  serialized_start=2162,
-  serialized_end=3138,
+  serialized_start=2187,
+  serialized_end=3163,
 )
 
 
@@ -1074,8 +1081,8 @@
   options=None,
   is_extendable=True,
   extension_ranges=[(1000, 536870912), ],
-  serialized_start=3141,
-  serialized_end=3316,
+  serialized_start=3166,
+  serialized_end=3341,
 )
 
 
@@ -1161,8 +1168,8 @@
   options=None,
   is_extendable=True,
   extension_ranges=[(1000, 536870912), ],
-  serialized_start=3319,
-  serialized_end=3813,
+  serialized_start=3344,
+  serialized_end=3838,
 )
 
 
@@ -1203,8 +1210,8 @@
   options=None,
   is_extendable=True,
   extension_ranges=[(1000, 536870912), ],
-  serialized_start=3816,
-  serialized_end=3948,
+  serialized_start=3841,
+  serialized_end=3973,
 )
 
 
@@ -1231,8 +1238,8 @@
   options=None,
   is_extendable=True,
   extension_ranges=[(1000, 536870912), ],
-  serialized_start=3950,
-  serialized_end=4039,
+  serialized_start=3975,
+  serialized_end=4064,
 )
 
 
@@ -1273,8 +1280,8 @@
   options=None,
   is_extendable=True,
   extension_ranges=[(1000, 536870912), ],
-  serialized_start=4042,
-  serialized_end=4197,
+  serialized_start=4067,
+  serialized_end=4222,
 )
 
 
@@ -1381,8 +1388,8 @@
   options=None,
   is_extendable=True,
   extension_ranges=[(1000, 536870912), ],
-  serialized_start=4200,
-  serialized_end=4917,
+  serialized_start=4225,
+  serialized_end=4942,
 )
 
 
@@ -1423,8 +1430,8 @@
   options=None,
   is_extendable=True,
   extension_ranges=[(1000, 536870912), ],
-  serialized_start=4920,
-  serialized_end=5078,
+  serialized_start=4945,
+  serialized_end=5103,
 )
 
 
@@ -1458,8 +1465,8 @@
   options=None,
   is_extendable=False,
   extension_ranges=[],
-  serialized_start=5307,
-  serialized_end=5358,
+  serialized_start=5332,
+  serialized_end=5383,
 )
 
 _UNINTERPRETEDOPTION = descriptor.Descriptor(
@@ -1527,8 +1534,8 @@
   options=None,
   is_extendable=False,
   extension_ranges=[],
-  serialized_start=5081,
-  serialized_end=5358,
+  serialized_start=5106,
+  serialized_end=5383,
 )
 
 
@@ -1562,8 +1569,8 @@
   options=None,
   is_extendable=False,
   extension_ranges=[],
-  serialized_start=5429,
-  serialized_end=5475,
+  serialized_start=5454,
+  serialized_end=5500,
 )
 
 _SOURCECODEINFO = descriptor.Descriptor(
@@ -1589,8 +1596,8 @@
   options=None,
   is_extendable=False,
   extension_ranges=[],
-  serialized_start=5360,
-  serialized_end=5475,
+  serialized_start=5385,
+  serialized_end=5500,
 )
 
 _FILEDESCRIPTORSET.fields_by_name['file'].message_type = _FILEDESCRIPTORPROTO
diff --git a/google/storage/speckle/python/api/rdbms.py b/google/storage/speckle/python/api/rdbms.py
index 0eebcec..3f71e05 100755
--- a/google/storage/speckle/python/api/rdbms.py
+++ b/google/storage/speckle/python/api/rdbms.py
@@ -436,7 +436,7 @@
 class Connection(object):
 
   def __init__(self, dsn, instance, database=None, user='root', password=None,
-               deadline_seconds=30.0, conv=None,
+               deadline_seconds=60.0, conv=None,
                query_deadline_seconds=86400.0, retry_interval_seconds=30.0):
     """Creates a new SQL Service connection.
 
diff --git a/google/storage/speckle/python/api/rdbms_googleapi.py b/google/storage/speckle/python/api/rdbms_googleapi.py
index 0df12d6..afc2098 100644
--- a/google/storage/speckle/python/api/rdbms_googleapi.py
+++ b/google/storage/speckle/python/api/rdbms_googleapi.py
@@ -36,7 +36,7 @@
 
   try:
     import google_sql
-    google_sql.fix_sys_path(include_google_sql_libs=True)
+    google_sql.fix_sys_path(google_sql.GOOGLE_SQL_EXTRA_PATHS)
   except ImportError:
     logging.warning(
         'Attempt to automatically load Google Cloud SQL dependencies failed! '
diff --git a/google/storage/speckle/python/django/backend/base.py b/google/storage/speckle/python/django/backend/base.py
index cef5526..fdc1806 100644
--- a/google/storage/speckle/python/django/backend/base.py
+++ b/google/storage/speckle/python/django/backend/base.py
@@ -62,6 +62,7 @@
 from django.db.backends import signals
 from django.utils import safestring
 
+from google.appengine.api import apiproxy_stub_map
 from google.storage.speckle.python.api import rdbms
 from google.storage.speckle.python.django.backend import client
 
@@ -130,9 +131,8 @@
     The imported driver module, or None if a suitable driver can not be found.
   """
   if not driver_name:
-    server_software = os.getenv('SERVER_SOFTWARE', '')
     base_pkg_path = 'google.storage.speckle.python.api.'
-    if server_software.startswith(PROD_SERVER_SOFTWARE):
+    if apiproxy_stub_map.apiproxy.GetStub('rdbms'):
       driver_name = base_pkg_path + 'rdbms_apiproxy'
     else:
       driver_name = base_pkg_path + 'rdbms_googleapi'
@@ -160,9 +160,9 @@
       found in storage and no oauth2_refresh_token was given.
   """
   driver = _GetDriver(driver_name)
-  server_software = os.getenv('SERVER_SOFTWARE', '')
-  if server_software and driver.__name__.endswith('rdbms_googleapi'):
-    if server_software.startswith(PROD_SERVER_SOFTWARE):
+  if (os.getenv('APPENGINE_RUNTIME') and
+      driver.__name__.endswith('rdbms_googleapi')):
+    if os.getenv('SERVER_SOFTWARE', '').startswith(PROD_SERVER_SOFTWARE):
       logging.warning(
           'Using the Google API driver is not recommended when running on '
           'production App Engine.  You should instead use the GAE API Proxy '
diff --git a/google_sql.py b/google_sql.py
index 88994d1..0276d25 100755
--- a/google_sql.py
+++ b/google_sql.py
@@ -21,6 +21,7 @@
 
 
 import os
+import re
 import sys
 
 
@@ -57,18 +58,32 @@
   os.path.join(DIR_PATH, 'lib', 'google.appengine._internal.graphy'),
 ]
 
+API_SERVER_EXTRA_PATHS = [
+  os.path.join(DIR_PATH, 'lib', 'argparse'),
+]
+API_SERVER_EXTRA_PATH_SCRIPTS = 'api_server'
 
-GOOGLE_SQL_EXTRA_PATHS = [
-  os.path.join(DIR_PATH, 'lib', 'enum'),
+
+OAUTH_CLIENT_EXTRA_PATHS = [
   os.path.join(DIR_PATH, 'lib', 'google-api-python-client'),
-  os.path.join(DIR_PATH, 'lib', 'grizzled'),
   os.path.join(DIR_PATH, 'lib', 'httplib2'),
+  os.path.join(DIR_PATH, 'lib', 'python-gflags'),
+]
+
+OAUTH_CLIENT_EXTRA_PATH_SCRIPTS = '(appcfg|bulkloader)'
+
+
+GOOGLE_SQL_EXTRA_PATHS = OAUTH_CLIENT_EXTRA_PATHS + [
+  os.path.join(DIR_PATH, 'lib', 'enum'),
+  os.path.join(DIR_PATH, 'lib', 'grizzled'),
   os.path.join(DIR_PATH, 'lib', 'oauth2'),
   os.path.join(DIR_PATH, 'lib', 'prettytable'),
-  os.path.join(DIR_PATH, 'lib', 'python-gflags'),
   os.path.join(DIR_PATH, 'lib', 'sqlcmd'),
 ]
 
+GOOGLE_SQL_EXTRA_PATH_SCRIPTS = 'google_sql'
+
+
 
 SCRIPT_EXCEPTIONS = {
   "dev_appserver.py" : "dev_appserver_main.py"
@@ -79,18 +94,27 @@
 }
 
 
-def fix_sys_path(include_google_sql_libs=False):
+def fix_sys_path(extra_extra_paths=()):
   """Fix the sys.path to include our extra paths."""
   extra_paths = EXTRA_PATHS[:]
-  if include_google_sql_libs:
-    extra_paths.extend(GOOGLE_SQL_EXTRA_PATHS)
+  extra_paths.extend(extra_extra_paths)
   sys.path = extra_paths + sys.path
 
 
 def run_file(file_path, globals_, script_dir=SCRIPT_DIR):
   """Execute the file at the specified path with the passed-in globals."""
   script_name = os.path.basename(file_path)
-  fix_sys_path('google_sql' in script_name)
+
+  if re.match(OAUTH_CLIENT_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = OAUTH_CLIENT_EXTRA_PATHS
+  elif re.match(GOOGLE_SQL_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = GOOGLE_SQL_EXTRA_PATHS
+  elif re.match(API_SERVER_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = API_SERVER_EXTRA_PATHS
+  else:
+    extra_extra_paths = []
+  fix_sys_path(extra_extra_paths)
+
   script_name = SCRIPT_EXCEPTIONS.get(script_name, script_name)
   script_dir = SCRIPT_DIR_EXCEPTIONS.get(script_name, script_dir)
   script_path = os.path.join(script_dir, script_name)
diff --git a/lib/argparse/LICENSE.txt b/lib/argparse/LICENSE.txt
new file mode 100644
index 0000000..89cd93f
--- /dev/null
+++ b/lib/argparse/LICENSE.txt
@@ -0,0 +1,56 @@
+argparse is (c) 2006-2009 Steven J. Bethard <steven.bethard@gmail.com>.
+
+The argparse module was contributed to Python as of Python 2.7 and thus
+was licensed under the Python license. Same license applies to all files in
+the argparse package project.
+
+For details about the Python License, please see doc/Python-License.txt.
+
+History
+-------
+
+Before (and including) argparse 1.1, the argparse package was licensed under
+Apache License v2.0.
+
+After argparse 1.1, all project files from the argparse project were deleted
+due to license compatibility issues between Apache License 2.0 and GNU GPL v2.
+
+The project repository then had a clean start with some files taken from
+Python 2.7.1, so definitely all files are under Python License now.
+
+PSF LICENSE AGREEMENT FOR PYTHON 2.7.2
+======================================
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation (“PSF”), and
+the Individual or Organization (“Licensee”) accessing and otherwise using
+Python 2.7.2 software in source or binary form and its associated documentation.
+2. Subject to the terms and conditions of this License Agreement, PSF hereby
+grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+analyze, test, perform and/or display publicly, prepare derivative works,
+distribute, and otherwise use Python 2.7.2 alone or in any derivative version,
+provided, however, that PSF’s License Agreement and PSF’s notice of copyright,
+i.e., “Copyright © 2001-2012 Python Software Foundation; All Rights Reserved”
+are retained in Python 2.7.2 alone or in any derivative version prepared by
+Licensee.
+3. In the event Licensee prepares a derivative work that is based on or
+incorporates Python 2.7.2 or any part thereof, and wants to make the derivative
+work available to others as provided herein, then Licensee hereby agrees to
+include in any such work a brief summary of the changes made to Python 2.7.2.
+PSF is making Python 2.7.2 available to Licensee on an “AS IS” basis.
+4. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF
+EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR
+WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE
+USE OF PYTHON 2.7.2 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
+PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 2.7.2 FOR ANY
+INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING,
+DISTRIBUTING, OR OTHERWISE USING PYTHON 2.7.2, OR ANY DERIVATIVE THEREOF, EVEN
+IF ADVISED OF THE POSSIBILITY THEREOF.
+6. This License Agreement will automatically terminate upon a material breach
+of its terms and conditions.
+7. Nothing in this License Agreement shall be deemed to create any relationship
+of agency, partnership, or joint venture between PSF and Licensee. This License
+Agreement does not grant permission to use PSF trademarks or trade name in a
+trademark sense to endorse or promote products or services of Licensee, or any
+third party.
+8. By copying, installing or otherwise using Python 2.7.2, Licensee agrees to
+be bound by the terms and conditions of this License Agreement.
diff --git a/lib/argparse/MANIFEST.in b/lib/argparse/MANIFEST.in
new file mode 100644
index 0000000..9f118cc
--- /dev/null
+++ b/lib/argparse/MANIFEST.in
@@ -0,0 +1,15 @@
+include README.txt LICENSE.txt NEWS.txt
+
+recursive-include doc *
+
+global-exclude *.pyc
+global-exclude *.pyo
+global-exclude *.orig
+global-exclude *.rej
+
+prune doc/_build
+prune env24
+prune env25
+prune env26
+prune env27
+
diff --git a/lib/argparse/NEWS.txt b/lib/argparse/NEWS.txt
new file mode 100644
index 0000000..65b9a87
--- /dev/null
+++ b/lib/argparse/NEWS.txt
@@ -0,0 +1,16 @@
+What's New
+==========
+
+argparse 1.2.1
+--------------
+
+- fixed Issue #82: argparse 1.2 incompatible with Python 3.1
+- hacked the tests so they don't have the minor failures that were caused
+  by the compatibility stuff for python 2.3 and 3.1
+
+argparse 1.2
+------------
+
+- fixed Issue #79: re-licensed argparse package under same license as py 2.7 stdlib argparse code
+- fixed Issue #80: argparse 1.2 is now same archive on pypi / on google code
+
diff --git a/lib/argparse/PKG-INFO b/lib/argparse/PKG-INFO
new file mode 100644
index 0000000..9306d24
--- /dev/null
+++ b/lib/argparse/PKG-INFO
@@ -0,0 +1,77 @@
+Metadata-Version: 1.0
+Name: argparse
+Version: 1.2.1
+Summary: Python command-line parsing library
+Home-page: http://code.google.com/p/argparse/
+Author: Steven Bethard
+Author-email: steven.bethard@gmail.com
+License: Python Software Foundation License
+Download-URL: http://argparse.googlecode.com/files/argparse-1.2.1.tar.gz
+Description: The argparse module makes it easy to write user friendly command line
+        interfaces.
+        
+        The program defines what arguments it requires, and argparse will figure out
+        how to parse those out of sys.argv. The argparse module also automatically
+        generates help and usage messages and issues errors when users give the
+        program invalid arguments.
+        
+        As of Python >= 2.7 and >= 3.2, the argparse module is maintained within the
+        Python standard library. For users who still need to support Python < 2.7 or
+        < 3.2, it is also provided as a separate package, which tries to stay
+        compatible with the module in the standard library, but also supports older
+        Python versions.
+        
+        argparse is licensed under the Python license, for details see LICENSE.txt.
+        
+        
+        Compatibility
+        -------------
+        
+        argparse should work on Python >= 2.3, it was tested on:
+        
+        * 2.3.5, 2.4.4, 2.5.5, 2.6.5 and 2.7
+        * 3.1, 3.2
+        
+        
+        Installation
+        ------------
+        
+        Try one of these:
+        
+            python setup.py install
+        
+            easy_install argparse
+        
+            pip install argparse
+        
+            putting argparse.py in some directory listed in sys.path should also work
+        
+        
+        Bugs
+        ----
+        
+        If you find a bug, please try to reproduce it with python 2.7.
+        
+        If it happens there also, please file a bug in the python.org issue tracker.
+        If it does not happen in 2.7, file a bug in the argparse package issue tracker.
+        
+        
+Keywords: argparse command line parser parsing
+Platform: any
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Console
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: Python Software Foundation License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 2.3
+Classifier: Programming Language :: Python :: 2.4
+Classifier: Programming Language :: Python :: 2.5
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3.0
+Classifier: Programming Language :: Python :: 3.1
+Classifier: Programming Language :: Python :: 3.2
+Classifier: Topic :: Software Development
diff --git a/lib/argparse/README.txt b/lib/argparse/README.txt
new file mode 100644
index 0000000..a16fb10
--- /dev/null
+++ b/lib/argparse/README.txt
@@ -0,0 +1,48 @@
+The argparse module makes it easy to write user friendly command line
+interfaces.
+
+The program defines what arguments it requires, and argparse will figure out
+how to parse those out of sys.argv. The argparse module also automatically
+generates help and usage messages and issues errors when users give the
+program invalid arguments.
+
+As of Python >= 2.7 and >= 3.2, the argparse module is maintained within the
+Python standard library. For users who still need to support Python < 2.7 or
+< 3.2, it is also provided as a separate package, which tries to stay
+compatible with the module in the standard library, but also supports older
+Python versions.
+
+argparse is licensed under the Python license, for details see LICENSE.txt.
+
+
+Compatibility
+-------------
+
+argparse should work on Python >= 2.3, it was tested on:
+
+* 2.3.5, 2.4.4, 2.5.5, 2.6.5 and 2.7
+* 3.1, 3.2
+
+
+Installation
+------------
+
+Try one of these:
+
+    python setup.py install
+
+    easy_install argparse
+
+    pip install argparse
+
+    putting argparse.py in some directory listed in sys.path should also work
+
+
+Bugs
+----
+
+If you find a bug, please try to reproduce it with python 2.7.
+
+If it happens there also, please file a bug in the python.org issue tracker.
+If it does not happen in 2.7, file a bug in the argparse package issue tracker.
+
diff --git a/lib/argparse/argparse.egg-info/PKG-INFO b/lib/argparse/argparse.egg-info/PKG-INFO
new file mode 100644
index 0000000..9306d24
--- /dev/null
+++ b/lib/argparse/argparse.egg-info/PKG-INFO
@@ -0,0 +1,77 @@
+Metadata-Version: 1.0
+Name: argparse
+Version: 1.2.1
+Summary: Python command-line parsing library
+Home-page: http://code.google.com/p/argparse/
+Author: Steven Bethard
+Author-email: steven.bethard@gmail.com
+License: Python Software Foundation License
+Download-URL: http://argparse.googlecode.com/files/argparse-1.2.1.tar.gz
+Description: The argparse module makes it easy to write user friendly command line
+        interfaces.
+        
+        The program defines what arguments it requires, and argparse will figure out
+        how to parse those out of sys.argv. The argparse module also automatically
+        generates help and usage messages and issues errors when users give the
+        program invalid arguments.
+        
+        As of Python >= 2.7 and >= 3.2, the argparse module is maintained within the
+        Python standard library. For users who still need to support Python < 2.7 or
+        < 3.2, it is also provided as a separate package, which tries to stay
+        compatible with the module in the standard library, but also supports older
+        Python versions.
+        
+        argparse is licensed under the Python license, for details see LICENSE.txt.
+        
+        
+        Compatibility
+        -------------
+        
+        argparse should work on Python >= 2.3, it was tested on:
+        
+        * 2.3.5, 2.4.4, 2.5.5, 2.6.5 and 2.7
+        * 3.1, 3.2
+        
+        
+        Installation
+        ------------
+        
+        Try one of these:
+        
+            python setup.py install
+        
+            easy_install argparse
+        
+            pip install argparse
+        
+            putting argparse.py in some directory listed in sys.path should also work
+        
+        
+        Bugs
+        ----
+        
+        If you find a bug, please try to reproduce it with python 2.7.
+        
+        If it happens there also, please file a bug in the python.org issue tracker.
+        If it does not happen in 2.7, file a bug in the argparse package issue tracker.
+        
+        
+Keywords: argparse command line parser parsing
+Platform: any
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Console
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: Python Software Foundation License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 2.3
+Classifier: Programming Language :: Python :: 2.4
+Classifier: Programming Language :: Python :: 2.5
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3.0
+Classifier: Programming Language :: Python :: 3.1
+Classifier: Programming Language :: Python :: 3.2
+Classifier: Topic :: Software Development
diff --git a/lib/argparse/argparse.egg-info/SOURCES.txt b/lib/argparse/argparse.egg-info/SOURCES.txt
new file mode 100644
index 0000000..09096f1
--- /dev/null
+++ b/lib/argparse/argparse.egg-info/SOURCES.txt
@@ -0,0 +1,19 @@
+LICENSE.txt
+MANIFEST.in
+NEWS.txt
+README.txt
+argparse.py
+setup.cfg
+setup.py
+argparse.egg-info/PKG-INFO
+argparse.egg-info/SOURCES.txt
+argparse.egg-info/dependency_links.txt
+argparse.egg-info/top_level.txt
+doc/Makefile
+doc/make.bat
+doc/source/Python-License.txt
+doc/source/argparse.rst
+doc/source/conf.py
+doc/source/index.rst
+doc/source/license.rst
+test/test_argparse.py
\ No newline at end of file
diff --git a/lib/argparse/argparse.egg-info/dependency_links.txt b/lib/argparse/argparse.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/lib/argparse/argparse.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/lib/argparse/argparse.egg-info/top_level.txt b/lib/argparse/argparse.egg-info/top_level.txt
new file mode 100644
index 0000000..1352d5e
--- /dev/null
+++ b/lib/argparse/argparse.egg-info/top_level.txt
@@ -0,0 +1 @@
+argparse
diff --git a/lib/argparse/argparse.py b/lib/argparse/argparse.py
new file mode 100644
index 0000000..32d948c
--- /dev/null
+++ b/lib/argparse/argparse.py
@@ -0,0 +1,2362 @@
+# Author: Steven J. Bethard <steven.bethard@gmail.com>.
+
+"""Command-line parsing library
+
+This module is an optparse-inspired command-line parsing library that:
+
+    - handles both optional and positional arguments
+    - produces highly informative usage messages
+    - supports parsers that dispatch to sub-parsers
+
+The following is a simple usage example that sums integers from the
+command-line and writes the result to a file::
+
+    parser = argparse.ArgumentParser(
+        description='sum the integers at the command line')
+    parser.add_argument(
+        'integers', metavar='int', nargs='+', type=int,
+        help='an integer to be summed')
+    parser.add_argument(
+        '--log', default=sys.stdout, type=argparse.FileType('w'),
+        help='the file where the sum should be written')
+    args = parser.parse_args()
+    args.log.write('%s' % sum(args.integers))
+    args.log.close()
+
+The module contains the following public classes:
+
+    - ArgumentParser -- The main entry point for command-line parsing. As the
+        example above shows, the add_argument() method is used to populate
+        the parser with actions for optional and positional arguments. Then
+        the parse_args() method is invoked to convert the args at the
+        command-line into an object with attributes.
+
+    - ArgumentError -- The exception raised by ArgumentParser objects when
+        there are errors with the parser's actions. Errors raised while
+        parsing the command-line are caught by ArgumentParser and emitted
+        as command-line messages.
+
+    - FileType -- A factory for defining types of files to be created. As the
+        example above shows, instances of FileType are typically passed as
+        the type= argument of add_argument() calls.
+
+    - Action -- The base class for parser actions. Typically actions are
+        selected by passing strings like 'store_true' or 'append_const' to
+        the action= argument of add_argument(). However, for greater
+        customization of ArgumentParser actions, subclasses of Action may
+        be defined and passed as the action= argument.
+
+    - HelpFormatter, RawDescriptionHelpFormatter, RawTextHelpFormatter,
+        ArgumentDefaultsHelpFormatter -- Formatter classes which
+        may be passed as the formatter_class= argument to the
+        ArgumentParser constructor. HelpFormatter is the default,
+        RawDescriptionHelpFormatter and RawTextHelpFormatter tell the parser
+        not to change the formatting for help text, and
+        ArgumentDefaultsHelpFormatter adds information about argument defaults
+        to the help.
+
+All other classes in this module are considered implementation details.
+(Also note that HelpFormatter and RawDescriptionHelpFormatter are only
+considered public as object names -- the API of the formatter objects is
+still considered an implementation detail.)
+"""
+
+__version__ = '1.2.1'
+__all__ = [
+    'ArgumentParser',
+    'ArgumentError',
+    'ArgumentTypeError',
+    'FileType',
+    'HelpFormatter',
+    'ArgumentDefaultsHelpFormatter',
+    'RawDescriptionHelpFormatter',
+    'RawTextHelpFormatter',
+    'Namespace',
+    'Action',
+    'ONE_OR_MORE',
+    'OPTIONAL',
+    'PARSER',
+    'REMAINDER',
+    'SUPPRESS',
+    'ZERO_OR_MORE',
+]
+
+
+import copy as _copy
+import os as _os
+import re as _re
+import sys as _sys
+import textwrap as _textwrap
+
+from gettext import gettext as _
+
+try:
+    set
+except NameError:
+    # for python < 2.4 compatibility (sets module is there since 2.3):
+    from sets import Set as set
+
+try:
+    basestring
+except NameError:
+    basestring = str
+
+try:
+    sorted
+except NameError:
+    # for python < 2.4 compatibility:
+    def sorted(iterable, reverse=False):
+        result = list(iterable)
+        result.sort()
+        if reverse:
+            result.reverse()
+        return result
+
+
+def _callable(obj):
+    return hasattr(obj, '__call__') or hasattr(obj, '__bases__')
+
+
+SUPPRESS = '==SUPPRESS=='
+
+OPTIONAL = '?'
+ZERO_OR_MORE = '*'
+ONE_OR_MORE = '+'
+PARSER = 'A...'
+REMAINDER = '...'
+_UNRECOGNIZED_ARGS_ATTR = '_unrecognized_args'
+
+# =============================
+# Utility functions and classes
+# =============================
+
+class _AttributeHolder(object):
+    """Abstract base class that provides __repr__.
+
+    The __repr__ method returns a string in the format::
+        ClassName(attr=name, attr=name, ...)
+    The attributes are determined either by a class-level attribute,
+    '_kwarg_names', or by inspecting the instance __dict__.
+    """
+
+    def __repr__(self):
+        type_name = type(self).__name__
+        arg_strings = []
+        for arg in self._get_args():
+            arg_strings.append(repr(arg))
+        for name, value in self._get_kwargs():
+            arg_strings.append('%s=%r' % (name, value))
+        return '%s(%s)' % (type_name, ', '.join(arg_strings))
+
+    def _get_kwargs(self):
+        return sorted(self.__dict__.items())
+
+    def _get_args(self):
+        return []
+
+
+def _ensure_value(namespace, name, value):
+    if getattr(namespace, name, None) is None:
+        setattr(namespace, name, value)
+    return getattr(namespace, name)
+
+
+# ===============
+# Formatting Help
+# ===============
+
+class HelpFormatter(object):
+    """Formatter for generating usage messages and argument help strings.
+
+    Only the name of this class is considered a public API. All the methods
+    provided by the class are considered an implementation detail.
+    """
+
+    def __init__(self,
+                 prog,
+                 indent_increment=2,
+                 max_help_position=24,
+                 width=None):
+
+        # default setting for width
+        if width is None:
+            try:
+                width = int(_os.environ['COLUMNS'])
+            except (KeyError, ValueError):
+                width = 80
+            width -= 2
+
+        self._prog = prog
+        self._indent_increment = indent_increment
+        self._max_help_position = max_help_position
+        self._width = width
+
+        self._current_indent = 0
+        self._level = 0
+        self._action_max_length = 0
+
+        self._root_section = self._Section(self, None)
+        self._current_section = self._root_section
+
+        self._whitespace_matcher = _re.compile(r'\s+')
+        self._long_break_matcher = _re.compile(r'\n\n\n+')
+
+    # ===============================
+    # Section and indentation methods
+    # ===============================
+    def _indent(self):
+        self._current_indent += self._indent_increment
+        self._level += 1
+
+    def _dedent(self):
+        self._current_indent -= self._indent_increment
+        assert self._current_indent >= 0, 'Indent decreased below 0.'
+        self._level -= 1
+
+    class _Section(object):
+
+        def __init__(self, formatter, parent, heading=None):
+            self.formatter = formatter
+            self.parent = parent
+            self.heading = heading
+            self.items = []
+
+        def format_help(self):
+            # format the indented section
+            if self.parent is not None:
+                self.formatter._indent()
+            join = self.formatter._join_parts
+            for func, args in self.items:
+                func(*args)
+            item_help = join([func(*args) for func, args in self.items])
+            if self.parent is not None:
+                self.formatter._dedent()
+
+            # return nothing if the section was empty
+            if not item_help:
+                return ''
+
+            # add the heading if the section was non-empty
+            if self.heading is not SUPPRESS and self.heading is not None:
+                current_indent = self.formatter._current_indent
+                heading = '%*s%s:\n' % (current_indent, '', self.heading)
+            else:
+                heading = ''
+
+            # join the section-initial newline, the heading and the help
+            return join(['\n', heading, item_help, '\n'])
+
+    def _add_item(self, func, args):
+        self._current_section.items.append((func, args))
+
+    # ========================
+    # Message building methods
+    # ========================
+    def start_section(self, heading):
+        self._indent()
+        section = self._Section(self, self._current_section, heading)
+        self._add_item(section.format_help, [])
+        self._current_section = section
+
+    def end_section(self):
+        self._current_section = self._current_section.parent
+        self._dedent()
+
+    def add_text(self, text):
+        if text is not SUPPRESS and text is not None:
+            self._add_item(self._format_text, [text])
+
+    def add_usage(self, usage, actions, groups, prefix=None):
+        if usage is not SUPPRESS:
+            args = usage, actions, groups, prefix
+            self._add_item(self._format_usage, args)
+
+    def add_argument(self, action):
+        if action.help is not SUPPRESS:
+
+            # find all invocations
+            get_invocation = self._format_action_invocation
+            invocations = [get_invocation(action)]
+            for subaction in self._iter_indented_subactions(action):
+                invocations.append(get_invocation(subaction))
+
+            # update the maximum item length
+            invocation_length = max([len(s) for s in invocations])
+            action_length = invocation_length + self._current_indent
+            self._action_max_length = max(self._action_max_length,
+                                          action_length)
+
+            # add the item to the list
+            self._add_item(self._format_action, [action])
+
+    def add_arguments(self, actions):
+        for action in actions:
+            self.add_argument(action)
+
+    # =======================
+    # Help-formatting methods
+    # =======================
+    def format_help(self):
+        help = self._root_section.format_help()
+        if help:
+            help = self._long_break_matcher.sub('\n\n', help)
+            help = help.strip('\n') + '\n'
+        return help
+
+    def _join_parts(self, part_strings):
+        return ''.join([part
+                        for part in part_strings
+                        if part and part is not SUPPRESS])
+
+    def _format_usage(self, usage, actions, groups, prefix):
+        if prefix is None:
+            prefix = _('usage: ')
+
+        # if usage is specified, use that
+        if usage is not None:
+            usage = usage % dict(prog=self._prog)
+
+        # if no optionals or positionals are available, usage is just prog
+        elif usage is None and not actions:
+            usage = '%(prog)s' % dict(prog=self._prog)
+
+        # if optionals and positionals are available, calculate usage
+        elif usage is None:
+            prog = '%(prog)s' % dict(prog=self._prog)
+
+            # split optionals from positionals
+            optionals = []
+            positionals = []
+            for action in actions:
+                if action.option_strings:
+                    optionals.append(action)
+                else:
+                    positionals.append(action)
+
+            # build full usage string
+            format = self._format_actions_usage
+            action_usage = format(optionals + positionals, groups)
+            usage = ' '.join([s for s in [prog, action_usage] if s])
+
+            # wrap the usage parts if it's too long
+            text_width = self._width - self._current_indent
+            if len(prefix) + len(usage) > text_width:
+
+                # break usage into wrappable parts
+                part_regexp = r'\(.*?\)+|\[.*?\]+|\S+'
+                opt_usage = format(optionals, groups)
+                pos_usage = format(positionals, groups)
+                opt_parts = _re.findall(part_regexp, opt_usage)
+                pos_parts = _re.findall(part_regexp, pos_usage)
+                assert ' '.join(opt_parts) == opt_usage
+                assert ' '.join(pos_parts) == pos_usage
+
+                # helper for wrapping lines
+                def get_lines(parts, indent, prefix=None):
+                    lines = []
+                    line = []
+                    if prefix is not None:
+                        line_len = len(prefix) - 1
+                    else:
+                        line_len = len(indent) - 1
+                    for part in parts:
+                        if line_len + 1 + len(part) > text_width:
+                            lines.append(indent + ' '.join(line))
+                            line = []
+                            line_len = len(indent) - 1
+                        line.append(part)
+                        line_len += len(part) + 1
+                    if line:
+                        lines.append(indent + ' '.join(line))
+                    if prefix is not None:
+                        lines[0] = lines[0][len(indent):]
+                    return lines
+
+                # if prog is short, follow it with optionals or positionals
+                if len(prefix) + len(prog) <= 0.75 * text_width:
+                    indent = ' ' * (len(prefix) + len(prog) + 1)
+                    if opt_parts:
+                        lines = get_lines([prog] + opt_parts, indent, prefix)
+                        lines.extend(get_lines(pos_parts, indent))
+                    elif pos_parts:
+                        lines = get_lines([prog] + pos_parts, indent, prefix)
+                    else:
+                        lines = [prog]
+
+                # if prog is long, put it on its own line
+                else:
+                    indent = ' ' * len(prefix)
+                    parts = opt_parts + pos_parts
+                    lines = get_lines(parts, indent)
+                    if len(lines) > 1:
+                        lines = []
+                        lines.extend(get_lines(opt_parts, indent))
+                        lines.extend(get_lines(pos_parts, indent))
+                    lines = [prog] + lines
+
+                # join lines into usage
+                usage = '\n'.join(lines)
+
+        # prefix with 'usage:'
+        return '%s%s\n\n' % (prefix, usage)
+
+    def _format_actions_usage(self, actions, groups):
+        # find group indices and identify actions in groups
+        group_actions = set()
+        inserts = {}
+        for group in groups:
+            try:
+                start = actions.index(group._group_actions[0])
+            except ValueError:
+                continue
+            else:
+                end = start + len(group._group_actions)
+                if actions[start:end] == group._group_actions:
+                    for action in group._group_actions:
+                        group_actions.add(action)
+                    if not group.required:
+                        if start in inserts:
+                            inserts[start] += ' ['
+                        else:
+                            inserts[start] = '['
+                        inserts[end] = ']'
+                    else:
+                        if start in inserts:
+                            inserts[start] += ' ('
+                        else:
+                            inserts[start] = '('
+                        inserts[end] = ')'
+                    for i in range(start + 1, end):
+                        inserts[i] = '|'
+
+        # collect all actions format strings
+        parts = []
+        for i, action in enumerate(actions):
+
+            # suppressed arguments are marked with None
+            # remove | separators for suppressed arguments
+            if action.help is SUPPRESS:
+                parts.append(None)
+                if inserts.get(i) == '|':
+                    inserts.pop(i)
+                elif inserts.get(i + 1) == '|':
+                    inserts.pop(i + 1)
+
+            # produce all arg strings
+            elif not action.option_strings:
+                part = self._format_args(action, action.dest)
+
+                # if it's in a group, strip the outer []
+                if action in group_actions:
+                    if part[0] == '[' and part[-1] == ']':
+                        part = part[1:-1]
+
+                # add the action string to the list
+                parts.append(part)
+
+            # produce the first way to invoke the option in brackets
+            else:
+                option_string = action.option_strings[0]
+
+                # if the Optional doesn't take a value, format is:
+                #    -s or --long
+                if action.nargs == 0:
+                    part = '%s' % option_string
+
+                # if the Optional takes a value, format is:
+                #    -s ARGS or --long ARGS
+                else:
+                    default = action.dest.upper()
+                    args_string = self._format_args(action, default)
+                    part = '%s %s' % (option_string, args_string)
+
+                # make it look optional if it's not required or in a group
+                if not action.required and action not in group_actions:
+                    part = '[%s]' % part
+
+                # add the action string to the list
+                parts.append(part)
+
+        # insert things at the necessary indices
+        for i in sorted(inserts, reverse=True):
+            parts[i:i] = [inserts[i]]
+
+        # join all the action items with spaces
+        text = ' '.join([item for item in parts if item is not None])
+
+        # clean up separators for mutually exclusive groups
+        open = r'[\[(]'
+        close = r'[\])]'
+        text = _re.sub(r'(%s) ' % open, r'\1', text)
+        text = _re.sub(r' (%s)' % close, r'\1', text)
+        text = _re.sub(r'%s *%s' % (open, close), r'', text)
+        text = _re.sub(r'\(([^|]*)\)', r'\1', text)
+        text = text.strip()
+
+        # return the text
+        return text
+
+    def _format_text(self, text):
+        if '%(prog)' in text:
+            text = text % dict(prog=self._prog)
+        text_width = self._width - self._current_indent
+        indent = ' ' * self._current_indent
+        return self._fill_text(text, text_width, indent) + '\n\n'
+
+    def _format_action(self, action):
+        # determine the required width and the entry label
+        help_position = min(self._action_max_length + 2,
+                            self._max_help_position)
+        help_width = self._width - help_position
+        action_width = help_position - self._current_indent - 2
+        action_header = self._format_action_invocation(action)
+
+        # ho nelp; start on same line and add a final newline
+        if not action.help:
+            tup = self._current_indent, '', action_header
+            action_header = '%*s%s\n' % tup
+
+        # short action name; start on the same line and pad two spaces
+        elif len(action_header) <= action_width:
+            tup = self._current_indent, '', action_width, action_header
+            action_header = '%*s%-*s  ' % tup
+            indent_first = 0
+
+        # long action name; start on the next line
+        else:
+            tup = self._current_indent, '', action_header
+            action_header = '%*s%s\n' % tup
+            indent_first = help_position
+
+        # collect the pieces of the action help
+        parts = [action_header]
+
+        # if there was help for the action, add lines of help text
+        if action.help:
+            help_text = self._expand_help(action)
+            help_lines = self._split_lines(help_text, help_width)
+            parts.append('%*s%s\n' % (indent_first, '', help_lines[0]))
+            for line in help_lines[1:]:
+                parts.append('%*s%s\n' % (help_position, '', line))
+
+        # or add a newline if the description doesn't end with one
+        elif not action_header.endswith('\n'):
+            parts.append('\n')
+
+        # if there are any sub-actions, add their help as well
+        for subaction in self._iter_indented_subactions(action):
+            parts.append(self._format_action(subaction))
+
+        # return a single string
+        return self._join_parts(parts)
+
+    def _format_action_invocation(self, action):
+        if not action.option_strings:
+            metavar, = self._metavar_formatter(action, action.dest)(1)
+            return metavar
+
+        else:
+            parts = []
+
+            # if the Optional doesn't take a value, format is:
+            #    -s, --long
+            if action.nargs == 0:
+                parts.extend(action.option_strings)
+
+            # if the Optional takes a value, format is:
+            #    -s ARGS, --long ARGS
+            else:
+                default = action.dest.upper()
+                args_string = self._format_args(action, default)
+                for option_string in action.option_strings:
+                    parts.append('%s %s' % (option_string, args_string))
+
+            return ', '.join(parts)
+
+    def _metavar_formatter(self, action, default_metavar):
+        if action.metavar is not None:
+            result = action.metavar
+        elif action.choices is not None:
+            choice_strs = [str(choice) for choice in action.choices]
+            result = '{%s}' % ','.join(choice_strs)
+        else:
+            result = default_metavar
+
+        def format(tuple_size):
+            if isinstance(result, tuple):
+                return result
+            else:
+                return (result, ) * tuple_size
+        return format
+
+    def _format_args(self, action, default_metavar):
+        get_metavar = self._metavar_formatter(action, default_metavar)
+        if action.nargs is None:
+            result = '%s' % get_metavar(1)
+        elif action.nargs == OPTIONAL:
+            result = '[%s]' % get_metavar(1)
+        elif action.nargs == ZERO_OR_MORE:
+            result = '[%s [%s ...]]' % get_metavar(2)
+        elif action.nargs == ONE_OR_MORE:
+            result = '%s [%s ...]' % get_metavar(2)
+        elif action.nargs == REMAINDER:
+            result = '...'
+        elif action.nargs == PARSER:
+            result = '%s ...' % get_metavar(1)
+        else:
+            formats = ['%s' for _ in range(action.nargs)]
+            result = ' '.join(formats) % get_metavar(action.nargs)
+        return result
+
+    def _expand_help(self, action):
+        params = dict(vars(action), prog=self._prog)
+        for name in list(params):
+            if params[name] is SUPPRESS:
+                del params[name]
+        for name in list(params):
+            if hasattr(params[name], '__name__'):
+                params[name] = params[name].__name__
+        if params.get('choices') is not None:
+            choices_str = ', '.join([str(c) for c in params['choices']])
+            params['choices'] = choices_str
+        return self._get_help_string(action) % params
+
+    def _iter_indented_subactions(self, action):
+        try:
+            get_subactions = action._get_subactions
+        except AttributeError:
+            pass
+        else:
+            self._indent()
+            for subaction in get_subactions():
+                yield subaction
+            self._dedent()
+
+    def _split_lines(self, text, width):
+        text = self._whitespace_matcher.sub(' ', text).strip()
+        return _textwrap.wrap(text, width)
+
+    def _fill_text(self, text, width, indent):
+        text = self._whitespace_matcher.sub(' ', text).strip()
+        return _textwrap.fill(text, width, initial_indent=indent,
+                                           subsequent_indent=indent)
+
+    def _get_help_string(self, action):
+        return action.help
+
+
+class RawDescriptionHelpFormatter(HelpFormatter):
+    """Help message formatter which retains any formatting in descriptions.
+
+    Only the name of this class is considered a public API. All the methods
+    provided by the class are considered an implementation detail.
+    """
+
+    def _fill_text(self, text, width, indent):
+        return ''.join([indent + line for line in text.splitlines(True)])
+
+
+class RawTextHelpFormatter(RawDescriptionHelpFormatter):
+    """Help message formatter which retains formatting of all help text.
+
+    Only the name of this class is considered a public API. All the methods
+    provided by the class are considered an implementation detail.
+    """
+
+    def _split_lines(self, text, width):
+        return text.splitlines()
+
+
+class ArgumentDefaultsHelpFormatter(HelpFormatter):
+    """Help message formatter which adds default values to argument help.
+
+    Only the name of this class is considered a public API. All the methods
+    provided by the class are considered an implementation detail.
+    """
+
+    def _get_help_string(self, action):
+        help = action.help
+        if '%(default)' not in action.help:
+            if action.default is not SUPPRESS:
+                defaulting_nargs = [OPTIONAL, ZERO_OR_MORE]
+                if action.option_strings or action.nargs in defaulting_nargs:
+                    help += ' (default: %(default)s)'
+        return help
+
+
+# =====================
+# Options and Arguments
+# =====================
+
+def _get_action_name(argument):
+    if argument is None:
+        return None
+    elif argument.option_strings:
+        return  '/'.join(argument.option_strings)
+    elif argument.metavar not in (None, SUPPRESS):
+        return argument.metavar
+    elif argument.dest not in (None, SUPPRESS):
+        return argument.dest
+    else:
+        return None
+
+
+class ArgumentError(Exception):
+    """An error from creating or using an argument (optional or positional).
+
+    The string value of this exception is the message, augmented with
+    information about the argument that caused it.
+    """
+
+    def __init__(self, argument, message):
+        self.argument_name = _get_action_name(argument)
+        self.message = message
+
+    def __str__(self):
+        if self.argument_name is None:
+            format = '%(message)s'
+        else:
+            format = 'argument %(argument_name)s: %(message)s'
+        return format % dict(message=self.message,
+                             argument_name=self.argument_name)
+
+
+class ArgumentTypeError(Exception):
+    """An error from trying to convert a command line string to a type."""
+    pass
+
+
+# ==============
+# Action classes
+# ==============
+
+class Action(_AttributeHolder):
+    """Information about how to convert command line strings to Python objects.
+
+    Action objects are used by an ArgumentParser to represent the information
+    needed to parse a single argument from one or more strings from the
+    command line. The keyword arguments to the Action constructor are also
+    all attributes of Action instances.
+
+    Keyword Arguments:
+
+        - option_strings -- A list of command-line option strings which
+            should be associated with this action.
+
+        - dest -- The name of the attribute to hold the created object(s)
+
+        - nargs -- The number of command-line arguments that should be
+            consumed. By default, one argument will be consumed and a single
+            value will be produced.  Other values include:
+                - N (an integer) consumes N arguments (and produces a list)
+                - '?' consumes zero or one arguments
+                - '*' consumes zero or more arguments (and produces a list)
+                - '+' consumes one or more arguments (and produces a list)
+            Note that the difference between the default and nargs=1 is that
+            with the default, a single value will be produced, while with
+            nargs=1, a list containing a single value will be produced.
+
+        - const -- The value to be produced if the option is specified and the
+            option uses an action that takes no values.
+
+        - default -- The value to be produced if the option is not specified.
+
+        - type -- The type which the command-line arguments should be converted
+            to, should be one of 'string', 'int', 'float', 'complex' or a
+            callable object that accepts a single string argument. If None,
+            'string' is assumed.
+
+        - choices -- A container of values that should be allowed. If not None,
+            after a command-line argument has been converted to the appropriate
+            type, an exception will be raised if it is not a member of this
+            collection.
+
+        - required -- True if the action must always be specified at the
+            command line. This is only meaningful for optional command-line
+            arguments.
+
+        - help -- The help string describing the argument.
+
+        - metavar -- The name to be used for the option's argument with the
+            help string. If None, the 'dest' value will be used as the name.
+    """
+
+    def __init__(self,
+                 option_strings,
+                 dest,
+                 nargs=None,
+                 const=None,
+                 default=None,
+                 type=None,
+                 choices=None,
+                 required=False,
+                 help=None,
+                 metavar=None):
+        self.option_strings = option_strings
+        self.dest = dest
+        self.nargs = nargs
+        self.const = const
+        self.default = default
+        self.type = type
+        self.choices = choices
+        self.required = required
+        self.help = help
+        self.metavar = metavar
+
+    def _get_kwargs(self):
+        names = [
+            'option_strings',
+            'dest',
+            'nargs',
+            'const',
+            'default',
+            'type',
+            'choices',
+            'help',
+            'metavar',
+        ]
+        return [(name, getattr(self, name)) for name in names]
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        raise NotImplementedError(_('.__call__() not defined'))
+
+
+class _StoreAction(Action):
+
+    def __init__(self,
+                 option_strings,
+                 dest,
+                 nargs=None,
+                 const=None,
+                 default=None,
+                 type=None,
+                 choices=None,
+                 required=False,
+                 help=None,
+                 metavar=None):
+        if nargs == 0:
+            raise ValueError('nargs for store actions must be > 0; if you '
+                             'have nothing to store, actions such as store '
+                             'true or store const may be more appropriate')
+        if const is not None and nargs != OPTIONAL:
+            raise ValueError('nargs must be %r to supply const' % OPTIONAL)
+        super(_StoreAction, self).__init__(
+            option_strings=option_strings,
+            dest=dest,
+            nargs=nargs,
+            const=const,
+            default=default,
+            type=type,
+            choices=choices,
+            required=required,
+            help=help,
+            metavar=metavar)
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        setattr(namespace, self.dest, values)
+
+
+class _StoreConstAction(Action):
+
+    def __init__(self,
+                 option_strings,
+                 dest,
+                 const,
+                 default=None,
+                 required=False,
+                 help=None,
+                 metavar=None):
+        super(_StoreConstAction, self).__init__(
+            option_strings=option_strings,
+            dest=dest,
+            nargs=0,
+            const=const,
+            default=default,
+            required=required,
+            help=help)
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        setattr(namespace, self.dest, self.const)
+
+
+class _StoreTrueAction(_StoreConstAction):
+
+    def __init__(self,
+                 option_strings,
+                 dest,
+                 default=False,
+                 required=False,
+                 help=None):
+        super(_StoreTrueAction, self).__init__(
+            option_strings=option_strings,
+            dest=dest,
+            const=True,
+            default=default,
+            required=required,
+            help=help)
+
+
+class _StoreFalseAction(_StoreConstAction):
+
+    def __init__(self,
+                 option_strings,
+                 dest,
+                 default=True,
+                 required=False,
+                 help=None):
+        super(_StoreFalseAction, self).__init__(
+            option_strings=option_strings,
+            dest=dest,
+            const=False,
+            default=default,
+            required=required,
+            help=help)
+
+
+class _AppendAction(Action):
+
+    def __init__(self,
+                 option_strings,
+                 dest,
+                 nargs=None,
+                 const=None,
+                 default=None,
+                 type=None,
+                 choices=None,
+                 required=False,
+                 help=None,
+                 metavar=None):
+        if nargs == 0:
+            raise ValueError('nargs for append actions must be > 0; if arg '
+                             'strings are not supplying the value to append, '
+                             'the append const action may be more appropriate')
+        if const is not None and nargs != OPTIONAL:
+            raise ValueError('nargs must be %r to supply const' % OPTIONAL)
+        super(_AppendAction, self).__init__(
+            option_strings=option_strings,
+            dest=dest,
+            nargs=nargs,
+            const=const,
+            default=default,
+            type=type,
+            choices=choices,
+            required=required,
+            help=help,
+            metavar=metavar)
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        items = _copy.copy(_ensure_value(namespace, self.dest, []))
+        items.append(values)
+        setattr(namespace, self.dest, items)
+
+
+class _AppendConstAction(Action):
+
+    def __init__(self,
+                 option_strings,
+                 dest,
+                 const,
+                 default=None,
+                 required=False,
+                 help=None,
+                 metavar=None):
+        super(_AppendConstAction, self).__init__(
+            option_strings=option_strings,
+            dest=dest,
+            nargs=0,
+            const=const,
+            default=default,
+            required=required,
+            help=help,
+            metavar=metavar)
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        items = _copy.copy(_ensure_value(namespace, self.dest, []))
+        items.append(self.const)
+        setattr(namespace, self.dest, items)
+
+
+class _CountAction(Action):
+
+    def __init__(self,
+                 option_strings,
+                 dest,
+                 default=None,
+                 required=False,
+                 help=None):
+        super(_CountAction, self).__init__(
+            option_strings=option_strings,
+            dest=dest,
+            nargs=0,
+            default=default,
+            required=required,
+            help=help)
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        new_count = _ensure_value(namespace, self.dest, 0) + 1
+        setattr(namespace, self.dest, new_count)
+
+
+class _HelpAction(Action):
+
+    def __init__(self,
+                 option_strings,
+                 dest=SUPPRESS,
+                 default=SUPPRESS,
+                 help=None):
+        super(_HelpAction, self).__init__(
+            option_strings=option_strings,
+            dest=dest,
+            default=default,
+            nargs=0,
+            help=help)
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        parser.print_help()
+        parser.exit()
+
+
+class _VersionAction(Action):
+
+    def __init__(self,
+                 option_strings,
+                 version=None,
+                 dest=SUPPRESS,
+                 default=SUPPRESS,
+                 help="show program's version number and exit"):
+        super(_VersionAction, self).__init__(
+            option_strings=option_strings,
+            dest=dest,
+            default=default,
+            nargs=0,
+            help=help)
+        self.version = version
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        version = self.version
+        if version is None:
+            version = parser.version
+        formatter = parser._get_formatter()
+        formatter.add_text(version)
+        parser.exit(message=formatter.format_help())
+
+
+class _SubParsersAction(Action):
+
+    class _ChoicesPseudoAction(Action):
+
+        def __init__(self, name, help):
+            sup = super(_SubParsersAction._ChoicesPseudoAction, self)
+            sup.__init__(option_strings=[], dest=name, help=help)
+
+    def __init__(self,
+                 option_strings,
+                 prog,
+                 parser_class,
+                 dest=SUPPRESS,
+                 help=None,
+                 metavar=None):
+
+        self._prog_prefix = prog
+        self._parser_class = parser_class
+        self._name_parser_map = {}
+        self._choices_actions = []
+
+        super(_SubParsersAction, self).__init__(
+            option_strings=option_strings,
+            dest=dest,
+            nargs=PARSER,
+            choices=self._name_parser_map,
+            help=help,
+            metavar=metavar)
+
+    def add_parser(self, name, **kwargs):
+        # set prog from the existing prefix
+        if kwargs.get('prog') is None:
+            kwargs['prog'] = '%s %s' % (self._prog_prefix, name)
+
+        # create a pseudo-action to hold the choice help
+        if 'help' in kwargs:
+            help = kwargs.pop('help')
+            choice_action = self._ChoicesPseudoAction(name, help)
+            self._choices_actions.append(choice_action)
+
+        # create the parser and add it to the map
+        parser = self._parser_class(**kwargs)
+        self._name_parser_map[name] = parser
+        return parser
+
+    def _get_subactions(self):
+        return self._choices_actions
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        parser_name = values[0]
+        arg_strings = values[1:]
+
+        # set the parser name if requested
+        if self.dest is not SUPPRESS:
+            setattr(namespace, self.dest, parser_name)
+
+        # select the parser
+        try:
+            parser = self._name_parser_map[parser_name]
+        except KeyError:
+            tup = parser_name, ', '.join(self._name_parser_map)
+            msg = _('unknown parser %r (choices: %s)' % tup)
+            raise ArgumentError(self, msg)
+
+        # parse all the remaining options into the namespace
+        # store any unrecognized options on the object, so that the top
+        # level parser can decide what to do with them
+        namespace, arg_strings = parser.parse_known_args(arg_strings, namespace)
+        if arg_strings:
+            vars(namespace).setdefault(_UNRECOGNIZED_ARGS_ATTR, [])
+            getattr(namespace, _UNRECOGNIZED_ARGS_ATTR).extend(arg_strings)
+
+
+# ==============
+# Type classes
+# ==============
+
+class FileType(object):
+    """Factory for creating file object types
+
+    Instances of FileType are typically passed as type= arguments to the
+    ArgumentParser add_argument() method.
+
+    Keyword Arguments:
+        - mode -- A string indicating how the file is to be opened. Accepts the
+            same values as the builtin open() function.
+        - bufsize -- The file's desired buffer size. Accepts the same values as
+            the builtin open() function.
+    """
+
+    def __init__(self, mode='r', bufsize=None):
+        self._mode = mode
+        self._bufsize = bufsize
+
+    def __call__(self, string):
+        # the special argument "-" means sys.std{in,out}
+        if string == '-':
+            if 'r' in self._mode:
+                return _sys.stdin
+            elif 'w' in self._mode:
+                return _sys.stdout
+            else:
+                msg = _('argument "-" with mode %r' % self._mode)
+                raise ValueError(msg)
+
+        # all other arguments are used as file names
+        if self._bufsize:
+            return open(string, self._mode, self._bufsize)
+        else:
+            return open(string, self._mode)
+
+    def __repr__(self):
+        args = [self._mode, self._bufsize]
+        args_str = ', '.join([repr(arg) for arg in args if arg is not None])
+        return '%s(%s)' % (type(self).__name__, args_str)
+
+# ===========================
+# Optional and Positional Parsing
+# ===========================
+
+class Namespace(_AttributeHolder):
+    """Simple object for storing attributes.
+
+    Implements equality by attribute names and values, and provides a simple
+    string representation.
+    """
+
+    def __init__(self, **kwargs):
+        for name in kwargs:
+            setattr(self, name, kwargs[name])
+
+    __hash__ = None
+
+    def __eq__(self, other):
+        return vars(self) == vars(other)
+
+    def __ne__(self, other):
+        return not (self == other)
+
+    def __contains__(self, key):
+        return key in self.__dict__
+
+
+class _ActionsContainer(object):
+
+    def __init__(self,
+                 description,
+                 prefix_chars,
+                 argument_default,
+                 conflict_handler):
+        super(_ActionsContainer, self).__init__()
+
+        self.description = description
+        self.argument_default = argument_default
+        self.prefix_chars = prefix_chars
+        self.conflict_handler = conflict_handler
+
+        # set up registries
+        self._registries = {}
+
+        # register actions
+        self.register('action', None, _StoreAction)
+        self.register('action', 'store', _StoreAction)
+        self.register('action', 'store_const', _StoreConstAction)
+        self.register('action', 'store_true', _StoreTrueAction)
+        self.register('action', 'store_false', _StoreFalseAction)
+        self.register('action', 'append', _AppendAction)
+        self.register('action', 'append_const', _AppendConstAction)
+        self.register('action', 'count', _CountAction)
+        self.register('action', 'help', _HelpAction)
+        self.register('action', 'version', _VersionAction)
+        self.register('action', 'parsers', _SubParsersAction)
+
+        # raise an exception if the conflict handler is invalid
+        self._get_handler()
+
+        # action storage
+        self._actions = []
+        self._option_string_actions = {}
+
+        # groups
+        self._action_groups = []
+        self._mutually_exclusive_groups = []
+
+        # defaults storage
+        self._defaults = {}
+
+        # determines whether an "option" looks like a negative number
+        self._negative_number_matcher = _re.compile(r'^-\d+$|^-\d*\.\d+$')
+
+        # whether or not there are any optionals that look like negative
+        # numbers -- uses a list so it can be shared and edited
+        self._has_negative_number_optionals = []
+
+    # ====================
+    # Registration methods
+    # ====================
+    def register(self, registry_name, value, object):
+        registry = self._registries.setdefault(registry_name, {})
+        registry[value] = object
+
+    def _registry_get(self, registry_name, value, default=None):
+        return self._registries[registry_name].get(value, default)
+
+    # ==================================
+    # Namespace default accessor methods
+    # ==================================
+    def set_defaults(self, **kwargs):
+        self._defaults.update(kwargs)
+
+        # if these defaults match any existing arguments, replace
+        # the previous default on the object with the new one
+        for action in self._actions:
+            if action.dest in kwargs:
+                action.default = kwargs[action.dest]
+
+    def get_default(self, dest):
+        for action in self._actions:
+            if action.dest == dest and action.default is not None:
+                return action.default
+        return self._defaults.get(dest, None)
+
+
+    # =======================
+    # Adding argument actions
+    # =======================
+    def add_argument(self, *args, **kwargs):
+        """
+        add_argument(dest, ..., name=value, ...)
+        add_argument(option_string, option_string, ..., name=value, ...)
+        """
+
+        # if no positional args are supplied or only one is supplied and
+        # it doesn't look like an option string, parse a positional
+        # argument
+        chars = self.prefix_chars
+        if not args or len(args) == 1 and args[0][0] not in chars:
+            if args and 'dest' in kwargs:
+                raise ValueError('dest supplied twice for positional argument')
+            kwargs = self._get_positional_kwargs(*args, **kwargs)
+
+        # otherwise, we're adding an optional argument
+        else:
+            kwargs = self._get_optional_kwargs(*args, **kwargs)
+
+        # if no default was supplied, use the parser-level default
+        if 'default' not in kwargs:
+            dest = kwargs['dest']
+            if dest in self._defaults:
+                kwargs['default'] = self._defaults[dest]
+            elif self.argument_default is not None:
+                kwargs['default'] = self.argument_default
+
+        # create the action object, and add it to the parser
+        action_class = self._pop_action_class(kwargs)
+        if not _callable(action_class):
+            raise ValueError('unknown action "%s"' % action_class)
+        action = action_class(**kwargs)
+
+        # raise an error if the action type is not callable
+        type_func = self._registry_get('type', action.type, action.type)
+        if not _callable(type_func):
+            raise ValueError('%r is not callable' % type_func)
+
+        return self._add_action(action)
+
+    def add_argument_group(self, *args, **kwargs):
+        group = _ArgumentGroup(self, *args, **kwargs)
+        self._action_groups.append(group)
+        return group
+
+    def add_mutually_exclusive_group(self, **kwargs):
+        group = _MutuallyExclusiveGroup(self, **kwargs)
+        self._mutually_exclusive_groups.append(group)
+        return group
+
+    def _add_action(self, action):
+        # resolve any conflicts
+        self._check_conflict(action)
+
+        # add to actions list
+        self._actions.append(action)
+        action.container = self
+
+        # index the action by any option strings it has
+        for option_string in action.option_strings:
+            self._option_string_actions[option_string] = action
+
+        # set the flag if any option strings look like negative numbers
+        for option_string in action.option_strings:
+            if self._negative_number_matcher.match(option_string):
+                if not self._has_negative_number_optionals:
+                    self._has_negative_number_optionals.append(True)
+
+        # return the created action
+        return action
+
+    def _remove_action(self, action):
+        self._actions.remove(action)
+
+    def _add_container_actions(self, container):
+        # collect groups by titles
+        title_group_map = {}
+        for group in self._action_groups:
+            if group.title in title_group_map:
+                msg = _('cannot merge actions - two groups are named %r')
+                raise ValueError(msg % (group.title))
+            title_group_map[group.title] = group
+
+        # map each action to its group
+        group_map = {}
+        for group in container._action_groups:
+
+            # if a group with the title exists, use that, otherwise
+            # create a new group matching the container's group
+            if group.title not in title_group_map:
+                title_group_map[group.title] = self.add_argument_group(
+                    title=group.title,
+                    description=group.description,
+                    conflict_handler=group.conflict_handler)
+
+            # map the actions to their new group
+            for action in group._group_actions:
+                group_map[action] = title_group_map[group.title]
+
+        # add container's mutually exclusive groups
+        # NOTE: if add_mutually_exclusive_group ever gains title= and
+        # description= then this code will need to be expanded as above
+        for group in container._mutually_exclusive_groups:
+            mutex_group = self.add_mutually_exclusive_group(
+                required=group.required)
+
+            # map the actions to their new mutex group
+            for action in group._group_actions:
+                group_map[action] = mutex_group
+
+        # add all actions to this container or their group
+        for action in container._actions:
+            group_map.get(action, self)._add_action(action)
+
+    def _get_positional_kwargs(self, dest, **kwargs):
+        # make sure required is not specified
+        if 'required' in kwargs:
+            msg = _("'required' is an invalid argument for positionals")
+            raise TypeError(msg)
+
+        # mark positional arguments as required if at least one is
+        # always required
+        if kwargs.get('nargs') not in [OPTIONAL, ZERO_OR_MORE]:
+            kwargs['required'] = True
+        if kwargs.get('nargs') == ZERO_OR_MORE and 'default' not in kwargs:
+            kwargs['required'] = True
+
+        # return the keyword arguments with no option strings
+        return dict(kwargs, dest=dest, option_strings=[])
+
+    def _get_optional_kwargs(self, *args, **kwargs):
+        # determine short and long option strings
+        option_strings = []
+        long_option_strings = []
+        for option_string in args:
+            # error on strings that don't start with an appropriate prefix
+            if not option_string[0] in self.prefix_chars:
+                msg = _('invalid option string %r: '
+                        'must start with a character %r')
+                tup = option_string, self.prefix_chars
+                raise ValueError(msg % tup)
+
+            # strings starting with two prefix characters are long options
+            option_strings.append(option_string)
+            if option_string[0] in self.prefix_chars:
+                if len(option_string) > 1:
+                    if option_string[1] in self.prefix_chars:
+                        long_option_strings.append(option_string)
+
+        # infer destination, '--foo-bar' -> 'foo_bar' and '-x' -> 'x'
+        dest = kwargs.pop('dest', None)
+        if dest is None:
+            if long_option_strings:
+                dest_option_string = long_option_strings[0]
+            else:
+                dest_option_string = option_strings[0]
+            dest = dest_option_string.lstrip(self.prefix_chars)
+            if not dest:
+                msg = _('dest= is required for options like %r')
+                raise ValueError(msg % option_string)
+            dest = dest.replace('-', '_')
+
+        # return the updated keyword arguments
+        return dict(kwargs, dest=dest, option_strings=option_strings)
+
+    def _pop_action_class(self, kwargs, default=None):
+        action = kwargs.pop('action', default)
+        return self._registry_get('action', action, action)
+
+    def _get_handler(self):
+        # determine function from conflict handler string
+        handler_func_name = '_handle_conflict_%s' % self.conflict_handler
+        try:
+            return getattr(self, handler_func_name)
+        except AttributeError:
+            msg = _('invalid conflict_resolution value: %r')
+            raise ValueError(msg % self.conflict_handler)
+
+    def _check_conflict(self, action):
+
+        # find all options that conflict with this option
+        confl_optionals = []
+        for option_string in action.option_strings:
+            if option_string in self._option_string_actions:
+                confl_optional = self._option_string_actions[option_string]
+                confl_optionals.append((option_string, confl_optional))
+
+        # resolve any conflicts
+        if confl_optionals:
+            conflict_handler = self._get_handler()
+            conflict_handler(action, confl_optionals)
+
+    def _handle_conflict_error(self, action, conflicting_actions):
+        message = _('conflicting option string(s): %s')
+        conflict_string = ', '.join([option_string
+                                     for option_string, action
+                                     in conflicting_actions])
+        raise ArgumentError(action, message % conflict_string)
+
+    def _handle_conflict_resolve(self, action, conflicting_actions):
+
+        # remove all conflicting options
+        for option_string, action in conflicting_actions:
+
+            # remove the conflicting option
+            action.option_strings.remove(option_string)
+            self._option_string_actions.pop(option_string, None)
+
+            # if the option now has no option string, remove it from the
+            # container holding it
+            if not action.option_strings:
+                action.container._remove_action(action)
+
+
+class _ArgumentGroup(_ActionsContainer):
+
+    def __init__(self, container, title=None, description=None, **kwargs):
+        # add any missing keyword arguments by checking the container
+        update = kwargs.setdefault
+        update('conflict_handler', container.conflict_handler)
+        update('prefix_chars', container.prefix_chars)
+        update('argument_default', container.argument_default)
+        super_init = super(_ArgumentGroup, self).__init__
+        super_init(description=description, **kwargs)
+
+        # group attributes
+        self.title = title
+        self._group_actions = []
+
+        # share most attributes with the container
+        self._registries = container._registries
+        self._actions = container._actions
+        self._option_string_actions = container._option_string_actions
+        self._defaults = container._defaults
+        self._has_negative_number_optionals = \
+            container._has_negative_number_optionals
+
+    def _add_action(self, action):
+        action = super(_ArgumentGroup, self)._add_action(action)
+        self._group_actions.append(action)
+        return action
+
+    def _remove_action(self, action):
+        super(_ArgumentGroup, self)._remove_action(action)
+        self._group_actions.remove(action)
+
+
+class _MutuallyExclusiveGroup(_ArgumentGroup):
+
+    def __init__(self, container, required=False):
+        super(_MutuallyExclusiveGroup, self).__init__(container)
+        self.required = required
+        self._container = container
+
+    def _add_action(self, action):
+        if action.required:
+            msg = _('mutually exclusive arguments must be optional')
+            raise ValueError(msg)
+        action = self._container._add_action(action)
+        self._group_actions.append(action)
+        return action
+
+    def _remove_action(self, action):
+        self._container._remove_action(action)
+        self._group_actions.remove(action)
+
+
+class ArgumentParser(_AttributeHolder, _ActionsContainer):
+    """Object for parsing command line strings into Python objects.
+
+    Keyword Arguments:
+        - prog -- The name of the program (default: sys.argv[0])
+        - usage -- A usage message (default: auto-generated from arguments)
+        - description -- A description of what the program does
+        - epilog -- Text following the argument descriptions
+        - parents -- Parsers whose arguments should be copied into this one
+        - formatter_class -- HelpFormatter class for printing help messages
+        - prefix_chars -- Characters that prefix optional arguments
+        - fromfile_prefix_chars -- Characters that prefix files containing
+            additional arguments
+        - argument_default -- The default value for all arguments
+        - conflict_handler -- String indicating how to handle conflicts
+        - add_help -- Add a -h/-help option
+    """
+
+    def __init__(self,
+                 prog=None,
+                 usage=None,
+                 description=None,
+                 epilog=None,
+                 version=None,
+                 parents=[],
+                 formatter_class=HelpFormatter,
+                 prefix_chars='-',
+                 fromfile_prefix_chars=None,
+                 argument_default=None,
+                 conflict_handler='error',
+                 add_help=True):
+
+        if version is not None:
+            import warnings
+            warnings.warn(
+                """The "version" argument to ArgumentParser is deprecated. """
+                """Please use """
+                """"add_argument(..., action='version', version="N", ...)" """
+                """instead""", DeprecationWarning)
+
+        superinit = super(ArgumentParser, self).__init__
+        superinit(description=description,
+                  prefix_chars=prefix_chars,
+                  argument_default=argument_default,
+                  conflict_handler=conflict_handler)
+
+        # default setting for prog
+        if prog is None:
+            prog = _os.path.basename(_sys.argv[0])
+
+        self.prog = prog
+        self.usage = usage
+        self.epilog = epilog
+        self.version = version
+        self.formatter_class = formatter_class
+        self.fromfile_prefix_chars = fromfile_prefix_chars
+        self.add_help = add_help
+
+        add_group = self.add_argument_group
+        self._positionals = add_group(_('positional arguments'))
+        self._optionals = add_group(_('optional arguments'))
+        self._subparsers = None
+
+        # register types
+        def identity(string):
+            return string
+        self.register('type', None, identity)
+
+        # add help and version arguments if necessary
+        # (using explicit default to override global argument_default)
+        if '-' in prefix_chars:
+            default_prefix = '-'
+        else:
+            default_prefix = prefix_chars[0]
+        if self.add_help:
+            self.add_argument(
+                default_prefix+'h', default_prefix*2+'help',
+                action='help', default=SUPPRESS,
+                help=_('show this help message and exit'))
+        if self.version:
+            self.add_argument(
+                default_prefix+'v', default_prefix*2+'version',
+                action='version', default=SUPPRESS,
+                version=self.version,
+                help=_("show program's version number and exit"))
+
+        # add parent arguments and defaults
+        for parent in parents:
+            self._add_container_actions(parent)
+            try:
+                defaults = parent._defaults
+            except AttributeError:
+                pass
+            else:
+                self._defaults.update(defaults)
+
+    # =======================
+    # Pretty __repr__ methods
+    # =======================
+    def _get_kwargs(self):
+        names = [
+            'prog',
+            'usage',
+            'description',
+            'version',
+            'formatter_class',
+            'conflict_handler',
+            'add_help',
+        ]
+        return [(name, getattr(self, name)) for name in names]
+
+    # ==================================
+    # Optional/Positional adding methods
+    # ==================================
+    def add_subparsers(self, **kwargs):
+        if self._subparsers is not None:
+            self.error(_('cannot have multiple subparser arguments'))
+
+        # add the parser class to the arguments if it's not present
+        kwargs.setdefault('parser_class', type(self))
+
+        if 'title' in kwargs or 'description' in kwargs:
+            title = _(kwargs.pop('title', 'subcommands'))
+            description = _(kwargs.pop('description', None))
+            self._subparsers = self.add_argument_group(title, description)
+        else:
+            self._subparsers = self._positionals
+
+        # prog defaults to the usage message of this parser, skipping
+        # optional arguments and with no "usage:" prefix
+        if kwargs.get('prog') is None:
+            formatter = self._get_formatter()
+            positionals = self._get_positional_actions()
+            groups = self._mutually_exclusive_groups
+            formatter.add_usage(self.usage, positionals, groups, '')
+            kwargs['prog'] = formatter.format_help().strip()
+
+        # create the parsers action and add it to the positionals list
+        parsers_class = self._pop_action_class(kwargs, 'parsers')
+        action = parsers_class(option_strings=[], **kwargs)
+        self._subparsers._add_action(action)
+
+        # return the created parsers action
+        return action
+
+    def _add_action(self, action):
+        if action.option_strings:
+            self._optionals._add_action(action)
+        else:
+            self._positionals._add_action(action)
+        return action
+
+    def _get_optional_actions(self):
+        return [action
+                for action in self._actions
+                if action.option_strings]
+
+    def _get_positional_actions(self):
+        return [action
+                for action in self._actions
+                if not action.option_strings]
+
+    # =====================================
+    # Command line argument parsing methods
+    # =====================================
+    def parse_args(self, args=None, namespace=None):
+        args, argv = self.parse_known_args(args, namespace)
+        if argv:
+            msg = _('unrecognized arguments: %s')
+            self.error(msg % ' '.join(argv))
+        return args
+
+    def parse_known_args(self, args=None, namespace=None):
+        # args default to the system args
+        if args is None:
+            args = _sys.argv[1:]
+
+        # default Namespace built from parser defaults
+        if namespace is None:
+            namespace = Namespace()
+
+        # add any action defaults that aren't present
+        for action in self._actions:
+            if action.dest is not SUPPRESS:
+                if not hasattr(namespace, action.dest):
+                    if action.default is not SUPPRESS:
+                        default = action.default
+                        if isinstance(action.default, basestring):
+                            default = self._get_value(action, default)
+                        setattr(namespace, action.dest, default)
+
+        # add any parser defaults that aren't present
+        for dest in self._defaults:
+            if not hasattr(namespace, dest):
+                setattr(namespace, dest, self._defaults[dest])
+
+        # parse the arguments and exit if there are any errors
+        try:
+            namespace, args = self._parse_known_args(args, namespace)
+            if hasattr(namespace, _UNRECOGNIZED_ARGS_ATTR):
+                args.extend(getattr(namespace, _UNRECOGNIZED_ARGS_ATTR))
+                delattr(namespace, _UNRECOGNIZED_ARGS_ATTR)
+            return namespace, args
+        except ArgumentError:
+            err = _sys.exc_info()[1]
+            self.error(str(err))
+
+    def _parse_known_args(self, arg_strings, namespace):
+        # replace arg strings that are file references
+        if self.fromfile_prefix_chars is not None:
+            arg_strings = self._read_args_from_files(arg_strings)
+
+        # map all mutually exclusive arguments to the other arguments
+        # they can't occur with
+        action_conflicts = {}
+        for mutex_group in self._mutually_exclusive_groups:
+            group_actions = mutex_group._group_actions
+            for i, mutex_action in enumerate(mutex_group._group_actions):
+                conflicts = action_conflicts.setdefault(mutex_action, [])
+                conflicts.extend(group_actions[:i])
+                conflicts.extend(group_actions[i + 1:])
+
+        # find all option indices, and determine the arg_string_pattern
+        # which has an 'O' if there is an option at an index,
+        # an 'A' if there is an argument, or a '-' if there is a '--'
+        option_string_indices = {}
+        arg_string_pattern_parts = []
+        arg_strings_iter = iter(arg_strings)
+        for i, arg_string in enumerate(arg_strings_iter):
+
+            # all args after -- are non-options
+            if arg_string == '--':
+                arg_string_pattern_parts.append('-')
+                for arg_string in arg_strings_iter:
+                    arg_string_pattern_parts.append('A')
+
+            # otherwise, add the arg to the arg strings
+            # and note the index if it was an option
+            else:
+                option_tuple = self._parse_optional(arg_string)
+                if option_tuple is None:
+                    pattern = 'A'
+                else:
+                    option_string_indices[i] = option_tuple
+                    pattern = 'O'
+                arg_string_pattern_parts.append(pattern)
+
+        # join the pieces together to form the pattern
+        arg_strings_pattern = ''.join(arg_string_pattern_parts)
+
+        # converts arg strings to the appropriate and then takes the action
+        seen_actions = set()
+        seen_non_default_actions = set()
+
+        def take_action(action, argument_strings, option_string=None):
+            seen_actions.add(action)
+            argument_values = self._get_values(action, argument_strings)
+
+            # error if this argument is not allowed with other previously
+            # seen arguments, assuming that actions that use the default
+            # value don't really count as "present"
+            if argument_values is not action.default:
+                seen_non_default_actions.add(action)
+                for conflict_action in action_conflicts.get(action, []):
+                    if conflict_action in seen_non_default_actions:
+                        msg = _('not allowed with argument %s')
+                        action_name = _get_action_name(conflict_action)
+                        raise ArgumentError(action, msg % action_name)
+
+            # take the action if we didn't receive a SUPPRESS value
+            # (e.g. from a default)
+            if argument_values is not SUPPRESS:
+                action(self, namespace, argument_values, option_string)
+
+        # function to convert arg_strings into an optional action
+        def consume_optional(start_index):
+
+            # get the optional identified at this index
+            option_tuple = option_string_indices[start_index]
+            action, option_string, explicit_arg = option_tuple
+
+            # identify additional optionals in the same arg string
+            # (e.g. -xyz is the same as -x -y -z if no args are required)
+            match_argument = self._match_argument
+            action_tuples = []
+            while True:
+
+                # if we found no optional action, skip it
+                if action is None:
+                    extras.append(arg_strings[start_index])
+                    return start_index + 1
+
+                # if there is an explicit argument, try to match the
+                # optional's string arguments to only this
+                if explicit_arg is not None:
+                    arg_count = match_argument(action, 'A')
+
+                    # if the action is a single-dash option and takes no
+                    # arguments, try to parse more single-dash options out
+                    # of the tail of the option string
+                    chars = self.prefix_chars
+                    if arg_count == 0 and option_string[1] not in chars:
+                        action_tuples.append((action, [], option_string))
+                        char = option_string[0]
+                        option_string = char + explicit_arg[0]
+                        new_explicit_arg = explicit_arg[1:] or None
+                        optionals_map = self._option_string_actions
+                        if option_string in optionals_map:
+                            action = optionals_map[option_string]
+                            explicit_arg = new_explicit_arg
+                        else:
+                            msg = _('ignored explicit argument %r')
+                            raise ArgumentError(action, msg % explicit_arg)
+
+                    # if the action expect exactly one argument, we've
+                    # successfully matched the option; exit the loop
+                    elif arg_count == 1:
+                        stop = start_index + 1
+                        args = [explicit_arg]
+                        action_tuples.append((action, args, option_string))
+                        break
+
+                    # error if a double-dash option did not use the
+                    # explicit argument
+                    else:
+                        msg = _('ignored explicit argument %r')
+                        raise ArgumentError(action, msg % explicit_arg)
+
+                # if there is no explicit argument, try to match the
+                # optional's string arguments with the following strings
+                # if successful, exit the loop
+                else:
+                    start = start_index + 1
+                    selected_patterns = arg_strings_pattern[start:]
+                    arg_count = match_argument(action, selected_patterns)
+                    stop = start + arg_count
+                    args = arg_strings[start:stop]
+                    action_tuples.append((action, args, option_string))
+                    break
+
+            # add the Optional to the list and return the index at which
+            # the Optional's string args stopped
+            assert action_tuples
+            for action, args, option_string in action_tuples:
+                take_action(action, args, option_string)
+            return stop
+
+        # the list of Positionals left to be parsed; this is modified
+        # by consume_positionals()
+        positionals = self._get_positional_actions()
+
+        # function to convert arg_strings into positional actions
+        def consume_positionals(start_index):
+            # match as many Positionals as possible
+            match_partial = self._match_arguments_partial
+            selected_pattern = arg_strings_pattern[start_index:]
+            arg_counts = match_partial(positionals, selected_pattern)
+
+            # slice off the appropriate arg strings for each Positional
+            # and add the Positional and its args to the list
+            for action, arg_count in zip(positionals, arg_counts):
+                args = arg_strings[start_index: start_index + arg_count]
+                start_index += arg_count
+                take_action(action, args)
+
+            # slice off the Positionals that we just parsed and return the
+            # index at which the Positionals' string args stopped
+            positionals[:] = positionals[len(arg_counts):]
+            return start_index
+
+        # consume Positionals and Optionals alternately, until we have
+        # passed the last option string
+        extras = []
+        start_index = 0
+        if option_string_indices:
+            max_option_string_index = max(option_string_indices)
+        else:
+            max_option_string_index = -1
+        while start_index <= max_option_string_index:
+
+            # consume any Positionals preceding the next option
+            next_option_string_index = min([
+                index
+                for index in option_string_indices
+                if index >= start_index])
+            if start_index != next_option_string_index:
+                positionals_end_index = consume_positionals(start_index)
+
+                # only try to parse the next optional if we didn't consume
+                # the option string during the positionals parsing
+                if positionals_end_index > start_index:
+                    start_index = positionals_end_index
+                    continue
+                else:
+                    start_index = positionals_end_index
+
+            # if we consumed all the positionals we could and we're not
+            # at the index of an option string, there were extra arguments
+            if start_index not in option_string_indices:
+                strings = arg_strings[start_index:next_option_string_index]
+                extras.extend(strings)
+                start_index = next_option_string_index
+
+            # consume the next optional and any arguments for it
+            start_index = consume_optional(start_index)
+
+        # consume any positionals following the last Optional
+        stop_index = consume_positionals(start_index)
+
+        # if we didn't consume all the argument strings, there were extras
+        extras.extend(arg_strings[stop_index:])
+
+        # if we didn't use all the Positional objects, there were too few
+        # arg strings supplied.
+        if positionals:
+            self.error(_('too few arguments'))
+
+        # make sure all required actions were present
+        for action in self._actions:
+            if action.required:
+                if action not in seen_actions:
+                    name = _get_action_name(action)
+                    self.error(_('argument %s is required') % name)
+
+        # make sure all required groups had one option present
+        for group in self._mutually_exclusive_groups:
+            if group.required:
+                for action in group._group_actions:
+                    if action in seen_non_default_actions:
+                        break
+
+                # if no actions were used, report the error
+                else:
+                    names = [_get_action_name(action)
+                             for action in group._group_actions
+                             if action.help is not SUPPRESS]
+                    msg = _('one of the arguments %s is required')
+                    self.error(msg % ' '.join(names))
+
+        # return the updated namespace and the extra arguments
+        return namespace, extras
+
+    def _read_args_from_files(self, arg_strings):
+        # expand arguments referencing files
+        new_arg_strings = []
+        for arg_string in arg_strings:
+
+            # for regular arguments, just add them back into the list
+            if arg_string[0] not in self.fromfile_prefix_chars:
+                new_arg_strings.append(arg_string)
+
+            # replace arguments referencing files with the file content
+            else:
+                try:
+                    args_file = open(arg_string[1:])
+                    try:
+                        arg_strings = []
+                        for arg_line in args_file.read().splitlines():
+                            for arg in self.convert_arg_line_to_args(arg_line):
+                                arg_strings.append(arg)
+                        arg_strings = self._read_args_from_files(arg_strings)
+                        new_arg_strings.extend(arg_strings)
+                    finally:
+                        args_file.close()
+                except IOError:
+                    err = _sys.exc_info()[1]
+                    self.error(str(err))
+
+        # return the modified argument list
+        return new_arg_strings
+
+    def convert_arg_line_to_args(self, arg_line):
+        return [arg_line]
+
+    def _match_argument(self, action, arg_strings_pattern):
+        # match the pattern for this action to the arg strings
+        nargs_pattern = self._get_nargs_pattern(action)
+        match = _re.match(nargs_pattern, arg_strings_pattern)
+
+        # raise an exception if we weren't able to find a match
+        if match is None:
+            nargs_errors = {
+                None: _('expected one argument'),
+                OPTIONAL: _('expected at most one argument'),
+                ONE_OR_MORE: _('expected at least one argument'),
+            }
+            default = _('expected %s argument(s)') % action.nargs
+            msg = nargs_errors.get(action.nargs, default)
+            raise ArgumentError(action, msg)
+
+        # return the number of arguments matched
+        return len(match.group(1))
+
+    def _match_arguments_partial(self, actions, arg_strings_pattern):
+        # progressively shorten the actions list by slicing off the
+        # final actions until we find a match
+        result = []
+        for i in range(len(actions), 0, -1):
+            actions_slice = actions[:i]
+            pattern = ''.join([self._get_nargs_pattern(action)
+                               for action in actions_slice])
+            match = _re.match(pattern, arg_strings_pattern)
+            if match is not None:
+                result.extend([len(string) for string in match.groups()])
+                break
+
+        # return the list of arg string counts
+        return result
+
+    def _parse_optional(self, arg_string):
+        # if it's an empty string, it was meant to be a positional
+        if not arg_string:
+            return None
+
+        # if it doesn't start with a prefix, it was meant to be positional
+        if not arg_string[0] in self.prefix_chars:
+            return None
+
+        # if the option string is present in the parser, return the action
+        if arg_string in self._option_string_actions:
+            action = self._option_string_actions[arg_string]
+            return action, arg_string, None
+
+        # if it's just a single character, it was meant to be positional
+        if len(arg_string) == 1:
+            return None
+
+        # if the option string before the "=" is present, return the action
+        if '=' in arg_string:
+            option_string, explicit_arg = arg_string.split('=', 1)
+            if option_string in self._option_string_actions:
+                action = self._option_string_actions[option_string]
+                return action, option_string, explicit_arg
+
+        # search through all possible prefixes of the option string
+        # and all actions in the parser for possible interpretations
+        option_tuples = self._get_option_tuples(arg_string)
+
+        # if multiple actions match, the option string was ambiguous
+        if len(option_tuples) > 1:
+            options = ', '.join([option_string
+                for action, option_string, explicit_arg in option_tuples])
+            tup = arg_string, options
+            self.error(_('ambiguous option: %s could match %s') % tup)
+
+        # if exactly one action matched, this segmentation is good,
+        # so return the parsed action
+        elif len(option_tuples) == 1:
+            option_tuple, = option_tuples
+            return option_tuple
+
+        # if it was not found as an option, but it looks like a negative
+        # number, it was meant to be positional
+        # unless there are negative-number-like options
+        if self._negative_number_matcher.match(arg_string):
+            if not self._has_negative_number_optionals:
+                return None
+
+        # if it contains a space, it was meant to be a positional
+        if ' ' in arg_string:
+            return None
+
+        # it was meant to be an optional but there is no such option
+        # in this parser (though it might be a valid option in a subparser)
+        return None, arg_string, None
+
+    def _get_option_tuples(self, option_string):
+        result = []
+
+        # option strings starting with two prefix characters are only
+        # split at the '='
+        chars = self.prefix_chars
+        if option_string[0] in chars and option_string[1] in chars:
+            if '=' in option_string:
+                option_prefix, explicit_arg = option_string.split('=', 1)
+            else:
+                option_prefix = option_string
+                explicit_arg = None
+            for option_string in self._option_string_actions:
+                if option_string.startswith(option_prefix):
+                    action = self._option_string_actions[option_string]
+                    tup = action, option_string, explicit_arg
+                    result.append(tup)
+
+        # single character options can be concatenated with their arguments
+        # but multiple character options always have to have their argument
+        # separate
+        elif option_string[0] in chars and option_string[1] not in chars:
+            option_prefix = option_string
+            explicit_arg = None
+            short_option_prefix = option_string[:2]
+            short_explicit_arg = option_string[2:]
+
+            for option_string in self._option_string_actions:
+                if option_string == short_option_prefix:
+                    action = self._option_string_actions[option_string]
+                    tup = action, option_string, short_explicit_arg
+                    result.append(tup)
+                elif option_string.startswith(option_prefix):
+                    action = self._option_string_actions[option_string]
+                    tup = action, option_string, explicit_arg
+                    result.append(tup)
+
+        # shouldn't ever get here
+        else:
+            self.error(_('unexpected option string: %s') % option_string)
+
+        # return the collected option tuples
+        return result
+
+    def _get_nargs_pattern(self, action):
+        # in all examples below, we have to allow for '--' args
+        # which are represented as '-' in the pattern
+        nargs = action.nargs
+
+        # the default (None) is assumed to be a single argument
+        if nargs is None:
+            nargs_pattern = '(-*A-*)'
+
+        # allow zero or one arguments
+        elif nargs == OPTIONAL:
+            nargs_pattern = '(-*A?-*)'
+
+        # allow zero or more arguments
+        elif nargs == ZERO_OR_MORE:
+            nargs_pattern = '(-*[A-]*)'
+
+        # allow one or more arguments
+        elif nargs == ONE_OR_MORE:
+            nargs_pattern = '(-*A[A-]*)'
+
+        # allow any number of options or arguments
+        elif nargs == REMAINDER:
+            nargs_pattern = '([-AO]*)'
+
+        # allow one argument followed by any number of options or arguments
+        elif nargs == PARSER:
+            nargs_pattern = '(-*A[-AO]*)'
+
+        # all others should be integers
+        else:
+            nargs_pattern = '(-*%s-*)' % '-*'.join('A' * nargs)
+
+        # if this is an optional action, -- is not allowed
+        if action.option_strings:
+            nargs_pattern = nargs_pattern.replace('-*', '')
+            nargs_pattern = nargs_pattern.replace('-', '')
+
+        # return the pattern
+        return nargs_pattern
+
+    # ========================
+    # Value conversion methods
+    # ========================
+    def _get_values(self, action, arg_strings):
+        # for everything but PARSER args, strip out '--'
+        if action.nargs not in [PARSER, REMAINDER]:
+            arg_strings = [s for s in arg_strings if s != '--']
+
+        # optional argument produces a default when not present
+        if not arg_strings and action.nargs == OPTIONAL:
+            if action.option_strings:
+                value = action.const
+            else:
+                value = action.default
+            if isinstance(value, basestring):
+                value = self._get_value(action, value)
+                self._check_value(action, value)
+
+        # when nargs='*' on a positional, if there were no command-line
+        # args, use the default if it is anything other than None
+        elif (not arg_strings and action.nargs == ZERO_OR_MORE and
+              not action.option_strings):
+            if action.default is not None:
+                value = action.default
+            else:
+                value = arg_strings
+            self._check_value(action, value)
+
+        # single argument or optional argument produces a single value
+        elif len(arg_strings) == 1 and action.nargs in [None, OPTIONAL]:
+            arg_string, = arg_strings
+            value = self._get_value(action, arg_string)
+            self._check_value(action, value)
+
+        # REMAINDER arguments convert all values, checking none
+        elif action.nargs == REMAINDER:
+            value = [self._get_value(action, v) for v in arg_strings]
+
+        # PARSER arguments convert all values, but check only the first
+        elif action.nargs == PARSER:
+            value = [self._get_value(action, v) for v in arg_strings]
+            self._check_value(action, value[0])
+
+        # all other types of nargs produce a list
+        else:
+            value = [self._get_value(action, v) for v in arg_strings]
+            for v in value:
+                self._check_value(action, v)
+
+        # return the converted value
+        return value
+
+    def _get_value(self, action, arg_string):
+        type_func = self._registry_get('type', action.type, action.type)
+        if not _callable(type_func):
+            msg = _('%r is not callable')
+            raise ArgumentError(action, msg % type_func)
+
+        # convert the value to the appropriate type
+        try:
+            result = type_func(arg_string)
+
+        # ArgumentTypeErrors indicate errors
+        except ArgumentTypeError:
+            name = getattr(action.type, '__name__', repr(action.type))
+            msg = str(_sys.exc_info()[1])
+            raise ArgumentError(action, msg)
+
+        # TypeErrors or ValueErrors also indicate errors
+        except (TypeError, ValueError):
+            name = getattr(action.type, '__name__', repr(action.type))
+            msg = _('invalid %s value: %r')
+            raise ArgumentError(action, msg % (name, arg_string))
+
+        # return the converted value
+        return result
+
+    def _check_value(self, action, value):
+        # converted value must be one of the choices (if specified)
+        if action.choices is not None and value not in action.choices:
+            tup = value, ', '.join(map(repr, action.choices))
+            msg = _('invalid choice: %r (choose from %s)') % tup
+            raise ArgumentError(action, msg)
+
+    # =======================
+    # Help-formatting methods
+    # =======================
+    def format_usage(self):
+        formatter = self._get_formatter()
+        formatter.add_usage(self.usage, self._actions,
+                            self._mutually_exclusive_groups)
+        return formatter.format_help()
+
+    def format_help(self):
+        formatter = self._get_formatter()
+
+        # usage
+        formatter.add_usage(self.usage, self._actions,
+                            self._mutually_exclusive_groups)
+
+        # description
+        formatter.add_text(self.description)
+
+        # positionals, optionals and user-defined groups
+        for action_group in self._action_groups:
+            formatter.start_section(action_group.title)
+            formatter.add_text(action_group.description)
+            formatter.add_arguments(action_group._group_actions)
+            formatter.end_section()
+
+        # epilog
+        formatter.add_text(self.epilog)
+
+        # determine help from format above
+        return formatter.format_help()
+
+    def format_version(self):
+        import warnings
+        warnings.warn(
+            'The format_version method is deprecated -- the "version" '
+            'argument to ArgumentParser is no longer supported.',
+            DeprecationWarning)
+        formatter = self._get_formatter()
+        formatter.add_text(self.version)
+        return formatter.format_help()
+
+    def _get_formatter(self):
+        return self.formatter_class(prog=self.prog)
+
+    # =====================
+    # Help-printing methods
+    # =====================
+    def print_usage(self, file=None):
+        if file is None:
+            file = _sys.stdout
+        self._print_message(self.format_usage(), file)
+
+    def print_help(self, file=None):
+        if file is None:
+            file = _sys.stdout
+        self._print_message(self.format_help(), file)
+
+    def print_version(self, file=None):
+        import warnings
+        warnings.warn(
+            'The print_version method is deprecated -- the "version" '
+            'argument to ArgumentParser is no longer supported.',
+            DeprecationWarning)
+        self._print_message(self.format_version(), file)
+
+    def _print_message(self, message, file=None):
+        if message:
+            if file is None:
+                file = _sys.stderr
+            file.write(message)
+
+    # ===============
+    # Exiting methods
+    # ===============
+    def exit(self, status=0, message=None):
+        if message:
+            self._print_message(message, _sys.stderr)
+        _sys.exit(status)
+
+    def error(self, message):
+        """error(message: string)
+
+        Prints a usage message incorporating the message to stderr and
+        exits.
+
+        If you override this in a subclass, it should not return -- it
+        should either exit or raise an exception.
+        """
+        self.print_usage(_sys.stderr)
+        self.exit(2, _('%s: error: %s\n') % (self.prog, message))
diff --git a/lib/argparse/doc/Makefile b/lib/argparse/doc/Makefile
new file mode 100644
index 0000000..60e53ae
--- /dev/null
+++ b/lib/argparse/doc/Makefile
@@ -0,0 +1,151 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = _build
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  html       to make standalone HTML files"
+	@echo "  dirhtml    to make HTML files named index.html in directories"
+	@echo "  singlehtml to make a single large HTML file"
+	@echo "  pickle     to make pickle files"
+	@echo "  json       to make JSON files"
+	@echo "  htmlhelp   to make HTML files and a HTML help project"
+	@echo "  qthelp     to make HTML files and a qthelp project"
+	@echo "  devhelp    to make HTML files and a Devhelp project"
+	@echo "  epub       to make an epub"
+	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+	@echo "  text       to make text files"
+	@echo "  man        to make manual pages"
+	@echo "  texinfo    to make Texinfo files"
+	@echo "  info       to make Texinfo files and run them through makeinfo"
+	@echo "  gettext    to make PO message catalogs"
+	@echo "  changes    to make an overview of all changed/added/deprecated items"
+	@echo "  linkcheck  to check all external links for integrity"
+	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+	-rm -rf $(BUILDDIR)/*
+
+html:
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+	@echo
+	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+	@echo
+	@echo "Build finished; now you can process the pickle files."
+
+json:
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+	@echo
+	@echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+	@echo
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
+	      ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+	@echo
+	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
+	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/argparse.qhcp"
+	@echo "To view the help file:"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/argparse.qhc"
+
+devhelp:
+	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+	@echo
+	@echo "Build finished."
+	@echo "To view the help file:"
+	@echo "# mkdir -p $$HOME/.local/share/devhelp/argparse"
+	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/argparse"
+	@echo "# devhelp"
+
+epub:
+	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+	@echo
+	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+	@echo "Run \`make' in that directory to run these through (pdf)latex" \
+	      "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through pdflatex..."
+	make -C $(BUILDDIR)/latex all-pdf
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+	@echo
+	@echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+	@echo
+	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo
+	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+	@echo "Run \`make' in that directory to run these through makeinfo" \
+	      "(use \`make info' here to do that automatically)."
+
+info:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo "Running Texinfo files through makeinfo..."
+	make -C $(BUILDDIR)/texinfo info
+	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+	$(SPHINXBUILD) -b gettext $(ALLSPHINXOPTS) $(BUILDDIR)/locale
+	@echo
+	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+	@echo
+	@echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+	@echo
+	@echo "Link check complete; look for any errors in the above output " \
+	      "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+	@echo "Testing of doctests in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/lib/argparse/doc/make.bat b/lib/argparse/doc/make.bat
new file mode 100644
index 0000000..f952e33
--- /dev/null
+++ b/lib/argparse/doc/make.bat
@@ -0,0 +1,188 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+	set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source
+if NOT "%PAPER%" == "" (
+	set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+	:help
+	echo.Please use `make ^<target^>` where ^<target^> is one of
+	echo.  html       to make standalone HTML files
+	echo.  dirhtml    to make HTML files named index.html in directories
+	echo.  singlehtml to make a single large HTML file
+	echo.  pickle     to make pickle files
+	echo.  json       to make JSON files
+	echo.  htmlhelp   to make HTML files and a HTML help project
+	echo.  qthelp     to make HTML files and a qthelp project
+	echo.  devhelp    to make HTML files and a Devhelp project
+	echo.  epub       to make an epub
+	echo.  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+	echo.  text       to make text files
+	echo.  man        to make manual pages
+	echo.  texinfo    to make Texinfo files
+	echo.  gettext    to make PO message catalogs
+	echo.  changes    to make an overview over all changed/added/deprecated items
+	echo.  linkcheck  to check all external links for integrity
+	echo.  doctest    to run all doctests embedded in the documentation if enabled
+	goto end
+)
+
+if "%1" == "clean" (
+	for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+	del /q /s %BUILDDIR%\*
+	goto end
+)
+
+if "%1" == "html" (
+	%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+	goto end
+)
+
+if "%1" == "dirhtml" (
+	%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+	goto end
+)
+
+if "%1" == "singlehtml" (
+	%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+	goto end
+)
+
+if "%1" == "pickle" (
+	%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the pickle files.
+	goto end
+)
+
+if "%1" == "json" (
+	%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the JSON files.
+	goto end
+)
+
+if "%1" == "htmlhelp" (
+	%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+	goto end
+)
+
+if "%1" == "qthelp" (
+	%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+	echo.^> qcollectiongenerator %BUILDDIR%\qthelp\argparse.qhcp
+	echo.To view the help file:
+	echo.^> assistant -collectionFile %BUILDDIR%\qthelp\argparse.ghc
+	goto end
+)
+
+if "%1" == "devhelp" (
+	%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished.
+	goto end
+)
+
+if "%1" == "epub" (
+	%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The epub file is in %BUILDDIR%/epub.
+	goto end
+)
+
+if "%1" == "latex" (
+	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+	goto end
+)
+
+if "%1" == "text" (
+	%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The text files are in %BUILDDIR%/text.
+	goto end
+)
+
+if "%1" == "man" (
+	%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The manual pages are in %BUILDDIR%/man.
+	goto end
+)
+
+if "%1" == "texinfo" (
+	%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+	goto end
+)
+
+if "%1" == "gettext" (
+	%SPHINXBUILD% -b gettext %ALLSPHINXOPTS% %BUILDDIR%/locale
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+	goto end
+)
+
+if "%1" == "changes" (
+	%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.The overview file is in %BUILDDIR%/changes.
+	goto end
+)
+
+if "%1" == "linkcheck" (
+	%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+	goto end
+)
+
+if "%1" == "doctest" (
+	%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+	goto end
+)
+
+:end
diff --git a/lib/argparse/doc/source/Python-License.txt b/lib/argparse/doc/source/Python-License.txt
new file mode 100644
index 0000000..5cdb01e
--- /dev/null
+++ b/lib/argparse/doc/source/Python-License.txt
@@ -0,0 +1,279 @@
+A. HISTORY OF THE SOFTWARE
+==========================
+
+Python was created in the early 1990s by Guido van Rossum at Stichting
+Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
+as a successor of a language called ABC.  Guido remains Python's
+principal author, although it includes many contributions from others.
+
+In 1995, Guido continued his work on Python at the Corporation for
+National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
+in Reston, Virginia where he released several versions of the
+software.
+
+In May 2000, Guido and the Python core development team moved to
+BeOpen.com to form the BeOpen PythonLabs team.  In October of the same
+year, the PythonLabs team moved to Digital Creations (now Zope
+Corporation, see http://www.zope.com).  In 2001, the Python Software
+Foundation (PSF, see http://www.python.org/psf/) was formed, a
+non-profit organization created specifically to own Python-related
+Intellectual Property.  Zope Corporation is a sponsoring member of
+the PSF.
+
+All Python releases are Open Source (see http://www.opensource.org for
+the Open Source Definition).  Historically, most, but not all, Python
+releases have also been GPL-compatible; the table below summarizes
+the various releases.
+
+    Release         Derived     Year        Owner       GPL-
+                    from                                compatible? (1)
+
+    0.9.0 thru 1.2              1991-1995   CWI         yes
+    1.3 thru 1.5.2  1.2         1995-1999   CNRI        yes
+    1.6             1.5.2       2000        CNRI        no
+    2.0             1.6         2000        BeOpen.com  no
+    1.6.1           1.6         2001        CNRI        yes (2)
+    2.1             2.0+1.6.1   2001        PSF         no
+    2.0.1           2.0+1.6.1   2001        PSF         yes
+    2.1.1           2.1+2.0.1   2001        PSF         yes
+    2.2             2.1.1       2001        PSF         yes
+    2.1.2           2.1.1       2002        PSF         yes
+    2.1.3           2.1.2       2002        PSF         yes
+    2.2.1           2.2         2002        PSF         yes
+    2.2.2           2.2.1       2002        PSF         yes
+    2.2.3           2.2.2       2003        PSF         yes
+    2.3             2.2.2       2002-2003   PSF         yes
+    2.3.1           2.3         2002-2003   PSF         yes
+    2.3.2           2.3.1       2002-2003   PSF         yes
+    2.3.3           2.3.2       2002-2003   PSF         yes
+    2.3.4           2.3.3       2004        PSF         yes
+    2.3.5           2.3.4       2005        PSF         yes
+    2.4             2.3         2004        PSF         yes
+    2.4.1           2.4         2005        PSF         yes
+    2.4.2           2.4.1       2005        PSF         yes
+    2.4.3           2.4.2       2006        PSF         yes
+    2.4.4           2.4.3       2006        PSF         yes
+    2.5             2.4         2006        PSF         yes
+    2.5.1           2.5         2007        PSF         yes
+    2.5.2           2.5.1       2008        PSF         yes
+    2.5.3           2.5.2       2008        PSF         yes
+    2.6             2.5         2008        PSF         yes
+    2.6.1           2.6         2008        PSF         yes
+    2.6.2           2.6.1       2009        PSF         yes
+    2.6.3           2.6.2       2009        PSF         yes
+    2.6.4           2.6.3       2009        PSF         yes
+    2.6.5           2.6.4       2010        PSF         yes
+    2.7             2.6         2010        PSF         yes
+
+Footnotes:
+
+(1) GPL-compatible doesn't mean that we're distributing Python under
+    the GPL.  All Python licenses, unlike the GPL, let you distribute
+    a modified version without making your changes open source.  The
+    GPL-compatible licenses make it possible to combine Python with
+    other software that is released under the GPL; the others don't.
+
+(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
+    because its license has a choice of law clause.  According to
+    CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
+    is "not incompatible" with the GPL.
+
+Thanks to the many outside volunteers who have worked under Guido's
+direction to make these releases possible.
+
+
+B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
+===============================================================
+
+PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
+--------------------------------------------
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation
+("PSF"), and the Individual or Organization ("Licensee") accessing and
+otherwise using this software ("Python") in source or binary form and
+its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF hereby
+grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+analyze, test, perform and/or display publicly, prepare derivative works,
+distribute, and otherwise use Python alone or in any derivative version,
+provided, however, that PSF's License Agreement and PSF's notice of copyright,
+i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+Python Software Foundation; All Rights Reserved" are retained in Python alone or
+in any derivative version prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates Python or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Python.
+
+4. PSF is making Python available to Licensee on an "AS IS"
+basis.  PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between PSF and
+Licensee.  This License Agreement does not grant permission to use PSF
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using Python, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
+BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
+-------------------------------------------
+
+BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
+
+1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
+office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
+Individual or Organization ("Licensee") accessing and otherwise using
+this software in source or binary form and its associated
+documentation ("the Software").
+
+2. Subject to the terms and conditions of this BeOpen Python License
+Agreement, BeOpen hereby grants Licensee a non-exclusive,
+royalty-free, world-wide license to reproduce, analyze, test, perform
+and/or display publicly, prepare derivative works, distribute, and
+otherwise use the Software alone or in any derivative version,
+provided, however, that the BeOpen Python License is retained in the
+Software, alone or in any derivative version prepared by Licensee.
+
+3. BeOpen is making the Software available to Licensee on an "AS IS"
+basis.  BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
+SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
+AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
+DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+5. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+6. This License Agreement shall be governed by and interpreted in all
+respects by the law of the State of California, excluding conflict of
+law provisions.  Nothing in this License Agreement shall be deemed to
+create any relationship of agency, partnership, or joint venture
+between BeOpen and Licensee.  This License Agreement does not grant
+permission to use BeOpen trademarks or trade names in a trademark
+sense to endorse or promote products or services of Licensee, or any
+third party.  As an exception, the "BeOpen Python" logos available at
+http://www.pythonlabs.com/logos.html may be used according to the
+permissions granted on that web page.
+
+7. By copying, installing or otherwise using the software, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
+CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
+---------------------------------------
+
+1. This LICENSE AGREEMENT is between the Corporation for National
+Research Initiatives, having an office at 1895 Preston White Drive,
+Reston, VA 20191 ("CNRI"), and the Individual or Organization
+("Licensee") accessing and otherwise using Python 1.6.1 software in
+source or binary form and its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, CNRI
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
+license to reproduce, analyze, test, perform and/or display publicly,
+prepare derivative works, distribute, and otherwise use Python 1.6.1
+alone or in any derivative version, provided, however, that CNRI's
+License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
+1995-2001 Corporation for National Research Initiatives; All Rights
+Reserved" are retained in Python 1.6.1 alone or in any derivative
+version prepared by Licensee.  Alternately, in lieu of CNRI's License
+Agreement, Licensee may substitute the following text (omitting the
+quotes): "Python 1.6.1 is made available subject to the terms and
+conditions in CNRI's License Agreement.  This Agreement together with
+Python 1.6.1 may be located on the Internet using the following
+unique, persistent identifier (known as a handle): 1895.22/1013.  This
+Agreement may also be obtained from a proxy server on the Internet
+using the following URL: http://hdl.handle.net/1895.22/1013".
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates Python 1.6.1 or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Python 1.6.1.
+
+4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
+basis.  CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. This License Agreement shall be governed by the federal
+intellectual property law of the United States, including without
+limitation the federal copyright law, and, to the extent such
+U.S. federal law does not apply, by the law of the Commonwealth of
+Virginia, excluding Virginia's conflict of law provisions.
+Notwithstanding the foregoing, with regard to derivative works based
+on Python 1.6.1 that incorporate non-separable material that was
+previously distributed under the GNU General Public License (GPL), the
+law of the Commonwealth of Virginia shall govern this License
+Agreement only as to issues arising under or with respect to
+Paragraphs 4, 5, and 7 of this License Agreement.  Nothing in this
+License Agreement shall be deemed to create any relationship of
+agency, partnership, or joint venture between CNRI and Licensee.  This
+License Agreement does not grant permission to use CNRI trademarks or
+trade name in a trademark sense to endorse or promote products or
+services of Licensee, or any third party.
+
+8. By clicking on the "ACCEPT" button where indicated, or by copying,
+installing or otherwise using Python 1.6.1, Licensee agrees to be
+bound by the terms and conditions of this License Agreement.
+
+        ACCEPT
+
+
+CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
+--------------------------------------------------
+
+Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
+The Netherlands.  All rights reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/lib/argparse/doc/source/argparse.rst b/lib/argparse/doc/source/argparse.rst
new file mode 100644
index 0000000..0ea8195
--- /dev/null
+++ b/lib/argparse/doc/source/argparse.rst
@@ -0,0 +1,1768 @@
+:mod:`argparse` --- Parser for command line options, arguments and sub-commands
+===============================================================================
+
+.. module:: argparse
+   :synopsis: Command-line option and argument parsing library.
+.. moduleauthor:: Steven Bethard <steven.bethard@gmail.com>
+.. versionadded:: 2.7
+.. sectionauthor:: Steven Bethard <steven.bethard@gmail.com>
+
+
+The :mod:`argparse` module makes it easy to write user friendly command line
+interfaces. The program defines what arguments it requires, and :mod:`argparse`
+will figure out how to parse those out of :data:`sys.argv`.  The :mod:`argparse`
+module also automatically generates help and usage messages and issues errors
+when users give the program invalid arguments.
+
+
+Example
+-------
+
+The following code is a Python program that takes a list of integers and
+produces either the sum or the max::
+
+   import argparse
+
+   parser = argparse.ArgumentParser(description='Process some integers.')
+   parser.add_argument('integers', metavar='N', type=int, nargs='+',
+                      help='an integer for the accumulator')
+   parser.add_argument('--sum', dest='accumulate', action='store_const',
+                      const=sum, default=max,
+                      help='sum the integers (default: find the max)')
+
+   args = parser.parse_args()
+   print args.accumulate(args.integers)
+
+Assuming the Python code above is saved into a file called ``prog.py``, it can
+be run at the command line and provides useful help messages::
+
+   $ prog.py -h
+   usage: prog.py [-h] [--sum] N [N ...]
+
+   Process some integers.
+
+   positional arguments:
+    N           an integer for the accumulator
+
+   optional arguments:
+    -h, --help  show this help message and exit
+    --sum       sum the integers (default: find the max)
+
+When run with the appropriate arguments, it prints either the sum or the max of
+the command-line integers::
+
+   $ prog.py 1 2 3 4
+   4
+
+   $ prog.py 1 2 3 4 --sum
+   10
+
+If invalid arguments are passed in, it will issue an error::
+
+   $ prog.py a b c
+   usage: prog.py [-h] [--sum] N [N ...]
+   prog.py: error: argument N: invalid int value: 'a'
+
+The following sections walk you through this example.
+
+
+Creating a parser
+^^^^^^^^^^^^^^^^^
+
+The first step in using the :mod:`argparse` is creating an
+:class:`ArgumentParser` object::
+
+   >>> parser = argparse.ArgumentParser(description='Process some integers.')
+
+The :class:`ArgumentParser` object will hold all the information necessary to
+parse the command line into python data types.
+
+
+Adding arguments
+^^^^^^^^^^^^^^^^
+
+Filling an :class:`ArgumentParser` with information about program arguments is
+done by making calls to the :meth:`~ArgumentParser.add_argument` method.
+Generally, these calls tell the :class:`ArgumentParser` how to take the strings
+on the command line and turn them into objects.  This information is stored and
+used when :meth:`~ArgumentParser.parse_args` is called. For example::
+
+   >>> parser.add_argument('integers', metavar='N', type=int, nargs='+',
+   ...                     help='an integer for the accumulator')
+   >>> parser.add_argument('--sum', dest='accumulate', action='store_const',
+   ...                     const=sum, default=max,
+   ...                     help='sum the integers (default: find the max)')
+
+Later, calling :meth:`parse_args` will return an object with
+two attributes, ``integers`` and ``accumulate``.  The ``integers`` attribute
+will be a list of one or more ints, and the ``accumulate`` attribute will be
+either the :func:`sum` function, if ``--sum`` was specified at the command line,
+or the :func:`max` function if it was not.
+
+
+Parsing arguments
+^^^^^^^^^^^^^^^^^
+
+:class:`ArgumentParser` parses args through the
+:meth:`~ArgumentParser.parse_args` method.  This will inspect the command-line,
+convert each arg to the appropriate type and then invoke the appropriate action.
+In most cases, this means a simple namespace object will be built up from
+attributes parsed out of the command-line::
+
+   >>> parser.parse_args(['--sum', '7', '-1', '42'])
+   Namespace(accumulate=<built-in function sum>, integers=[7, -1, 42])
+
+In a script, :meth:`~ArgumentParser.parse_args` will typically be called with no
+arguments, and the :class:`ArgumentParser` will automatically determine the
+command-line args from :data:`sys.argv`.
+
+
+ArgumentParser objects
+----------------------
+
+.. class:: ArgumentParser([description], [epilog], [prog], [usage], [add_help], [argument_default], [parents], [prefix_chars], [conflict_handler], [formatter_class])
+
+   Create a new :class:`ArgumentParser` object.  Each parameter has its own more
+   detailed description below, but in short they are:
+
+   * description_ - Text to display before the argument help.
+
+   * epilog_ - Text to display after the argument help.
+
+   * add_help_ - Add a -h/--help option to the parser. (default: ``True``)
+
+   * argument_default_ - Set the global default value for arguments.
+     (default: ``None``)
+
+   * parents_ - A list of :class:`ArgumentParser` objects whose arguments should
+     also be included.
+
+   * prefix_chars_ - The set of characters that prefix optional arguments.
+     (default: '-')
+
+   * fromfile_prefix_chars_ - The set of characters that prefix files from
+     which additional arguments should be read. (default: ``None``)
+
+   * formatter_class_ - A class for customizing the help output.
+
+   * conflict_handler_ - Usually unnecessary, defines strategy for resolving
+     conflicting optionals.
+
+   * prog_ - The name of the program (default:
+     :data:`sys.argv[0]`)
+
+   * usage_ - The string describing the program usage (default: generated)
+
+The following sections describe how each of these are used.
+
+
+description
+^^^^^^^^^^^
+
+Most calls to the :class:`ArgumentParser` constructor will use the
+``description=`` keyword argument.  This argument gives a brief description of
+what the program does and how it works.  In help messages, the description is
+displayed between the command-line usage string and the help messages for the
+various arguments::
+
+   >>> parser = argparse.ArgumentParser(description='A foo that bars')
+   >>> parser.print_help()
+   usage: argparse.py [-h]
+
+   A foo that bars
+
+   optional arguments:
+    -h, --help  show this help message and exit
+
+By default, the description will be line-wrapped so that it fits within the
+given space.  To change this behavior, see the formatter_class_ argument.
+
+
+epilog
+^^^^^^
+
+Some programs like to display additional description of the program after the
+description of the arguments.  Such text can be specified using the ``epilog=``
+argument to :class:`ArgumentParser`::
+
+   >>> parser = argparse.ArgumentParser(
+   ...     description='A foo that bars',
+   ...     epilog="And that's how you'd foo a bar")
+   >>> parser.print_help()
+   usage: argparse.py [-h]
+
+   A foo that bars
+
+   optional arguments:
+    -h, --help  show this help message and exit
+
+   And that's how you'd foo a bar
+
+As with the description_ argument, the ``epilog=`` text is by default
+line-wrapped, but this behavior can be adjusted with the formatter_class_
+argument to :class:`ArgumentParser`.
+
+
+add_help
+^^^^^^^^
+
+By default, ArgumentParser objects add an option which simply displays
+the parser's help message. For example, consider a file named
+``myprogram.py`` containing the following code::
+
+   import argparse
+   parser = argparse.ArgumentParser()
+   parser.add_argument('--foo', help='foo help')
+   args = parser.parse_args()
+
+If ``-h`` or ``--help`` is supplied is at the command-line, the ArgumentParser
+help will be printed::
+
+   $ python myprogram.py --help
+   usage: myprogram.py [-h] [--foo FOO]
+
+   optional arguments:
+    -h, --help  show this help message and exit
+    --foo FOO   foo help
+
+Occasionally, it may be useful to disable the addition of this help option.
+This can be achieved by passing ``False`` as the ``add_help=`` argument to
+:class:`ArgumentParser`::
+
+   >>> parser = argparse.ArgumentParser(prog='PROG', add_help=False)
+   >>> parser.add_argument('--foo', help='foo help')
+   >>> parser.print_help()
+   usage: PROG [--foo FOO]
+
+   optional arguments:
+    --foo FOO  foo help
+
+The help option is typically ``-h/--help``. The exception to this is
+if the ``prefix_chars=`` is specified and does not include ``'-'``, in
+which case ``-h`` and ``--help`` are not valid options.  In
+this case, the first character in ``prefix_chars`` is used to prefix
+the help options::
+
+   >>> parser = argparse.ArgumentParser(prog='PROG', prefix_chars='+/')
+   >>> parser.print_help()
+   usage: PROG [+h]
+
+   optional arguments:
+     +h, ++help  show this help message and exit
+
+
+prefix_chars
+^^^^^^^^^^^^
+
+Most command-line options will use ``'-'`` as the prefix, e.g. ``-f/--foo``.
+Parsers that need to support different or additional prefix
+characters, e.g. for options
+like ``+f`` or ``/foo``, may specify them using the ``prefix_chars=`` argument
+to the ArgumentParser constructor::
+
+   >>> parser = argparse.ArgumentParser(prog='PROG', prefix_chars='-+')
+   >>> parser.add_argument('+f')
+   >>> parser.add_argument('++bar')
+   >>> parser.parse_args('+f X ++bar Y'.split())
+   Namespace(bar='Y', f='X')
+
+The ``prefix_chars=`` argument defaults to ``'-'``. Supplying a set of
+characters that does not include ``'-'`` will cause ``-f/--foo`` options to be
+disallowed.
+
+
+fromfile_prefix_chars
+^^^^^^^^^^^^^^^^^^^^^
+
+Sometimes, for example when dealing with a particularly long argument lists, it
+may make sense to keep the list of arguments in a file rather than typing it out
+at the command line.  If the ``fromfile_prefix_chars=`` argument is given to the
+:class:`ArgumentParser` constructor, then arguments that start with any of the
+specified characters will be treated as files, and will be replaced by the
+arguments they contain.  For example::
+
+   >>> with open('args.txt', 'w') as fp:
+   ...    fp.write('-f\nbar')
+   >>> parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
+   >>> parser.add_argument('-f')
+   >>> parser.parse_args(['-f', 'foo', '@args.txt'])
+   Namespace(f='bar')
+
+Arguments read from a file must by default be one per line (but see also
+:meth:`convert_arg_line_to_args`) and are treated as if they were in the same
+place as the original file referencing argument on the command line.  So in the
+example above, the expression ``['-f', 'foo', '@args.txt']`` is considered
+equivalent to the expression ``['-f', 'foo', '-f', 'bar']``.
+
+The ``fromfile_prefix_chars=`` argument defaults to ``None``, meaning that
+arguments will never be treated as file references.
+
+
+argument_default
+^^^^^^^^^^^^^^^^
+
+Generally, argument defaults are specified either by passing a default to
+:meth:`add_argument` or by calling the :meth:`set_defaults` methods with a
+specific set of name-value pairs.  Sometimes however, it may be useful to
+specify a single parser-wide default for arguments.  This can be accomplished by
+passing the ``argument_default=`` keyword argument to :class:`ArgumentParser`.
+For example, to globally suppress attribute creation on :meth:`parse_args`
+calls, we supply ``argument_default=SUPPRESS``::
+
+   >>> parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS)
+   >>> parser.add_argument('--foo')
+   >>> parser.add_argument('bar', nargs='?')
+   >>> parser.parse_args(['--foo', '1', 'BAR'])
+   Namespace(bar='BAR', foo='1')
+   >>> parser.parse_args([])
+   Namespace()
+
+
+parents
+^^^^^^^
+
+Sometimes, several parsers share a common set of arguments. Rather than
+repeating the definitions of these arguments, a single parser with all the
+shared arguments and passed to ``parents=`` argument to :class:`ArgumentParser`
+can be used.  The ``parents=`` argument takes a list of :class:`ArgumentParser`
+objects, collects all the positional and optional actions from them, and adds
+these actions to the :class:`ArgumentParser` object being constructed::
+
+   >>> parent_parser = argparse.ArgumentParser(add_help=False)
+   >>> parent_parser.add_argument('--parent', type=int)
+
+   >>> foo_parser = argparse.ArgumentParser(parents=[parent_parser])
+   >>> foo_parser.add_argument('foo')
+   >>> foo_parser.parse_args(['--parent', '2', 'XXX'])
+   Namespace(foo='XXX', parent=2)
+
+   >>> bar_parser = argparse.ArgumentParser(parents=[parent_parser])
+   >>> bar_parser.add_argument('--bar')
+   >>> bar_parser.parse_args(['--bar', 'YYY'])
+   Namespace(bar='YYY', parent=None)
+
+Note that most parent parsers will specify ``add_help=False``.  Otherwise, the
+:class:`ArgumentParser` will see two ``-h/--help`` options (one in the parent
+and one in the child) and raise an error.
+
+
+formatter_class
+^^^^^^^^^^^^^^^
+
+:class:`ArgumentParser` objects allow the help formatting to be customized by
+specifying an alternate formatting class.  Currently, there are three such
+classes: :class:`argparse.RawDescriptionHelpFormatter`,
+:class:`argparse.RawTextHelpFormatter` and
+:class:`argparse.ArgumentDefaultsHelpFormatter`.  The first two allow more
+control over how textual descriptions are displayed, while the last
+automatically adds information about argument default values.
+
+By default, :class:`ArgumentParser` objects line-wrap the description_ and
+epilog_ texts in command-line help messages::
+
+   >>> parser = argparse.ArgumentParser(
+   ...     prog='PROG',
+   ...     description='''this description
+   ...         was indented weird
+   ...             but that is okay''',
+   ...     epilog='''
+   ...             likewise for this epilog whose whitespace will
+   ...         be cleaned up and whose words will be wrapped
+   ...         across a couple lines''')
+   >>> parser.print_help()
+   usage: PROG [-h]
+
+   this description was indented weird but that is okay
+
+   optional arguments:
+    -h, --help  show this help message and exit
+
+   likewise for this epilog whose whitespace will be cleaned up and whose words
+   will be wrapped across a couple lines
+
+Passing :class:`argparse.RawDescriptionHelpFormatter` as ``formatter_class=``
+indicates that description_ and epilog_ are already correctly formatted and
+should not be line-wrapped::
+
+   >>> parser = argparse.ArgumentParser(
+   ...     prog='PROG',
+   ...     formatter_class=argparse.RawDescriptionHelpFormatter,
+   ...     description=textwrap.dedent('''\
+   ...         Please do not mess up this text!
+   ...         --------------------------------
+   ...             I have indented it
+   ...             exactly the way
+   ...             I want it
+   ...         '''))
+   >>> parser.print_help()
+   usage: PROG [-h]
+
+   Please do not mess up this text!
+   --------------------------------
+      I have indented it
+      exactly the way
+      I want it
+
+   optional arguments:
+    -h, --help  show this help message and exit
+
+:class:`RawTextHelpFormatter` maintains whitespace for all sorts of help text
+including argument descriptions.
+
+The other formatter class available, :class:`ArgumentDefaultsHelpFormatter`,
+will add information about the default value of each of the arguments::
+
+   >>> parser = argparse.ArgumentParser(
+   ...     prog='PROG',
+   ...     formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+   >>> parser.add_argument('--foo', type=int, default=42, help='FOO!')
+   >>> parser.add_argument('bar', nargs='*', default=[1, 2, 3], help='BAR!')
+   >>> parser.print_help()
+   usage: PROG [-h] [--foo FOO] [bar [bar ...]]
+
+   positional arguments:
+    bar         BAR! (default: [1, 2, 3])
+
+   optional arguments:
+    -h, --help  show this help message and exit
+    --foo FOO   FOO! (default: 42)
+
+
+conflict_handler
+^^^^^^^^^^^^^^^^
+
+:class:`ArgumentParser` objects do not allow two actions with the same option
+string.  By default, :class:`ArgumentParser` objects raises an exception if an
+attempt is made to create an argument with an option string that is already in
+use::
+
+   >>> parser = argparse.ArgumentParser(prog='PROG')
+   >>> parser.add_argument('-f', '--foo', help='old foo help')
+   >>> parser.add_argument('--foo', help='new foo help')
+   Traceback (most recent call last):
+    ..
+   ArgumentError: argument --foo: conflicting option string(s): --foo
+
+Sometimes (e.g. when using parents_) it may be useful to simply override any
+older arguments with the same option string.  To get this behavior, the value
+``'resolve'`` can be supplied to the ``conflict_handler=`` argument of
+:class:`ArgumentParser`::
+
+   >>> parser = argparse.ArgumentParser(prog='PROG', conflict_handler='resolve')
+   >>> parser.add_argument('-f', '--foo', help='old foo help')
+   >>> parser.add_argument('--foo', help='new foo help')
+   >>> parser.print_help()
+   usage: PROG [-h] [-f FOO] [--foo FOO]
+
+   optional arguments:
+    -h, --help  show this help message and exit
+    -f FOO      old foo help
+    --foo FOO   new foo help
+
+Note that :class:`ArgumentParser` objects only remove an action if all of its
+option strings are overridden.  So, in the example above, the old ``-f/--foo``
+action is retained as the ``-f`` action, because only the ``--foo`` option
+string was overridden.
+
+
+prog
+^^^^
+
+By default, :class:`ArgumentParser` objects uses ``sys.argv[0]`` to determine
+how to display the name of the program in help messages.  This default is almost
+always desirable because it will make the help messages match how the program was
+invoked on the command line.  For example, consider a file named
+``myprogram.py`` with the following code::
+
+   import argparse
+   parser = argparse.ArgumentParser()
+   parser.add_argument('--foo', help='foo help')
+   args = parser.parse_args()
+
+The help for this program will display ``myprogram.py`` as the program name
+(regardless of where the program was invoked from)::
+
+   $ python myprogram.py --help
+   usage: myprogram.py [-h] [--foo FOO]
+
+   optional arguments:
+    -h, --help  show this help message and exit
+    --foo FOO   foo help
+   $ cd ..
+   $ python subdir\myprogram.py --help
+   usage: myprogram.py [-h] [--foo FOO]
+
+   optional arguments:
+    -h, --help  show this help message and exit
+    --foo FOO   foo help
+
+To change this default behavior, another value can be supplied using the
+``prog=`` argument to :class:`ArgumentParser`::
+
+   >>> parser = argparse.ArgumentParser(prog='myprogram')
+   >>> parser.print_help()
+   usage: myprogram [-h]
+
+   optional arguments:
+    -h, --help  show this help message and exit
+
+Note that the program name, whether determined from ``sys.argv[0]`` or from the
+``prog=`` argument, is available to help messages using the ``%(prog)s`` format
+specifier.
+
+::
+
+   >>> parser = argparse.ArgumentParser(prog='myprogram')
+   >>> parser.add_argument('--foo', help='foo of the %(prog)s program')
+   >>> parser.print_help()
+   usage: myprogram [-h] [--foo FOO]
+
+   optional arguments:
+    -h, --help  show this help message and exit
+    --foo FOO   foo of the myprogram program
+
+
+usage
+^^^^^
+
+By default, :class:`ArgumentParser` calculates the usage message from the
+arguments it contains::
+
+   >>> parser = argparse.ArgumentParser(prog='PROG')
+   >>> parser.add_argument('--foo', nargs='?', help='foo help')
+   >>> parser.add_argument('bar', nargs='+', help='bar help')
+   >>> parser.print_help()
+   usage: PROG [-h] [--foo [FOO]] bar [bar ...]
+
+   positional arguments:
+    bar          bar help
+
+   optional arguments:
+    -h, --help   show this help message and exit
+    --foo [FOO]  foo help
+
+The default message can be overridden with the ``usage=`` keyword argument::
+
+   >>> parser = argparse.ArgumentParser(prog='PROG', usage='%(prog)s [options]')
+   >>> parser.add_argument('--foo', nargs='?', help='foo help')
+   >>> parser.add_argument('bar', nargs='+', help='bar help')
+   >>> parser.print_help()
+   usage: PROG [options]
+
+   positional arguments:
+    bar          bar help
+
+   optional arguments:
+    -h, --help   show this help message and exit
+    --foo [FOO]  foo help
+
+The ``%(prog)s`` format specifier is available to fill in the program name in
+your usage messages.
+
+
+The add_argument() method
+-------------------------
+
+.. method:: ArgumentParser.add_argument(name or flags..., [action], [nargs], [const], [default], [type], [choices], [required], [help], [metavar], [dest])
+
+   Define how a single command line argument should be parsed.  Each parameter
+   has its own more detailed description below, but in short they are:
+
+   * `name or flags`_ - Either a name or a list of option strings, e.g. ``foo``
+     or ``-f, --foo``
+
+   * action_ - The basic type of action to be taken when this argument is
+     encountered at the command-line.
+
+   * nargs_ - The number of command-line arguments that should be consumed.
+
+   * const_ - A constant value required by some action_ and nargs_ selections.
+
+   * default_ - The value produced if the argument is absent from the
+     command-line.
+
+   * type_ - The type to which the command-line arg should be converted.
+
+   * choices_ - A container of the allowable values for the argument.
+
+   * required_ - Whether or not the command-line option may be omitted
+     (optionals only).
+
+   * help_ - A brief description of what the argument does.
+
+   * metavar_ - A name for the argument in usage messages.
+
+   * dest_ - The name of the attribute to be added to the object returned by
+     :meth:`parse_args`.
+
+The following sections describe how each of these are used.
+
+
+name or flags
+^^^^^^^^^^^^^
+
+The :meth:`add_argument` method must know whether an optional argument, like
+``-f`` or ``--foo``, or a positional argument, like a list of filenames, is
+expected.  The first arguments passed to :meth:`add_argument` must therefore be
+either a series of flags, or a simple argument name.  For example, an optional
+argument could be created like::
+
+   >>> parser.add_argument('-f', '--foo')
+
+while a positional argument could be created like::
+
+   >>> parser.add_argument('bar')
+
+When :meth:`parse_args` is called, optional arguments will be identified by the
+``-`` prefix, and the remaining arguments will be assumed to be positional::
+
+   >>> parser = argparse.ArgumentParser(prog='PROG')
+   >>> parser.add_argument('-f', '--foo')
+   >>> parser.add_argument('bar')
+   >>> parser.parse_args(['BAR'])
+   Namespace(bar='BAR', foo=None)
+   >>> parser.parse_args(['BAR', '--foo', 'FOO'])
+   Namespace(bar='BAR', foo='FOO')
+   >>> parser.parse_args(['--foo', 'FOO'])
+   usage: PROG [-h] [-f FOO] bar
+   PROG: error: too few arguments
+
+
+action
+^^^^^^
+
+:class:`ArgumentParser` objects associate command-line args with actions.  These
+actions can do just about anything with the command-line args associated with
+them, though most actions simply add an attribute to the object returned by
+:meth:`parse_args`.  The ``action`` keyword argument specifies how the
+command-line args should be handled. The supported actions are:
+
+* ``'store'`` - This just stores the argument's value.  This is the default
+   action. For example::
+
+    >>> parser = argparse.ArgumentParser()
+    >>> parser.add_argument('--foo')
+    >>> parser.parse_args('--foo 1'.split())
+    Namespace(foo='1')
+
+* ``'store_const'`` - This stores the value specified by the const_ keyword
+   argument.  (Note that the const_ keyword argument defaults to the rather
+   unhelpful ``None``.)  The ``'store_const'`` action is most commonly used with
+   optional arguments that specify some sort of flag.  For example::
+
+    >>> parser = argparse.ArgumentParser()
+    >>> parser.add_argument('--foo', action='store_const', const=42)
+    >>> parser.parse_args('--foo'.split())
+    Namespace(foo=42)
+
+* ``'store_true'`` and ``'store_false'`` - These store the values ``True`` and
+  ``False`` respectively.  These are special cases of ``'store_const'``.  For
+  example::
+
+    >>> parser = argparse.ArgumentParser()
+    >>> parser.add_argument('--foo', action='store_true')
+    >>> parser.add_argument('--bar', action='store_false')
+    >>> parser.parse_args('--foo --bar'.split())
+    Namespace(bar=False, foo=True)
+
+* ``'append'`` - This stores a list, and appends each argument value to the
+  list.  This is useful to allow an option to be specified multiple times.
+  Example usage::
+
+    >>> parser = argparse.ArgumentParser()
+    >>> parser.add_argument('--foo', action='append')
+    >>> parser.parse_args('--foo 1 --foo 2'.split())
+    Namespace(foo=['1', '2'])
+
+* ``'append_const'`` - This stores a list, and appends the value specified by
+  the const_ keyword argument to the list.  (Note that the const_ keyword
+  argument defaults to ``None``.)  The ``'append_const'`` action is typically
+  useful when multiple arguments need to store constants to the same list. For
+  example::
+
+    >>> parser = argparse.ArgumentParser()
+    >>> parser.add_argument('--str', dest='types', action='append_const', const=str)
+    >>> parser.add_argument('--int', dest='types', action='append_const', const=int)
+    >>> parser.parse_args('--str --int'.split())
+    Namespace(types=[<type 'str'>, <type 'int'>])
+
+* ``'version'`` - This expects a ``version=`` keyword argument in the
+  :meth:`add_argument` call, and prints version information and exits when
+  invoked.
+
+    >>> import argparse
+    >>> parser = argparse.ArgumentParser(prog='PROG')
+    >>> parser.add_argument('--version', action='version', version='%(prog)s 2.0')
+    >>> parser.parse_args(['--version'])
+    PROG 2.0
+
+You can also specify an arbitrary action by passing an object that implements
+the Action API.  The easiest way to do this is to extend
+:class:`argparse.Action`, supplying an appropriate ``__call__`` method.  The
+``__call__`` method should accept four parameters:
+
+* ``parser`` - The ArgumentParser object which contains this action.
+
+* ``namespace`` - The namespace object that will be returned by
+  :meth:`parse_args`.  Most actions add an attribute to this object.
+
+* ``values`` - The associated command-line args, with any type-conversions
+  applied.  (Type-conversions are specified with the type_ keyword argument to
+  :meth:`add_argument`.
+
+* ``option_string`` - The option string that was used to invoke this action.
+  The ``option_string`` argument is optional, and will be absent if the action
+  is associated with a positional argument.
+
+An example of a custom action::
+
+   >>> class FooAction(argparse.Action):
+   ...     def __call__(self, parser, namespace, values, option_string=None):
+   ...         print '%r %r %r' % (namespace, values, option_string)
+   ...         setattr(namespace, self.dest, values)
+   ...
+   >>> parser = argparse.ArgumentParser()
+   >>> parser.add_argument('--foo', action=FooAction)
+   >>> parser.add_argument('bar', action=FooAction)
+   >>> args = parser.parse_args('1 --foo 2'.split())
+   Namespace(bar=None, foo=None) '1' None
+   Namespace(bar='1', foo=None) '2' '--foo'
+   >>> args
+   Namespace(bar='1', foo='2')
+
+
+nargs
+^^^^^
+
+ArgumentParser objects usually associate a single command-line argument with a
+single action to be taken.  The ``nargs`` keyword argument associates a
+different number of command-line arguments with a single action..  The supported
+values are:
+
+* N (an integer).  N args from the command-line will be gathered together into a
+  list.  For example::
+
+     >>> parser = argparse.ArgumentParser()
+     >>> parser.add_argument('--foo', nargs=2)
+     >>> parser.add_argument('bar', nargs=1)
+     >>> parser.parse_args('c --foo a b'.split())
+     Namespace(bar=['c'], foo=['a', 'b'])
+
+  Note that ``nargs=1`` produces a list of one item.  This is different from
+  the default, in which the item is produced by itself.
+
+* ``'?'``. One arg will be consumed from the command-line if possible, and
+  produced as a single item.  If no command-line arg is present, the value from
+  default_ will be produced.  Note that for optional arguments, there is an
+  additional case - the option string is present but not followed by a
+  command-line arg.  In this case the value from const_ will be produced.  Some
+  examples to illustrate this::
+
+     >>> parser = argparse.ArgumentParser()
+     >>> parser.add_argument('--foo', nargs='?', const='c', default='d')
+     >>> parser.add_argument('bar', nargs='?', default='d')
+     >>> parser.parse_args('XX --foo YY'.split())
+     Namespace(bar='XX', foo='YY')
+     >>> parser.parse_args('XX --foo'.split())
+     Namespace(bar='XX', foo='c')
+     >>> parser.parse_args(''.split())
+     Namespace(bar='d', foo='d')
+
+  One of the more common uses of ``nargs='?'`` is to allow optional input and
+  output files::
+
+     >>> parser = argparse.ArgumentParser()
+     >>> parser.add_argument('infile', nargs='?', type=argparse.FileType('r'),
+     ...                     default=sys.stdin)
+     >>> parser.add_argument('outfile', nargs='?', type=argparse.FileType('w'),
+     ...                     default=sys.stdout)
+     >>> parser.parse_args(['input.txt', 'output.txt'])
+     Namespace(infile=<open file 'input.txt', mode 'r' at 0x...>, outfile=<open file 'output.txt', mode 'w' at 0x...>)
+     >>> parser.parse_args([])
+     Namespace(infile=<open file '<stdin>', mode 'r' at 0x...>, outfile=<open file '<stdout>', mode 'w' at 0x...>)
+
+* ``'*'``.  All command-line args present are gathered into a list.  Note that
+  it generally doesn't make much sense to have more than one positional argument
+  with ``nargs='*'``, but multiple optional arguments with ``nargs='*'`` is
+  possible.  For example::
+
+     >>> parser = argparse.ArgumentParser()
+     >>> parser.add_argument('--foo', nargs='*')
+     >>> parser.add_argument('--bar', nargs='*')
+     >>> parser.add_argument('baz', nargs='*')
+     >>> parser.parse_args('a b --foo x y --bar 1 2'.split())
+     Namespace(bar=['1', '2'], baz=['a', 'b'], foo=['x', 'y'])
+
+* ``'+'``. Just like ``'*'``, all command-line args present are gathered into a
+  list.  Additionally, an error message will be generated if there wasn't at
+  least one command-line arg present.  For example::
+
+     >>> parser = argparse.ArgumentParser(prog='PROG')
+     >>> parser.add_argument('foo', nargs='+')
+     >>> parser.parse_args('a b'.split())
+     Namespace(foo=['a', 'b'])
+     >>> parser.parse_args(''.split())
+     usage: PROG [-h] foo [foo ...]
+     PROG: error: too few arguments
+
+If the ``nargs`` keyword argument is not provided, the number of args consumed
+is determined by the action_.  Generally this means a single command-line arg
+will be consumed and a single item (not a list) will be produced.
+
+
+const
+^^^^^
+
+The ``const`` argument of :meth:`add_argument` is used to hold constant values
+that are not read from the command line but are required for the various
+ArgumentParser actions.  The two most common uses of it are:
+
+* When :meth:`add_argument` is called with ``action='store_const'`` or
+  ``action='append_const'``.  These actions add the ``const`` value to one of
+  the attributes of the object returned by :meth:`parse_args`.  See the action_
+  description for examples.
+
+* When :meth:`add_argument` is called with option strings (like ``-f`` or
+  ``--foo``) and ``nargs='?'``.  This creates an optional argument that can be
+  followed by zero or one command-line args.  When parsing the command-line, if
+  the option string is encountered with no command-line arg following it, the
+  value of ``const`` will be assumed instead. See the nargs_ description for
+  examples.
+
+The ``const`` keyword argument defaults to ``None``.
+
+
+default
+^^^^^^^
+
+All optional arguments and some positional arguments may be omitted at the
+command-line.  The ``default`` keyword argument of :meth:`add_argument`, whose
+value defaults to ``None``, specifies what value should be used if the
+command-line arg is not present.  For optional arguments, the ``default`` value
+is used when the option string was not present at the command line::
+
+   >>> parser = argparse.ArgumentParser()
+   >>> parser.add_argument('--foo', default=42)
+   >>> parser.parse_args('--foo 2'.split())
+   Namespace(foo='2')
+   >>> parser.parse_args(''.split())
+   Namespace(foo=42)
+
+For positional arguments with nargs_ ``='?'`` or ``'*'``, the ``default`` value
+is used when no command-line arg was present::
+
+   >>> parser = argparse.ArgumentParser()
+   >>> parser.add_argument('foo', nargs='?', default=42)
+   >>> parser.parse_args('a'.split())
+   Namespace(foo='a')
+   >>> parser.parse_args(''.split())
+   Namespace(foo=42)
+
+
+Providing ``default=argparse.SUPPRESS`` causes no attribute to be added if the
+command-line argument was not present.::
+
+   >>> parser = argparse.ArgumentParser()
+   >>> parser.add_argument('--foo', default=argparse.SUPPRESS)
+   >>> parser.parse_args([])
+   Namespace()
+   >>> parser.parse_args(['--foo', '1'])
+   Namespace(foo='1')
+
+
+type
+^^^^
+
+By default, ArgumentParser objects read command-line args in as simple strings.
+However, quite often the command-line string should instead be interpreted as
+another type, like a :class:`float`, :class:`int` or :class:`file`.  The
+``type`` keyword argument of :meth:`add_argument` allows any necessary
+type-checking and type-conversions to be performed.  Many common built-in types
+can be used directly as the value of the ``type`` argument::
+
+   >>> parser = argparse.ArgumentParser()
+   >>> parser.add_argument('foo', type=int)
+   >>> parser.add_argument('bar', type=file)
+   >>> parser.parse_args('2 temp.txt'.split())
+   Namespace(bar=<open file 'temp.txt', mode 'r' at 0x...>, foo=2)
+
+To ease the use of various types of files, the argparse module provides the
+factory FileType which takes the ``mode=`` and ``bufsize=`` arguments of the
+``file`` object.  For example, ``FileType('w')`` can be used to create a
+writable file::
+
+   >>> parser = argparse.ArgumentParser()
+   >>> parser.add_argument('bar', type=argparse.FileType('w'))
+   >>> parser.parse_args(['out.txt'])
+   Namespace(bar=<open file 'out.txt', mode 'w' at 0x...>)
+
+``type=`` can take any callable that takes a single string argument and returns
+the type-converted value::
+
+   >>> def perfect_square(string):
+   ...     value = int(string)
+   ...     sqrt = math.sqrt(value)
+   ...     if sqrt != int(sqrt):
+   ...         msg = "%r is not a perfect square" % string
+   ...         raise argparse.ArgumentTypeError(msg)
+   ...     return value
+   ...
+   >>> parser = argparse.ArgumentParser(prog='PROG')
+   >>> parser.add_argument('foo', type=perfect_square)
+   >>> parser.parse_args('9'.split())
+   Namespace(foo=9)
+   >>> parser.parse_args('7'.split())
+   usage: PROG [-h] foo
+   PROG: error: argument foo: '7' is not a perfect square
+
+The choices_ keyword argument may be more convenient for type checkers that
+simply check against a range of values::
+
+   >>> parser = argparse.ArgumentParser(prog='PROG')
+   >>> parser.add_argument('foo', type=int, choices=xrange(5, 10))
+   >>> parser.parse_args('7'.split())
+   Namespace(foo=7)
+   >>> parser.parse_args('11'.split())
+   usage: PROG [-h] {5,6,7,8,9}
+   PROG: error: argument foo: invalid choice: 11 (choose from 5, 6, 7, 8, 9)
+
+See the choices_ section for more details.
+
+
+choices
+^^^^^^^
+
+Some command-line args should be selected from a restricted set of values.
+These can be handled by passing a container object as the ``choices`` keyword
+argument to :meth:`add_argument`.  When the command-line is parsed, arg values
+will be checked, and an error message will be displayed if the arg was not one
+of the acceptable values::
+
+   >>> parser = argparse.ArgumentParser(prog='PROG')
+   >>> parser.add_argument('foo', choices='abc')
+   >>> parser.parse_args('c'.split())
+   Namespace(foo='c')
+   >>> parser.parse_args('X'.split())
+   usage: PROG [-h] {a,b,c}
+   PROG: error: argument foo: invalid choice: 'X' (choose from 'a', 'b', 'c')
+
+Note that inclusion in the ``choices`` container is checked after any type_
+conversions have been performed, so the type of the objects in the ``choices``
+container should match the type_ specified::
+
+   >>> parser = argparse.ArgumentParser(prog='PROG')
+   >>> parser.add_argument('foo', type=complex, choices=[1, 1j])
+   >>> parser.parse_args('1j'.split())
+   Namespace(foo=1j)
+   >>> parser.parse_args('-- -4'.split())
+   usage: PROG [-h] {1,1j}
+   PROG: error: argument foo: invalid choice: (-4+0j) (choose from 1, 1j)
+
+Any object that supports the ``in`` operator can be passed as the ``choices``
+value, so :class:`dict` objects, :class:`set` objects, custom containers,
+etc. are all supported.
+
+
+required
+^^^^^^^^
+
+In general, the argparse module assumes that flags like ``-f`` and ``--bar``
+indicate *optional* arguments, which can always be omitted at the command-line.
+To make an option *required*, ``True`` can be specified for the ``required=``
+keyword argument to :meth:`add_argument`::
+
+   >>> parser = argparse.ArgumentParser()
+   >>> parser.add_argument('--foo', required=True)
+   >>> parser.parse_args(['--foo', 'BAR'])
+   Namespace(foo='BAR')
+   >>> parser.parse_args([])
+   usage: argparse.py [-h] [--foo FOO]
+   argparse.py: error: option --foo is required
+
+As the example shows, if an option is marked as ``required``, :meth:`parse_args`
+will report an error if that option is not present at the command line.
+
+.. note::
+
+    Required options are generally considered bad form because users expect
+    *options* to be *optional*, and thus they should be avoided when possible.
+
+
+help
+^^^^
+
+The ``help`` value is a string containing a brief description of the argument.
+When a user requests help (usually by using ``-h`` or ``--help`` at the
+command-line), these ``help`` descriptions will be displayed with each
+argument::
+
+   >>> parser = argparse.ArgumentParser(prog='frobble')
+   >>> parser.add_argument('--foo', action='store_true',
+   ...         help='foo the bars before frobbling')
+   >>> parser.add_argument('bar', nargs='+',
+   ...         help='one of the bars to be frobbled')
+   >>> parser.parse_args('-h'.split())
+   usage: frobble [-h] [--foo] bar [bar ...]
+
+   positional arguments:
+    bar     one of the bars to be frobbled
+
+   optional arguments:
+    -h, --help  show this help message and exit
+    --foo   foo the bars before frobbling
+
+The ``help`` strings can include various format specifiers to avoid repetition
+of things like the program name or the argument default_.  The available
+specifiers include the program name, ``%(prog)s`` and most keyword arguments to
+:meth:`add_argument`, e.g. ``%(default)s``, ``%(type)s``, etc.::
+
+   >>> parser = argparse.ArgumentParser(prog='frobble')
+   >>> parser.add_argument('bar', nargs='?', type=int, default=42,
+   ...         help='the bar to %(prog)s (default: %(default)s)')
+   >>> parser.print_help()
+   usage: frobble [-h] [bar]
+
+   positional arguments:
+    bar     the bar to frobble (default: 42)
+
+   optional arguments:
+    -h, --help  show this help message and exit
+
+
+metavar
+^^^^^^^
+
+When :class:`ArgumentParser` generates help messages, it need some way to refer
+to each expected argument.  By default, ArgumentParser objects use the dest_
+value as the "name" of each object.  By default, for positional argument
+actions, the dest_ value is used directly, and for optional argument actions,
+the dest_ value is uppercased.  So, a single positional argument with
+``dest='bar'`` will that argument will be referred to as ``bar``. A single
+optional argument ``--foo`` that should be followed by a single command-line arg
+will be referred to as ``FOO``.  An example::
+
+   >>> parser = argparse.ArgumentParser()
+   >>> parser.add_argument('--foo')
+   >>> parser.add_argument('bar')
+   >>> parser.parse_args('X --foo Y'.split())
+   Namespace(bar='X', foo='Y')
+   >>> parser.print_help()
+   usage:  [-h] [--foo FOO] bar
+
+   positional arguments:
+    bar
+
+   optional arguments:
+    -h, --help  show this help message and exit
+    --foo FOO
+
+An alternative name can be specified with ``metavar``::
+
+   >>> parser = argparse.ArgumentParser()
+   >>> parser.add_argument('--foo', metavar='YYY')
+   >>> parser.add_argument('bar', metavar='XXX')
+   >>> parser.parse_args('X --foo Y'.split())
+   Namespace(bar='X', foo='Y')
+   >>> parser.print_help()
+   usage:  [-h] [--foo YYY] XXX
+
+   positional arguments:
+    XXX
+
+   optional arguments:
+    -h, --help  show this help message and exit
+    --foo YYY
+
+Note that ``metavar`` only changes the *displayed* name - the name of the
+attribute on the :meth:`parse_args` object is still determined by the dest_
+value.
+
+Different values of ``nargs`` may cause the metavar to be used multiple times.
+Providing a tuple to ``metavar`` specifies a different display for each of the
+arguments::
+
+   >>> parser = argparse.ArgumentParser(prog='PROG')
+   >>> parser.add_argument('-x', nargs=2)
+   >>> parser.add_argument('--foo', nargs=2, metavar=('bar', 'baz'))
+   >>> parser.print_help()
+   usage: PROG [-h] [-x X X] [--foo bar baz]
+
+   optional arguments:
+    -h, --help     show this help message and exit
+    -x X X
+    --foo bar baz
+
+
+dest
+^^^^
+
+Most :class:`ArgumentParser` actions add some value as an attribute of the
+object returned by :meth:`parse_args`.  The name of this attribute is determined
+by the ``dest`` keyword argument of :meth:`add_argument`.  For positional
+argument actions, ``dest`` is normally supplied as the first argument to
+:meth:`add_argument`::
+
+   >>> parser = argparse.ArgumentParser()
+   >>> parser.add_argument('bar')
+   >>> parser.parse_args('XXX'.split())
+   Namespace(bar='XXX')
+
+For optional argument actions, the value of ``dest`` is normally inferred from
+the option strings.  :class:`ArgumentParser` generates the value of ``dest`` by
+taking the first long option string and stripping away the initial ``'--'``
+string.  If no long option strings were supplied, ``dest`` will be derived from
+the first short option string by stripping the initial ``'-'`` character.  Any
+internal ``'-'`` characters will be converted to ``'_'`` characters to make sure
+the string is a valid attribute name.  The examples below illustrate this
+behavior::
+
+   >>> parser = argparse.ArgumentParser()
+   >>> parser.add_argument('-f', '--foo-bar', '--foo')
+   >>> parser.add_argument('-x', '-y')
+   >>> parser.parse_args('-f 1 -x 2'.split())
+   Namespace(foo_bar='1', x='2')
+   >>> parser.parse_args('--foo 1 -y 2'.split())
+   Namespace(foo_bar='1', x='2')
+
+``dest`` allows a custom attribute name to be provided::
+
+   >>> parser = argparse.ArgumentParser()
+   >>> parser.add_argument('--foo', dest='bar')
+   >>> parser.parse_args('--foo XXX'.split())
+   Namespace(bar='XXX')
+
+
+The parse_args() method
+-----------------------
+
+.. method:: ArgumentParser.parse_args(args=None, namespace=None)
+
+   Convert argument strings to objects and assign them as attributes of the
+   namespace.  Return the populated namespace.
+
+   Previous calls to :meth:`add_argument` determine exactly what objects are
+   created and how they are assigned. See the documentation for
+   :meth:`add_argument` for details.
+
+   By default, the arg strings are taken from :data:`sys.argv`, and a new empty
+   :class:`Namespace` object is created for the attributes.
+
+
+Option value syntax
+^^^^^^^^^^^^^^^^^^^
+
+The :meth:`parse_args` method supports several ways of specifying the value of
+an option (if it takes one).  In the simplest case, the option and its value are
+passed as two separate arguments::
+
+   >>> parser = argparse.ArgumentParser(prog='PROG')
+   >>> parser.add_argument('-x')
+   >>> parser.add_argument('--foo')
+   >>> parser.parse_args('-x X'.split())
+   Namespace(foo=None, x='X')
+   >>> parser.parse_args('--foo FOO'.split())
+   Namespace(foo='FOO', x=None)
+
+For long options (options with names longer than a single character), the option
+and value can also be passed as a single command line argument, using ``=`` to
+separate them::
+
+   >>> parser.parse_args('--foo=FOO'.split())
+   Namespace(foo='FOO', x=None)
+
+For short options (options only one character long), the option and its value
+can be concatenated::
+
+   >>> parser.parse_args('-xX'.split())
+   Namespace(foo=None, x='X')
+
+Several short options can be joined together, using only a single ``-`` prefix,
+as long as only the last option (or none of them) requires a value::
+
+   >>> parser = argparse.ArgumentParser(prog='PROG')
+   >>> parser.add_argument('-x', action='store_true')
+   >>> parser.add_argument('-y', action='store_true')
+   >>> parser.add_argument('-z')
+   >>> parser.parse_args('-xyzZ'.split())
+   Namespace(x=True, y=True, z='Z')
+
+
+Invalid arguments
+^^^^^^^^^^^^^^^^^
+
+While parsing the command-line, ``parse_args`` checks for a variety of errors,
+including ambiguous options, invalid types, invalid options, wrong number of
+positional arguments, etc.  When it encounters such an error, it exits and
+prints the error along with a usage message::
+
+   >>> parser = argparse.ArgumentParser(prog='PROG')
+   >>> parser.add_argument('--foo', type=int)
+   >>> parser.add_argument('bar', nargs='?')
+
+   >>> # invalid type
+   >>> parser.parse_args(['--foo', 'spam'])
+   usage: PROG [-h] [--foo FOO] [bar]
+   PROG: error: argument --foo: invalid int value: 'spam'
+
+   >>> # invalid option
+   >>> parser.parse_args(['--bar'])
+   usage: PROG [-h] [--foo FOO] [bar]
+   PROG: error: no such option: --bar
+
+   >>> # wrong number of arguments
+   >>> parser.parse_args(['spam', 'badger'])
+   usage: PROG [-h] [--foo FOO] [bar]
+   PROG: error: extra arguments found: badger
+
+
+Arguments containing ``"-"``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``parse_args`` method attempts to give errors whenever the user has clearly
+made a mistake, but some situations are inherently ambiguous.  For example, the
+command-line arg ``'-1'`` could either be an attempt to specify an option or an
+attempt to provide a positional argument.  The ``parse_args`` method is cautious
+here: positional arguments may only begin with ``'-'`` if they look like
+negative numbers and there are no options in the parser that look like negative
+numbers::
+
+   >>> parser = argparse.ArgumentParser(prog='PROG')
+   >>> parser.add_argument('-x')
+   >>> parser.add_argument('foo', nargs='?')
+
+   >>> # no negative number options, so -1 is a positional argument
+   >>> parser.parse_args(['-x', '-1'])
+   Namespace(foo=None, x='-1')
+
+   >>> # no negative number options, so -1 and -5 are positional arguments
+   >>> parser.parse_args(['-x', '-1', '-5'])
+   Namespace(foo='-5', x='-1')
+
+   >>> parser = argparse.ArgumentParser(prog='PROG')
+   >>> parser.add_argument('-1', dest='one')
+   >>> parser.add_argument('foo', nargs='?')
+
+   >>> # negative number options present, so -1 is an option
+   >>> parser.parse_args(['-1', 'X'])
+   Namespace(foo=None, one='X')
+
+   >>> # negative number options present, so -2 is an option
+   >>> parser.parse_args(['-2'])
+   usage: PROG [-h] [-1 ONE] [foo]
+   PROG: error: no such option: -2
+
+   >>> # negative number options present, so both -1s are options
+   >>> parser.parse_args(['-1', '-1'])
+   usage: PROG [-h] [-1 ONE] [foo]
+   PROG: error: argument -1: expected one argument
+
+If you have positional arguments that must begin with ``'-'`` and don't look
+like negative numbers, you can insert the pseudo-argument ``'--'`` which tells
+``parse_args`` that everything after that is a positional argument::
+
+   >>> parser.parse_args(['--', '-f'])
+   Namespace(foo='-f', one=None)
+
+
+Argument abbreviations
+^^^^^^^^^^^^^^^^^^^^^^
+
+The :meth:`parse_args` method allows long options to be abbreviated if the
+abbreviation is unambiguous::
+
+   >>> parser = argparse.ArgumentParser(prog='PROG')
+   >>> parser.add_argument('-bacon')
+   >>> parser.add_argument('-badger')
+   >>> parser.parse_args('-bac MMM'.split())
+   Namespace(bacon='MMM', badger=None)
+   >>> parser.parse_args('-bad WOOD'.split())
+   Namespace(bacon=None, badger='WOOD')
+   >>> parser.parse_args('-ba BA'.split())
+   usage: PROG [-h] [-bacon BACON] [-badger BADGER]
+   PROG: error: ambiguous option: -ba could match -badger, -bacon
+
+An error is produced for arguments that could produce more than one options.
+
+
+Beyond ``sys.argv``
+^^^^^^^^^^^^^^^^^^^
+
+Sometimes it may be useful to have an ArgumentParser parse args other than those
+of :data:`sys.argv`.  This can be accomplished by passing a list of strings to
+``parse_args``.  This is useful for testing at the interactive prompt::
+
+   >>> parser = argparse.ArgumentParser()
+   >>> parser.add_argument(
+   ...     'integers', metavar='int', type=int, choices=xrange(10),
+   ...  nargs='+', help='an integer in the range 0..9')
+   >>> parser.add_argument(
+   ...     '--sum', dest='accumulate', action='store_const', const=sum,
+   ...   default=max, help='sum the integers (default: find the max)')
+   >>> parser.parse_args(['1', '2', '3', '4'])
+   Namespace(accumulate=<built-in function max>, integers=[1, 2, 3, 4])
+   >>> parser.parse_args('1 2 3 4 --sum'.split())
+   Namespace(accumulate=<built-in function sum>, integers=[1, 2, 3, 4])
+
+
+Custom namespaces
+^^^^^^^^^^^^^^^^^
+
+It may also be useful to have an :class:`ArgumentParser` assign attributes to an
+already existing object, rather than the newly-created :class:`Namespace` object
+that is normally used.  This can be achieved by specifying the ``namespace=``
+keyword argument::
+
+   >>> class C(object):
+   ...     pass
+   ...
+   >>> c = C()
+   >>> parser = argparse.ArgumentParser()
+   >>> parser.add_argument('--foo')
+   >>> parser.parse_args(args=['--foo', 'BAR'], namespace=c)
+   >>> c.foo
+   'BAR'
+
+
+Other utilities
+---------------
+
+Sub-commands
+^^^^^^^^^^^^
+
+.. method:: ArgumentParser.add_subparsers()
+
+   Many programs split up their functionality into a number of sub-commands,
+   for example, the ``svn`` program can invoke sub-commands like ``svn
+   checkout``, ``svn update``, and ``svn commit``.  Splitting up functionality
+   this way can be a particularly good idea when a program performs several
+   different functions which require different kinds of command-line arguments.
+   :class:`ArgumentParser` supports the creation of such sub-commands with the
+   :meth:`add_subparsers` method.  The :meth:`add_subparsers` method is normally
+   called with no arguments and returns an special action object.  This object
+   has a single method, ``add_parser``, which takes a command name and any
+   :class:`ArgumentParser` constructor arguments, and returns an
+   :class:`ArgumentParser` object that can be modified as usual.
+
+   Some example usage::
+
+     >>> # create the top-level parser
+     >>> parser = argparse.ArgumentParser(prog='PROG')
+     >>> parser.add_argument('--foo', action='store_true', help='foo help')
+     >>> subparsers = parser.add_subparsers(help='sub-command help')
+     >>>
+     >>> # create the parser for the "a" command
+     >>> parser_a = subparsers.add_parser('a', help='a help')
+     >>> parser_a.add_argument('bar', type=int, help='bar help')
+     >>>
+     >>> # create the parser for the "b" command
+     >>> parser_b = subparsers.add_parser('b', help='b help')
+     >>> parser_b.add_argument('--baz', choices='XYZ', help='baz help')
+     >>>
+     >>> # parse some arg lists
+     >>> parser.parse_args(['a', '12'])
+     Namespace(bar=12, foo=False)
+     >>> parser.parse_args(['--foo', 'b', '--baz', 'Z'])
+     Namespace(baz='Z', foo=True)
+
+   Note that the object returned by :meth:`parse_args` will only contain
+   attributes for the main parser and the subparser that was selected by the
+   command line (and not any other subparsers).  So in the example above, when
+   the ``"a"`` command is specified, only the ``foo`` and ``bar`` attributes are
+   present, and when the ``"b"`` command is specified, only the ``foo`` and
+   ``baz`` attributes are present.
+
+   Similarly, when a help message is requested from a subparser, only the help
+   for that particular parser will be printed.  The help message will not
+   include parent parser or sibling parser messages.  (A help message for each
+   subparser command, however, can be given by supplying the ``help=`` argument
+   to ``add_parser`` as above.)
+
+   ::
+
+     >>> parser.parse_args(['--help'])
+     usage: PROG [-h] [--foo] {a,b} ...
+
+     positional arguments:
+       {a,b}   sub-command help
+     a     a help
+     b     b help
+
+     optional arguments:
+       -h, --help  show this help message and exit
+       --foo   foo help
+
+     >>> parser.parse_args(['a', '--help'])
+     usage: PROG a [-h] bar
+
+     positional arguments:
+       bar     bar help
+
+     optional arguments:
+       -h, --help  show this help message and exit
+
+     >>> parser.parse_args(['b', '--help'])
+     usage: PROG b [-h] [--baz {X,Y,Z}]
+
+     optional arguments:
+       -h, --help     show this help message and exit
+       --baz {X,Y,Z}  baz help
+
+   The :meth:`add_subparsers` method also supports ``title`` and ``description``
+   keyword arguments.  When either is present, the subparser's commands will
+   appear in their own group in the help output.  For example::
+
+     >>> parser = argparse.ArgumentParser()
+     >>> subparsers = parser.add_subparsers(title='subcommands',
+     ...                                    description='valid subcommands',
+     ...                                    help='additional help')
+     >>> subparsers.add_parser('foo')
+     >>> subparsers.add_parser('bar')
+     >>> parser.parse_args(['-h'])
+     usage:  [-h] {foo,bar} ...
+
+     optional arguments:
+       -h, --help  show this help message and exit
+
+     subcommands:
+       valid subcommands
+
+       {foo,bar}   additional help
+
+
+   One particularly effective way of handling sub-commands is to combine the use
+   of the :meth:`add_subparsers` method with calls to :meth:`set_defaults` so
+   that each subparser knows which Python function it should execute.  For
+   example::
+
+     >>> # sub-command functions
+     >>> def foo(args):
+     ...     print args.x * args.y
+     ...
+     >>> def bar(args):
+     ...     print '((%s))' % args.z
+     ...
+     >>> # create the top-level parser
+     >>> parser = argparse.ArgumentParser()
+     >>> subparsers = parser.add_subparsers()
+     >>>
+     >>> # create the parser for the "foo" command
+     >>> parser_foo = subparsers.add_parser('foo')
+     >>> parser_foo.add_argument('-x', type=int, default=1)
+     >>> parser_foo.add_argument('y', type=float)
+     >>> parser_foo.set_defaults(func=foo)
+     >>>
+     >>> # create the parser for the "bar" command
+     >>> parser_bar = subparsers.add_parser('bar')
+     >>> parser_bar.add_argument('z')
+     >>> parser_bar.set_defaults(func=bar)
+     >>>
+     >>> # parse the args and call whatever function was selected
+     >>> args = parser.parse_args('foo 1 -x 2'.split())
+     >>> args.func(args)
+     2.0
+     >>>
+     >>> # parse the args and call whatever function was selected
+     >>> args = parser.parse_args('bar XYZYX'.split())
+     >>> args.func(args)
+     ((XYZYX))
+
+   This way, you can let :meth:`parse_args` does the job of calling the
+   appropriate function after argument parsing is complete.  Associating
+   functions with actions like this is typically the easiest way to handle the
+   different actions for each of your subparsers.  However, if it is necessary
+   to check the name of the subparser that was invoked, the ``dest`` keyword
+   argument to the :meth:`add_subparsers` call will work::
+
+     >>> parser = argparse.ArgumentParser()
+     >>> subparsers = parser.add_subparsers(dest='subparser_name')
+     >>> subparser1 = subparsers.add_parser('1')
+     >>> subparser1.add_argument('-x')
+     >>> subparser2 = subparsers.add_parser('2')
+     >>> subparser2.add_argument('y')
+     >>> parser.parse_args(['2', 'frobble'])
+     Namespace(subparser_name='2', y='frobble')
+
+
+FileType objects
+^^^^^^^^^^^^^^^^
+
+.. class:: FileType(mode='r', bufsize=None)
+
+   The :class:`FileType` factory creates objects that can be passed to the type
+   argument of :meth:`ArgumentParser.add_argument`.  Arguments that have
+   :class:`FileType` objects as their type will open command-line args as files
+   with the requested modes and buffer sizes:
+
+   >>> parser = argparse.ArgumentParser()
+   >>> parser.add_argument('--output', type=argparse.FileType('wb', 0))
+   >>> parser.parse_args(['--output', 'out'])
+   Namespace(output=<open file 'out', mode 'wb' at 0x...>)
+
+   FileType objects understand the pseudo-argument ``'-'`` and automatically
+   convert this into ``sys.stdin`` for readable :class:`FileType` objects and
+   ``sys.stdout`` for writable :class:`FileType` objects:
+
+   >>> parser = argparse.ArgumentParser()
+   >>> parser.add_argument('infile', type=argparse.FileType('r'))
+   >>> parser.parse_args(['-'])
+   Namespace(infile=<open file '<stdin>', mode 'r' at 0x...>)
+
+
+Argument groups
+^^^^^^^^^^^^^^^
+
+.. method:: ArgumentParser.add_argument_group(title=None, description=None)
+
+   By default, :class:`ArgumentParser` groups command-line arguments into
+   "positional arguments" and "optional arguments" when displaying help
+   messages. When there is a better conceptual grouping of arguments than this
+   default one, appropriate groups can be created using the
+   :meth:`add_argument_group` method::
+
+     >>> parser = argparse.ArgumentParser(prog='PROG', add_help=False)
+     >>> group = parser.add_argument_group('group')
+     >>> group.add_argument('--foo', help='foo help')
+     >>> group.add_argument('bar', help='bar help')
+     >>> parser.print_help()
+     usage: PROG [--foo FOO] bar
+
+     group:
+       bar    bar help
+       --foo FOO  foo help
+
+   The :meth:`add_argument_group` method returns an argument group object which
+   has an :meth:`~ArgumentParser.add_argument` method just like a regular
+   :class:`ArgumentParser`.  When an argument is added to the group, the parser
+   treats it just like a normal argument, but displays the argument in a
+   separate group for help messages.  The :meth:`add_argument_group` method
+   accepts *title* and *description* arguments which can be used to
+   customize this display::
+
+     >>> parser = argparse.ArgumentParser(prog='PROG', add_help=False)
+     >>> group1 = parser.add_argument_group('group1', 'group1 description')
+     >>> group1.add_argument('foo', help='foo help')
+     >>> group2 = parser.add_argument_group('group2', 'group2 description')
+     >>> group2.add_argument('--bar', help='bar help')
+     >>> parser.print_help()
+     usage: PROG [--bar BAR] foo
+
+     group1:
+       group1 description
+
+       foo    foo help
+
+     group2:
+       group2 description
+
+       --bar BAR  bar help
+
+   Note that any arguments not your user defined groups will end up back in the
+   usual "positional arguments" and "optional arguments" sections.
+
+
+Mutual exclusion
+^^^^^^^^^^^^^^^^
+
+.. method:: add_mutually_exclusive_group(required=False)
+
+   Create a mutually exclusive group. argparse will make sure that only one of
+   the arguments in the mutually exclusive group was present on the command
+   line::
+
+     >>> parser = argparse.ArgumentParser(prog='PROG')
+     >>> group = parser.add_mutually_exclusive_group()
+     >>> group.add_argument('--foo', action='store_true')
+     >>> group.add_argument('--bar', action='store_false')
+     >>> parser.parse_args(['--foo'])
+     Namespace(bar=True, foo=True)
+     >>> parser.parse_args(['--bar'])
+     Namespace(bar=False, foo=False)
+     >>> parser.parse_args(['--foo', '--bar'])
+     usage: PROG [-h] [--foo | --bar]
+     PROG: error: argument --bar: not allowed with argument --foo
+
+   The :meth:`add_mutually_exclusive_group` method also accepts a *required*
+   argument, to indicate that at least one of the mutually exclusive arguments
+   is required::
+
+     >>> parser = argparse.ArgumentParser(prog='PROG')
+     >>> group = parser.add_mutually_exclusive_group(required=True)
+     >>> group.add_argument('--foo', action='store_true')
+     >>> group.add_argument('--bar', action='store_false')
+     >>> parser.parse_args([])
+     usage: PROG [-h] (--foo | --bar)
+     PROG: error: one of the arguments --foo --bar is required
+
+   Note that currently mutually exclusive argument groups do not support the
+   *title* and *description* arguments of :meth:`add_argument_group`.
+
+
+Parser defaults
+^^^^^^^^^^^^^^^
+
+.. method:: ArgumentParser.set_defaults(**kwargs)
+
+   Most of the time, the attributes of the object returned by :meth:`parse_args`
+   will be fully determined by inspecting the command-line args and the argument
+   actions.  :meth:`ArgumentParser.set_defaults` allows some additional
+   attributes that are determined without any inspection of the command-line to
+   be added::
+
+     >>> parser = argparse.ArgumentParser()
+     >>> parser.add_argument('foo', type=int)
+     >>> parser.set_defaults(bar=42, baz='badger')
+     >>> parser.parse_args(['736'])
+     Namespace(bar=42, baz='badger', foo=736)
+
+   Note that parser-level defaults always override argument-level defaults::
+
+     >>> parser = argparse.ArgumentParser()
+     >>> parser.add_argument('--foo', default='bar')
+     >>> parser.set_defaults(foo='spam')
+     >>> parser.parse_args([])
+     Namespace(foo='spam')
+
+   Parser-level defaults can be particularly useful when working with multiple
+   parsers.  See the :meth:`~ArgumentParser.add_subparsers` method for an
+   example of this type.
+
+.. method:: ArgumentParser.get_default(dest)
+
+   Get the default value for a namespace attribute, as set by either
+   :meth:`~ArgumentParser.add_argument` or by
+   :meth:`~ArgumentParser.set_defaults`::
+
+     >>> parser = argparse.ArgumentParser()
+     >>> parser.add_argument('--foo', default='badger')
+     >>> parser.get_default('foo')
+     'badger'
+
+
+Printing help
+^^^^^^^^^^^^^
+
+In most typical applications, :meth:`parse_args` will take care of formatting
+and printing any usage or error messages.  However, several formatting methods
+are available:
+
+.. method:: ArgumentParser.print_usage(file=None)
+
+   Print a brief description of how the :class:`ArgumentParser` should be
+   invoked on the command line.  If *file* is ``None``, :data:`sys.stderr` is
+   assumed.
+
+.. method:: ArgumentParser.print_help(file=None)
+
+   Print a help message, including the program usage and information about the
+   arguments registered with the :class:`ArgumentParser`.  If *file* is
+   ``None``, :data:`sys.stderr` is assumed.
+
+There are also variants of these methods that simply return a string instead of
+printing it:
+
+.. method:: ArgumentParser.format_usage()
+
+   Return a string containing a brief description of how the
+   :class:`ArgumentParser` should be invoked on the command line.
+
+.. method:: ArgumentParser.format_help()
+
+   Return a string containing a help message, including the program usage and
+   information about the arguments registered with the :class:`ArgumentParser`.
+
+
+Partial parsing
+^^^^^^^^^^^^^^^
+
+.. method:: ArgumentParser.parse_known_args(args=None, namespace=None)
+
+Sometimes a script may only parse a few of the command line arguments, passing
+the remaining arguments on to another script or program. In these cases, the
+:meth:`parse_known_args` method can be useful.  It works much like
+:meth:`~ArgumentParser.parse_args` except that it does not produce an error when
+extra arguments are present.  Instead, it returns a two item tuple containing
+the populated namespace and the list of remaining argument strings.
+
+::
+
+   >>> parser = argparse.ArgumentParser()
+   >>> parser.add_argument('--foo', action='store_true')
+   >>> parser.add_argument('bar')
+   >>> parser.parse_known_args(['--foo', '--badger', 'BAR', 'spam'])
+   (Namespace(bar='BAR', foo=True), ['--badger', 'spam'])
+
+
+Customizing file parsing
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. method:: ArgumentParser.convert_arg_line_to_args(arg_line)
+
+   Arguments that are read from a file (see the *fromfile_prefix_chars*
+   keyword argument to the :class:`ArgumentParser` constructor) are read one
+   argument per line. :meth:`convert_arg_line_to_args` can be overriden for
+   fancier reading.
+
+   This method takes a single argument *arg_line* which is a string read from
+   the argument file.  It returns a list of arguments parsed from this string.
+   The method is called once per line read from the argument file, in order.
+
+   A useful override of this method is one that treats each space-separated word
+   as an argument::
+
+    def convert_arg_line_to_args(self, arg_line):
+        for arg in arg_line.split():
+            if not arg.strip():
+                continue
+            yield arg
+
+
+Exiting methods
+^^^^^^^^^^^^^^^
+
+.. method:: ArgumentParser.exit(status=0, message=None)
+
+   This method terminates the program, exiting with the specified *status*
+   and, if given, it prints a *message* before that.
+
+.. method:: ArgumentParser.error(message)
+
+   This method prints a usage message including the *message* to the
+   standard output and terminates the program with a status code of 2.
+
+
+.. _argparse-from-optparse:
+
+Upgrading optparse code
+-----------------------
+
+Originally, the argparse module had attempted to maintain compatibility with
+optparse.  However, optparse was difficult to extend transparently, particularly
+with the changes required to support the new ``nargs=`` specifiers and better
+usage messages.  When most everything in optparse had either been copy-pasted
+over or monkey-patched, it no longer seemed practical to try to maintain the
+backwards compatibility.
+
+A partial upgrade path from optparse to argparse:
+
+* Replace all ``add_option()`` calls with :meth:`ArgumentParser.add_argument` calls.
+
+* Replace ``options, args = parser.parse_args()`` with ``args =
+  parser.parse_args()`` and add additional :meth:`ArgumentParser.add_argument` calls for the
+  positional arguments.
+
+* Replace callback actions and the ``callback_*`` keyword arguments with
+  ``type`` or ``action`` arguments.
+
+* Replace string names for ``type`` keyword arguments with the corresponding
+  type objects (e.g. int, float, complex, etc).
+
+* Replace :class:`optparse.Values` with :class:`Namespace` and
+  :exc:`optparse.OptionError` and :exc:`optparse.OptionValueError` with
+  :exc:`ArgumentError`.
+
+* Replace strings with implicit arguments such as ``%default`` or ``%prog`` with
+  the standard python syntax to use dictionaries to format strings, that is,
+  ``%(default)s`` and ``%(prog)s``.
+
+* Replace the OptionParser constructor ``version`` argument with a call to
+  ``parser.add_argument('--version', action='version', version='<the version>')``
diff --git a/lib/argparse/doc/source/conf.py b/lib/argparse/doc/source/conf.py
new file mode 100644
index 0000000..f3217cb
--- /dev/null
+++ b/lib/argparse/doc/source/conf.py
@@ -0,0 +1,229 @@
+# -*- coding: utf-8 -*-
+#
+# argparse documentation build configuration file, created by
+# sphinx-quickstart on Sun Mar 27 01:27:16 2011.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = []
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'argparse'
+copyright = u'2011, Steven J. Bethard'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '1.2'
+# The full version, including alpha/beta/rc tags.
+release = '1.2'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = []
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'argparsedoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+  ('index', 'argparse.tex', u'argparse Documentation',
+   u'Steven J. Bethard', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    ('index', 'argparse', u'argparse Documentation',
+     [u'Steven J. Bethard'], 1)
+]
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+  ('index', 'argparse', u'argparse Documentation', u'Steven J. Bethard',
+   'argparse', 'One line description of project.', 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+texinfo_appendices = []
diff --git a/lib/argparse/doc/source/index.rst b/lib/argparse/doc/source/index.rst
new file mode 100644
index 0000000..1038c5f
--- /dev/null
+++ b/lib/argparse/doc/source/index.rst
@@ -0,0 +1,22 @@
+.. argparse documentation master file, created by
+   sphinx-quickstart on Sun Mar 27 01:27:16 2011.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+Welcome to argparse's documentation!
+====================================
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+   argparse
+   license
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`search`
+
diff --git a/lib/argparse/doc/source/license.rst b/lib/argparse/doc/source/license.rst
new file mode 100644
index 0000000..6106f56
--- /dev/null
+++ b/lib/argparse/doc/source/license.rst
@@ -0,0 +1,11 @@
+arparse Copyright and License
+=============================
+
+.. _license:
+
+.. literalinclude:: ../../LICENSE.txt
+
+This is the Python License (from file doc/Python-License.txt):
+
+.. literalinclude:: Python-License.txt
+
diff --git a/lib/argparse/setup.cfg b/lib/argparse/setup.cfg
new file mode 100644
index 0000000..c10415a
--- /dev/null
+++ b/lib/argparse/setup.cfg
@@ -0,0 +1,23 @@
+[bdist_rpm]
+release = 1
+requires = python
+build_requires = python
+doc_files = 
+	README.txt
+	LICENSE.txt
+	PKG-INFO
+	doc/
+
+[egg_info]
+tag_build = 
+tag_date = 0
+tag_svn_revision = 0
+
+[upload_sphinx]
+upload-dir = doc/_build/html
+
+[build_sphinx]
+all_files = 1
+build-dir = doc/_build
+source-dir = doc/
+
diff --git a/lib/argparse/setup.py b/lib/argparse/setup.py
new file mode 100644
index 0000000..20493d3
--- /dev/null
+++ b/lib/argparse/setup.py
@@ -0,0 +1,45 @@
+import sys, os
+
+from setuptools import setup, find_packages
+
+import argparse
+
+long_description = open('README.txt').read()
+
+
+setup_args = dict(
+    name="argparse",
+    version=argparse.__version__,
+    description='Python command-line parsing library',
+    long_description=long_description,
+    author="Steven Bethard",
+    author_email="steven.bethard@gmail.com",
+    download_url="http://argparse.googlecode.com/files/argparse-%s.tar.gz" % (argparse.__version__, ),
+    url="http://code.google.com/p/argparse/",
+    license="Python Software Foundation License",
+    keywords="argparse command line parser parsing",
+    platforms="any",
+    classifiers="""\
+Development Status :: 5 - Production/Stable
+Environment :: Console
+Intended Audience :: Developers
+License :: OSI Approved :: Python Software Foundation License
+Operating System :: OS Independent
+Programming Language :: Python
+Programming Language :: Python :: 2
+Programming Language :: Python :: 3
+Programming Language :: Python :: 2.3
+Programming Language :: Python :: 2.4
+Programming Language :: Python :: 2.5
+Programming Language :: Python :: 2.6
+Programming Language :: Python :: 2.7
+Programming Language :: Python :: 3.0
+Programming Language :: Python :: 3.1
+Programming Language :: Python :: 3.2
+Topic :: Software Development""".splitlines(),
+    py_modules=['argparse'],
+)
+
+if __name__ == '__main__':
+    setup(**setup_args)
+
diff --git a/lib/argparse/test/test_argparse.py b/lib/argparse/test/test_argparse.py
new file mode 100644
index 0000000..bfa5f9e
--- /dev/null
+++ b/lib/argparse/test/test_argparse.py
@@ -0,0 +1,4380 @@
+# Author: Steven J. Bethard <steven.bethard@gmail.com>.
+
+import codecs
+import inspect
+import os
+import shutil
+import sys
+import textwrap
+import tempfile
+import unittest
+import argparse
+
+try:
+    from StringIO import StringIO
+except ImportError:
+    from io import StringIO
+
+class StdIOBuffer(StringIO):
+    pass
+
+
+try:
+    set
+except NameError:
+    # for python < 2.4 compatibility (sets module is there since 2.3):
+    from sets import Set as set
+
+try:
+    sorted
+except NameError:
+    # for python < 2.4 compatibility:
+    def sorted(iterable, reverse=False):
+        result = list(iterable)
+        result.sort()
+        if reverse:
+            result.reverse()
+        return result
+
+# silence some warnings - these are expected
+import warnings
+warnings.filterwarnings(
+    action='ignore',
+    message='The "version" argument to ArgumentParser is deprecated.',
+    category=DeprecationWarning)
+warnings.filterwarnings(
+    action='ignore',
+    message='The format_version method is deprecated',
+    category=DeprecationWarning)
+warnings.filterwarnings(
+    action='ignore',
+    message='The print_version method is deprecated',
+    category=DeprecationWarning)
+
+
+class TestCase(unittest.TestCase):
+
+    def assertEqual(self, obj1, obj2):
+        if obj1 != obj2:
+            print('')
+            print(repr(obj1))
+            print(repr(obj2))
+            print(obj1)
+            print(obj2)
+        super(TestCase, self).assertEqual(obj1, obj2)
+
+    # Python 2.3 does not have unittest.TestCase.assertTrue:
+    def assertTrue(self, expr, msg=None):
+        if not expr:
+            msg = self._formatMessage(msg, "%s is not True" % safe_repr(expr))
+            raise self.failureException(msg)
+
+
+class TempDirMixin(object):
+
+    def setUp(self):
+        self.temp_dir = tempfile.mkdtemp()
+        self.old_dir = os.getcwd()
+        os.chdir(self.temp_dir)
+
+    def tearDown(self):
+        os.chdir(self.old_dir)
+        while True:
+            try:
+                shutil.rmtree(self.temp_dir)
+            except WindowsError:
+                continue
+            else:
+                break
+
+
+class Sig(object):
+
+    def __init__(self, *args, **kwargs):
+        self.args = args
+        self.kwargs = kwargs
+
+
+class NS(object):
+
+    def __init__(self, **kwargs):
+        self.__dict__.update(kwargs)
+
+    def __repr__(self):
+        sorted_items = sorted(self.__dict__.items())
+        kwarg_str = ', '.join(['%s=%r' % tup for tup in sorted_items])
+        return '%s(%s)' % (type(self).__name__, kwarg_str)
+
+    __hash__ = None
+
+    def __eq__(self, other):
+        return vars(self) == vars(other)
+
+    def __ne__(self, other):
+        return not (self == other)
+
+
+class ArgumentParserError(Exception):
+
+    def __init__(self, message, stdout=None, stderr=None, error_code=None):
+        Exception.__init__(self, message, stdout, stderr)
+        self.message = message
+        self.stdout = stdout
+        self.stderr = stderr
+        self.error_code = error_code
+
+
+def stderr_to_parser_error(parse_args, *args, **kwargs):
+    # if this is being called recursively and stderr or stdout is already being
+    # redirected, simply call the function and let the enclosing function
+    # catch the exception
+    if isinstance(sys.stderr, StdIOBuffer) or isinstance(sys.stdout, StdIOBuffer):
+        return parse_args(*args, **kwargs)
+
+    # if this is not being called recursively, redirect stderr and
+    # use it as the ArgumentParserError message
+    old_stdout = sys.stdout
+    old_stderr = sys.stderr
+    sys.stdout = StdIOBuffer()
+    sys.stderr = StdIOBuffer()
+    try:
+        try:
+            result = parse_args(*args, **kwargs)
+            for key in list(vars(result)):
+                if getattr(result, key) is sys.stdout:
+                    setattr(result, key, old_stdout)
+                if getattr(result, key) is sys.stderr:
+                    setattr(result, key, old_stderr)
+            return result
+        except SystemExit:
+            code = sys.exc_info()[1].code
+            stdout = sys.stdout.getvalue()
+            stderr = sys.stderr.getvalue()
+            raise ArgumentParserError("SystemExit", stdout, stderr, code)
+    finally:
+        sys.stdout = old_stdout
+        sys.stderr = old_stderr
+
+
+class ErrorRaisingArgumentParser(argparse.ArgumentParser):
+
+    def parse_args(self, *args, **kwargs):
+        parse_args = super(ErrorRaisingArgumentParser, self).parse_args
+        return stderr_to_parser_error(parse_args, *args, **kwargs)
+
+    def exit(self, *args, **kwargs):
+        exit = super(ErrorRaisingArgumentParser, self).exit
+        return stderr_to_parser_error(exit, *args, **kwargs)
+
+    def error(self, *args, **kwargs):
+        error = super(ErrorRaisingArgumentParser, self).error
+        return stderr_to_parser_error(error, *args, **kwargs)
+
+
+class ParserTesterMetaclass(type):
+    """Adds parser tests using the class attributes.
+
+    Classes of this type should specify the following attributes:
+
+    argument_signatures -- a list of Sig objects which specify
+        the signatures of Argument objects to be created
+    failures -- a list of args lists that should cause the parser
+        to fail
+    successes -- a list of (initial_args, options, remaining_args) tuples
+        where initial_args specifies the string args to be parsed,
+        options is a dict that should match the vars() of the options
+        parsed out of initial_args, and remaining_args should be any
+        remaining unparsed arguments
+    """
+
+    def __init__(cls, name, bases, bodydict):
+        if name == 'ParserTestCase':
+            return
+
+        # default parser signature is empty
+        if not hasattr(cls, 'parser_signature'):
+            cls.parser_signature = Sig()
+        if not hasattr(cls, 'parser_class'):
+            cls.parser_class = ErrorRaisingArgumentParser
+
+        # ---------------------------------------
+        # functions for adding optional arguments
+        # ---------------------------------------
+        def no_groups(parser, argument_signatures):
+            """Add all arguments directly to the parser"""
+            for sig in argument_signatures:
+                parser.add_argument(*sig.args, **sig.kwargs)
+
+        def one_group(parser, argument_signatures):
+            """Add all arguments under a single group in the parser"""
+            group = parser.add_argument_group('foo')
+            for sig in argument_signatures:
+                group.add_argument(*sig.args, **sig.kwargs)
+
+        def many_groups(parser, argument_signatures):
+            """Add each argument in its own group to the parser"""
+            for i, sig in enumerate(argument_signatures):
+                group = parser.add_argument_group('foo:%i' % i)
+                group.add_argument(*sig.args, **sig.kwargs)
+
+        # --------------------------
+        # functions for parsing args
+        # --------------------------
+        def listargs(parser, args):
+            """Parse the args by passing in a list"""
+            return parser.parse_args(args)
+
+        def sysargs(parser, args):
+            """Parse the args by defaulting to sys.argv"""
+            old_sys_argv = sys.argv
+            sys.argv = [old_sys_argv[0]] + args
+            try:
+                return parser.parse_args()
+            finally:
+                sys.argv = old_sys_argv
+
+        # class that holds the combination of one optional argument
+        # addition method and one arg parsing method
+        class AddTests(object):
+
+            def __init__(self, tester_cls, add_arguments, parse_args):
+                self._add_arguments = add_arguments
+                self._parse_args = parse_args
+
+                add_arguments_name = self._add_arguments.__name__
+                parse_args_name = self._parse_args.__name__
+                for test_func in [self.test_failures, self.test_successes]:
+                    func_name = test_func.__name__
+                    names = func_name, add_arguments_name, parse_args_name
+                    test_name = '_'.join(names)
+
+                    def wrapper(self, test_func=test_func):
+                        test_func(self)
+                    try:
+                        wrapper.__name__ = test_name
+                    except TypeError:
+                        pass
+                    setattr(tester_cls, test_name, wrapper)
+
+            def _get_parser(self, tester):
+                args = tester.parser_signature.args
+                kwargs = tester.parser_signature.kwargs
+                parser = tester.parser_class(*args, **kwargs)
+                self._add_arguments(parser, tester.argument_signatures)
+                return parser
+
+            def test_failures(self, tester):
+                parser = self._get_parser(tester)
+                for args_str in tester.failures:
+                    args = args_str.split()
+                    raises = tester.assertRaises
+                    raises(ArgumentParserError, parser.parse_args, args)
+
+            def test_successes(self, tester):
+                parser = self._get_parser(tester)
+                for args, expected_ns in tester.successes:
+                    if isinstance(args, str):
+                        args = args.split()
+                    result_ns = self._parse_args(parser, args)
+                    tester.assertEqual(expected_ns, result_ns)
+
+        # add tests for each combination of an optionals adding method
+        # and an arg parsing method
+        for add_arguments in [no_groups, one_group, many_groups]:
+            for parse_args in [listargs, sysargs]:
+                AddTests(cls, add_arguments, parse_args)
+
+bases = TestCase,
+ParserTestCase = ParserTesterMetaclass('ParserTestCase', bases, {})
+
+# ===============
+# Optionals tests
+# ===============
+
+class TestOptionalsSingleDash(ParserTestCase):
+    """Test an Optional with a single-dash option string"""
+
+    argument_signatures = [Sig('-x')]
+    failures = ['-x', 'a', '--foo', '-x --foo', '-x -y']
+    successes = [
+        ('', NS(x=None)),
+        ('-x a', NS(x='a')),
+        ('-xa', NS(x='a')),
+        ('-x -1', NS(x='-1')),
+        ('-x-1', NS(x='-1')),
+    ]
+
+
+class TestOptionalsSingleDashCombined(ParserTestCase):
+    """Test an Optional with a single-dash option string"""
+
+    argument_signatures = [
+        Sig('-x', action='store_true'),
+        Sig('-yyy', action='store_const', const=42),
+        Sig('-z'),
+    ]
+    failures = ['a', '--foo', '-xa', '-x --foo', '-x -z', '-z -x',
+                '-yx', '-yz a', '-yyyx', '-yyyza', '-xyza']
+    successes = [
+        ('', NS(x=False, yyy=None, z=None)),
+        ('-x', NS(x=True, yyy=None, z=None)),
+        ('-za', NS(x=False, yyy=None, z='a')),
+        ('-z a', NS(x=False, yyy=None, z='a')),
+        ('-xza', NS(x=True, yyy=None, z='a')),
+        ('-xz a', NS(x=True, yyy=None, z='a')),
+        ('-x -za', NS(x=True, yyy=None, z='a')),
+        ('-x -z a', NS(x=True, yyy=None, z='a')),
+        ('-y', NS(x=False, yyy=42, z=None)),
+        ('-yyy', NS(x=False, yyy=42, z=None)),
+        ('-x -yyy -za', NS(x=True, yyy=42, z='a')),
+        ('-x -yyy -z a', NS(x=True, yyy=42, z='a')),
+    ]
+
+
+class TestOptionalsSingleDashLong(ParserTestCase):
+    """Test an Optional with a multi-character single-dash option string"""
+
+    argument_signatures = [Sig('-foo')]
+    failures = ['-foo', 'a', '--foo', '-foo --foo', '-foo -y', '-fooa']
+    successes = [
+        ('', NS(foo=None)),
+        ('-foo a', NS(foo='a')),
+        ('-foo -1', NS(foo='-1')),
+        ('-fo a', NS(foo='a')),
+        ('-f a', NS(foo='a')),
+    ]
+
+
+class TestOptionalsSingleDashSubsetAmbiguous(ParserTestCase):
+    """Test Optionals where option strings are subsets of each other"""
+
+    argument_signatures = [Sig('-f'), Sig('-foobar'), Sig('-foorab')]
+    failures = ['-f', '-foo', '-fo', '-foo b', '-foob', '-fooba', '-foora']
+    successes = [
+        ('', NS(f=None, foobar=None, foorab=None)),
+        ('-f a', NS(f='a', foobar=None, foorab=None)),
+        ('-fa', NS(f='a', foobar=None, foorab=None)),
+        ('-foa', NS(f='oa', foobar=None, foorab=None)),
+        ('-fooa', NS(f='ooa', foobar=None, foorab=None)),
+        ('-foobar a', NS(f=None, foobar='a', foorab=None)),
+        ('-foorab a', NS(f=None, foobar=None, foorab='a')),
+    ]
+
+
+class TestOptionalsSingleDashAmbiguous(ParserTestCase):
+    """Test Optionals that partially match but are not subsets"""
+
+    argument_signatures = [Sig('-foobar'), Sig('-foorab')]
+    failures = ['-f', '-f a', '-fa', '-foa', '-foo', '-fo', '-foo b']
+    successes = [
+        ('', NS(foobar=None, foorab=None)),
+        ('-foob a', NS(foobar='a', foorab=None)),
+        ('-foor a', NS(foobar=None, foorab='a')),
+        ('-fooba a', NS(foobar='a', foorab=None)),
+        ('-foora a', NS(foobar=None, foorab='a')),
+        ('-foobar a', NS(foobar='a', foorab=None)),
+        ('-foorab a', NS(foobar=None, foorab='a')),
+    ]
+
+
+class TestOptionalsNumeric(ParserTestCase):
+    """Test an Optional with a short opt string"""
+
+    argument_signatures = [Sig('-1', dest='one')]
+    failures = ['-1', 'a', '-1 --foo', '-1 -y', '-1 -1', '-1 -2']
+    successes = [
+        ('', NS(one=None)),
+        ('-1 a', NS(one='a')),
+        ('-1a', NS(one='a')),
+        ('-1-2', NS(one='-2')),
+    ]
+
+
+class TestOptionalsDoubleDash(ParserTestCase):
+    """Test an Optional with a double-dash option string"""
+
+    argument_signatures = [Sig('--foo')]
+    failures = ['--foo', '-f', '-f a', 'a', '--foo -x', '--foo --bar']
+    successes = [
+        ('', NS(foo=None)),
+        ('--foo a', NS(foo='a')),
+        ('--foo=a', NS(foo='a')),
+        ('--foo -2.5', NS(foo='-2.5')),
+        ('--foo=-2.5', NS(foo='-2.5')),
+    ]
+
+
+class TestOptionalsDoubleDashPartialMatch(ParserTestCase):
+    """Tests partial matching with a double-dash option string"""
+
+    argument_signatures = [
+        Sig('--badger', action='store_true'),
+        Sig('--bat'),
+    ]
+    failures = ['--bar', '--b', '--ba', '--b=2', '--ba=4', '--badge 5']
+    successes = [
+        ('', NS(badger=False, bat=None)),
+        ('--bat X', NS(badger=False, bat='X')),
+        ('--bad', NS(badger=True, bat=None)),
+        ('--badg', NS(badger=True, bat=None)),
+        ('--badge', NS(badger=True, bat=None)),
+        ('--badger', NS(badger=True, bat=None)),
+    ]
+
+
+class TestOptionalsDoubleDashPrefixMatch(ParserTestCase):
+    """Tests when one double-dash option string is a prefix of another"""
+
+    argument_signatures = [
+        Sig('--badger', action='store_true'),
+        Sig('--ba'),
+    ]
+    failures = ['--bar', '--b', '--ba', '--b=2', '--badge 5']
+    successes = [
+        ('', NS(badger=False, ba=None)),
+        ('--ba X', NS(badger=False, ba='X')),
+        ('--ba=X', NS(badger=False, ba='X')),
+        ('--bad', NS(badger=True, ba=None)),
+        ('--badg', NS(badger=True, ba=None)),
+        ('--badge', NS(badger=True, ba=None)),
+        ('--badger', NS(badger=True, ba=None)),
+    ]
+
+
+class TestOptionalsSingleDoubleDash(ParserTestCase):
+    """Test an Optional with single- and double-dash option strings"""
+
+    argument_signatures = [
+        Sig('-f', action='store_true'),
+        Sig('--bar'),
+        Sig('-baz', action='store_const', const=42),
+    ]
+    failures = ['--bar', '-fbar', '-fbaz', '-bazf', '-b B', 'B']
+    successes = [
+        ('', NS(f=False, bar=None, baz=None)),
+        ('-f', NS(f=True, bar=None, baz=None)),
+        ('--ba B', NS(f=False, bar='B', baz=None)),
+        ('-f --bar B', NS(f=True, bar='B', baz=None)),
+        ('-f -b', NS(f=True, bar=None, baz=42)),
+        ('-ba -f', NS(f=True, bar=None, baz=42)),
+    ]
+
+
+class TestOptionalsAlternatePrefixChars(ParserTestCase):
+    """Test an Optional with option strings with custom prefixes"""
+
+    parser_signature = Sig(prefix_chars='+:/', add_help=False)
+    argument_signatures = [
+        Sig('+f', action='store_true'),
+        Sig('::bar'),
+        Sig('/baz', action='store_const', const=42),
+    ]
+    failures = ['--bar', '-fbar', '-b B', 'B', '-f', '--bar B', '-baz', '-h', '--help', '+h', '::help', '/help']
+    successes = [
+        ('', NS(f=False, bar=None, baz=None)),
+        ('+f', NS(f=True, bar=None, baz=None)),
+        ('::ba B', NS(f=False, bar='B', baz=None)),
+        ('+f ::bar B', NS(f=True, bar='B', baz=None)),
+        ('+f /b', NS(f=True, bar=None, baz=42)),
+        ('/ba +f', NS(f=True, bar=None, baz=42)),
+    ]
+
+
+class TestOptionalsAlternatePrefixCharsAddedHelp(ParserTestCase):
+    """When ``-`` not in prefix_chars, default operators created for help
+       should use the prefix_chars in use rather than - or --
+       http://bugs.python.org/issue9444"""
+
+    parser_signature = Sig(prefix_chars='+:/', add_help=True)
+    argument_signatures = [
+        Sig('+f', action='store_true'),
+        Sig('::bar'),
+        Sig('/baz', action='store_const', const=42),
+    ]
+    failures = ['--bar', '-fbar', '-b B', 'B', '-f', '--bar B', '-baz']
+    successes = [
+        ('', NS(f=False, bar=None, baz=None)),
+        ('+f', NS(f=True, bar=None, baz=None)),
+        ('::ba B', NS(f=False, bar='B', baz=None)),
+        ('+f ::bar B', NS(f=True, bar='B', baz=None)),
+        ('+f /b', NS(f=True, bar=None, baz=42)),
+        ('/ba +f', NS(f=True, bar=None, baz=42))
+    ]
+
+
+class TestOptionalsAlternatePrefixCharsMultipleShortArgs(ParserTestCase):
+    """Verify that Optionals must be called with their defined prefixes"""
+
+    parser_signature = Sig(prefix_chars='+-', add_help=False)
+    argument_signatures = [
+        Sig('-x', action='store_true'),
+        Sig('+y', action='store_true'),
+        Sig('+z', action='store_true'),
+    ]
+    failures = ['-w',
+                '-xyz',
+                '+x',
+                '-y',
+                '+xyz',
+    ]
+    successes = [
+        ('', NS(x=False, y=False, z=False)),
+        ('-x', NS(x=True, y=False, z=False)),
+        ('+y -x', NS(x=True, y=True, z=False)),
+        ('+yz -x', NS(x=True, y=True, z=True)),
+    ]
+
+
+class TestOptionalsShortLong(ParserTestCase):
+    """Test a combination of single- and double-dash option strings"""
+
+    argument_signatures = [
+        Sig('-v', '--verbose', '-n', '--noisy', action='store_true'),
+    ]
+    failures = ['--x --verbose', '-N', 'a', '-v x']
+    successes = [
+        ('', NS(verbose=False)),
+        ('-v', NS(verbose=True)),
+        ('--verbose', NS(verbose=True)),
+        ('-n', NS(verbose=True)),
+        ('--noisy', NS(verbose=True)),
+    ]
+
+
+class TestOptionalsDest(ParserTestCase):
+    """Tests various means of setting destination"""
+
+    argument_signatures = [Sig('--foo-bar'), Sig('--baz', dest='zabbaz')]
+    failures = ['a']
+    successes = [
+        ('--foo-bar f', NS(foo_bar='f', zabbaz=None)),
+        ('--baz g', NS(foo_bar=None, zabbaz='g')),
+        ('--foo-bar h --baz i', NS(foo_bar='h', zabbaz='i')),
+        ('--baz j --foo-bar k', NS(foo_bar='k', zabbaz='j')),
+    ]
+
+
+class TestOptionalsDefault(ParserTestCase):
+    """Tests specifying a default for an Optional"""
+
+    argument_signatures = [Sig('-x'), Sig('-y', default=42)]
+    failures = ['a']
+    successes = [
+        ('', NS(x=None, y=42)),
+        ('-xx', NS(x='x', y=42)),
+        ('-yy', NS(x=None, y='y')),
+    ]
+
+
+class TestOptionalsNargsDefault(ParserTestCase):
+    """Tests not specifying the number of args for an Optional"""
+
+    argument_signatures = [Sig('-x')]
+    failures = ['a', '-x']
+    successes = [
+        ('', NS(x=None)),
+        ('-x a', NS(x='a')),
+    ]
+
+
+class TestOptionalsNargs1(ParserTestCase):
+    """Tests specifying the 1 arg for an Optional"""
+
+    argument_signatures = [Sig('-x', nargs=1)]
+    failures = ['a', '-x']
+    successes = [
+        ('', NS(x=None)),
+        ('-x a', NS(x=['a'])),
+    ]
+
+
+class TestOptionalsNargs3(ParserTestCase):
+    """Tests specifying the 3 args for an Optional"""
+
+    argument_signatures = [Sig('-x', nargs=3)]
+    failures = ['a', '-x', '-x a', '-x a b', 'a -x', 'a -x b']
+    successes = [
+        ('', NS(x=None)),
+        ('-x a b c', NS(x=['a', 'b', 'c'])),
+    ]
+
+
+class TestOptionalsNargsOptional(ParserTestCase):
+    """Tests specifying an Optional arg for an Optional"""
+
+    argument_signatures = [
+        Sig('-w', nargs='?'),
+        Sig('-x', nargs='?', const=42),
+        Sig('-y', nargs='?', default='spam'),
+        Sig('-z', nargs='?', type=int, const='42', default='84'),
+    ]
+    failures = ['2']
+    successes = [
+        ('', NS(w=None, x=None, y='spam', z=84)),
+        ('-w', NS(w=None, x=None, y='spam', z=84)),
+        ('-w 2', NS(w='2', x=None, y='spam', z=84)),
+        ('-x', NS(w=None, x=42, y='spam', z=84)),
+        ('-x 2', NS(w=None, x='2', y='spam', z=84)),
+        ('-y', NS(w=None, x=None, y=None, z=84)),
+        ('-y 2', NS(w=None, x=None, y='2', z=84)),
+        ('-z', NS(w=None, x=None, y='spam', z=42)),
+        ('-z 2', NS(w=None, x=None, y='spam', z=2)),
+    ]
+
+
+class TestOptionalsNargsZeroOrMore(ParserTestCase):
+    """Tests specifying an args for an Optional that accepts zero or more"""
+
+    argument_signatures = [
+        Sig('-x', nargs='*'),
+        Sig('-y', nargs='*', default='spam'),
+    ]
+    failures = ['a']
+    successes = [
+        ('', NS(x=None, y='spam')),
+        ('-x', NS(x=[], y='spam')),
+        ('-x a', NS(x=['a'], y='spam')),
+        ('-x a b', NS(x=['a', 'b'], y='spam')),
+        ('-y', NS(x=None, y=[])),
+        ('-y a', NS(x=None, y=['a'])),
+        ('-y a b', NS(x=None, y=['a', 'b'])),
+    ]
+
+
+class TestOptionalsNargsOneOrMore(ParserTestCase):
+    """Tests specifying an args for an Optional that accepts one or more"""
+
+    argument_signatures = [
+        Sig('-x', nargs='+'),
+        Sig('-y', nargs='+', default='spam'),
+    ]
+    failures = ['a', '-x', '-y', 'a -x', 'a -y b']
+    successes = [
+        ('', NS(x=None, y='spam')),
+        ('-x a', NS(x=['a'], y='spam')),
+        ('-x a b', NS(x=['a', 'b'], y='spam')),
+        ('-y a', NS(x=None, y=['a'])),
+        ('-y a b', NS(x=None, y=['a', 'b'])),
+    ]
+
+
+class TestOptionalsChoices(ParserTestCase):
+    """Tests specifying the choices for an Optional"""
+
+    argument_signatures = [
+        Sig('-f', choices='abc'),
+        Sig('-g', type=int, choices=range(5))]
+    failures = ['a', '-f d', '-fad', '-ga', '-g 6']
+    successes = [
+        ('', NS(f=None, g=None)),
+        ('-f a', NS(f='a', g=None)),
+        ('-f c', NS(f='c', g=None)),
+        ('-g 0', NS(f=None, g=0)),
+        ('-g 03', NS(f=None, g=3)),
+        ('-fb -g4', NS(f='b', g=4)),
+    ]
+
+
+class TestOptionalsRequired(ParserTestCase):
+    """Tests the an optional action that is required"""
+
+    argument_signatures = [
+        Sig('-x', type=int, required=True),
+    ]
+    failures = ['a', '']
+    successes = [
+        ('-x 1', NS(x=1)),
+        ('-x42', NS(x=42)),
+    ]
+
+
+class TestOptionalsActionStore(ParserTestCase):
+    """Tests the store action for an Optional"""
+
+    argument_signatures = [Sig('-x', action='store')]
+    failures = ['a', 'a -x']
+    successes = [
+        ('', NS(x=None)),
+        ('-xfoo', NS(x='foo')),
+    ]
+
+
+class TestOptionalsActionStoreConst(ParserTestCase):
+    """Tests the store_const action for an Optional"""
+
+    argument_signatures = [Sig('-y', action='store_const', const=object)]
+    failures = ['a']
+    successes = [
+        ('', NS(y=None)),
+        ('-y', NS(y=object)),
+    ]
+
+
+class TestOptionalsActionStoreFalse(ParserTestCase):
+    """Tests the store_false action for an Optional"""
+
+    argument_signatures = [Sig('-z', action='store_false')]
+    failures = ['a', '-za', '-z a']
+    successes = [
+        ('', NS(z=True)),
+        ('-z', NS(z=False)),
+    ]
+
+
+class TestOptionalsActionStoreTrue(ParserTestCase):
+    """Tests the store_true action for an Optional"""
+
+    argument_signatures = [Sig('--apple', action='store_true')]
+    failures = ['a', '--apple=b', '--apple b']
+    successes = [
+        ('', NS(apple=False)),
+        ('--apple', NS(apple=True)),
+    ]
+
+
+class TestOptionalsActionAppend(ParserTestCase):
+    """Tests the append action for an Optional"""
+
+    argument_signatures = [Sig('--baz', action='append')]
+    failures = ['a', '--baz', 'a --baz', '--baz a b']
+    successes = [
+        ('', NS(baz=None)),
+        ('--baz a', NS(baz=['a'])),
+        ('--baz a --baz b', NS(baz=['a', 'b'])),
+    ]
+
+
+class TestOptionalsActionAppendWithDefault(ParserTestCase):
+    """Tests the append action for an Optional"""
+
+    argument_signatures = [Sig('--baz', action='append', default=['X'])]
+    failures = ['a', '--baz', 'a --baz', '--baz a b']
+    successes = [
+        ('', NS(baz=['X'])),
+        ('--baz a', NS(baz=['X', 'a'])),
+        ('--baz a --baz b', NS(baz=['X', 'a', 'b'])),
+    ]
+
+
+class TestOptionalsActionAppendConst(ParserTestCase):
+    """Tests the append_const action for an Optional"""
+
+    argument_signatures = [
+        Sig('-b', action='append_const', const=Exception),
+        Sig('-c', action='append', dest='b'),
+    ]
+    failures = ['a', '-c', 'a -c', '-bx', '-b x']
+    successes = [
+        ('', NS(b=None)),
+        ('-b', NS(b=[Exception])),
+        ('-b -cx -b -cyz', NS(b=[Exception, 'x', Exception, 'yz'])),
+    ]
+
+
+class TestOptionalsActionAppendConstWithDefault(ParserTestCase):
+    """Tests the append_const action for an Optional"""
+
+    argument_signatures = [
+        Sig('-b', action='append_const', const=Exception, default=['X']),
+        Sig('-c', action='append', dest='b'),
+    ]
+    failures = ['a', '-c', 'a -c', '-bx', '-b x']
+    successes = [
+        ('', NS(b=['X'])),
+        ('-b', NS(b=['X', Exception])),
+        ('-b -cx -b -cyz', NS(b=['X', Exception, 'x', Exception, 'yz'])),
+    ]
+
+
+class TestOptionalsActionCount(ParserTestCase):
+    """Tests the count action for an Optional"""
+
+    argument_signatures = [Sig('-x', action='count')]
+    failures = ['a', '-x a', '-x b', '-x a -x b']
+    successes = [
+        ('', NS(x=None)),
+        ('-x', NS(x=1)),
+    ]
+
+
+# ================
+# Positional tests
+# ================
+
+class TestPositionalsNargsNone(ParserTestCase):
+    """Test a Positional that doesn't specify nargs"""
+
+    argument_signatures = [Sig('foo')]
+    failures = ['', '-x', 'a b']
+    successes = [
+        ('a', NS(foo='a')),
+    ]
+
+
+class TestPositionalsNargs1(ParserTestCase):
+    """Test a Positional that specifies an nargs of 1"""
+
+    argument_signatures = [Sig('foo', nargs=1)]
+    failures = ['', '-x', 'a b']
+    successes = [
+        ('a', NS(foo=['a'])),
+    ]
+
+
+class TestPositionalsNargs2(ParserTestCase):
+    """Test a Positional that specifies an nargs of 2"""
+
+    argument_signatures = [Sig('foo', nargs=2)]
+    failures = ['', 'a', '-x', 'a b c']
+    successes = [
+        ('a b', NS(foo=['a', 'b'])),
+    ]
+
+
+class TestPositionalsNargsZeroOrMore(ParserTestCase):
+    """Test a Positional that specifies unlimited nargs"""
+
+    argument_signatures = [Sig('foo', nargs='*')]
+    failures = ['-x']
+    successes = [
+        ('', NS(foo=[])),
+        ('a', NS(foo=['a'])),
+        ('a b', NS(foo=['a', 'b'])),
+    ]
+
+
+class TestPositionalsNargsZeroOrMoreDefault(ParserTestCase):
+    """Test a Positional that specifies unlimited nargs and a default"""
+
+    argument_signatures = [Sig('foo', nargs='*', default='bar')]
+    failures = ['-x']
+    successes = [
+        ('', NS(foo='bar')),
+        ('a', NS(foo=['a'])),
+        ('a b', NS(foo=['a', 'b'])),
+    ]
+
+
+class TestPositionalsNargsOneOrMore(ParserTestCase):
+    """Test a Positional that specifies one or more nargs"""
+
+    argument_signatures = [Sig('foo', nargs='+')]
+    failures = ['', '-x']
+    successes = [
+        ('a', NS(foo=['a'])),
+        ('a b', NS(foo=['a', 'b'])),
+    ]
+
+
+class TestPositionalsNargsOptional(ParserTestCase):
+    """Tests an Optional Positional"""
+
+    argument_signatures = [Sig('foo', nargs='?')]
+    failures = ['-x', 'a b']
+    successes = [
+        ('', NS(foo=None)),
+        ('a', NS(foo='a')),
+    ]
+
+
+class TestPositionalsNargsOptionalDefault(ParserTestCase):
+    """Tests an Optional Positional with a default value"""
+
+    argument_signatures = [Sig('foo', nargs='?', default=42)]
+    failures = ['-x', 'a b']
+    successes = [
+        ('', NS(foo=42)),
+        ('a', NS(foo='a')),
+    ]
+
+
+class TestPositionalsNargsOptionalConvertedDefault(ParserTestCase):
+    """Tests an Optional Positional with a default value
+    that needs to be converted to the appropriate type.
+    """
+
+    argument_signatures = [
+        Sig('foo', nargs='?', type=int, default='42'),
+    ]
+    failures = ['-x', 'a b', '1 2']
+    successes = [
+        ('', NS(foo=42)),
+        ('1', NS(foo=1)),
+    ]
+
+
+class TestPositionalsNargsNoneNone(ParserTestCase):
+    """Test two Positionals that don't specify nargs"""
+
+    argument_signatures = [Sig('foo'), Sig('bar')]
+    failures = ['', '-x', 'a', 'a b c']
+    successes = [
+        ('a b', NS(foo='a', bar='b')),
+    ]
+
+
+class TestPositionalsNargsNone1(ParserTestCase):
+    """Test a Positional with no nargs followed by one with 1"""
+
+    argument_signatures = [Sig('foo'), Sig('bar', nargs=1)]
+    failures = ['', '--foo', 'a', 'a b c']
+    successes = [
+        ('a b', NS(foo='a', bar=['b'])),
+    ]
+
+
+class TestPositionalsNargs2None(ParserTestCase):
+    """Test a Positional with 2 nargs followed by one with none"""
+
+    argument_signatures = [Sig('foo', nargs=2), Sig('bar')]
+    failures = ['', '--foo', 'a', 'a b', 'a b c d']
+    successes = [
+        ('a b c', NS(foo=['a', 'b'], bar='c')),
+    ]
+
+
+class TestPositionalsNargsNoneZeroOrMore(ParserTestCase):
+    """Test a Positional with no nargs followed by one with unlimited"""
+
+    argument_signatures = [Sig('foo'), Sig('bar', nargs='*')]
+    failures = ['', '--foo']
+    successes = [
+        ('a', NS(foo='a', bar=[])),
+        ('a b', NS(foo='a', bar=['b'])),
+        ('a b c', NS(foo='a', bar=['b', 'c'])),
+    ]
+
+
+class TestPositionalsNargsNoneOneOrMore(ParserTestCase):
+    """Test a Positional with no nargs followed by one with one or more"""
+
+    argument_signatures = [Sig('foo'), Sig('bar', nargs='+')]
+    failures = ['', '--foo', 'a']
+    successes = [
+        ('a b', NS(foo='a', bar=['b'])),
+        ('a b c', NS(foo='a', bar=['b', 'c'])),
+    ]
+
+
+class TestPositionalsNargsNoneOptional(ParserTestCase):
+    """Test a Positional with no nargs followed by one with an Optional"""
+
+    argument_signatures = [Sig('foo'), Sig('bar', nargs='?')]
+    failures = ['', '--foo', 'a b c']
+    successes = [
+        ('a', NS(foo='a', bar=None)),
+        ('a b', NS(foo='a', bar='b')),
+    ]
+
+
+class TestPositionalsNargsZeroOrMoreNone(ParserTestCase):
+    """Test a Positional with unlimited nargs followed by one with none"""
+
+    argument_signatures = [Sig('foo', nargs='*'), Sig('bar')]
+    failures = ['', '--foo']
+    successes = [
+        ('a', NS(foo=[], bar='a')),
+        ('a b', NS(foo=['a'], bar='b')),
+        ('a b c', NS(foo=['a', 'b'], bar='c')),
+    ]
+
+
+class TestPositionalsNargsOneOrMoreNone(ParserTestCase):
+    """Test a Positional with one or more nargs followed by one with none"""
+
+    argument_signatures = [Sig('foo', nargs='+'), Sig('bar')]
+    failures = ['', '--foo', 'a']
+    successes = [
+        ('a b', NS(foo=['a'], bar='b')),
+        ('a b c', NS(foo=['a', 'b'], bar='c')),
+    ]
+
+
+class TestPositionalsNargsOptionalNone(ParserTestCase):
+    """Test a Positional with an Optional nargs followed by one with none"""
+
+    argument_signatures = [Sig('foo', nargs='?', default=42), Sig('bar')]
+    failures = ['', '--foo', 'a b c']
+    successes = [
+        ('a', NS(foo=42, bar='a')),
+        ('a b', NS(foo='a', bar='b')),
+    ]
+
+
+class TestPositionalsNargs2ZeroOrMore(ParserTestCase):
+    """Test a Positional with 2 nargs followed by one with unlimited"""
+
+    argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='*')]
+    failures = ['', '--foo', 'a']
+    successes = [
+        ('a b', NS(foo=['a', 'b'], bar=[])),
+        ('a b c', NS(foo=['a', 'b'], bar=['c'])),
+    ]
+
+
+class TestPositionalsNargs2OneOrMore(ParserTestCase):
+    """Test a Positional with 2 nargs followed by one with one or more"""
+
+    argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='+')]
+    failures = ['', '--foo', 'a', 'a b']
+    successes = [
+        ('a b c', NS(foo=['a', 'b'], bar=['c'])),
+    ]
+
+
+class TestPositionalsNargs2Optional(ParserTestCase):
+    """Test a Positional with 2 nargs followed by one optional"""
+
+    argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='?')]
+    failures = ['', '--foo', 'a', 'a b c d']
+    successes = [
+        ('a b', NS(foo=['a', 'b'], bar=None)),
+        ('a b c', NS(foo=['a', 'b'], bar='c')),
+    ]
+
+
+class TestPositionalsNargsZeroOrMore1(ParserTestCase):
+    """Test a Positional with unlimited nargs followed by one with 1"""
+
+    argument_signatures = [Sig('foo', nargs='*'), Sig('bar', nargs=1)]
+    failures = ['', '--foo', ]
+    successes = [
+        ('a', NS(foo=[], bar=['a'])),
+        ('a b', NS(foo=['a'], bar=['b'])),
+        ('a b c', NS(foo=['a', 'b'], bar=['c'])),
+    ]
+
+
+class TestPositionalsNargsOneOrMore1(ParserTestCase):
+    """Test a Positional with one or more nargs followed by one with 1"""
+
+    argument_signatures = [Sig('foo', nargs='+'), Sig('bar', nargs=1)]
+    failures = ['', '--foo', 'a']
+    successes = [
+        ('a b', NS(foo=['a'], bar=['b'])),
+        ('a b c', NS(foo=['a', 'b'], bar=['c'])),
+    ]
+
+
+class TestPositionalsNargsOptional1(ParserTestCase):
+    """Test a Positional with an Optional nargs followed by one with 1"""
+
+    argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs=1)]
+    failures = ['', '--foo', 'a b c']
+    successes = [
+        ('a', NS(foo=None, bar=['a'])),
+        ('a b', NS(foo='a', bar=['b'])),
+    ]
+
+
+class TestPositionalsNargsNoneZeroOrMore1(ParserTestCase):
+    """Test three Positionals: no nargs, unlimited nargs and 1 nargs"""
+
+    argument_signatures = [
+        Sig('foo'),
+        Sig('bar', nargs='*'),
+        Sig('baz', nargs=1),
+    ]
+    failures = ['', '--foo', 'a']
+    successes = [
+        ('a b', NS(foo='a', bar=[], baz=['b'])),
+        ('a b c', NS(foo='a', bar=['b'], baz=['c'])),
+    ]
+
+
+class TestPositionalsNargsNoneOneOrMore1(ParserTestCase):
+    """Test three Positionals: no nargs, one or more nargs and 1 nargs"""
+
+    argument_signatures = [
+        Sig('foo'),
+        Sig('bar', nargs='+'),
+        Sig('baz', nargs=1),
+    ]
+    failures = ['', '--foo', 'a', 'b']
+    successes = [
+        ('a b c', NS(foo='a', bar=['b'], baz=['c'])),
+        ('a b c d', NS(foo='a', bar=['b', 'c'], baz=['d'])),
+    ]
+
+
+class TestPositionalsNargsNoneOptional1(ParserTestCase):
+    """Test three Positionals: no nargs, optional narg and 1 nargs"""
+
+    argument_signatures = [
+        Sig('foo'),
+        Sig('bar', nargs='?', default=0.625),
+        Sig('baz', nargs=1),
+    ]
+    failures = ['', '--foo', 'a']
+    successes = [
+        ('a b', NS(foo='a', bar=0.625, baz=['b'])),
+        ('a b c', NS(foo='a', bar='b', baz=['c'])),
+    ]
+
+
+class TestPositionalsNargsOptionalOptional(ParserTestCase):
+    """Test two optional nargs"""
+
+    argument_signatures = [
+        Sig('foo', nargs='?'),
+        Sig('bar', nargs='?', default=42),
+    ]
+    failures = ['--foo', 'a b c']
+    successes = [
+        ('', NS(foo=None, bar=42)),
+        ('a', NS(foo='a', bar=42)),
+        ('a b', NS(foo='a', bar='b')),
+    ]
+
+
+class TestPositionalsNargsOptionalZeroOrMore(ParserTestCase):
+    """Test an Optional narg followed by unlimited nargs"""
+
+    argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs='*')]
+    failures = ['--foo']
+    successes = [
+        ('', NS(foo=None, bar=[])),
+        ('a', NS(foo='a', bar=[])),
+        ('a b', NS(foo='a', bar=['b'])),
+        ('a b c', NS(foo='a', bar=['b', 'c'])),
+    ]
+
+
+class TestPositionalsNargsOptionalOneOrMore(ParserTestCase):
+    """Test an Optional narg followed by one or more nargs"""
+
+    argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs='+')]
+    failures = ['', '--foo']
+    successes = [
+        ('a', NS(foo=None, bar=['a'])),
+        ('a b', NS(foo='a', bar=['b'])),
+        ('a b c', NS(foo='a', bar=['b', 'c'])),
+    ]
+
+
+class TestPositionalsChoicesString(ParserTestCase):
+    """Test a set of single-character choices"""
+
+    argument_signatures = [Sig('spam', choices=set('abcdefg'))]
+    failures = ['', '--foo', 'h', '42', 'ef']
+    successes = [
+        ('a', NS(spam='a')),
+        ('g', NS(spam='g')),
+    ]
+
+
+class TestPositionalsChoicesInt(ParserTestCase):
+    """Test a set of integer choices"""
+
+    argument_signatures = [Sig('spam', type=int, choices=range(20))]
+    failures = ['', '--foo', 'h', '42', 'ef']
+    successes = [
+        ('4', NS(spam=4)),
+        ('15', NS(spam=15)),
+    ]
+
+
+class TestPositionalsActionAppend(ParserTestCase):
+    """Test the 'append' action"""
+
+    argument_signatures = [
+        Sig('spam', action='append'),
+        Sig('spam', action='append', nargs=2),
+    ]
+    failures = ['', '--foo', 'a', 'a b', 'a b c d']
+    successes = [
+        ('a b c', NS(spam=['a', ['b', 'c']])),
+    ]
+
+# ========================================
+# Combined optionals and positionals tests
+# ========================================
+
+class TestOptionalsNumericAndPositionals(ParserTestCase):
+    """Tests negative number args when numeric options are present"""
+
+    argument_signatures = [
+        Sig('x', nargs='?'),
+        Sig('-4', dest='y', action='store_true'),
+    ]
+    failures = ['-2', '-315']
+    successes = [
+        ('', NS(x=None, y=False)),
+        ('a', NS(x='a', y=False)),
+        ('-4', NS(x=None, y=True)),
+        ('-4 a', NS(x='a', y=True)),
+    ]
+
+
+class TestOptionalsAlmostNumericAndPositionals(ParserTestCase):
+    """Tests negative number args when almost numeric options are present"""
+
+    argument_signatures = [
+        Sig('x', nargs='?'),
+        Sig('-k4', dest='y', action='store_true'),
+    ]
+    failures = ['-k3']
+    successes = [
+        ('', NS(x=None, y=False)),
+        ('-2', NS(x='-2', y=False)),
+        ('a', NS(x='a', y=False)),
+        ('-k4', NS(x=None, y=True)),
+        ('-k4 a', NS(x='a', y=True)),
+    ]
+
+
+class TestEmptyAndSpaceContainingArguments(ParserTestCase):
+
+    argument_signatures = [
+        Sig('x', nargs='?'),
+        Sig('-y', '--yyy', dest='y'),
+    ]
+    failures = ['-y']
+    successes = [
+        ([''], NS(x='', y=None)),
+        (['a badger'], NS(x='a badger', y=None)),
+        (['-a badger'], NS(x='-a badger', y=None)),
+        (['-y', ''], NS(x=None, y='')),
+        (['-y', 'a badger'], NS(x=None, y='a badger')),
+        (['-y', '-a badger'], NS(x=None, y='-a badger')),
+        (['--yyy=a badger'], NS(x=None, y='a badger')),
+        (['--yyy=-a badger'], NS(x=None, y='-a badger')),
+    ]
+
+
+class TestPrefixCharacterOnlyArguments(ParserTestCase):
+
+    parser_signature = Sig(prefix_chars='-+')
+    argument_signatures = [
+        Sig('-', dest='x', nargs='?', const='badger'),
+        Sig('+', dest='y', type=int, default=42),
+        Sig('-+-', dest='z', action='store_true'),
+    ]
+    failures = ['-y', '+ -']
+    successes = [
+        ('', NS(x=None, y=42, z=False)),
+        ('-', NS(x='badger', y=42, z=False)),
+        ('- X', NS(x='X', y=42, z=False)),
+        ('+ -3', NS(x=None, y=-3, z=False)),
+        ('-+-', NS(x=None, y=42, z=True)),
+        ('- ===', NS(x='===', y=42, z=False)),
+    ]
+
+
+class TestNargsZeroOrMore(ParserTestCase):
+    """Tests specifying an args for an Optional that accepts zero or more"""
+
+    argument_signatures = [Sig('-x', nargs='*'), Sig('y', nargs='*')]
+    failures = []
+    successes = [
+        ('', NS(x=None, y=[])),
+        ('-x', NS(x=[], y=[])),
+        ('-x a', NS(x=['a'], y=[])),
+        ('-x a -- b', NS(x=['a'], y=['b'])),
+        ('a', NS(x=None, y=['a'])),
+        ('a -x', NS(x=[], y=['a'])),
+        ('a -x b', NS(x=['b'], y=['a'])),
+    ]
+
+
+class TestNargsRemainder(ParserTestCase):
+    """Tests specifying a positional with nargs=REMAINDER"""
+
+    argument_signatures = [Sig('x'), Sig('y', nargs='...'), Sig('-z')]
+    failures = ['', '-z', '-z Z']
+    successes = [
+        ('X', NS(x='X', y=[], z=None)),
+        ('-z Z X', NS(x='X', y=[], z='Z')),
+        ('X A B -z Z', NS(x='X', y=['A', 'B', '-z', 'Z'], z=None)),
+        ('X Y --foo', NS(x='X', y=['Y', '--foo'], z=None)),
+    ]
+
+
+class TestOptionLike(ParserTestCase):
+    """Tests options that may or may not be arguments"""
+
+    argument_signatures = [
+        Sig('-x', type=float),
+        Sig('-3', type=float, dest='y'),
+        Sig('z', nargs='*'),
+    ]
+    failures = ['-x', '-y2.5', '-xa', '-x -a',
+                '-x -3', '-x -3.5', '-3 -3.5',
+                '-x -2.5', '-x -2.5 a', '-3 -.5',
+                'a x -1', '-x -1 a', '-3 -1 a']
+    successes = [
+        ('', NS(x=None, y=None, z=[])),
+        ('-x 2.5', NS(x=2.5, y=None, z=[])),
+        ('-x 2.5 a', NS(x=2.5, y=None, z=['a'])),
+        ('-3.5', NS(x=None, y=0.5, z=[])),
+        ('-3-.5', NS(x=None, y=-0.5, z=[])),
+        ('-3 .5', NS(x=None, y=0.5, z=[])),
+        ('a -3.5', NS(x=None, y=0.5, z=['a'])),
+        ('a', NS(x=None, y=None, z=['a'])),
+        ('a -x 1', NS(x=1.0, y=None, z=['a'])),
+        ('-x 1 a', NS(x=1.0, y=None, z=['a'])),
+        ('-3 1 a', NS(x=None, y=1.0, z=['a'])),
+    ]
+
+
+class TestDefaultSuppress(ParserTestCase):
+    """Test actions with suppressed defaults"""
+
+    argument_signatures = [
+        Sig('foo', nargs='?', default=argparse.SUPPRESS),
+        Sig('bar', nargs='*', default=argparse.SUPPRESS),
+        Sig('--baz', action='store_true', default=argparse.SUPPRESS),
+    ]
+    failures = ['-x']
+    successes = [
+        ('', NS()),
+        ('a', NS(foo='a')),
+        ('a b', NS(foo='a', bar=['b'])),
+        ('--baz', NS(baz=True)),
+        ('a --baz', NS(foo='a', baz=True)),
+        ('--baz a b', NS(foo='a', bar=['b'], baz=True)),
+    ]
+
+
+class TestParserDefaultSuppress(ParserTestCase):
+    """Test actions with a parser-level default of SUPPRESS"""
+
+    parser_signature = Sig(argument_default=argparse.SUPPRESS)
+    argument_signatures = [
+        Sig('foo', nargs='?'),
+        Sig('bar', nargs='*'),
+        Sig('--baz', action='store_true'),
+    ]
+    failures = ['-x']
+    successes = [
+        ('', NS()),
+        ('a', NS(foo='a')),
+        ('a b', NS(foo='a', bar=['b'])),
+        ('--baz', NS(baz=True)),
+        ('a --baz', NS(foo='a', baz=True)),
+        ('--baz a b', NS(foo='a', bar=['b'], baz=True)),
+    ]
+
+
+class TestParserDefault42(ParserTestCase):
+    """Test actions with a parser-level default of 42"""
+
+    parser_signature = Sig(argument_default=42, version='1.0')
+    argument_signatures = [
+        Sig('foo', nargs='?'),
+        Sig('bar', nargs='*'),
+        Sig('--baz', action='store_true'),
+    ]
+    failures = ['-x']
+    successes = [
+        ('', NS(foo=42, bar=42, baz=42)),
+        ('a', NS(foo='a', bar=42, baz=42)),
+        ('a b', NS(foo='a', bar=['b'], baz=42)),
+        ('--baz', NS(foo=42, bar=42, baz=True)),
+        ('a --baz', NS(foo='a', bar=42, baz=True)),
+        ('--baz a b', NS(foo='a', bar=['b'], baz=True)),
+    ]
+
+
+class TestArgumentsFromFile(TempDirMixin, ParserTestCase):
+    """Test reading arguments from a file"""
+
+    def setUp(self):
+        super(TestArgumentsFromFile, self).setUp()
+        file_texts = [
+            ('hello', 'hello world!\n'),
+            ('recursive', '-a\n'
+                          'A\n'
+                          '@hello'),
+            ('invalid', '@no-such-path\n'),
+        ]
+        for path, text in file_texts:
+            file = open(path, 'w')
+            file.write(text)
+            file.close()
+
+    parser_signature = Sig(fromfile_prefix_chars='@')
+    argument_signatures = [
+        Sig('-a'),
+        Sig('x'),
+        Sig('y', nargs='+'),
+    ]
+    failures = ['', '-b', 'X', '@invalid', '@missing']
+    successes = [
+        ('X Y', NS(a=None, x='X', y=['Y'])),
+        ('X -a A Y Z', NS(a='A', x='X', y=['Y', 'Z'])),
+        ('@hello X', NS(a=None, x='hello world!', y=['X'])),
+        ('X @hello', NS(a=None, x='X', y=['hello world!'])),
+        ('-a B @recursive Y Z', NS(a='A', x='hello world!', y=['Y', 'Z'])),
+        ('X @recursive Z -a B', NS(a='B', x='X', y=['hello world!', 'Z'])),
+    ]
+
+
+class TestArgumentsFromFileConverter(TempDirMixin, ParserTestCase):
+    """Test reading arguments from a file"""
+
+    def setUp(self):
+        super(TestArgumentsFromFileConverter, self).setUp()
+        file_texts = [
+            ('hello', 'hello world!\n'),
+        ]
+        for path, text in file_texts:
+            file = open(path, 'w')
+            file.write(text)
+            file.close()
+
+    class FromFileConverterArgumentParser(ErrorRaisingArgumentParser):
+
+        def convert_arg_line_to_args(self, arg_line):
+            for arg in arg_line.split():
+                if not arg.strip():
+                    continue
+                yield arg
+    parser_class = FromFileConverterArgumentParser
+    parser_signature = Sig(fromfile_prefix_chars='@')
+    argument_signatures = [
+        Sig('y', nargs='+'),
+    ]
+    failures = []
+    successes = [
+        ('@hello X', NS(y=['hello', 'world!', 'X'])),
+    ]
+
+
+# =====================
+# Type conversion tests
+# =====================
+
+class TestFileTypeRepr(TestCase):
+
+    def test_r(self):
+        type = argparse.FileType('r')
+        self.assertEqual("FileType('r')", repr(type))
+
+    def test_wb_1(self):
+        type = argparse.FileType('wb', 1)
+        self.assertEqual("FileType('wb', 1)", repr(type))
+
+
+class RFile(object):
+    seen = {}
+
+    def __init__(self, name):
+        self.name = name
+
+    __hash__ = None
+
+    def __eq__(self, other):
+        if other in self.seen:
+            text = self.seen[other]
+        else:
+            text = self.seen[other] = other.read()
+            other.close()
+        if not isinstance(text, str):
+            text = text.decode('ascii')
+        return self.name == other.name == text
+
+
+class TestFileTypeR(TempDirMixin, ParserTestCase):
+    """Test the FileType option/argument type for reading files"""
+
+    def setUp(self):
+        super(TestFileTypeR, self).setUp()
+        for file_name in ['foo', 'bar']:
+            file = open(os.path.join(self.temp_dir, file_name), 'w')
+            file.write(file_name)
+            file.close()
+
+    argument_signatures = [
+        Sig('-x', type=argparse.FileType()),
+        Sig('spam', type=argparse.FileType('r')),
+    ]
+    failures = ['-x', '-x bar']
+    successes = [
+        ('foo', NS(x=None, spam=RFile('foo'))),
+        ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
+        ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
+        ('-x - -', NS(x=sys.stdin, spam=sys.stdin)),
+    ]
+
+
+class TestFileTypeRB(TempDirMixin, ParserTestCase):
+    """Test the FileType option/argument type for reading files"""
+
+    def setUp(self):
+        super(TestFileTypeRB, self).setUp()
+        for file_name in ['foo', 'bar']:
+            file = open(os.path.join(self.temp_dir, file_name), 'w')
+            file.write(file_name)
+            file.close()
+
+    argument_signatures = [
+        Sig('-x', type=argparse.FileType('rb')),
+        Sig('spam', type=argparse.FileType('rb')),
+    ]
+    failures = ['-x', '-x bar']
+    successes = [
+        ('foo', NS(x=None, spam=RFile('foo'))),
+        ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
+        ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
+        ('-x - -', NS(x=sys.stdin, spam=sys.stdin)),
+    ]
+
+
+class WFile(object):
+    seen = set()
+
+    def __init__(self, name):
+        self.name = name
+
+    __hash__ = None
+
+    def __eq__(self, other):
+        if other not in self.seen:
+            text = 'Check that file is writable.'
+            if 'b' in other.mode:
+                text = text.encode('ascii')
+            other.write(text)
+            other.close()
+            self.seen.add(other)
+        return self.name == other.name
+
+
+class TestFileTypeW(TempDirMixin, ParserTestCase):
+    """Test the FileType option/argument type for writing files"""
+
+    argument_signatures = [
+        Sig('-x', type=argparse.FileType('w')),
+        Sig('spam', type=argparse.FileType('w')),
+    ]
+    failures = ['-x', '-x bar']
+    successes = [
+        ('foo', NS(x=None, spam=WFile('foo'))),
+        ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
+        ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
+        ('-x - -', NS(x=sys.stdout, spam=sys.stdout)),
+    ]
+
+
+class TestFileTypeWB(TempDirMixin, ParserTestCase):
+
+    argument_signatures = [
+        Sig('-x', type=argparse.FileType('wb')),
+        Sig('spam', type=argparse.FileType('wb')),
+    ]
+    failures = ['-x', '-x bar']
+    successes = [
+        ('foo', NS(x=None, spam=WFile('foo'))),
+        ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
+        ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
+        ('-x - -', NS(x=sys.stdout, spam=sys.stdout)),
+    ]
+
+
+class TestTypeCallable(ParserTestCase):
+    """Test some callables as option/argument types"""
+
+    argument_signatures = [
+        Sig('--eggs', type=complex),
+        Sig('spam', type=float),
+    ]
+    failures = ['a', '42j', '--eggs a', '--eggs 2i']
+    successes = [
+        ('--eggs=42 42', NS(eggs=42, spam=42.0)),
+        ('--eggs 2j -- -1.5', NS(eggs=2j, spam=-1.5)),
+        ('1024.675', NS(eggs=None, spam=1024.675)),
+    ]
+
+
+class TestTypeUserDefined(ParserTestCase):
+    """Test a user-defined option/argument type"""
+
+    class MyType(TestCase):
+
+        def __init__(self, value):
+            self.value = value
+
+        __hash__ = None
+
+        def __eq__(self, other):
+            return (type(self), self.value) == (type(other), other.value)
+
+    argument_signatures = [
+        Sig('-x', type=MyType),
+        Sig('spam', type=MyType),
+    ]
+    failures = []
+    successes = [
+        ('a -x b', NS(x=MyType('b'), spam=MyType('a'))),
+        ('-xf g', NS(x=MyType('f'), spam=MyType('g'))),
+    ]
+
+
+class TestTypeClassicClass(ParserTestCase):
+    """Test a classic class type"""
+
+    class C:
+
+        def __init__(self, value):
+            self.value = value
+
+        __hash__ = None
+
+        def __eq__(self, other):
+            return (type(self), self.value) == (type(other), other.value)
+
+    argument_signatures = [
+        Sig('-x', type=C),
+        Sig('spam', type=C),
+    ]
+    failures = []
+    successes = [
+        ('a -x b', NS(x=C('b'), spam=C('a'))),
+        ('-xf g', NS(x=C('f'), spam=C('g'))),
+    ]
+
+
+class TestTypeRegistration(TestCase):
+    """Test a user-defined type by registering it"""
+
+    def test(self):
+
+        def get_my_type(string):
+            return 'my_type{%s}' % string
+
+        parser = argparse.ArgumentParser()
+        parser.register('type', 'my_type', get_my_type)
+        parser.add_argument('-x', type='my_type')
+        parser.add_argument('y', type='my_type')
+
+        self.assertEqual(parser.parse_args('1'.split()),
+                         NS(x=None, y='my_type{1}'))
+        self.assertEqual(parser.parse_args('-x 1 42'.split()),
+                         NS(x='my_type{1}', y='my_type{42}'))
+
+
+# ============
+# Action tests
+# ============
+
+class TestActionUserDefined(ParserTestCase):
+    """Test a user-defined option/argument action"""
+
+    class OptionalAction(argparse.Action):
+
+        def __call__(self, parser, namespace, value, option_string=None):
+            try:
+                # check destination and option string
+                assert self.dest == 'spam', 'dest: %s' % self.dest
+                assert option_string == '-s', 'flag: %s' % option_string
+                # when option is before argument, badger=2, and when
+                # option is after argument, badger=<whatever was set>
+                expected_ns = NS(spam=0.25)
+                if value in [0.125, 0.625]:
+                    expected_ns.badger = 2
+                elif value in [2.0]:
+                    expected_ns.badger = 84
+                else:
+                    raise AssertionError('value: %s' % value)
+                assert expected_ns == namespace, ('expected %s, got %s' %
+                                                  (expected_ns, namespace))
+            except AssertionError:
+                e = sys.exc_info()[1]
+                raise ArgumentParserError('opt_action failed: %s' % e)
+            setattr(namespace, 'spam', value)
+
+    class PositionalAction(argparse.Action):
+
+        def __call__(self, parser, namespace, value, option_string=None):
+            try:
+                assert option_string is None, ('option_string: %s' %
+                                               option_string)
+                # check destination
+                assert self.dest == 'badger', 'dest: %s' % self.dest
+                # when argument is before option, spam=0.25, and when
+                # option is after argument, spam=<whatever was set>
+                expected_ns = NS(badger=2)
+                if value in [42, 84]:
+                    expected_ns.spam = 0.25
+                elif value in [1]:
+                    expected_ns.spam = 0.625
+                elif value in [2]:
+                    expected_ns.spam = 0.125
+                else:
+                    raise AssertionError('value: %s' % value)
+                assert expected_ns == namespace, ('expected %s, got %s' %
+                                                  (expected_ns, namespace))
+            except AssertionError:
+                e = sys.exc_info()[1]
+                raise ArgumentParserError('arg_action failed: %s' % e)
+            setattr(namespace, 'badger', value)
+
+    argument_signatures = [
+        Sig('-s', dest='spam', action=OptionalAction,
+            type=float, default=0.25),
+        Sig('badger', action=PositionalAction,
+            type=int, nargs='?', default=2),
+    ]
+    failures = []
+    successes = [
+        ('-s0.125', NS(spam=0.125, badger=2)),
+        ('42', NS(spam=0.25, badger=42)),
+        ('-s 0.625 1', NS(spam=0.625, badger=1)),
+        ('84 -s2', NS(spam=2.0, badger=84)),
+    ]
+
+
+class TestActionRegistration(TestCase):
+    """Test a user-defined action supplied by registering it"""
+
+    class MyAction(argparse.Action):
+
+        def __call__(self, parser, namespace, values, option_string=None):
+            setattr(namespace, self.dest, 'foo[%s]' % values)
+
+    def test(self):
+
+        parser = argparse.ArgumentParser()
+        parser.register('action', 'my_action', self.MyAction)
+        parser.add_argument('badger', action='my_action')
+
+        self.assertEqual(parser.parse_args(['1']), NS(badger='foo[1]'))
+        self.assertEqual(parser.parse_args(['42']), NS(badger='foo[42]'))
+
+
+# ================
+# Subparsers tests
+# ================
+
+class TestAddSubparsers(TestCase):
+    """Test the add_subparsers method"""
+
+    def assertArgumentParserError(self, *args, **kwargs):
+        self.assertRaises(ArgumentParserError, *args, **kwargs)
+
+    def _get_parser(self, subparser_help=False, prefix_chars=None):
+        # create a parser with a subparsers argument
+        if prefix_chars:
+            parser = ErrorRaisingArgumentParser(
+                prog='PROG', description='main description', prefix_chars=prefix_chars)
+            parser.add_argument(
+                prefix_chars[0] * 2 + 'foo', action='store_true', help='foo help')
+        else:
+            parser = ErrorRaisingArgumentParser(
+                prog='PROG', description='main description')
+            parser.add_argument(
+                '--foo', action='store_true', help='foo help')
+        parser.add_argument(
+            'bar', type=float, help='bar help')
+
+        # check that only one subparsers argument can be added
+        subparsers = parser.add_subparsers(help='command help')
+        self.assertArgumentParserError(parser.add_subparsers)
+
+        # add first sub-parser
+        parser1_kwargs = dict(description='1 description')
+        if subparser_help:
+            parser1_kwargs['help'] = '1 help'
+        parser1 = subparsers.add_parser('1', **parser1_kwargs)
+        parser1.add_argument('-w', type=int, help='w help')
+        parser1.add_argument('x', choices='abc', help='x help')
+
+        # add second sub-parser
+        parser2_kwargs = dict(description='2 description')
+        if subparser_help:
+            parser2_kwargs['help'] = '2 help'
+        parser2 = subparsers.add_parser('2', **parser2_kwargs)
+        parser2.add_argument('-y', choices='123', help='y help')
+        parser2.add_argument('z', type=complex, nargs='*', help='z help')
+
+        # return the main parser
+        return parser
+
+    def setUp(self):
+        super(TestAddSubparsers, self).setUp()
+        self.parser = self._get_parser()
+        self.command_help_parser = self._get_parser(subparser_help=True)
+
+    def test_parse_args_failures(self):
+        # check some failure cases:
+        for args_str in ['', 'a', 'a a', '0.5 a', '0.5 1',
+                         '0.5 1 -y', '0.5 2 -w']:
+            args = args_str.split()
+            self.assertArgumentParserError(self.parser.parse_args, args)
+
+    def test_parse_args(self):
+        # check some non-failure cases:
+        self.assertEqual(
+            self.parser.parse_args('0.5 1 b -w 7'.split()),
+            NS(foo=False, bar=0.5, w=7, x='b'),
+        )
+        self.assertEqual(
+            self.parser.parse_args('0.25 --foo 2 -y 2 3j -- -1j'.split()),
+            NS(foo=True, bar=0.25, y='2', z=[3j, -1j]),
+        )
+        self.assertEqual(
+            self.parser.parse_args('--foo 0.125 1 c'.split()),
+            NS(foo=True, bar=0.125, w=None, x='c'),
+        )
+
+    def test_parse_known_args(self):
+        self.assertEqual(
+            self.parser.parse_known_args('0.5 1 b -w 7'.split()),
+            (NS(foo=False, bar=0.5, w=7, x='b'), []),
+        )
+        self.assertEqual(
+            self.parser.parse_known_args('0.5 -p 1 b -w 7'.split()),
+            (NS(foo=False, bar=0.5, w=7, x='b'), ['-p']),
+        )
+        self.assertEqual(
+            self.parser.parse_known_args('0.5 1 b -w 7 -p'.split()),
+            (NS(foo=False, bar=0.5, w=7, x='b'), ['-p']),
+        )
+        self.assertEqual(
+            self.parser.parse_known_args('0.5 1 b -q -rs -w 7'.split()),
+            (NS(foo=False, bar=0.5, w=7, x='b'), ['-q', '-rs']),
+        )
+        self.assertEqual(
+            self.parser.parse_known_args('0.5 -W 1 b -X Y -w 7 Z'.split()),
+            (NS(foo=False, bar=0.5, w=7, x='b'), ['-W', '-X', 'Y', 'Z']),
+        )
+
+    def test_dest(self):
+        parser = ErrorRaisingArgumentParser()
+        parser.add_argument('--foo', action='store_true')
+        subparsers = parser.add_subparsers(dest='bar')
+        parser1 = subparsers.add_parser('1')
+        parser1.add_argument('baz')
+        self.assertEqual(NS(foo=False, bar='1', baz='2'),
+                         parser.parse_args('1 2'.split()))
+
+    def test_help(self):
+        self.assertEqual(self.parser.format_usage(),
+                         'usage: PROG [-h] [--foo] bar {1,2} ...\n')
+        self.assertEqual(self.parser.format_help(), textwrap.dedent('''\
+            usage: PROG [-h] [--foo] bar {1,2} ...
+
+            main description
+
+            positional arguments:
+              bar         bar help
+              {1,2}       command help
+
+            optional arguments:
+              -h, --help  show this help message and exit
+              --foo       foo help
+            '''))
+
+    def test_help_extra_prefix_chars(self):
+        # Make sure - is still used for help if it is a non-first prefix char
+        parser = self._get_parser(prefix_chars='+:-')
+        self.assertEqual(parser.format_usage(),
+                         'usage: PROG [-h] [++foo] bar {1,2} ...\n')
+        self.assertEqual(parser.format_help(), textwrap.dedent('''\
+            usage: PROG [-h] [++foo] bar {1,2} ...
+
+            main description
+
+            positional arguments:
+              bar         bar help
+              {1,2}       command help
+
+            optional arguments:
+              -h, --help  show this help message and exit
+              ++foo       foo help
+            '''))
+
+
+    def test_help_alternate_prefix_chars(self):
+        parser = self._get_parser(prefix_chars='+:/')
+        self.assertEqual(parser.format_usage(),
+                         'usage: PROG [+h] [++foo] bar {1,2} ...\n')
+        self.assertEqual(parser.format_help(), textwrap.dedent('''\
+            usage: PROG [+h] [++foo] bar {1,2} ...
+
+            main description
+
+            positional arguments:
+              bar         bar help
+              {1,2}       command help
+
+            optional arguments:
+              +h, ++help  show this help message and exit
+              ++foo       foo help
+            '''))
+
+    def test_parser_command_help(self):
+        self.assertEqual(self.command_help_parser.format_usage(),
+                         'usage: PROG [-h] [--foo] bar {1,2} ...\n')
+        self.assertEqual(self.command_help_parser.format_help(),
+                         textwrap.dedent('''\
+            usage: PROG [-h] [--foo] bar {1,2} ...
+
+            main description
+
+            positional arguments:
+              bar         bar help
+              {1,2}       command help
+                1         1 help
+                2         2 help
+
+            optional arguments:
+              -h, --help  show this help message and exit
+              --foo       foo help
+            '''))
+
+    def test_subparser_title_help(self):
+        parser = ErrorRaisingArgumentParser(prog='PROG',
+                                            description='main description')
+        parser.add_argument('--foo', action='store_true', help='foo help')
+        parser.add_argument('bar', help='bar help')
+        subparsers = parser.add_subparsers(title='subcommands',
+                                           description='command help',
+                                           help='additional text')
+        parser1 = subparsers.add_parser('1')
+        parser2 = subparsers.add_parser('2')
+        self.assertEqual(parser.format_usage(),
+                         'usage: PROG [-h] [--foo] bar {1,2} ...\n')
+        self.assertEqual(parser.format_help(), textwrap.dedent('''\
+            usage: PROG [-h] [--foo] bar {1,2} ...
+
+            main description
+
+            positional arguments:
+              bar         bar help
+
+            optional arguments:
+              -h, --help  show this help message and exit
+              --foo       foo help
+
+            subcommands:
+              command help
+
+              {1,2}       additional text
+            '''))
+
+    def _test_subparser_help(self, args_str, expected_help):
+        try:
+            self.parser.parse_args(args_str.split())
+        except ArgumentParserError:
+            err = sys.exc_info()[1]
+            if err.stdout != expected_help:
+                print(repr(expected_help))
+                print(repr(err.stdout))
+            self.assertEqual(err.stdout, expected_help)
+
+    def test_subparser1_help(self):
+        self._test_subparser_help('5.0 1 -h', textwrap.dedent('''\
+            usage: PROG bar 1 [-h] [-w W] {a,b,c}
+
+            1 description
+
+            positional arguments:
+              {a,b,c}     x help
+
+            optional arguments:
+              -h, --help  show this help message and exit
+              -w W        w help
+            '''))
+
+    def test_subparser2_help(self):
+        self._test_subparser_help('5.0 2 -h', textwrap.dedent('''\
+            usage: PROG bar 2 [-h] [-y {1,2,3}] [z [z ...]]
+
+            2 description
+
+            positional arguments:
+              z           z help
+
+            optional arguments:
+              -h, --help  show this help message and exit
+              -y {1,2,3}  y help
+            '''))
+
+# ============
+# Groups tests
+# ============
+
+class TestPositionalsGroups(TestCase):
+    """Tests that order of group positionals matches construction order"""
+
+    def test_nongroup_first(self):
+        parser = ErrorRaisingArgumentParser()
+        parser.add_argument('foo')
+        group = parser.add_argument_group('g')
+        group.add_argument('bar')
+        parser.add_argument('baz')
+        expected = NS(foo='1', bar='2', baz='3')
+        result = parser.parse_args('1 2 3'.split())
+        self.assertEqual(expected, result)
+
+    def test_group_first(self):
+        parser = ErrorRaisingArgumentParser()
+        group = parser.add_argument_group('xxx')
+        group.add_argument('foo')
+        parser.add_argument('bar')
+        parser.add_argument('baz')
+        expected = NS(foo='1', bar='2', baz='3')
+        result = parser.parse_args('1 2 3'.split())
+        self.assertEqual(expected, result)
+
+    def test_interleaved_groups(self):
+        parser = ErrorRaisingArgumentParser()
+        group = parser.add_argument_group('xxx')
+        parser.add_argument('foo')
+        group.add_argument('bar')
+        parser.add_argument('baz')
+        group = parser.add_argument_group('yyy')
+        group.add_argument('frell')
+        expected = NS(foo='1', bar='2', baz='3', frell='4')
+        result = parser.parse_args('1 2 3 4'.split())
+        self.assertEqual(expected, result)
+
+# ===================
+# Parent parser tests
+# ===================
+
+class TestParentParsers(TestCase):
+    """Tests that parsers can be created with parent parsers"""
+
+    def assertArgumentParserError(self, *args, **kwargs):
+        self.assertRaises(ArgumentParserError, *args, **kwargs)
+
+    def setUp(self):
+        super(TestParentParsers, self).setUp()
+        self.wxyz_parent = ErrorRaisingArgumentParser(add_help=False)
+        self.wxyz_parent.add_argument('--w')
+        x_group = self.wxyz_parent.add_argument_group('x')
+        x_group.add_argument('-y')
+        self.wxyz_parent.add_argument('z')
+
+        self.abcd_parent = ErrorRaisingArgumentParser(add_help=False)
+        self.abcd_parent.add_argument('a')
+        self.abcd_parent.add_argument('-b')
+        c_group = self.abcd_parent.add_argument_group('c')
+        c_group.add_argument('--d')
+
+        self.w_parent = ErrorRaisingArgumentParser(add_help=False)
+        self.w_parent.add_argument('--w')
+
+        self.z_parent = ErrorRaisingArgumentParser(add_help=False)
+        self.z_parent.add_argument('z')
+
+        # parents with mutually exclusive groups
+        self.ab_mutex_parent = ErrorRaisingArgumentParser(add_help=False)
+        group = self.ab_mutex_parent.add_mutually_exclusive_group()
+        group.add_argument('-a', action='store_true')
+        group.add_argument('-b', action='store_true')
+
+        self.main_program = os.path.basename(sys.argv[0])
+
+    def test_single_parent(self):
+        parser = ErrorRaisingArgumentParser(parents=[self.wxyz_parent])
+        self.assertEqual(parser.parse_args('-y 1 2 --w 3'.split()),
+                         NS(w='3', y='1', z='2'))
+
+    def test_single_parent_mutex(self):
+        self._test_mutex_ab(self.ab_mutex_parent.parse_args)
+        parser = ErrorRaisingArgumentParser(parents=[self.ab_mutex_parent])
+        self._test_mutex_ab(parser.parse_args)
+
+    def test_single_granparent_mutex(self):
+        parents = [self.ab_mutex_parent]
+        parser = ErrorRaisingArgumentParser(add_help=False, parents=parents)
+        parser = ErrorRaisingArgumentParser(parents=[parser])
+        self._test_mutex_ab(parser.parse_args)
+
+    def _test_mutex_ab(self, parse_args):
+        self.assertEqual(parse_args([]), NS(a=False, b=False))
+        self.assertEqual(parse_args(['-a']), NS(a=True, b=False))
+        self.assertEqual(parse_args(['-b']), NS(a=False, b=True))
+        self.assertArgumentParserError(parse_args, ['-a', '-b'])
+        self.assertArgumentParserError(parse_args, ['-b', '-a'])
+        self.assertArgumentParserError(parse_args, ['-c'])
+        self.assertArgumentParserError(parse_args, ['-a', '-c'])
+        self.assertArgumentParserError(parse_args, ['-b', '-c'])
+
+    def test_multiple_parents(self):
+        parents = [self.abcd_parent, self.wxyz_parent]
+        parser = ErrorRaisingArgumentParser(parents=parents)
+        self.assertEqual(parser.parse_args('--d 1 --w 2 3 4'.split()),
+                         NS(a='3', b=None, d='1', w='2', y=None, z='4'))
+
+    def test_multiple_parents_mutex(self):
+        parents = [self.ab_mutex_parent, self.wxyz_parent]
+        parser = ErrorRaisingArgumentParser(parents=parents)
+        self.assertEqual(parser.parse_args('-a --w 2 3'.split()),
+                         NS(a=True, b=False, w='2', y=None, z='3'))
+        self.assertArgumentParserError(
+            parser.parse_args, '-a --w 2 3 -b'.split())
+        self.assertArgumentParserError(
+            parser.parse_args, '-a -b --w 2 3'.split())
+
+    def test_conflicting_parents(self):
+        self.assertRaises(
+            argparse.ArgumentError,
+            argparse.ArgumentParser,
+            parents=[self.w_parent, self.wxyz_parent])
+
+    def test_conflicting_parents_mutex(self):
+        self.assertRaises(
+            argparse.ArgumentError,
+            argparse.ArgumentParser,
+            parents=[self.abcd_parent, self.ab_mutex_parent])
+
+    def test_same_argument_name_parents(self):
+        parents = [self.wxyz_parent, self.z_parent]
+        parser = ErrorRaisingArgumentParser(parents=parents)
+        self.assertEqual(parser.parse_args('1 2'.split()),
+                         NS(w=None, y=None, z='2'))
+
+    def test_subparser_parents(self):
+        parser = ErrorRaisingArgumentParser()
+        subparsers = parser.add_subparsers()
+        abcde_parser = subparsers.add_parser('bar', parents=[self.abcd_parent])
+        abcde_parser.add_argument('e')
+        self.assertEqual(parser.parse_args('bar -b 1 --d 2 3 4'.split()),
+                         NS(a='3', b='1', d='2', e='4'))
+
+    def test_subparser_parents_mutex(self):
+        parser = ErrorRaisingArgumentParser()
+        subparsers = parser.add_subparsers()
+        parents = [self.ab_mutex_parent]
+        abc_parser = subparsers.add_parser('foo', parents=parents)
+        c_group = abc_parser.add_argument_group('c_group')
+        c_group.add_argument('c')
+        parents = [self.wxyz_parent, self.ab_mutex_parent]
+        wxyzabe_parser = subparsers.add_parser('bar', parents=parents)
+        wxyzabe_parser.add_argument('e')
+        self.assertEqual(parser.parse_args('foo -a 4'.split()),
+                         NS(a=True, b=False, c='4'))
+        self.assertEqual(parser.parse_args('bar -b  --w 2 3 4'.split()),
+                         NS(a=False, b=True, w='2', y=None, z='3', e='4'))
+        self.assertArgumentParserError(
+            parser.parse_args, 'foo -a -b 4'.split())
+        self.assertArgumentParserError(
+            parser.parse_args, 'bar -b -a 4'.split())
+
+    def test_parent_help(self):
+        parents = [self.abcd_parent, self.wxyz_parent]
+        parser = ErrorRaisingArgumentParser(parents=parents)
+        parser_help = parser.format_help()
+        self.assertEqual(parser_help, textwrap.dedent('''\
+            usage: %(prog)s [-h] [-b B] [--d D] [--w W] [-y Y] a z
+
+            positional arguments:
+              a
+              z
+
+            optional arguments:
+              -h, --help  show this help message and exit
+              -b B
+              --w W
+
+            c:
+              --d D
+
+            x:
+              -y Y
+        ''' % dict(prog=self.main_program)))
+
+    def test_groups_parents(self):
+        parent = ErrorRaisingArgumentParser(add_help=False)
+        g = parent.add_argument_group(title='g', description='gd')
+        g.add_argument('-w')
+        g.add_argument('-x')
+        m = parent.add_mutually_exclusive_group()
+        m.add_argument('-y')
+        m.add_argument('-z')
+        parser = ErrorRaisingArgumentParser(parents=[parent])
+
+        self.assertRaises(ArgumentParserError, parser.parse_args,
+            ['-y', 'Y', '-z', 'Z'])
+
+        parser_help = parser.format_help()
+        self.assertEqual(parser_help, textwrap.dedent('''\
+            usage: %(prog)s [-h] [-w W] [-x X] [-y Y | -z Z]
+
+            optional arguments:
+              -h, --help  show this help message and exit
+              -y Y
+              -z Z
+
+            g:
+              gd
+
+              -w W
+              -x X
+        ''' % dict(prog=self.main_program)))
+
+# ==============================
+# Mutually exclusive group tests
+# ==============================
+
+class TestMutuallyExclusiveGroupErrors(TestCase):
+
+    def test_invalid_add_argument_group(self):
+        parser = ErrorRaisingArgumentParser()
+        raises = self.assertRaises
+        raises(TypeError, parser.add_mutually_exclusive_group, title='foo')
+
+    def test_invalid_add_argument(self):
+        parser = ErrorRaisingArgumentParser()
+        group = parser.add_mutually_exclusive_group()
+        add_argument = group.add_argument
+        raises = self.assertRaises
+        raises(ValueError, add_argument, '--foo', required=True)
+        raises(ValueError, add_argument, 'bar')
+        raises(ValueError, add_argument, 'bar', nargs='+')
+        raises(ValueError, add_argument, 'bar', nargs=1)
+        raises(ValueError, add_argument, 'bar', nargs=argparse.PARSER)
+
+    def test_help(self):
+        parser = ErrorRaisingArgumentParser(prog='PROG')
+        group1 = parser.add_mutually_exclusive_group()
+        group1.add_argument('--foo', action='store_true')
+        group1.add_argument('--bar', action='store_false')
+        group2 = parser.add_mutually_exclusive_group()
+        group2.add_argument('--soup', action='store_true')
+        group2.add_argument('--nuts', action='store_false')
+        expected = '''\
+            usage: PROG [-h] [--foo | --bar] [--soup | --nuts]
+
+            optional arguments:
+              -h, --help  show this help message and exit
+              --foo
+              --bar
+              --soup
+              --nuts
+              '''
+        # note: .rstrip(' ') fixes different behaviour of py 2.4 textwrap.dedent
+        self.assertEqual(parser.format_help(), textwrap.dedent(expected).rstrip(' '))
+
+class MEMixin(object):
+
+    def test_failures_when_not_required(self):
+        parse_args = self.get_parser(required=False).parse_args
+        error = ArgumentParserError
+        for args_string in self.failures:
+            self.assertRaises(error, parse_args, args_string.split())
+
+    def test_failures_when_required(self):
+        parse_args = self.get_parser(required=True).parse_args
+        error = ArgumentParserError
+        for args_string in self.failures + ['']:
+            self.assertRaises(error, parse_args, args_string.split())
+
+    def test_successes_when_not_required(self):
+        parse_args = self.get_parser(required=False).parse_args
+        successes = self.successes + self.successes_when_not_required
+        for args_string, expected_ns in successes:
+            actual_ns = parse_args(args_string.split())
+            self.assertEqual(actual_ns, expected_ns)
+
+    def test_successes_when_required(self):
+        parse_args = self.get_parser(required=True).parse_args
+        for args_string, expected_ns in self.successes:
+            actual_ns = parse_args(args_string.split())
+            self.assertEqual(actual_ns, expected_ns)
+
+    def test_usage_when_not_required(self):
+        format_usage = self.get_parser(required=False).format_usage
+        expected_usage = self.usage_when_not_required
+        self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
+
+    def test_usage_when_required(self):
+        format_usage = self.get_parser(required=True).format_usage
+        expected_usage = self.usage_when_required
+        self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
+
+    def test_help_when_not_required(self):
+        format_help = self.get_parser(required=False).format_help
+        help = self.usage_when_not_required + self.help
+        self.assertEqual(format_help(), textwrap.dedent(help))
+
+    def test_help_when_required(self):
+        format_help = self.get_parser(required=True).format_help
+        help = self.usage_when_required + self.help
+        self.assertEqual(format_help(), textwrap.dedent(help))
+
+
+class TestMutuallyExclusiveSimple(MEMixin, TestCase):
+
+    def get_parser(self, required=None):
+        parser = ErrorRaisingArgumentParser(prog='PROG')
+        group = parser.add_mutually_exclusive_group(required=required)
+        group.add_argument('--bar', help='bar help')
+        group.add_argument('--baz', nargs='?', const='Z', help='baz help')
+        return parser
+
+    failures = ['--bar X --baz Y', '--bar X --baz']
+    successes = [
+        ('--bar X', NS(bar='X', baz=None)),
+        ('--bar X --bar Z', NS(bar='Z', baz=None)),
+        ('--baz Y', NS(bar=None, baz='Y')),
+        ('--baz', NS(bar=None, baz='Z')),
+    ]
+    successes_when_not_required = [
+        ('', NS(bar=None, baz=None)),
+    ]
+
+    usage_when_not_required = '''\
+        usage: PROG [-h] [--bar BAR | --baz [BAZ]]
+        '''
+    usage_when_required = '''\
+        usage: PROG [-h] (--bar BAR | --baz [BAZ])
+        '''
+    help = '''\
+
+        optional arguments:
+          -h, --help   show this help message and exit
+          --bar BAR    bar help
+          --baz [BAZ]  baz help
+        '''
+
+
+class TestMutuallyExclusiveLong(MEMixin, TestCase):
+
+    def get_parser(self, required=None):
+        parser = ErrorRaisingArgumentParser(prog='PROG')
+        parser.add_argument('--abcde', help='abcde help')
+        parser.add_argument('--fghij', help='fghij help')
+        group = parser.add_mutually_exclusive_group(required=required)
+        group.add_argument('--klmno', help='klmno help')
+        group.add_argument('--pqrst', help='pqrst help')
+        return parser
+
+    failures = ['--klmno X --pqrst Y']
+    successes = [
+        ('--klmno X', NS(abcde=None, fghij=None, klmno='X', pqrst=None)),
+        ('--abcde Y --klmno X',
+            NS(abcde='Y', fghij=None, klmno='X', pqrst=None)),
+        ('--pqrst X', NS(abcde=None, fghij=None, klmno=None, pqrst='X')),
+        ('--pqrst X --fghij Y',
+            NS(abcde=None, fghij='Y', klmno=None, pqrst='X')),
+    ]
+    successes_when_not_required = [
+        ('', NS(abcde=None, fghij=None, klmno=None, pqrst=None)),
+    ]
+
+    usage_when_not_required = '''\
+    usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
+                [--klmno KLMNO | --pqrst PQRST]
+    '''
+    usage_when_required = '''\
+    usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
+                (--klmno KLMNO | --pqrst PQRST)
+    '''
+    help = '''\
+
+    optional arguments:
+      -h, --help     show this help message and exit
+      --abcde ABCDE  abcde help
+      --fghij FGHIJ  fghij help
+      --klmno KLMNO  klmno help
+      --pqrst PQRST  pqrst help
+    '''
+
+
+class TestMutuallyExclusiveFirstSuppressed(MEMixin, TestCase):
+
+    def get_parser(self, required):
+        parser = ErrorRaisingArgumentParser(prog='PROG')
+        group = parser.add_mutually_exclusive_group(required=required)
+        group.add_argument('-x', help=argparse.SUPPRESS)
+        group.add_argument('-y', action='store_false', help='y help')
+        return parser
+
+    failures = ['-x X -y']
+    successes = [
+        ('-x X', NS(x='X', y=True)),
+        ('-x X -x Y', NS(x='Y', y=True)),
+        ('-y', NS(x=None, y=False)),
+    ]
+    successes_when_not_required = [
+        ('', NS(x=None, y=True)),
+    ]
+
+    usage_when_not_required = '''\
+        usage: PROG [-h] [-y]
+        '''
+    usage_when_required = '''\
+        usage: PROG [-h] -y
+        '''
+    help = '''\
+
+        optional arguments:
+          -h, --help  show this help message and exit
+          -y          y help
+        '''
+
+
+class TestMutuallyExclusiveManySuppressed(MEMixin, TestCase):
+
+    def get_parser(self, required):
+        parser = ErrorRaisingArgumentParser(prog='PROG')
+        group = parser.add_mutually_exclusive_group(required=required)
+        add = group.add_argument
+        add('--spam', action='store_true', help=argparse.SUPPRESS)
+        add('--badger', action='store_false', help=argparse.SUPPRESS)
+        add('--bladder', help=argparse.SUPPRESS)
+        return parser
+
+    failures = [
+        '--spam --badger',
+        '--badger --bladder B',
+        '--bladder B --spam',
+    ]
+    successes = [
+        ('--spam', NS(spam=True, badger=True, bladder=None)),
+        ('--badger', NS(spam=False, badger=False, bladder=None)),
+        ('--bladder B', NS(spam=False, badger=True, bladder='B')),
+        ('--spam --spam', NS(spam=True, badger=True, bladder=None)),
+    ]
+    successes_when_not_required = [
+        ('', NS(spam=False, badger=True, bladder=None)),
+    ]
+
+    usage_when_required = usage_when_not_required = '''\
+        usage: PROG [-h]
+        '''
+    help = '''\
+
+        optional arguments:
+          -h, --help  show this help message and exit
+        '''
+
+
+class TestMutuallyExclusiveOptionalAndPositional(MEMixin, TestCase):
+
+    def get_parser(self, required):
+        parser = ErrorRaisingArgumentParser(prog='PROG')
+        group = parser.add_mutually_exclusive_group(required=required)
+        group.add_argument('--foo', action='store_true', help='FOO')
+        group.add_argument('--spam', help='SPAM')
+        group.add_argument('badger', nargs='*', default='X', help='BADGER')
+        return parser
+
+    failures = [
+        '--foo --spam S',
+        '--spam S X',
+        'X --foo',
+        'X Y Z --spam S',
+        '--foo X Y',
+    ]
+    successes = [
+        ('--foo', NS(foo=True, spam=None, badger='X')),
+        ('--spam S', NS(foo=False, spam='S', badger='X')),
+        ('X', NS(foo=False, spam=None, badger=['X'])),
+        ('X Y Z', NS(foo=False, spam=None, badger=['X', 'Y', 'Z'])),
+    ]
+    successes_when_not_required = [
+        ('', NS(foo=False, spam=None, badger='X')),
+    ]
+
+    usage_when_not_required = '''\
+        usage: PROG [-h] [--foo | --spam SPAM | badger [badger ...]]
+        '''
+    usage_when_required = '''\
+        usage: PROG [-h] (--foo | --spam SPAM | badger [badger ...])
+        '''
+    help = '''\
+
+        positional arguments:
+          badger       BADGER
+
+        optional arguments:
+          -h, --help   show this help message and exit
+          --foo        FOO
+          --spam SPAM  SPAM
+        '''
+
+
+class TestMutuallyExclusiveOptionalsMixed(MEMixin, TestCase):
+
+    def get_parser(self, required):
+        parser = ErrorRaisingArgumentParser(prog='PROG')
+        parser.add_argument('-x', action='store_true', help='x help')
+        group = parser.add_mutually_exclusive_group(required=required)
+        group.add_argument('-a', action='store_true', help='a help')
+        group.add_argument('-b', action='store_true', help='b help')
+        parser.add_argument('-y', action='store_true', help='y help')
+        group.add_argument('-c', action='store_true', help='c help')
+        return parser
+
+    failures = ['-a -b', '-b -c', '-a -c', '-a -b -c']
+    successes = [
+        ('-a', NS(a=True, b=False, c=False, x=False, y=False)),
+        ('-b', NS(a=False, b=True, c=False, x=False, y=False)),
+        ('-c', NS(a=False, b=False, c=True, x=False, y=False)),
+        ('-a -x', NS(a=True, b=False, c=False, x=True, y=False)),
+        ('-y -b', NS(a=False, b=True, c=False, x=False, y=True)),
+        ('-x -y -c', NS(a=False, b=False, c=True, x=True, y=True)),
+    ]
+    successes_when_not_required = [
+        ('', NS(a=False, b=False, c=False, x=False, y=False)),
+        ('-x', NS(a=False, b=False, c=False, x=True, y=False)),
+        ('-y', NS(a=False, b=False, c=False, x=False, y=True)),
+    ]
+
+    usage_when_required = usage_when_not_required = '''\
+        usage: PROG [-h] [-x] [-a] [-b] [-y] [-c]
+        '''
+    help = '''\
+
+        optional arguments:
+          -h, --help  show this help message and exit
+          -x          x help
+          -a          a help
+          -b          b help
+          -y          y help
+          -c          c help
+        '''
+
+
+class TestMutuallyExclusiveOptionalsAndPositionalsMixed(MEMixin, TestCase):
+
+    def get_parser(self, required):
+        parser = ErrorRaisingArgumentParser(prog='PROG')
+        parser.add_argument('x', help='x help')
+        parser.add_argument('-y', action='store_true', help='y help')
+        group = parser.add_mutually_exclusive_group(required=required)
+        group.add_argument('a', nargs='?', help='a help')
+        group.add_argument('-b', action='store_true', help='b help')
+        group.add_argument('-c', action='store_true', help='c help')
+        return parser
+
+    failures = ['X A -b', '-b -c', '-c X A']
+    successes = [
+        ('X A', NS(a='A', b=False, c=False, x='X', y=False)),
+        ('X -b', NS(a=None, b=True, c=False, x='X', y=False)),
+        ('X -c', NS(a=None, b=False, c=True, x='X', y=False)),
+        ('X A -y', NS(a='A', b=False, c=False, x='X', y=True)),
+        ('X -y -b', NS(a=None, b=True, c=False, x='X', y=True)),
+    ]
+    successes_when_not_required = [
+        ('X', NS(a=None, b=False, c=False, x='X', y=False)),
+        ('X -y', NS(a=None, b=False, c=False, x='X', y=True)),
+    ]
+
+    usage_when_required = usage_when_not_required = '''\
+        usage: PROG [-h] [-y] [-b] [-c] x [a]
+        '''
+    help = '''\
+
+        positional arguments:
+          x           x help
+          a           a help
+
+        optional arguments:
+          -h, --help  show this help message and exit
+          -y          y help
+          -b          b help
+          -c          c help
+        '''
+
+# =================================================
+# Mutually exclusive group in parent parser tests
+# =================================================
+
+class MEPBase(object):
+
+    def get_parser(self, required=None):
+        parent = super(MEPBase, self).get_parser(required=required)
+        parser = ErrorRaisingArgumentParser(
+            prog=parent.prog, add_help=False, parents=[parent])
+        return parser
+
+
+class TestMutuallyExclusiveGroupErrorsParent(
+    MEPBase, TestMutuallyExclusiveGroupErrors):
+    pass
+
+
+class TestMutuallyExclusiveSimpleParent(
+    MEPBase, TestMutuallyExclusiveSimple):
+    pass
+
+
+class TestMutuallyExclusiveLongParent(
+    MEPBase, TestMutuallyExclusiveLong):
+    pass
+
+
+class TestMutuallyExclusiveFirstSuppressedParent(
+    MEPBase, TestMutuallyExclusiveFirstSuppressed):
+    pass
+
+
+class TestMutuallyExclusiveManySuppressedParent(
+    MEPBase, TestMutuallyExclusiveManySuppressed):
+    pass
+
+
+class TestMutuallyExclusiveOptionalAndPositionalParent(
+    MEPBase, TestMutuallyExclusiveOptionalAndPositional):
+    pass
+
+
+class TestMutuallyExclusiveOptionalsMixedParent(
+    MEPBase, TestMutuallyExclusiveOptionalsMixed):
+    pass
+
+
+class TestMutuallyExclusiveOptionalsAndPositionalsMixedParent(
+    MEPBase, TestMutuallyExclusiveOptionalsAndPositionalsMixed):
+    pass
+
+# =================
+# Set default tests
+# =================
+
+class TestSetDefaults(TestCase):
+
+    def test_set_defaults_no_args(self):
+        parser = ErrorRaisingArgumentParser()
+        parser.set_defaults(x='foo')
+        parser.set_defaults(y='bar', z=1)
+        self.assertEqual(NS(x='foo', y='bar', z=1),
+                         parser.parse_args([]))
+        self.assertEqual(NS(x='foo', y='bar', z=1),
+                         parser.parse_args([], NS()))
+        self.assertEqual(NS(x='baz', y='bar', z=1),
+                         parser.parse_args([], NS(x='baz')))
+        self.assertEqual(NS(x='baz', y='bar', z=2),
+                         parser.parse_args([], NS(x='baz', z=2)))
+
+    def test_set_defaults_with_args(self):
+        parser = ErrorRaisingArgumentParser()
+        parser.set_defaults(x='foo', y='bar')
+        parser.add_argument('-x', default='xfoox')
+        self.assertEqual(NS(x='xfoox', y='bar'),
+                         parser.parse_args([]))
+        self.assertEqual(NS(x='xfoox', y='bar'),
+                         parser.parse_args([], NS()))
+        self.assertEqual(NS(x='baz', y='bar'),
+                         parser.parse_args([], NS(x='baz')))
+        self.assertEqual(NS(x='1', y='bar'),
+                         parser.parse_args('-x 1'.split()))
+        self.assertEqual(NS(x='1', y='bar'),
+                         parser.parse_args('-x 1'.split(), NS()))
+        self.assertEqual(NS(x='1', y='bar'),
+                         parser.parse_args('-x 1'.split(), NS(x='baz')))
+
+    def test_set_defaults_subparsers(self):
+        parser = ErrorRaisingArgumentParser()
+        parser.set_defaults(x='foo')
+        subparsers = parser.add_subparsers()
+        parser_a = subparsers.add_parser('a')
+        parser_a.set_defaults(y='bar')
+        self.assertEqual(NS(x='foo', y='bar'),
+                         parser.parse_args('a'.split()))
+
+    def test_set_defaults_parents(self):
+        parent = ErrorRaisingArgumentParser(add_help=False)
+        parent.set_defaults(x='foo')
+        parser = ErrorRaisingArgumentParser(parents=[parent])
+        self.assertEqual(NS(x='foo'), parser.parse_args([]))
+
+    def test_set_defaults_same_as_add_argument(self):
+        parser = ErrorRaisingArgumentParser()
+        parser.set_defaults(w='W', x='X', y='Y', z='Z')
+        parser.add_argument('-w')
+        parser.add_argument('-x', default='XX')
+        parser.add_argument('y', nargs='?')
+        parser.add_argument('z', nargs='?', default='ZZ')
+
+        # defaults set previously
+        self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
+                         parser.parse_args([]))
+
+        # reset defaults
+        parser.set_defaults(w='WW', x='X', y='YY', z='Z')
+        self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
+                         parser.parse_args([]))
+
+    def test_set_defaults_same_as_add_argument_group(self):
+        parser = ErrorRaisingArgumentParser()
+        parser.set_defaults(w='W', x='X', y='Y', z='Z')
+        group = parser.add_argument_group('foo')
+        group.add_argument('-w')
+        group.add_argument('-x', default='XX')
+        group.add_argument('y', nargs='?')
+        group.add_argument('z', nargs='?', default='ZZ')
+
+
+        # defaults set previously
+        self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
+                         parser.parse_args([]))
+
+        # reset defaults
+        parser.set_defaults(w='WW', x='X', y='YY', z='Z')
+        self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
+                         parser.parse_args([]))
+
+# =================
+# Get default tests
+# =================
+
+class TestGetDefault(TestCase):
+
+    def test_get_default(self):
+        parser = ErrorRaisingArgumentParser()
+        self.assertEqual(None, parser.get_default("foo"))
+        self.assertEqual(None, parser.get_default("bar"))
+
+        parser.add_argument("--foo")
+        self.assertEqual(None, parser.get_default("foo"))
+        self.assertEqual(None, parser.get_default("bar"))
+
+        parser.add_argument("--bar", type=int, default=42)
+        self.assertEqual(None, parser.get_default("foo"))
+        self.assertEqual(42, parser.get_default("bar"))
+
+        parser.set_defaults(foo="badger")
+        self.assertEqual("badger", parser.get_default("foo"))
+        self.assertEqual(42, parser.get_default("bar"))
+
+# ==========================
+# Namespace 'contains' tests
+# ==========================
+
+class TestNamespaceContainsSimple(TestCase):
+
+    def test_empty(self):
+        ns = argparse.Namespace()
+        self.assertEqual('' in ns, False)
+        self.assertEqual('' not in ns, True)
+        self.assertEqual('x' in ns, False)
+
+    def test_non_empty(self):
+        ns = argparse.Namespace(x=1, y=2)
+        self.assertEqual('x' in ns, True)
+        self.assertEqual('x' not in ns, False)
+        self.assertEqual('y' in ns, True)
+        self.assertEqual('' in ns, False)
+        self.assertEqual('xx' in ns, False)
+        self.assertEqual('z' in ns, False)
+
+# =====================
+# Help formatting tests
+# =====================
+
+class TestHelpFormattingMetaclass(type):
+
+    def __init__(cls, name, bases, bodydict):
+        if name == 'HelpTestCase':
+            return
+
+        class AddTests(object):
+
+            def __init__(self, test_class, func_suffix, std_name):
+                self.func_suffix = func_suffix
+                self.std_name = std_name
+
+                for test_func in [self.test_format,
+                                  self.test_print,
+                                  self.test_print_file]:
+                    test_name = '%s_%s' % (test_func.__name__, func_suffix)
+
+                    def test_wrapper(self, test_func=test_func):
+                        test_func(self)
+                    try:
+                        test_wrapper.__name__ = test_name
+                    except TypeError:
+                        pass
+                    setattr(test_class, test_name, test_wrapper)
+
+            def _get_parser(self, tester):
+                parser = argparse.ArgumentParser(
+                    *tester.parser_signature.args,
+                    **tester.parser_signature.kwargs)
+                for argument_sig in tester.argument_signatures:
+                    parser.add_argument(*argument_sig.args,
+                                        **argument_sig.kwargs)
+                group_signatures = tester.argument_group_signatures
+                for group_sig, argument_sigs in group_signatures:
+                    group = parser.add_argument_group(*group_sig.args,
+                                                      **group_sig.kwargs)
+                    for argument_sig in argument_sigs:
+                        group.add_argument(*argument_sig.args,
+                                           **argument_sig.kwargs)
+                return parser
+
+            def _test(self, tester, parser_text):
+                expected_text = getattr(tester, self.func_suffix)
+                expected_text = textwrap.dedent(expected_text)
+                if expected_text != parser_text:
+                    print(repr(expected_text))
+                    print(repr(parser_text))
+                    for char1, char2 in zip(expected_text, parser_text):
+                        if char1 != char2:
+                            print('first diff: %r %r' % (char1, char2))
+                            break
+                tester.assertEqual(expected_text, parser_text)
+
+            def test_format(self, tester):
+                parser = self._get_parser(tester)
+                format = getattr(parser, 'format_%s' % self.func_suffix)
+                self._test(tester, format())
+
+            def test_print(self, tester):
+                parser = self._get_parser(tester)
+                print_ = getattr(parser, 'print_%s' % self.func_suffix)
+                old_stream = getattr(sys, self.std_name)
+                setattr(sys, self.std_name, StdIOBuffer())
+                try:
+                    print_()
+                    parser_text = getattr(sys, self.std_name).getvalue()
+                finally:
+                    setattr(sys, self.std_name, old_stream)
+                self._test(tester, parser_text)
+
+            def test_print_file(self, tester):
+                parser = self._get_parser(tester)
+                print_ = getattr(parser, 'print_%s' % self.func_suffix)
+                sfile = StdIOBuffer()
+                print_(sfile)
+                parser_text = sfile.getvalue()
+                self._test(tester, parser_text)
+
+        # add tests for {format,print}_{usage,help,version}
+        for func_suffix, std_name in [('usage', 'stdout'),
+                                      ('help', 'stdout'),
+                                      ('version', 'stderr')]:
+            AddTests(cls, func_suffix, std_name)
+
+bases = TestCase,
+HelpTestCase = TestHelpFormattingMetaclass('HelpTestCase', bases, {})
+
+
+class TestHelpBiggerOptionals(HelpTestCase):
+    """Make sure that argument help aligns when options are longer"""
+
+    parser_signature = Sig(prog='PROG', description='DESCRIPTION',
+                           epilog='EPILOG', version='0.1')
+    argument_signatures = [
+        Sig('-x', action='store_true', help='X HELP'),
+        Sig('--y', help='Y HELP'),
+        Sig('foo', help='FOO HELP'),
+        Sig('bar', help='BAR HELP'),
+    ]
+    argument_group_signatures = []
+    usage = '''\
+        usage: PROG [-h] [-v] [-x] [--y Y] foo bar
+        '''
+    help = usage + '''\
+
+        DESCRIPTION
+
+        positional arguments:
+          foo            FOO HELP
+          bar            BAR HELP
+
+        optional arguments:
+          -h, --help     show this help message and exit
+          -v, --version  show program's version number and exit
+          -x             X HELP
+          --y Y          Y HELP
+
+        EPILOG
+    '''
+    version = '''\
+        0.1
+        '''
+
+
+class TestHelpBiggerOptionalGroups(HelpTestCase):
+    """Make sure that argument help aligns when options are longer"""
+
+    parser_signature = Sig(prog='PROG', description='DESCRIPTION',
+                           epilog='EPILOG', version='0.1')
+    argument_signatures = [
+        Sig('-x', action='store_true', help='X HELP'),
+        Sig('--y', help='Y HELP'),
+        Sig('foo', help='FOO HELP'),
+        Sig('bar', help='BAR HELP'),
+    ]
+    argument_group_signatures = [
+        (Sig('GROUP TITLE', description='GROUP DESCRIPTION'), [
+            Sig('baz', help='BAZ HELP'),
+            Sig('-z', nargs='+', help='Z HELP')]),
+    ]
+    usage = '''\
+        usage: PROG [-h] [-v] [-x] [--y Y] [-z Z [Z ...]] foo bar baz
+        '''
+    help = usage + '''\
+
+        DESCRIPTION
+
+        positional arguments:
+          foo            FOO HELP
+          bar            BAR HELP
+
+        optional arguments:
+          -h, --help     show this help message and exit
+          -v, --version  show program's version number and exit
+          -x             X HELP
+          --y Y          Y HELP
+
+        GROUP TITLE:
+          GROUP DESCRIPTION
+
+          baz            BAZ HELP
+          -z Z [Z ...]   Z HELP
+
+        EPILOG
+    '''
+    version = '''\
+        0.1
+        '''
+
+
+class TestHelpBiggerPositionals(HelpTestCase):
+    """Make sure that help aligns when arguments are longer"""
+
+    parser_signature = Sig(usage='USAGE', description='DESCRIPTION')
+    argument_signatures = [
+        Sig('-x', action='store_true', help='X HELP'),
+        Sig('--y', help='Y HELP'),
+        Sig('ekiekiekifekang', help='EKI HELP'),
+        Sig('bar', help='BAR HELP'),
+    ]
+    argument_group_signatures = []
+    usage = '''\
+        usage: USAGE
+        '''
+    help = usage + '''\
+
+        DESCRIPTION
+
+        positional arguments:
+          ekiekiekifekang  EKI HELP
+          bar              BAR HELP
+
+        optional arguments:
+          -h, --help       show this help message and exit
+          -x               X HELP
+          --y Y            Y HELP
+        '''
+
+    version = ''
+
+
+class TestHelpReformatting(HelpTestCase):
+    """Make sure that text after short names starts on the first line"""
+
+    parser_signature = Sig(
+        prog='PROG',
+        description='   oddly    formatted\n'
+                    'description\n'
+                    '\n'
+                    'that is so long that it should go onto multiple '
+                    'lines when wrapped')
+    argument_signatures = [
+        Sig('-x', metavar='XX', help='oddly\n'
+                                     '    formatted -x help'),
+        Sig('y', metavar='yyy', help='normal y help'),
+    ]
+    argument_group_signatures = [
+        (Sig('title', description='\n'
+                                  '    oddly formatted group\n'
+                                  '\n'
+                                  'description'),
+         [Sig('-a', action='store_true',
+              help=' oddly \n'
+                   'formatted    -a  help  \n'
+                   '    again, so long that it should be wrapped over '
+                   'multiple lines')]),
+    ]
+    usage = '''\
+        usage: PROG [-h] [-x XX] [-a] yyy
+        '''
+    help = usage + '''\
+
+        oddly formatted description that is so long that it should go onto \
+multiple
+        lines when wrapped
+
+        positional arguments:
+          yyy         normal y help
+
+        optional arguments:
+          -h, --help  show this help message and exit
+          -x XX       oddly formatted -x help
+
+        title:
+          oddly formatted group description
+
+          -a          oddly formatted -a help again, so long that it should \
+be wrapped
+                      over multiple lines
+        '''
+    version = ''
+
+
+class TestHelpWrappingShortNames(HelpTestCase):
+    """Make sure that text after short names starts on the first line"""
+
+    parser_signature = Sig(prog='PROG', description= 'D\nD' * 30)
+    argument_signatures = [
+        Sig('-x', metavar='XX', help='XHH HX' * 20),
+        Sig('y', metavar='yyy', help='YH YH' * 20),
+    ]
+    argument_group_signatures = [
+        (Sig('ALPHAS'), [
+            Sig('-a', action='store_true', help='AHHH HHA' * 10)]),
+    ]
+    usage = '''\
+        usage: PROG [-h] [-x XX] [-a] yyy
+        '''
+    help = usage + '''\
+
+        D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
+DD DD DD
+        DD DD DD DD D
+
+        positional arguments:
+          yyy         YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
+YHYH YHYH
+                      YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
+
+        optional arguments:
+          -h, --help  show this help message and exit
+          -x XX       XHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH \
+HXXHH HXXHH
+                      HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HX
+
+        ALPHAS:
+          -a          AHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH \
+HHAAHHH
+                      HHAAHHH HHAAHHH HHA
+        '''
+    version = ''
+
+
+class TestHelpWrappingLongNames(HelpTestCase):
+    """Make sure that text after long names starts on the next line"""
+
+    parser_signature = Sig(usage='USAGE', description= 'D D' * 30,
+                           version='V V'*30)
+    argument_signatures = [
+        Sig('-x', metavar='X' * 25, help='XH XH' * 20),
+        Sig('y', metavar='y' * 25, help='YH YH' * 20),
+    ]
+    argument_group_signatures = [
+        (Sig('ALPHAS'), [
+            Sig('-a', metavar='A' * 25, help='AH AH' * 20),
+            Sig('z', metavar='z' * 25, help='ZH ZH' * 20)]),
+    ]
+    usage = '''\
+        usage: USAGE
+        '''
+    help = usage + '''\
+
+        D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
+DD DD DD
+        DD DD DD DD D
+
+        positional arguments:
+          yyyyyyyyyyyyyyyyyyyyyyyyy
+                                YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
+YHYH YHYH
+                                YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
+
+        optional arguments:
+          -h, --help            show this help message and exit
+          -v, --version         show program's version number and exit
+          -x XXXXXXXXXXXXXXXXXXXXXXXXX
+                                XH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH \
+XHXH XHXH
+                                XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XH
+
+        ALPHAS:
+          -a AAAAAAAAAAAAAAAAAAAAAAAAA
+                                AH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH \
+AHAH AHAH
+                                AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AH
+          zzzzzzzzzzzzzzzzzzzzzzzzz
+                                ZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH \
+ZHZH ZHZH
+                                ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZH
+        '''
+    version = '''\
+        V VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV \
+VV VV VV
+        VV VV VV VV V
+        '''
+
+
+class TestHelpUsage(HelpTestCase):
+    """Test basic usage messages"""
+
+    parser_signature = Sig(prog='PROG')
+    argument_signatures = [
+        Sig('-w', nargs='+', help='w'),
+        Sig('-x', nargs='*', help='x'),
+        Sig('a', help='a'),
+        Sig('b', help='b', nargs=2),
+        Sig('c', help='c', nargs='?'),
+    ]
+    argument_group_signatures = [
+        (Sig('group'), [
+            Sig('-y', nargs='?', help='y'),
+            Sig('-z', nargs=3, help='z'),
+            Sig('d', help='d', nargs='*'),
+            Sig('e', help='e', nargs='+'),
+        ])
+    ]
+    usage = '''\
+        usage: PROG [-h] [-w W [W ...]] [-x [X [X ...]]] [-y [Y]] [-z Z Z Z]
+                    a b b [c] [d [d ...]] e [e ...]
+        '''
+    help = usage + '''\
+
+        positional arguments:
+          a               a
+          b               b
+          c               c
+
+        optional arguments:
+          -h, --help      show this help message and exit
+          -w W [W ...]    w
+          -x [X [X ...]]  x
+
+        group:
+          -y [Y]          y
+          -z Z Z Z        z
+          d               d
+          e               e
+        '''
+    version = ''
+
+
+class TestHelpOnlyUserGroups(HelpTestCase):
+    """Test basic usage messages"""
+
+    parser_signature = Sig(prog='PROG', add_help=False)
+    argument_signatures = []
+    argument_group_signatures = [
+        (Sig('xxxx'), [
+            Sig('-x', help='x'),
+            Sig('a', help='a'),
+        ]),
+        (Sig('yyyy'), [
+            Sig('b', help='b'),
+            Sig('-y', help='y'),
+        ]),
+    ]
+    usage = '''\
+        usage: PROG [-x X] [-y Y] a b
+        '''
+    help = usage + '''\
+
+        xxxx:
+          -x X  x
+          a     a
+
+        yyyy:
+          b     b
+          -y Y  y
+        '''
+    version = ''
+
+
+class TestHelpUsageLongProg(HelpTestCase):
+    """Test usage messages where the prog is long"""
+
+    parser_signature = Sig(prog='P' * 60)
+    argument_signatures = [
+        Sig('-w', metavar='W'),
+        Sig('-x', metavar='X'),
+        Sig('a'),
+        Sig('b'),
+    ]
+    argument_group_signatures = []
+    usage = '''\
+        usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
+               [-h] [-w W] [-x X] a b
+        '''
+    help = usage + '''\
+
+        positional arguments:
+          a
+          b
+
+        optional arguments:
+          -h, --help  show this help message and exit
+          -w W
+          -x X
+        '''
+    version = ''
+
+
+class TestHelpUsageLongProgOptionsWrap(HelpTestCase):
+    """Test usage messages where the prog is long and the optionals wrap"""
+
+    parser_signature = Sig(prog='P' * 60)
+    argument_signatures = [
+        Sig('-w', metavar='W' * 25),
+        Sig('-x', metavar='X' * 25),
+        Sig('-y', metavar='Y' * 25),
+        Sig('-z', metavar='Z' * 25),
+        Sig('a'),
+        Sig('b'),
+    ]
+    argument_group_signatures = []
+    usage = '''\
+        usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
+               [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
+[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
+               [-y YYYYYYYYYYYYYYYYYYYYYYYYY] [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
+               a b
+        '''
+    help = usage + '''\
+
+        positional arguments:
+          a
+          b
+
+        optional arguments:
+          -h, --help            show this help message and exit
+          -w WWWWWWWWWWWWWWWWWWWWWWWWW
+          -x XXXXXXXXXXXXXXXXXXXXXXXXX
+          -y YYYYYYYYYYYYYYYYYYYYYYYYY
+          -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
+        '''
+    version = ''
+
+
+class TestHelpUsageLongProgPositionalsWrap(HelpTestCase):
+    """Test usage messages where the prog is long and the positionals wrap"""
+
+    parser_signature = Sig(prog='P' * 60, add_help=False)
+    argument_signatures = [
+        Sig('a' * 25),
+        Sig('b' * 25),
+        Sig('c' * 25),
+    ]
+    argument_group_signatures = []
+    usage = '''\
+        usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
+               aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
+               ccccccccccccccccccccccccc
+        '''
+    help = usage + '''\
+
+        positional arguments:
+          aaaaaaaaaaaaaaaaaaaaaaaaa
+          bbbbbbbbbbbbbbbbbbbbbbbbb
+          ccccccccccccccccccccccccc
+        '''
+    version = ''
+
+
+class TestHelpUsageOptionalsWrap(HelpTestCase):
+    """Test usage messages where the optionals wrap"""
+
+    parser_signature = Sig(prog='PROG')
+    argument_signatures = [
+        Sig('-w', metavar='W' * 25),
+        Sig('-x', metavar='X' * 25),
+        Sig('-y', metavar='Y' * 25),
+        Sig('-z', metavar='Z' * 25),
+        Sig('a'),
+        Sig('b'),
+        Sig('c'),
+    ]
+    argument_group_signatures = []
+    usage = '''\
+        usage: PROG [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
+[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
+                    [-y YYYYYYYYYYYYYYYYYYYYYYYYY] \
+[-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
+                    a b c
+        '''
+    help = usage + '''\
+
+        positional arguments:
+          a
+          b
+          c
+
+        optional arguments:
+          -h, --help            show this help message and exit
+          -w WWWWWWWWWWWWWWWWWWWWWWWWW
+          -x XXXXXXXXXXXXXXXXXXXXXXXXX
+          -y YYYYYYYYYYYYYYYYYYYYYYYYY
+          -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
+        '''
+    version = ''
+
+
+class TestHelpUsagePositionalsWrap(HelpTestCase):
+    """Test usage messages where the positionals wrap"""
+
+    parser_signature = Sig(prog='PROG')
+    argument_signatures = [
+        Sig('-x'),
+        Sig('-y'),
+        Sig('-z'),
+        Sig('a' * 25),
+        Sig('b' * 25),
+        Sig('c' * 25),
+    ]
+    argument_group_signatures = []
+    usage = '''\
+        usage: PROG [-h] [-x X] [-y Y] [-z Z]
+                    aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
+                    ccccccccccccccccccccccccc
+        '''
+    help = usage + '''\
+
+        positional arguments:
+          aaaaaaaaaaaaaaaaaaaaaaaaa
+          bbbbbbbbbbbbbbbbbbbbbbbbb
+          ccccccccccccccccccccccccc
+
+        optional arguments:
+          -h, --help            show this help message and exit
+          -x X
+          -y Y
+          -z Z
+        '''
+    version = ''
+
+
+class TestHelpUsageOptionalsPositionalsWrap(HelpTestCase):
+    """Test usage messages where the optionals and positionals wrap"""
+
+    parser_signature = Sig(prog='PROG')
+    argument_signatures = [
+        Sig('-x', metavar='X' * 25),
+        Sig('-y', metavar='Y' * 25),
+        Sig('-z', metavar='Z' * 25),
+        Sig('a' * 25),
+        Sig('b' * 25),
+        Sig('c' * 25),
+    ]
+    argument_group_signatures = []
+    usage = '''\
+        usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
+[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
+                    [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
+                    aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
+                    ccccccccccccccccccccccccc
+        '''
+    help = usage + '''\
+
+        positional arguments:
+          aaaaaaaaaaaaaaaaaaaaaaaaa
+          bbbbbbbbbbbbbbbbbbbbbbbbb
+          ccccccccccccccccccccccccc
+
+        optional arguments:
+          -h, --help            show this help message and exit
+          -x XXXXXXXXXXXXXXXXXXXXXXXXX
+          -y YYYYYYYYYYYYYYYYYYYYYYYYY
+          -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
+        '''
+    version = ''
+
+
+class TestHelpUsageOptionalsOnlyWrap(HelpTestCase):
+    """Test usage messages where there are only optionals and they wrap"""
+
+    parser_signature = Sig(prog='PROG')
+    argument_signatures = [
+        Sig('-x', metavar='X' * 25),
+        Sig('-y', metavar='Y' * 25),
+        Sig('-z', metavar='Z' * 25),
+    ]
+    argument_group_signatures = []
+    usage = '''\
+        usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
+[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
+                    [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
+        '''
+    help = usage + '''\
+
+        optional arguments:
+          -h, --help            show this help message and exit
+          -x XXXXXXXXXXXXXXXXXXXXXXXXX
+          -y YYYYYYYYYYYYYYYYYYYYYYYYY
+          -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
+        '''
+    version = ''
+
+
+class TestHelpUsagePositionalsOnlyWrap(HelpTestCase):
+    """Test usage messages where there are only positionals and they wrap"""
+
+    parser_signature = Sig(prog='PROG', add_help=False)
+    argument_signatures = [
+        Sig('a' * 25),
+        Sig('b' * 25),
+        Sig('c' * 25),
+    ]
+    argument_group_signatures = []
+    usage = '''\
+        usage: PROG aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
+                    ccccccccccccccccccccccccc
+        '''
+    help = usage + '''\
+
+        positional arguments:
+          aaaaaaaaaaaaaaaaaaaaaaaaa
+          bbbbbbbbbbbbbbbbbbbbbbbbb
+          ccccccccccccccccccccccccc
+        '''
+    version = ''
+
+
+class TestHelpVariableExpansion(HelpTestCase):
+    """Test that variables are expanded properly in help messages"""
+
+    parser_signature = Sig(prog='PROG')
+    argument_signatures = [
+        Sig('-x', type=int,
+            help='x %(prog)s %(default)s %(type)s %%'),
+        Sig('-y', action='store_const', default=42, const='XXX',
+            help='y %(prog)s %(default)s %(const)s'),
+        Sig('--foo', choices='abc',
+            help='foo %(prog)s %(default)s %(choices)s'),
+        Sig('--bar', default='baz', choices=[1, 2], metavar='BBB',
+            help='bar %(prog)s %(default)s %(dest)s'),
+        Sig('spam', help='spam %(prog)s %(default)s'),
+        Sig('badger', default=0.5, help='badger %(prog)s %(default)s'),
+    ]
+    argument_group_signatures = [
+        (Sig('group'), [
+            Sig('-a', help='a %(prog)s %(default)s'),
+            Sig('-b', default=-1, help='b %(prog)s %(default)s'),
+        ])
+    ]
+    usage = ('''\
+        usage: PROG [-h] [-x X] [-y] [--foo {a,b,c}] [--bar BBB] [-a A] [-b B]
+                    spam badger
+        ''')
+    help = usage + '''\
+
+        positional arguments:
+          spam           spam PROG None
+          badger         badger PROG 0.5
+
+        optional arguments:
+          -h, --help     show this help message and exit
+          -x X           x PROG None int %
+          -y             y PROG 42 XXX
+          --foo {a,b,c}  foo PROG None a, b, c
+          --bar BBB      bar PROG baz bar
+
+        group:
+          -a A           a PROG None
+          -b B           b PROG -1
+        '''
+    version = ''
+
+
+class TestHelpVariableExpansionUsageSupplied(HelpTestCase):
+    """Test that variables are expanded properly when usage= is present"""
+
+    parser_signature = Sig(prog='PROG', usage='%(prog)s FOO')
+    argument_signatures = []
+    argument_group_signatures = []
+    usage = ('''\
+        usage: PROG FOO
+        ''')
+    help = usage + '''\
+
+        optional arguments:
+          -h, --help  show this help message and exit
+        '''
+    version = ''
+
+
+class TestHelpVariableExpansionNoArguments(HelpTestCase):
+    """Test that variables are expanded properly with no arguments"""
+
+    parser_signature = Sig(prog='PROG', add_help=False)
+    argument_signatures = []
+    argument_group_signatures = []
+    usage = ('''\
+        usage: PROG
+        ''')
+    help = usage
+    version = ''
+
+
+class TestHelpSuppressUsage(HelpTestCase):
+    """Test that items can be suppressed in usage messages"""
+
+    parser_signature = Sig(prog='PROG', usage=argparse.SUPPRESS)
+    argument_signatures = [
+        Sig('--foo', help='foo help'),
+        Sig('spam', help='spam help'),
+    ]
+    argument_group_signatures = []
+    help = '''\
+        positional arguments:
+          spam        spam help
+
+        optional arguments:
+          -h, --help  show this help message and exit
+          --foo FOO   foo help
+        '''
+    usage = ''
+    version = ''
+
+
+class TestHelpSuppressOptional(HelpTestCase):
+    """Test that optional arguments can be suppressed in help messages"""
+
+    parser_signature = Sig(prog='PROG', add_help=False)
+    argument_signatures = [
+        Sig('--foo', help=argparse.SUPPRESS),
+        Sig('spam', help='spam help'),
+    ]
+    argument_group_signatures = []
+    usage = '''\
+        usage: PROG spam
+        '''
+    help = usage + '''\
+
+        positional arguments:
+          spam  spam help
+        '''
+    version = ''
+
+
+class TestHelpSuppressOptionalGroup(HelpTestCase):
+    """Test that optional groups can be suppressed in help messages"""
+
+    parser_signature = Sig(prog='PROG')
+    argument_signatures = [
+        Sig('--foo', help='foo help'),
+        Sig('spam', help='spam help'),
+    ]
+    argument_group_signatures = [
+        (Sig('group'), [Sig('--bar', help=argparse.SUPPRESS)]),
+    ]
+    usage = '''\
+        usage: PROG [-h] [--foo FOO] spam
+        '''
+    help = usage + '''\
+
+        positional arguments:
+          spam        spam help
+
+        optional arguments:
+          -h, --help  show this help message and exit
+          --foo FOO   foo help
+        '''
+    version = ''
+
+
+class TestHelpSuppressPositional(HelpTestCase):
+    """Test that positional arguments can be suppressed in help messages"""
+
+    parser_signature = Sig(prog='PROG')
+    argument_signatures = [
+        Sig('--foo', help='foo help'),
+        Sig('spam', help=argparse.SUPPRESS),
+    ]
+    argument_group_signatures = []
+    usage = '''\
+        usage: PROG [-h] [--foo FOO]
+        '''
+    help = usage + '''\
+
+        optional arguments:
+          -h, --help  show this help message and exit
+          --foo FOO   foo help
+        '''
+    version = ''
+
+
+class TestHelpRequiredOptional(HelpTestCase):
+    """Test that required options don't look optional"""
+
+    parser_signature = Sig(prog='PROG')
+    argument_signatures = [
+        Sig('--foo', required=True, help='foo help'),
+    ]
+    argument_group_signatures = []
+    usage = '''\
+        usage: PROG [-h] --foo FOO
+        '''
+    help = usage + '''\
+
+        optional arguments:
+          -h, --help  show this help message and exit
+          --foo FOO   foo help
+        '''
+    version = ''
+
+
+class TestHelpAlternatePrefixChars(HelpTestCase):
+    """Test that options display with different prefix characters"""
+
+    parser_signature = Sig(prog='PROG', prefix_chars='^;', add_help=False)
+    argument_signatures = [
+        Sig('^^foo', action='store_true', help='foo help'),
+        Sig(';b', ';;bar', help='bar help'),
+    ]
+    argument_group_signatures = []
+    usage = '''\
+        usage: PROG [^^foo] [;b BAR]
+        '''
+    help = usage + '''\
+
+        optional arguments:
+          ^^foo              foo help
+          ;b BAR, ;;bar BAR  bar help
+        '''
+    version = ''
+
+
+class TestHelpNoHelpOptional(HelpTestCase):
+    """Test that the --help argument can be suppressed help messages"""
+
+    parser_signature = Sig(prog='PROG', add_help=False)
+    argument_signatures = [
+        Sig('--foo', help='foo help'),
+        Sig('spam', help='spam help'),
+    ]
+    argument_group_signatures = []
+    usage = '''\
+        usage: PROG [--foo FOO] spam
+        '''
+    help = usage + '''\
+
+        positional arguments:
+          spam       spam help
+
+        optional arguments:
+          --foo FOO  foo help
+        '''
+    version = ''
+
+
+class TestHelpVersionOptional(HelpTestCase):
+    """Test that the --version argument can be suppressed help messages"""
+
+    parser_signature = Sig(prog='PROG', version='1.0')
+    argument_signatures = [
+        Sig('--foo', help='foo help'),
+        Sig('spam', help='spam help'),
+    ]
+    argument_group_signatures = []
+    usage = '''\
+        usage: PROG [-h] [-v] [--foo FOO] spam
+        '''
+    help = usage + '''\
+
+        positional arguments:
+          spam           spam help
+
+        optional arguments:
+          -h, --help     show this help message and exit
+          -v, --version  show program's version number and exit
+          --foo FOO      foo help
+        '''
+    version = '''\
+        1.0
+        '''
+
+
+class TestHelpNone(HelpTestCase):
+    """Test that no errors occur if no help is specified"""
+
+    parser_signature = Sig(prog='PROG')
+    argument_signatures = [
+        Sig('--foo'),
+        Sig('spam'),
+    ]
+    argument_group_signatures = []
+    usage = '''\
+        usage: PROG [-h] [--foo FOO] spam
+        '''
+    help = usage + '''\
+
+        positional arguments:
+          spam
+
+        optional arguments:
+          -h, --help  show this help message and exit
+          --foo FOO
+        '''
+    version = ''
+
+
+class TestHelpTupleMetavar(HelpTestCase):
+    """Test specifying metavar as a tuple"""
+
+    parser_signature = Sig(prog='PROG')
+    argument_signatures = [
+        Sig('-w', help='w', nargs='+', metavar=('W1', 'W2')),
+        Sig('-x', help='x', nargs='*', metavar=('X1', 'X2')),
+        Sig('-y', help='y', nargs=3, metavar=('Y1', 'Y2', 'Y3')),
+        Sig('-z', help='z', nargs='?', metavar=('Z1', )),
+    ]
+    argument_group_signatures = []
+    usage = '''\
+        usage: PROG [-h] [-w W1 [W2 ...]] [-x [X1 [X2 ...]]] [-y Y1 Y2 Y3] \
+[-z [Z1]]
+        '''
+    help = usage + '''\
+
+        optional arguments:
+          -h, --help        show this help message and exit
+          -w W1 [W2 ...]    w
+          -x [X1 [X2 ...]]  x
+          -y Y1 Y2 Y3       y
+          -z [Z1]           z
+        '''
+    version = ''
+
+
+class TestHelpRawText(HelpTestCase):
+    """Test the RawTextHelpFormatter"""
+
+    parser_signature = Sig(
+        prog='PROG', formatter_class=argparse.RawTextHelpFormatter,
+        description='Keep the formatting\n'
+                    '    exactly as it is written\n'
+                    '\n'
+                    'here\n')
+
+    argument_signatures = [
+        Sig('--foo', help='    foo help should also\n'
+                          'appear as given here'),
+        Sig('spam', help='spam help'),
+    ]
+    argument_group_signatures = [
+        (Sig('title', description='    This text\n'
+                                  '  should be indented\n'
+                                  '    exactly like it is here\n'),
+         [Sig('--bar', help='bar help')]),
+    ]
+    usage = '''\
+        usage: PROG [-h] [--foo FOO] [--bar BAR] spam
+        '''
+    help = usage + '''\
+
+        Keep the formatting
+            exactly as it is written
+
+        here
+
+        positional arguments:
+          spam        spam help
+
+        optional arguments:
+          -h, --help  show this help message and exit
+          --foo FOO       foo help should also
+                      appear as given here
+
+        title:
+              This text
+            should be indented
+              exactly like it is here
+
+          --bar BAR   bar help
+        '''
+    version = ''
+
+
+class TestHelpRawDescription(HelpTestCase):
+    """Test the RawTextHelpFormatter"""
+
+    parser_signature = Sig(
+        prog='PROG', formatter_class=argparse.RawDescriptionHelpFormatter,
+        description='Keep the formatting\n'
+                    '    exactly as it is written\n'
+                    '\n'
+                    'here\n')
+
+    argument_signatures = [
+        Sig('--foo', help='  foo help should not\n'
+                          '    retain this odd formatting'),
+        Sig('spam', help='spam help'),
+    ]
+    argument_group_signatures = [
+        (Sig('title', description='    This text\n'
+                                  '  should be indented\n'
+                                  '    exactly like it is here\n'),
+         [Sig('--bar', help='bar help')]),
+    ]
+    usage = '''\
+        usage: PROG [-h] [--foo FOO] [--bar BAR] spam
+        '''
+    help = usage + '''\
+
+        Keep the formatting
+            exactly as it is written
+
+        here
+
+        positional arguments:
+          spam        spam help
+
+        optional arguments:
+          -h, --help  show this help message and exit
+          --foo FOO   foo help should not retain this odd formatting
+
+        title:
+              This text
+            should be indented
+              exactly like it is here
+
+          --bar BAR   bar help
+        '''
+    version = ''
+
+
+class TestHelpArgumentDefaults(HelpTestCase):
+    """Test the ArgumentDefaultsHelpFormatter"""
+
+    parser_signature = Sig(
+        prog='PROG', formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+        description='description')
+
+    argument_signatures = [
+        Sig('--foo', help='foo help - oh and by the way, %(default)s'),
+        Sig('--bar', action='store_true', help='bar help'),
+        Sig('spam', help='spam help'),
+        Sig('badger', nargs='?', default='wooden', help='badger help'),
+    ]
+    argument_group_signatures = [
+        (Sig('title', description='description'),
+         [Sig('--baz', type=int, default=42, help='baz help')]),
+    ]
+    usage = '''\
+        usage: PROG [-h] [--foo FOO] [--bar] [--baz BAZ] spam [badger]
+        '''
+    help = usage + '''\
+
+        description
+
+        positional arguments:
+          spam        spam help
+          badger      badger help (default: wooden)
+
+        optional arguments:
+          -h, --help  show this help message and exit
+          --foo FOO   foo help - oh and by the way, None
+          --bar       bar help (default: False)
+
+        title:
+          description
+
+          --baz BAZ   baz help (default: 42)
+        '''
+    version = ''
+
+class TestHelpVersionAction(HelpTestCase):
+    """Test the default help for the version action"""
+
+    parser_signature = Sig(prog='PROG', description='description')
+    argument_signatures = [Sig('-V', '--version', action='version', version='3.6')]
+    argument_group_signatures = []
+    usage = '''\
+        usage: PROG [-h] [-V]
+        '''
+    help = usage + '''\
+
+        description
+
+        optional arguments:
+          -h, --help     show this help message and exit
+          -V, --version  show program's version number and exit
+        '''
+    version = ''
+
+# =====================================
+# Optional/Positional constructor tests
+# =====================================
+
+class TestInvalidArgumentConstructors(TestCase):
+    """Test a bunch of invalid Argument constructors"""
+
+    def assertTypeError(self, *args, **kwargs):
+        parser = argparse.ArgumentParser()
+        self.assertRaises(TypeError, parser.add_argument,
+                          *args, **kwargs)
+
+    def assertValueError(self, *args, **kwargs):
+        parser = argparse.ArgumentParser()
+        self.assertRaises(ValueError, parser.add_argument,
+                          *args, **kwargs)
+
+    def test_invalid_keyword_arguments(self):
+        self.assertTypeError('-x', bar=None)
+        self.assertTypeError('-y', callback='foo')
+        self.assertTypeError('-y', callback_args=())
+        self.assertTypeError('-y', callback_kwargs={})
+
+    def test_missing_destination(self):
+        self.assertTypeError()
+        for action in ['append', 'store']:
+            self.assertTypeError(action=action)
+
+    def test_invalid_option_strings(self):
+        self.assertValueError('--')
+        self.assertValueError('---')
+
+    def test_invalid_type(self):
+        self.assertValueError('--foo', type='int')
+
+    def test_invalid_action(self):
+        self.assertValueError('-x', action='foo')
+        self.assertValueError('foo', action='baz')
+        parser = argparse.ArgumentParser()
+        try:
+            parser.add_argument("--foo", action="store-true")
+        except ValueError:
+            e = sys.exc_info()[1]
+            expected = 'unknown action'
+            msg = 'expected %r, found %r' % (expected, e)
+            self.assertTrue(expected in str(e), msg)
+
+    def test_multiple_dest(self):
+        parser = argparse.ArgumentParser()
+        parser.add_argument(dest='foo')
+        try:
+            parser.add_argument('bar', dest='baz')
+        except ValueError:
+            e = sys.exc_info()[1]
+            expected = 'dest supplied twice for positional argument'
+            msg = 'expected %r, found %r' % (expected, e)
+            self.assertTrue(expected in str(e), msg)
+
+    def test_no_argument_actions(self):
+        for action in ['store_const', 'store_true', 'store_false',
+                       'append_const', 'count']:
+            for attrs in [dict(type=int), dict(nargs='+'),
+                          dict(choices='ab')]:
+                self.assertTypeError('-x', action=action, **attrs)
+
+    def test_no_argument_no_const_actions(self):
+        # options with zero arguments
+        for action in ['store_true', 'store_false', 'count']:
+
+            # const is always disallowed
+            self.assertTypeError('-x', const='foo', action=action)
+
+            # nargs is always disallowed
+            self.assertTypeError('-x', nargs='*', action=action)
+
+    def test_more_than_one_argument_actions(self):
+        for action in ['store', 'append']:
+
+            # nargs=0 is disallowed
+            self.assertValueError('-x', nargs=0, action=action)
+            self.assertValueError('spam', nargs=0, action=action)
+
+            # const is disallowed with non-optional arguments
+            for nargs in [1, '*', '+']:
+                self.assertValueError('-x', const='foo',
+                                      nargs=nargs, action=action)
+                self.assertValueError('spam', const='foo',
+                                      nargs=nargs, action=action)
+
+    def test_required_const_actions(self):
+        for action in ['store_const', 'append_const']:
+
+            # nargs is always disallowed
+            self.assertTypeError('-x', nargs='+', action=action)
+
+    def test_parsers_action_missing_params(self):
+        self.assertTypeError('command', action='parsers')
+        self.assertTypeError('command', action='parsers', prog='PROG')
+        self.assertTypeError('command', action='parsers',
+                             parser_class=argparse.ArgumentParser)
+
+    def test_required_positional(self):
+        self.assertTypeError('foo', required=True)
+
+    def test_user_defined_action(self):
+
+        class Success(Exception):
+            pass
+
+        class Action(object):
+
+            def __init__(self,
+                         option_strings,
+                         dest,
+                         const,
+                         default,
+                         required=False):
+                if dest == 'spam':
+                    if const is Success:
+                        if default is Success:
+                            raise Success()
+
+            def __call__(self, *args, **kwargs):
+                pass
+
+        parser = argparse.ArgumentParser()
+        self.assertRaises(Success, parser.add_argument, '--spam',
+                          action=Action, default=Success, const=Success)
+        self.assertRaises(Success, parser.add_argument, 'spam',
+                          action=Action, default=Success, const=Success)
+
+# ================================
+# Actions returned by add_argument
+# ================================
+
+class TestActionsReturned(TestCase):
+
+    def test_dest(self):
+        parser = argparse.ArgumentParser()
+        action = parser.add_argument('--foo')
+        self.assertEqual(action.dest, 'foo')
+        action = parser.add_argument('-b', '--bar')
+        self.assertEqual(action.dest, 'bar')
+        action = parser.add_argument('-x', '-y')
+        self.assertEqual(action.dest, 'x')
+
+    def test_misc(self):
+        parser = argparse.ArgumentParser()
+        action = parser.add_argument('--foo', nargs='?', const=42,
+                                     default=84, type=int, choices=[1, 2],
+                                     help='FOO', metavar='BAR', dest='baz')
+        self.assertEqual(action.nargs, '?')
+        self.assertEqual(action.const, 42)
+        self.assertEqual(action.default, 84)
+        self.assertEqual(action.type, int)
+        self.assertEqual(action.choices, [1, 2])
+        self.assertEqual(action.help, 'FOO')
+        self.assertEqual(action.metavar, 'BAR')
+        self.assertEqual(action.dest, 'baz')
+
+
+# ================================
+# Argument conflict handling tests
+# ================================
+
+class TestConflictHandling(TestCase):
+
+    def test_bad_type(self):
+        self.assertRaises(ValueError, argparse.ArgumentParser,
+                          conflict_handler='foo')
+
+    def test_conflict_error(self):
+        parser = argparse.ArgumentParser()
+        parser.add_argument('-x')
+        self.assertRaises(argparse.ArgumentError,
+                          parser.add_argument, '-x')
+        parser.add_argument('--spam')
+        self.assertRaises(argparse.ArgumentError,
+                          parser.add_argument, '--spam')
+
+    def test_resolve_error(self):
+        get_parser = argparse.ArgumentParser
+        parser = get_parser(prog='PROG', conflict_handler='resolve')
+
+        parser.add_argument('-x', help='OLD X')
+        parser.add_argument('-x', help='NEW X')
+        self.assertEqual(parser.format_help(), textwrap.dedent('''\
+            usage: PROG [-h] [-x X]
+
+            optional arguments:
+              -h, --help  show this help message and exit
+              -x X        NEW X
+            '''))
+
+        parser.add_argument('--spam', metavar='OLD_SPAM')
+        parser.add_argument('--spam', metavar='NEW_SPAM')
+        self.assertEqual(parser.format_help(), textwrap.dedent('''\
+            usage: PROG [-h] [-x X] [--spam NEW_SPAM]
+
+            optional arguments:
+              -h, --help       show this help message and exit
+              -x X             NEW X
+              --spam NEW_SPAM
+            '''))
+
+
+# =============================
+# Help and Version option tests
+# =============================
+
+class TestOptionalsHelpVersionActions(TestCase):
+    """Test the help and version actions"""
+
+    def _get_error(self, func, *args, **kwargs):
+        try:
+            func(*args, **kwargs)
+        except ArgumentParserError:
+            return sys.exc_info()[1]
+        else:
+            self.assertRaises(ArgumentParserError, func, *args, **kwargs)
+
+    def assertPrintHelpExit(self, parser, args_str):
+        self.assertEqual(
+            parser.format_help(),
+            self._get_error(parser.parse_args, args_str.split()).stdout)
+
+    def assertPrintVersionExit(self, parser, args_str):
+        self.assertEqual(
+            parser.format_version(),
+            self._get_error(parser.parse_args, args_str.split()).stderr)
+
+    def assertArgumentParserError(self, parser, *args):
+        self.assertRaises(ArgumentParserError, parser.parse_args, args)
+
+    def test_version(self):
+        parser = ErrorRaisingArgumentParser(version='1.0')
+        self.assertPrintHelpExit(parser, '-h')
+        self.assertPrintHelpExit(parser, '--help')
+        self.assertPrintVersionExit(parser, '-v')
+        self.assertPrintVersionExit(parser, '--version')
+
+    def test_version_format(self):
+        parser = ErrorRaisingArgumentParser(prog='PPP', version='%(prog)s 3.5')
+        msg = self._get_error(parser.parse_args, ['-v']).stderr
+        self.assertEqual('PPP 3.5\n', msg)
+
+    def test_version_no_help(self):
+        parser = ErrorRaisingArgumentParser(add_help=False, version='1.0')
+        self.assertArgumentParserError(parser, '-h')
+        self.assertArgumentParserError(parser, '--help')
+        self.assertPrintVersionExit(parser, '-v')
+        self.assertPrintVersionExit(parser, '--version')
+
+    def test_version_action(self):
+        parser = ErrorRaisingArgumentParser(prog='XXX')
+        parser.add_argument('-V', action='version', version='%(prog)s 3.7')
+        msg = self._get_error(parser.parse_args, ['-V']).stderr
+        self.assertEqual('XXX 3.7\n', msg)
+
+    def test_no_help(self):
+        parser = ErrorRaisingArgumentParser(add_help=False)
+        self.assertArgumentParserError(parser, '-h')
+        self.assertArgumentParserError(parser, '--help')
+        self.assertArgumentParserError(parser, '-v')
+        self.assertArgumentParserError(parser, '--version')
+
+    def test_alternate_help_version(self):
+        parser = ErrorRaisingArgumentParser()
+        parser.add_argument('-x', action='help')
+        parser.add_argument('-y', action='version')
+        self.assertPrintHelpExit(parser, '-x')
+        self.assertPrintVersionExit(parser, '-y')
+        self.assertArgumentParserError(parser, '-v')
+        self.assertArgumentParserError(parser, '--version')
+
+    def test_help_version_extra_arguments(self):
+        parser = ErrorRaisingArgumentParser(version='1.0')
+        parser.add_argument('-x', action='store_true')
+        parser.add_argument('y')
+
+        # try all combinations of valid prefixes and suffixes
+        valid_prefixes = ['', '-x', 'foo', '-x bar', 'baz -x']
+        valid_suffixes = valid_prefixes + ['--bad-option', 'foo bar baz']
+        for prefix in valid_prefixes:
+            for suffix in valid_suffixes:
+                format = '%s %%s %s' % (prefix, suffix)
+            self.assertPrintHelpExit(parser, format % '-h')
+            self.assertPrintHelpExit(parser, format % '--help')
+            self.assertPrintVersionExit(parser, format % '-v')
+            self.assertPrintVersionExit(parser, format % '--version')
+
+
+# ======================
+# str() and repr() tests
+# ======================
+
+class TestStrings(TestCase):
+    """Test str()  and repr() on Optionals and Positionals"""
+
+    def assertStringEqual(self, obj, result_string):
+        for func in [str, repr]:
+            self.assertEqual(func(obj), result_string)
+
+    def test_optional(self):
+        option = argparse.Action(
+            option_strings=['--foo', '-a', '-b'],
+            dest='b',
+            type='int',
+            nargs='+',
+            default=42,
+            choices=[1, 2, 3],
+            help='HELP',
+            metavar='METAVAR')
+        string = (
+            "Action(option_strings=['--foo', '-a', '-b'], dest='b', "
+            "nargs='+', const=None, default=42, type='int', "
+            "choices=[1, 2, 3], help='HELP', metavar='METAVAR')")
+        self.assertStringEqual(option, string)
+
+    def test_argument(self):
+        argument = argparse.Action(
+            option_strings=[],
+            dest='x',
+            type=float,
+            nargs='?',
+            default=2.5,
+            choices=[0.5, 1.5, 2.5],
+            help='H HH H',
+            metavar='MV MV MV')
+        string = (
+            "Action(option_strings=[], dest='x', nargs='?', "
+            "const=None, default=2.5, type=%r, choices=[0.5, 1.5, 2.5], "
+            "help='H HH H', metavar='MV MV MV')" % float)
+        self.assertStringEqual(argument, string)
+
+    def test_namespace(self):
+        ns = argparse.Namespace(foo=42, bar='spam')
+        string = "Namespace(bar='spam', foo=42)"
+        self.assertStringEqual(ns, string)
+
+    def test_parser(self):
+        parser = argparse.ArgumentParser(prog='PROG')
+        string = (
+            "ArgumentParser(prog='PROG', usage=None, description=None, "
+            "version=None, formatter_class=%r, conflict_handler='error', "
+            "add_help=True)" % argparse.HelpFormatter)
+        self.assertStringEqual(parser, string)
+
+# ===============
+# Namespace tests
+# ===============
+
+class TestNamespace(TestCase):
+
+    def test_constructor(self):
+        ns = argparse.Namespace()
+        self.assertRaises(AttributeError, getattr, ns, 'x')
+
+        ns = argparse.Namespace(a=42, b='spam')
+        self.assertEqual(ns.a, 42)
+        self.assertEqual(ns.b, 'spam')
+
+    def test_equality(self):
+        ns1 = argparse.Namespace(a=1, b=2)
+        ns2 = argparse.Namespace(b=2, a=1)
+        ns3 = argparse.Namespace(a=1)
+        ns4 = argparse.Namespace(b=2)
+
+        self.assertEqual(ns1, ns2)
+        self.assertNotEqual(ns1, ns3)
+        self.assertNotEqual(ns1, ns4)
+        self.assertNotEqual(ns2, ns3)
+        self.assertNotEqual(ns2, ns4)
+        self.assertTrue(ns1 != ns3)
+        self.assertTrue(ns1 != ns4)
+        self.assertTrue(ns2 != ns3)
+        self.assertTrue(ns2 != ns4)
+
+
+# ===================
+# File encoding tests
+# ===================
+
+class TestEncoding(TestCase):
+
+    def _test_module_encoding(self, path):
+        path, _ = os.path.splitext(path)
+        path += ".py"
+        f = codecs.open(path, 'r', 'utf8')
+        try:
+            f.read()
+        finally:
+            f.close
+
+    def test_argparse_module_encoding(self):
+        self._test_module_encoding(argparse.__file__)
+
+    def test_test_argparse_module_encoding(self):
+        self._test_module_encoding(__file__)
+
+# ===================
+# ArgumentError tests
+# ===================
+
+class TestArgumentError(TestCase):
+
+    def test_argument_error(self):
+        msg = "my error here"
+        error = argparse.ArgumentError(None, msg)
+        self.assertEqual(str(error), msg)
+
+# =======================
+# ArgumentTypeError tests
+# =======================
+
+class TestArgumentError(TestCase):
+
+    def test_argument_type_error(self):
+
+        def spam(string):
+            raise argparse.ArgumentTypeError('spam!')
+
+        parser = ErrorRaisingArgumentParser(prog='PROG', add_help=False)
+        parser.add_argument('x', type=spam)
+        try:
+            parser.parse_args(['XXX'])
+        except ArgumentParserError:
+            expected = 'usage: PROG x\nPROG: error: argument x: spam!\n'
+            msg = sys.exc_info()[1].stderr
+            self.assertEqual(expected, msg)
+        else:
+            self.fail()
+
+# ======================
+# parse_known_args tests
+# ======================
+
+class TestParseKnownArgs(TestCase):
+
+    def test_optionals(self):
+        parser = argparse.ArgumentParser()
+        parser.add_argument('--foo')
+        args, extras = parser.parse_known_args('--foo F --bar --baz'.split())
+        self.assertEqual(NS(foo='F'), args)
+        self.assertEqual(['--bar', '--baz'], extras)
+
+    def test_mixed(self):
+        parser = argparse.ArgumentParser()
+        parser.add_argument('-v', nargs='?', const=1, type=int)
+        parser.add_argument('--spam', action='store_false')
+        parser.add_argument('badger')
+
+        argv = ["B", "C", "--foo", "-v", "3", "4"]
+        args, extras = parser.parse_known_args(argv)
+        self.assertEqual(NS(v=3, spam=True, badger="B"), args)
+        self.assertEqual(["C", "--foo", "4"], extras)
+
+# ============================
+# from argparse import * tests
+# ============================
+
+class TestImportStar(TestCase):
+
+    def test(self):
+        for name in argparse.__all__:
+            self.assertTrue(hasattr(argparse, name))
+
+    def test_all_exports_everything_but_modules(self):
+        items = [
+            name
+            for name, value in vars(argparse).items()
+            if not name.startswith("_")
+            if not inspect.ismodule(value)
+        ]
+        # ignore "set" and "sorted" on python 2.3:
+        if sys.version_info[:2] == (2, 3):
+            items.remove("set")
+            items.remove("sorted")
+        # ignore "basestring" on python 3.x:
+        if sys.version_info[:2] >= (3, 0):
+            items.remove("basestring")
+        self.assertEqual(sorted(items), sorted(argparse.__all__))
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/lib/cacerts/urlfetch_cacerts.txt b/lib/cacerts/urlfetch_cacerts.txt
index 1395499..38256ed 100755
--- a/lib/cacerts/urlfetch_cacerts.txt
+++ b/lib/cacerts/urlfetch_cacerts.txt
@@ -6205,34 +6205,6 @@
 c8dbng5hi1e5YGCfREE4G3fKAsvLAJ5Xww==
 -----END CERTIFICATE-----
 
-subject= /O=GlobalSign Inc/CN=Cybertrust SureServer CA
-serial=040003CB
------BEGIN CERTIFICATE-----
-MIIENTCCA56gAwIBAgIEBAADyzANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJV
-UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU
-cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds
-b2JhbCBSb290MB4XDTA1MDIxNjE5MTQwMFoXDTEyMDIxNjIzNTkwMFowPDEXMBUG
-A1UEChMOR2xvYmFsU2lnbiBJbmMxITAfBgNVBAMTGEN5YmVydHJ1c3QgU3VyZVNl
-cnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkqaiCFnesi
-GjFZiQMdiKc4X/Iaoe2eB3fPOb/J5uZCbmZDm11x9bIitnrOzBU4tYbFhe8inKQu
-jOSyMYik5bHw2hfr5BIdi8rgy+d90Vj/BrjPiqYL7ZSSgy6UAv1G6EnRNEAc1e/F
-LiicRK8Y5WQ9fsW+l2TAyDpNIqwk2KdMF3R+zOW4tOhHQjcUyLPHPknNgeiX1Qoe
-MSFgS0be3XxKnzrPcLUIpPU+VIjjnldmqgkvFPW4KOR8rCR85kn201OTZ+GZMjuf
-rKNv6XF0oGksWC6cD/DqxN+oqgMuBdaoTR7gEhPxU1VM1Uzk7P7qNa1o7mZDE9kr
-rp79Y2LjdYkCAwEAAaOCAYUwggGBMEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly93
-d3cucHVibGljLXRydXN0LmNvbS9jZ2ktYmluL0NSTC8yMDE4L2NkcC5jcmwwHQYD
-VR0OBBYEFCs3U5NkR2YjTwDT993oMLZbhIkjMFUGA1UdIAROMEwwSgYJKwYBBAGx
-PgEyMD0wOwYIKwYBBQUHAgEWL2h0dHA6Ly93d3cucHVibGljLXRydXN0LmNvbS9D
-UFMvU3VyZVNlcnZlci5odG1sMIGgBgNVHSMEgZgwgZWAFKYMHZ9h/wcXtb84RttD
-MNWOsFIGoXmkdzB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0
-aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAh
-BgNVBAMTGkdURSBDeWJlclRydXN0IEdsb2JhbCBSb290ggIBpTAOBgNVHQ8BAf8E
-BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQBfaMVGftRn
-1WLz/Ppk3JFVlZnYMoRxf3ZqtHECyzlZr1Uv68wwca9InU+OYsThHhS33XMrEj2b
-0ADXUBUlgI9DpeepNqh90DInMMYDsH7YjwW5Z2kfRlSYudDpIp5nzy+OB1nY5Ylq
-XlijuEEzFlNeUHO8dn+qQZwz/xUCLnXE6w==
------END CERTIFICATE-----
-
 subject= /C=PL/O=Unizeto Technologies S.A./OU=Certum Certification Authority/CN=Certum Level III CA
 serial=047A53
 -----BEGIN CERTIFICATE-----
@@ -7252,35 +7224,6 @@
 DC1rrFMhoPE=
 -----END CERTIFICATE-----
 
-subject= /C=IT/O=Postecom S.p.A./OU=Servizi Certification Authority/CN=Postecom CS2
-serial=040003CC
------BEGIN CERTIFICATE-----
-MIIEVjCCA7+gAwIBAgIEBAADzDANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJV
-UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU
-cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds
-b2JhbCBSb290MB4XDTA1MDIxNjE5MTYwMFoXDTEyMDIxNjIzNTkwMFowaDELMAkG
-A1UEBhMCSVQxGDAWBgNVBAoTD1Bvc3RlY29tIFMucC5BLjEoMCYGA1UECxMfU2Vy
-dml6aSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEVMBMGA1UEAxMMUG9zdGVjb20g
-Q1MyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqbSsVrz3ITxO8EXN
-rVuNyP94oJUNYysYq8vvVLt+eIJUZDy3zZpVFXH69WOohNmrXZp9RnpAc07KYC7+
-M+5ywcwgn0k/+GwGz7FvCBHcUTSrXq6ptYQfDdSxv/0COLbjZnrJnPapCnI+Nr2X
-qQz38kpJx0v2u5q4WzcOB7x3ZpMS30x4m+x1gg/WMN0zrExpbdIOUX/BnzyAmcBl
-HkpV3waU8gz+znCLSsLKAZDSNKlIEq9bvetSqP+W6XdqjzGPKJBLs0D6o9S7Ujy8
-BLYGCf6uODamiB7cCRr7N70ytt4BuFn1v3QkxOSXNcABJFb9I9xmBQVHqfC5FSjU
-yXoEVwIDAQABo4IBejCCAXYwRQYDVR0fBD4wPDA6oDigNoY0aHR0cDovL3d3dy5w
-dWJsaWMtdHJ1c3QuY29tL2NnaS1iaW4vQ1JMLzIwMTgvY2RwLmNybDAdBgNVHQ4E
-FgQUQxMF4OsnRk1IVlzcFQ/BNxTbgEcwXgYDVR0gBFcwVTBIBgkrBgEEAbE+AQAw
-OzA5BggrBgEFBQcCARYtaHR0cDovL3d3dy5wdWJsaWMtdHJ1c3QuY29tL0NQUy9P
-bW5pUm9vdC5odG1sMAkGBytMCwEBAwEwgYkGA1UdIwSBgTB/oXmkdzB1MQswCQYD
-VQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUg
-Q3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRy
-dXN0IEdsb2JhbCBSb290ggIBpTAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgw
-BgEB/wIBADANBgkqhkiG9w0BAQUFAAOBgQCBNAklVdNAFUEq0hJSri2X05d51Qqx
-6bYlCNnclX9jmTRkU/0PGGU1AefCYCqLnnHjrCoGbcHoRivB5MmMVO60/ypT87A1
-6EpaF5/AMq3qFBcOZ5sj/vBMK16f2esCJ/N1xmKkkY6CTa3A/SLYq1tjb1TXA7/1
-q2ILed+P+e6ijg==
------END CERTIFICATE-----
-
 subject= /C=US/O=WoSign, Inc./CN=WoSign Premium Server Authority
 serial=64D1B8FD4F3656C28DC536B5D5AEA2E4
 -----BEGIN CERTIFICATE-----
@@ -8301,36 +8244,6 @@
 bxQe3FL+vN8MvSk/dvsRX2hoFQ==
 -----END CERTIFICATE-----
 
-subject= /C=US/O=Network Solutions L.L.C./CN=Network Solutions Certificate Authority
-serial=040003C5
------BEGIN CERTIFICATE-----
-MIIEkDCCA/mgAwIBAgIEBAADxTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJV
-UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU
-cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds
-b2JhbCBSb290MB4XDTA1MDIwODE5MTcwMFoXDTEyMDIwODIzNTkwMFowYjELMAkG
-A1UEBhMCVVMxITAfBgNVBAoTGE5ldHdvcmsgU29sdXRpb25zIEwuTC5DLjEwMC4G
-A1UEAxMnTmV0d29yayBTb2x1dGlvbnMgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIIB
-IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy62ek00PKRG9e0xcFYe1uFMJ
-SGhRtkiY9sqYZaIEuaWpngf7vuUJd7ZoUuO6lEQuYI18QWWRMZ9sJUV1I1qN2csv
-OKNsI8MA5dFSH8cq+ur+dCvprS3xll+MBFjCAw9ArcatppLD1L9YUNBLMWjwXIDO
-G5K17tMbeNA2dQu4uCAqa2R7nJPaBhssGH7ZcgsnxFWy1vMla3A4nzd99/C7rwJI
-EiDtM1GFPl7cv1s2bBUnqHIoEzH9nWkAWBJATcqkxH189iu4bFxv4TQfeEq1CIF0
-qmSOUBKNu2JKsjYC2fXlWTTjJ0oJr77Y02tZzIR11kBu6Zsyt+8/cRp0d4UvywID
-AQABo4IBujCCAbYwRQYDVR0fBD4wPDA6oDigNoY0aHR0cDovL3d3dy5wdWJsaWMt
-dHJ1c3QuY29tL2NnaS1iaW4vQ1JMLzIwMTgvY2RwLmNybDAdBgNVHQ4EFgQUAbmY
-lDcvUo5mlZdgiFn32IWb94cwgZ0GA1UdIASBlTCBkjBIBgkrBgEEAbE+AQAwOzA5
-BggrBgEFBQcCARYtaHR0cDovL3d3dy5wdWJsaWMtdHJ1c3QuY29tL0NQUy9PbW5p
-Um9vdC5odG1sMEYGDCsGAQQBhg4BAgEDATA2MDQGCCsGAQUFBwIBFihodHRwczov
-L3d3dy5uZXRzb2xzc2wuY29tL3JlcG9zaXRvcnkvQ1BTMIGJBgNVHSMEgYEwf6F5
-pHcwdTELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD0dURSBDb3Jwb3JhdGlvbjEnMCUG
-A1UECxMeR1RFIEN5YmVyVHJ1c3QgU29sdXRpb25zLCBJbmMuMSMwIQYDVQQDExpH
-VEUgQ3liZXJUcnVzdCBHbG9iYWwgUm9vdIICAaUwDgYDVR0PAQH/BAQDAgEGMBIG
-A1UdEwEB/wQIMAYBAf8CAQAwDQYJKoZIhvcNAQEFBQADgYEAfEk2kSeNpHd6WV9C
-KQFPt782VaUow9rXZRFxvs68pOwd8ktobk2ITkTt8LIBRxMERxATH4JFB1HxWJQ9
-6uJLVPn5TNrQbDwyDQiFJDxQcODMMlOTbq6fH3bk3E+nK1z2Ow5aerOu+Ga4l1eT
-UpSTSVSzHX3qMgtALXAfqCUFvoc=
------END CERTIFICATE-----
-
 subject= /O=Deutsche Post World Net/OU=I2 PS/CN=DPWN SSL CA I2 PS
 serial=1AEA8B42000000000006
 -----BEGIN CERTIFICATE-----
diff --git a/lib/google-api-python-client/MANIFEST.in b/lib/google-api-python-client/MANIFEST.in
index 2034f57..6ccb0b2 100644
--- a/lib/google-api-python-client/MANIFEST.in
+++ b/lib/google-api-python-client/MANIFEST.in
@@ -1,19 +1,16 @@
 recursive-include tests *.py *.json
-recursive-include functional_tests *.py
-recursive-include httplib2 *.py
+recursive-include tests/data *.json *.sh *.p12 *.pem *.jpg *.png
 recursive-include uritemplate *.py
 recursive-include apiclient *.json *.py
-recursive-include oauth2 *.py
 recursive-include docs *.html
-recursive-include simplejson *.py *.c
 recursive-include samples *.py *.png *.html *.yaml *.json
 include samples/gtaskqueue_sample/gtaskqueue/gen_appengine_access_token
 include samples/gtaskqueue_sample/gtaskqueue/gtaskqueue
 include samples/gtaskqueue_sample/gtaskqueue/gtaskqueue_puller
 include runtests.py
+include CHANGELOG
+include README
+include FAQ
 include runsamples.py
 include setpath.sh
-include setup_utils.py
-include gflags.py
-include gflags_validators.py
 include bin/enable-app-engine-project
diff --git a/lib/google-api-python-client/README b/lib/google-api-python-client/README
index 35ba3da..48ed3a9 100644
--- a/lib/google-api-python-client/README
+++ b/lib/google-api-python-client/README
@@ -1,5 +1,4 @@
-This is a prototype implementation of a client
-for discovery based APIs.
+This is python client library for Google's discovery based APIs.
 
 
 Installation
@@ -7,26 +6,19 @@
 
 To install, simply say
 
-   $ python setup.py install
-
-If you want to do a "mock install" and simply extend your PYTHONPATH
-for the current shell to include this folder and the packages in it, do
-
-   $ source setpath.sh
-
-from the root of the project directory.
+   $ easy_install --upgrade google-api-python-client
 
 
 Running
 =======
 
 After following the install directions (using setup.py or setpath.sh) you
-should be able to cd to samples/buzz and run buzz.py from there, which will use
-the apiclient library to retrieve the title of the most recent entry in Buzz
-and post a test message.  The first time you run it you will be prompted to
-authorize the application to access your Buzz information.
+should be able to cd to samples/plus and run plus.py from there, which will use
+the apiclient library to retrieve a snippet of text from each entry in Google
+Plus. The first time you run it you will be prompted to authorize the
+application to access your plus information.
 
-   $ python samples/buzz/buzz.py
+   $ python samples/plus/plus.py
 
 
 Third Party Libraries
diff --git a/lib/google-api-python-client/apiclient/contrib/buzz/__init__.py b/lib/google-api-python-client/apiclient/contrib/buzz/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/lib/google-api-python-client/apiclient/contrib/buzz/__init__.py
+++ /dev/null
diff --git a/lib/google-api-python-client/apiclient/contrib/buzz/future.json b/lib/google-api-python-client/apiclient/contrib/buzz/future.json
deleted file mode 100644
index 05018e8..0000000
--- a/lib/google-api-python-client/apiclient/contrib/buzz/future.json
+++ /dev/null
@@ -1,142 +0,0 @@
-{
-        "baseUrl": "https://www.googleapis.com/", 
-        "auth": {
-          "request": {
-            "url": "https://www.google.com/accounts/OAuthGetRequestToken",
-            "parameters": {
-              "xoauth_displayname": {
-                "parameterType": "query",
-                "required": false
-              },
-              "domain": {
-                "parameterType": "query",
-                "required": true
-              },
-              "scope": {
-                "parameterType": "query",
-                "required": true
-              }
-            }
-          },
-          "authorize": {
-            "url": "https://www.google.com/buzz/api/auth/OAuthAuthorizeToken",
-            "parameters": {
-              "oauth_token": {
-                "parameterType": "query",
-                "required": true
-              },
-              "iconUrl": {
-                "parameterType": "query",
-                "required": false
-              },
-              "domain": {
-                "parameterType": "query",
-                "required": true
-              },
-              "scope": {
-                "parameterType": "query",
-                "required": true
-              }
-            }
-          },
-          "access": {
-            "url": "https://www.google.com/accounts/OAuthGetAccessToken",
-            "parameters": {
-              "domain": {
-                "parameterType": "query",
-                "required": true
-              },
-              "scope": {
-                "parameterType": "query",
-                "required": true
-              }
-            }
-          }
-        },
-        "resources": {
-          "activities": {
-            "methods": {
-              "delete": {}, 
-              "extractPeopleFromSearch": {}, 
-              "get": {}, 
-              "insert": {}, 
-              "list": {
-                "next": {
-                  "type": "uri",
-                  "location": ["links", "next", 0, "href"]
-                }
-              }, 
-              "search": {
-                "next": {
-                  "type": "uri",
-                  "location": ["links", "next", 0, "href"]
-                }
-              }, 
-              "update": {}
-            }
-          }, 
-          "comments": {
-            "methods": {
-              "delete": {}, 
-              "get": {}, 
-              "insert": {}, 
-              "list": {}, 
-              "update": {}
-            }
-          }, 
-          "feeds": {
-            "methods": {
-              "delete": {}, 
-              "insert": {}, 
-              "list": {}, 
-              "update": {}
-            }
-          }, 
-          "groups": {
-            "methods": {
-              "delete": {}, 
-              "get": {}, 
-              "insert": {}, 
-              "list": {
-                "next": {
-                  "type": "uri",
-                  "location": ["links", "next", 0, "href"]
-                }
-              }, 
-              "update": {}
-            }
-          }, 
-          "people": {
-            "methods": {
-              "delete": {}, 
-              "get": {}, 
-              "liked": {
-                "next": {
-                  "type": "uri",
-                  "location": ["links", "next", 0, "href"]
-                }
-              },
-              "list": {}, 
-              "relatedToUri": {}, 
-              "reshared": {}, 
-              "search": {}, 
-              "update": {}
-            }
-          }, 
-          "photos": {
-            "methods": {
-              "insert": {}
-            }
-          }, 
-          "related": {
-            "methods": {
-              "list": {}
-            }
-          }, 
-          "search": {
-            "methods": {
-              "extractPeople": {}
-            }
-          }
-        }
-}
diff --git a/lib/google-api-python-client/apiclient/discovery.py b/lib/google-api-python-client/apiclient/discovery.py
index 7cb4852..a0ca930 100644
--- a/lib/google-api-python-client/apiclient/discovery.py
+++ b/lib/google-api-python-client/apiclient/discovery.py
@@ -26,6 +26,7 @@
 import httplib2
 import logging
 import os
+import random
 import re
 import uritemplate
 import urllib
@@ -38,16 +39,22 @@
 except ImportError:
     from cgi import parse_qsl
 
-from anyjson import simplejson
+from apiclient.errors import HttpError
+from apiclient.errors import InvalidJsonError
+from apiclient.errors import MediaUploadSizeError
+from apiclient.errors import UnacceptableMimeTypeError
+from apiclient.errors import UnknownApiNameOrVersion
+from apiclient.errors import UnknownLinkType
+from apiclient.http import HttpRequest
+from apiclient.http import MediaFileUpload
+from apiclient.http import MediaUpload
+from apiclient.model import JsonModel
+from apiclient.model import RawModel
+from apiclient.schema import Schemas
 from email.mime.multipart import MIMEMultipart
 from email.mime.nonmultipart import MIMENonMultipart
-from errors import HttpError
-from errors import InvalidJsonError
-from errors import MediaUploadSizeError
-from errors import UnacceptableMimeTypeError
-from errors import UnknownLinkType
-from http import HttpRequest
-from model import JsonModel
+from oauth2client.anyjson import simplejson
+
 
 URITEMPLATE = re.compile('{[^}]*}')
 VARNAME = re.compile('[a-zA-Z0-9_-]+')
@@ -156,10 +163,10 @@
 
   requested_url = uritemplate.expand(discoveryServiceUrl, params)
 
-  # REMOTE_ADDR is defined by the CGI spec [RFC3875] as the environment variable
-  # that contains the network address of the client sending the request. If it
-  # exists then add that to the request for the discovery document to avoid
-  # exceeding the quota on discovery requests.
+  # REMOTE_ADDR is defined by the CGI spec [RFC3875] as the environment
+  # variable that contains the network address of the client sending the
+  # request. If it exists then add that to the request for the discovery
+  # document to avoid exceeding the quota on discovery requests.
   if 'REMOTE_ADDR' in os.environ:
     requested_url = _add_query_parameter(requested_url, 'userIp',
                                          os.environ['REMOTE_ADDR'])
@@ -167,6 +174,9 @@
 
   resp, content = http.request(requested_url)
 
+  if resp.status == 404:
+    raise UnknownApiNameOrVersion("name: %s  version: %s" % (serviceName,
+                                                            version))
   if resp.status >= 400:
     raise HttpError(resp, content, requested_url)
 
@@ -229,7 +239,7 @@
   else:
     future = {}
     auth_discovery = {}
-  schema = service.get('schemas', {})
+  schema = Schemas(service)
 
   if model is None:
     features = service.get('features', [])
@@ -321,6 +331,7 @@
     if 'mediaUpload' in methodDesc:
       mediaUpload = methodDesc['mediaUpload']
       mediaPathUrl = mediaUpload['protocols']['simple']['path']
+      mediaResumablePathUrl = mediaUpload['protocols']['resumable']['path']
       accept = mediaUpload['accept']
       maxSize = _media_size_to_long(mediaUpload.get('maxSize', ''))
 
@@ -332,18 +343,23 @@
           'location': 'query'
           }
 
-    if httpMethod in ['PUT', 'POST', 'PATCH']:
+    if httpMethod in ['PUT', 'POST', 'PATCH'] and 'request' in methodDesc:
       methodDesc['parameters']['body'] = {
           'description': 'The request body.',
           'type': 'object',
           'required': True,
           }
-      if 'mediaUpload' in methodDesc:
-        methodDesc['parameters']['media_body'] = {
-            'description': 'The filename of the media request body.',
-            'type': 'string',
-            'required': False,
-            }
+      if 'request' in methodDesc:
+        methodDesc['parameters']['body'].update(methodDesc['request'])
+      else:
+        methodDesc['parameters']['body']['type'] = 'object'
+    if 'mediaUpload' in methodDesc:
+      methodDesc['parameters']['media_body'] = {
+          'description': 'The filename of the media request body.',
+          'type': 'string',
+          'required': False,
+          }
+      if 'body' in methodDesc['parameters']:
         methodDesc['parameters']['body']['required'] = False
 
     argmap = {} # Map from method parameter name to query parameter name
@@ -393,10 +409,15 @@
 
       for name, regex in pattern_params.iteritems():
         if name in kwargs:
-          if re.match(regex, kwargs[name]) is None:
-            raise TypeError(
-                'Parameter "%s" value "%s" does not match the pattern "%s"' %
-                (name, kwargs[name], regex))
+          if isinstance(kwargs[name], basestring):
+            pvalues = [kwargs[name]]
+          else:
+            pvalues = kwargs[name]
+          for pvalue in pvalues:
+            if re.match(regex, pvalue) is None:
+              raise TypeError(
+                  'Parameter "%s" value "%s" does not match the pattern "%s"' %
+                  (name, pvalue, regex))
 
       for name, enums in enum_params.iteritems():
         if name in kwargs:
@@ -424,67 +445,89 @@
       if self._developerKey:
         actual_query_params['key'] = self._developerKey
 
+      model = self._model
+      # If there is no schema for the response then presume a binary blob.
+      if 'response' not in methodDesc:
+        model = RawModel()
+
       headers = {}
-      headers, params, query, body = self._model.request(headers,
+      headers, params, query, body = model.request(headers,
           actual_path_params, actual_query_params, body_value)
 
       expanded_url = uritemplate.expand(pathUrl, params)
       url = urlparse.urljoin(self._baseUrl, expanded_url + query)
 
+      resumable = None
+      multipart_boundary = ''
+
       if media_filename:
-        (media_mime_type, encoding) = mimetypes.guess_type(media_filename)
-        if media_mime_type is None:
-          raise UnknownFileType(media_filename)
-        if not mimeparse.best_match([media_mime_type], ','.join(accept)):
-          raise UnacceptableMimeTypeError(media_mime_type)
+        # Ensure we end up with a valid MediaUpload object.
+        if isinstance(media_filename, basestring):
+          (media_mime_type, encoding) = mimetypes.guess_type(media_filename)
+          if media_mime_type is None:
+            raise UnknownFileType(media_filename)
+          if not mimeparse.best_match([media_mime_type], ','.join(accept)):
+            raise UnacceptableMimeTypeError(media_mime_type)
+          media_upload = MediaFileUpload(media_filename, media_mime_type)
+        elif isinstance(media_filename, MediaUpload):
+          media_upload = media_filename
+        else:
+          raise TypeError('media_filename must be str or MediaUpload.')
 
         # Check the maxSize
-        if maxSize > 0 and os.path.getsize(media_filename) > maxSize:
-          raise MediaUploadSizeError(media_filename)
+        if maxSize > 0 and media_upload.size() > maxSize:
+          raise MediaUploadSizeError("Media larger than: %s" % maxSize)
 
         # Use the media path uri for media uploads
-        expanded_url = uritemplate.expand(mediaPathUrl, params)
+        if media_upload.resumable():
+          expanded_url = uritemplate.expand(mediaResumablePathUrl, params)
+        else:
+          expanded_url = uritemplate.expand(mediaPathUrl, params)
         url = urlparse.urljoin(self._baseUrl, expanded_url + query)
 
-        if body is None:
-          headers['content-type'] = media_mime_type
-          # make the body the contents of the file
-          f = file(media_filename, 'rb')
-          body = f.read()
-          f.close()
+        if media_upload.resumable():
+          # This is all we need to do for resumable, if the body exists it gets
+          # sent in the first request, otherwise an empty body is sent.
+          resumable = media_upload
         else:
-          msgRoot = MIMEMultipart('related')
-          # msgRoot should not write out it's own headers
-          setattr(msgRoot, '_write_headers', lambda self: None)
+          # A non-resumable upload
+          if body is None:
+            # This is a simple media upload
+            headers['content-type'] = media_upload.mimetype()
+            body = media_upload.getbytes(0, media_upload.size())
+          else:
+            # This is a multipart/related upload.
+            msgRoot = MIMEMultipart('related')
+            # msgRoot should not write out it's own headers
+            setattr(msgRoot, '_write_headers', lambda self: None)
 
-          # attach the body as one part
-          msg = MIMENonMultipart(*headers['content-type'].split('/'))
-          msg.set_payload(body)
-          msgRoot.attach(msg)
+            # attach the body as one part
+            msg = MIMENonMultipart(*headers['content-type'].split('/'))
+            msg.set_payload(body)
+            msgRoot.attach(msg)
 
-          # attach the media as the second part
-          msg = MIMENonMultipart(*media_mime_type.split('/'))
-          msg['Content-Transfer-Encoding'] = 'binary'
+            # attach the media as the second part
+            msg = MIMENonMultipart(*media_upload.mimetype().split('/'))
+            msg['Content-Transfer-Encoding'] = 'binary'
 
-          f = file(media_filename, 'rb')
-          msg.set_payload(f.read())
-          f.close()
-          msgRoot.attach(msg)
+            payload = media_upload.getbytes(0, media_upload.size())
+            msg.set_payload(payload)
+            msgRoot.attach(msg)
+            body = msgRoot.as_string()
 
-          body = msgRoot.as_string()
-
-          # must appear after the call to as_string() to get the right boundary
-          headers['content-type'] = ('multipart/related; '
-                                     'boundary="%s"') % msgRoot.get_boundary()
+            multipart_boundary = msgRoot.get_boundary()
+            headers['content-type'] = ('multipart/related; '
+                                       'boundary="%s"') % multipart_boundary
 
       logging.info('URL being requested: %s' % url)
       return self._requestBuilder(self._http,
-                                  self._model.response,
+                                  model.response,
                                   url,
                                   method=httpMethod,
                                   body=body,
                                   headers=headers,
-                                  methodId=methodId)
+                                  methodId=methodId,
+                                  resumable=resumable)
 
     docs = [methodDesc.get('description', DEFAULT_METHOD_DOC), '\n\n']
     if len(argmap) > 0:
@@ -500,15 +543,24 @@
         required = ' (required)'
       paramdesc = methodDesc['parameters'][argmap[arg]]
       paramdoc = paramdesc.get('description', 'A parameter')
-      paramtype = paramdesc.get('type', 'string')
-      docs.append('  %s: %s, %s%s%s\n' % (arg, paramtype, paramdoc, required,
-                                          repeated))
+      if '$ref' in paramdesc:
+        docs.append(
+            ('  %s: object, %s%s%s\n    The object takes the'
+            ' form of:\n\n%s\n\n') % (arg, paramdoc, required, repeated,
+              schema.prettyPrintByName(paramdesc['$ref'])))
+      else:
+        paramtype = paramdesc.get('type', 'string')
+        docs.append('  %s: %s, %s%s%s\n' % (arg, paramtype, paramdoc, required,
+                                            repeated))
       enum = paramdesc.get('enum', [])
       enumDesc = paramdesc.get('enumDescriptions', [])
       if enum and enumDesc:
         docs.append('    Allowed values\n')
         for (name, desc) in zip(enum, enumDesc):
           docs.append('      %s - %s\n' % (name, desc))
+    if 'response' in methodDesc:
+      docs.append('\nReturns:\n  An object of the form\n\n    ')
+      docs.append(schema.prettyPrintSchema(methodDesc['response']))
 
     setattr(method, '__doc__', ''.join(docs))
     setattr(theclass, methodName, method)
@@ -600,7 +652,6 @@
 
     setattr(theclass, methodName, methodNext)
 
-
   # Add basic methods to Resource
   if 'methods' in resourceDesc:
     for methodName, methodDesc in resourceDesc['methods'].iteritems():
@@ -647,7 +698,7 @@
       if 'response' in methodDesc:
         responseSchema = methodDesc['response']
         if '$ref' in responseSchema:
-          responseSchema = schema[responseSchema['$ref']]
+          responseSchema = schema.get(responseSchema['$ref'])
         hasNextPageToken = 'nextPageToken' in responseSchema.get('properties',
                                                                  {})
         hasPageToken = 'pageToken' in methodDesc.get('parameters', {})
diff --git a/lib/google-api-python-client/apiclient/errors.py b/lib/google-api-python-client/apiclient/errors.py
index c017912..b6ee9a5 100644
--- a/lib/google-api-python-client/apiclient/errors.py
+++ b/lib/google-api-python-client/apiclient/errors.py
@@ -23,7 +23,7 @@
 __author__ = 'jcgregorio@google.com (Joe Gregorio)'
 
 
-from anyjson import simplejson
+from oauth2client.anyjson import simplejson
 
 
 class Error(Exception):
@@ -71,6 +71,11 @@
   pass
 
 
+class UnknownApiNameOrVersion(Error):
+  """No API with that name and version exists."""
+  pass
+
+
 class UnacceptableMimeTypeError(Error):
   """That is an unacceptable mimetype for this operation."""
   pass
@@ -81,6 +86,25 @@
   pass
 
 
+class ResumableUploadError(Error):
+  """Error occured during resumable upload."""
+  pass
+
+
+class BatchError(HttpError):
+  """Error occured during batch operations."""
+
+  def __init__(self, reason, resp=None, content=None):
+    self.resp = resp
+    self.content = content
+    self.reason = reason
+
+  def __repr__(self):
+      return '<BatchError %s "%s">' % (self.resp.status, self.reason)
+
+  __str__ = __repr__
+
+
 class UnexpectedMethodError(Error):
   """Exception raised by RequestMockBuilder on unexpected calls."""
 
diff --git a/lib/google-api-python-client/apiclient/http.py b/lib/google-api-python-client/apiclient/http.py
index 081a4ed..8e15e11 100644
--- a/lib/google-api-python-client/apiclient/http.py
+++ b/lib/google-api-python-client/apiclient/http.py
@@ -25,25 +25,206 @@
     'set_user_agent', 'tunnel_patch'
     ]
 
+import StringIO
+import copy
+import gzip
 import httplib2
+import mimeparse
+import mimetypes
 import os
+import urllib
+import urlparse
+import uuid
 
-from model import JsonModel
+from email.mime.multipart import MIMEMultipart
+from email.mime.nonmultipart import MIMENonMultipart
+from email.parser import FeedParser
+from errors import BatchError
 from errors import HttpError
+from errors import ResumableUploadError
 from errors import UnexpectedBodyError
 from errors import UnexpectedMethodError
-from anyjson import simplejson
+from model import JsonModel
+from oauth2client.anyjson import simplejson
+
+
+class MediaUploadProgress(object):
+  """Status of a resumable upload."""
+
+  def __init__(self, resumable_progress, total_size):
+    """Constructor.
+
+    Args:
+      resumable_progress: int, bytes sent so far.
+      total_size: int, total bytes in complete upload.
+    """
+    self.resumable_progress = resumable_progress
+    self.total_size = total_size
+
+  def progress(self):
+    """Percent of upload completed, as a float."""
+    return float(self.resumable_progress) / float(self.total_size)
+
+
+class MediaUpload(object):
+  """Describes a media object to upload.
+
+  Base class that defines the interface of MediaUpload subclasses.
+  """
+
+  def getbytes(self, begin, end):
+    raise NotImplementedError()
+
+  def size(self):
+    raise NotImplementedError()
+
+  def chunksize(self):
+    raise NotImplementedError()
+
+  def mimetype(self):
+    return 'application/octet-stream'
+
+  def resumable(self):
+    return False
+
+  def _to_json(self, strip=None):
+    """Utility function for creating a JSON representation of a MediaUpload.
+
+    Args:
+      strip: array, An array of names of members to not include in the JSON.
+
+    Returns:
+       string, a JSON representation of this instance, suitable to pass to
+       from_json().
+    """
+    t = type(self)
+    d = copy.copy(self.__dict__)
+    if strip is not None:
+      for member in strip:
+        del d[member]
+    d['_class'] = t.__name__
+    d['_module'] = t.__module__
+    return simplejson.dumps(d)
+
+  def to_json(self):
+    """Create a JSON representation of an instance of MediaUpload.
+
+    Returns:
+       string, a JSON representation of this instance, suitable to pass to
+       from_json().
+    """
+    return self._to_json()
+
+  @classmethod
+  def new_from_json(cls, s):
+    """Utility class method to instantiate a MediaUpload subclass from a JSON
+    representation produced by to_json().
+
+    Args:
+      s: string, JSON from to_json().
+
+    Returns:
+      An instance of the subclass of MediaUpload that was serialized with
+      to_json().
+    """
+    data = simplejson.loads(s)
+    # Find and call the right classmethod from_json() to restore the object.
+    module = data['_module']
+    m = __import__(module, fromlist=module.split('.')[:-1])
+    kls = getattr(m, data['_class'])
+    from_json = getattr(kls, 'from_json')
+    return from_json(s)
+
+
+class MediaFileUpload(MediaUpload):
+  """A MediaUpload for a file.
+
+  Construct a MediaFileUpload and pass as the media_body parameter of the
+  method. For example, if we had a service that allowed uploading images:
+
+
+    media = MediaFileUpload('smiley.png', mimetype='image/png', chunksize=1000,
+                    resumable=True)
+    service.objects().insert(
+        bucket=buckets['items'][0]['id'],
+        name='smiley.png',
+        media_body=media).execute()
+  """
+
+  def __init__(self, filename, mimetype=None, chunksize=256*1024, resumable=False):
+    """Constructor.
+
+    Args:
+      filename: string, Name of the file.
+      mimetype: string, Mime-type of the file. If None then a mime-type will be
+        guessed from the file extension.
+      chunksize: int, File will be uploaded in chunks of this many bytes. Only
+        used if resumable=True.
+      resumable: bool, True if this is a resumable upload. False means upload
+        in a single request.
+    """
+    self._filename = filename
+    self._size = os.path.getsize(filename)
+    self._fd = None
+    if mimetype is None:
+      (mimetype, encoding) = mimetypes.guess_type(filename)
+    self._mimetype = mimetype
+    self._chunksize = chunksize
+    self._resumable = resumable
+
+  def mimetype(self):
+    return self._mimetype
+
+  def size(self):
+    return self._size
+
+  def chunksize(self):
+    return self._chunksize
+
+  def resumable(self):
+    return self._resumable
+
+  def getbytes(self, begin, length):
+    """Get bytes from the media.
+
+    Args:
+      begin: int, offset from beginning of file.
+      length: int, number of bytes to read, starting at begin.
+
+    Returns:
+      A string of bytes read. May be shorted than length if EOF was reached
+      first.
+    """
+    if self._fd is None:
+      self._fd = open(self._filename, 'rb')
+    self._fd.seek(begin)
+    return self._fd.read(length)
+
+  def to_json(self):
+    """Creating a JSON representation of an instance of Credentials.
+
+    Returns:
+       string, a JSON representation of this instance, suitable to pass to
+       from_json().
+    """
+    return self._to_json(['_fd'])
+
+  @staticmethod
+  def from_json(s):
+    d = simplejson.loads(s)
+    return MediaFileUpload(
+        d['_filename'], d['_mimetype'], d['_chunksize'], d['_resumable'])
 
 
 class HttpRequest(object):
-  """Encapsulates a single HTTP request.
-  """
+  """Encapsulates a single HTTP request."""
 
   def __init__(self, http, postproc, uri,
                method='GET',
                body=None,
                headers=None,
-               methodId=None):
+               methodId=None,
+               resumable=None):
     """Constructor for an HttpRequest.
 
     Args:
@@ -53,16 +234,32 @@
                 on an error.
       uri: string, the absolute URI to send the request to
       method: string, the HTTP method to use
-      body: string, the request body of the HTTP request
+      body: string, the request body of the HTTP request,
       headers: dict, the HTTP request headers
       methodId: string, a unique identifier for the API method being called.
+      resumable: MediaUpload, None if this is not a resumbale request.
     """
     self.uri = uri
     self.method = method
     self.body = body
     self.headers = headers or {}
+    self.methodId = methodId
     self.http = http
     self.postproc = postproc
+    self.resumable = resumable
+
+    # Pull the multipart boundary out of the content-type header.
+    major, minor, params = mimeparse.parse_mime_type(
+        headers.get('content-type', 'application/json'))
+
+    # The size of the non-media part of the request.
+    self.body_size = len(self.body or '')
+
+    # The resumable URI to send chunks to.
+    self.resumable_uri = None
+
+    # The bytes that have been uploaded.
+    self.resumable_progress = 0
 
   def execute(self, http=None):
     """Execute the request.
@@ -81,13 +278,388 @@
     """
     if http is None:
       http = self.http
-    resp, content = http.request(self.uri, self.method,
-                                      body=self.body,
-                                      headers=self.headers)
+    if self.resumable:
+      body = None
+      while body is None:
+        _, body = self.next_chunk(http)
+      return body
+    else:
+      resp, content = http.request(self.uri, self.method,
+                                   body=self.body,
+                                   headers=self.headers)
+
+      if resp.status >= 300:
+        raise HttpError(resp, content, self.uri)
+    return self.postproc(resp, content)
+
+  def next_chunk(self, http=None):
+    """Execute the next step of a resumable upload.
+
+    Can only be used if the method being executed supports media uploads and
+    the MediaUpload object passed in was flagged as using resumable upload.
+
+    Example:
+
+      media = MediaFileUpload('smiley.png', mimetype='image/png',
+                              chunksize=1000, resumable=True)
+      request = service.objects().insert(
+          bucket=buckets['items'][0]['id'],
+          name='smiley.png',
+          media_body=media)
+
+      response = None
+      while response is None:
+        status, response = request.next_chunk()
+        if status:
+          print "Upload %d%% complete." % int(status.progress() * 100)
+
+
+    Returns:
+      (status, body): (ResumableMediaStatus, object)
+         The body will be None until the resumable media is fully uploaded.
+    """
+    if http is None:
+      http = self.http
+
+    if self.resumable_uri is None:
+      start_headers = copy.copy(self.headers)
+      start_headers['X-Upload-Content-Type'] = self.resumable.mimetype()
+      start_headers['X-Upload-Content-Length'] = str(self.resumable.size())
+      start_headers['content-length'] = str(self.body_size)
+
+      resp, content = http.request(self.uri, self.method,
+                                   body=self.body,
+                                   headers=start_headers)
+      if resp.status == 200 and 'location' in resp:
+        self.resumable_uri = resp['location']
+      else:
+        raise ResumableUploadError("Failed to retrieve starting URI.")
+
+    data = self.resumable.getbytes(self.resumable_progress,
+                                   self.resumable.chunksize())
+
+    headers = {
+        'Content-Range': 'bytes %d-%d/%d' % (
+            self.resumable_progress, self.resumable_progress + len(data) - 1,
+            self.resumable.size()),
+        }
+    resp, content = http.request(self.resumable_uri, 'PUT',
+                                 body=data,
+                                 headers=headers)
+    if resp.status in [200, 201]:
+      return None, self.postproc(resp, content)
+    elif resp.status == 308:
+      # A "308 Resume Incomplete" indicates we are not done.
+      self.resumable_progress = int(resp['range'].split('-')[1]) + 1
+      if 'location' in resp:
+        self.resumable_uri = resp['location']
+    else:
+      raise HttpError(resp, content, self.uri)
+
+    return (MediaUploadProgress(self.resumable_progress, self.resumable.size()),
+            None)
+
+  def to_json(self):
+    """Returns a JSON representation of the HttpRequest."""
+    d = copy.copy(self.__dict__)
+    if d['resumable'] is not None:
+      d['resumable'] = self.resumable.to_json()
+    del d['http']
+    del d['postproc']
+    return simplejson.dumps(d)
+
+  @staticmethod
+  def from_json(s, http, postproc):
+    """Returns an HttpRequest populated with info from a JSON object."""
+    d = simplejson.loads(s)
+    if d['resumable'] is not None:
+      d['resumable'] = MediaUpload.new_from_json(d['resumable'])
+    return HttpRequest(
+        http,
+        postproc,
+        uri=d['uri'],
+        method=d['method'],
+        body=d['body'],
+        headers=d['headers'],
+        methodId=d['methodId'],
+        resumable=d['resumable'])
+
+
+class BatchHttpRequest(object):
+  """Batches multiple HttpRequest objects into a single HTTP request."""
+
+  def __init__(self, callback=None, batch_uri=None):
+    """Constructor for a BatchHttpRequest.
+
+    Args:
+      callback: callable, A callback to be called for each response, of the
+        form callback(id, response). The first parameter is the request id, and
+        the second is the deserialized response object.
+      batch_uri: string, URI to send batch requests to.
+    """
+    if batch_uri is None:
+      batch_uri = 'https://www.googleapis.com/batch'
+    self._batch_uri = batch_uri
+
+    # Global callback to be called for each individual response in the batch.
+    self._callback = callback
+
+    # A map from id to (request, callback) pairs.
+    self._requests = {}
+
+    # List of request ids, in the order in which they were added.
+    self._order = []
+
+    # The last auto generated id.
+    self._last_auto_id = 0
+
+    # Unique ID on which to base the Content-ID headers.
+    self._base_id = None
+
+  def _id_to_header(self, id_):
+    """Convert an id to a Content-ID header value.
+
+    Args:
+      id_: string, identifier of individual request.
+
+    Returns:
+      A Content-ID header with the id_ encoded into it. A UUID is prepended to
+      the value because Content-ID headers are supposed to be universally
+      unique.
+    """
+    if self._base_id is None:
+      self._base_id = uuid.uuid4()
+
+    return '<%s+%s>' % (self._base_id, urllib.quote(id_))
+
+  def _header_to_id(self, header):
+    """Convert a Content-ID header value to an id.
+
+    Presumes the Content-ID header conforms to the format that _id_to_header()
+    returns.
+
+    Args:
+      header: string, Content-ID header value.
+
+    Returns:
+      The extracted id value.
+
+    Raises:
+      BatchError if the header is not in the expected format.
+    """
+    if header[0] != '<' or header[-1] != '>':
+      raise BatchError("Invalid value for Content-ID: %s" % header)
+    if '+' not in header:
+      raise BatchError("Invalid value for Content-ID: %s" % header)
+    base, id_ = header[1:-1].rsplit('+', 1)
+
+    return urllib.unquote(id_)
+
+  def _serialize_request(self, request):
+    """Convert an HttpRequest object into a string.
+
+    Args:
+      request: HttpRequest, the request to serialize.
+
+    Returns:
+      The request as a string in application/http format.
+    """
+    # Construct status line
+    parsed = urlparse.urlparse(request.uri)
+    request_line = urlparse.urlunparse(
+        (None, None, parsed.path, parsed.params, parsed.query, None)
+        )
+    status_line = request.method + ' ' + request_line + ' HTTP/1.1\n'
+    major, minor = request.headers.get('content-type', 'application/json').split('/')
+    msg = MIMENonMultipart(major, minor)
+    headers = request.headers.copy()
+
+    # MIMENonMultipart adds its own Content-Type header.
+    if 'content-type' in headers:
+      del headers['content-type']
+
+    for key, value in headers.iteritems():
+      msg[key] = value
+    msg['Host'] = parsed.netloc
+    msg.set_unixfrom(None)
+
+    if request.body is not None:
+      msg.set_payload(request.body)
+      msg['content-length'] = str(len(request.body))
+
+    body = msg.as_string(False)
+    # Strip off the \n\n that the MIME lib tacks onto the end of the payload.
+    if request.body is None:
+      body = body[:-2]
+
+    return status_line.encode('utf-8') + body
+
+  def _deserialize_response(self, payload):
+    """Convert string into httplib2 response and content.
+
+    Args:
+      payload: string, headers and body as a string.
+
+    Returns:
+      A pair (resp, content) like would be returned from httplib2.request.
+    """
+    # Strip off the status line
+    status_line, payload = payload.split('\n', 1)
+    protocol, status, reason = status_line.split(' ', 2)
+
+    # Parse the rest of the response
+    parser = FeedParser()
+    parser.feed(payload)
+    msg = parser.close()
+    msg['status'] = status
+
+    # Create httplib2.Response from the parsed headers.
+    resp = httplib2.Response(msg)
+    resp.reason = reason
+    resp.version = int(protocol.split('/', 1)[1].replace('.', ''))
+
+    content = payload.split('\r\n\r\n', 1)[1]
+
+    return resp, content
+
+  def _new_id(self):
+    """Create a new id.
+
+    Auto incrementing number that avoids conflicts with ids already used.
+
+    Returns:
+       string, a new unique id.
+    """
+    self._last_auto_id += 1
+    while str(self._last_auto_id) in self._requests:
+      self._last_auto_id += 1
+    return str(self._last_auto_id)
+
+  def add(self, request, callback=None, request_id=None):
+    """Add a new request.
+
+    Every callback added will be paired with a unique id, the request_id. That
+    unique id will be passed back to the callback when the response comes back
+    from the server. The default behavior is to have the library generate it's
+    own unique id. If the caller passes in a request_id then they must ensure
+    uniqueness for each request_id, and if they are not an exception is
+    raised. Callers should either supply all request_ids or nevery supply a
+    request id, to avoid such an error.
+
+    Args:
+      request: HttpRequest, Request to add to the batch.
+      callback: callable, A callback to be called for this response, of the
+        form callback(id, response). The first parameter is the request id, and
+        the second is the deserialized response object.
+      request_id: string, A unique id for the request. The id will be passed to
+        the callback with the response.
+
+    Returns:
+      None
+
+    Raises:
+      BatchError if a resumable request is added to a batch.
+      KeyError is the request_id is not unique.
+    """
+    if request_id is None:
+      request_id = self._new_id()
+    if request.resumable is not None:
+      raise BatchError("Resumable requests cannot be used in a batch request.")
+    if request_id in self._requests:
+      raise KeyError("A request with this ID already exists: %s" % request_id)
+    self._requests[request_id] = (request, callback)
+    self._order.append(request_id)
+
+  def execute(self, http=None):
+    """Execute all the requests as a single batched HTTP request.
+
+    Args:
+      http: httplib2.Http, an http object to be used in place of the one the
+        HttpRequest request object was constructed with.  If one isn't supplied
+        then use a http object from the requests in this batch.
+
+    Returns:
+      None
+
+    Raises:
+      apiclient.errors.HttpError if the response was not a 2xx.
+      httplib2.Error if a transport error has occured.
+      apiclient.errors.BatchError if the response is the wrong format.
+    """
+    if http is None:
+      for request_id in self._order:
+        request, callback = self._requests[request_id]
+        if request is not None:
+          http = request.http
+          break
+    if http is None:
+      raise ValueError("Missing a valid http object.")
+
+
+    msgRoot = MIMEMultipart('mixed')
+    # msgRoot should not write out it's own headers
+    setattr(msgRoot, '_write_headers', lambda self: None)
+
+    # Add all the individual requests.
+    for request_id in self._order:
+      request, callback = self._requests[request_id]
+
+      msg = MIMENonMultipart('application', 'http')
+      msg['Content-Transfer-Encoding'] = 'binary'
+      msg['Content-ID'] = self._id_to_header(request_id)
+
+      body = self._serialize_request(request)
+      msg.set_payload(body)
+      msgRoot.attach(msg)
+
+    body = msgRoot.as_string()
+
+    headers = {}
+    headers['content-type'] = ('multipart/mixed; '
+                               'boundary="%s"') % msgRoot.get_boundary()
+
+    resp, content = http.request(self._batch_uri, 'POST', body=body,
+                                 headers=headers)
 
     if resp.status >= 300:
-      raise HttpError(resp, content, self.uri)
-    return self.postproc(resp, content)
+      raise HttpError(resp, content, self._batch_uri)
+
+    # Now break up the response and process each one with the correct postproc
+    # and trigger the right callbacks.
+    boundary, _ = content.split(None, 1)
+
+    # Prepend with a content-type header so FeedParser can handle it.
+    header = 'content-type: %s\r\n\r\n' % resp['content-type']
+    for_parser = header + content
+
+    parser = FeedParser()
+    parser.feed(for_parser)
+    respRoot = parser.close()
+
+    if not respRoot.is_multipart():
+      raise BatchError("Response not in multipart/mixed format.", resp,
+          content)
+
+    parts = respRoot.get_payload()
+    for part in parts:
+      request_id = self._header_to_id(part['Content-ID'])
+
+      headers, content = self._deserialize_response(part.get_payload())
+
+      # TODO(jcgregorio) Remove this temporary hack once the server stops
+      # gzipping individual response bodies.
+      if content[0] != '{':
+        gzipped_content = content
+        content = gzip.GzipFile(
+            fileobj=StringIO.StringIO(gzipped_content)).read()
+
+      request, cb = self._requests[request_id]
+      postproc = request.postproc
+      response = postproc(resp, content)
+      if cb is not None:
+        cb(request_id, response)
+      if self._callback is not None:
+        self._callback(request_id, response)
 
 
 class HttpRequestMock(object):
@@ -136,14 +708,14 @@
       response = '{"data": {"id": "tag:google.c...'
       requestBuilder = RequestMockBuilder(
         {
-          'chili.activities.get': (None, response),
+          'plus.activities.get': (None, response),
         }
       )
-      apiclient.discovery.build("buzz", "v1", requestBuilder=requestBuilder)
+      apiclient.discovery.build("plus", "v1", requestBuilder=requestBuilder)
 
     Methods that you do not supply a response for will return a
-    200 OK with an empty string as the response content or raise an excpetion if
-    check_unexpected is set to True. The methodId is taken from the rpcName
+    200 OK with an empty string as the response content or raise an excpetion
+    if check_unexpected is set to True. The methodId is taken from the rpcName
     in the discovery document.
 
     For more details see the project wiki.
@@ -166,7 +738,7 @@
     self.check_unexpected = check_unexpected
 
   def __call__(self, http, postproc, uri, method='GET', body=None,
-               headers=None, methodId=None):
+               headers=None, methodId=None, resumable=None):
     """Implements the callable interface that discovery.build() expects
     of requestBuilder, which is to build an object compatible with
     HttpRequest.execute(). See that method for the description of the
diff --git a/lib/google-api-python-client/apiclient/model.py b/lib/google-api-python-client/apiclient/model.py
index b8271f9..aafd88b 100644
--- a/lib/google-api-python-client/apiclient/model.py
+++ b/lib/google-api-python-client/apiclient/model.py
@@ -28,8 +28,8 @@
 import logging
 import urllib
 
-from anyjson import simplejson
 from errors import HttpError
+from oauth2client.anyjson import simplejson
 
 FLAGS = gflags.FLAGS
 
@@ -161,7 +161,8 @@
     Returns:
       The query parameters properly encoded into an HTTP URI query string.
     """
-    params.update({'alt': self.alt_param})
+    if self.alt_param is not None:
+      params.update({'alt': self.alt_param})
     astuples = []
     for key, value in params.iteritems():
       if type(value) == type([]):
@@ -269,6 +270,25 @@
     return {}
 
 
+class RawModel(JsonModel):
+  """Model class for requests that don't return JSON.
+
+  Serializes and de-serializes between JSON and the Python
+  object representation of HTTP request, and returns the raw bytes
+  of the response body.
+  """
+  accept = '*/*'
+  content_type = 'application/json'
+  alt_param = None
+
+  def deserialize(self, content):
+    return content
+
+  @property
+  def no_content_response(self):
+    return ''
+
+
 class ProtocolBufferModel(BaseModel):
   """Model class for protocol buffers.
 
diff --git a/lib/google-api-python-client/apiclient/oauth.py b/lib/google-api-python-client/apiclient/oauth.py
index 11eb680..136adcd 100644
--- a/lib/google-api-python-client/apiclient/oauth.py
+++ b/lib/google-api-python-client/apiclient/oauth.py
@@ -26,7 +26,11 @@
 import oauth2 as oauth
 import urllib
 import urlparse
-from anyjson import simplejson
+
+from oauth2client.anyjson import simplejson
+from oauth2client.client import Credentials
+from oauth2client.client import Flow
+from oauth2client.client import Storage
 
 try:
   from urlparse import parse_qsl
@@ -78,50 +82,6 @@
   return discovery[name]['url'] + '?' + urllib.urlencode(query)
 
 
-class Credentials(object):
-  """Base class for all Credentials objects.
-
-  Subclasses must define an authorize() method
-  that applies the credentials to an HTTP transport.
-  """
-
-  def authorize(self, http):
-    """Take an httplib2.Http instance (or equivalent) and
-    authorizes it for the set of credentials, usually by
-    replacing http.request() with a method that adds in
-    the appropriate headers and then delegates to the original
-    Http.request() method.
-    """
-    _abstract()
-
-
-class Flow(object):
-  """Base class for all Flow objects."""
-  pass
-
-
-class Storage(object):
-  """Base class for all Storage objects.
-
-  Store and retrieve a single credential.
-  """
-
-  def get(self):
-    """Retrieve credential.
-
-    Returns:
-      apiclient.oauth.Credentials
-    """
-    _abstract()
-
-  def put(self, credentials):
-    """Write a credential.
-
-    Args:
-      credentials: Credentials, the credentials to store.
-    """
-    _abstract()
-
 
 class OAuthCredentials(Credentials):
   """Credentials object for OAuth 1.0a
diff --git a/lib/google-api-python-client/apiclient/schema.py b/lib/google-api-python-client/apiclient/schema.py
new file mode 100644
index 0000000..ddcd670
--- /dev/null
+++ b/lib/google-api-python-client/apiclient/schema.py
@@ -0,0 +1,303 @@
+# Copyright (C) 2010 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Schema processing for discovery based APIs
+
+Schemas holds an APIs discovery schemas. It can return those schema as
+deserialized JSON objects, or pretty print them as prototype objects that
+conform to the schema.
+
+For example, given the schema:
+
+ schema = \"\"\"{
+   "Foo": {
+    "type": "object",
+    "properties": {
+     "etag": {
+      "type": "string",
+      "description": "ETag of the collection."
+     },
+     "kind": {
+      "type": "string",
+      "description": "Type of the collection ('calendar#acl').",
+      "default": "calendar#acl"
+     },
+     "nextPageToken": {
+      "type": "string",
+      "description": "Token used to access the next
+         page of this result. Omitted if no further results are available."
+     }
+    }
+   }
+ }\"\"\"
+
+ s = Schemas(schema)
+ print s.prettyPrintByName('Foo')
+
+ Produces the following output:
+
+  {
+   "nextPageToken": "A String", # Token used to access the
+       # next page of this result. Omitted if no further results are available.
+   "kind": "A String", # Type of the collection ('calendar#acl').
+   "etag": "A String", # ETag of the collection.
+  },
+
+The constructor takes a discovery document in which to look up named schema.
+"""
+
+# TODO(jcgregorio) support format, enum, minimum, maximum
+
+__author__ = 'jcgregorio@google.com (Joe Gregorio)'
+
+import copy
+from oauth2client.anyjson import simplejson
+
+
+class Schemas(object):
+  """Schemas for an API."""
+
+  def __init__(self, discovery):
+    """Constructor.
+
+    Args:
+      discovery: object, Deserialized discovery document from which we pull
+        out the named schema.
+    """
+    self.schemas = discovery.get('schemas', {})
+
+    # Cache of pretty printed schemas.
+    self.pretty = {}
+
+  def _prettyPrintByName(self, name, seen=None, dent=0):
+    """Get pretty printed object prototype from the schema name.
+
+    Args:
+      name: string, Name of schema in the discovery document.
+      seen: list of string, Names of schema already seen. Used to handle
+        recursive definitions.
+
+    Returns:
+      string, A string that contains a prototype object with
+        comments that conforms to the given schema.
+    """
+    if seen is None:
+      seen = []
+
+    if name in seen:
+      # Do not fall into an infinite loop over recursive definitions.
+      return '# Object with schema name: %s' % name
+    seen.append(name)
+
+    if name not in self.pretty:
+      self.pretty[name] = _SchemaToStruct(self.schemas[name],
+          seen, dent).to_str(self._prettyPrintByName)
+
+    seen.pop()
+
+    return self.pretty[name]
+
+  def prettyPrintByName(self, name):
+    """Get pretty printed object prototype from the schema name.
+
+    Args:
+      name: string, Name of schema in the discovery document.
+
+    Returns:
+      string, A string that contains a prototype object with
+        comments that conforms to the given schema.
+    """
+    # Return with trailing comma and newline removed.
+    return self._prettyPrintByName(name, seen=[], dent=1)[:-2]
+
+  def _prettyPrintSchema(self, schema, seen=None, dent=0):
+    """Get pretty printed object prototype of schema.
+
+    Args:
+      schema: object, Parsed JSON schema.
+      seen: list of string, Names of schema already seen. Used to handle
+        recursive definitions.
+
+    Returns:
+      string, A string that contains a prototype object with
+        comments that conforms to the given schema.
+    """
+    if seen is None:
+      seen = []
+
+    return _SchemaToStruct(schema, seen, dent).to_str(self._prettyPrintByName)
+
+  def prettyPrintSchema(self, schema):
+    """Get pretty printed object prototype of schema.
+
+    Args:
+      schema: object, Parsed JSON schema.
+
+    Returns:
+      string, A string that contains a prototype object with
+        comments that conforms to the given schema.
+    """
+    # Return with trailing comma and newline removed.
+    return self._prettyPrintSchema(schema, dent=1)[:-2]
+
+  def get(self, name):
+    """Get deserialized JSON schema from the schema name.
+
+    Args:
+      name: string, Schema name.
+    """
+    return self.schemas[name]
+
+
+class _SchemaToStruct(object):
+  """Convert schema to a prototype object."""
+
+  def __init__(self, schema, seen, dent=0):
+    """Constructor.
+
+    Args:
+      schema: object, Parsed JSON schema.
+      seen: list, List of names of schema already seen while parsing. Used to
+        handle recursive definitions.
+      dent: int, Initial indentation depth.
+    """
+    # The result of this parsing kept as list of strings.
+    self.value = []
+
+    # The final value of the parsing.
+    self.string = None
+
+    # The parsed JSON schema.
+    self.schema = schema
+
+    # Indentation level.
+    self.dent = dent
+
+    # Method that when called returns a prototype object for the schema with
+    # the given name.
+    self.from_cache = None
+
+    # List of names of schema already seen while parsing.
+    self.seen = seen
+
+  def emit(self, text):
+    """Add text as a line to the output.
+
+    Args:
+      text: string, Text to output.
+    """
+    self.value.extend(["  " * self.dent, text, '\n'])
+
+  def emitBegin(self, text):
+    """Add text to the output, but with no line terminator.
+
+    Args:
+      text: string, Text to output.
+      """
+    self.value.extend(["  " * self.dent, text])
+
+  def emitEnd(self, text, comment):
+    """Add text and comment to the output with line terminator.
+
+    Args:
+      text: string, Text to output.
+      comment: string, Python comment.
+    """
+    if comment:
+      divider = '\n' + '  ' * (self.dent + 2) + '# '
+      lines = comment.splitlines()
+      lines = [x.rstrip() for x in lines]
+      comment = divider.join(lines)
+      self.value.extend([text, ' # ', comment, '\n'])
+    else:
+      self.value.extend([text, '\n'])
+
+  def indent(self):
+    """Increase indentation level."""
+    self.dent += 1
+
+  def undent(self):
+    """Decrease indentation level."""
+    self.dent -= 1
+
+  def _to_str_impl(self, schema):
+    """Prototype object based on the schema, in Python code with comments.
+
+    Args:
+      schema: object, Parsed JSON schema file.
+
+    Returns:
+      Prototype object based on the schema, in Python code with comments.
+    """
+    stype = schema.get('type')
+    if stype == 'object':
+      self.emitEnd('{', schema.get('description', ''))
+      self.indent()
+      for pname, pschema in schema.get('properties', {}).iteritems():
+        self.emitBegin('"%s": ' % pname)
+        self._to_str_impl(pschema)
+      self.undent()
+      self.emit('},')
+    elif '$ref' in schema:
+      schemaName = schema['$ref']
+      description = schema.get('description', '')
+      s = self.from_cache(schemaName, self.seen)
+      parts = s.splitlines()
+      self.emitEnd(parts[0], description)
+      for line in parts[1:]:
+        self.emit(line.rstrip())
+    elif stype == 'boolean':
+      value = schema.get('default', 'True or False')
+      self.emitEnd('%s,' % str(value), schema.get('description', ''))
+    elif stype == 'string':
+      value = schema.get('default', 'A String')
+      self.emitEnd('"%s",' % str(value), schema.get('description', ''))
+    elif stype == 'integer':
+      value = schema.get('default', '42')
+      self.emitEnd('%s,' % str(value), schema.get('description', ''))
+    elif stype == 'number':
+      value = schema.get('default', '3.14')
+      self.emitEnd('%s,' % str(value), schema.get('description', ''))
+    elif stype == 'null':
+      self.emitEnd('None,', schema.get('description', ''))
+    elif stype == 'any':
+      self.emitEnd('"",', schema.get('description', ''))
+    elif stype == 'array':
+      self.emitEnd('[', schema.get('description'))
+      self.indent()
+      self.emitBegin('')
+      self._to_str_impl(schema['items'])
+      self.undent()
+      self.emit('],')
+    else:
+      self.emit('Unknown type! %s' % stype)
+      self.emitEnd('', '')
+
+    self.string = ''.join(self.value)
+    return self.string
+
+  def to_str(self, from_cache):
+    """Prototype object based on the schema, in Python code with comments.
+
+    Args:
+      from_cache: callable(name, seen), Callable that retrieves an object
+         prototype for a schema with the given name. Seen is a list of schema
+         names already seen as we recursively descend the schema definition.
+
+    Returns:
+      Prototype object based on the schema, in Python code with comments.
+      The lines of the code will all be properly indented.
+    """
+    self.from_cache = from_cache
+    return self._to_str_impl(self.schema)
diff --git a/lib/google-api-python-client/functional_tests/test_services.py b/lib/google-api-python-client/functional_tests/test_services.py
deleted file mode 100644
index f9263a3..0000000
--- a/lib/google-api-python-client/functional_tests/test_services.py
+++ /dev/null
@@ -1,288 +0,0 @@
-#!/usr/bin/python2.4
-#
-# Copyright 2010 Google Inc. All Rights Reserved.
-
-"""Discovery document tests
-
-Functional tests that verify we can retrieve data from existing services.
-"""
-
-__author__ = 'ade@google.com (Ade Oshineye)'
-
-import httplib2
-import pprint
-
-from apiclient.discovery import build
-import httplib2
-import logging
-import pickle
-import os
-import time
-import unittest
-
-class BuzzFunctionalTest(unittest.TestCase):
-  def setUp(self):
-    self.buzz = build('buzz', 'v1', developerKey='AIzaSyD7aEm5tyC9BAdoC-MfL0ol7VV1P4zQgig')
-
-  def test_can_get_specific_activity(self):
-    activity = self.buzz.activities().get(userId='105037104815911535953',
-                                     postId='B:z12sspviqyakfvye123wehng0muwz5jzq04').execute()
-
-    self.assertTrue(activity is not None)
-
-  def test_can_get_specific_activity_with_tag_id(self):
-    activity = self.buzz.activities().get(userId='105037104815911535953',
-                                     postId='tag:google.com,2010:buzz:z13ptnw5usmnv15ey22fzlswnuqoebasu').execute()
-
-    self.assertTrue(activity is not None)
-
-  def test_can_get_buzz_activities_with_many_params(self):
-    max_results = 2
-    activities_command = self.buzz.activities()
-    activities = activities_command.list(userId='googlebuzz', scope='@self',
-                             max_comments=max_results*2 ,max_liked=max_results*3,
-                             max_results=max_results).execute()
-    activity_count = len(activities['items'])
-    self.assertEquals(max_results, activity_count)
-
-    activities = activities_command.list_next(activities).execute()
-    activity_count = len(activities['items'])
-    self.assertEquals(max_results, activity_count)
-
-  def test_can_get_multiple_pages_of_buzz_activities(self):
-    max_results = 2
-    activities_command = self.buzz.activities()
-
-    activities = activities_command.list(userId='adewale', scope='@self',
-                             max_results=max_results).execute()
-    for count in range(10):
-      activities = activities_command.list_next(activities).execute()
-      activity_count = len(activities['items'])
-      self.assertEquals(max_results, activity_count, 'Failed after %s pages' % str(count))
-
-  def IGNORE_test_can_get_multiple_pages_of_buzz_likers(self):
-    # Ignore this test until the Buzz API fixes the bug with next links
-    # http://code.google.com/p/google-buzz-api/issues/detail?id=114
-    max_results = 1
-    people_cmd = self.buzz.people()
-    # The post https://www.googleapis.com/buzz/v1/activities/111062888259659218284/@self/B:z13nh535yk2syfob004cdjyb3mjeulcwv3c?alt=json#
-    #Perform this call https://www.googleapis.com/buzz/v1/activities/111062888259659218284/@self/B:z13nh535yk2syfob004cdjyb3mjeulcwv3c/@liked?alt=json&max-results=1
-    people = people_cmd.liked(groupId='@liked', userId='googlebuzz', scope='@self',
-                              postId='B:z13nh535yk2syfob004cdjyb3mjeulcwv3c', max_results=max_results).execute()
-
-    for count in range(10):
-      print count
-      people = people_cmd.liked_next(people).execute()
-      people_count = len(people['items'])
-      self.assertEquals(max_results, people_count, 'Failed after %s pages' % str(count))
-
-  def test_can_get_user_profile(self):
-    person = self.buzz.people().get(userId='googlebuzz').execute()
-
-    self.assertTrue(person is not None)
-    self.assertEquals('buzz#person', person['kind'])
-    self.assertEquals('Google Buzz Team', person['displayName'])
-    self.assertEquals('111062888259659218284', person['id'])
-    self.assertEquals('https://profiles.google.com/googlebuzz', person['profileUrl'])
-
-  def test_can_get_user_profile_using_numeric_identifier(self):
-    person = self.buzz.people().get(userId='108242092577082601423').execute()
-
-    self.assertTrue(person is not None)
-    self.assertEquals('buzz#person', person['kind'])
-    self.assertEquals('Test Account', person['displayName'])
-    self.assertEquals('108242092577082601423', person['id'])
-    self.assertEquals('https://profiles.google.com/108242092577082601423', person['profileUrl'])
-
-  def test_can_get_followees_of_user(self):
-    expected_followees = 30
-    following = self.buzz.people().list(userId='googlebuzz', groupId='@following', max_results=expected_followees).execute()
-
-    self.assertEquals(expected_followees, following['totalResults'])
-    self.assertEquals(expected_followees, len(following['entry']))
-
-  def test_can_efficiently_get_follower_count_of_user(self):
-
-    # Restricting max_results to 1 means only a tiny amount of data comes back but the totalResults still has the total.
-    followers = self.buzz.people().list(userId='googlebuzz', groupId='@followers',
-                                   max_results='1').execute()
-
-    # @googlebuzz has a large but fluctuating number of followers
-    # It is sufficient if the result is bigger than 10, 000
-    follower_count = followers['totalResults']
-    self.assertTrue(follower_count > 10000, follower_count)
-
-  def test_follower_count_is_missing_for_user_with_hidden_follower_count(self):
-    followers = self.buzz.people().list(userId='adewale', groupId='@followers').execute()
-
-    self.assertFalse('totalResults' in followers)
-
-
-class BuzzAuthenticatedFunctionalTest(unittest.TestCase):
-  def __init__(self, method_name):
-    unittest.TestCase.__init__(self, method_name)
-    credentials_dir = os.path.join(logging.os.path.dirname(__file__), './data')
-    f = file(os.path.join(credentials_dir, 'buzz_credentials.dat'), 'r')
-    credentials = pickle.loads(f.read())
-    f.close()
-
-    self.http = credentials.authorize(httplib2.Http())
-    self.buzz = build('buzz', 'v1', http=self.http, developerKey='AIzaSyD7aEm5tyC9BAdoC-MfL0ol7VV1P4zQgig')
-
-  def test_can_create_activity(self):
-
-    activity = self.buzz.activities().insert(userId='@me', body={
-        'data': {
-            'title': 'Testing insert',
-            'object': {
-                'content': u'Just a short note to show that insert is working. ?',
-                'type': 'note'}
-            }
-        }
-    ).execute()
-    self.assertTrue(activity is not None)
-
-  def test_fields_parameter_restricts_response_fields(self):
-    activity = self.buzz.activities().insert(userId='@me', body={
-        'data': {
-            'title': 'Testing patch',
-            'object': {
-                'content': u'Just a short note to show that insert is working. ?',
-                'type': 'note'}
-            }
-        }
-    ).execute()
-    self.assertTrue('kind' in activity)
-
-    # test fields to restrict what is returned
-    activity = self.buzz.activities().get(userId='@me', postId=activity['id'],
-                                        fields='object,id').execute()
-    self.assertTrue('kind' not in activity)
-    self.assertTrue('object' in activity)
-    self.assertTrue('id' in activity)
-
-  def test_patch(self):
-    activity = self.buzz.activities().insert(userId='@me', body={
-        'data': {
-            'title': 'Testing patch',
-            'object': {
-                'content': u'Just a short note to show that insert is working. ?',
-                'type': 'note'}
-            }
-        }).execute()
-    # Construct a raw patch to send, also restrict the response with fields
-    activity = self.buzz.activities().patch(userId='@me',
-                                            scope='@self',
-                                            postId=activity['id'],
-                                            body={
-        'object': {
-            'content': 'Updated content only!'}},
-        fields='object').execute()
-    self.assertEquals(activity['object']['content'], 'Updated content only!')
-    self.assertTrue('id' not in activity)
-
-  def test_can_create_private_activity(self):
-    activity = self.buzz.activities().insert(userId='@me', body={
-        'data': {
-            'title': 'Testing insert',
-            'object': {
-                'content': 'This is a private post.'
-                },
-            'visibility': {
-                'entries': [
-                    { 'id': 'tag:google.com,2010:buzz-group:108242092577082601423:13' }
-                    ]
-                }
-            }
-        }
-    ).execute()
-    self.assertTrue(activity is not None)
-
-  def test_can_create_and_delete_new_group(self):
-    group_name = 'New Group Created At' + str(time.time())
-    group = self.buzz.groups().insert(userId='@me', body = {
-      'data': {
-        'title': group_name
-      }
-    }).execute()
-    self.assertTrue(group is not None)
-
-    result = self.buzz.groups().delete(userId='@me', groupId=group['id']).execute()
-    self.assertEquals({}, result)
-
-  def test_can_identify_number_of_groups_belonging_to_user(self):
-    groups = self.buzz.groups().list(userId='108242092577082601423').execute()
-
-    # This should work as long as no-one deletes the 4 default groups for this test account
-    expected_default_number_of_groups = 4
-    self.assertTrue(len(groups['items']) > expected_default_number_of_groups)
-
-  def IGNORE__test_can_like_activity(self):
-    activity = self.buzz.activities().insert(userId='@me', body={
-        'data': {
-            'title': 'Testing insert',
-            'object': {
-                'content': u'Just a short note to show that insert is working. ?',
-                'type': 'note'}
-            }
-        }
-    ).execute()
-    pprint.pprint(activity)
-    id = activity['id']
-    likers = self.buzz.people().liked(userId='105037104815911535953', postId=id, groupId='@liked', scope='@self').execute()
-    # Todo(ade) Insert the new liker once the Buzz back-end bug is fixed
-
-  def test_can_comment_on_activity(self):
-    activity = self.buzz.activities().insert(userId='@me', body={
-        'data': {
-            'title': 'A new activity',
-            'object': {
-                'content': u'The body of the new activity',
-                'type': 'note'}
-            }
-        }
-    ).execute()
-
-    id = activity['id']
-    comment = self.buzz.comments().insert(userId='@me', postId=id, body={
-        'data': {
-            'content': 'A comment on the new activity'
-            }
-    }).execute()
-
-  def test_can_list_groups_belonging_to_user(self):
-    groups = self.buzz.groups().list(userId='108242092577082601423').execute()
-
-    group = self.buzz.groups().get(userId='108242092577082601423', groupId='G:108242092577082601423:15').execute()
-    self.assertEquals('G:108242092577082601423:15', group['id'], group)
-
-    group = self.buzz.groups().get(userId='108242092577082601423', groupId='G:108242092577082601423:14').execute()
-    self.assertEquals('G:108242092577082601423:14', group['id'], group)
-
-    group = self.buzz.groups().get(userId='108242092577082601423', groupId='G:108242092577082601423:13').execute()
-    self.assertEquals('G:108242092577082601423:13', group['id'], group)
-
-    group = self.buzz.groups().get(userId='108242092577082601423', groupId='G:108242092577082601423:6').execute()
-    self.assertEquals('G:108242092577082601423:6', group['id'], group)
-
-  def test_can_delete_activity(self):
-    activity = self.buzz.activities().insert(userId='@me', body={
-        'data': {
-            'title': 'Activity to be deleted',
-            'object': {
-                'content': u'Created this activity so that it can be deleted.',
-                'type': 'note'}
-            }
-        }
-    ).execute()
-    id = activity['id']
-
-    self.buzz.activities().delete(scope='@self', userId='@me', postId=id).execute()
-    time.sleep(2)
-
-    activity_url = activity['links']['self'][0]['href']
-    resp, content = self.http.request(activity_url, 'GET')
-    self.assertEquals(404, resp.status)
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/lib/google-api-python-client/apiclient/anyjson.py b/lib/google-api-python-client/oauth2client/anyjson.py
similarity index 90%
rename from lib/google-api-python-client/apiclient/anyjson.py
rename to lib/google-api-python-client/oauth2client/anyjson.py
index 7fb7846..ae21c33 100644
--- a/lib/google-api-python-client/apiclient/anyjson.py
+++ b/lib/google-api-python-client/oauth2client/anyjson.py
@@ -22,11 +22,11 @@
 
 
 try: # pragma: no cover
-  import simplejson
+  # Should work for Python2.6 and higher.
+  import json as simplejson
 except ImportError: # pragma: no cover
   try:
+    import simplejson
+  except ImportError:
     # Try to import from django, should work on App Engine
     from django.utils import simplejson
-  except ImportError:
-    # Should work for Python2.6 and higher.
-    import json as simplejson
diff --git a/lib/google-api-python-client/oauth2client/appengine.py b/lib/google-api-python-client/oauth2client/appengine.py
index 1bc2aaa..e4169e9 100644
--- a/lib/google-api-python-client/oauth2client/appengine.py
+++ b/lib/google-api-python-client/oauth2client/appengine.py
@@ -25,18 +25,9 @@
 import pickle
 import time
 
-try: # pragma: no cover
-  import simplejson
-except ImportError: # pragma: no cover
-  try:
-    # Try to import from django, should work on App Engine
-    from django.utils import simplejson
-  except ImportError:
-    # Should work for Python2.6 and higher.
-    import json as simplejson
-
 import clientsecrets
 
+from anyjson import simplejson
 from client import AccessTokenRefreshError
 from client import AssertionCredentials
 from client import Credentials
@@ -248,12 +239,15 @@
       json = self._cache.get(self._key_name)
       if json:
         return Credentials.new_from_json(json)
-    entity = self._model.get_or_insert(self._key_name)
-    credential = getattr(entity, self._property_name)
-    if credential and hasattr(credential, 'set_store'):
-      credential.set_store(self)
-      if self._cache:
-        self._cache.set(self._key_name, credentials.to_json())
+
+    credential = None
+    entity = self._model.get_by_key_name(self._key_name)
+    if entity is not None:
+      credential = getattr(entity, self._property_name)
+      if credential and hasattr(credential, 'set_store'):
+        credential.set_store(self)
+        if self._cache:
+          self._cache.set(self._key_name, credentials.to_json())
 
     return credential
 
@@ -289,7 +283,7 @@
     decorator = OAuth2Decorator(
         client_id='837...ent.com',
         client_secret='Qh...wwI',
-        scope='https://www.googleapis.com/auth/buzz')
+        scope='https://www.googleapis.com/auth/plus')
 
 
     class MainHandler(webapp.RequestHandler):
@@ -305,7 +299,7 @@
   def __init__(self, client_id, client_secret, scope,
                auth_uri='https://accounts.google.com/o/oauth2/auth',
                token_uri='https://accounts.google.com/o/oauth2/token',
-               message=None):
+               message=None, **kwargs):
 
     """Constructor for OAuth2Decorator
 
@@ -321,9 +315,11 @@
       message: Message to display if there are problems with the OAuth 2.0
         configuration. The message may contain HTML and will be presented on the
         web interface for any method that uses the decorator.
+      **kwargs: dict, Keyword arguments are be passed along as kwargs to the
+        OAuth2WebServerFlow constructor.
     """
     self.flow = OAuth2WebServerFlow(client_id, client_secret, scope, None,
-        auth_uri, token_uri)
+        auth_uri, token_uri, **kwargs)
     self.credentials = None
     self._request_handler = None
     self._message = message
@@ -446,7 +442,7 @@
 
     decorator = OAuth2DecoratorFromClientSecrets(
       os.path.join(os.path.dirname(__file__), 'client_secrets.json')
-      scope='https://www.googleapis.com/auth/buzz')
+      scope='https://www.googleapis.com/auth/plus')
 
 
     class MainHandler(webapp.RequestHandler):
@@ -528,7 +524,7 @@
         credentials = flow.step2_exchange(self.request.params)
         StorageByKeyName(
             CredentialsModel, user.user_id(), 'credentials').put(credentials)
-        self.redirect(self.request.get('state'))
+        self.redirect(str(self.request.get('state')))
       else:
         # TODO Add error handling here.
         pass
diff --git a/lib/google-api-python-client/oauth2client/client.py b/lib/google-api-python-client/oauth2client/client.py
index 3d81a8c..cd03e38 100644
--- a/lib/google-api-python-client/oauth2client/client.py
+++ b/lib/google-api-python-client/oauth2client/client.py
@@ -19,24 +19,28 @@
 
 __author__ = 'jcgregorio@google.com (Joe Gregorio)'
 
+import base64
 import clientsecrets
 import copy
 import datetime
 import httplib2
 import logging
+import os
 import sys
+import time
 import urllib
 import urlparse
 
-try:  # pragma: no cover
-  import simplejson
-except ImportError:  # pragma: no cover
-  try:
-    # Try to import from django, should work on App Engine
-    from django.utils import simplejson
-  except ImportError:
-    # Should work for Python2.6 and higher.
-    import json as simplejson
+from anyjson import simplejson
+
+HAS_OPENSSL = False
+try:
+  from oauth2client.crypt import Signer
+  from oauth2client.crypt import make_signed_jwt
+  from oauth2client.crypt import verify_signed_jwt_with_certs
+  HAS_OPENSSL = True
+except ImportError:
+  pass
 
 try:
   from urlparse import parse_qsl
@@ -46,7 +50,10 @@
 logger = logging.getLogger(__name__)
 
 # Expiry is stored in RFC3339 UTC format
-EXPIRY_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
+EXPIRY_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
+
+# Which certs to use to validate id_tokens received.
+ID_TOKEN_VERIFICATON_CERTS = 'https://www.googleapis.com/oauth2/v1/certs'
 
 
 class Error(Exception):
@@ -73,6 +80,11 @@
   pass
 
 
+class VerifyJwtTokenError(Error):
+  """Could on retrieve certificates for validation."""
+  pass
+
+
 def _abstract():
   raise NotImplementedError('You need to override this function')
 
@@ -229,14 +241,13 @@
   """Credentials object for OAuth 2.0.
 
   Credentials can be applied to an httplib2.Http object using the authorize()
-  method, which then signs each request from that object with the OAuth 2.0
-  access token.
+  method, which then adds the OAuth 2.0 access token to each request.
 
   OAuth2Credentials objects may be safely pickled and unpickled.
   """
 
   def __init__(self, access_token, client_id, client_secret, refresh_token,
-               token_expiry, token_uri, user_agent):
+               token_expiry, token_uri, user_agent, id_token=None):
     """Create an instance of OAuth2Credentials.
 
     This constructor is not usually called by the user, instead
@@ -250,9 +261,10 @@
       token_expiry: datetime, when the access_token expires.
       token_uri: string, URI of token endpoint.
       user_agent: string, The HTTP User-Agent to provide for this application.
+      id_token: object, The identity of the resource owner.
 
     Notes:
-      store: callable, a callable that when passed a Credential
+      store: callable, A callable that when passed a Credential
         will store the credential back to where it came from.
         This is needed to store the latest access_token if it
         has expired and been refreshed.
@@ -265,6 +277,7 @@
     self.token_expiry = token_expiry
     self.token_uri = token_uri
     self.user_agent = user_agent
+    self.id_token = id_token
 
     # True if the credentials have been revoked or expired and can't be
     # refreshed.
@@ -299,7 +312,8 @@
         data['refresh_token'],
         data['token_expiry'],
         data['token_uri'],
-        data['user_agent'])
+        data['user_agent'],
+        data.get('id_token', None))
     retval.invalid = data['invalid']
     return retval
 
@@ -607,6 +621,147 @@
     """
     _abstract()
 
+if HAS_OPENSSL:
+  # PyOpenSSL is not a prerequisite for oauth2client, so if it is missing then
+  # don't create the SignedJwtAssertionCredentials or the verify_id_token()
+  # method.
+
+  class SignedJwtAssertionCredentials(AssertionCredentials):
+    """Credentials object used for OAuth 2.0 Signed JWT assertion grants.
+
+    This credential does not require a flow to instantiate because it
+    represents a two legged flow, and therefore has all of the required
+    information to generate and refresh its own access tokens.
+    """
+
+    MAX_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds
+
+    def __init__(self,
+        service_account_name,
+        private_key,
+        scope,
+        private_key_password='notasecret',
+        user_agent=None,
+        token_uri='https://accounts.google.com/o/oauth2/token',
+        **kwargs):
+      """Constructor for SignedJwtAssertionCredentials.
+
+      Args:
+        service_account_name: string, id for account, usually an email address.
+        private_key: string, private key in P12 format.
+        scope: string or list of strings, scope(s) of the credentials being
+          requested.
+        private_key_password: string, password for private_key.
+        user_agent: string, HTTP User-Agent to provide for this application.
+        token_uri: string, URI for token endpoint. For convenience
+          defaults to Google's endpoints but any OAuth 2.0 provider can be used.
+        kwargs: kwargs, Additional parameters to add to the JWT token, for
+          example prn=joe@xample.org."""
+
+      super(SignedJwtAssertionCredentials, self).__init__(
+          'http://oauth.net/grant_type/jwt/1.0/bearer',
+          user_agent,
+          token_uri=token_uri,
+          )
+
+      if type(scope) is list:
+        scope = ' '.join(scope)
+      self.scope = scope
+
+      self.private_key = private_key
+      self.private_key_password = private_key_password
+      self.service_account_name = service_account_name
+      self.kwargs = kwargs
+
+    @classmethod
+    def from_json(cls, s):
+      data = simplejson.loads(s)
+      retval = SignedJwtAssertionCredentials(
+          data['service_account_name'],
+          data['private_key'],
+          data['private_key_password'],
+          data['scope'],
+          data['user_agent'],
+          data['token_uri'],
+          data['kwargs']
+          )
+      retval.invalid = data['invalid']
+      return retval
+
+    def _generate_assertion(self):
+      """Generate the assertion that will be used in the request."""
+      now = long(time.time())
+      payload = {
+          'aud': self.token_uri,
+          'scope': self.scope,
+          'iat': now,
+          'exp': now + SignedJwtAssertionCredentials.MAX_TOKEN_LIFETIME_SECS,
+          'iss': self.service_account_name
+      }
+      payload.update(self.kwargs)
+      logging.debug(str(payload))
+
+      return make_signed_jwt(
+          Signer.from_string(self.private_key, self.private_key_password),
+          payload)
+
+
+  def verify_id_token(id_token, audience, http=None,
+      cert_uri=ID_TOKEN_VERIFICATON_CERTS):
+    """Verifies a signed JWT id_token.
+
+    Args:
+      id_token: string, A Signed JWT.
+      audience: string, The audience 'aud' that the token should be for.
+      http: httplib2.Http, instance to use to make the HTTP request. Callers
+        should supply an instance that has caching enabled.
+      cert_uri: string, URI of the certificates in JSON format to
+        verify the JWT against.
+
+    Returns:
+      The deserialized JSON in the JWT.
+
+    Raises:
+      oauth2client.crypt.AppIdentityError if the JWT fails to verify.
+    """
+    if http is None:
+      http = httplib2.Http()
+
+    resp, content = http.request(cert_uri)
+
+    if resp.status == 200:
+      certs = simplejson.loads(content)
+      return verify_signed_jwt_with_certs(id_token, certs, audience)
+    else:
+      raise VerifyJwtTokenError('Status code: %d' % resp.status)
+
+
+def _urlsafe_b64decode(b64string):
+  # Guard against unicode strings, which base64 can't handle.
+  b64string = b64string.encode('ascii')
+  padded = b64string + '=' * (4 - len(b64string) % 4)
+  return base64.urlsafe_b64decode(padded)
+
+
+def _extract_id_token(id_token):
+  """Extract the JSON payload from a JWT.
+
+  Does the extraction w/o checking the signature.
+
+  Args:
+    id_token: string, OAuth 2.0 id_token.
+
+  Returns:
+    object, The deserialized JSON payload.
+  """
+  segments = id_token.split('.')
+
+  if (len(segments) != 3):
+    raise VerifyJwtTokenError(
+      'Wrong number of segments in token: %s' % id_token)
+
+  return simplejson.loads(_urlsafe_b64decode(segments[1]))
+
 
 class OAuth2WebServerFlow(Flow):
   """Does the Web Server Flow for OAuth 2.0.
@@ -641,7 +796,10 @@
     self.user_agent = user_agent
     self.auth_uri = auth_uri
     self.token_uri = token_uri
-    self.params = kwargs
+    self.params = {
+        'access_type': 'offline',
+        }
+    self.params.update(kwargs)
     self.redirect_uri = None
 
   def step1_get_authorize_url(self, redirect_uri='oob'):
@@ -701,6 +859,7 @@
 
     if http is None:
       http = httplib2.Http()
+
     resp, content = http.request(self.token_uri, method='POST', body=body,
                                  headers=headers)
     if resp.status == 200:
@@ -713,10 +872,14 @@
         token_expiry = datetime.datetime.utcnow() + datetime.timedelta(
             seconds=int(d['expires_in']))
 
+      if 'id_token' in d:
+        d['id_token'] = _extract_id_token(d['id_token'])
+
       logger.info('Successfully retrieved access token: %s' % content)
       return OAuth2Credentials(access_token, self.client_id,
                                self.client_secret, refresh_token, token_expiry,
-                               self.token_uri, self.user_agent)
+                               self.token_uri, self.user_agent,
+                               id_token=d.get('id_token', None))
     else:
       logger.error('Failed to retrieve access token: %s' % content)
       error_msg = 'Invalid response %s.' % resp['status']
diff --git a/lib/google-api-python-client/oauth2client/clientsecrets.py b/lib/google-api-python-client/oauth2client/clientsecrets.py
index da48be7..1327a2a 100644
--- a/lib/google-api-python-client/oauth2client/clientsecrets.py
+++ b/lib/google-api-python-client/oauth2client/clientsecrets.py
@@ -21,15 +21,7 @@
 __author__ = 'jcgregorio@google.com (Joe Gregorio)'
 
 
-try: # pragma: no cover
-  import simplejson
-except ImportError: # pragma: no cover
-  try:
-    # Try to import from django, should work on App Engine
-    from django.utils import simplejson
-  except ImportError:
-    # Should work for Python2.6 and higher.
-    import json as simplejson
+from anyjson import simplejson
 
 # Properties that make a client_secrets.json file valid.
 TYPE_WEB = 'web'
diff --git a/lib/google-api-python-client/oauth2client/crypt.py b/lib/google-api-python-client/oauth2client/crypt.py
new file mode 100644
index 0000000..3df861d
--- /dev/null
+++ b/lib/google-api-python-client/oauth2client/crypt.py
@@ -0,0 +1,244 @@
+#!/usr/bin/python2.4
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2011 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import base64
+import hashlib
+import logging
+import time
+
+from OpenSSL import crypto
+from anyjson import simplejson
+
+
+CLOCK_SKEW_SECS = 300  # 5 minutes in seconds
+AUTH_TOKEN_LIFETIME_SECS = 300  # 5 minutes in seconds
+MAX_TOKEN_LIFETIME_SECS = 86400  # 1 day in seconds
+
+
+class AppIdentityError(Exception):
+  pass
+
+
+class Verifier(object):
+  """Verifies the signature on a message."""
+
+  def __init__(self, pubkey):
+    """Constructor.
+
+    Args:
+      pubkey, OpenSSL.crypto.PKey, The public key to verify with.
+    """
+    self._pubkey = pubkey
+
+  def verify(self, message, signature):
+    """Verifies a message against a signature.
+
+    Args:
+      message: string, The message to verify.
+      signature: string, The signature on the message.
+
+    Returns:
+      True if message was singed by the private key associated with the public
+      key that this object was constructed with.
+    """
+    try:
+      crypto.verify(self._pubkey, signature, message, 'sha256')
+      return True
+    except:
+      return False
+
+  @staticmethod
+  def from_string(key_pem, is_x509_cert):
+    """Construct a Verified instance from a string.
+
+    Args:
+      key_pem: string, public key in PEM format.
+      is_x509_cert: bool, True if key_pem is an X509 cert, otherwise it is
+        expected to be an RSA key in PEM format.
+
+    Returns:
+      Verifier instance.
+
+    Raises:
+      OpenSSL.crypto.Error if the key_pem can't be parsed.
+    """
+    if is_x509_cert:
+      pubkey = crypto.load_certificate(crypto.FILETYPE_PEM, key_pem)
+    else:
+      pubkey = crypto.load_privatekey(crypto.FILETYPE_PEM, key_pem)
+    return Verifier(pubkey)
+
+
+class Signer(object):
+  """Signs messages with a private key."""
+
+  def __init__(self, pkey):
+    """Constructor.
+
+    Args:
+      pkey, OpenSSL.crypto.PKey, The private key to sign with.
+    """
+    self._key = pkey
+
+  def sign(self, message):
+    """Signs a message.
+
+    Args:
+      message: string, Message to be signed.
+
+    Returns:
+      string, The signature of the message for the given key.
+    """
+    return crypto.sign(self._key, message, 'sha256')
+
+  @staticmethod
+  def from_string(key, password='notasecret'):
+    """Construct a Signer instance from a string.
+
+    Args:
+      key: string, private key in P12 format.
+      password: string, password for the private key file.
+
+    Returns:
+      Signer instance.
+
+    Raises:
+      OpenSSL.crypto.Error if the key can't be parsed.
+    """
+    pkey = crypto.load_pkcs12(key, password).get_privatekey()
+    return Signer(pkey)
+
+
+def _urlsafe_b64encode(raw_bytes):
+  return base64.urlsafe_b64encode(raw_bytes).rstrip('=')
+
+
+def _urlsafe_b64decode(b64string):
+  # Guard against unicode strings, which base64 can't handle.
+  b64string = b64string.encode('ascii')
+  padded = b64string + '=' * (4 - len(b64string) % 4)
+  return base64.urlsafe_b64decode(padded)
+
+
+def _json_encode(data):
+  return simplejson.dumps(data, separators = (',', ':'))
+
+
+def make_signed_jwt(signer, payload):
+  """Make a signed JWT.
+
+  See http://self-issued.info/docs/draft-jones-json-web-token.html.
+
+  Args:
+    signer: crypt.Signer, Cryptographic signer.
+    payload: dict, Dictionary of data to convert to JSON and then sign.
+
+  Returns:
+    string, The JWT for the payload.
+  """
+  header = {'typ': 'JWT', 'alg': 'RS256'}
+
+  segments = [
+          _urlsafe_b64encode(_json_encode(header)),
+          _urlsafe_b64encode(_json_encode(payload)),
+  ]
+  signing_input = '.'.join(segments)
+
+  signature = signer.sign(signing_input)
+  segments.append(_urlsafe_b64encode(signature))
+
+  logging.debug(str(segments))
+
+  return '.'.join(segments)
+
+
+def verify_signed_jwt_with_certs(jwt, certs, audience):
+  """Verify a JWT against public certs.
+
+  See http://self-issued.info/docs/draft-jones-json-web-token.html.
+
+  Args:
+    jwt: string, A JWT.
+    certs: dict, Dictionary where values of public keys in PEM format.
+    audience: string, The audience, 'aud', that this JWT should contain. If
+      None then the JWT's 'aud' parameter is not verified.
+
+  Returns:
+    dict, The deserialized JSON payload in the JWT.
+
+  Raises:
+    AppIdentityError if any checks are failed.
+  """
+  segments = jwt.split('.')
+
+  if (len(segments) != 3):
+    raise AppIdentityError(
+      'Wrong number of segments in token: %s' % jwt)
+  signed = '%s.%s' % (segments[0], segments[1])
+
+  signature = _urlsafe_b64decode(segments[2])
+
+  # Parse token.
+  json_body = _urlsafe_b64decode(segments[1])
+  try:
+    parsed = simplejson.loads(json_body)
+  except:
+    raise AppIdentityError('Can\'t parse token: %s' % json_body)
+
+  # Check signature.
+  verified = False
+  for (keyname, pem) in certs.items():
+    verifier = Verifier.from_string(pem, True)
+    if (verifier.verify(signed, signature)):
+      verified = True
+      break
+  if not verified:
+    raise AppIdentityError('Invalid token signature: %s' % jwt)
+
+  # Check creation timestamp.
+  iat = parsed.get('iat')
+  if iat is None:
+    raise AppIdentityError('No iat field in token: %s' % json_body)
+  earliest = iat - CLOCK_SKEW_SECS
+
+  # Check expiration timestamp.
+  now = long(time.time())
+  exp = parsed.get('exp')
+  if exp is None:
+    raise AppIdentityError('No exp field in token: %s' % json_body)
+  if exp >= now + MAX_TOKEN_LIFETIME_SECS:
+    raise AppIdentityError(
+      'exp field too far in future: %s' % json_body)
+  latest = exp + CLOCK_SKEW_SECS
+
+  if now < earliest:
+    raise AppIdentityError('Token used too early, %d < %d: %s' %
+      (now, earliest, json_body))
+  if now > latest:
+    raise AppIdentityError('Token used too late, %d > %d: %s' %
+      (now, latest, json_body))
+
+  # Check audience.
+  if audience is not None:
+    aud = parsed.get('aud')
+    if aud is None:
+      raise AppIdentityError('No aud field in token: %s' % json_body)
+    if aud != audience:
+      raise AppIdentityError('Wrong recipient, %s != %s: %s' %
+          (aud, audience, json_body))
+
+  return parsed
diff --git a/lib/google-api-python-client/oauth2client/file.py b/lib/google-api-python-client/oauth2client/file.py
index 34a5f48..d71e888 100644
--- a/lib/google-api-python-client/oauth2client/file.py
+++ b/lib/google-api-python-client/oauth2client/file.py
@@ -20,20 +20,11 @@
 
 __author__ = 'jcgregorio@google.com (Joe Gregorio)'
 
+import os
+import stat
 import threading
 
-
-try:  # pragma: no cover
-  import simplejson
-except ImportError:  # pragma: no cover
-  try:
-    # Try to import from django, should work on App Engine
-    from django.utils import simplejson
-  except ImportError:
-    # Should work for Python2.6 and higher.
-    import json as simplejson
-
-
+from anyjson import simplejson
 from client import Storage as BaseStorage
 from client import Credentials
 
@@ -67,7 +58,7 @@
     """
     credentials = None
     try:
-      f = open(self._filename, 'r')
+      f = open(self._filename, 'rb')
       content = f.read()
       f.close()
     except IOError:
@@ -81,12 +72,28 @@
 
     return credentials
 
+  def _create_file_if_needed(self):
+    """Create an empty file if necessary.
+
+    This method will not initialize the file. Instead it implements a
+    simple version of "touch" to ensure the file has been created.
+    """
+    if not os.path.exists(self._filename):
+      old_umask = os.umask(0177)
+      try:
+        open(self._filename, 'a+b').close()
+      finally:
+        os.umask(old_umask)
+
+
   def locked_put(self, credentials):
     """Write Credentials to file.
 
     Args:
       credentials: Credentials, the credentials to store.
     """
-    f = open(self._filename, 'w')
+
+    self._create_file_if_needed()
+    f = open(self._filename, 'wb')
     f.write(credentials.to_json())
     f.close()
diff --git a/lib/google-api-python-client/oauth2client/multistore_file.py b/lib/google-api-python-client/oauth2client/multistore_file.py
index cf43dd9..d9b89c8 100644
--- a/lib/google-api-python-client/oauth2client/multistore_file.py
+++ b/lib/google-api-python-client/oauth2client/multistore_file.py
@@ -32,21 +32,13 @@
 __author__ = 'jbeda@google.com (Joe Beda)'
 
 import base64
+import errno
 import fcntl
 import logging
 import os
 import threading
 
-try:  # pragma: no cover
-  import simplejson
-except ImportError:  # pragma: no cover
-  try:
-    # Try to import from django, should work on App Engine
-    from django.utils import simplejson
-  except ImportError:
-    # Should work for Python2.6 and higher.
-    import json as simplejson
-
+from anyjson import simplejson
 from client import Storage as BaseStorage
 from client import Credentials
 
@@ -176,7 +168,7 @@
     if not os.path.exists(self._filename):
       old_umask = os.umask(0177)
       try:
-        open(self._filename, 'a+').close()
+        open(self._filename, 'a+b').close()
       finally:
         os.umask(old_umask)
 
@@ -184,12 +176,13 @@
     """Lock the entire multistore."""
     self._thread_lock.acquire()
     # Check to see if the file is writeable.
-    if os.access(self._filename, os.W_OK):
-      self._file_handle = open(self._filename, 'r+')
+    try:
+      self._file_handle = open(self._filename, 'r+b')
       fcntl.lockf(self._file_handle.fileno(), fcntl.LOCK_EX)
-    else:
-      # Cannot open in read/write mode. Open only in read mode.
-      self._file_handle = open(self._filename, 'r')
+    except IOError, e:
+      if e.errno != errno.EACCES:
+        raise e
+      self._file_handle = open(self._filename, 'rb')
       self._read_only = True
       if self._warn_on_readonly:
         logger.warn('The credentials file (%s) is not writable. Opening in '
diff --git a/lib/google-api-python-client/oauth2client/tools.py b/lib/google-api-python-client/oauth2client/tools.py
index 574a747..d441cd9 100644
--- a/lib/google-api-python-client/oauth2client/tools.py
+++ b/lib/google-api-python-client/oauth2client/tools.py
@@ -27,6 +27,7 @@
 import gflags
 import socket
 import sys
+import webbrowser
 
 from client import FlowExchangeError
 
@@ -120,13 +121,21 @@
     oauth_callback = 'oob'
   authorize_url = flow.step1_get_authorize_url(oauth_callback)
 
-  print 'Go to the following link in your browser:'
-  print authorize_url
-  print
   if FLAGS.auth_local_webserver:
+    webbrowser.open(authorize_url, new=1, autoraise=True)
+    print 'Your browser has been opened to visit:'
+    print
+    print '    ' + authorize_url
+    print
     print 'If your browser is on a different machine then exit and re-run this'
     print 'application with the command-line parameter '
-    print '--noauth_local_webserver.'
+    print
+    print '  --noauth_local_webserver'
+    print
+  else:
+    print 'Go to the following link in your browser:'
+    print
+    print '    ' + authorize_url
     print
 
   code = None
diff --git a/lib/google-api-python-client/runtests.py b/lib/google-api-python-client/runtests.py
index c1f9d1d..8ec0f54 100644
--- a/lib/google-api-python-client/runtests.py
+++ b/lib/google-api-python-client/runtests.py
@@ -1,5 +1,6 @@
 #!/usr/bin/env python
 import glob
+import imp
 import logging
 import os
 import sys
@@ -23,63 +24,11 @@
 use_library('django', '1.2')
 
 
-def build_suite(folder, verbosity):
-  # find all of the test modules
-  top_level_modules = map(fullmodname, glob.glob(os.path.join(folder, 'test_*.py')))
-  # TODO(ade) Verify that this works on Windows. If it doesn't then switch to os.walk instead
-  lower_level_modules = map(fullmodname, glob.glob(os.path.join(folder, '*/test_*.py')))
-  modules = top_level_modules + lower_level_modules
-  if verbosity > 0:
-    print "Running the tests found in the following modules:"
-    print modules
-
-  # load all of the tests into a suite
-  try:
-    return unittest.TestLoader().loadTestsFromNames(modules)
-  except Exception, exception:
-    # attempt to produce a more specific message
-    for module in modules:
-      __import__(module)
-    raise
-
-def run(test_folder_name, verbosity, exit_on_failure):
-  # Build and run the tests in test_folder_name
-  tests = build_suite(test_folder_name, verbosity)
-  result = unittest.TextTestRunner(verbosity=verbosity).run(tests)
-  if exit_on_failure and not result.wasSuccessful():
-    sys.exit(1)
-  cleanup()
-
 def main():
-  if '--help' in sys.argv:
-    print 'Usage: python runtests.py [-q|--quiet|-v|--verbose] [--exit_on_failure] [tests|functional_tests|contrib_tests]'
-    return
-  verbosity = 1
-  exit_on_failure = '--exit_on_failure' in sys.argv
-  if '-q' in sys.argv or '--quiet' in sys.argv:
-    verbosity = 0
-  if "-v" in sys.argv or '--verbose' in sys.argv:
-    verbosity = 2
-  if verbosity == 0:
-    logging.disable(logging.CRITICAL)
-  elif verbosity == 1:
-    logging.disable(logging.ERROR)
-  elif verbosity == 2:
-    logging.basicConfig(level=logging.DEBUG)
+  module = imp.load_source('test', sys.argv[1])
+  test = unittest.TestLoader().loadTestsFromModule(module)
+  result = unittest.TextTestRunner(verbosity=1).run(test)
 
-  import dev_appserver
-  dev_appserver.fix_sys_path()
-  # Allow user to run a specific folder of tests
-  if 'tests' in sys.argv:
-    run('tests', verbosity, exit_on_failure)
-  elif 'functional_tests' in sys.argv:
-    run('functional_tests', verbosity, exit_on_failure)
-  elif 'contrib_tests' in sys.argv:
-    run('contrib_tests', verbosity, exit_on_failure)
-  else:
-    run('tests', verbosity, exit_on_failure)
-    run('functional_tests', verbosity, exit_on_failure)
-    run('contrib_tests', verbosity, exit_on_failure)
 
 if __name__ == '__main__':
   main()
diff --git a/lib/google-api-python-client/setup.py b/lib/google-api-python-client/setup.py
index 219f673..2ffc37c 100644
--- a/lib/google-api-python-client/setup.py
+++ b/lib/google-api-python-client/setup.py
@@ -24,7 +24,6 @@
   'oauth2client',
   'apiclient.ext',
   'apiclient.contrib',
-  'apiclient.contrib.buzz',
   'apiclient.contrib.latitude',
   'apiclient.contrib.moderator',
   'uritemplate',
@@ -46,10 +45,10 @@
   install_requires.append('simplejson')
 
 long_desc = """The Google API Client for Python is a client library for
-accessing the Buzz, Moderator, and Latitude APIs."""
+accessing the Plus, Moderator, and many other Google APIs."""
 
 setup(name="google-api-python-client",
-      version="1.0beta6",
+      version="1.0beta7",
       description="Google API Client Library for Python",
       long_description=long_desc,
       author="Joe Gregorio",
diff --git a/lib/httplib2/httplib2/sync_from_mercurial.sh b/lib/httplib2/httplib2/sync_from_mercurial.sh
deleted file mode 100644
index 5678153..0000000
--- a/lib/httplib2/httplib2/sync_from_mercurial.sh
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2011 Google Inc. All Rights Reserved.
-# Author: jcgregorio@google.com (Joe Gregorio)
-#
-# Script to update google3 from the external hg repository or local
-# copy of repository.  This will open/add all the changed/new files
-# from the external repository. It does not take care of deleted file.
-# You must manaully call 'g4 mail' on the changes.
-
-source gbash.sh || exit
-
-DEFINE_string local_source "" \
-  "Local copy of repository to copy over.  If not set, remote repository is used."
-
-gbash::init_google "$@"
-
-if [[ -z "${FLAGS_local_source}" ]]; then
-  echo '*** Syncing copy of repository'
-  rm -rf /tmp/httplib2
-  mkdir /tmp/httplib2
-  hg clone https://httplib2.googlecode.com/hg/ /tmp/httplib2
-  COPY_SOURCE=/tmp/httplib2
-else
-  eval COPY_SOURCE=${FLAGS_local_source}
-fi
-
-echo '*** Copying httplib2 over'
-find third_party/py/httplib2 | xargs g4 open
-cp -r ${COPY_SOURCE}/python2/httplib2/. third_party/py/httplib2/
-
-echo '*** Adding new files'
-g4 nothave third_party/py/httplib2 | xargs --no-run-if-empty g4 add
-
-if [[ -z "${FLAGS_local_source}" ]]; then
-  echo '*** Updating README.google'
-  g4 edit third_party/py/httplib2/README.google
-  VERSION=`hg log -r tip --template="{node}" /tmp/httplib2/`
-  sed --in-place "s/^Version: .*/Version: $VERSION/" third_party/py/httplib2/README.google
-  sed --in-place "s/r=.*/r=$VERSION/" third_party/py/httplib2/README.google
-fi
-
-echo '*** Reverting unchanged files'
-g4 revert -a third_party/py/httplib2/...
-
-echo
-echo '*** All new and updated files have been added. Remember to look for deleted files.'
-echo
-echo '*** REMEMBER to fix up the importing of CA_CERTS in __init__.py'
diff --git a/lib/jinja2/AUTHORS b/lib/jinja2/AUTHORS
new file mode 100644
index 0000000..c6cd9ba
--- /dev/null
+++ b/lib/jinja2/AUTHORS
@@ -0,0 +1,31 @@
+Jinja is written and maintained by the Jinja Team and various
+contributors:
+
+Lead Developer:
+
+- Armin Ronacher <armin.ronacher@active-4.com>
+
+Developers:
+
+- Christoph Hack
+- Georg Brandl
+
+Contributors:
+
+- Bryan McLemore
+- Mickaël Guérin <kael@crocobox.org>
+- Cameron Knight
+- Lawrence Journal-World.
+- David Cramer
+
+Patches and suggestions:
+
+- Ronny Pfannschmidt
+- Axel Böhm
+- Alexey Melchakov
+- Bryan McLemore
+- Clovis Fabricio (nosklo)
+- Cameron Knight
+- Peter van Dijk (Habbie)
+- Stefan Ebner
+- Rene Leonhardt
diff --git a/lib/jinja2/CHANGES b/lib/jinja2/CHANGES
new file mode 100644
index 0000000..ae07828
--- /dev/null
+++ b/lib/jinja2/CHANGES
@@ -0,0 +1,269 @@
+Jinja2 Changelog
+================
+
+Version 2.6
+-----------
+(codename Convolution, released on July 24th 2011)
+
+- internal attributes now raise an internal attribute error now instead
+  of returning an undefined.  This fixes problems when passing undefined
+  objects to Python semantics expecting APIs.
+- traceback support now works properly for PyPy.  (Tested with 1.4)
+- implemented operator intercepting for sandboxed environments.  This
+  allows application developers to disable builtin operators for better
+  security.  (For instance limit the mathematical operators to actual
+  integers instead of longs)
+- groupby filter now supports dotted notation for grouping by attributes
+  of attributes.
+- scoped blocks not properly treat toplevel assignments and imports.
+  Previously an import suddenly "disappeared" in a scoped block.
+- automatically detect newer Python interpreter versions before loading code
+  from bytecode caches to prevent segfaults on invalid opcodes.  The segfault
+  in earlier Jinja2 versions here was not a Jinja2 bug but a limitation in
+  the underlying Python interpreter.  If you notice Jinja2 segfaulting in
+  earlier versions after an upgrade of the Python interpreter you don't have
+  to upgrade, it's enough to flush the bytecode cache.  This just no longer
+  makes this necessary, Jinja2 will automatically detect these cases now.
+- the sum filter can now sum up values by attribute.  This is a backwards
+  incompatible change.  The argument to the filter previously was the
+  optional starting index which defaultes to zero.  This now became the
+  second argument to the function because it's rarely used.
+- like sum, sort now also makes it possible to order items by attribute.
+- like sum and sort, join now also is able to join attributes of objects
+  as string.
+- the internal eval context now has a reference to the environment.
+- added a mapping test to see if an object is a dict or an object with
+  a similar interface.
+
+Version 2.5.5
+-------------
+(re-release of 2.5.4 with built documentation removed for filesize.
+ Released on October 18th 2010)
+
+- built documentation is no longer part of release.
+
+Version 2.5.4
+-------------
+(bugfix release, released on October 17th 2010)
+
+- Fixed extensions not loading properly with overlays.
+- Work around a bug in cpython for the debugger that causes segfaults
+  on 64bit big-endian architectures.
+
+Version 2.5.3
+-------------
+(bugfix release, released on October 17th 2010)
+
+- fixed an operator precedence error introduced in 2.5.2.  Statements
+  like "-foo.bar" had their implicit parentheses applied around the
+  first part of the expression ("(-foo).bar") instead of the more
+  correct "-(foo.bar)".
+
+Version 2.5.2
+-------------
+(bugfix release, released on August 18th 2010)
+
+- improved setup.py script to better work with assumptions people
+  might still have from it (``--with-speedups``).
+- fixed a packaging error that excluded the new debug support.
+
+Version 2.5.1
+-------------
+(bugfix release, released on August 17th 2010)
+
+- StopIteration exceptions raised by functions called from templates
+  are now intercepted and converted to undefineds.  This solves a
+  lot of debugging grief.  (StopIteration is used internally to
+  abort template execution)
+- improved performance of macro calls slightly.
+- babel extraction can now properly extract newstyle gettext calls.
+- using the variable `num` in newstyle gettext for something else
+  than the pluralize count will no longer raise a :exc:`KeyError`.
+- removed builtin markup class and switched to markupsafe.  For backwards
+  compatibility the pure Python implementation still exists but is
+  pulled from markupsafe by the Jinja2 developers.  The debug support
+  went into a separate feature called "debugsupport" and is disabled
+  by default because it is only relevant for Python 2.4
+- fixed an issue with unary operators having the wrong precendence.
+
+Version 2.5
+-----------
+(codename Incoherence, relased on May 29th 2010)
+
+- improved the sort filter (should have worked like this for a
+  long time) by adding support for case insensitive searches.
+- fixed a bug for getattribute constant folding.
+- support for newstyle gettext translations which result in a
+  nicer in-template user interface and more consistent
+  catalogs. (:ref:`newstyle-gettext`)
+- it's now possible to register extensions after an environment
+  was created.
+
+Version 2.4.1
+-------------
+(bugfix release, released on April 20th 2010)
+
+- fixed an error reporting bug for undefineds.
+
+Version 2.4
+-----------
+(codename Correlation, released on April 13th 2010)
+
+- the environment template loading functions now transparently
+  pass through a template object if it was passed to it.  This
+  makes it possible to import or extend from a template object
+  that was passed to the template.
+- added a :class:`ModuleLoader` that can load templates from
+  precompiled sources.  The environment now features a method
+  to compile the templates from a configured loader into a zip
+  file or folder.
+- the _speedups C extension now supports Python 3.
+- added support for autoescaping toggling sections and support
+  for evaluation contexts (:ref:`eval-context`).
+- extensions have a priority now.
+
+Version 2.3.1
+-------------
+(bugfix release, released on February 19th 2010)
+
+- fixed an error reporting bug on all python versions
+- fixed an error reporting bug on Python 2.4
+
+Version 2.3
+-----------
+(3000 Pythons, released on February 10th 2010)
+
+- fixes issue with code generator that causes unbound variables
+  to be generated if set was used in if-blocks and other small
+  identifier problems.
+- include tags are now able to select between multiple templates
+  and take the first that exists, if a list of templates is
+  given.
+- fixed a problem with having call blocks in outer scopes that
+  have an argument that is also used as local variable in an
+  inner frame (#360).
+- greatly improved error message reporting (#339)
+- implicit tuple expressions can no longer be totally empty.
+  This change makes ``{% if %}...{% endif %}`` a syntax error
+  now. (#364)
+- added support for translator comments if extracted via babel.
+- added with-statement extension.
+- experimental Python 3 support.
+
+Version 2.2.1
+-------------
+(bugfix release, released on September 14th 2009)
+
+- fixes some smaller problems for Jinja2 on Jython.
+
+Version 2.2
+-----------
+(codename Kong, released on September 13th 2009)
+
+- Include statements can now be marked with ``ignore missing`` to skip
+  non existing templates.
+- Priority of `not` raised.  It's now possible to write `not foo in bar`
+  as an alias to `foo not in bar` like in python.  Previously the grammar
+  required parentheses (`not (foo in bar)`) which was odd.
+- Fixed a bug that caused syntax errors when defining macros or using the
+  `{% call %}` tag inside loops.
+- Fixed a bug in the parser that made ``{{ foo[1, 2] }}`` impossible.
+- Made it possible to refer to names from outer scopes in included templates
+  that were unused in the callers frame (#327)
+- Fixed a bug that caused internal errors if names where used as iteration
+  variable and regular variable *after* the loop if that variable was unused
+  *before* the loop.  (#331)
+- Added support for optional `scoped` modifier to blocks.
+- Added support for line-comments.
+- Added the `meta` module.
+- Renamed (undocumented) attribute "overlay" to "overlayed" on the
+  environment because it was clashing with a method of the same name.
+- speedup extension is now disabled by default.
+
+Version 2.1.1
+-------------
+(Bugfix release)
+
+- Fixed a translation error caused by looping over empty recursive loops.
+
+Version 2.1
+-----------
+(codename Yasuzō, released on November 23rd 2008)
+
+- fixed a bug with nested loops and the special loop variable.  Before the
+  change an inner loop overwrote the loop variable from the outer one after
+  iteration.
+
+- fixed a bug with the i18n extension that caused the explicit pluralization
+  block to look up the wrong variable.
+
+- fixed a limitation in the lexer that made ``{{ foo.0.0 }}`` impossible.
+
+- index based subscribing of variables with a constant value returns an
+  undefined object now instead of raising an index error.  This was a bug
+  caused by eager optimizing.
+
+- the i18n extension looks up `foo.ugettext` now followed by `foo.gettext`
+  if an translations object is installed.  This makes dealing with custom
+  translations classes easier.
+
+- fixed a confusing behavior with conditional extending.  loops were partially
+  executed under some conditions even though they were not part of a visible
+  area.
+
+- added `sort` filter that works like `dictsort` but for arbitrary sequences.
+
+- fixed a bug with empty statements in macros.
+
+- implemented a bytecode cache system.  (:ref:`bytecode-cache`)
+
+- the template context is now weakref-able
+
+- inclusions and imports "with context" forward all variables now, not only
+  the initial context.
+
+- added a cycle helper called `cycler`.
+
+- added a joining helper called `joiner`.
+
+- added a `compile_expression` method to the environment that allows compiling
+  of Jinja expressions into callable Python objects.
+
+- fixed an escaping bug in urlize
+
+Version 2.0
+-----------
+(codename jinjavitus, released on July 17th 2008)
+
+- the subscribing of objects (looking up attributes and items) changed from
+  slightly.  It's now possible to give attributes or items a higher priority
+  by either using dot-notation lookup or the bracket syntax.  This also
+  changed the AST slightly.  `Subscript` is gone and was replaced with
+  :class:`~jinja2.nodes.Getitem` and :class:`~jinja2.nodes.Getattr`.
+
+  For more information see :ref:`the implementation details <notes-on-subscriptions>`.
+
+- added support for preprocessing and token stream filtering for extensions.
+  This would allow extensions to allow simplified gettext calls in template
+  data and something similar.
+
+- added :meth:`jinja2.environment.TemplateStream.dump`.
+
+- added missing support for implicit string literal concatenation.
+  ``{{ "foo" "bar" }}`` is equivalent to ``{{ "foobar" }}``
+
+- `else` is optional for conditional expressions.  If not given it evaluates
+  to `false`.
+
+- improved error reporting for undefined values by providing a position.
+
+- `filesizeformat` filter uses decimal prefixes now per default and can be
+  set to binary mode with the second parameter.
+
+- fixed bug in finalizer
+
+Version 2.0rc1
+--------------
+(no codename, released on June 9th 2008)
+
+- first release of Jinja2
diff --git a/lib/jinja2/Jinja2.egg-info/PKG-INFO b/lib/jinja2/Jinja2.egg-info/PKG-INFO
new file mode 100644
index 0000000..f2ae308
--- /dev/null
+++ b/lib/jinja2/Jinja2.egg-info/PKG-INFO
@@ -0,0 +1,55 @@
+Metadata-Version: 1.0
+Name: Jinja2
+Version: 2.6
+Summary: A small but fast and easy to use stand-alone template engine written in pure python.
+Home-page: http://jinja.pocoo.org/
+Author: Armin Ronacher
+Author-email: armin.ronacher@active-4.com
+License: BSD
+Description: 
+        Jinja2
+        ~~~~~~
+        
+        Jinja2 is a template engine written in pure Python.  It provides a
+        `Django`_ inspired non-XML syntax but supports inline expressions and
+        an optional `sandboxed`_ environment.
+        
+        Nutshell
+        --------
+        
+        Here a small example of a Jinja template::
+        
+            {% extends 'base.html' %}
+            {% block title %}Memberlist{% endblock %}
+            {% block content %}
+              <ul>
+              {% for user in users %}
+                <li><a href="{{ user.url }}">{{ user.username }}</a></li>
+              {% endfor %}
+              </ul>
+            {% endblock %}
+        
+        Philosophy
+        ----------
+        
+        Application logic is for the controller but don't try to make the life
+        for the template designer too hard by giving him too few functionality.
+        
+        For more informations visit the new `Jinja2 webpage`_ and `documentation`_.
+        
+        .. _sandboxed: http://en.wikipedia.org/wiki/Sandbox_(computer_security)
+        .. _Django: http://www.djangoproject.com/
+        .. _Jinja2 webpage: http://jinja.pocoo.org/
+        .. _documentation: http://jinja.pocoo.org/2/documentation/
+        
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Web Environment
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
+Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: Text Processing :: Markup :: HTML
diff --git a/lib/jinja2/Jinja2.egg-info/SOURCES.txt b/lib/jinja2/Jinja2.egg-info/SOURCES.txt
new file mode 100644
index 0000000..ebbb564
--- /dev/null
+++ b/lib/jinja2/Jinja2.egg-info/SOURCES.txt
@@ -0,0 +1,136 @@
+AUTHORS
+CHANGES
+LICENSE
+MANIFEST.in
+Makefile
+setup.cfg
+setup.py
+Jinja2.egg-info/PKG-INFO
+Jinja2.egg-info/SOURCES.txt
+Jinja2.egg-info/dependency_links.txt
+Jinja2.egg-info/entry_points.txt
+Jinja2.egg-info/not-zip-safe
+Jinja2.egg-info/requires.txt
+Jinja2.egg-info/top_level.txt
+artwork/jinjalogo.svg
+custom_fixers/__init__.py
+custom_fixers/fix_alt_unicode.py
+custom_fixers/fix_broken_reraising.py
+custom_fixers/fix_xrange2.py
+docs/.DS_Store
+docs/Makefile
+docs/api.rst
+docs/cache_extension.py
+docs/changelog.rst
+docs/conf.py
+docs/contents.rst.inc
+docs/extensions.rst
+docs/faq.rst
+docs/index.rst
+docs/integration.rst
+docs/intro.rst
+docs/jinjaext.py
+docs/jinjastyle.sty
+docs/latexindex.rst
+docs/logo.pdf
+docs/sandbox.rst
+docs/switching.rst
+docs/templates.rst
+docs/tricks.rst
+docs/_static/.ignore
+docs/_static/jinja-small.png
+docs/_templates/sidebarintro.html
+docs/_templates/sidebarlogo.html
+docs/_themes/LICENSE
+docs/_themes/README
+docs/_themes/jinja/layout.html
+docs/_themes/jinja/relations.html
+docs/_themes/jinja/theme.conf
+docs/_themes/jinja/static/jinja.css_t
+examples/bench.py
+examples/profile.py
+examples/basic/cycle.py
+examples/basic/debugger.py
+examples/basic/inheritance.py
+examples/basic/test.py
+examples/basic/test2.py
+examples/basic/test2.pyc
+examples/basic/test_filter_and_linestatements.py
+examples/basic/test_loop_filter.py
+examples/basic/translate.py
+examples/basic/templates/broken.html
+examples/basic/templates/subbroken.html
+examples/rwbench/djangoext.py
+examples/rwbench/rwbench.py
+examples/rwbench/django/_form.html
+examples/rwbench/django/_input_field.html
+examples/rwbench/django/_textarea.html
+examples/rwbench/django/index.html
+examples/rwbench/django/layout.html
+examples/rwbench/genshi/helpers.html
+examples/rwbench/genshi/index.html
+examples/rwbench/genshi/layout.html
+examples/rwbench/jinja/helpers.html
+examples/rwbench/jinja/index.html
+examples/rwbench/jinja/layout.html
+examples/rwbench/mako/helpers.html
+examples/rwbench/mako/index.html
+examples/rwbench/mako/layout.html
+ext/JinjaTemplates.tmbundle.tar.gz
+ext/djangojinja2.py
+ext/inlinegettext.py
+ext/jinja.el
+ext/Vim/jinja.vim
+ext/django2jinja/django2jinja.py
+ext/django2jinja/example.py
+ext/django2jinja/templates/index.html
+ext/django2jinja/templates/layout.html
+ext/django2jinja/templates/subtemplate.html
+jinja2/__init__.py
+jinja2/_debugsupport.c
+jinja2/_stringdefs.py
+jinja2/bccache.py
+jinja2/compiler.py
+jinja2/constants.py
+jinja2/debug.py
+jinja2/defaults.py
+jinja2/environment.py
+jinja2/exceptions.py
+jinja2/ext.py
+jinja2/filters.py
+jinja2/lexer.py
+jinja2/loaders.py
+jinja2/meta.py
+jinja2/nodes.py
+jinja2/optimizer.py
+jinja2/parser.py
+jinja2/runtime.py
+jinja2/sandbox.py
+jinja2/tests.py
+jinja2/utils.py
+jinja2/visitor.py
+jinja2/_markupsafe/__init__.py
+jinja2/_markupsafe/_bundle.py
+jinja2/_markupsafe/_constants.py
+jinja2/_markupsafe/_native.py
+jinja2/_markupsafe/tests.py
+jinja2/testsuite/__init__.py
+jinja2/testsuite/api.py
+jinja2/testsuite/core_tags.py
+jinja2/testsuite/debug.py
+jinja2/testsuite/doctests.py
+jinja2/testsuite/ext.py
+jinja2/testsuite/filters.py
+jinja2/testsuite/imports.py
+jinja2/testsuite/inheritance.py
+jinja2/testsuite/lexnparse.py
+jinja2/testsuite/loader.py
+jinja2/testsuite/regression.py
+jinja2/testsuite/security.py
+jinja2/testsuite/tests.py
+jinja2/testsuite/utils.py
+jinja2/testsuite/res/__init__.py
+jinja2/testsuite/res/templates/broken.html
+jinja2/testsuite/res/templates/syntaxerror.html
+jinja2/testsuite/res/templates/test.html
+jinja2/testsuite/res/templates/foo/test.html
\ No newline at end of file
diff --git a/lib/jinja2/Jinja2.egg-info/dependency_links.txt b/lib/jinja2/Jinja2.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/lib/jinja2/Jinja2.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/lib/jinja2/Jinja2.egg-info/entry_points.txt b/lib/jinja2/Jinja2.egg-info/entry_points.txt
new file mode 100644
index 0000000..32e6b75
--- /dev/null
+++ b/lib/jinja2/Jinja2.egg-info/entry_points.txt
@@ -0,0 +1,4 @@
+
+    [babel.extractors]
+    jinja2 = jinja2.ext:babel_extract[i18n]
+    
\ No newline at end of file
diff --git a/lib/jinja2/Jinja2.egg-info/not-zip-safe b/lib/jinja2/Jinja2.egg-info/not-zip-safe
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/lib/jinja2/Jinja2.egg-info/not-zip-safe
@@ -0,0 +1 @@
+
diff --git a/lib/jinja2/Jinja2.egg-info/requires.txt b/lib/jinja2/Jinja2.egg-info/requires.txt
new file mode 100644
index 0000000..c17d533
--- /dev/null
+++ b/lib/jinja2/Jinja2.egg-info/requires.txt
@@ -0,0 +1,4 @@
+
+
+[i18n]
+Babel>=0.8
\ No newline at end of file
diff --git a/lib/jinja2/Jinja2.egg-info/top_level.txt b/lib/jinja2/Jinja2.egg-info/top_level.txt
new file mode 100644
index 0000000..7f7afbf
--- /dev/null
+++ b/lib/jinja2/Jinja2.egg-info/top_level.txt
@@ -0,0 +1 @@
+jinja2
diff --git a/lib/jinja2/LICENSE b/lib/jinja2/LICENSE
new file mode 100644
index 0000000..31bf900
--- /dev/null
+++ b/lib/jinja2/LICENSE
@@ -0,0 +1,31 @@
+Copyright (c) 2009 by the Jinja Team, see AUTHORS for more details.
+
+Some rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * The names of the contributors may not be used to endorse or
+      promote products derived from this software without specific
+      prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/lib/jinja2/MANIFEST.in b/lib/jinja2/MANIFEST.in
new file mode 100644
index 0000000..aeb66af
--- /dev/null
+++ b/lib/jinja2/MANIFEST.in
@@ -0,0 +1,12 @@
+include MANIFEST.in Makefile CHANGES LICENSE AUTHORS jinja2/_debugsupport.c
+recursive-include docs *
+recursive-include custom_fixers *
+recursive-include ext *
+recursive-include artwork *
+recursive-include examples *
+recursive-include jinja2/testsuite/res *
+recursive-exclude docs/_build *
+recursive-exclude jinja2 *.pyc
+recursive-exclude docs *.pyc
+recursive-exclude jinja2 *.pyo
+recursive-exclude docs *.pyo
diff --git a/lib/jinja2/Makefile b/lib/jinja2/Makefile
new file mode 100644
index 0000000..0d89eda
--- /dev/null
+++ b/lib/jinja2/Makefile
@@ -0,0 +1,15 @@
+test:
+	python setup.py test
+
+release:
+	python scripts/make-release.py
+
+upload-docs:
+	$(MAKE) -C docs html dirhtml latex
+	$(MAKE) -C docs/_build/latex all-pdf
+	cd docs/_build/; mv html jinja-docs; zip -r jinja-docs.zip jinja-docs; mv jinja-docs html
+	scp -r docs/_build/dirhtml/* pocoo.org:/var/www/jinja.pocoo.org/docs/
+	scp -r docs/_build/latex/Jinja2.pdf pocoo.org:/var/www/jinja.pocoo.org/docs/jinja-docs.pdf
+	scp -r docs/_build/jinja-docs.zip pocoo.org:/var/www/jinja.pocoo.org/docs/
+
+.PHONY: test
diff --git a/lib/jinja2/PKG-INFO b/lib/jinja2/PKG-INFO
new file mode 100644
index 0000000..f2ae308
--- /dev/null
+++ b/lib/jinja2/PKG-INFO
@@ -0,0 +1,55 @@
+Metadata-Version: 1.0
+Name: Jinja2
+Version: 2.6
+Summary: A small but fast and easy to use stand-alone template engine written in pure python.
+Home-page: http://jinja.pocoo.org/
+Author: Armin Ronacher
+Author-email: armin.ronacher@active-4.com
+License: BSD
+Description: 
+        Jinja2
+        ~~~~~~
+        
+        Jinja2 is a template engine written in pure Python.  It provides a
+        `Django`_ inspired non-XML syntax but supports inline expressions and
+        an optional `sandboxed`_ environment.
+        
+        Nutshell
+        --------
+        
+        Here a small example of a Jinja template::
+        
+            {% extends 'base.html' %}
+            {% block title %}Memberlist{% endblock %}
+            {% block content %}
+              <ul>
+              {% for user in users %}
+                <li><a href="{{ user.url }}">{{ user.username }}</a></li>
+              {% endfor %}
+              </ul>
+            {% endblock %}
+        
+        Philosophy
+        ----------
+        
+        Application logic is for the controller but don't try to make the life
+        for the template designer too hard by giving him too few functionality.
+        
+        For more informations visit the new `Jinja2 webpage`_ and `documentation`_.
+        
+        .. _sandboxed: http://en.wikipedia.org/wiki/Sandbox_(computer_security)
+        .. _Django: http://www.djangoproject.com/
+        .. _Jinja2 webpage: http://jinja.pocoo.org/
+        .. _documentation: http://jinja.pocoo.org/2/documentation/
+        
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Web Environment
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
+Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: Text Processing :: Markup :: HTML
diff --git a/lib/jinja2/artwork/jinjalogo.svg b/lib/jinja2/artwork/jinjalogo.svg
new file mode 100644
index 0000000..0bc9ea4
--- /dev/null
+++ b/lib/jinja2/artwork/jinjalogo.svg
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="300"
+   height="120"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.45.1"
+   version="1.0"
+   sodipodi:docbase="/Users/mitsuhiko/Development/jinja2/artwork"
+   sodipodi:docname="jinjalogo.svg"
+   inkscape:export-filename="/Users/mitsuhiko/Development/jinja2/docs/_static/jinjabanner.png"
+   inkscape:export-xdpi="60"
+   inkscape:export-ydpi="60"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient6558">
+      <stop
+         style="stop-color:#575757;stop-opacity:1;"
+         offset="0"
+         id="stop6560" />
+      <stop
+         style="stop-color:#2f2f2f;stop-opacity:1;"
+         offset="1"
+         id="stop6562" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient6558"
+       id="radialGradient6564"
+       cx="61.297766"
+       cy="60.910986"
+       fx="61.297766"
+       fy="60.910986"
+       r="44.688254"
+       gradientTransform="matrix(1,0,0,0.945104,0,3.343747)"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient6558"
+       id="radialGradient6580"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,0.945104,0.355158,3.334402)"
+       cx="61.297766"
+       cy="60.910986"
+       fx="61.297766"
+       fy="60.910986"
+       r="44.688254" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient6558"
+       id="linearGradient4173"
+       x1="255.15521"
+       y1="32.347946"
+       x2="279.8912"
+       y2="32.347946"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.8073249,0,0,0.8073249,57.960878,7.4036303)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient6558"
+       id="linearGradient5145"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.7902775,0,0,0.82474,60.019977,8.0684132)"
+       x1="255.15521"
+       y1="32.347946"
+       x2="279.8912"
+       y2="32.347946" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="2.8"
+     inkscape:cx="137.4752"
+     inkscape:cy="57.574575"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="300px"
+     height="120px"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:window-width="1396"
+     inkscape:window-height="900"
+     inkscape:window-x="0"
+     inkscape:window-y="22" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       style="font-size:12px;font-style:normal;font-weight:normal;fill:#f4f4f4;fill-opacity:1;stroke:#e7e7e7;stroke-width:0.8;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;font-family:Bitstream Vera Sans;stroke-miterlimit:4;stroke-dasharray:none"
+       d="M 165.36463,80.874808 L 165.36463,80.874808 L 153.32556,80.874808 L 153.32556,81.8344 L 147.64994,81.8344 L 147.64994,36.035583 L 165.36463,36.035583 L 165.36463,20.333129 C 170.58154,21.031083 173.07533,22.077914 172.84609,23.473621 C 172.78871,24.055258 172.21545,24.549594 171.12624,24.956624 L 171.12624,36.035583 L 189.09895,36.035583 L 189.09895,82.532286 L 183.33733,82.532286 L 183.33733,80.874808 L 171.12624,80.874808 L 171.12624,102.94548 L 165.36463,102.94548 L 165.36463,80.874808 M 153.32556,55.489173 L 153.32556,55.489173 L 165.36463,55.489173 L 165.36463,41.793146 L 153.32556,41.793146 L 153.32556,55.489173 M 171.12624,55.489173 L 171.12624,55.489173 L 183.33733,55.489173 L 183.33733,41.793146 L 171.12624,41.793146 L 171.12624,55.489173 M 183.33733,61.333977 L 183.33733,61.333977 L 171.12624,61.333977 L 171.12624,75.030006 L 183.33733,75.030006 L 183.33733,61.333977 M 165.36463,61.333977 L 165.36463,61.333977 L 153.32556,61.333977 L 153.32556,75.030006 L 165.36463,75.030006 L 165.36463,61.333977 M 132.85897,59.414792 C 137.33069,63.136883 140.99969,67.934848 143.86618,73.808701 L 139.13654,77.385372 C 137.24467,72.965445 134.6362,69.12707 131.31114,65.87024 L 131.31114,102.94548 L 125.63554,102.94548 L 125.63554,68.57455 C 122.31042,71.947693 118.52671,74.913707 114.28436,77.47261 L 109.64069,73.372526 C 121.50782,67.091566 130.62312,55.489212 136.98668,38.565417 L 116.26221,38.565417 L 116.26221,32.720615 L 125.80754,32.720615 L 125.80754,20.333129 C 130.85245,21.031083 133.31761,22.048838 133.20299,23.386383 C 133.14561,24.026183 132.57235,24.549594 131.48307,24.956624 L 131.48307,32.720615 L 140.77043,32.720615 L 143.60824,36.733469 C 140.68444,45.51526 137.10137,53.075692 132.85897,59.414792 M 254.11016,49.469901 L 254.11016,49.469901 L 254.11016,20.333129 C 259.21243,21.031083 261.67755,22.048838 261.50562,23.386383 C 261.44823,23.909869 261.04699,24.346044 260.30172,24.694917 C 260.30164,24.694986 260.30164,24.694986 260.30172,24.694917 L 260.30172,24.694917 L 259.78578,24.956624 L 259.78578,49.469901 L 277.15652,49.469901 L 277.15652,55.227471 L 259.78578,55.227471 L 259.78578,93.785712 L 281.45616,93.785712 L 281.45616,99.63051 L 232.35378,99.63051 L 232.35378,93.785712 L 254.11016,93.785712 L 254.11016,55.227471 L 236.22346,55.227471 L 236.22346,49.469901 L 254.11016,49.469901 M 225.5603,59.327554 C 231.12111,63.107798 235.62145,67.876693 239.06127,73.634235 L 234.76157,77.647079 C 231.60845,72.180322 227.82475,67.934848 223.41044,64.910648 L 223.41044,102.94548 L 217.73484,102.94548 L 217.73484,67.44049 C 212.91919,71.627831 207.70222,75.030021 202.084,77.647079 L 197.87027,73.198053 C 212.66118,66.917101 224.01239,55.372897 231.92377,38.565417 L 205.35172,38.565417 L 205.35172,32.720615 L 217.99283,32.720615 L 217.99283,20.333129 C 223.03774,21.031083 225.50291,22.048838 225.38829,23.386383 C 225.33089,24.026183 224.75765,24.549594 223.66837,24.956624 L 223.66837,32.720615 L 236.22346,32.720615 L 238.80326,36.733469 C 235.13421,45.51526 230.71987,53.046611 225.5603,59.327554"
+       id="text4761" />
+    <path
+       style="font-size:44.09793472px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#b41717;fill-opacity:1;stroke:#7f2828;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Candara;stroke-miterlimit:4;stroke-dasharray:none"
+       d="M 149.14708,37.774469 C 148.97807,41.117899 148.84526,44.824225 148.74871,48.893456 C 148.67626,52.962754 148.3818,70.641328 148.38184,75.524422 C 148.3818,79.065795 148.05588,81.991266 147.40406,84.300835 C 146.75219,86.610422 145.72612,88.557071 144.32585,90.140779 C 142.94969,91.724494 141.17522,92.901283 139.00239,93.671139 C 136.82953,94.440996 134.22211,94.825935 131.18014,94.825935 C 128.83828,94.825935 126.73787,94.59498 124.87889,94.133049 L 125.4221,89.31593 C 127.13623,90.0418 128.92278,90.404734 130.78177,90.404733 C 132.85805,90.404734 134.66875,90.140782 136.2139,89.612876 C 137.78315,89.062981 139.02651,88.216133 139.94396,87.072335 C 140.8855,85.928548 141.54942,84.520804 141.93572,82.8491 C 142.34613,81.177412 142.55134,78.988811 142.55136,76.283285 C 142.55134,66.297119 142.62852,44.659257 142.26641,37.774469 L 149.14708,37.774469 M 166.38498,80.732697 L 159.83024,80.732697 C 160.16821,76.333498 160.33723,71.307412 160.33723,65.654424 C 160.33723,59.2976 159.91471,53.963567 159.06973,49.652319 L 166.31257,48.761483 C 166.02284,53.358679 165.87799,58.98965 165.87799,65.654424 C 165.87799,70.933479 166.04699,75.959565 166.38498,80.732697 M 167.90601,39.490159 C 167.90598,40.611994 167.5076,41.590815 166.7109,42.42662 C 165.91418,43.240515 164.79155,43.647442 163.343,43.647399 C 162.11172,43.647442 161.146,43.295504 160.44588,42.591595 C 159.76988,41.865769 159.43188,40.996927 159.43188,39.98507 C 159.43188,38.885304 159.84231,37.928485 160.66315,37.114591 C 161.48399,36.30078 162.61869,35.893853 164.06727,35.893811 C 165.25023,35.893853 166.17975,36.256783 166.85575,36.982609 C 167.55588,37.686526 167.90598,38.522373 167.90601,39.490159 M 206.72748,80.732697 L 200.13651,80.732697 C 200.66763,74.947749 200.93319,68.634899 200.9332,61.794122 C 200.93319,58.406756 200.1727,56.097177 198.65174,54.865371 C 197.15487,53.61163 195.00619,52.984747 192.20564,52.984714 C 188.77731,52.984747 185.61465,54.117535 182.71753,56.383099 C 182.71753,63.883761 182.76583,72.000287 182.86238,80.732697 L 176.27142,80.732697 C 176.68182,73.254058 176.88707,67.843042 176.88707,64.499632 C 176.88707,59.352589 176.3559,54.359493 175.29363,49.520339 L 181.66734,48.695493 L 182.35539,52.720761 L 182.64511,52.720761 C 186.21823,49.773323 190.04483,48.299592 194.12499,48.299567 C 198.13265,48.299592 201.23499,49.113454 203.43201,50.741118 C 205.62895,52.346863 206.72747,55.217334 206.72748,59.352563 C 206.72747,59.770507 206.70331,60.595362 206.65507,61.827118 C 206.60675,63.058915 206.5826,63.883761 206.58262,64.30167 C 206.5826,67.975018 206.63088,73.452022 206.72748,80.732697 M 222.69791,48.695493 C 222.28747,55.514282 222.08225,62.355041 222.08225,69.21778 C 222.08225,71.043461 222.14262,73.463019 222.26332,76.476468 C 222.40822,79.467925 222.4806,81.502559 222.48063,82.580363 C 222.4806,89.685068 219.51105,93.996287 213.57195,95.514024 L 211.76124,93.006484 C 213.90995,91.356766 215.2378,89.597085 215.74478,87.727431 C 216.49321,85.043912 216.86743,79.324953 216.86743,70.570535 C 216.86743,61.178248 216.3846,54.16153 215.41887,49.520339 L 222.69791,48.695493 M 224.2551,39.490159 C 224.2551,40.611994 223.85673,41.590815 223.06006,42.42662 C 222.26332,43.240515 221.14069,43.647442 219.69213,43.647399 C 218.46084,43.647442 217.49515,43.295504 216.795,42.591595 C 216.119,41.865769 215.781,40.996927 215.781,39.98507 C 215.781,38.885304 216.19144,37.928485 217.01231,37.114591 C 217.83316,36.30078 218.96785,35.893853 220.4164,35.893811 C 221.5994,35.893853 222.52889,36.256783 223.20492,36.982609 C 223.90503,37.686526 224.2551,38.522373 224.2551,39.490159 M 259.60008,80.732697 L 253.91446,80.930661 C 253.62473,79.852857 253.47987,78.830045 253.4799,77.862216 L 253.11774,77.862216 C 250.14817,80.325772 246.10427,81.557546 240.98606,81.557547 C 238.20962,81.557546 235.8195,80.820682 233.81563,79.346948 C 231.81178,77.851221 230.80988,75.728607 230.80988,72.979099 C 230.80988,69.591724 232.37914,66.875216 235.51769,64.829574 C 238.65625,62.761967 244.48667,61.67316 253.00913,61.563165 C 253.08155,61.035275 253.11772,60.430386 253.11774,59.748497 C 253.11772,57.043003 252.32104,55.239336 250.72765,54.337474 C 249.15832,53.435661 246.76819,52.984747 243.55721,52.984714 C 239.76681,52.984747 236.03678,53.413668 232.3671,54.271484 L 232.9827,49.718301 C 236.60411,48.77251 240.76873,48.299592 245.47658,48.299567 C 249.77395,48.299592 253.09359,49.113454 255.43545,50.741118 C 257.77728,52.346863 258.94819,55.096363 258.94824,58.989625 C 258.94819,60.023469 258.88785,61.904117 258.76715,64.631608 C 258.67054,67.337133 258.62228,69.140806 258.6223,70.042632 C 258.62228,74.045913 258.94819,77.609265 259.60008,80.732697 M 253.19019,74.331856 C 253.06945,70.988469 253.00909,67.986016 253.00913,65.324484 C 248.47027,65.324498 245.01786,65.632443 242.65187,66.248318 C 238.69248,67.348131 236.71278,69.448748 236.71278,72.550177 C 236.71278,75.541643 239.03044,77.037371 243.66588,77.037366 C 247.64942,77.037371 250.82416,76.135534 253.19019,74.331856"
+       id="text3736"
+       sodipodi:nodetypes="ccsscssccscccsccccsccsccsscsssccccscscccsccccscsssccscscccscccsscsssccccccscsccscsccscscsccccssc" />
+    <path
+       style="fill:url(#radialGradient6564);fill-opacity:1.0;fill-rule:evenodd;stroke:#323232;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+       d="M 105.45673,18.675923 C 105.45673,18.675923 88.211949,26.918461 74.172834,28.737898 C 60.133727,30.557333 33.360434,32.377571 28.045622,31.093256 C 22.730818,29.808941 18.915645,28.309196 18.915645,28.309196 L 20.021441,32.056583 L 16.609513,35.052471 L 17.2144,36.121726 L 18.61792,36.22764 L 22.92773,36.762252 L 23.532621,38.688909 L 25.937975,38.905784 L 27.143021,42.970927 C 27.143021,42.970927 32.254764,43.399628 33.758953,43.399628 C 35.263142,43.399628 38.271966,43.187802 38.271966,43.187802 L 38.371202,44.791657 L 39.477002,45.003495 L 39.477002,46.824227 L 37.066917,48.967759 L 37.671807,49.073671 L 37.671807,49.820127 C 37.671807,49.820127 32.255457,50.252157 30.049301,49.93109 C 27.843157,49.610006 27.440747,49.608286 27.440747,49.608286 L 27.242258,49.820127 L 27.143021,50.783455 L 27.643946,50.783455 L 27.84242,54.959544 L 38.976091,54.530844 L 38.172728,68.980747 L 38.073481,70.796442 L 28.645781,70.261816 L 28.546544,66.408513 L 30.649462,66.408513 L 30.852673,64.910557 L 32.757107,64.481857 L 33.059555,64.058192 L 25.937975,62.343374 L 20.522364,63.947229 L 21.42496,64.698732 L 22.327572,64.698732 L 22.426809,65.984848 L 24.331254,66.09076 L 24.331254,69.838147 L 22.228335,70.372777 L 22.630009,71.225146 L 23.130934,71.547931 L 23.130934,74.437917 L 24.435218,74.437917 L 24.435218,87.813529 L 22.327572,88.13632 L 22.630009,91.989617 L 23.929569,92.206492 L 23.731093,100.98236 L 29.449141,101.08826 L 28.244105,92.418334 L 36.868446,92.206492 L 36.268285,96.912181 L 35.464925,100.23086 L 44.188501,100.33677 L 44.287739,91.777793 L 50.303506,91.243181 L 50.005786,96.700351 L 49.802585,99.90807 L 54.920484,99.90807 L 54.717274,91.132217 L 55.421397,91.243181 L 55.619882,87.067076 L 54.816521,87.067076 L 54.518798,85.352258 L 54.017874,80.429702 L 54.216359,74.760706 L 55.31743,74.760706 L 55.31743,71.336105 L 53.913913,71.442015 L 54.117112,67.402096 L 55.747469,67.240708 L 55.823083,65.929374 L 56.749319,65.793192 L 57.699176,65.071956 L 51.985842,63.896802 L 46.31977,65.15265 L 46.872668,66.060507 L 47.47283,66.010066 L 48.172228,65.984848 L 48.299828,67.639144 L 49.878196,67.563497 L 49.906548,71.144447 L 43.111042,70.988097 L 43.337879,67.160002 L 43.559978,63.679927 L 43.559978,59.105378 L 43.763188,54.288748 L 57.373101,53.592733 L 73.567955,52.659674 L 73.71917,55.736265 L 73.142647,63.120082 L 72.892183,69.9945 L 66.928387,69.888585 L 66.900039,65.071956 L 69.106918,64.991267 L 69.206169,63.629486 L 70.108765,63.493308 L 70.061506,63.226006 L 70.964116,63.175568 L 71.465028,62.504773 L 64.721507,60.926122 L 58.001612,62.368592 L 58.4789,63.200785 L 59.230285,63.1453 L 59.230285,63.523577 L 60.156518,63.523577 L 60.156518,65.046738 L 62.136575,65.071956 L 62.112937,69.298485 L 60.109259,69.298485 L 60.080907,70.261816 L 60.785031,70.342507 L 60.70942,74.009202 L 62.188552,74.089909 L 62.013701,88.620507 L 60.057282,89.018952 L 60.080907,89.714967 L 60.761406,89.714967 L 60.761406,93.437137 L 61.886113,93.437137 L 61.588391,98.52109 L 61.210343,102.95945 L 68.331912,103.14605 L 68.105084,99.29275 L 67.580538,96.085028 L 67.476575,93.300955 L 73.520696,93.195041 L 73.345845,97.502272 L 73.317494,102.05159 L 76.729426,102.3189 L 81.3653,102.1323 L 82.820807,101.70358 L 82.017437,99.26753 L 81.818959,95.439438 L 81.440912,92.710853 L 87.206218,92.499027 L 86.955759,95.842931 L 86.932133,101.08826 L 89.238253,101.30009 L 91.520751,101.24965 L 92.621828,100.90165 L 91.969693,95.923633 L 91.747577,92.176239 L 92.725793,92.070324 L 92.749427,88.726422 L 93.02352,88.670945 L 92.976244,87.949712 L 91.846823,87.949712 L 91.619996,85.488427 L 91.520751,74.811143 L 92.371377,74.785924 L 92.371377,71.280616 L 92.725793,71.336105 L 92.725793,70.640088 L 91.468773,70.529127 L 91.497126,66.463987 L 93.600043,66.277382 L 93.477182,64.910557 L 94.403419,64.829863 L 94.351424,64.562549 L 95.580099,63.947229 L 89.337489,62.69138 L 82.995657,63.977495 L 83.39733,64.723951 L 84.375543,64.643256 L 84.427528,64.966046 L 85.254515,64.966046 L 85.301775,66.569901 L 87.357445,66.544681 L 87.532293,70.478688 L 80.264217,70.423216 L 79.413593,64.512124 L 78.733106,61.380041 L 78.184923,55.761484 L 78.510996,52.473053 L 92.999878,51.373557 L 93.047136,46.476221 L 93.774891,46.289613 L 93.727651,45.543159 L 93.174743,45.220372 C 93.174629,45.220372 85.252181,46.395266 82.745197,46.66284 C 82.0389,46.738209 82.09239,46.733258 81.516524,46.79397 L 81.440912,45.886118 L 78.444837,44.317564 L 78.482644,42.491786 L 79.512842,42.461518 L 79.588444,39.949808 C 79.588444,39.949808 85.728225,39.546834 88.009582,39.0117 C 90.290937,38.476559 93.524432,37.942456 93.524432,37.942456 L 95.055545,33.79662 L 98.089437,32.913987 L 98.339888,32.217972 L 105.20628,30.316548 L 105.98602,29.676006 L 103.37744,23.976741 L 103.62792,22.690624 L 104.95584,21.994611 L 105.91041,19.079404 L 105.45673,18.675923 z M 72.466874,40.403728 L 72.429067,42.476654 L 73.983813,42.542211 L 73.884576,44.509221 L 70.836515,46.506487 L 70.647496,47.081457 L 71.876167,47.091543 L 71.866712,47.575729 L 62.552432,48.029652 L 62.613863,46.652742 L 63.039175,45.966809 L 63.067524,45.528025 L 63.07698,44.579832 L 63.341609,43.949374 L 63.440849,43.439982 L 63.440849,43.076841 L 63.842533,41.47297 L 72.466874,40.403728 z M 52.987688,42.168984 L 52.760853,43.561027 L 53.488599,44.418431 L 53.441349,45.916386 L 54.117112,46.960408 L 53.942262,48.191039 L 54.443185,48.912273 L 44.939872,49.2855 L 44.916247,48.967759 L 46.017333,48.831579 L 46.069307,48.428097 L 43.66394,47.121797 L 43.536351,45.03375 L 44.689411,44.978276 L 44.788661,42.72883 L 52.987688,42.168984 z M 67.051262,74.276518 L 72.81657,74.649742 L 72.618099,82.411833 L 73.36947,88.776857 L 67.254465,88.565018 L 67.051262,74.276518 z M 28.44258,74.599304 L 37.671807,75.078442 L 36.868446,80.429702 L 36.868446,84.928593 L 37.520583,87.440302 L 28.494569,87.869006 L 28.44258,74.599304 z M 87.508658,74.649742 L 87.508658,87.924488 L 81.644113,88.353194 L 81.440912,81.342592 L 80.788764,74.811143 L 87.508658,74.649742 z M 43.087416,74.947312 L 49.906548,74.972531 L 49.977434,87.278902 L 43.611966,87.389863 L 43.285891,83.400379 L 43.262266,79.441156 L 43.087416,74.947312 z "
+       id="path4735" />
+  </g>
+</svg>
diff --git a/lib/jinja2/docs/Makefile b/lib/jinja2/docs/Makefile
new file mode 100644
index 0000000..52d78d9
--- /dev/null
+++ b/lib/jinja2/docs/Makefile
@@ -0,0 +1,118 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = _build
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp epub latex changes linkcheck doctest
+
+help:
+	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  html       to make standalone HTML files"
+	@echo "  dirhtml    to make HTML files named index.html in directories"
+	@echo "  singlehtml to make a single large HTML file"
+	@echo "  pickle     to make pickle files"
+	@echo "  json       to make JSON files"
+	@echo "  htmlhelp   to make HTML files and a HTML help project"
+	@echo "  qthelp     to make HTML files and a qthelp project"
+	@echo "  devhelp    to make HTML files and a Devhelp project"
+	@echo "  epub       to make an epub"
+	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+	@echo "  changes    to make an overview of all changed/added/deprecated items"
+	@echo "  linkcheck  to check all external links for integrity"
+	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+	-rm -rf $(BUILDDIR)/*
+
+html:
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+	@echo
+	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+	@echo
+	@echo "Build finished; now you can process the pickle files."
+
+json:
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+	@echo
+	@echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+	@echo
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
+	      ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+	@echo
+	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
+	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Flask.qhcp"
+	@echo "To view the help file:"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Flask.qhc"
+
+devhelp:
+	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) _build/devhelp
+	@echo
+	@echo "Build finished."
+	@echo "To view the help file:"
+	@echo "# mkdir -p $$HOME/.local/share/devhelp/Flask"
+	@echo "# ln -s _build/devhelp $$HOME/.local/share/devhelp/Flask"
+	@echo "# devhelp"
+
+epub:
+	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+	@echo
+	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+	@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
+	      "run these through (pdf)latex."
+
+latexpdf: latex
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex
+	@echo "Running LaTeX files through pdflatex..."
+	make -C _build/latex all-pdf
+	@echo "pdflatex finished; the PDF files are in _build/latex."
+
+changes:
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+	@echo
+	@echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+	@echo
+	@echo "Link check complete; look for any errors in the above output " \
+	      "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+	@echo "Testing of doctests in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/lib/jinja2/docs/_static/jinja-small.png b/lib/jinja2/docs/_static/jinja-small.png
new file mode 100644
index 0000000..455b4c3
--- /dev/null
+++ b/lib/jinja2/docs/_static/jinja-small.png
Binary files differ
diff --git a/lib/jinja2/docs/_templates/sidebarintro.html b/lib/jinja2/docs/_templates/sidebarintro.html
new file mode 100644
index 0000000..b7fcfda
--- /dev/null
+++ b/lib/jinja2/docs/_templates/sidebarintro.html
@@ -0,0 +1,20 @@
+<h3>About Jinja2</h3>
+<p>
+  Jinja2 is a full featured template engine for Python. It has full unicode
+  support, an optional integrated sandboxed execution environment, widely used
+  and BSD licensed.
+</p>
+<h3>Other Formats</h3>
+<p>
+  You can download the documentation in other formats as well:
+</p>
+<ul>
+  <li><a href="http://jinja.pocoo.org/docs/jinja-docs.pdf">as PDF</a>
+  <li><a href="http://jinja.pocoo.org/docs/jinja-docs.zip">as zipped HTML</a>
+</ul>
+<h3>Useful Links</h3>
+<ul>
+  <li><a href="http://jinja.pocoo.org/">The Jinja2 Website</a></li>
+  <li><a href="http://pypi.python.org/pypi/Jinja2">Jinja2 @ PyPI</a></li>
+  <li><a href="http://github.com/mitsuhiko/jinja2">Jinja2 @ github</a></li>
+</ul>
diff --git a/lib/jinja2/docs/_templates/sidebarlogo.html b/lib/jinja2/docs/_templates/sidebarlogo.html
new file mode 100644
index 0000000..ca211c6
--- /dev/null
+++ b/lib/jinja2/docs/_templates/sidebarlogo.html
@@ -0,0 +1,3 @@
+<p class="logo"><a href="{{ pathto(master_doc) }}">
+  <img class="logo" src="{{ pathto('_static/jinja-small.png', 1) }}" alt="Logo"/>
+</a></p>
diff --git a/lib/jinja2/docs/_themes/LICENSE b/lib/jinja2/docs/_themes/LICENSE
new file mode 100644
index 0000000..8daab7e
--- /dev/null
+++ b/lib/jinja2/docs/_themes/LICENSE
@@ -0,0 +1,37 @@
+Copyright (c) 2010 by Armin Ronacher.
+
+Some rights reserved.
+
+Redistribution and use in source and binary forms of the theme, with or
+without modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the following
+  disclaimer in the documentation and/or other materials provided
+  with the distribution.
+
+* The names of the contributors may not be used to endorse or
+  promote products derived from this software without specific
+  prior written permission.
+
+We kindly ask you to only use these themes in an unmodified manner just
+for Flask and Flask-related products, not for unrelated projects.  If you
+like the visual style and want to use it for your own projects, please
+consider making some larger changes to the themes (such as changing
+font faces, sizes, colors or margins).
+
+THIS THEME IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS THEME, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/lib/jinja2/docs/_themes/README b/lib/jinja2/docs/_themes/README
new file mode 100644
index 0000000..b3292bd
--- /dev/null
+++ b/lib/jinja2/docs/_themes/README
@@ -0,0 +1,31 @@
+Flask Sphinx Styles
+===================
+
+This repository contains sphinx styles for Flask and Flask related
+projects.  To use this style in your Sphinx documentation, follow
+this guide:
+
+1. put this folder as _themes into your docs folder.  Alternatively
+   you can also use git submodules to check out the contents there.
+2. add this to your conf.py:
+
+   sys.path.append(os.path.abspath('_themes'))
+   html_theme_path = ['_themes']
+   html_theme = 'flask'
+
+The following themes exist:
+
+- 'flask' - the standard flask documentation theme for large
+  projects
+- 'flask_small' - small one-page theme.  Intended to be used by
+  very small addon libraries for flask.
+
+The following options exist for the flask_small theme:
+
+   [options]
+   index_logo = ''              filename of a picture in _static
+                                to be used as replacement for the
+                                h1 in the index.rst file.
+   index_logo_height = 120px    height of the index logo
+   github_fork = ''             repository name on github for the
+                                "fork me" badge
diff --git a/lib/jinja2/docs/_themes/jinja/layout.html b/lib/jinja2/docs/_themes/jinja/layout.html
new file mode 100644
index 0000000..a0c9cab
--- /dev/null
+++ b/lib/jinja2/docs/_themes/jinja/layout.html
@@ -0,0 +1,8 @@
+{%- extends "basic/layout.html" %}
+{%- block relbar2 %}{% endblock %}
+{%- block footer %}
+    <div class="footer">
+      &copy; Copyright {{ copyright }}.
+      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>.
+    </div>
+{%- endblock %}
diff --git a/lib/jinja2/docs/_themes/jinja/relations.html b/lib/jinja2/docs/_themes/jinja/relations.html
new file mode 100644
index 0000000..3bbcde8
--- /dev/null
+++ b/lib/jinja2/docs/_themes/jinja/relations.html
@@ -0,0 +1,19 @@
+<h3>Related Topics</h3>
+<ul>
+  <li><a href="{{ pathto(master_doc) }}">Documentation overview</a><ul>
+  {%- for parent in parents %}
+  <li><a href="{{ parent.link|e }}">{{ parent.title }}</a><ul>
+  {%- endfor %}
+    {%- if prev %}
+      <li>Previous: <a href="{{ prev.link|e }}" title="{{ _('previous chapter')
+        }}">{{ prev.title }}</a></li>
+    {%- endif %}
+    {%- if next %}
+      <li>Next: <a href="{{ next.link|e }}" title="{{ _('next chapter')
+        }}">{{ next.title }}</a></li>
+    {%- endif %}
+  {%- for parent in parents %}
+  </ul></li>
+  {%- endfor %}
+  </ul></li>
+</ul>
diff --git a/lib/jinja2/docs/_themes/jinja/static/jinja.css_t b/lib/jinja2/docs/_themes/jinja/static/jinja.css_t
new file mode 100644
index 0000000..3291ba6
--- /dev/null
+++ b/lib/jinja2/docs/_themes/jinja/static/jinja.css_t
@@ -0,0 +1,396 @@
+/*
+ * jinja.css_t
+ * ~~~~~~~~~~~
+ *
+ * :copyright: Copyright 2011 by Armin Ronacher.
+ * :license: Flask Design License, see LICENSE for details.
+ */
+
+@import url(http://fonts.googleapis.com/css?family=Crimson+Text);
+
+{% set page_width = '940px' %}
+{% set sidebar_width = '220px' %}
+{% set font_family = 'Georgia, serif' %}
+{% set header_font_family = 'Crimson Text, ' ~ font_family %}
+ 
+@import url("basic.css");
+ 
+/* -- page layout ----------------------------------------------------------- */
+ 
+body {
+    font-family: {{ font_family }};
+    font-size: 17px;
+    background-color: white;
+    color: #000;
+    margin: 0;
+    padding: 0;
+}
+
+div.document {
+    width: {{ page_width }};
+    margin: 30px auto 0 auto;
+}
+
+div.documentwrapper {
+    float: left;
+    width: 100%;
+}
+
+div.bodywrapper {
+    margin: 0 0 0 {{ sidebar_width }};
+}
+
+div.sphinxsidebar {
+    width: {{ sidebar_width }};
+}
+
+hr {
+    border: 1px solid #B1B4B6;
+}
+ 
+div.body {
+    background-color: #ffffff;
+    color: #3E4349;
+    padding: 0 30px 0 30px;
+}
+
+img.floatingflask {
+    padding: 0 0 10px 10px;
+    float: right;
+}
+ 
+div.footer {
+    width: {{ page_width }};
+    margin: 20px auto 30px auto;
+    font-size: 14px;
+    color: #888;
+    text-align: right;
+}
+
+div.footer a {
+    color: #888;
+}
+
+div.related {
+    display: none;
+}
+ 
+div.sphinxsidebar a {
+    color: #444;
+    text-decoration: none;
+    border-bottom: 1px dotted #999;
+}
+
+div.sphinxsidebar a:hover {
+    border-bottom: 1px solid #999;
+}
+ 
+div.sphinxsidebar {
+    font-size: 15px;
+    line-height: 1.5;
+}
+
+div.sphinxsidebarwrapper {
+    padding: 18px 10px;
+}
+
+div.sphinxsidebarwrapper p.logo {
+    padding: 0 0 20px 0;
+    margin: 0;
+    text-align: center;
+}
+ 
+div.sphinxsidebar h3,
+div.sphinxsidebar h4 {
+    font-family: {{ font_family }};
+    color: #444;
+    font-size: 24px;
+    font-weight: normal;
+    margin: 0 0 5px 0;
+    padding: 0;
+}
+
+div.sphinxsidebar h4 {
+    font-size: 20px;
+}
+ 
+div.sphinxsidebar h3 a {
+    color: #444;
+}
+
+div.sphinxsidebar p.logo a,
+div.sphinxsidebar h3 a,
+div.sphinxsidebar p.logo a:hover,
+div.sphinxsidebar h3 a:hover {
+    border: none;
+}
+ 
+div.sphinxsidebar p {
+    color: #555;
+    margin: 10px 0;
+}
+
+div.sphinxsidebar ul {
+    margin: 10px 0;
+    padding: 0;
+    color: #000;
+}
+ 
+div.sphinxsidebar input {
+    border: 1px solid #ccc;
+    font-family: {{ font_family }};
+    font-size: 14px;
+}
+
+div.sphinxsidebar form.search input[name="q"] {
+    width: 130px;
+}
+ 
+/* -- body styles ----------------------------------------------------------- */
+ 
+a {
+    color: #aa0000;
+    text-decoration: underline;
+}
+ 
+a:hover {
+    color: #dd0000;
+    text-decoration: underline;
+}
+ 
+div.body h1,
+div.body h2,
+div.body h3,
+div.body h4,
+div.body h5,
+div.body h6 {
+    font-family: {{ header_font_family }};
+    font-weight: normal;
+    margin: 30px 0px 10px 0px;
+    padding: 0;
+    color: black;
+}
+ 
+div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; }
+div.body h2 { font-size: 180%; }
+div.body h3 { font-size: 150%; }
+div.body h4 { font-size: 130%; }
+div.body h5 { font-size: 100%; }
+div.body h6 { font-size: 100%; }
+ 
+a.headerlink {
+    color: #ddd;
+    padding: 0 4px;
+    text-decoration: none;
+}
+ 
+a.headerlink:hover {
+    color: #444;
+    background: #eaeaea;
+}
+ 
+div.body p, div.body dd, div.body li {
+    line-height: 1.4em;
+}
+
+div.admonition {
+    background: #fafafa;
+    margin: 20px -30px;
+    padding: 10px 30px;
+    border-top: 1px solid #ccc;
+    border-bottom: 1px solid #ccc;
+}
+
+div.admonition tt.xref, div.admonition a tt {
+    border-bottom: 1px solid #fafafa;
+}
+
+dd div.admonition {
+    margin-left: -60px;
+    padding-left: 60px;
+}
+
+div.admonition p.admonition-title {
+    font-family: {{ font_family }};
+    font-weight: normal;
+    font-size: 24px;
+    margin: 0 0 10px 0;
+    padding: 0;
+    line-height: 1;
+}
+
+div.admonition p.last {
+    margin-bottom: 0;
+}
+
+div.highlight {
+    background-color: white;
+}
+
+dt:target, .highlight {
+    background: #FAF3E8;
+}
+
+div.note {
+    background-color: #eee;
+    border: 1px solid #ccc;
+}
+ 
+div.seealso {
+    background-color: #ffc;
+    border: 1px solid #ff6;
+}
+ 
+div.topic {
+    background-color: #eee;
+}
+ 
+p.admonition-title {
+    display: inline;
+}
+ 
+p.admonition-title:after {
+    content: ":";
+}
+
+pre, tt {
+    font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
+    font-size: 0.85em;
+}
+
+img.screenshot {
+}
+
+tt.descname, tt.descclassname {
+    font-size: 0.95em;
+}
+
+tt.descname {
+    padding-right: 0.08em;
+}
+
+img.screenshot {
+    -moz-box-shadow: 2px 2px 4px #eee;
+    -webkit-box-shadow: 2px 2px 4px #eee;
+    box-shadow: 2px 2px 4px #eee;
+}
+
+table.docutils {
+    border: 1px solid #888;
+    -moz-box-shadow: 2px 2px 4px #eee;
+    -webkit-box-shadow: 2px 2px 4px #eee;
+    box-shadow: 2px 2px 4px #eee;
+}
+
+table.docutils td, table.docutils th {
+    border: 1px solid #888;
+    padding: 0.25em 0.7em;
+}
+
+table.field-list, table.footnote {
+    border: none;
+    -moz-box-shadow: none;
+    -webkit-box-shadow: none;
+    box-shadow: none;
+}
+
+table.footnote {
+    margin: 15px 0;
+    width: 100%;
+    border: 1px solid #eee;
+    background: #fdfdfd;
+    font-size: 0.9em;
+}
+
+table.footnote + table.footnote {
+    margin-top: -15px;
+    border-top: none;
+}
+
+table.field-list th {
+    padding: 0 0.8em 0 0;
+}
+
+table.field-list td {
+    padding: 0;
+}
+
+table.footnote td.label {
+    width: 0px;
+    padding: 0.3em 0 0.3em 0.5em;
+}
+
+table.footnote td {
+    padding: 0.3em 0.5em;
+}
+
+dl {
+    margin: 0;
+    padding: 0;
+}
+
+dl dd {
+    margin-left: 30px;
+}
+
+blockquote {
+    margin: 0 0 0 30px;
+    padding: 0;
+}
+
+ul, ol {
+    margin: 10px 0 10px 30px;
+    padding: 0;
+}
+ 
+pre {
+    background: #eee;
+    padding: 7px 30px;
+    margin: 15px -30px;
+    line-height: 1.3em;
+}
+
+dl pre, blockquote pre, li pre {
+    margin-left: -60px;
+    padding-left: 60px;
+}
+
+dl dl pre {
+    margin-left: -90px;
+    padding-left: 90px;
+}
+ 
+tt {
+    background-color: #E8EFF0;
+    color: #222;
+    /* padding: 1px 2px; */
+}
+
+tt.xref, a tt {
+    background-color: #E8EFF0;
+    border-bottom: 1px solid white;
+}
+
+a.reference {
+    text-decoration: none;
+    border-bottom: 1px dotted #bb0000;
+}
+
+a.reference:hover {
+    border-bottom: 1px solid #dd0000;
+}
+
+a.footnote-reference {
+    text-decoration: none;
+    font-size: 0.7em;
+    vertical-align: top;
+    border-bottom: 1px dotted #bb0000;
+}
+
+a.footnote-reference:hover {
+    border-bottom: 1px solid #dd0000;
+}
+
+a:hover tt {
+    background: #EEE;
+}
diff --git a/lib/jinja2/docs/_themes/jinja/theme.conf b/lib/jinja2/docs/_themes/jinja/theme.conf
new file mode 100644
index 0000000..10c7e56
--- /dev/null
+++ b/lib/jinja2/docs/_themes/jinja/theme.conf
@@ -0,0 +1,3 @@
+[theme]
+inherit = basic
+stylesheet = jinja.css
diff --git a/lib/jinja2/docs/api.rst b/lib/jinja2/docs/api.rst
new file mode 100644
index 0000000..58ffc9f
--- /dev/null
+++ b/lib/jinja2/docs/api.rst
@@ -0,0 +1,790 @@
+API
+===
+
+.. module:: jinja2
+    :synopsis: public Jinja2 API
+
+This document describes the API to Jinja2 and not the template language.  It
+will be most useful as reference to those implementing the template interface
+to the application and not those who are creating Jinja2 templates.
+
+Basics
+------
+
+Jinja2 uses a central object called the template :class:`Environment`.
+Instances of this class are used to store the configuration, global objects
+and are used to load templates from the file system or other locations.
+Even if you are creating templates from strings by using the constructor of
+:class:`Template` class, an environment is created automatically for you,
+albeit a shared one.
+
+Most applications will create one :class:`Environment` object on application
+initialization and use that to load templates.  In some cases it's however
+useful to have multiple environments side by side, if different configurations
+are in use.
+
+The simplest way to configure Jinja2 to load templates for your application
+looks roughly like this::
+
+    from jinja2 import Environment, PackageLoader
+    env = Environment(loader=PackageLoader('yourapplication', 'templates'))
+
+This will create a template environment with the default settings and a
+loader that looks up the templates in the `templates` folder inside the
+`yourapplication` python package.  Different loaders are available
+and you can also write your own if you want to load templates from a
+database or other resources.
+
+To load a template from this environment you just have to call the
+:meth:`get_template` method which then returns the loaded :class:`Template`::
+
+    template = env.get_template('mytemplate.html')
+
+To render it with some variables, just call the :meth:`render` method::
+
+    print template.render(the='variables', go='here')
+
+Using a template loader rather then passing strings to :class:`Template`
+or :meth:`Environment.from_string` has multiple advantages.  Besides being
+a lot easier to use it also enables template inheritance.
+
+
+Unicode
+-------
+
+Jinja2 is using Unicode internally which means that you have to pass Unicode
+objects to the render function or bytestrings that only consist of ASCII
+characters.  Additionally newlines are normalized to one end of line
+sequence which is per default UNIX style (``\n``).
+
+Python 2.x supports two ways of representing string objects.  One is the
+`str` type and the other is the `unicode` type, both of which extend a type
+called `basestring`.  Unfortunately the default is `str` which should not
+be used to store text based information unless only ASCII characters are
+used.  With Python 2.6 it is possible to make `unicode` the default on a per
+module level and with Python 3 it will be the default.
+
+To explicitly use a Unicode string you have to prefix the string literal
+with a `u`: ``u'Hänsel und Gretel sagen Hallo'``.  That way Python will
+store the string as Unicode by decoding the string with the character
+encoding from the current Python module.  If no encoding is specified this
+defaults to 'ASCII' which means that you can't use any non ASCII identifier.
+
+To set a better module encoding add the following comment to the first or
+second line of the Python module using the Unicode literal::
+
+    # -*- coding: utf-8 -*-
+
+We recommend utf-8 as Encoding for Python modules and templates as it's
+possible to represent every Unicode character in utf-8 and because it's
+backwards compatible to ASCII.  For Jinja2 the default encoding of templates
+is assumed to be utf-8.
+
+It is not possible to use Jinja2 to process non-Unicode data.  The reason
+for this is that Jinja2 uses Unicode already on the language level.  For
+example Jinja2 treats the non-breaking space as valid whitespace inside
+expressions which requires knowledge of the encoding or operating on an
+Unicode string.
+
+For more details about Unicode in Python have a look at the excellent
+`Unicode documentation`_.
+
+Another important thing is how Jinja2 is handling string literals in
+templates.  A naive implementation would be using Unicode strings for
+all string literals but it turned out in the past that this is problematic
+as some libraries are typechecking against `str` explicitly.  For example
+`datetime.strftime` does not accept Unicode arguments.  To not break it
+completely Jinja2 is returning `str` for strings that fit into ASCII and
+for everything else `unicode`:
+
+>>> m = Template(u"{% set a, b = 'foo', 'föö' %}").module
+>>> m.a
+'foo'
+>>> m.b
+u'f\xf6\xf6'
+
+
+.. _Unicode documentation: http://docs.python.org/dev/howto/unicode.html
+
+High Level API
+--------------
+
+The high-level API is the API you will use in the application to load and
+render Jinja2 templates.  The :ref:`low-level-api` on the other side is only
+useful if you want to dig deeper into Jinja2 or :ref:`develop extensions
+<jinja-extensions>`.
+
+.. autoclass:: Environment([options])
+    :members: from_string, get_template, select_template,
+              get_or_select_template, join_path, extend, compile_expression,
+              compile_templates, list_templates
+
+    .. attribute:: shared
+
+        If a template was created by using the :class:`Template` constructor
+        an environment is created automatically.  These environments are
+        created as shared environments which means that multiple templates
+        may have the same anonymous environment.  For all shared environments
+        this attribute is `True`, else `False`.
+
+    .. attribute:: sandboxed
+
+        If the environment is sandboxed this attribute is `True`.  For the
+        sandbox mode have a look at the documentation for the
+        :class:`~jinja2.sandbox.SandboxedEnvironment`.
+
+    .. attribute:: filters
+
+        A dict of filters for this environment.  As long as no template was
+        loaded it's safe to add new filters or remove old.  For custom filters
+        see :ref:`writing-filters`.  For valid filter names have a look at
+        :ref:`identifier-naming`.
+
+    .. attribute:: tests
+
+        A dict of test functions for this environment.  As long as no
+        template was loaded it's safe to modify this dict.  For custom tests
+        see :ref:`writing-tests`.  For valid test names have a look at
+        :ref:`identifier-naming`.
+
+    .. attribute:: globals
+
+        A dict of global variables.  These variables are always available
+        in a template.  As long as no template was loaded it's safe
+        to modify this dict.  For more details see :ref:`global-namespace`.
+        For valid object names have a look at :ref:`identifier-naming`.
+
+    .. automethod:: overlay([options])
+
+    .. method:: undefined([hint, obj, name, exc])
+
+        Creates a new :class:`Undefined` object for `name`.  This is useful
+        for filters or functions that may return undefined objects for
+        some operations.  All parameters except of `hint` should be provided
+        as keyword parameters for better readability.  The `hint` is used as
+        error message for the exception if provided, otherwise the error
+        message will be generated from `obj` and `name` automatically.  The exception
+        provided as `exc` is raised if something with the generated undefined
+        object is done that the undefined object does not allow.  The default
+        exception is :exc:`UndefinedError`.  If a `hint` is provided the
+        `name` may be ommited.
+
+        The most common way to create an undefined object is by providing
+        a name only::
+
+            return environment.undefined(name='some_name')
+
+        This means that the name `some_name` is not defined.  If the name
+        was from an attribute of an object it makes sense to tell the
+        undefined object the holder object to improve the error message::
+
+            if not hasattr(obj, 'attr'):
+                return environment.undefined(obj=obj, name='attr')
+
+        For a more complex example you can provide a hint.  For example
+        the :func:`first` filter creates an undefined object that way::
+
+            return environment.undefined('no first item, sequence was empty')            
+
+        If it the `name` or `obj` is known (for example because an attribute
+        was accessed) it shold be passed to the undefined object, even if
+        a custom `hint` is provided.  This gives undefined objects the
+        possibility to enhance the error message.
+
+.. autoclass:: Template
+    :members: module, make_module
+
+    .. attribute:: globals
+
+        The dict with the globals of that template.  It's unsafe to modify
+        this dict as it may be shared with other templates or the environment
+        that loaded the template.
+
+    .. attribute:: name
+
+        The loading name of the template.  If the template was loaded from a
+        string this is `None`.
+
+    .. attribute:: filename
+
+        The filename of the template on the file system if it was loaded from
+        there.  Otherwise this is `None`.
+
+    .. automethod:: render([context])
+
+    .. automethod:: generate([context])
+
+    .. automethod:: stream([context])
+
+
+.. autoclass:: jinja2.environment.TemplateStream()
+    :members: disable_buffering, enable_buffering, dump
+
+
+Autoescaping
+------------
+
+.. versionadded:: 2.4
+
+As of Jinja 2.4 the preferred way to do autoescaping is to enable the
+:ref:`autoescape-extension` and to configure a sensible default for
+autoescaping.  This makes it possible to enable and disable autoescaping
+on a per-template basis (HTML versus text for instance).
+
+Here a recommended setup that enables autoescaping for templates ending
+in ``'.html'``, ``'.htm'`` and ``'.xml'`` and disabling it by default
+for all other extensions::
+
+    def guess_autoescape(template_name):
+        if template_name is None or '.' not in template_name:
+            return False
+        ext = template_name.rsplit('.', 1)[1]
+        return ext in ('html', 'htm', 'xml')
+
+    env = Environment(autoescape=guess_autoescape,
+                      loader=PackageLoader('mypackage'),
+                      extensions=['jinja2.ext.autoescape'])
+
+When implementing a guessing autoescape function, make sure you also
+accept `None` as valid template name.  This will be passed when generating
+templates from strings.
+
+Inside the templates the behaviour can be temporarily changed by using
+the `autoescape` block (see :ref:`autoescape-overrides`).
+
+
+.. _identifier-naming:
+
+Notes on Identifiers
+--------------------
+
+Jinja2 uses the regular Python 2.x naming rules.  Valid identifiers have to
+match ``[a-zA-Z_][a-zA-Z0-9_]*``.  As a matter of fact non ASCII characters
+are currently not allowed.  This limitation will probably go away as soon as
+unicode identifiers are fully specified for Python 3.
+
+Filters and tests are looked up in separate namespaces and have slightly
+modified identifier syntax.  Filters and tests may contain dots to group
+filters and tests by topic.  For example it's perfectly valid to add a
+function into the filter dict and call it `to.unicode`.  The regular
+expression for filter and test identifiers is
+``[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)*```.
+
+
+Undefined Types
+---------------
+
+These classes can be used as undefined types.  The :class:`Environment`
+constructor takes an `undefined` parameter that can be one of those classes
+or a custom subclass of :class:`Undefined`.  Whenever the template engine is
+unable to look up a name or access an attribute one of those objects is
+created and returned.  Some operations on undefined values are then allowed,
+others fail.
+
+The closest to regular Python behavior is the `StrictUndefined` which
+disallows all operations beside testing if it's an undefined object.
+
+.. autoclass:: jinja2.Undefined()
+
+    .. attribute:: _undefined_hint
+
+        Either `None` or an unicode string with the error message for
+        the undefined object.
+
+    .. attribute:: _undefined_obj
+
+        Either `None` or the owner object that caused the undefined object
+        to be created (for example because an attribute does not exist).
+
+    .. attribute:: _undefined_name
+
+        The name for the undefined variable / attribute or just `None`
+        if no such information exists.
+
+    .. attribute:: _undefined_exception
+
+        The exception that the undefined object wants to raise.  This
+        is usually one of :exc:`UndefinedError` or :exc:`SecurityError`.
+
+    .. method:: _fail_with_undefined_error(\*args, \**kwargs)
+
+        When called with any arguments this method raises
+        :attr:`_undefined_exception` with an error message generated
+        from the undefined hints stored on the undefined object.
+
+.. autoclass:: jinja2.DebugUndefined()
+
+.. autoclass:: jinja2.StrictUndefined()
+
+Undefined objects are created by calling :attr:`undefined`.
+
+.. admonition:: Implementation
+
+    :class:`Undefined` objects are implemented by overriding the special
+    `__underscore__` methods.  For example the default :class:`Undefined`
+    class implements `__unicode__` in a way that it returns an empty
+    string, however `__int__` and others still fail with an exception.  To
+    allow conversion to int by returning ``0`` you can implement your own::
+
+        class NullUndefined(Undefined):
+            def __int__(self):
+                return 0
+            def __float__(self):
+                return 0.0
+
+    To disallow a method, just override it and raise
+    :attr:`~Undefined._undefined_exception`.  Because this is a very common
+    idom in undefined objects there is the helper method
+    :meth:`~Undefined._fail_with_undefined_error` that does the error raising
+    automatically.  Here a class that works like the regular :class:`Undefined`
+    but chokes on iteration::
+
+        class NonIterableUndefined(Undefined):
+            __iter__ = Undefined._fail_with_undefined_error
+
+
+The Context
+-----------
+
+.. autoclass:: jinja2.runtime.Context()
+    :members: resolve, get_exported, get_all
+
+    .. attribute:: parent
+
+        A dict of read only, global variables the template looks up.  These
+        can either come from another :class:`Context`, from the
+        :attr:`Environment.globals` or :attr:`Template.globals` or points
+        to a dict created by combining the globals with the variables
+        passed to the render function.  It must not be altered.
+
+    .. attribute:: vars
+
+        The template local variables.  This list contains environment and
+        context functions from the :attr:`parent` scope as well as local
+        modifications and exported variables from the template.  The template
+        will modify this dict during template evaluation but filters and
+        context functions are not allowed to modify it.
+
+    .. attribute:: environment
+
+        The environment that loaded the template.
+
+    .. attribute:: exported_vars
+
+        This set contains all the names the template exports.  The values for
+        the names are in the :attr:`vars` dict.  In order to get a copy of the
+        exported variables as dict, :meth:`get_exported` can be used.
+
+    .. attribute:: name
+
+        The load name of the template owning this context.
+
+    .. attribute:: blocks
+
+        A dict with the current mapping of blocks in the template.  The keys
+        in this dict are the names of the blocks, and the values a list of
+        blocks registered.  The last item in each list is the current active
+        block (latest in the inheritance chain).
+
+    .. attribute:: eval_ctx
+
+        The current :ref:`eval-context`.
+
+    .. automethod:: jinja2.runtime.Context.call(callable, \*args, \**kwargs)
+
+
+.. admonition:: Implementation
+
+    Context is immutable for the same reason Python's frame locals are
+    immutable inside functions.  Both Jinja2 and Python are not using the
+    context / frame locals as data storage for variables but only as primary
+    data source.
+
+    When a template accesses a variable the template does not define, Jinja2
+    looks up the variable in the context, after that the variable is treated
+    as if it was defined in the template.
+
+
+.. _loaders:
+
+Loaders
+-------
+
+Loaders are responsible for loading templates from a resource such as the
+file system.  The environment will keep the compiled modules in memory like
+Python's `sys.modules`.  Unlike `sys.modules` however this cache is limited in
+size by default and templates are automatically reloaded.
+All loaders are subclasses of :class:`BaseLoader`.  If you want to create your
+own loader, subclass :class:`BaseLoader` and override `get_source`.
+
+.. autoclass:: jinja2.BaseLoader
+    :members: get_source, load
+
+Here a list of the builtin loaders Jinja2 provides:
+
+.. autoclass:: jinja2.FileSystemLoader
+
+.. autoclass:: jinja2.PackageLoader
+
+.. autoclass:: jinja2.DictLoader
+
+.. autoclass:: jinja2.FunctionLoader
+
+.. autoclass:: jinja2.PrefixLoader
+
+.. autoclass:: jinja2.ChoiceLoader
+
+.. autoclass:: jinja2.ModuleLoader
+
+
+.. _bytecode-cache:
+
+Bytecode Cache
+--------------
+
+Jinja 2.1 and higher support external bytecode caching.  Bytecode caches make
+it possible to store the generated bytecode on the file system or a different
+location to avoid parsing the templates on first use.
+
+This is especially useful if you have a web application that is initialized on
+the first request and Jinja compiles many templates at once which slows down
+the application.
+
+To use a bytecode cache, instanciate it and pass it to the :class:`Environment`.
+
+.. autoclass:: jinja2.BytecodeCache
+    :members: load_bytecode, dump_bytecode, clear
+
+.. autoclass:: jinja2.bccache.Bucket
+    :members: write_bytecode, load_bytecode, bytecode_from_string,
+              bytecode_to_string, reset
+
+    .. attribute:: environment
+
+        The :class:`Environment` that created the bucket.
+
+    .. attribute:: key
+
+        The unique cache key for this bucket
+
+    .. attribute:: code
+
+        The bytecode if it's loaded, otherwise `None`.
+
+
+Builtin bytecode caches:
+
+.. autoclass:: jinja2.FileSystemBytecodeCache
+
+.. autoclass:: jinja2.MemcachedBytecodeCache
+
+
+Utilities
+---------
+
+These helper functions and classes are useful if you add custom filters or
+functions to a Jinja2 environment.
+
+.. autofunction:: jinja2.environmentfilter
+
+.. autofunction:: jinja2.contextfilter
+
+.. autofunction:: jinja2.evalcontextfilter
+
+.. autofunction:: jinja2.environmentfunction
+
+.. autofunction:: jinja2.contextfunction
+
+.. autofunction:: jinja2.evalcontextfunction
+
+.. function:: escape(s)
+
+    Convert the characters ``&``, ``<``, ``>``, ``'``, and ``"`` in string `s`
+    to HTML-safe sequences.  Use this if you need to display text that might
+    contain such characters in HTML.  This function will not escaped objects
+    that do have an HTML representation such as already escaped data.
+
+    The return value is a :class:`Markup` string.
+
+.. autofunction:: jinja2.clear_caches
+
+.. autofunction:: jinja2.is_undefined
+
+.. autoclass:: jinja2.Markup([string])
+    :members: escape, unescape, striptags
+
+.. admonition:: Note
+
+    The Jinja2 :class:`Markup` class is compatible with at least Pylons and
+    Genshi.  It's expected that more template engines and framework will pick
+    up the `__html__` concept soon.
+
+
+Exceptions
+----------
+
+.. autoexception:: jinja2.TemplateError
+
+.. autoexception:: jinja2.UndefinedError
+
+.. autoexception:: jinja2.TemplateNotFound
+
+.. autoexception:: jinja2.TemplatesNotFound
+
+.. autoexception:: jinja2.TemplateSyntaxError
+
+    .. attribute:: message
+
+        The error message as utf-8 bytestring.
+
+    .. attribute:: lineno
+
+        The line number where the error occurred
+
+    .. attribute:: name
+
+        The load name for the template as unicode string.
+
+    .. attribute:: filename
+
+        The filename that loaded the template as bytestring in the encoding
+        of the file system (most likely utf-8 or mbcs on Windows systems).
+
+    The reason why the filename and error message are bytestrings and not
+    unicode strings is that Python 2.x is not using unicode for exceptions
+    and tracebacks as well as the compiler.  This will change with Python 3.
+
+.. autoexception:: jinja2.TemplateAssertionError
+
+
+.. _writing-filters:
+
+Custom Filters
+--------------
+
+Custom filters are just regular Python functions that take the left side of
+the filter as first argument and the the arguments passed to the filter as
+extra arguments or keyword arguments.
+
+For example in the filter ``{{ 42|myfilter(23) }}`` the function would be
+called with ``myfilter(42, 23)``.  Here for example a simple filter that can
+be applied to datetime objects to format them::
+
+    def datetimeformat(value, format='%H:%M / %d-%m-%Y'):
+        return value.strftime(format)
+
+You can register it on the template environment by updating the
+:attr:`~Environment.filters` dict on the environment::
+
+    environment.filters['datetimeformat'] = datetimeformat
+
+Inside the template it can then be used as follows:
+
+.. sourcecode:: jinja
+
+    written on: {{ article.pub_date|datetimeformat }}
+    publication date: {{ article.pub_date|datetimeformat('%d-%m-%Y') }}
+
+Filters can also be passed the current template context or environment.  This
+is useful if a filter wants to return an undefined value or check the current
+:attr:`~Environment.autoescape` setting.  For this purpose three decorators
+exist: :func:`environmentfilter`, :func:`contextfilter` and
+:func:`evalcontextfilter`.
+
+Here a small example filter that breaks a text into HTML line breaks and
+paragraphs and marks the return value as safe HTML string if autoescaping is
+enabled::
+
+    import re
+    from jinja2 import evalcontextfilter, Markup, escape
+
+    _paragraph_re = re.compile(r'(?:\r\n|\r|\n){2,}')
+
+    @evalcontextfilter
+    def nl2br(eval_ctx, value):
+        result = u'\n\n'.join(u'<p>%s</p>' % p.replace('\n', '<br>\n')
+                              for p in _paragraph_re.split(escape(value)))
+        if eval_ctx.autoescape:
+            result = Markup(result)
+        return result
+
+Context filters work the same just that the first argument is the current
+active :class:`Context` rather then the environment.
+
+
+.. _eval-context:
+
+Evaluation Context
+------------------
+
+The evaluation context (short eval context or eval ctx) is a new object
+introducted in Jinja 2.4 that makes it possible to activate and deactivate
+compiled features at runtime.
+
+Currently it is only used to enable and disable the automatic escaping but
+can be used for extensions as well.
+
+In previous Jinja versions filters and functions were marked as
+environment callables in order to check for the autoescape status from the
+environment.  In new versions it's encouraged to check the setting from the
+evaluation context instead.
+
+Previous versions::
+
+    @environmentfilter
+    def filter(env, value):
+        result = do_something(value)
+        if env.autoescape:
+            result = Markup(result)
+        return result
+
+In new versions you can either use a :func:`contextfilter` and access the
+evaluation context from the actual context, or use a
+:func:`evalcontextfilter` which directly passes the evaluation context to
+the function::
+
+    @contextfilter
+    def filter(context, value):
+        result = do_something(value)
+        if context.eval_ctx.autoescape:
+            result = Markup(result)
+        return result
+
+    @evalcontextfilter
+    def filter(eval_ctx, value):
+        result = do_something(value)
+        if eval_ctx.autoescape:
+            result = Markup(result)
+        return result
+
+The evaluation context must not be modified at runtime.  Modifications
+must only happen with a :class:`nodes.EvalContextModifier` and
+:class:`nodes.ScopedEvalContextModifier` from an extension, not on the
+eval context object itself.
+
+.. autoclass:: jinja2.nodes.EvalContext
+
+   .. attribute:: autoescape
+
+      `True` or `False` depending on if autoescaping is active or not.
+
+   .. attribute:: volatile
+
+      `True` if the compiler cannot evaluate some expressions at compile
+      time.  At runtime this should always be `False`.
+
+
+.. _writing-tests:
+
+Custom Tests
+------------
+
+Tests work like filters just that there is no way for a test to get access
+to the environment or context and that they can't be chained.  The return
+value of a test should be `True` or `False`.  The purpose of a test is to
+give the template designers the possibility to perform type and conformability
+checks.
+
+Here a simple test that checks if a variable is a prime number::
+
+    import math
+
+    def is_prime(n):
+        if n == 2:
+            return True
+        for i in xrange(2, int(math.ceil(math.sqrt(n))) + 1):
+            if n % i == 0:
+                return False
+        return True
+        
+
+You can register it on the template environment by updating the
+:attr:`~Environment.tests` dict on the environment::
+
+    environment.tests['prime'] = is_prime
+
+A template designer can then use the test like this:
+
+.. sourcecode:: jinja
+
+    {% if 42 is prime %}
+        42 is a prime number
+    {% else %}
+        42 is not a prime number
+    {% endif %}
+
+
+.. _global-namespace:
+
+The Global Namespace
+--------------------
+
+Variables stored in the :attr:`Environment.globals` dict are special as they
+are available for imported templates too, even if they are imported without
+context.  This is the place where you can put variables and functions
+that should be available all the time.  Additionally :attr:`Template.globals`
+exist that are variables available to a specific template that are available
+to all :meth:`~Template.render` calls.
+
+
+.. _low-level-api:
+
+Low Level API
+-------------
+
+The low level API exposes functionality that can be useful to understand some
+implementation details, debugging purposes or advanced :ref:`extension
+<jinja-extensions>` techniques.  Unless you know exactly what you are doing we
+don't recommend using any of those.
+
+.. automethod:: Environment.lex
+
+.. automethod:: Environment.parse
+
+.. automethod:: Environment.preprocess
+
+.. automethod:: Template.new_context
+
+.. method:: Template.root_render_func(context)
+
+    This is the low level render function.  It's passed a :class:`Context`
+    that has to be created by :meth:`new_context` of the same template or
+    a compatible template.  This render function is generated by the
+    compiler from the template code and returns a generator that yields
+    unicode strings.
+
+    If an exception in the template code happens the template engine will
+    not rewrite the exception but pass through the original one.  As a
+    matter of fact this function should only be called from within a
+    :meth:`render` / :meth:`generate` / :meth:`stream` call.
+
+.. attribute:: Template.blocks
+
+    A dict of block render functions.  Each of these functions works exactly
+    like the :meth:`root_render_func` with the same limitations.
+
+.. attribute:: Template.is_up_to_date
+
+    This attribute is `False` if there is a newer version of the template
+    available, otherwise `True`.
+
+.. admonition:: Note
+
+    The low-level API is fragile.  Future Jinja2 versions will try not to
+    change it in a backwards incompatible way but modifications in the Jinja2
+    core may shine through.  For example if Jinja2 introduces a new AST node
+    in later versions that may be returned by :meth:`~Environment.parse`.
+
+The Meta API
+------------
+
+.. versionadded:: 2.2
+
+The meta API returns some information about abstract syntax trees that
+could help applications to implement more advanced template concepts.  All
+the functions of the meta API operate on an abstract syntax tree as
+returned by the :meth:`Environment.parse` method.
+
+.. autofunction:: jinja2.meta.find_undeclared_variables
+
+.. autofunction:: jinja2.meta.find_referenced_templates
diff --git a/lib/jinja2/docs/cache_extension.py b/lib/jinja2/docs/cache_extension.py
new file mode 100644
index 0000000..8fdefb5
--- /dev/null
+++ b/lib/jinja2/docs/cache_extension.py
@@ -0,0 +1,56 @@
+from jinja2 import nodes
+from jinja2.ext import Extension
+
+
+class FragmentCacheExtension(Extension):
+    # a set of names that trigger the extension.
+    tags = set(['cache'])
+
+    def __init__(self, environment):
+        super(FragmentCacheExtension, self).__init__(environment)
+
+        # add the defaults to the environment
+        environment.extend(
+            fragment_cache_prefix='',
+            fragment_cache=None
+        )
+
+    def parse(self, parser):
+        # the first token is the token that started the tag.  In our case
+        # we only listen to ``'cache'`` so this will be a name token with
+        # `cache` as value.  We get the line number so that we can give
+        # that line number to the nodes we create by hand.
+        lineno = parser.stream.next().lineno
+
+        # now we parse a single expression that is used as cache key.
+        args = [parser.parse_expression()]
+
+        # if there is a comma, the user provided a timeout.  If not use
+        # None as second parameter.
+        if parser.stream.skip_if('comma'):
+            args.append(parser.parse_expression())
+        else:
+            args.append(nodes.Const(None))
+
+        # now we parse the body of the cache block up to `endcache` and
+        # drop the needle (which would always be `endcache` in that case)
+        body = parser.parse_statements(['name:endcache'], drop_needle=True)
+
+        # now return a `CallBlock` node that calls our _cache_support
+        # helper method on this extension.
+        return nodes.CallBlock(self.call_method('_cache_support', args),
+                               [], [], body).set_lineno(lineno)
+
+    def _cache_support(self, name, timeout, caller):
+        """Helper callback."""
+        key = self.environment.fragment_cache_prefix + name
+
+        # try to load the block from the cache
+        # if there is no fragment in the cache, render it and store
+        # it in the cache.
+        rv = self.environment.fragment_cache.get(key)
+        if rv is not None:
+            return rv
+        rv = caller()
+        self.environment.fragment_cache.add(key, rv, timeout)
+        return rv
diff --git a/lib/jinja2/docs/changelog.rst b/lib/jinja2/docs/changelog.rst
new file mode 100644
index 0000000..9f11484
--- /dev/null
+++ b/lib/jinja2/docs/changelog.rst
@@ -0,0 +1,3 @@
+.. module:: jinja2
+
+.. include:: ../CHANGES
diff --git a/lib/jinja2/docs/conf.py b/lib/jinja2/docs/conf.py
new file mode 100644
index 0000000..6e990be
--- /dev/null
+++ b/lib/jinja2/docs/conf.py
@@ -0,0 +1,160 @@
+# -*- coding: utf-8 -*-
+#
+# Jinja2 documentation build configuration file, created by
+# sphinx-quickstart on Sun Apr 27 21:42:41 2008.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# The contents of this file are pickled, so don't put values in the namespace
+# that aren't pickleable (module imports are okay, they're removed automatically).
+#
+# All configuration values have a default value; values that are commented out
+# serve to show the default value.
+
+import sys, os
+
+# If your extensions are in another directory, add it here. If the directory
+# is relative to the documentation root, use os.path.abspath to make it
+# absolute, like shown here.
+sys.path.append(os.path.dirname(os.path.abspath(__file__)))
+
+# General configuration
+# ---------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc', 'jinjaext']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General substitutions.
+project = 'Jinja2'
+copyright = '2008, Armin Ronacher'
+
+# The default replacements for |version| and |release|, also used in various
+# other places throughout the built documents.
+#
+# The short X.Y version.
+import pkg_resources
+try:
+    release = pkg_resources.get_distribution('Jinja2').version
+except ImportError:
+    print 'To build the documentation, The distribution information of Jinja2'
+    print 'Has to be available.  Either install the package into your'
+    print 'development environment or run "setup.py develop" to setup the'
+    print 'metadata.  A virtualenv is recommended!'
+    sys.exit(1)
+if 'dev' in release:
+    release = release.split('dev')[0] + 'dev'
+version = '.'.join(release.split('.')[:2])
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'jinjaext.JinjaStyle'
+
+
+# Options for HTML output
+# -----------------------
+
+html_theme = 'jinja'
+html_theme_path = ['_themes']
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# no modindex
+html_use_modindex = False
+
+# If true, the reST sources are included in the HTML build as _sources/<name>.
+#html_copy_source = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.
+#html_use_opensearch = False
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Jinja2doc'
+
+
+# Options for LaTeX output
+# ------------------------
+
+# The paper size ('letter' or 'a4').
+latex_paper_size = 'a4'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, document class [howto/manual]).
+latex_documents = [
+  ('latexindex', 'Jinja2.tex', 'Jinja2 Documentation', 'Armin Ronacher',
+   'manual'),
+]
+
+# Additional stuff for LaTeX
+latex_elements = {
+    'fontpkg':      r'\usepackage{mathpazo}',
+    'papersize':    'a4paper',
+    'pointsize':    '12pt',
+    'preamble':     r'''
+\usepackage{jinjastyle}
+
+% i hate you latex
+\DeclareUnicodeCharacter{14D}{o}
+'''
+}
+
+latex_use_parts = True
+
+latex_additional_files = ['jinjastyle.sty', 'logo.pdf']
+
+# If false, no module index is generated.
+latex_use_modindex = False
+
+html_sidebars = {
+    'index':    ['sidebarlogo.html', 'sidebarintro.html', 'sourcelink.html',
+                 'searchbox.html'],
+    '**':       ['sidebarlogo.html', 'localtoc.html', 'relations.html',
+                 'sourcelink.html', 'searchbox.html']
+}
diff --git a/lib/jinja2/docs/contents.rst.inc b/lib/jinja2/docs/contents.rst.inc
new file mode 100644
index 0000000..35d6d23
--- /dev/null
+++ b/lib/jinja2/docs/contents.rst.inc
@@ -0,0 +1,29 @@
+Jinja2 Documentation
+--------------------
+
+.. toctree::
+   :maxdepth: 2
+
+   intro
+   api
+   sandbox
+   templates
+   extensions
+   integration
+   switching
+   tricks
+
+Additional Information
+----------------------
+
+.. toctree::
+   :maxdepth: 2
+
+   faq
+   changelog
+
+If you can't find the information you're looking for, have a look at the
+index of try to find it using the search function:
+
+* :ref:`genindex`
+* :ref:`search`
diff --git a/lib/jinja2/docs/extensions.rst b/lib/jinja2/docs/extensions.rst
new file mode 100644
index 0000000..c6b6ec9
--- /dev/null
+++ b/lib/jinja2/docs/extensions.rst
@@ -0,0 +1,347 @@
+.. _jinja-extensions:
+
+Extensions
+==========
+
+Jinja2 supports extensions that can add extra filters, tests, globals or even
+extend the parser.  The main motivation of extensions is it to move often used
+code into a reusable class like adding support for internationalization.
+
+
+Adding Extensions
+-----------------
+
+Extensions are added to the Jinja2 environment at creation time.  Once the
+environment is created additional extensions cannot be added.  To add an
+extension pass a list of extension classes or import paths to the
+`environment` parameter of the :class:`Environment` constructor.  The following
+example creates a Jinja2 environment with the i18n extension loaded::
+
+    jinja_env = Environment(extensions=['jinja2.ext.i18n'])
+
+
+.. _i18n-extension:
+
+i18n Extension
+--------------
+
+**Import name:** `jinja2.ext.i18n`
+
+Jinja2 currently comes with one extension, the i18n extension.  It can be
+used in combination with `gettext`_ or `babel`_.  If the i18n extension is
+enabled Jinja2 provides a `trans` statement that marks the wrapped string as
+translatable and calls `gettext`.
+
+After enabling dummy `_` function that forwards calls to `gettext` is added
+to the environment globals.  An internationalized application then has to
+provide at least an `gettext` and optoinally a `ngettext` function into the
+namespace.  Either globally or for each rendering.
+
+Environment Methods
+~~~~~~~~~~~~~~~~~~~
+
+After enabling of the extension the environment provides the following
+additional methods:
+
+.. method:: jinja2.Environment.install_gettext_translations(translations, newstyle=False)
+
+    Installs a translation globally for that environment.  The tranlations
+    object provided must implement at least `ugettext` and `ungettext`.
+    The `gettext.NullTranslations` and `gettext.GNUTranslations` classes
+    as well as `Babel`_\s `Translations` class are supported.
+
+    .. versionchanged:: 2.5 newstyle gettext added
+
+.. method:: jinja2.Environment.install_null_translations(newstyle=False)
+
+    Install dummy gettext functions.  This is useful if you want to prepare
+    the application for internationalization but don't want to implement the
+    full internationalization system yet.
+
+    .. versionchanged:: 2.5 newstyle gettext added
+
+.. method:: jinja2.Environment.install_gettext_callables(gettext, ngettext, newstyle=False)
+
+    Installs the given `gettext` and `ngettext` callables into the
+    environment as globals.  They are supposed to behave exactly like the
+    standard library's :func:`gettext.ugettext` and
+    :func:`gettext.ungettext` functions.
+
+    If `newstyle` is activated, the callables are wrapped to work like
+    newstyle callables.  See :ref:`newstyle-gettext` for more information.
+
+    .. versionadded:: 2.5
+
+.. method:: jinja2.Environment.uninstall_gettext_translations()
+
+    Uninstall the translations again.
+
+.. method:: jinja2.Environment.extract_translations(source)
+
+    Extract localizable strings from the given template node or source.
+
+    For every string found this function yields a ``(lineno, function,
+    message)`` tuple, where:
+
+    * `lineno` is the number of the line on which the string was found,
+    * `function` is the name of the `gettext` function used (if the
+      string was extracted from embedded Python code), and
+    *  `message` is the string itself (a `unicode` object, or a tuple
+       of `unicode` objects for functions with multiple string arguments).
+
+    If `Babel`_ is installed :ref:`the babel integration <babel-integration>`
+    can be used to extract strings for babel.
+
+For a web application that is available in multiple languages but gives all
+the users the same language (for example a multilingual forum software
+installed for a French community) may load the translations once and add the
+translation methods to the environment at environment generation time::
+
+    translations = get_gettext_translations()
+    env = Environment(extensions=['jinja2.ext.i18n'])
+    env.install_gettext_translations(translations)
+
+The `get_gettext_translations` function would return the translator for the
+current configuration.  (For example by using `gettext.find`)
+
+The usage of the `i18n` extension for template designers is covered as part
+:ref:`of the template documentation <i18n-in-templates>`.
+
+.. _gettext: http://docs.python.org/dev/library/gettext
+.. _Babel: http://babel.edgewall.org/
+
+.. _newstyle-gettext:
+
+Newstyle Gettext
+~~~~~~~~~~~~~~~~
+
+.. versionadded:: 2.5
+
+Starting with version 2.5 you can use newstyle gettext calls.  These are
+inspired by trac's internal gettext functions and are fully supported by
+the babel extraction tool.  They might not work as expected by other
+extraction tools in case you are not using Babel's.
+
+What's the big difference between standard and newstyle gettext calls?  In
+general they are less to type and less error prone.  Also if they are used
+in an autoescaping environment they better support automatic escaping.
+Here some common differences between old and new calls:
+
+standard gettext:
+
+.. sourcecode:: html+jinja
+
+    {{ gettext('Hello World!') }}
+    {{ gettext('Hello %(name)s!')|format(name='World') }}
+    {{ ngettext('%(num)d apple', '%(num)d apples', apples|count)|format(
+        num=apples|count
+    )}}
+
+newstyle gettext looks like this instead:
+
+.. sourcecode:: html+jinja
+
+    {{ gettext('Hello World!') }}
+    {{ gettext('Hello %(name)s!', name='World') }}
+    {{ ngettext('%(num)d apple', '%(num)d apples', apples|count) }}
+
+The advantages of newstyle gettext is that you have less to type and that
+named placeholders become mandatory.  The latter sounds like a
+disadvantage but solves a lot of troubles translators are often facing
+when they are unable to switch the positions of two placeholder.  With
+newstyle gettext, all format strings look the same.
+
+Furthermore with newstyle gettext, string formatting is also used if no
+placeholders are used which makes all strings behave exactly the same.
+Last but not least are newstyle gettext calls able to properly mark
+strings for autoescaping which solves lots of escaping related issues many
+templates are experiencing over time when using autoescaping.
+
+Expression Statement
+--------------------
+
+**Import name:** `jinja2.ext.do`
+
+The "do" aka expression-statement extension adds a simple `do` tag to the
+template engine that works like a variable expression but ignores the
+return value.
+
+.. _loopcontrols-extension:
+
+Loop Controls
+-------------
+
+**Import name:** `jinja2.ext.loopcontrols`
+
+This extension adds support for `break` and `continue` in loops.  After
+enabling Jinja2 provides those two keywords which work exactly like in
+Python.
+
+.. _with-extension:
+
+With Statement
+--------------
+
+**Import name:** `jinja2.ext.with_`
+
+.. versionadded:: 2.3
+
+This extension adds support for the with keyword.  Using this keyword it
+is possible to enforce a nested scope in a template.  Variables can be
+declared directly in the opening block of the with statement or using a
+standard `set` statement directly within.
+
+.. _autoescape-extension:
+
+Autoescape Extension
+--------------------
+
+**Import name:** `jinja2.ext.autoescape`
+
+.. versionadded:: 2.4
+
+The autoescape extension allows you to toggle the autoescape feature from
+within the template.  If the environment's :attr:`~Environment.autoescape`
+setting is set to `False` it can be activated, if it's `True` it can be
+deactivated.  The setting overriding is scoped.
+
+
+.. _writing-extensions:
+
+Writing Extensions
+------------------
+
+.. module:: jinja2.ext
+
+By writing extensions you can add custom tags to Jinja2.  This is a non trival
+task and usually not needed as the default tags and expressions cover all
+common use cases.  The i18n extension is a good example of why extensions are
+useful, another one would be fragment caching.
+
+When writing extensions you have to keep in mind that you are working with the
+Jinja2 template compiler which does not validate the node tree you are possing
+to it.  If the AST is malformed you will get all kinds of compiler or runtime
+errors that are horrible to debug.  Always make sure you are using the nodes
+you create correctly.  The API documentation below shows which nodes exist and
+how to use them.
+
+Example Extension
+~~~~~~~~~~~~~~~~~
+
+The following example implements a `cache` tag for Jinja2 by using the
+`Werkzeug`_ caching contrib module:
+
+.. literalinclude:: cache_extension.py
+    :language: python
+
+And here is how you use it in an environment::
+
+    from jinja2 import Environment
+    from werkzeug.contrib.cache import SimpleCache
+
+    env = Environment(extensions=[FragmentCacheExtension])
+    env.fragment_cache = SimpleCache()
+
+Inside the template it's then possible to mark blocks as cacheable.  The
+following example caches a sidebar for 300 seconds:
+
+.. sourcecode:: html+jinja
+
+    {% cache 'sidebar', 300 %}
+    <div class="sidebar">
+        ...
+    </div>
+    {% endcache %}
+
+.. _Werkzeug: http://werkzeug.pocoo.org/
+
+Extension API
+~~~~~~~~~~~~~
+
+Extensions always have to extend the :class:`jinja2.ext.Extension` class:
+
+.. autoclass:: Extension
+    :members: preprocess, filter_stream, parse, attr, call_method
+
+    .. attribute:: identifier
+
+        The identifier of the extension.  This is always the true import name
+        of the extension class and must not be changed.
+
+    .. attribute:: tags
+
+        If the extension implements custom tags this is a set of tag names
+        the extension is listening for.
+
+Parser API
+~~~~~~~~~~
+
+The parser passed to :meth:`Extension.parse` provides ways to parse
+expressions of different types.  The following methods may be used by
+extensions:
+
+.. autoclass:: jinja2.parser.Parser
+    :members: parse_expression, parse_tuple, parse_assign_target,
+              parse_statements, free_identifier, fail
+
+    .. attribute:: filename
+
+        The filename of the template the parser processes.  This is **not**
+        the load name of the template.  For the load name see :attr:`name`.
+        For templates that were not loaded form the file system this is
+        `None`.
+
+    .. attribute:: name
+
+        The load name of the template.
+
+    .. attribute:: stream
+
+        The current :class:`~jinja2.lexer.TokenStream`
+
+.. autoclass:: jinja2.lexer.TokenStream
+   :members: push, look, eos, skip, next, next_if, skip_if, expect
+
+   .. attribute:: current
+
+        The current :class:`~jinja2.lexer.Token`.
+
+.. autoclass:: jinja2.lexer.Token
+    :members: test, test_any
+
+    .. attribute:: lineno
+
+        The line number of the token
+
+    .. attribute:: type
+
+        The type of the token.  This string is interned so you may compare
+        it with arbitrary strings using the `is` operator.
+
+    .. attribute:: value
+
+        The value of the token.
+
+There is also a utility function in the lexer module that can count newline
+characters in strings:
+
+.. autofunction:: jinja2.lexer.count_newlines
+
+AST
+~~~
+
+The AST (Abstract Syntax Tree) is used to represent a template after parsing.
+It's build of nodes that the compiler then converts into executable Python
+code objects.  Extensions that provide custom statements can return nodes to
+execute custom Python code.
+
+The list below describes all nodes that are currently available.  The AST may
+change between Jinja2 versions but will stay backwards compatible.
+
+For more information have a look at the repr of :meth:`jinja2.Environment.parse`.
+
+.. module:: jinja2.nodes
+
+.. jinjanodes::
+
+.. autoexception:: Impossible
diff --git a/lib/jinja2/docs/faq.rst b/lib/jinja2/docs/faq.rst
new file mode 100644
index 0000000..2e4be8c
--- /dev/null
+++ b/lib/jinja2/docs/faq.rst
@@ -0,0 +1,191 @@
+Frequently Asked Questions
+==========================
+
+This page answers some of the often asked questions about Jinja.
+
+.. highlight:: html+jinja
+
+Why is it called Jinja?
+-----------------------
+
+The name Jinja was chosen because it's the name of a Japanese temple and
+temple and template share a similar pronunciation.  It is not named after
+the city in Uganda.
+
+How fast is it?
+---------------
+
+We really hate benchmarks especially since they don't reflect much.  The
+performance of a template depends on many factors and you would have to
+benchmark different engines in different situations.  The benchmarks from the
+testsuite show that Jinja2 has a similar performance to `Mako`_ and is between
+10 and 20 times faster than Django's template engine or Genshi.  These numbers
+should be taken with tons of salt as the benchmarks that took these numbers
+only test a few performance related situations such as looping.  Generally
+speaking the performance of a template engine doesn't matter much as the
+usual bottleneck in a web application is either the database or the application
+code.
+
+.. _Mako: http://www.makotemplates.org/
+
+How Compatible is Jinja2 with Django?
+-------------------------------------
+
+The default syntax of Jinja2 matches Django syntax in many ways.  However
+this similarity doesn't mean that you can use a Django template unmodified
+in Jinja2.  For example filter arguments use a function call syntax rather
+than a colon to separate filter name and arguments.  Additionally the
+extension interface in Jinja is fundamentally different from the Django one
+which means that your custom tags won't work any longer.
+
+Generally speaking you will use much less custom extensions as the Jinja
+template system allows you to use a certain subset of Python expressions
+which can replace most Django extensions.  For example instead of using
+something like this::
+
+    {% load comments %}
+    {% get_latest_comments 10 as latest_comments %}
+    {% for comment in latest_comments %}
+        ...
+    {% endfor %}
+
+You will most likely provide an object with attributes to retrieve
+comments from the database::
+
+    {% for comment in models.comments.latest(10) %}
+        ...
+    {% endfor %}
+
+Or directly provide the model for quick testing::
+
+    {% for comment in Comment.objects.order_by('-pub_date')[:10] %}
+        ...
+    {% endfor %}
+
+Please keep in mind that even though you may put such things into templates
+it still isn't a good idea.  Queries should go into the view code and not
+the template!
+
+Isn't it a terrible idea to put Logic into Templates?
+-----------------------------------------------------
+
+Without a doubt you should try to remove as much logic from templates as
+possible.  But templates without any logic mean that you have to do all
+the processing in the code which is boring and stupid.  A template engine
+that does that is shipped with Python and called `string.Template`.  Comes
+without loops and if conditions and is by far the fastest template engine
+you can get for Python.
+
+So some amount of logic is required in templates to keep everyone happy.
+And Jinja leaves it pretty much to you how much logic you want to put into
+templates.  There are some restrictions in what you can do and what not.
+
+Jinja2 neither allows you to put arbitrary Python code into templates nor
+does it allow all Python expressions.  The operators are limited to the
+most common ones and more advanced expressions such as list comprehensions
+and generator expressions are not supported.  This keeps the template engine
+easier to maintain and templates more readable.
+
+Why is Autoescaping not the Default?
+------------------------------------
+
+There are multiple reasons why automatic escaping is not the default mode
+and also not the recommended one.  While automatic escaping of variables
+means that you will less likely have an XSS problem it also causes a huge
+amount of extra processing in the template engine which can cause serious
+performance problems.  As Python doesn't provide a way to mark strings as
+unsafe Jinja has to hack around that limitation by providing a custom
+string class (the :class:`Markup` string) that safely interacts with safe
+and unsafe strings.
+
+With explicit escaping however the template engine doesn't have to perform
+any safety checks on variables.  Also a human knows not to escape integers
+or strings that may never contain characters one has to escape or already
+HTML markup.  For example when iterating over a list over a table of
+integers and floats for a table of statistics the template designer can
+omit the escaping because he knows that integers or floats don't contain
+any unsafe parameters.
+
+Additionally Jinja2 is a general purpose template engine and not only used
+for HTML/XML generation.  For example you may generate LaTeX, emails,
+CSS, JavaScript, or configuration files.
+
+Why is the Context immutable?
+-----------------------------
+
+When writing a :func:`contextfunction` or something similar you may have
+noticed that the context tries to stop you from modifying it.  If you have
+managed to modify the context by using an internal context API you may
+have noticed that changes in the context don't seem to be visible in the
+template.  The reason for this is that Jinja uses the context only as
+primary data source for template variables for performance reasons.
+
+If you want to modify the context write a function that returns a variable
+instead that one can assign to a variable by using set::
+
+    {% set comments = get_latest_comments() %}
+
+What is the speedups module and why is it missing?
+--------------------------------------------------
+
+To achieve a good performance with automatic escaping enabled, the escaping
+function was also implemented in pure C in older Jinja2 releases and used if
+Jinja2 was installed with the speedups module.
+
+Because this feature itself is very useful for non-template engines as
+well it was moved into a separate project on PyPI called `MarkupSafe`_.
+
+Jinja2 no longer ships with a C implementation of it but only the pure
+Python implementation.  It will however check if MarkupSafe is available
+and installed, and if it is, use the Markup class from MarkupSafe.
+
+So if you want the speedups, just import MarkupSafe.
+
+.. _MarkupSafe: http://pypi.python.org/pypi/MarkupSafe
+
+My tracebacks look weird.  What's happening?
+--------------------------------------------
+
+If the debugsupport module is not compiled and you are using a Python
+installation without ctypes (Python 2.4 without ctypes, Jython or Google's
+AppEngine) Jinja2 is unable to provide correct debugging information and
+the traceback may be incomplete.  There is currently no good workaround
+for Jython or the AppEngine as ctypes is unavailable there and it's not
+possible to use the debugsupport extension.
+
+Why is there no Python 2.3 support?
+-----------------------------------
+
+Python 2.3 is missing a lot of features that are used heavily in Jinja2.  This
+decision was made as with the upcoming Python 2.6 and 3.0 versions it becomes
+harder to maintain the code for older Python versions.  If you really need
+Python 2.3 support you either have to use `Jinja 1`_ or other templating
+engines that still support 2.3.
+
+My Macros are overriden by something
+------------------------------------
+
+In some situations the Jinja scoping appears arbitrary:
+
+layout.tmpl:
+
+.. sourcecode:: jinja
+
+    {% macro foo() %}LAYOUT{% endmacro %}
+    {% block body %}{% endblock %}
+
+child.tmpl:
+
+.. sourcecode:: jinja
+
+    {% extends 'layout.tmpl' %}
+    {% macro foo() %}CHILD{% endmacro %}
+    {% block body %}{{ foo() }}{% endblock %}
+
+This will print ``LAYOUT`` in Jinja2.  This is a side effect of having
+the parent template evaluated after the child one.  This allows child
+templates passing information to the parent template.  To avoid this
+issue rename the macro or variable in the parent template to have an
+uncommon prefix.
+
+.. _Jinja 1: http://jinja.pocoo.org/1/
diff --git a/lib/jinja2/docs/index.rst b/lib/jinja2/docs/index.rst
new file mode 100644
index 0000000..7225e1c
--- /dev/null
+++ b/lib/jinja2/docs/index.rst
@@ -0,0 +1,34 @@
+Welcome to Jinja2
+=================
+
+Jinja2 is a modern and designer friendly templating language for Python,
+modelled after Django's templates.  It is fast, widely used and secure
+with the optional sandboxed template execution environment:
+
+.. sourcecode:: html+jinja
+
+   <title>{% block title %}{% endblock %}</title>
+   <ul>
+   {% for user in users %}
+     <li><a href="{{ user.url }}">{{ user.username }}</a></li>
+   {% endfor %}
+   </ul>
+
+**Features:**
+
+-   sandboxed execution
+-   powerful automatic HTML escaping system for XSS prevention
+-   template inheritance
+-   compiles down to the optimal python code just in time
+-   optional ahead of time template compilation
+-   easy to debug.  Line numbers of exceptions directly point to
+    the correct line in the template.
+-   configurable syntax
+
+.. include:: contents.rst.inc
+
+If you can't find the information you're looking for, have a look at the
+index of try to find it using the search function:
+
+* :ref:`genindex`
+* :ref:`search`
diff --git a/lib/jinja2/docs/integration.rst b/lib/jinja2/docs/integration.rst
new file mode 100644
index 0000000..1875711
--- /dev/null
+++ b/lib/jinja2/docs/integration.rst
@@ -0,0 +1,88 @@
+Integration
+===========
+
+Jinja2 provides some code for integration into other tools such as frameworks,
+the `Babel`_ library or your favourite editor for fancy code highlighting.
+This is a brief description of whats included.
+
+.. _babel-integration:
+
+Babel Integration
+-----------------
+
+Jinja provides support for extracting gettext messages from templates via a
+`Babel`_ extractor entry point called `jinja2.ext.babel_extract`.  The Babel
+support is implemented as part of the :ref:`i18n-extension` extension.
+
+Gettext messages extracted from both `trans` tags and code expressions.
+
+To extract gettext messages from templates, the project needs a Jinja2 section
+in its Babel extraction method `mapping file`_:
+
+.. sourcecode:: ini
+
+    [jinja2: **/templates/**.html]
+    encoding = utf-8
+
+The syntax related options of the :class:`Environment` are also available as
+configuration values in the mapping file.  For example to tell the extraction
+that templates use ``%`` as `line_statement_prefix` you can use this code:
+
+.. sourcecode:: ini
+
+    [jinja2: **/templates/**.html]
+    encoding = utf-8
+    line_statement_prefix = %
+
+:ref:`jinja-extensions` may also be defined by passing a comma separated list
+of import paths as `extensions` value.  The i18n extension is added
+automatically.
+
+.. _mapping file: http://babel.edgewall.org/wiki/Documentation/messages.html#extraction-method-mapping-and-configuration
+
+Pylons
+------
+
+With `Pylons`_ 0.9.7 onwards it's incredible easy to integrate Jinja into a
+Pylons powered application.
+
+The template engine is configured in `config/environment.py`.  The configuration
+for Jinja2 looks something like that::
+
+    from jinja2 import Environment, PackageLoader
+    config['pylons.app_globals'].jinja_env = Environment(
+        loader=PackageLoader('yourapplication', 'templates')
+    )
+
+After that you can render Jinja templates by using the `render_jinja` function
+from the `pylons.templating` module.
+
+Additionally it's a good idea to set the Pylons' `c` object into strict mode.
+Per default any attribute to not existing attributes on the `c` object return
+an empty string and not an undefined object.  To change this just use this
+snippet and add it into your `config/environment.py`::
+
+    config['pylons.strict_c'] = True
+
+.. _Pylons: http://www.pylonshq.com/
+
+TextMate
+--------
+
+Inside the `ext` folder of Jinja2 there is a bundle for TextMate that supports
+syntax highlighting for Jinja1 and Jinja2 for text based templates as well as
+HTML.  It also contains a few often used snippets.
+
+Vim
+---
+
+A syntax plugin for `Vim`_ exists in the Vim-scripts directory as well as the
+ext folder of Jinja2.  `The script <http://www.vim.org/scripts/script.php?script_id=1856>`_
+supports Jinja1 and Jinja2.  Once installed two file types are available `jinja`
+and `htmljinja`.  The first one for text based templates, the latter for HTML
+templates.
+
+Copy the files into your `syntax` folder.
+
+.. _Babel: http://babel.edgewall.org/
+.. _Vim: http://www.vim.org/
diff --git a/lib/jinja2/docs/intro.rst b/lib/jinja2/docs/intro.rst
new file mode 100644
index 0000000..b08947d
--- /dev/null
+++ b/lib/jinja2/docs/intro.rst
@@ -0,0 +1,149 @@
+Introduction
+============
+
+This is the documentation for the Jinja2 general purpose templating language.
+Jinja2 is a library for Python 2.4 and onwards that is designed to be flexible,
+fast and secure.
+
+If you have any exposure to other text-based template languages, such as Smarty or
+Django, you should feel right at home with Jinja2.  It's both designer and
+developer friendly by sticking to Python's principles and adding functionality
+useful for templating environments.
+
+Prerequisites
+-------------
+
+Jinja2 needs at least **Python 2.4** to run.  Additionally a working C-compiler
+that can create python extensions should be installed for the debugger if you
+are using Python 2.4.
+
+If you don't have a working C-compiler and you are trying to install the source
+release with the debugsupport you will get a compiler error.
+
+.. _ctypes: http://python.net/crew/theller/ctypes/
+
+
+Installation
+------------
+
+You have multiple ways to install Jinja2.  If you are unsure what to do, go
+with the Python egg or tarball.
+
+As a Python egg (via easy_install)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can install the most recent Jinja2 version using `easy_install`_ or `pip`_::
+
+    easy_install Jinja2
+    pip install Jinja2
+
+This will install a Jinja2 egg in your Python installation's site-packages
+directory.
+
+(If you are installing from the windows command line omit the `sudo` and make
+sure to run the command as user with administrator rights)
+
+From the tarball release
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1.  Download the most recent tarball from the `download page`_
+2.  Unpack the tarball
+3.  ``sudo python setup.py install``
+
+Note that you either have to have setuptools or `distribute`_ installed,
+the latter is preferred.
+
+This will install Jinja2 into your Python installation's site-packages directory.
+
+.. _distribute: http://pypi.python.org/pypi/distribute
+
+Installing the development version
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1.  Install `git`_
+2.  ``git clone git://github.com/mitsuhiko/jinja2.git``
+3.  ``cd jinja2``
+4.  ``ln -s jinja2 /usr/lib/python2.X/site-packages``
+
+As an alternative to steps 4 you can also do ``python setup.py develop``
+which will install the package via distribute in development mode.  This also
+has the advantage that the C extensions are compiled.
+
+.. _download page: http://pypi.python.org/pypi/Jinja2
+.. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools
+.. _easy_install: http://peak.telecommunity.com/DevCenter/EasyInstall
+.. _pip: http://pypi.python.org/pypi/pip
+.. _git: http://git-scm.org/
+
+
+More Speed with MarkupSafe
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+As of version 2.5.1 Jinja2 will check for an installed `MarkupSafe`_
+module.  If it can find it, it will use the Markup class of that module
+instead of the one that comes with Jinja2.  `MarkupSafe` replaces the
+older speedups module that came with Jinja2 and has the advantage that is
+has a better setup script and will automatically attempt to install the C
+version and nicely fall back to a pure Python implementation if that is
+not possible.
+
+The C implementation of MarkupSafe is much faster and recommended when
+using Jinja2 with autoescaping.
+
+.. _MarkupSafe: http://pypi.python.org/pypi/MarkupSafe
+
+
+Enable the debug support Module
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+By default Jinja2 will not compile the debug support module.  Enabling this
+will fail if you don't have the Python headers or a working compiler.  This
+is often the case if you are installing Jinja2 from a windows machine.
+
+Because the debug support is only necessary for Python 2.4 you will not
+have to do this unless you run 2.4::
+
+    sudo python setup.py --with-debugsupport install
+
+
+Basic API Usage
+---------------
+
+This section gives you a brief introduction to the Python API for Jinja2
+templates.
+
+The most basic way to create a template and render it is through
+:class:`~jinja2.Template`.  This however is not the recommended way to
+work with it if your templates are not loaded from strings but the file
+system or another data source:
+
+>>> from jinja2 import Template
+>>> template = Template('Hello {{ name }}!')
+>>> template.render(name='John Doe')
+u'Hello John Doe!'
+
+By creating an instance of :class:`~jinja2.Template` you get back a new template
+object that provides a method called :meth:`~jinja2.Template.render` which when
+called with a dict or keyword arguments expands the template.  The dict
+or keywords arguments passed to the template are the so-called "context"
+of the template.
+
+What you can see here is that Jinja2 is using unicode internally and the
+return value is an unicode string.  So make sure that your application is
+indeed using unicode internally.
+
+
+Experimental Python 3 Support
+-----------------------------
+
+Jinja 2.3 brings experimental support for Python 3.  It means that all
+unittests pass on the new version, but there might still be small bugs in
+there and behavior might be inconsistent.  If you notice any bugs, please
+provide feedback in the `Jinja bug tracker`_.
+
+Also please keep in mind that the documentation is written with Python 2
+in mind, you will have to adapt the shown code examples to Python 3 syntax
+for yourself.
+
+
+.. _Jinja bug tracker: http://github.com/mitsuhiko/jinja2/issues
diff --git a/lib/jinja2/docs/jinjaext.py b/lib/jinja2/docs/jinjaext.py
new file mode 100644
index 0000000..12b5447
--- /dev/null
+++ b/lib/jinja2/docs/jinjaext.py
@@ -0,0 +1,193 @@
+# -*- coding: utf-8 -*-
+"""
+    Jinja Documentation Extensions
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Support for automatically documenting filters and tests.
+
+    :copyright: Copyright 2008 by Armin Ronacher.
+    :license: BSD.
+"""
+import os
+import re
+import inspect
+import jinja2
+from itertools import islice
+from types import BuiltinFunctionType
+from docutils import nodes
+from docutils.statemachine import ViewList
+from sphinx.ext.autodoc import prepare_docstring
+from sphinx.application import TemplateBridge
+from pygments.style import Style
+from pygments.token import Keyword, Name, Comment, String, Error, \
+     Number, Operator, Generic
+from jinja2 import Environment, FileSystemLoader
+
+
+def parse_rst(state, content_offset, doc):
+    node = nodes.section()
+    # hack around title style bookkeeping
+    surrounding_title_styles = state.memo.title_styles
+    surrounding_section_level = state.memo.section_level
+    state.memo.title_styles = []
+    state.memo.section_level = 0
+    state.nested_parse(doc, content_offset, node, match_titles=1)
+    state.memo.title_styles = surrounding_title_styles
+    state.memo.section_level = surrounding_section_level
+    return node.children
+
+
+class JinjaStyle(Style):
+    title = 'Jinja Style'
+    default_style = ""
+    styles = {
+        Comment:                    'italic #aaaaaa',
+        Comment.Preproc:            'noitalic #B11414',
+        Comment.Special:            'italic #505050',
+
+        Keyword:                    'bold #B80000',
+        Keyword.Type:               '#808080',
+
+        Operator.Word:              'bold #B80000',
+
+        Name.Builtin:               '#333333',
+        Name.Function:              '#333333',
+        Name.Class:                 'bold #333333',
+        Name.Namespace:             'bold #333333',
+        Name.Entity:                'bold #363636',
+        Name.Attribute:             '#686868',
+        Name.Tag:                   'bold #686868',
+        Name.Decorator:             '#686868',
+
+        String:                     '#AA891C',
+        Number:                     '#444444',
+
+        Generic.Heading:            'bold #000080',
+        Generic.Subheading:         'bold #800080',
+        Generic.Deleted:            '#aa0000',
+        Generic.Inserted:           '#00aa00',
+        Generic.Error:              '#aa0000',
+        Generic.Emph:               'italic',
+        Generic.Strong:             'bold',
+        Generic.Prompt:             '#555555',
+        Generic.Output:             '#888888',
+        Generic.Traceback:          '#aa0000',
+
+        Error:                      '#F00 bg:#FAA'
+    }
+
+
+_sig_re = re.compile(r'^[a-zA-Z_][a-zA-Z0-9_]*(\(.*?\))')
+
+
+def format_function(name, aliases, func):
+    lines = inspect.getdoc(func).splitlines()
+    signature = '()'
+    if isinstance(func, BuiltinFunctionType):
+        match = _sig_re.match(lines[0])
+        if match is not None:
+            del lines[:1 + bool(lines and not lines[0])]
+            signature = match.group(1)
+    else:
+        try:
+            argspec = inspect.getargspec(func)
+            if getattr(func, 'environmentfilter', False) or \
+               getattr(func, 'contextfilter', False) or \
+               getattr(func, 'evalcontextfilter', False):
+                del argspec[0][0]
+            signature = inspect.formatargspec(*argspec)
+        except:
+            pass
+    result = ['.. function:: %s%s' % (name, signature), '']
+    result.extend('    ' + line for line in lines)
+    if aliases:
+        result.extend(('', '    :aliases: %s' % ', '.join(
+                      '``%s``' % x for x in sorted(aliases))))
+    return result
+
+
+def dump_functions(mapping):
+    def directive(dirname, arguments, options, content, lineno,
+                      content_offset, block_text, state, state_machine):
+        reverse_mapping = {}
+        for name, func in mapping.iteritems():
+            reverse_mapping.setdefault(func, []).append(name)
+        filters = []
+        for func, names in reverse_mapping.iteritems():
+            aliases = sorted(names, key=lambda x: len(x))
+            name = aliases.pop()
+            filters.append((name, aliases, func))
+        filters.sort()
+
+        result = ViewList()
+        for name, aliases, func in filters:
+            for item in format_function(name, aliases, func):
+                result.append(item, '<jinjaext>')
+
+        node = nodes.paragraph()
+        state.nested_parse(result, content_offset, node)
+        return node.children
+    return directive
+
+
+from jinja2.defaults import DEFAULT_FILTERS, DEFAULT_TESTS
+jinja_filters = dump_functions(DEFAULT_FILTERS)
+jinja_tests = dump_functions(DEFAULT_TESTS)
+
+
+def jinja_nodes(dirname, arguments, options, content, lineno,
+                content_offset, block_text, state, state_machine):
+    from jinja2.nodes import Node
+    doc = ViewList()
+    def walk(node, indent):
+        p = ' ' * indent
+        sig = ', '.join(node.fields)
+        doc.append(p + '.. autoclass:: %s(%s)' % (node.__name__, sig), '')
+        if node.abstract:
+            members = []
+            for key, name in node.__dict__.iteritems():
+                if not key.startswith('_') and \
+                   not hasattr(node.__base__, key) and callable(name):
+                    members.append(key)
+            if members:
+                members.sort()
+                doc.append('%s :members: %s' % (p, ', '.join(members)), '')
+        if node.__base__ != object:
+            doc.append('', '')
+            doc.append('%s :Node type: :class:`%s`' %
+                       (p, node.__base__.__name__), '')
+        doc.append('', '')
+        children = node.__subclasses__()
+        children.sort(key=lambda x: x.__name__.lower())
+        for child in children:
+            walk(child, indent)
+    walk(Node, 0)
+    return parse_rst(state, content_offset, doc)
+
+
+def inject_toc(app, doctree, docname):
+    titleiter = iter(doctree.traverse(nodes.title))
+    try:
+        # skip first title, we are not interested in that one
+        titleiter.next()
+        title = titleiter.next()
+        # and check if there is at least another title
+        titleiter.next()
+    except StopIteration:
+        return
+    tocnode = nodes.section('')
+    tocnode['classes'].append('toc')
+    toctitle = nodes.section('')
+    toctitle['classes'].append('toctitle')
+    toctitle.append(nodes.title(text='Table Of Contents'))
+    tocnode.append(toctitle)
+    tocnode += doctree.document.settings.env.get_toc_for(docname)[0][1]
+    title.parent.insert(title.parent.children.index(title), tocnode)
+
+
+def setup(app):
+    app.add_directive('jinjafilters', jinja_filters, 0, (0, 0, 0))
+    app.add_directive('jinjatests', jinja_tests, 0, (0, 0, 0))
+    app.add_directive('jinjanodes', jinja_nodes, 0, (0, 0, 0))
+    # uncomment for inline toc.  links are broken unfortunately
+    ##app.connect('doctree-resolved', inject_toc)
diff --git a/lib/jinja2/docs/jinjastyle.sty b/lib/jinja2/docs/jinjastyle.sty
new file mode 100644
index 0000000..da811ce
--- /dev/null
+++ b/lib/jinja2/docs/jinjastyle.sty
@@ -0,0 +1,119 @@
+\definecolor{TitleColor}{rgb}{0,0,0}
+\definecolor{InnerLinkColor}{rgb}{0,0,0}
+\definecolor{OuterLinkColor}{rgb}{0.8,0,0}
+
+\renewcommand{\maketitle}{%
+  \begin{titlepage}%
+    \let\footnotesize\small
+    \let\footnoterule\relax
+    \ifsphinxpdfoutput
+      \begingroup
+      % This \def is required to deal with multi-line authors; it
+      % changes \\ to ', ' (comma-space), making it pass muster for
+      % generating document info in the PDF file.
+      \def\\{, }
+      \pdfinfo{
+        /Author (\@author)
+        /Title (\@title)
+      }
+      \endgroup
+    \fi
+    \begin{flushright}%
+      %\sphinxlogo%
+      {\center
+        \vspace*{3cm}
+      	\includegraphics{logo.pdf}
+        \vspace{3cm}
+	\par
+        {\rm\Huge \@title \par}%
+        {\em\LARGE \py@release\releaseinfo \par}
+        {\large
+         \@date \par
+         \py@authoraddress \par
+        }}%
+    \end{flushright}%\par
+    \@thanks
+  \end{titlepage}%
+  \cleardoublepage%
+  \setcounter{footnote}{0}%
+  \let\thanks\relax\let\maketitle\relax
+  %\gdef\@thanks{}\gdef\@author{}\gdef\@title{}
+}
+
+\fancypagestyle{normal}{
+  \fancyhf{}
+  \fancyfoot[LE,RO]{{\thepage}}
+  \fancyfoot[LO]{{\nouppercase{\rightmark}}}
+  \fancyfoot[RE]{{\nouppercase{\leftmark}}}
+  \fancyhead[LE,RO]{{ \@title, \py@release}}
+  \renewcommand{\headrulewidth}{0.4pt}
+  \renewcommand{\footrulewidth}{0.4pt}
+}
+
+\fancypagestyle{plain}{
+  \fancyhf{}
+  \fancyfoot[LE,RO]{{\thepage}}
+  \renewcommand{\headrulewidth}{0pt}
+  \renewcommand{\footrulewidth}{0.4pt}
+}
+
+\titleformat{\section}{\Large}%
+            {\py@TitleColor\thesection}{0.5em}{\py@TitleColor}{\py@NormalColor}
+\titleformat{\subsection}{\large}%
+            {\py@TitleColor\thesubsection}{0.5em}{\py@TitleColor}{\py@NormalColor}
+\titleformat{\subsubsection}{}%
+            {\py@TitleColor\thesubsubsection}{0.5em}{\py@TitleColor}{\py@NormalColor}
+\titleformat{\paragraph}{\large}%
+            {\py@TitleColor}{0em}{\py@TitleColor}{\py@NormalColor}
+
+\ChNameVar{\raggedleft\normalsize}
+\ChNumVar{\raggedleft \bfseries\Large}
+\ChTitleVar{\raggedleft \rm\Huge}
+
+\renewcommand\thepart{\@Roman\c@part}
+\renewcommand\part{%
+   \pagestyle{plain}
+   \if@noskipsec \leavevmode \fi
+   \cleardoublepage
+   \vspace*{6cm}%
+   \@afterindentfalse
+   \secdef\@part\@spart}
+
+\def\@part[#1]#2{%
+    \ifnum \c@secnumdepth >\m@ne
+      \refstepcounter{part}%
+      \addcontentsline{toc}{part}{\thepart\hspace{1em}#1}%
+    \else
+      \addcontentsline{toc}{part}{#1}%
+    \fi
+    {\parindent \z@ %\center
+     \interlinepenalty \@M
+     \normalfont
+     \ifnum \c@secnumdepth >\m@ne
+       \rm\Large \partname~\thepart
+       \par\nobreak
+     \fi
+     \MakeUppercase{\rm\Huge #2}%
+     \markboth{}{}\par}%
+    \nobreak
+    \vskip 8ex
+    \@afterheading}
+\def\@spart#1{%
+    {\parindent \z@ %\center
+     \interlinepenalty \@M
+     \normalfont
+     \huge \bfseries #1\par}%
+     \nobreak
+     \vskip 3ex
+     \@afterheading}
+
+% use inconsolata font
+\usepackage{inconsolata}
+
+% fix single quotes, for inconsolata. (does not work)
+%%\usepackage{textcomp}
+%%\begingroup
+%%  \catcode`'=\active
+%%  \g@addto@macro\@noligs{\let'\textsinglequote}
+%%  \endgroup
+%%\endinput
diff --git a/lib/jinja2/docs/latexindex.rst b/lib/jinja2/docs/latexindex.rst
new file mode 100644
index 0000000..300e60d
--- /dev/null
+++ b/lib/jinja2/docs/latexindex.rst
@@ -0,0 +1,6 @@
+:orphan:
+
+Jinja2 Documentation
+====================
+
+.. include:: contents.rst.inc
diff --git a/lib/jinja2/docs/logo.pdf b/lib/jinja2/docs/logo.pdf
new file mode 100644
index 0000000..3e8a9cf
--- /dev/null
+++ b/lib/jinja2/docs/logo.pdf
Binary files differ
diff --git a/lib/jinja2/docs/sandbox.rst b/lib/jinja2/docs/sandbox.rst
new file mode 100644
index 0000000..1302f18
--- /dev/null
+++ b/lib/jinja2/docs/sandbox.rst
@@ -0,0 +1,94 @@
+Sandbox
+=======
+
+The Jinja2 sandbox can be used to evaluate untrusted code.  Access to unsafe
+attributes and methods is prohibited.
+
+Assuming `env` is a :class:`SandboxedEnvironment` in the default configuration
+the following piece of code shows how it works:
+
+>>> env.from_string("{{ func.func_code }}").render(func=lambda:None)
+u''
+>>> env.from_string("{{ func.func_code.do_something }}").render(func=lambda:None)
+Traceback (most recent call last):
+  ...
+SecurityError: access to attribute 'func_code' of 'function' object is unsafe.
+
+API
+---
+
+.. module:: jinja2.sandbox
+
+.. autoclass:: SandboxedEnvironment([options])
+    :members: is_safe_attribute, is_safe_callable, default_binop_table,
+              default_unop_table, intercepted_binops, intercepted_unops,
+              call_binop, call_unop
+
+.. autoclass:: ImmutableSandboxedEnvironment([options])
+
+.. autoexception:: SecurityError
+
+.. autofunction:: unsafe
+
+.. autofunction:: is_internal_attribute
+
+.. autofunction:: modifies_known_mutable
+
+.. admonition:: Note
+
+    The Jinja2 sandbox alone is no solution for perfect security.  Especially
+    for web applications you have to keep in mind that users may create
+    templates with arbitrary HTML in so it's crucial to ensure that (if you
+    are running multiple users on the same server) they can't harm each other
+    via JavaScript insertions and much more.
+
+    Also the sandbox is only as good as the configuration.  We stronly
+    recommend only passing non-shared resources to the template and use
+    some sort of whitelisting for attributes.
+
+    Also keep in mind that templates may raise runtime or compile time errors,
+    so make sure to catch them.
+
+Operator Intercepting
+---------------------
+
+.. versionadded:: 2.6
+
+For maximum performace Jinja2 will let operators call directly the type
+specific callback methods.  This means that it's not possible to have this
+intercepted by overriding :meth:`Environment.call`.  Furthermore a
+conversion from operator to special method is not always directly possible
+due to how operators work.  For instance for divisions more than one
+special method exist.
+
+With Jinja 2.6 there is now support for explicit operator intercepting.
+This can be used to customize specific operators as necessary.  In order
+to intercept an operator one has to override the
+:attr:`SandboxedEnvironment.intercepted_binops` attribute.  Once the
+operator that needs to be intercepted is added to that set Jinja2 will
+generate bytecode that calls the :meth:`SandboxedEnvironment.call_binop`
+function.  For unary operators the `unary` attributes and methods have to
+be used instead.
+
+The default implementation of :attr:`SandboxedEnvironment.call_binop`
+will use the :attr:`SandboxedEnvironment.binop_table` to translate
+operator symbols into callbacks performing the default operator behavior.
+
+This example shows how the power (``**``) operator can be disabled in
+Jinja2::
+
+    from jinja2.sandbox import SandboxedEnvironment
+
+
+    class MyEnvironment(SandboxedEnvironment):
+        intercepted_binops = frozenset(['**'])
+
+        def call_binop(self, context, operator, left, right):
+            if operator == '**':
+                return self.undefined('the power operator is unavailable')
+            return SandboxedEnvironment.call_binop(self, context,
+                                                   operator, left, right)
+
+Make sure to always call into the super method, even if you are not
+intercepting the call.  Jinja2 might internally call the method to
+evaluate expressions.
diff --git a/lib/jinja2/docs/switching.rst b/lib/jinja2/docs/switching.rst
new file mode 100644
index 0000000..ba3cfb1
--- /dev/null
+++ b/lib/jinja2/docs/switching.rst
@@ -0,0 +1,242 @@
+Switching from other Template Engines
+=====================================
+
+.. highlight:: html+jinja
+
+If you have used a different template engine in the past and want to swtich
+to Jinja2 here is a small guide that shows the basic syntatic and semantic
+changes between some common, similar text template engines for Python.
+
+Jinja1
+------
+
+Jinja2 is mostly compatible with Jinja1 in terms of API usage and template
+syntax.  The differences between Jinja1 and 2 are explained in the following
+list.
+
+API
+~~~
+
+Loaders
+    Jinja2 uses a different loader API.  Because the internal representation
+    of templates changed there is no longer support for external caching
+    systems such as memcached.  The memory consumed by templates is comparable
+    with regular Python modules now and external caching doesn't give any
+    advantage.  If you have used a custom loader in the past have a look at
+    the new :ref:`loader API <loaders>`.
+
+Loading templates from strings
+    In the past it was possible to generate templates from a string with the
+    default environment configuration by using `jinja.from_string`.  Jinja2
+    provides a :class:`Template` class that can be used to do the same, but
+    with optional additional configuration.
+
+Automatic unicode conversion
+    Jinja1 performed automatic conversion of bytestrings in a given encoding
+    into unicode objects.  This conversion is no longer implemented as it
+    was inconsistent as most libraries are using the regular Python ASCII
+    bytestring to Unicode conversion.  An application powered by Jinja2
+    *has to* use unicode internally everywhere or make sure that Jinja2 only
+    gets unicode strings passed.
+
+i18n
+    Jinja1 used custom translators for internationalization.  i18n is now
+    available as Jinja2 extension and uses a simpler, more gettext friendly
+    interface and has support for babel.  For more details see
+    :ref:`i18n-extension`.
+
+Internal methods
+    Jinja1 exposed a few internal methods on the environment object such
+    as `call_function`, `get_attribute` and others.  While they were marked
+    as being an internal method it was possible to override them.  Jinja2
+    doesn't have equivalent methods.
+
+Sandbox
+    Jinja1 was running sandbox mode by default.  Few applications actually
+    used that feature so it became optional in Jinja2.  For more details
+    about the sandboxed execution see :class:`SandboxedEnvironment`.
+
+Context
+    Jinja1 had a stacked context as storage for variables passed to the
+    environment.  In Jinja2 a similar object exists but it doesn't allow
+    modifications nor is it a singleton.  As inheritance is dynamic now
+    multiple context objects may exist during template evaluation.
+
+Filters and Tests
+    Filters and tests are regular functions now.  It's no longer necessary
+    and allowed to use factory functions.
+
+
+Templates
+~~~~~~~~~
+
+Jinja2 has mostly the same syntax as Jinja1.  What's different is that
+macros require parentheses around the argument list now.
+
+Additionally Jinja2 allows dynamic inheritance now and dynamic includes.
+The old helper function `rendertemplate` is gone now, `include` can be used
+instead.  Includes no longer import macros and variable assignments, for
+that the new `import` tag is used.  This concept is explained in the
+:ref:`import` documentation.
+
+Another small change happened in the `for`-tag.  The special loop variable
+doesn't have a `parent` attribute, instead you have to alias the loop
+yourself.  See :ref:`accessing-the-parent-loop` for more details.
+
+
+Django
+------
+
+If you have previously worked with Django templates, you should find
+Jinja2 very familiar.  In fact, most of the syntax elements look and
+work the same.
+
+However, Jinja2 provides some more syntax elements covered in the
+documentation and some work a bit different.
+
+This section covers the template changes.  As the API is fundamentally
+different we won't cover it here.
+
+Method Calls
+~~~~~~~~~~~~
+
+In Django method calls work implicitly.  With Jinja2 you have to specify that
+you want to call an object.  Thus this Django code::
+
+    {% for page in user.get_created_pages %}
+        ...
+    {% endfor %}
+    
+will look like this in Jinja::
+
+    {% for page in user.get_created_pages() %}
+        ...
+    {% endfor %}
+
+This allows you to pass variables to the function which is also used for macros
+which is not possible in Django.
+
+Conditions
+~~~~~~~~~~
+
+In Django you can use the following constructs to check for equality::
+
+    {% ifequal foo "bar" %}
+        ...
+    {% else %}
+        ...
+    {% endifequal %}
+
+In Jinja2 you can use the normal if statement in combination with operators::
+
+    {% if foo == 'bar' %}
+        ...
+    {% else %}
+        ...
+    {% endif %}
+
+You can also have multiple elif branches in your template::
+
+    {% if something %}
+        ...
+    {% elif otherthing %}
+        ...
+    {% elif foothing %}
+        ...
+    {% else %}
+        ...
+    {% endif %}
+
+Filter Arguments
+~~~~~~~~~~~~~~~~
+
+Jinja2 provides more than one argument for filters.  Also the syntax for
+argument passing is different.  A template that looks like this in Django::
+
+    {{ items|join:", " }}
+
+looks like this in Jinja2::
+
+    {{ items|join(', ') }}
+
+In fact it's a bit more verbose but it allows different types of arguments -
+including variables - and more than one of them.
+
+Tests
+~~~~~
+
+In addition to filters there also are tests you can perform using the is
+operator.  Here are some examples::
+
+    {% if user.user_id is odd %}
+        {{ user.username|e }} is odd
+    {% else %}
+        hmm. {{ user.username|e }} looks pretty normal
+    {% endif %}
+
+Loops
+~~~~~
+
+For loops work very similar to Django, the only incompatibility is that in
+Jinja2 the special variable for the loop context is called `loop` and not
+`forloop` like in Django.
+
+Cycle
+~~~~~
+
+The ``{% cycle %}`` tag does not exist in Jinja because of it's implicit
+nature.  However you can achieve mostly the same by using the `cycle`
+method on a loop object.
+
+The following Django template::
+
+    {% for user in users %}
+        <li class="{% cycle 'odd' 'even' %}">{{ user }}</li>
+    {% endfor %}
+
+Would look like this in Jinja::
+
+    {% for user in users %}
+        <li class="{{ loop.cycle('odd', 'even') }}">{{ user }}</li>
+    {% endfor %}
+
+There is no equivalent of ``{% cycle ... as variable %}``.
+
+
+Mako
+----
+
+.. highlight:: html+mako
+
+If you have used Mako so far and want to switch to Jinja2 you can configure
+Jinja2 to look more like Mako:
+
+.. sourcecode:: python
+
+    env = Environment('<%', '%>', '${', '}', '%')
+
+Once the environment is configure like that Jinja2 should be able to interpret
+a small subset of Mako templates.  Jinja2 does not support embedded Python code
+so you would have to move that out of the template.  The syntax for defs (in
+Jinja2 defs are called macros) and template inheritance is different too.  The
+following Mako template::
+
+    <%inherit file="layout.html" />
+    <%def name="title()">Page Title</%def>
+    <ul>
+    % for item in list:
+        <li>${item}</li>
+    % endfor
+    </ul>
+
+Looks like this in Jinja2 with the above configuration::
+
+    <% extends "layout.html" %>
+    <% block title %>Page Title<% endblock %>
+    <% block body %>
+    <ul>
+    % for item in list:
+        <li>${item}</li>
+    % endfor
+    </ul>
+    <% endblock %>
diff --git a/lib/jinja2/docs/templates.rst b/lib/jinja2/docs/templates.rst
new file mode 100644
index 0000000..ab1b9c1
--- /dev/null
+++ b/lib/jinja2/docs/templates.rst
@@ -0,0 +1,1366 @@
+Template Designer Documentation
+===============================
+
+.. highlight:: html+jinja
+
+This document describes the syntax and semantics of the template engine and
+will be most useful as reference to those creating Jinja templates.  As the
+template engine is very flexible the configuration from the application might
+be slightly different from here in terms of delimiters and behavior of
+undefined values.
+
+
+Synopsis
+--------
+
+A template is simply a text file.  It can generate any text-based format
+(HTML, XML, CSV, LaTeX, etc.).  It doesn't have a specific extension,
+``.html`` or ``.xml`` are just fine.
+
+A template contains **variables** or **expressions**, which get replaced with
+values when the template is evaluated, and tags, which control the logic of
+the template.  The template syntax is heavily inspired by Django and Python.
+
+Below is a minimal template that illustrates a few basics.  We will cover
+the details later in that document::
+
+    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+    <html lang="en">
+    <head>
+        <title>My Webpage</title>
+    </head>
+    <body>
+        <ul id="navigation">
+        {% for item in navigation %}
+            <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
+        {% endfor %}
+        </ul>
+
+        <h1>My Webpage</h1>
+        {{ a_variable }}
+    </body>
+    </html>
+
+This covers the default settings.  The application developer might have
+changed the syntax from ``{% foo %}`` to ``<% foo %>`` or something similar.
+
+There are two kinds of delimiters. ``{% ... %}`` and ``{{ ... }}``.  The first
+one is used to execute statements such as for-loops or assign values, the
+latter prints the result of the expression to the template.
+
+.. _variables:
+
+Variables
+---------
+
+The application passes variables to the templates you can mess around in the
+template.  Variables may have attributes or elements on them you can access
+too.  How a variable looks like, heavily depends on the application providing
+those.
+
+You can use a dot (``.``) to access attributes of a variable, alternative the
+so-called "subscript" syntax (``[]``) can be used.  The following lines do
+the same::
+
+    {{ foo.bar }}
+    {{ foo['bar'] }}
+
+It's important to know that the curly braces are *not* part of the variable
+but the print statement.  If you access variables inside tags don't put the
+braces around.
+
+If a variable or attribute does not exist you will get back an undefined
+value.  What you can do with that kind of value depends on the application
+configuration, the default behavior is that it evaluates to an empty string
+if printed and that you can iterate over it, but every other operation fails.
+
+.. _notes-on-subscriptions:
+
+.. admonition:: Implementation
+
+    For convenience sake ``foo.bar`` in Jinja2 does the following things on
+    the Python layer:
+
+    -   check if there is an attribute called `bar` on `foo`.
+    -   if there is not, check if there is an item ``'bar'`` in `foo`.
+    -   if there is not, return an undefined object.
+
+    ``foo['bar']`` on the other hand works mostly the same with the a small
+    difference in the order:
+
+    -   check if there is an item ``'bar'`` in `foo`.
+    -   if there is not, check if there is an attribute called `bar` on `foo`.
+    -   if there is not, return an undefined object.
+
+    This is important if an object has an item or attribute with the same
+    name.  Additionally there is the :func:`attr` filter that just looks up
+    attributes.
+
+.. _filters:
+
+Filters
+-------
+
+Variables can be modified by **filters**.  Filters are separated from the
+variable by a pipe symbol (``|``) and may have optional arguments in
+parentheses.  Multiple filters can be chained.  The output of one filter is
+applied to the next.
+
+``{{ name|striptags|title }}`` for example will remove all HTML Tags from the
+`name` and title-cases it.  Filters that accept arguments have parentheses
+around the arguments, like a function call.  This example will join a list
+by commas:  ``{{ list|join(', ') }}``.
+
+The :ref:`builtin-filters` below describes all the builtin filters.
+
+.. _tests:
+
+Tests
+-----
+
+Beside filters there are also so called "tests" available.  Tests can be used
+to test a variable against a common expression.  To test a variable or
+expression you add `is` plus the name of the test after the variable.  For
+example to find out if a variable is defined you can do ``name is defined``
+which will then return true or false depending on if `name` is defined.
+
+Tests can accept arguments too.  If the test only takes one argument you can
+leave out the parentheses to group them.  For example the following two
+expressions do the same::
+
+    {% if loop.index is divisibleby 3 %}
+    {% if loop.index is divisibleby(3) %}
+
+The :ref:`builtin-tests` below describes all the builtin tests.
+
+
+Comments
+--------
+
+To comment-out part of a line in a template, use the comment syntax which is
+by default set to ``{# ... #}``.  This is useful to comment out parts of the
+template for debugging or to add information for other template designers or
+yourself::
+
+    {# note: disabled template because we no longer use this
+        {% for user in users %}
+            ...
+        {% endfor %}
+    #}
+
+
+Whitespace Control
+------------------
+
+In the default configuration whitespace is not further modified by the
+template engine, so each whitespace (spaces, tabs, newlines etc.) is returned
+unchanged.  If the application configures Jinja to `trim_blocks` the first
+newline after a a template tag is removed automatically (like in PHP).
+
+But you can also strip whitespace in templates by hand.  If you put an minus
+sign (``-``) to the start or end of an block (for example a for tag), a
+comment or variable expression you can remove the whitespaces after or before
+that block::
+
+    {% for item in seq -%}
+        {{ item }}
+    {%- endfor %}
+
+This will yield all elements without whitespace between them.  If `seq` was
+a list of numbers from ``1`` to ``9`` the output would be ``123456789``.
+
+If :ref:`line-statements` are enabled they strip leading whitespace
+automatically up to the beginning of the line.
+
+.. admonition:: Note
+
+    You must not use a whitespace between the tag and the minus sign.
+
+    **valid**::
+
+        {%- if foo -%}...{% endif %}
+
+    **invalid**::
+
+        {% - if foo - %}...{% endif %}
+
+
+Escaping
+--------
+
+It is sometimes desirable or even necessary to have Jinja ignore parts it
+would otherwise handle as variables or blocks.  For example if the default
+syntax is used and you want to use ``{{`` as raw string in the template and
+not start a variable you have to use a trick.
+
+The easiest way is to output the variable delimiter (``{{``) by using a
+variable expression::
+
+    {{ '{{' }}
+
+For bigger sections it makes sense to mark a block `raw`.  For example to
+put Jinja syntax as example into a template you can use this snippet::
+
+    {% raw %}
+        <ul>
+        {% for item in seq %}
+            <li>{{ item }}</li>
+        {% endfor %}
+        </ul>
+    {% endraw %}
+
+
+.. _line-statements:
+
+Line Statements
+---------------
+
+If line statements are enabled by the application it's possible to mark a
+line as a statement.  For example if the line statement prefix is configured
+to ``#`` the following two examples are equivalent::
+
+    <ul>
+    # for item in seq
+        <li>{{ item }}</li>
+    # endfor
+    </ul>
+
+    <ul>
+    {% for item in seq %}
+        <li>{{ item }}</li>
+    {% endfor %}
+    </ul>
+
+The line statement prefix can appear anywhere on the line as long as no text
+precedes it.  For better readability statements that start a block (such as
+`for`, `if`, `elif` etc.) may end with a colon::
+
+    # for item in seq:
+        ...
+    # endfor
+
+
+.. admonition:: Note
+
+    Line statements can span multiple lines if there are open parentheses,
+    braces or brackets::
+
+        <ul>
+        # for href, caption in [('index.html', 'Index'),
+                                ('about.html', 'About')]:
+            <li><a href="{{ href }}">{{ caption }}</a></li>
+        # endfor
+        </ul>
+
+Since Jinja 2.2 line-based comments are available as well.  For example if
+the line-comment prefix is configured to be ``##`` everything from ``##`` to
+the end of the line is ignored (excluding the newline sign)::
+
+    # for item in seq:
+        <li>{{ item }}</li>     ## this comment is ignored
+    # endfor
+
+
+.. _template-inheritance:
+
+Template Inheritance
+--------------------
+
+The most powerful part of Jinja is template inheritance. Template inheritance
+allows you to build a base "skeleton" template that contains all the common
+elements of your site and defines **blocks** that child templates can override.
+
+Sounds complicated but is very basic. It's easiest to understand it by starting
+with an example.
+
+
+Base Template
+~~~~~~~~~~~~~
+
+This template, which we'll call ``base.html``, defines a simple HTML skeleton
+document that you might use for a simple two-column page. It's the job of
+"child" templates to fill the empty blocks with content::
+
+    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+    <html lang="en">
+    <html xmlns="http://www.w3.org/1999/xhtml">
+    <head>
+        {% block head %}
+        <link rel="stylesheet" href="style.css" />
+        <title>{% block title %}{% endblock %} - My Webpage</title>
+        {% endblock %}
+    </head>
+    <body>
+        <div id="content">{% block content %}{% endblock %}</div>
+        <div id="footer">
+            {% block footer %}
+            &copy; Copyright 2008 by <a href="http://domain.invalid/">you</a>.
+            {% endblock %}
+        </div>
+    </body>
+
+In this example, the ``{% block %}`` tags define four blocks that child templates
+can fill in. All the `block` tag does is to tell the template engine that a
+child template may override those portions of the template.
+
+Child Template
+~~~~~~~~~~~~~~
+
+A child template might look like this::
+
+    {% extends "base.html" %}
+    {% block title %}Index{% endblock %}
+    {% block head %}
+        {{ super() }}
+        <style type="text/css">
+            .important { color: #336699; }
+        </style>
+    {% endblock %}
+    {% block content %}
+        <h1>Index</h1>
+        <p class="important">
+          Welcome on my awesome homepage.
+        </p>
+    {% endblock %}
+
+The ``{% extends %}`` tag is the key here. It tells the template engine that
+this template "extends" another template.  When the template system evaluates
+this template, first it locates the parent.  The extends tag should be the
+first tag in the template.  Everything before it is printed out normally and
+may cause confusion.  For details about this behavior and how to take
+advantage of it, see :ref:`null-master-fallback`.
+
+The filename of the template depends on the template loader.  For example the
+:class:`FileSystemLoader` allows you to access other templates by giving the
+filename.  You can access templates in subdirectories with an slash::
+
+    {% extends "layout/default.html" %}
+
+But this behavior can depend on the application embedding Jinja.  Note that
+since the child template doesn't define the ``footer`` block, the value from
+the parent template is used instead.
+
+You can't define multiple ``{% block %}`` tags with the same name in the
+same template.  This limitation exists because a block tag works in "both"
+directions.  That is, a block tag doesn't just provide a hole to fill - it
+also defines the content that fills the hole in the *parent*.  If there
+were two similarly-named ``{% block %}`` tags in a template, that template's
+parent wouldn't know which one of the blocks' content to use.
+
+If you want to print a block multiple times you can however use the special
+`self` variable and call the block with that name::
+
+    <title>{% block title %}{% endblock %}</title>
+    <h1>{{ self.title() }}</h1>
+    {% block body %}{% endblock %}
+
+
+Super Blocks
+~~~~~~~~~~~~
+
+It's possible to render the contents of the parent block by calling `super`.
+This gives back the results of the parent block::
+
+    {% block sidebar %}
+        <h3>Table Of Contents</h3>
+        ...
+        {{ super() }}
+    {% endblock %}
+
+
+Named Block End-Tags
+~~~~~~~~~~~~~~~~~~~~
+
+Jinja2 allows you to put the name of the block after the end tag for better
+readability::
+
+    {% block sidebar %}
+        {% block inner_sidebar %}
+            ...
+        {% endblock inner_sidebar %}
+    {% endblock sidebar %}
+
+However the name after the `endblock` word must match the block name.
+
+
+Block Nesting and Scope
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Blocks can be nested for more complex layouts.  However per default blocks
+may not access variables from outer scopes::
+
+    {% for item in seq %}
+        <li>{% block loop_item %}{{ item }}{% endblock %}</li>
+    {% endfor %}
+
+This example would output empty ``<li>`` items because `item` is unavailable
+inside the block.  The reason for this is that if the block is replaced by
+a child template a variable would appear that was not defined in the block or
+passed to the context.
+
+Starting with Jinja 2.2 you can explicitly specify that variables are
+available in a block by setting the block to "scoped" by adding the `scoped`
+modifier to a block declaration::
+
+    {% for item in seq %}
+        <li>{% block loop_item scoped %}{{ item }}{% endblock %}</li>
+    {% endfor %}
+
+When overriding a block the `scoped` modifier does not have to be provided.
+
+
+Template Objects
+~~~~~~~~~~~~~~~~
+
+.. versionchanged:: 2.4
+
+If a template object was passed to the template context you can
+extend from that object as well.  Assuming the calling code passes
+a layout template as `layout_template` to the environment, this
+code works::
+
+    {% extends layout_template %}
+
+Previously the `layout_template` variable had to be a string with
+the layout template's filename for this to work.
+
+
+HTML Escaping
+-------------
+
+When generating HTML from templates, there's always a risk that a variable will
+include characters that affect the resulting HTML.  There are two approaches:
+manually escaping each variable or automatically escaping everything by default.
+
+Jinja supports both, but what is used depends on the application configuration.
+The default configuaration is no automatic escaping for various reasons:
+
+-   escaping everything except of safe values will also mean that Jinja is
+    escaping variables known to not include HTML such as numbers which is
+    a huge performance hit.
+
+-   The information about the safety of a variable is very fragile.  It could
+    happen that by coercing safe and unsafe values the return value is double
+    escaped HTML.
+
+Working with Manual Escaping
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If manual escaping is enabled it's **your** responsibility to escape
+variables if needed.  What to escape?  If you have a variable that *may*
+include any of the following chars (``>``, ``<``, ``&``, or ``"``) you
+**have to** escape it unless the variable contains well-formed and trusted
+HTML.  Escaping works by piping the variable through the ``|e`` filter:
+``{{ user.username|e }}``.
+
+Working with Automatic Escaping
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When automatic escaping is enabled everything is escaped by default except
+for values explicitly marked as safe.  Those can either be marked by the
+application or in the template by using the `|safe` filter.  The main
+problem with this approach is that Python itself doesn't have the concept
+of tainted values so the information if a value is safe or unsafe can get
+lost.  If the information is lost escaping will take place which means that
+you could end up with double escaped contents.
+
+Double escaping is easy to avoid however, just rely on the tools Jinja2
+provides and don't use builtin Python constructs such as the string modulo
+operator.
+
+Functions returning template data (macros, `super`, `self.BLOCKNAME`) return
+safe markup always.
+
+String literals in templates with automatic escaping are considered unsafe
+too.  The reason for this is that the safe string is an extension to Python
+and not every library will work properly with it.
+
+
+List of Control Structures
+--------------------------
+
+A control structure refers to all those things that control the flow of a
+program - conditionals (i.e. if/elif/else), for-loops, as well as things like
+macros and blocks.  Control structures appear inside ``{% ... %}`` blocks
+in the default syntax.
+
+For
+~~~
+
+Loop over each item in a sequence.  For example, to display a list of users
+provided in a variable called `users`::
+
+    <h1>Members</h1>
+    <ul>
+    {% for user in users %}
+      <li>{{ user.username|e }}</li>
+    {% endfor %}
+    </ul>
+
+Inside of a for loop block you can access some special variables:
+
++-----------------------+---------------------------------------------------+
+| Variable              | Description                                       |
++=======================+===================================================+
+| `loop.index`          | The current iteration of the loop. (1 indexed)    |
++-----------------------+---------------------------------------------------+
+| `loop.index0`         | The current iteration of the loop. (0 indexed)    |
++-----------------------+---------------------------------------------------+
+| `loop.revindex`       | The number of iterations from the end of the loop |
+|                       | (1 indexed)                                       |
++-----------------------+---------------------------------------------------+
+| `loop.revindex0`      | The number of iterations from the end of the loop |
+|                       | (0 indexed)                                       |
++-----------------------+---------------------------------------------------+
+| `loop.first`          | True if first iteration.                          |
++-----------------------+---------------------------------------------------+
+| `loop.last`           | True if last iteration.                           |
++-----------------------+---------------------------------------------------+
+| `loop.length`         | The number of items in the sequence.              |
++-----------------------+---------------------------------------------------+
+| `loop.cycle`          | A helper function to cycle between a list of      |
+|                       | sequences.  See the explanation below.            |
++-----------------------+---------------------------------------------------+
+
+Within a for-loop, it's possible to cycle among a list of strings/variables
+each time through the loop by using the special `loop.cycle` helper::
+
+    {% for row in rows %}
+        <li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li>
+    {% endfor %}
+
+With Jinja 2.1 an extra `cycle` helper exists that allows loop-unbound
+cycling.  For more information have a look at the :ref:`builtin-globals`.
+
+.. _loop-filtering:
+
+Unlike in Python it's not possible to `break` or `continue` in a loop.  You
+can however filter the sequence during iteration which allows you to skip
+items.  The following example skips all the users which are hidden::
+
+    {% for user in users if not user.hidden %}
+        <li>{{ user.username|e }}</li>
+    {% endfor %}
+
+The advantage is that the special `loop` variable will count correctly thus
+not counting the users not iterated over.
+
+If no iteration took place because the sequence was empty or the filtering
+removed all the items from the sequence you can render a replacement block
+by using `else`::
+
+    <ul>
+    {% for user in users %}
+        <li>{{ user.username|e }}</li>
+    {% else %}
+        <li><em>no users found</em></li>
+    {% endfor %}
+    </ul>
+
+It is also possible to use loops recursively.  This is useful if you are
+dealing with recursive data such as sitemaps.  To use loops recursively you
+basically have to add the `recursive` modifier to the loop definition and
+call the `loop` variable with the new iterable where you want to recurse.
+
+The following example implements a sitemap with recursive loops::
+
+    <ul class="sitemap">
+    {%- for item in sitemap recursive %}
+        <li><a href="{{ item.href|e }}">{{ item.title }}</a>
+        {%- if item.children -%}
+            <ul class="submenu">{{ loop(item.children) }}</ul>
+        {%- endif %}</li>
+    {%- endfor %}
+    </ul>
+
+
+If
+~~
+
+The `if` statement in Jinja is comparable with the if statements of Python.
+In the simplest form you can use it to test if a variable is defined, not
+empty or not false::
+
+    {% if users %}
+    <ul>
+    {% for user in users %}
+        <li>{{ user.username|e }}</li>
+    {% endfor %}
+    </ul>
+    {% endif %}
+
+For multiple branches `elif` and `else` can be used like in Python.  You can
+use more complex :ref:`expressions` there too::
+
+    {% if kenny.sick %}
+        Kenny is sick.
+    {% elif kenny.dead %}
+        You killed Kenny!  You bastard!!!
+    {% else %}
+        Kenny looks okay --- so far
+    {% endif %}
+
+If can also be used as :ref:`inline expression <if-expression>` and for
+:ref:`loop filtering <loop-filtering>`.
+
+
+Macros
+~~~~~~
+
+Macros are comparable with functions in regular programming languages.  They
+are useful to put often used idioms into reusable functions to not repeat
+yourself.
+
+Here a small example of a macro that renders a form element::
+
+    {% macro input(name, value='', type='text', size=20) -%}
+        <input type="{{ type }}" name="{{ name }}" value="{{
+            value|e }}" size="{{ size }}">
+    {%- endmacro %}
+
+The macro can then be called like a function in the namespace::
+
+    <p>{{ input('username') }}</p>
+    <p>{{ input('password', type='password') }}</p>
+
+If the macro was defined in a different template you have to
+:ref:`import <import>` it first.
+
+Inside macros you have access to three special variables:
+
+`varargs`
+    If more positional arguments are passed to the macro than accepted by the
+    macro they end up in the special `varargs` variable as list of values.
+
+`kwargs`
+    Like `varargs` but for keyword arguments.  All unconsumed keyword
+    arguments are stored in this special variable.
+
+`caller`
+    If the macro was called from a :ref:`call<call>` tag the caller is stored
+    in this variable as macro which can be called.
+
+Macros also expose some of their internal details.  The following attributes
+are available on a macro object:
+
+`name`
+    The name of the macro.  ``{{ input.name }}`` will print ``input``.
+
+`arguments`
+    A tuple of the names of arguments the macro accepts.
+
+`defaults`
+    A tuple of default values.
+
+`catch_kwargs`
+    This is `true` if the macro accepts extra keyword arguments (ie: accesses
+    the special `kwargs` variable).
+
+`catch_varargs`
+    This is `true` if the macro accepts extra positional arguments (ie:
+    accesses the special `varargs` variable).
+
+`caller`
+    This is `true` if the macro accesses the special `caller` variable and may
+    be called from a :ref:`call<call>` tag.
+
+If a macro name starts with an underscore it's not exported and can't
+be imported.
+
+
+.. _call:
+
+Call
+~~~~
+
+In some cases it can be useful to pass a macro to another macro.  For this
+purpose you can use the special `call` block.  The following example shows
+a macro that takes advantage of the call functionality and how it can be
+used::
+
+    {% macro render_dialog(title, class='dialog') -%}
+        <div class="{{ class }}">
+            <h2>{{ title }}</h2>
+            <div class="contents">
+                {{ caller() }}
+            </div>
+        </div>
+    {%- endmacro %}
+
+    {% call render_dialog('Hello World') %}
+        This is a simple dialog rendered by using a macro and
+        a call block.
+    {% endcall %}
+
+It's also possible to pass arguments back to the call block.  This makes it
+useful as replacement for loops.  Generally speaking a call block works
+exactly like an macro, just that it doesn't have a name.
+
+Here an example of how a call block can be used with arguments::
+
+    {% macro dump_users(users) -%}
+        <ul>
+        {%- for user in users %}
+            <li><p>{{ user.username|e }}</p>{{ caller(user) }}</li>
+        {%- endfor %}
+        </ul>
+    {%- endmacro %}
+
+    {% call(user) dump_users(list_of_user) %}
+        <dl>
+            <dl>Realname</dl>
+            <dd>{{ user.realname|e }}</dd>
+            <dl>Description</dl>
+            <dd>{{ user.description }}</dd>
+        </dl>
+    {% endcall %}
+
+
+Filters
+~~~~~~~
+
+Filter sections allow you to apply regular Jinja2 filters on a block of
+template data.  Just wrap the code in the special `filter` section::
+
+    {% filter upper %}
+        This text becomes uppercase
+    {% endfilter %}
+
+
+Assignments
+~~~~~~~~~~~
+
+Inside code blocks you can also assign values to variables.  Assignments at
+top level (outside of blocks, macros or loops) are exported from the template
+like top level macros and can be imported by other templates.
+
+Assignments use the `set` tag and can have multiple targets::
+
+    {% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
+    {% set key, value = call_something() %}
+
+
+Extends
+~~~~~~~
+
+The `extends` tag can be used to extend a template from another one.  You
+can have multiple of them in a file but only one of them may be executed
+at the time.  See the section about :ref:`template-inheritance` above.
+
+
+Block
+~~~~~
+
+Blocks are used for inheritance and act as placeholders and replacements
+at the same time.  They are documented in detail as part of the section
+about :ref:`template-inheritance`.
+
+
+Include
+~~~~~~~
+
+The `include` statement is useful to include a template and return the
+rendered contents of that file into the current namespace::
+
+    {% include 'header.html' %}
+        Body
+    {% include 'footer.html' %}
+
+Included templates have access to the variables of the active context by
+default.  For more details about context behavior of imports and includes
+see :ref:`import-visibility`.
+
+From Jinja 2.2 onwards you can mark an include with ``ignore missing`` in
+which case Jinja will ignore the statement if the template to be ignored
+does not exist.  When combined with ``with`` or ``without context`` it has
+to be placed *before* the context visibility statement.  Here some valid
+examples::
+
+    {% include "sidebar.html" ignore missing %}
+    {% include "sidebar.html" ignore missing with context %}
+    {% include "sidebar.html" ignore missing without context %}
+
+.. versionadded:: 2.2
+
+You can also provide a list of templates that are checked for existence
+before inclusion.  The first template that exists will be included.  If
+`ignore missing` is given, it will fall back to rendering nothing if
+none of the templates exist, otherwise it will raise an exception.
+
+Example::
+
+    {% include ['page_detailed.html', 'page.html'] %}
+    {% include ['special_sidebar.html', 'sidebar.html'] ignore missing %}
+
+.. versionchanged:: 2.4
+   If a template object was passed to the template context you can
+   include that object using `include`.
+
+.. _import:
+
+Import
+~~~~~~
+
+Jinja2 supports putting often used code into macros.  These macros can go into
+different templates and get imported from there.  This works similar to the
+import statements in Python.  It's important to know that imports are cached
+and imported templates don't have access to the current template variables,
+just the globals by defualt.  For more details about context behavior of
+imports and includes see :ref:`import-visibility`.
+
+There are two ways to import templates.  You can import the complete template
+into a variable or request specific macros / exported variables from it.
+
+Imagine we have a helper module that renders forms (called `forms.html`)::
+
+    {% macro input(name, value='', type='text') -%}
+        <input type="{{ type }}" value="{{ value|e }}" name="{{ name }}">
+    {%- endmacro %}
+
+    {%- macro textarea(name, value='', rows=10, cols=40) -%}
+        <textarea name="{{ name }}" rows="{{ rows }}" cols="{{ cols
+            }}">{{ value|e }}</textarea>
+    {%- endmacro %}
+
+The easiest and most flexible is importing the whole module into a variable.
+That way you can access the attributes::
+
+    {% import 'forms.html' as forms %}
+    <dl>
+        <dt>Username</dt>
+        <dd>{{ forms.input('username') }}</dd>
+        <dt>Password</dt>
+        <dd>{{ forms.input('password', type='password') }}</dd>
+    </dl>
+    <p>{{ forms.textarea('comment') }}</p>
+
+
+Alternatively you can import names from the template into the current
+namespace::
+
+    {% from 'forms.html' import input as input_field, textarea %}
+    <dl>
+        <dt>Username</dt>
+        <dd>{{ input_field('username') }}</dd>
+        <dt>Password</dt>
+        <dd>{{ input_field('password', type='password') }}</dd>
+    </dl>
+    <p>{{ textarea('comment') }}</p>
+
+Macros and variables starting with one ore more underscores are private and
+cannot be imported.
+
+.. versionchanged:: 2.4
+   If a template object was passed to the template context you can
+   import from that object.
+
+
+.. _import-visibility:
+
+Import Context Behavior
+-----------------------
+
+Per default included templates are passed the current context and imported
+templates not.  The reason for this is that imports unlike includes are
+cached as imports are often used just as a module that holds macros.
+
+This however can be changed of course explicitly.  By adding `with context`
+or `without context` to the import/include directive the current context
+can be passed to the template and caching is disabled automatically.
+
+Here two examples::
+
+    {% from 'forms.html' import input with context %}
+    {% include 'header.html' without context %}
+
+.. admonition:: Note
+
+    In Jinja 2.0 the context that was passed to the included template
+    did not include variables defined in the template.  As a matter of
+    fact this did not work::
+
+        {% for box in boxes %}
+            {% include "render_box.html" %}
+        {% endfor %}
+
+    The included template ``render_box.html`` is *not* able to access
+    `box` in Jinja 2.0. As of Jinja 2.1 ``render_box.html`` *is* able
+    to do so.
+
+
+.. _expressions:
+
+Expressions
+-----------
+
+Jinja allows basic expressions everywhere.  These work very similar to regular
+Python and even if you're not working with Python you should feel comfortable
+with it.
+
+Literals
+~~~~~~~~
+
+The simplest form of expressions are literals.  Literals are representations
+for Python objects such as strings and numbers.  The following literals exist:
+
+"Hello World":
+    Everything between two double or single quotes is a string.  They are
+    useful whenever you need a string in the template (for example as
+    arguments to function calls, filters or just to extend or include a
+    template).
+
+42 / 42.23:
+    Integers and floating point numbers are created by just writing the
+    number down.  If a dot is present the number is a float, otherwise an
+    integer.  Keep in mind that for Python ``42`` and ``42.0`` is something
+    different.
+
+['list', 'of', 'objects']:
+    Everything between two brackets is a list.  Lists are useful to store
+    sequential data in or to iterate over them.  For example you can easily
+    create a list of links using lists and tuples with a for loop::
+
+        <ul>
+        {% for href, caption in [('index.html', 'Index'), ('about.html', 'About'),
+                                 ('downloads.html', 'Downloads')] %}
+            <li><a href="{{ href }}">{{ caption }}</a></li>
+        {% endfor %}
+        </ul>
+
+('tuple', 'of', 'values'):
+    Tuples are like lists, just that you can't modify them.  If the tuple
+    only has one item you have to end it with a comma.  Tuples are usually
+    used to represent items of two or more elements.  See the example above
+    for more details.
+
+{'dict': 'of', 'key': 'and', 'value': 'pairs'}:
+    A dict in Python is a structure that combines keys and values.  Keys must
+    be unique and always have exactly one value.  Dicts are rarely used in
+    templates, they are useful in some rare cases such as the :func:`xmlattr`
+    filter.
+
+true / false:
+    true is always true and false is always false.
+
+.. admonition:: Note
+
+    The special constants `true`, `false` and `none` are indeed lowercase.
+    Because that caused confusion in the past, when writing `True` expands
+    to an undefined variable that is considered false, all three of them can
+    be written in title case too (`True`, `False`, and `None`).  However for
+    consistency (all Jinja identifiers are lowercase) you should use the
+    lowercase versions.
+
+Math
+~~~~
+
+Jinja allows you to calculate with values.  This is rarely useful in templates
+but exists for completeness' sake.  The following operators are supported:
+
+\+
+    Adds two objects together.  Usually the objects are numbers but if both are
+    strings or lists you can concatenate them this way.  This however is not
+    the preferred way to concatenate strings!  For string concatenation have
+    a look at the ``~`` operator.  ``{{ 1 + 1 }}`` is ``2``.
+
+\-
+    Substract the second number from the first one.  ``{{ 3 - 2 }}`` is ``1``.
+
+/
+    Divide two numbers.  The return value will be a floating point number.
+    ``{{ 1 / 2 }}`` is ``{{ 0.5 }}``.
+
+//
+    Divide two numbers and return the truncated integer result.
+    ``{{ 20 // 7 }}`` is ``2``.
+
+%
+    Calculate the remainder of an integer division.  ``{{ 11 % 7 }}`` is ``4``.
+
+\*
+    Multiply the left operand with the right one.  ``{{ 2 * 2 }}`` would
+    return ``4``.  This can also be used to repeat a string multiple times.
+    ``{{ '=' * 80 }}`` would print a bar of 80 equal signs.
+
+\**
+    Raise the left operand to the power of the right operand.  ``{{ 2**3 }}``
+    would return ``8``.
+
+Comparisons
+~~~~~~~~~~~
+
+==
+    Compares two objects for equality.
+
+!=
+    Compares two objects for inequality.
+
+>
+    `true` if the left hand side is greater than the right hand side.
+
+>=
+    `true` if the left hand side is greater or equal to the right hand side.
+
+<
+    `true` if the left hand side is lower than the right hand side.
+
+<=
+    `true` if the left hand side is lower or equal to the right hand side.
+
+Logic
+~~~~~
+
+For `if` statements, `for` filtering or `if` expressions it can be useful to
+combine multiple expressions:
+
+and
+    Return true if the left and the right operand is true.
+
+or
+    Return true if the left or the right operand is true.
+
+not
+    negate a statement (see below).
+
+(expr)
+    group an expression.
+
+.. admonition:: Note
+
+    The ``is`` and ``in`` operators support negation using an infix notation
+    too: ``foo is not bar`` and ``foo not in bar`` instead of ``not foo is bar``
+    and ``not foo in bar``.  All other expressions require a prefix notation:
+    ``not (foo and bar).``
+
+
+Other Operators
+~~~~~~~~~~~~~~~
+
+The following operators are very useful but don't fit into any of the other
+two categories:
+
+in
+    Perform sequence / mapping containment test.  Returns true if the left
+    operand is contained in the right.  ``{{ 1 in [1, 2, 3] }}`` would for
+    example return true.
+
+is
+    Performs a :ref:`test <tests>`.
+
+\|
+    Applies a :ref:`filter <filters>`.
+
+~
+    Converts all operands into strings and concatenates them.
+    ``{{ "Hello " ~ name ~ "!" }}`` would return (assuming `name` is
+    ``'John'``) ``Hello John!``.
+
+()
+    Call a callable: ``{{ post.render() }}``.  Inside of the parentheses you
+    can use positional arguments and keyword arguments like in python:
+    ``{{ post.render(user, full=true) }}``.
+
+. / []
+    Get an attribute of an object.  (See :ref:`variables`)
+
+
+.. _if-expression:
+
+If Expression
+~~~~~~~~~~~~~
+
+It is also possible to use inline `if` expressions.  These are useful in some
+situations.  For example you can use this to extend from one template if a
+variable is defined, otherwise from the default layout template::
+
+    {% extends layout_template if layout_template is defined else 'master.html' %}
+
+The general syntax is ``<do something> if <something is true> else <do
+something else>``.
+
+The `else` part is optional.  If not provided the else block implicitly
+evaluates into an undefined object::
+
+    {{ '[%s]' % page.title if page.title }}
+
+
+.. _builtin-filters:
+
+List of Builtin Filters
+-----------------------
+
+.. jinjafilters::
+
+
+.. _builtin-tests:
+
+List of Builtin Tests
+---------------------
+
+.. jinjatests::
+
+.. _builtin-globals:
+
+List of Global Functions
+------------------------
+
+The following functions are available in the global scope by default:
+
+.. function:: range([start,] stop[, step])
+
+    Return a list containing an arithmetic progression of integers.
+    range(i, j) returns [i, i+1, i+2, ..., j-1]; start (!) defaults to 0.
+    When step is given, it specifies the increment (or decrement).
+    For example, range(4) returns [0, 1, 2, 3].  The end point is omitted!
+    These are exactly the valid indices for a list of 4 elements.
+
+    This is useful to repeat a template block multiple times for example
+    to fill a list.  Imagine you have 7 users in the list but you want to
+    render three empty items to enforce a height with CSS::
+
+        <ul>
+        {% for user in users %}
+            <li>{{ user.username }}</li>
+        {% endfor %}
+        {% for number in range(10 - users|count) %}
+            <li class="empty"><span>...</span></li>
+        {% endfor %}
+        </ul>
+
+.. function:: lipsum(n=5, html=True, min=20, max=100)
+
+    Generates some lorem ipsum for the template.  Per default five paragraphs
+    with HTML are generated each paragraph between 20 and 100 words.  If html
+    is disabled regular text is returned.  This is useful to generate simple
+    contents for layout testing.
+
+.. function:: dict(\**items)
+
+    A convenient alternative to dict literals.  ``{'foo': 'bar'}`` is the same
+    as ``dict(foo='bar')``.
+
+.. class:: cycler(\*items)
+
+    The cycler allows you to cycle among values similar to how `loop.cycle`
+    works.  Unlike `loop.cycle` however you can use this cycler outside of
+    loops or over multiple loops.
+
+    This is for example very useful if you want to show a list of folders and
+    files, with the folders on top, but both in the same list with alternating
+    row colors.
+
+    The following example shows how `cycler` can be used::
+
+        {% set row_class = cycler('odd', 'even') %}
+        <ul class="browser">
+        {% for folder in folders %}
+          <li class="folder {{ row_class.next() }}">{{ folder|e }}</li>
+        {% endfor %}
+        {% for filename in files %}
+          <li class="file {{ row_class.next() }}">{{ filename|e }}</li>
+        {% endfor %}
+        </ul>
+
+    A cycler has the following attributes and methods:
+
+    .. method:: reset()
+
+        Resets the cycle to the first item.
+
+    .. method:: next()
+
+        Goes one item a head and returns the then current item.
+
+    .. attribute:: current
+
+        Returns the current item.
+
+    **new in Jinja 2.1**
+
+.. class:: joiner(sep=', ')
+
+    A tiny helper that can be use to "join" multiple sections.  A joiner is
+    passed a string and will return that string every time it's calld, except
+    the first time in which situation it returns an empty string.  You can
+    use this to join things::
+
+        {% set pipe = joiner("|") %}
+        {% if categories %} {{ pipe() }}
+            Categories: {{ categories|join(", ") }}
+        {% endif %}
+        {% if author %} {{ pipe() }}
+            Author: {{ author() }}
+        {% endif %}
+        {% if can_edit %} {{ pipe() }}
+            <a href="?action=edit">Edit</a>
+        {% endif %}
+
+    **new in Jinja 2.1**
+
+
+Extensions
+----------
+
+The following sections cover the built-in Jinja2 extensions that may be
+enabled by the application.  The application could also provide further
+extensions not covered by this documentation.  In that case there should
+be a separate document explaining the extensions.
+
+.. _i18n-in-templates:
+
+i18n
+~~~~
+
+If the i18n extension is enabled it's possible to mark parts in the template
+as translatable.  To mark a section as translatable you can use `trans`::
+
+    <p>{% trans %}Hello {{ user }}!{% endtrans %}</p>
+
+To translate a template expression --- say, using template filters or just
+accessing an attribute of an object --- you need to bind the expression to a
+name for use within the translation block::
+
+    <p>{% trans user=user.username %}Hello {{ user }}!{% endtrans %}</p>
+
+If you need to bind more than one expression inside a `trans` tag, separate
+the pieces with a comma (``,``)::
+
+    {% trans book_title=book.title, author=author.name %}
+    This is {{ book_title }} by {{ author }}
+    {% endtrans %}
+
+Inside trans tags no statements are allowed, only variable tags are.
+
+To pluralize, specify both the singular and plural forms with the `pluralize`
+tag, which appears between `trans` and `endtrans`::
+
+    {% trans count=list|length %}
+    There is {{ count }} {{ name }} object.
+    {% pluralize %}
+    There are {{ count }} {{ name }} objects.
+    {% endtrans %}
+
+Per default the first variable in a block is used to determine the correct
+singular or plural form.  If that doesn't work out you can specify the name
+which should be used for pluralizing by adding it as parameter to `pluralize`::
+
+    {% trans ..., user_count=users|length %}...
+    {% pluralize user_count %}...{% endtrans %}
+
+It's also possible to translate strings in expressions.  For that purpose
+three functions exist:
+
+_   `gettext`: translate a single string
+-   `ngettext`: translate a pluralizable string
+-   `_`: alias for `gettext`
+
+For example you can print a translated string easily this way::
+
+    {{ _('Hello World!') }}
+
+To use placeholders you can use the `format` filter::
+
+    {{ _('Hello %(user)s!')|format(user=user.username) }}
+
+For multiple placeholders always use keyword arguments to `format` as other
+languages may not use the words in the same order.
+
+.. versionchanged:: 2.5
+
+If newstyle gettext calls are activated (:ref:`newstyle-gettext`), using
+placeholders is a lot easier:
+
+.. sourcecode:: html+jinja
+
+    {{ gettext('Hello World!') }}
+    {{ gettext('Hello %(name)s!', name='World') }}
+    {{ ngettext('%(num)d apple', '%(num)d apples', apples|count) }}
+
+Note that the `ngettext` function's format string automatically recieves
+the count as `num` parameter additionally to the regular parameters.
+
+
+Expression Statement
+~~~~~~~~~~~~~~~~~~~~
+
+If the expression-statement extension is loaded a tag called `do` is available
+that works exactly like the regular variable expression (``{{ ... }}``) just
+that it doesn't print anything.  This can be used to modify lists::
+
+    {% do navigation.append('a string') %}
+
+
+Loop Controls
+~~~~~~~~~~~~~
+
+If the application enables the :ref:`loopcontrols-extension` it's possible to
+use `break` and `continue` in loops.  When `break` is reached, the loop is
+terminated, if `continue` is eached the processing is stopped and continues
+with the next iteration.
+
+Here a loop that skips every second item::
+
+    {% for user in users %}
+        {%- if loop.index is even %}{% continue %}{% endif %}
+        ...
+    {% endfor %}
+
+Likewise a look that stops processing after the 10th iteration::
+
+    {% for user in users %}
+        {%- if loop.index >= 10 %}{% break %}{% endif %}
+    {%- endfor %}
+
+
+With Statement
+~~~~~~~~~~~~~~
+
+.. versionadded:: 2.3
+
+If the application enables the :ref:`with-extension` it is possible to
+use the `with` keyword in templates.  This makes it possible to create
+a new inner scope.  Variables set within this scope are not visible
+outside of the scope.
+
+With in a nutshell::
+
+    {% with %}
+        {% set foo = 42 %}
+        {{ foo }}           foo is 42 here
+    {% endwith %}
+    foo is not visible here any longer
+
+Because it is common to set variables at the beginning of the scope
+you can do that within the with statement.  The following two examples
+are equivalent::
+
+    {% with foo = 42 %}
+        {{ foo }}
+    {% endwith %}
+
+    {% with %}
+        {% set foo = 42 %}
+        {{ foo }}
+    {% endwith %}
+
+.. _autoescape-overrides:
+
+Autoescape Extension
+--------------------
+
+.. versionadded:: 2.4
+
+If the application enables the :ref:`autoescape-extension` one can
+activate and deactivate the autoescaping from within the templates.
+
+Example::
+
+    {% autoescape true %}
+        Autoescaping is active within this block
+    {% endautoescape %}
+
+    {% autoescape false %}
+        Autoescaping is inactive within this block
+    {% endautoescape %}
+
+After the `endautoescape` the behavior is reverted to what it was before.
diff --git a/lib/jinja2/docs/tricks.rst b/lib/jinja2/docs/tricks.rst
new file mode 100644
index 0000000..566575e
--- /dev/null
+++ b/lib/jinja2/docs/tricks.rst
@@ -0,0 +1,100 @@
+Tips and Tricks
+===============
+
+.. highlight:: html+jinja
+
+This part of the documentation shows some tips and tricks for Jinja2
+templates.
+
+
+.. _null-master-fallback:
+
+Null-Master Fallback
+--------------------
+
+Jinja2 supports dynamic inheritance and does not distinguish between parent
+and child template as long as no `extends` tag is visited.  While this leads
+to the surprising behavior that everything before the first `extends` tag
+including whitespace is printed out instead of being igored, it can be used
+for a neat trick.
+
+Usually child templates extend from one template that adds a basic HTML
+skeleton.  However it's possible put the `extends` tag into an `if` tag to
+only extend from the layout template if the `standalone` variable evaluates
+to false which it does per default if it's not defined.  Additionally a very
+basic skeleton is added to the file so that if it's indeed rendered with
+`standalone` set to `True` a very basic HTML skeleton is added::
+
+    {% if not standalone %}{% extends 'master.html' %}{% endif -%}
+    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+    <title>{% block title %}The Page Title{% endblock %}</title>
+    <link rel="stylesheet" href="style.css" type="text/css">
+    {% block body %}
+      <p>This is the page body.</p>
+    {% endblock %}
+
+
+Alternating Rows
+----------------
+
+If you want to have different styles for each row of a table or
+list you can use the `cycle` method on the `loop` object::
+
+    <ul>
+    {% for row in rows %}
+      <li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li>
+    {% endfor %}
+    </ul>
+
+`cycle` can take an unlimited amount of strings.  Each time this
+tag is encountered the next item from the list is rendered.
+
+
+Highlighting Active Menu Items
+------------------------------
+
+Often you want to have a navigation bar with an active navigation
+item.  This is really simple to achieve.  Because assignments outside
+of `block`\s in child templates are global and executed before the layout
+template is evaluated it's possible to define the active menu item in the
+child template::
+
+    {% extends "layout.html" %}
+    {% set active_page = "index" %}
+
+The layout template can then access `active_page`.  Additionally it makes
+sense to defined a default for that variable::
+
+    {% set navigation_bar = [
+        ('/', 'index', 'Index'),
+        ('/downloads/', 'downloads', 'Downloads'),
+        ('/about/', 'about', 'About')
+    ] -%}
+    {% set active_page = active_page|default('index') -%}
+    ...
+    <ul id="navigation">
+    {% for href, id, caption in navigation_bar %}
+      <li{% if id == active_page %} class="active"{% endif
+      %}><a href="{{ href|e }}">{{ caption|e }}</a>/li>
+    {% endfor %}
+    </ul>
+    ...
+
+.. _accessing-the-parent-loop:
+
+Accessing the parent Loop
+-------------------------
+
+The special `loop` variable always points to the innermost loop.  If it's
+desired to have access to an outer loop it's possible to alias it::
+
+    <table>
+    {% for row in table %}
+      <tr>
+      {% set rowloop = loop %}
+      {% for cell in row %}
+        <td id="cell-{{ rowloop.index }}-{{ loop.index }}>{{ cell }}</td>
+      {% endfor %}
+      </tr>
+    {% endfor %}
+    </table>
diff --git a/lib/jinja2/examples/basic/cycle.py b/lib/jinja2/examples/basic/cycle.py
new file mode 100644
index 0000000..73dd632
--- /dev/null
+++ b/lib/jinja2/examples/basic/cycle.py
@@ -0,0 +1,13 @@
+from jinja2 import Environment
+
+
+env = Environment(line_statement_prefix="#", variable_start_string="${", variable_end_string="}")
+
+
+print env.from_string("""\
+<ul>
+# for item in range(10)
+    <li class="${loop.cycle('odd', 'even')}">${item}</li>
+# endfor
+</ul>\
+""").render()
diff --git a/lib/jinja2/examples/basic/debugger.py b/lib/jinja2/examples/basic/debugger.py
new file mode 100644
index 0000000..4291ff7
--- /dev/null
+++ b/lib/jinja2/examples/basic/debugger.py
@@ -0,0 +1,7 @@
+from jinja2 import Environment
+from jinja2.loaders import FileSystemLoader
+
+env = Environment(loader=FileSystemLoader('templates'))
+
+tmpl = env.get_template('broken.html')
+print tmpl.render(seq=[3, 2, 4, 5, 3, 2, 0, 2, 1])
diff --git a/lib/jinja2/examples/basic/inheritance.py b/lib/jinja2/examples/basic/inheritance.py
new file mode 100644
index 0000000..aa687c8
--- /dev/null
+++ b/lib/jinja2/examples/basic/inheritance.py
@@ -0,0 +1,12 @@
+from jinja2 import Environment
+from jinja2.loaders import DictLoader
+
+
+env = Environment(loader=DictLoader({
+'a': '''[A[{% block body %}{% endblock %}]]''',
+'b': '''{% extends 'a' %}{% block body %}[B]{% endblock %}''',
+'c': '''{% extends 'b' %}{% block body %}###{{ super() }}###{% endblock %}'''
+}))
+
+
+print env.get_template('c').render()
diff --git a/lib/jinja2/examples/basic/templates/broken.html b/lib/jinja2/examples/basic/templates/broken.html
new file mode 100644
index 0000000..294d5c9
--- /dev/null
+++ b/lib/jinja2/examples/basic/templates/broken.html
@@ -0,0 +1,6 @@
+{% from 'subbroken.html' import may_break %}
+<ul>
+{% for item in seq %}
+  <li>{{ may_break(item) }}</li>
+{% endfor %}
+</ul>
diff --git a/lib/jinja2/examples/basic/templates/subbroken.html b/lib/jinja2/examples/basic/templates/subbroken.html
new file mode 100644
index 0000000..245eb7e
--- /dev/null
+++ b/lib/jinja2/examples/basic/templates/subbroken.html
@@ -0,0 +1,3 @@
+{% macro may_break(item) -%}
+  [{{ item / 0 }}]
+{%- endmacro %}
diff --git a/lib/jinja2/examples/basic/test.py b/lib/jinja2/examples/basic/test.py
new file mode 100644
index 0000000..b62c84f
--- /dev/null
+++ b/lib/jinja2/examples/basic/test.py
@@ -0,0 +1,27 @@
+from jinja2 import Environment
+from jinja2.loaders import DictLoader
+
+env = Environment(loader=DictLoader({
+'child.html': u'''\
+{% extends master_layout or 'master.html' %}
+{% include helpers = 'helpers.html' %}
+{% macro get_the_answer() %}42{% endmacro %}
+{% title = 'Hello World' %}
+{% block body %}
+    {{ get_the_answer() }}
+    {{ helpers.conspirate() }}
+{% endblock %}
+''',
+'master.html': u'''\
+<!doctype html>
+<title>{{ title }}</title>
+{% block body %}{% endblock %}
+''',
+'helpers.html': u'''\
+{% macro conspirate() %}23{% endmacro %}
+'''
+}))
+
+
+tmpl = env.get_template("child.html")
+print tmpl.render()
diff --git a/lib/jinja2/examples/basic/test2.py b/lib/jinja2/examples/basic/test2.py
new file mode 100644
index 0000000..313ac7b
--- /dev/null
+++ b/lib/jinja2/examples/basic/test2.py
@@ -0,0 +1,14 @@
+from __pypy__ import tproxy
+
+
+def make_proxy(obj, proxy):
+    if tproxy is None:
+        return proxy
+    def operation_handler(operation, *args, **kwargs):
+        if operation in ('__getattribute__', '__getattr__'):
+            return getattr(proxy, args[0])
+        elif operation == '__setattr__':
+            proxy.__setattr__(*args, **kwargs)
+        else:
+            return getattr(proxy, operation)(*args, **kwargs)
+    return tproxy(type(obj), operation_handler)
diff --git a/lib/jinja2/examples/basic/test_filter_and_linestatements.py b/lib/jinja2/examples/basic/test_filter_and_linestatements.py
new file mode 100644
index 0000000..c9e8f95
--- /dev/null
+++ b/lib/jinja2/examples/basic/test_filter_and_linestatements.py
@@ -0,0 +1,25 @@
+from jinja2 import Environment
+
+
+env = Environment(line_statement_prefix='%', variable_start_string="${", variable_end_string="}")
+tmpl = env.from_string("""\
+% macro foo()
+    ${caller(42)}
+% endmacro
+<ul>
+% for item in seq
+    <li>${item}</li>
+% endfor
+</ul>
+% call(var) foo()
+    [${var}]
+% endcall
+% filter escape
+    <hello world>
+    % for item in [1, 2, 3]
+      -  ${item}
+    % endfor
+% endfilter
+""")
+
+print tmpl.render(seq=range(10))
diff --git a/lib/jinja2/examples/basic/test_loop_filter.py b/lib/jinja2/examples/basic/test_loop_filter.py
new file mode 100644
index 0000000..49c2efc
--- /dev/null
+++ b/lib/jinja2/examples/basic/test_loop_filter.py
@@ -0,0 +1,12 @@
+from jinja2 import Environment
+
+tmpl = Environment().from_string("""\
+<ul>
+{%- for item in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] if item % 2 == 0 %}
+    <li>{{ loop.index }} / {{ loop.length }}: {{ item }}</li>
+{%- endfor %}
+</ul>
+if condition: {{ 1 if foo else 0 }}
+""")
+
+print tmpl.render(foo=True)
diff --git a/lib/jinja2/examples/basic/translate.py b/lib/jinja2/examples/basic/translate.py
new file mode 100644
index 0000000..1fb8ee6
--- /dev/null
+++ b/lib/jinja2/examples/basic/translate.py
@@ -0,0 +1,14 @@
+from jinja2 import Environment
+
+env = Environment(extensions=['jinja2.ext.i18n'])
+env.globals['gettext'] = {
+    'Hello %(user)s!': 'Hallo %(user)s!'
+}.__getitem__
+env.globals['ngettext'] = lambda s, p, n: {
+    '%(count)s user': '%(count)d Benutzer',
+    '%(count)s users': '%(count)d Benutzer'
+}[n == 1 and s or p]
+print env.from_string("""\
+{% trans %}Hello {{ user }}!{% endtrans %}
+{% trans count=users|count %}{{ count }} user{% pluralize %}{{ count }} users{% endtrans %}
+""").render(user="someone", users=[1, 2, 3])
diff --git a/lib/jinja2/examples/bench.py b/lib/jinja2/examples/bench.py
new file mode 100644
index 0000000..c648dc6
--- /dev/null
+++ b/lib/jinja2/examples/bench.py
@@ -0,0 +1,433 @@
+"""\
+    This benchmark compares some python templating engines with Jinja 2 so
+    that we get a picture of how fast Jinja 2 is for a semi real world
+    template.  If a template engine is not installed the test is skipped.\
+"""
+import sys
+import cgi
+from timeit import Timer
+from jinja2 import Environment as JinjaEnvironment
+
+context = {
+    'page_title': 'mitsuhiko\'s benchmark',
+    'table': [dict(a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,i=9,j=10) for x in range(1000)]
+}
+
+jinja_template = JinjaEnvironment(
+    line_statement_prefix='%',
+    variable_start_string="${",
+    variable_end_string="}"
+).from_string("""\
+<!doctype html>
+<html>
+  <head>
+    <title>${page_title|e}</title>
+  </head>
+  <body>
+    <div class="header">
+      <h1>${page_title|e}</h1>
+    </div>
+    <ul class="navigation">
+    % for href, caption in [
+        ('index.html', 'Index'),
+        ('downloads.html', 'Downloads'),
+        ('products.html', 'Products')
+      ]
+      <li><a href="${href|e}">${caption|e}</a></li>
+    % endfor
+    </ul>
+    <div class="table">
+      <table>
+      % for row in table
+        <tr>
+        % for cell in row
+          <td>${cell}</td>
+        % endfor
+        </tr>
+      % endfor
+      </table>
+    </div>
+  </body>
+</html>\
+""")
+
+def test_jinja():
+    jinja_template.render(context)
+
+try:
+    from tornado.template import Template
+except ImportError:
+    test_tornado = None
+else:
+    tornado_template = Template("""\
+<!doctype html>
+<html>
+  <head>
+    <title>{{ page_title }}</title>
+  </head>
+  <body>
+    <div class="header">
+      <h1>{{ page_title }}</h1>
+    </div>
+    <ul class="navigation">
+    {% for href, caption in [ \
+        ('index.html', 'Index'), \
+        ('downloads.html', 'Downloads'), \
+        ('products.html', 'Products') \
+      ] %}
+      <li><a href="{{ href }}">{{ caption }}</a></li>
+    {% end %}
+    </ul>
+    <div class="table">
+      <table>
+      {% for row in table %}
+        <tr>
+        {% for cell in row %}
+          <td>{{ cell }}</td>
+        {% end %}
+        </tr>
+      {% end %}
+      </table>
+    </div>
+  </body>
+</html>\
+""")
+
+    def test_tornado():
+        tornado_template.generate(**context)
+
+try:
+    from django.conf import settings
+    settings.configure()
+    from django.template import Template as DjangoTemplate, Context as DjangoContext
+except ImportError:
+    test_django = None
+else:
+    django_template = DjangoTemplate("""\
+<!doctype html>
+<html>
+  <head>
+    <title>{{ page_title }}</title>
+  </head>
+  <body>
+    <div class="header">
+      <h1>{{ page_title }}</h1>
+    </div>
+    <ul class="navigation">
+    {% for href, caption in navigation %}
+      <li><a href="{{ href }}">{{ caption }}</a></li>
+    {% endfor %}
+    </ul>
+    <div class="table">
+      <table>
+      {% for row in table %}
+        <tr>
+        {% for cell in row %}
+          <td>{{ cell }}</td>
+        {% endfor %}
+        </tr>
+      {% endfor %}
+      </table>
+    </div>
+  </body>
+</html>\
+""")
+
+    def test_django():
+        c = DjangoContext(context)
+        c['navigation'] = [('index.html', 'Index'), ('downloads.html', 'Downloads'),
+                           ('products.html', 'Products')]
+        django_template.render(c)
+
+try:
+    from mako.template import Template as MakoTemplate
+except ImportError:
+    test_mako = None
+else:
+    mako_template = MakoTemplate("""\
+<!doctype html>
+<html>
+  <head>
+    <title>${page_title|h}</title>
+  </head>
+  <body>
+    <div class="header">
+      <h1>${page_title|h}</h1>
+    </div>
+    <ul class="navigation">
+    % for href, caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]:
+      <li><a href="${href|h}">${caption|h}</a></li>
+    % endfor
+    </ul>
+    <div class="table">
+      <table>
+      % for row in table:
+        <tr>
+        % for cell in row:
+          <td>${cell}</td>
+        % endfor
+        </tr>
+      % endfor
+      </table>
+    </div>
+  </body>
+</html>\
+""")
+
+    def test_mako():
+        mako_template.render(**context)
+
+try:
+    from genshi.template import MarkupTemplate as GenshiTemplate
+except ImportError:
+    test_genshi = None
+else:
+    genshi_template = GenshiTemplate("""\
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/">
+  <head>
+    <title>${page_title}</title>
+  </head>
+  <body>
+    <div class="header">
+      <h1>${page_title}</h1>
+    </div>
+    <ul class="navigation">
+      <li py:for="href, caption in [
+        ('index.html', 'Index'),
+        ('downloads.html', 'Downloads'),
+        ('products.html', 'Products')]"><a href="${href}">${caption}</a></li>
+    </ul>
+    <div class="table">
+      <table>
+        <tr py:for="row in table">
+          <td py:for="cell in row">${cell}</td>
+        </tr>
+      </table>
+    </div>
+  </body>
+</html>\
+""")
+
+    def test_genshi():
+        genshi_template.generate(**context).render('html', strip_whitespace=False)
+
+try:
+    from Cheetah.Template import Template as CheetahTemplate
+except ImportError:
+    test_cheetah = None
+else:
+    cheetah_template = CheetahTemplate("""\
+#import cgi
+<!doctype html>
+<html>
+  <head>
+    <title>$cgi.escape($page_title)</title>
+  </head>
+  <body>
+    <div class="header">
+      <h1>$cgi.escape($page_title)</h1>
+    </div>
+    <ul class="navigation">
+    #for $href, $caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]:
+      <li><a href="$cgi.escape($href)">$cgi.escape($caption)</a></li>
+    #end for
+    </ul>
+    <div class="table">
+      <table>
+      #for $row in $table:
+        <tr>
+        #for $cell in $row:
+          <td>$cell</td>
+        #end for
+        </tr>
+      #end for
+      </table>
+    </div>
+  </body>
+</html>\
+""", searchList=[dict(context)])
+
+    def test_cheetah():
+        unicode(cheetah_template)
+
+try:
+    import tenjin
+except ImportError:
+    test_tenjin = None
+else:
+    tenjin_template = tenjin.Template()
+    tenjin_template.convert("""\
+<!doctype html>
+<html>
+  <head>
+    <title>${page_title}</title>
+  </head>
+  <body>
+    <div class="header">
+      <h1>${page_title}</h1>
+    </div>
+    <ul class="navigation">
+<?py for href, caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]: ?>
+      <li><a href="${href}">${caption}</a></li>
+<?py #end ?>
+    </ul>
+    <div class="table">
+      <table>
+<?py for row in table: ?>
+        <tr>
+<?py     for cell in row: ?>
+          <td>#{cell}</td>
+<?py #end ?>
+        </tr>
+<?py #end ?>
+      </table>
+    </div>
+  </body>
+</html>\
+""")
+
+    def test_tenjin():
+        from tenjin.helpers import escape, to_str
+        tenjin_template.render(context, locals())
+
+try:
+    from spitfire.compiler import util as SpitfireTemplate
+    from spitfire.compiler.analyzer import o2_options as spitfire_optimizer
+except ImportError:
+    test_spitfire = None
+else:
+    spitfire_template = SpitfireTemplate.load_template("""\
+<!doctype html>
+<html>
+  <head>
+    <title>$cgi.escape($page_title)</title>
+  </head>
+  <body>
+    <div class="header">
+      <h1>$cgi.escape($page_title)</h1>
+    </div>
+    <ul class="navigation">
+    #for $href, $caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]
+      <li><a href="$cgi.escape($href)">$cgi.escape($caption)</a></li>
+    #end for
+    </ul>
+    <div class="table">
+      <table>
+      #for $row in $table
+        <tr>
+        #for $cell in $row
+          <td>$cell</td>
+        #end for
+        </tr>
+      #end for
+      </table>
+    </div>
+  </body>
+</html>\
+""", 'spitfire_tmpl', spitfire_optimizer, {'enable_filters': False})
+    spitfire_context = dict(context, **{'cgi': cgi})
+
+    def test_spitfire():
+        spitfire_template(search_list=[spitfire_context]).main()
+
+
+try:
+    from chameleon.zpt.template import PageTemplate
+except ImportError:
+    test_chameleon = None
+else:
+    chameleon_template = PageTemplate("""\
+<html xmlns:tal="http://xml.zope.org/namespaces/tal">
+  <head>
+    <title tal:content="page_title">Page Title</title>
+  </head>
+  <body>
+    <div class="header">
+      <h1 tal:content="page_title">Page Title</h1>
+    </div>
+    <ul class="navigation">
+    <li tal:repeat="item sections"><a tal:attributes="href item[0]" tal:content="item[1]">caption</a></li>
+    </ul>
+    <div class="table">
+      <table>
+        <tr tal:repeat="row table">
+        <td tal:repeat="cell row" tal:content="row[cell]">cell</td>
+        </tr>
+      </table>
+    </div>
+  </body>
+</html>\
+""")
+    chameleon_context = dict(context)
+    chameleon_context['sections'] = [
+        ('index.html', 'Index'),
+        ('downloads.html', 'Downloads'),
+        ('products.html', 'Products')
+    ]
+    def test_chameleon():
+        chameleon_template.render(**chameleon_context)
+
+try:
+    from chameleon.zpt.template import PageTemplate
+    from chameleon.genshi import language
+except ImportError:
+    test_chameleon_genshi = None
+else:
+    chameleon_genshi_template = PageTemplate("""\
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/">
+  <head>
+    <title>${page_title}</title>
+  </head>
+  <body>
+    <div class="header">
+      <h1>${page_title}</h1>
+    </div>
+    <ul class="navigation">
+    <li py:for="info in sections"><a href="${info[0]}">${info[1]}</a></li>
+    </ul>
+    <div class="table">
+      <table>
+        <tr py:for="row in table">
+          <td py:for="cell in row">${row[cell]}</td>
+        </tr>
+      </table>
+    </div>
+  </body>
+</html>\
+""", parser=language.Parser())
+    chameleon_genshi_context = dict(context)
+    chameleon_genshi_context['sections'] = [
+        ('index.html', 'Index'),
+        ('downloads.html', 'Downloads'),
+        ('products.html', 'Products')
+    ]
+    def test_chameleon_genshi():
+        chameleon_genshi_template.render(**chameleon_genshi_context)
+
+
+sys.stdout.write('\r' + '\n'.join((
+    '=' * 80,
+    'Template Engine BigTable Benchmark'.center(80),
+    '=' * 80,
+    __doc__,
+    '-' * 80
+)) + '\n')
+
+
+for test in 'jinja', 'mako', 'tornado', 'tenjin', 'spitfire', 'django', 'genshi', 'cheetah', 'chameleon', 'chameleon_genshi':
+    if locals()['test_' + test] is None:
+        sys.stdout.write('    %-20s*not installed*\n' % test)
+        continue
+    t = Timer(setup='from __main__ import test_%s as bench' % test,
+              stmt='bench()')
+    sys.stdout.write(' >> %-20s<running>' % test)
+    sys.stdout.flush()
+    sys.stdout.write('\r    %-20s%.4f seconds\n' % (test, t.timeit(number=50) / 50))
+sys.stdout.write('-' * 80 + '\n')
+sys.stdout.write('''\
+    WARNING: The results of this benchmark are useless to compare the
+    performance of template engines and should not be taken seriously in any
+    way.  It's testing the performance of simple loops and has no real-world
+    usefulnes.  It only used to check if changes on the Jinja code affect
+    performance in a good or bad way and how it roughly compares to others.
+''' + '=' * 80 + '\n')
diff --git a/lib/jinja2/examples/profile.py b/lib/jinja2/examples/profile.py
new file mode 100644
index 0000000..0c907ae
--- /dev/null
+++ b/lib/jinja2/examples/profile.py
@@ -0,0 +1,52 @@
+try:
+    from cProfile import Profile
+except ImportError:
+    from profile import Profile
+from pstats import Stats
+from jinja2 import Environment as JinjaEnvironment
+
+context = {
+    'page_title': 'mitsuhiko\'s benchmark',
+    'table': [dict(a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,i=9,j=10) for x in range(1000)]
+}
+
+source = """\
+% macro testmacro(x)
+  <span>${x}</span>
+% endmacro
+<!doctype html>
+<html>
+  <head>
+    <title>${page_title|e}</title>
+  </head>
+  <body>
+    <div class="header">
+      <h1>${page_title|e}</h1>
+    </div>
+    <div class="table">
+      <table>
+      % for row in table
+        <tr>
+        % for cell in row
+          <td>${testmacro(cell)}</td>
+        % endfor
+        </tr>
+      % endfor
+      </table>
+    </div>
+  </body>
+</html>\
+"""
+jinja_template = JinjaEnvironment(
+    line_statement_prefix='%',
+    variable_start_string="${",
+    variable_end_string="}"
+).from_string(source)
+print jinja_template.environment.compile(source, raw=True)
+
+
+p = Profile()
+p.runcall(lambda: jinja_template.render(context))
+stats = Stats(p)
+stats.sort_stats('time', 'calls')
+stats.print_stats()
diff --git a/lib/jinja2/examples/rwbench/django/_form.html b/lib/jinja2/examples/rwbench/django/_form.html
new file mode 100644
index 0000000..9c4f710
--- /dev/null
+++ b/lib/jinja2/examples/rwbench/django/_form.html
@@ -0,0 +1 @@
+<form action="{{ action }}" method="{{ method }}">{{ body }}</form>
diff --git a/lib/jinja2/examples/rwbench/django/_input_field.html b/lib/jinja2/examples/rwbench/django/_input_field.html
new file mode 100644
index 0000000..290fdbd
--- /dev/null
+++ b/lib/jinja2/examples/rwbench/django/_input_field.html
@@ -0,0 +1 @@
+<input type="{{ type }}" value="{{ value }}" name="{{ name }}">
diff --git a/lib/jinja2/examples/rwbench/django/_textarea.html b/lib/jinja2/examples/rwbench/django/_textarea.html
new file mode 100644
index 0000000..7f10424
--- /dev/null
+++ b/lib/jinja2/examples/rwbench/django/_textarea.html
@@ -0,0 +1 @@
+<textarea name="{{ name }}" rows="{{ rows }}" cols="{{ cols }}">{{ value }}</textarea>
diff --git a/lib/jinja2/examples/rwbench/django/index.html b/lib/jinja2/examples/rwbench/django/index.html
new file mode 100644
index 0000000..6f620bb
--- /dev/null
+++ b/lib/jinja2/examples/rwbench/django/index.html
@@ -0,0 +1,29 @@
+{% extends "layout.html" %}
+{% block page_title %}Index Page{% endblock %}
+{% block body %}
+  {% for article in articles %}
+  {% if article.published %}
+  <div class="article">
+    <h2><a href="{{ article.href }}">{{ article.title }}</a></h2>
+    <p class="meta">written by <a href="{{ article.user.href }}">{{ article.user.username }}</a> on {{ article.pub_date|dateformat }}</p>
+    <div class="text">{{ article.body|safe }}</div>
+  </div>
+  {% endif %}
+  {% endfor %}
+  {% form %}
+    <dl>
+      <dt>Name</dt>
+      <dd>{% input_field 'name' %}</dd>
+      <dt>E-Mail</dt>
+      <dd>{% input_field 'email' %}</dd>
+      <dt>URL</dt>
+      <dd>{% input_field 'url' %}</dd>
+      <dt>Comment</dt>
+      <dd>{% textarea 'comment' %}</dd>
+      <dt>Captcha</dt>
+      <dd>{% input_field 'captcha' %}</dd>
+    </dl>
+    {% input_field '' 'submit' 'Submit' %}
+    {% input_field 'cancel' 'submit' 'Cancel' %}
+  {% endform %}
+{% endblock %}
diff --git a/lib/jinja2/examples/rwbench/django/layout.html b/lib/jinja2/examples/rwbench/django/layout.html
new file mode 100644
index 0000000..60039ce
--- /dev/null
+++ b/lib/jinja2/examples/rwbench/django/layout.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+  <title>{% block page_title %}{% endblock %} | RealWorld Benchmark</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+</head>
+<body>
+  <div class="contents">
+    <div class="header">
+      <h1>RealWorld Benchmark</h1>
+      <blockquote><p>
+        A less stupid benchmark for Mako and Jinja2 to get an impression how
+        code changes affect runtime performance.
+      </p></blockquote>
+    </div>
+    <ul class="navigation">
+    {% for href, caption in page_navigation %}
+      <li><a href="{{ href }}">{{ caption }}</a></li>
+    {% endfor %}
+    </ul>
+    <div class="body">
+      {% block body %}{% endblock %}
+    </div>
+    <div class="footer">
+      &copy; Copyright 2008 by I don't know who.
+    </div>
+  </div>
+</body>
+</html>
diff --git a/lib/jinja2/examples/rwbench/djangoext.py b/lib/jinja2/examples/rwbench/djangoext.py
new file mode 100644
index 0000000..9e9fa6c
--- /dev/null
+++ b/lib/jinja2/examples/rwbench/djangoext.py
@@ -0,0 +1,135 @@
+# -*- coding: utf-8 -*-
+from rwbench import ROOT
+from os.path import join
+from django.conf import settings
+settings.configure(
+    TEMPLATE_DIRS=(join(ROOT, 'django'),),
+    TEMPLATE_LOADERS=(
+        ('django.template.loaders.cached.Loader', (
+            'django.template.loaders.filesystem.Loader',
+        )),
+    )
+)
+from django.template import loader as django_loader, Context as DjangoContext, \
+     Node, NodeList, Variable, TokenParser
+from django import template as django_template_module
+from django.template import Library
+
+
+# for django extensions.  We monkey patch our extensions in so that
+# we don't have to initialize a more complex django setup.
+django_extensions = django_template_module.Library()
+django_template_module.builtins.append(django_extensions)
+
+
+from rwbench import dateformat
+django_extensions.filter(dateformat)
+
+
+def var_or_none(x):
+    if x is not None:
+        return Variable(x)
+
+
+# and more django extensions
+@django_extensions.tag
+def input_field(parser, token):
+    p = TokenParser(token.contents)
+    args = [p.value()]
+    while p.more():
+        args.append(p.value())
+    return InputFieldNode(*args)
+
+
+@django_extensions.tag
+def textarea(parser, token):
+    p = TokenParser(token.contents)
+    args = [p.value()]
+    while p.more():
+        args.append(p.value())
+    return TextareaNode(*args)
+
+
+@django_extensions.tag
+def form(parser, token):
+    p = TokenParser(token.contents)
+    args = []
+    while p.more():
+        args.append(p.value())
+    body = parser.parse(('endform',))
+    parser.delete_first_token()
+    return FormNode(body, *args)
+
+
+class InputFieldNode(Node):
+
+    def __init__(self, name, type=None, value=None):
+        self.name = var_or_none(name)
+        self.type = var_or_none(type)
+        self.value = var_or_none(value)
+
+    def render(self, context):
+        name = self.name.resolve(context)
+        type = 'text'
+        value = ''
+        if self.type is not None:
+            type = self.type.resolve(context)
+        if self.value is not None:
+            value = self.value.resolve(context)
+        tmpl = django_loader.get_template('_input_field.html')
+        return tmpl.render(DjangoContext({
+            'name':     name,
+            'type':     type,
+            'value':    value
+        }))
+
+
+class TextareaNode(Node):
+
+    def __init__(self, name, rows=None, cols=None, value=None):
+        self.name = var_or_none(name)
+        self.rows = var_or_none(rows)
+        self.cols = var_or_none(cols)
+        self.value = var_or_none(value)
+
+    def render(self, context):
+        name = self.name.resolve(context)
+        rows = 10
+        cols = 40
+        value = ''
+        if self.rows is not None:
+            rows = int(self.rows.resolve(context))
+        if self.cols is not None:
+            cols = int(self.cols.resolve(context))
+        if self.value is not None:
+            value = self.value.resolve(context)
+        tmpl = django_loader.get_template('_textarea.html')
+        return tmpl.render(DjangoContext({
+            'name':     name,
+            'rows':     rows,
+            'cols':     cols,
+            'value':    value
+        }))
+
+
+class FormNode(Node):
+
+    def __init__(self, body, action=None, method=None):
+        self.body = body
+        self.action = action
+        self.method = method
+
+    def render(self, context):
+        body = self.body.render(context)
+        action = ''
+        method = 'post'
+        if self.action is not None:
+            action = self.action.resolve(context)
+        if self.method is not None:
+            method = self.method.resolve(context)
+        tmpl = django_loader.get_template('_form.html')
+        return tmpl.render(DjangoContext({
+            'body':     body,
+            'action':   action,
+            'method':   method
+        }))
diff --git a/lib/jinja2/examples/rwbench/genshi/helpers.html b/lib/jinja2/examples/rwbench/genshi/helpers.html
new file mode 100644
index 0000000..ecc6dc4
--- /dev/null
+++ b/lib/jinja2/examples/rwbench/genshi/helpers.html
@@ -0,0 +1,12 @@
+<div xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/"
+     py:strip="">
+
+  <py:def function="input_field(name='', value='', type='text')">
+    <input type="$type" value="$value" name="$name" />
+  </py:def>
+
+  <py:def function="textarea(name, value='', rows=10, cols=40)">
+    <textarea name="$name" rows="$rows" cols="cols">$value</textarea>
+  </py:def>
+
+</div>
diff --git a/lib/jinja2/examples/rwbench/genshi/index.html b/lib/jinja2/examples/rwbench/genshi/index.html
new file mode 100644
index 0000000..70f697d
--- /dev/null
+++ b/lib/jinja2/examples/rwbench/genshi/index.html
@@ -0,0 +1,41 @@
+<?python
+  from rwbench import dateformat
+?>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xi="http://www.w3.org/2001/XInclude"
+      xmlns:py="http://genshi.edgewall.org/">
+  <xi:include href="layout.html" />
+  <xi:include href="helpers.html" />
+  <head><title>Index Page</title></head>
+  <body>
+    <div class="article" py:for="article in articles">
+      <py:if test="article.published">
+        <h2><a href="${article.href}">${article.title}</a></h2>
+        <p class="meta">written by <a href="${article.user.href}"
+          >${article.user.username}</a> on ${dateformat(article.pub_date)}</p>
+        <div class="text">${Markup(article.body)}</div>
+      </py:if>
+    </div>
+    <!--
+      For a fair and balanced comparison we would have to use a def here
+      that wraps the form data but I don't know what would be the best
+      Genshi equivalent for that.  Quite frankly I doubt that this makes
+      sense in Genshi anyways.
+    -->
+    <form action="" method="post">
+      <dl>
+        <dt>Name</dt>
+        <dd>${input_field('name')}</dd>
+        <dt>E-Mail</dt>
+        <dd>${input_field('email')}</dd>
+        <dt>URL</dt>
+        <dd>${input_field('url')}</dd>
+        <dt>Comment</dt>
+        <dd>${textarea('comment')}</dd>
+        <dt>Captcha</dt>
+        <dd>${input_field('captcha')}</dd>
+      </dl>
+      ${input_field(type='submit', value='Submit')}
+      ${input_field(name='cancel', type='submit', value='Cancel')}
+    </form>
+  </body>
+</html>
diff --git a/lib/jinja2/examples/rwbench/genshi/layout.html b/lib/jinja2/examples/rwbench/genshi/layout.html
new file mode 100644
index 0000000..b12aec4
--- /dev/null
+++ b/lib/jinja2/examples/rwbench/genshi/layout.html
@@ -0,0 +1,30 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/" >
+  <py:match path="head" once="true">
+    <head>
+      <title>${select('title/text()')} | RealWorld Benchmark</title>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    </head>
+  </py:match>
+  <py:match path="body" once="true">
+    <body>
+      <div class="contents">
+        <div class="header">
+          <h1>RealWorld Benchmark</h1>
+          <blockquote><p>
+            A less stupid benchmark for Mako and Jinja2 to get an impression how
+            code changes affect runtime performance.
+          </p></blockquote>
+        </div>
+        <ul class="navigation">
+          <li py:for="href, caption in page_navigation"><a href="$href">$caption</a></li>
+        </ul>
+        <div class="body">
+          ${select('*|text()')}
+        </div>
+        <div class="footer">
+          &copy; Copyright 2008 by I don't know who.
+        </div>
+      </div>
+    </body>
+  </py:match>
+</html>
diff --git a/lib/jinja2/examples/rwbench/jinja/helpers.html b/lib/jinja2/examples/rwbench/jinja/helpers.html
new file mode 100644
index 0000000..89976aa
--- /dev/null
+++ b/lib/jinja2/examples/rwbench/jinja/helpers.html
@@ -0,0 +1,12 @@
+{% macro input_field(name, value='', type='text') -%}
+  <input type="{{ type }}" value="{{ value|e }}" name="{{ name }}">
+{%- endmacro %}
+
+{% macro textarea(name, value='', rows=10, cols=40) -%}
+  <textarea name="{{ name }}" rows="{{ rows }}" cols="{{ cols }}">{{
+    value|e }}</textarea>
+{%- endmacro %}
+
+{% macro form(action='', method='post') -%}
+  <form action="{{ action|e }}" method="{{ method }}">{{ caller() }}</form>
+{%- endmacro %}
diff --git a/lib/jinja2/examples/rwbench/jinja/index.html b/lib/jinja2/examples/rwbench/jinja/index.html
new file mode 100644
index 0000000..b006d05
--- /dev/null
+++ b/lib/jinja2/examples/rwbench/jinja/index.html
@@ -0,0 +1,29 @@
+{% extends "layout.html" %}
+{% from "helpers.html" import input_field, textarea, form %}
+{% block page_title %}Index Page{% endblock %}
+{% block body %}
+  {%- for article in articles if article.published %}
+  <div class="article">
+    <h2><a href="{{ article.href|e }}">{{ article.title|e }}</a></h2>
+    <p class="meta">written by <a href="{{ article.user.href|e
+      }}">{{ article.user.username|e }}</a> on {{ article.pub_date|dateformat }}</p>
+    <div class="text">{{ article.body }}</div>
+  </div>
+  {%- endfor %}
+  {%- call form() %}
+    <dl>
+      <dt>Name</dt>
+      <dd>{{ input_field('name') }}</dd>
+      <dt>E-Mail</dt>
+      <dd>{{ input_field('email') }}</dd>
+      <dt>URL</dt>
+      <dd>{{ input_field('url') }}</dd>
+      <dt>Comment</dt>
+      <dd>{{ textarea('comment') }}</dd>
+      <dt>Captcha</dt>
+      <dd>{{ input_field('captcha') }}</dd>
+    </dl>
+    {{ input_field(type='submit', value='Submit') }}
+    {{ input_field('cancel', type='submit', value='Cancel') }}
+  {%- endcall %}
+{% endblock %}
diff --git a/lib/jinja2/examples/rwbench/jinja/layout.html b/lib/jinja2/examples/rwbench/jinja/layout.html
new file mode 100644
index 0000000..755789e
--- /dev/null
+++ b/lib/jinja2/examples/rwbench/jinja/layout.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+  <title>{% block page_title %}{% endblock %} | RealWorld Benchmark</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+</head>
+<body>
+  <div class="contents">
+    <div class="header">
+      <h1>RealWorld Benchmark</h1>
+      <blockquote><p>
+        A less stupid benchmark for Mako and Jinja2 to get an impression how
+        code changes affect runtime performance.
+      </p></blockquote>
+    </div>
+    <ul class="navigation">
+    {%- for href, caption in page_navigation %}
+      <li><a href="{{ href|e }}">{{ caption }}</a></li>
+    {%- endfor %}
+    </ul>
+    <div class="body">
+      {% block body %}{% endblock %}
+    </div>
+    <div class="footer">
+      &copy; Copyright 2008 by I don't know who.
+    </div>
+  </div>
+</body>
+</html>
diff --git a/lib/jinja2/examples/rwbench/mako/helpers.html b/lib/jinja2/examples/rwbench/mako/helpers.html
new file mode 100644
index 0000000..a0290eb
--- /dev/null
+++ b/lib/jinja2/examples/rwbench/mako/helpers.html
@@ -0,0 +1,11 @@
+<%def name="input_field(name='', value='', type='text')">
+  <input type="${type}" value="${value|h}" name="${name}">
+</%def>
+
+<%def name="textarea(name, value='', rows=10, cols=40)">
+  <textarea name="${name}" rows="${rows}" cols="${cols}">${value|h}</textarea>
+</%def>
+
+<%def name="form(action='', method='post')">
+  <form action="${action|h}" method="${method}">${caller.body()}</form>
+</%def>
diff --git a/lib/jinja2/examples/rwbench/mako/index.html b/lib/jinja2/examples/rwbench/mako/index.html
new file mode 100644
index 0000000..c4c6303
--- /dev/null
+++ b/lib/jinja2/examples/rwbench/mako/index.html
@@ -0,0 +1,31 @@
+<%!
+  from rwbench import dateformat
+%>
+<%inherit file="layout.html" />
+<%namespace file="helpers.html" import="input_field, textarea, form" />
+<%def name="page_title()">Index Page</%def>
+% for article in articles:
+  <% if not article.published: continue %>
+<div class="article">
+  <h2><a href="${article.href|h}">${article.title|h}</a></h2>
+  <p class="meta">written by <a href="${article.user.href|h
+    }">${article.user.username|h}</a> on ${dateformat(article.pub_date)}</p>
+  <div class="text">${article.body}</div>
+</div>
+% endfor
+<%call expr="form()">
+  <dl>
+    <dt>Name</dt>
+    <dd>${input_field('name')}</dd>
+    <dt>E-Mail</dt>
+    <dd>${input_field('email')}</dd>
+    <dt>URL</dt>
+    <dd>${input_field('url')}</dd>
+    <dt>Comment</dt>
+    <dd>${textarea('comment')}</dd>
+    <dt>Captcha</dt>
+    <dd>${input_field('captcha')}</dd>
+  </dl>
+  ${input_field(type='submit', value='Submit')}
+  ${input_field(name='cancel', type='submit', value='Cancel')}
+</%call>
diff --git a/lib/jinja2/examples/rwbench/mako/layout.html b/lib/jinja2/examples/rwbench/mako/layout.html
new file mode 100644
index 0000000..a9c353e
--- /dev/null
+++ b/lib/jinja2/examples/rwbench/mako/layout.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+  <title>${self.page_title()} | RealWorld Benchmark</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+</head>
+<body>
+  <div class="contents">
+    <div class="header">
+      <h1>RealWorld Benchmark</h1>
+      <blockquote><p>
+        A less stupid benchmark for Mako and Jinja2 to get an impression how
+        code changes affect runtime performance.
+      </p></blockquote>
+    </div>
+    <ul class="navigation">
+    % for href, caption in page_navigation:
+      <li><a href="${href|h}">${caption}</a></li>
+    % endfor
+    </ul>
+    <div class="body">
+      ${self.body()}
+    </div>
+    <div class="footer">
+      &copy; Copyright 2008 by I don't know who.
+    </div>
+  </div>
+</body>
+</html>
+<%def name="page_title()"></%def>
diff --git a/lib/jinja2/examples/rwbench/rwbench.py b/lib/jinja2/examples/rwbench/rwbench.py
new file mode 100644
index 0000000..813dd56
--- /dev/null
+++ b/lib/jinja2/examples/rwbench/rwbench.py
@@ -0,0 +1,112 @@
+# -*- coding: utf-8 -*-
+"""
+    RealWorldish Benchmark
+    ~~~~~~~~~~~~~~~~~~~~~~
+
+    A more real-world benchmark of Jinja2.  Like the other benchmark in the
+    Jinja2 repository this has no real-world usefulnes (despite the name).
+    Just go away and ignore it.  NOW!
+
+    :copyright: (c) 2009 by the Jinja Team.
+    :license: BSD.
+"""
+import sys
+from os.path import join, dirname, abspath
+try:
+    from cProfile import Profile
+except ImportError:
+    from profile import Profile
+from pstats import Stats
+ROOT = abspath(dirname(__file__))
+
+from random import choice, randrange
+from datetime import datetime
+from timeit import Timer
+from jinja2 import Environment, FileSystemLoader
+from jinja2.utils import generate_lorem_ipsum
+from mako.lookup import TemplateLookup
+from genshi.template import TemplateLoader as GenshiTemplateLoader
+
+
+def dateformat(x):
+    return x.strftime('%Y-%m-%d')
+
+
+jinja_env = Environment(loader=FileSystemLoader(join(ROOT, 'jinja')))
+jinja_env.filters['dateformat'] = dateformat
+mako_lookup = TemplateLookup(directories=[join(ROOT, 'mako')])
+genshi_loader = GenshiTemplateLoader([join(ROOT, 'genshi')])
+
+class Article(object):
+
+    def __init__(self, id):
+        self.id = id
+        self.href = '/article/%d' % self.id
+        self.title = generate_lorem_ipsum(1, False, 5, 10)
+        self.user = choice(users)
+        self.body = generate_lorem_ipsum()
+        self.pub_date = datetime.utcfromtimestamp(randrange(10 ** 9, 2 * 10 ** 9))
+        self.published = True
+
+
+class User(object):
+
+    def __init__(self, username):
+        self.href = '/user/%s' % username
+        self.username = username
+
+
+users = map(User, [u'John Doe', u'Jane Doe', u'Peter Somewhat'])
+articles = map(Article, range(20))
+navigation = [
+    ('index',           'Index'),
+    ('about',           'About'),
+    ('foo?bar=1',       'Foo with Bar'),
+    ('foo?bar=2&s=x',   'Foo with X'),
+    ('blah',            'Blub Blah'),
+    ('hehe',            'Haha'),
+] * 5
+
+context = dict(users=users, articles=articles, page_navigation=navigation)
+
+
+jinja_template = jinja_env.get_template('index.html')
+mako_template = mako_lookup.get_template('index.html')
+genshi_template = genshi_loader.load('index.html')
+
+
+def test_jinja():
+    jinja_template.render(context)
+
+def test_mako():
+    mako_template.render_unicode(**context)
+
+
+from djangoext import django_loader, DjangoContext
+def test_django():
+    # not cached because django is not thread safe and does
+    # not cache by itself so it would be unfair to cache it here.
+    django_template = django_loader.get_template('index.html')
+    django_template.render(DjangoContext(context))
+
+
+def test_genshi():
+    genshi_template.generate(**context).render('html', doctype='html')
+
+
+if __name__ == '__main__':
+    sys.stdout.write('Realworldish Benchmark:\n')
+    for test in 'jinja', 'mako', 'django', 'genshi':
+        t = Timer(setup='from __main__ import test_%s as bench' % test,
+                  stmt='bench()')
+        sys.stdout.write(' >> %-20s<running>' % test)
+        sys.stdout.flush()
+        sys.stdout.write('\r    %-20s%.4f seconds\n' % (test, t.timeit(number=200) / 200))
+
+    if '-p' in sys.argv:
+        print 'Jinja profile'
+        p = Profile()
+        p.runcall(test_jinja)
+        stats = Stats(p)
+        stats.sort_stats('time', 'calls')
+        stats.print_stats()
diff --git a/lib/jinja2/ext/JinjaTemplates.tmbundle.tar.gz b/lib/jinja2/ext/JinjaTemplates.tmbundle.tar.gz
new file mode 100644
index 0000000..65b7422
--- /dev/null
+++ b/lib/jinja2/ext/JinjaTemplates.tmbundle.tar.gz
Binary files differ
diff --git a/lib/jinja2/ext/Vim/jinja.vim b/lib/jinja2/ext/Vim/jinja.vim
new file mode 100644
index 0000000..894dcc4
--- /dev/null
+++ b/lib/jinja2/ext/Vim/jinja.vim
@@ -0,0 +1,135 @@
+" Vim syntax file
+" Language:	Jinja template
+" Maintainer:	Armin Ronacher <armin.ronacher@active-4.com>
+" Last Change:	2008 May 9
+" Version:      1.1
+"
+" Known Bugs:
+"   because of odd limitations dicts and the modulo operator
+"   appear wrong in the template.
+"
+" Changes:
+"
+"     2008 May 9:     Added support for Jinja2 changes (new keyword rules)
+
+" .vimrc variable to disable html highlighting
+if !exists('g:jinja_syntax_html')
+   let g:jinja_syntax_html=1
+endif
+
+" For version 5.x: Clear all syntax items
+" For version 6.x: Quit when a syntax file was already loaded
+if !exists("main_syntax")
+  if version < 600
+    syntax clear
+  elseif exists("b:current_syntax")
+  finish
+endif
+  let main_syntax = 'jinja'
+endif
+
+" Pull in the HTML syntax.
+if g:jinja_syntax_html
+  if version < 600
+    so <sfile>:p:h/html.vim
+  else
+    runtime! syntax/html.vim
+    unlet b:current_syntax
+  endif
+endif
+
+syntax case match
+
+" Jinja template built-in tags and parameters (without filter, macro, is and raw, they
+" have special threatment)
+syn keyword jinjaStatement containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained and if else in not or recursive as import
+
+syn keyword jinjaStatement containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained is filter skipwhite nextgroup=jinjaFilter
+syn keyword jinjaStatement containedin=jinjaTagBlock contained macro skipwhite nextgroup=jinjaFunction
+syn keyword jinjaStatement containedin=jinjaTagBlock contained block skipwhite nextgroup=jinjaBlockName
+
+" Variable Names
+syn match jinjaVariable containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained skipwhite /[a-zA-Z_][a-zA-Z0-9_]*/
+syn keyword jinjaSpecial containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained false true none False True None loop super caller varargs kwargs
+
+" Filters
+syn match jinjaOperator "|" containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained nextgroup=jinjaFilter
+syn match jinjaFilter contained skipwhite /[a-zA-Z_][a-zA-Z0-9_]*/
+syn match jinjaFunction contained skipwhite /[a-zA-Z_][a-zA-Z0-9_]*/
+syn match jinjaBlockName contained skipwhite /[a-zA-Z_][a-zA-Z0-9_]*/
+
+" Jinja template constants
+syn region jinjaString containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained start=/"/ skip=/\\"/ end=/"/
+syn region jinjaString containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained start=/'/ skip=/\\'/ end=/'/
+syn match jinjaNumber containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained /[0-9]\+\(\.[0-9]\+\)\?/
+
+" Operators
+syn match jinjaOperator containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained /[+\-*\/<>=!,:]/
+syn match jinjaPunctuation containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained /[()\[\]]/
+syn match jinjaOperator containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained /\./ nextgroup=jinjaAttribute
+syn match jinjaAttribute contained /[a-zA-Z_][a-zA-Z0-9_]*/
+
+" Jinja template tag and variable blocks
+syn region jinjaNested matchgroup=jinjaOperator start="(" end=")" transparent display containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained
+syn region jinjaNested matchgroup=jinjaOperator start="\[" end="\]" transparent display containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained
+syn region jinjaNested matchgroup=jinjaOperator start="{" end="}" transparent display containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained
+syn region jinjaTagBlock matchgroup=jinjaTagDelim start=/{%-\?/ end=/-\?%}/ skipwhite containedin=ALLBUT,jinjaTagBlock,jinjaVarBlock,jinjaRaw,jinjaString,jinjaNested,jinjaComment
+
+syn region jinjaVarBlock matchgroup=jinjaVarDelim start=/{{-\?/ end=/-\?}}/ containedin=ALLBUT,jinjaTagBlock,jinjaVarBlock,jinjaRaw,jinjaString,jinjaNested,jinjaComment
+
+" Jinja template 'raw' tag
+syn region jinjaRaw matchgroup=jinjaRawDelim start="{%\s*raw\s*%}" end="{%\s*endraw\s*%}" containedin=ALLBUT,jinjaTagBlock,jinjaVarBlock,jinjaString,jinjaComment
+
+" Jinja comments
+syn region jinjaComment matchgroup=jinjaCommentDelim start="{#" end="#}" containedin=ALLBUT,jinjaTagBlock,jinjaVarBlock,jinjaString
+
+" Block start keywords.  A bit tricker.  We only highlight at the start of a
+" tag block and only if the name is not followed by a comma or equals sign
+" which usually means that we have to deal with an assignment.
+syn match jinjaStatement containedin=jinjaTagBlock contained skipwhite /\({%-\?\s*\)\@<=\<[a-zA-Z_][a-zA-Z0-9_]*\>\(\s*[,=]\)\@!/
+
+" and context modifiers
+syn match jinjaStatement containedin=jinjaTagBlock contained /\<with\(out\)\?\s\+context\>/ skipwhite
+
+
+" Define the default highlighting.
+" For version 5.7 and earlier: only when not done already
+" For version 5.8 and later: only when an item doesn't have highlighting yet
+if version >= 508 || !exists("did_jinja_syn_inits")
+  if version < 508
+    let did_jinja_syn_inits = 1
+    command -nargs=+ HiLink hi link <args>
+  else
+    command -nargs=+ HiLink hi def link <args>
+  endif
+
+  HiLink jinjaPunctuation jinjaOperator
+  HiLink jinjaAttribute jinjaVariable
+  HiLink jinjaFunction jinjaFilter
+
+  HiLink jinjaTagDelim jinjaTagBlock
+  HiLink jinjaVarDelim jinjaVarBlock
+  HiLink jinjaCommentDelim jinjaComment
+  HiLink jinjaRawDelim jinja
+
+  HiLink jinjaSpecial Special
+  HiLink jinjaOperator Normal
+  HiLink jinjaRaw Normal
+  HiLink jinjaTagBlock PreProc
+  HiLink jinjaVarBlock PreProc
+  HiLink jinjaStatement Statement
+  HiLink jinjaFilter Function
+  HiLink jinjaBlockName Function
+  HiLink jinjaVariable Identifier
+  HiLink jinjaString Constant
+  HiLink jinjaNumber Constant
+  HiLink jinjaComment Comment
+
+  delcommand HiLink
+endif
+
+let b:current_syntax = "jinja"
+
+if main_syntax == 'jinja'
+  unlet main_syntax
+endif
diff --git a/lib/jinja2/ext/django2jinja/django2jinja.py b/lib/jinja2/ext/django2jinja/django2jinja.py
new file mode 100644
index 0000000..6d9e76c
--- /dev/null
+++ b/lib/jinja2/ext/django2jinja/django2jinja.py
@@ -0,0 +1,768 @@
+# -*- coding: utf-8 -*-
+"""
+    Django to Jinja
+    ~~~~~~~~~~~~~~~
+
+    Helper module that can convert django templates into Jinja2 templates.
+
+    This file is not intended to be used as stand alone application but to
+    be used as library.  To convert templates you basically create your own
+    writer, add extra conversion logic for your custom template tags,
+    configure your django environment and run the `convert_templates`
+    function.
+
+    Here a simple example::
+
+        # configure django (or use settings.configure)
+        import os
+        os.environ['DJANGO_SETTINGS_MODULE'] = 'yourapplication.settings'
+        from yourapplication.foo.templatetags.bar import MyNode
+
+        from django2jinja import Writer, convert_templates
+
+        def write_my_node(writer, node):
+            writer.start_variable()
+            writer.write('myfunc(')
+            for idx, arg in enumerate(node.args):
+                if idx:
+                    writer.write(', ')
+                writer.node(arg)
+            writer.write(')')
+            writer.end_variable()
+
+        writer = Writer()
+        writer.node_handlers[MyNode] = write_my_node
+        convert_templates('/path/to/output/folder', writer=writer)
+    
+    Here is an example hos to automatically translate your django
+    variables to jinja2::
+        
+        import re
+        # List of tuple (Match pattern, Replace pattern, Exclusion pattern)
+        
+        var_re  = ((re.compile(r"(u|user)\.is_authenticated"), r"\1.is_authenticated()", None),
+                  (re.compile(r"\.non_field_errors"), r".non_field_errors()", None),
+                  (re.compile(r"\.label_tag"), r".label_tag()", None),
+                  (re.compile(r"\.as_dl"), r".as_dl()", None),
+                  (re.compile(r"\.as_table"), r".as_table()", None),
+                  (re.compile(r"\.as_widget"), r".as_widget()", None),
+                  (re.compile(r"\.as_hidden"), r".as_hidden()", None),
+                  
+                  (re.compile(r"\.get_([0-9_\w]+)_url"), r".get_\1_url()", None),
+                  (re.compile(r"\.url"), r".url()", re.compile(r"(form|calendar).url")),
+                  (re.compile(r"\.get_([0-9_\w]+)_display"), r".get_\1_display()", None),
+                  (re.compile(r"loop\.counter"), r"loop.index", None),
+                  (re.compile(r"loop\.revcounter"), r"loop.revindex", None),
+                  (re.compile(r"request\.GET\.([0-9_\w]+)"), r"request.GET.get('\1', '')", None),
+                  (re.compile(r"request\.get_host"), r"request.get_host()", None),
+                  
+                  (re.compile(r"\.all(?!_)"), r".all()", None),
+                  (re.compile(r"\.all\.0"), r".all()[0]", None),
+                  (re.compile(r"\.([0-9])($|\s+)"), r"[\1]\2", None),
+                  (re.compile(r"\.items"), r".items()", None),
+        )
+        writer = Writer(var_re=var_re)
+        
+    For details about the writing process have a look at the module code.
+
+    :copyright: (c) 2009 by the Jinja Team.
+    :license: BSD.
+"""
+import re
+import os
+import sys
+from jinja2.defaults import *
+from django.conf import settings
+from django.template import defaulttags as core_tags, loader, TextNode, \
+     FilterExpression, libraries, Variable, loader_tags, TOKEN_TEXT, \
+     TOKEN_VAR
+from django.template.debug import DebugVariableNode as VariableNode
+from django.templatetags import i18n as i18n_tags
+from StringIO import StringIO
+
+
+_node_handlers = {}
+_resolved_filters = {}
+_newline_re = re.compile(r'(?:\r\n|\r|\n)')
+
+
+# Django stores an itertools object on the cycle node.  Not only is this
+# thread unsafe but also a problem for the converter which needs the raw
+# string values passed to the constructor to create a jinja loop.cycle()
+# call from it.
+_old_cycle_init = core_tags.CycleNode.__init__
+def _fixed_cycle_init(self, cyclevars, variable_name=None):
+    self.raw_cycle_vars = map(Variable, cyclevars)
+    _old_cycle_init(self, cyclevars, variable_name)
+core_tags.CycleNode.__init__ = _fixed_cycle_init
+
+
+def node(cls):
+    def proxy(f):
+        _node_handlers[cls] = f
+        return f
+    return proxy
+
+
+def convert_templates(output_dir, extensions=('.html', '.txt'), writer=None,
+                      callback=None):
+    """Iterates over all templates in the template dirs configured and
+    translates them and writes the new templates into the output directory.
+    """
+    if writer is None:
+        writer = Writer()
+
+    def filter_templates(files):
+        for filename in files:
+            ifilename = filename.lower()
+            for extension in extensions:
+                if ifilename.endswith(extension):
+                    yield filename
+
+    def translate(f, loadname):
+        template = loader.get_template(loadname)
+        original = writer.stream
+        writer.stream = f
+        writer.body(template.nodelist)
+        writer.stream = original
+
+    if callback is None:
+        def callback(template):
+            print template
+
+    for directory in settings.TEMPLATE_DIRS:
+        for dirname, _, files in os.walk(directory):
+            dirname = dirname[len(directory) + 1:]
+            for filename in filter_templates(files):
+                source = os.path.normpath(os.path.join(dirname, filename))
+                target = os.path.join(output_dir, dirname, filename)
+                basetarget = os.path.dirname(target)
+                if not os.path.exists(basetarget):
+                    os.makedirs(basetarget)
+                callback(source)
+                f = file(target, 'w')
+                try:
+                    translate(f, source)
+                finally:
+                    f.close()
+
+
+class Writer(object):
+    """The core writer class."""
+
+    def __init__(self, stream=None, error_stream=None,
+                 block_start_string=BLOCK_START_STRING,
+                 block_end_string=BLOCK_END_STRING,
+                 variable_start_string=VARIABLE_START_STRING,
+                 variable_end_string=VARIABLE_END_STRING,
+                 comment_start_string=COMMENT_START_STRING,
+                 comment_end_string=COMMENT_END_STRING,
+                 initial_autoescape=True,
+                 use_jinja_autoescape=False,
+                 custom_node_handlers=None,
+                 var_re=[],
+                 env=None):
+        if stream is None:
+            stream = sys.stdout
+        if error_stream is None:
+            error_stream = sys.stderr
+        self.stream = stream
+        self.error_stream = error_stream
+        self.block_start_string = block_start_string
+        self.block_end_string = block_end_string
+        self.variable_start_string = variable_start_string
+        self.variable_end_string = variable_end_string
+        self.comment_start_string = comment_start_string
+        self.comment_end_string = comment_end_string
+        self.autoescape = initial_autoescape
+        self.spaceless = False
+        self.use_jinja_autoescape = use_jinja_autoescape
+        self.node_handlers = dict(_node_handlers,
+                                  **(custom_node_handlers or {}))
+        self._loop_depth = 0
+        self._filters_warned = set()
+        self.var_re = var_re
+        self.env = env
+
+    def enter_loop(self):
+        """Increments the loop depth so that write functions know if they
+        are in a loop.
+        """
+        self._loop_depth += 1
+
+    def leave_loop(self):
+        """Reverse of enter_loop."""
+        self._loop_depth -= 1
+
+    @property
+    def in_loop(self):
+        """True if we are in a loop."""
+        return self._loop_depth > 0
+
+    def write(self, s):
+        """Writes stuff to the stream."""
+        self.stream.write(s.encode(settings.FILE_CHARSET))
+
+    def print_expr(self, expr):
+        """Open a variable tag, write to the string to the stream and close."""
+        self.start_variable()
+        self.write(expr)
+        self.end_variable()
+
+    def _post_open(self):
+        if self.spaceless:
+            self.write('- ')
+        else:
+            self.write(' ')
+
+    def _pre_close(self):
+        if self.spaceless:
+            self.write(' -')
+        else:
+            self.write(' ')
+
+    def start_variable(self):
+        """Start a variable."""
+        self.write(self.variable_start_string)
+        self._post_open()
+
+    def end_variable(self, always_safe=False):
+        """End a variable."""
+        if not always_safe and self.autoescape and \
+           not self.use_jinja_autoescape:
+            self.write('|e')
+        self._pre_close()
+        self.write(self.variable_end_string)
+
+    def start_block(self):
+        """Starts a block."""
+        self.write(self.block_start_string)
+        self._post_open()
+
+    def end_block(self):
+        """Ends a block."""
+        self._pre_close()
+        self.write(self.block_end_string)
+
+    def tag(self, name):
+        """Like `print_expr` just for blocks."""
+        self.start_block()
+        self.write(name)
+        self.end_block()
+
+    def variable(self, name):
+        """Prints a variable.  This performs variable name transformation."""
+        self.write(self.translate_variable_name(name))
+
+    def literal(self, value):
+        """Writes a value as literal."""
+        value = repr(value)
+        if value[:2] in ('u"', "u'"):
+            value = value[1:]
+        self.write(value)
+
+    def filters(self, filters, is_block=False):
+        """Dumps a list of filters."""
+        want_pipe = not is_block
+        for filter, args in filters:
+            name = self.get_filter_name(filter)
+            if name is None:
+                self.warn('Could not find filter %s' % name)
+                continue
+            if name not in DEFAULT_FILTERS and \
+               name not in self._filters_warned:
+                self._filters_warned.add(name)
+                self.warn('Filter %s probably doesn\'t exist in Jinja' %
+                            name)
+            if not want_pipe:
+                want_pipe = True
+            else:
+                self.write('|')
+            self.write(name)
+            if args:
+                self.write('(')
+                for idx, (is_var, value) in enumerate(args):
+                    if idx:
+                        self.write(', ')
+                    if is_var:
+                        self.node(value)
+                    else:
+                        self.literal(value)
+                self.write(')')
+
+    def get_location(self, origin, position):
+        """Returns the location for an origin and position tuple as name
+        and lineno.
+        """
+        if hasattr(origin, 'source'):
+            source = origin.source
+            name = '<unknown source>'
+        else:
+            source = origin.loader(origin.loadname, origin.dirs)[0]
+            name = origin.loadname
+        lineno = len(_newline_re.findall(source[:position[0]])) + 1
+        return name, lineno
+
+    def warn(self, message, node=None):
+        """Prints a warning to the error stream."""
+        if node is not None and hasattr(node, 'source'):
+            filename, lineno = self.get_location(*node.source)
+            message = '[%s:%d] %s' % (filename, lineno, message)
+        print >> self.error_stream, message
+
+    def translate_variable_name(self, var):
+        """Performs variable name translation."""
+        if self.in_loop and var == 'forloop' or var.startswith('forloop.'):
+            var = var[3:]
+        
+        for reg, rep, unless in self.var_re:
+            no_unless = unless and unless.search(var) or True
+            if reg.search(var) and no_unless:
+                var = reg.sub(rep, var)
+                break
+        return var
+
+    def get_filter_name(self, filter):
+        """Returns the filter name for a filter function or `None` if there
+        is no such filter.
+        """
+        if filter not in _resolved_filters:
+            for library in libraries.values():
+                for key, value in library.filters.iteritems():
+                    _resolved_filters[value] = key
+        return _resolved_filters.get(filter, None)
+
+    def node(self, node):
+        """Invokes the node handler for a node."""
+        for cls, handler in self.node_handlers.iteritems():
+            if type(node) is cls or type(node).__name__ == cls:
+                handler(self, node)
+                break
+        else:
+            self.warn('Untranslatable node %s.%s found' % (
+                node.__module__,
+                node.__class__.__name__
+            ), node)
+
+    def body(self, nodes):
+        """Calls node() for every node in the iterable passed."""
+        for node in nodes:
+            self.node(node)
+
+
+@node(TextNode)
+def text_node(writer, node):
+    writer.write(node.s)
+
+
+@node(Variable)
+def variable(writer, node):
+    if node.translate:
+        writer.warn('i18n system used, make sure to install translations', node)
+        writer.write('_(')
+    if node.literal is not None:
+        writer.literal(node.literal)
+    else:
+        writer.variable(node.var)
+    if node.translate:
+        writer.write(')')
+
+
+@node(VariableNode)
+def variable_node(writer, node):
+    writer.start_variable()
+    if node.filter_expression.var.var == 'block.super' \
+       and not node.filter_expression.filters:
+        writer.write('super()')
+    else:
+        writer.node(node.filter_expression)
+    writer.end_variable()
+
+
+@node(FilterExpression)
+def filter_expression(writer, node):
+    writer.node(node.var)
+    writer.filters(node.filters)
+
+
+@node(core_tags.CommentNode)
+def comment_tag(writer, node):
+    pass
+
+
+@node(core_tags.DebugNode)
+def comment_tag(writer, node):
+    writer.warn('Debug tag detected.  Make sure to add a global function '
+                'called debug to the namespace.', node=node)
+    writer.print_expr('debug()')
+
+
+@node(core_tags.ForNode)
+def for_loop(writer, node):
+    writer.start_block()
+    writer.write('for ')
+    for idx, var in enumerate(node.loopvars):
+        if idx:
+            writer.write(', ')
+        writer.variable(var)
+    writer.write(' in ')
+    if node.is_reversed:
+        writer.write('(')
+    writer.node(node.sequence)
+    if node.is_reversed:
+        writer.write(')|reverse')
+    writer.end_block()
+    writer.enter_loop()
+    writer.body(node.nodelist_loop)
+    writer.leave_loop()
+    writer.tag('endfor')
+
+
+@node(core_tags.IfNode)
+def if_condition(writer, node):
+    writer.start_block()
+    writer.write('if ')
+    join_with = 'and'
+    if node.link_type == core_tags.IfNode.LinkTypes.or_:
+        join_with = 'or'
+    
+    for idx, (ifnot, expr) in enumerate(node.bool_exprs):
+        if idx:
+            writer.write(' %s ' % join_with)
+        if ifnot:
+            writer.write('not ')
+        writer.node(expr)
+    writer.end_block()
+    writer.body(node.nodelist_true)
+    if node.nodelist_false:
+        writer.tag('else')
+        writer.body(node.nodelist_false)
+    writer.tag('endif')
+
+
+@node(core_tags.IfEqualNode)
+def if_equal(writer, node):
+    writer.start_block()
+    writer.write('if ')
+    writer.node(node.var1)
+    if node.negate:
+        writer.write(' != ')
+    else:
+        writer.write(' == ')
+    writer.node(node.var2)
+    writer.end_block()
+    writer.body(node.nodelist_true)
+    if node.nodelist_false:
+        writer.tag('else')
+        writer.body(node.nodelist_false)
+    writer.tag('endif')
+
+
+@node(loader_tags.BlockNode)
+def block(writer, node):
+    writer.tag('block ' + node.name.replace('-', '_').rstrip('_'))
+    node = node
+    while node.parent is not None:
+        node = node.parent
+    writer.body(node.nodelist)
+    writer.tag('endblock')
+
+
+@node(loader_tags.ExtendsNode)
+def extends(writer, node):
+    writer.start_block()
+    writer.write('extends ')
+    if node.parent_name_expr:
+        writer.node(node.parent_name_expr)
+    else:
+        writer.literal(node.parent_name)
+    writer.end_block()
+    writer.body(node.nodelist)
+
+
+@node(loader_tags.ConstantIncludeNode)
+@node(loader_tags.IncludeNode)
+def include(writer, node):
+    writer.start_block()
+    writer.write('include ')
+    if hasattr(node, 'template'):
+        writer.literal(node.template.name)
+    else:
+        writer.node(node.template_name)
+    writer.end_block()
+
+
+@node(core_tags.CycleNode)
+def cycle(writer, node):
+    if not writer.in_loop:
+        writer.warn('Untranslatable free cycle (cycle outside loop)', node=node)
+        return
+    if node.variable_name is not None:
+        writer.start_block()
+        writer.write('set %s = ' % node.variable_name)
+    else:
+        writer.start_variable()
+    writer.write('loop.cycle(')
+    for idx, var in enumerate(node.raw_cycle_vars):
+        if idx:
+            writer.write(', ')
+        writer.node(var)
+    writer.write(')')
+    if node.variable_name is not None:
+        writer.end_block()
+    else:
+        writer.end_variable()
+
+
+@node(core_tags.FilterNode)
+def filter(writer, node):
+    writer.start_block()
+    writer.write('filter ')
+    writer.filters(node.filter_expr.filters, True)
+    writer.end_block()
+    writer.body(node.nodelist)
+    writer.tag('endfilter')
+
+
+@node(core_tags.AutoEscapeControlNode)
+def autoescape_control(writer, node):
+    original = writer.autoescape
+    writer.autoescape = node.setting
+    writer.body(node.nodelist)
+    writer.autoescape = original
+
+
+@node(core_tags.SpacelessNode)
+def spaceless(writer, node):
+    original = writer.spaceless
+    writer.spaceless = True
+    writer.warn('entering spaceless mode with different semantics', node)
+    # do the initial stripping
+    nodelist = list(node.nodelist)
+    if nodelist:
+        if isinstance(nodelist[0], TextNode):
+            nodelist[0] = TextNode(nodelist[0].s.lstrip())
+        if isinstance(nodelist[-1], TextNode):
+            nodelist[-1] = TextNode(nodelist[-1].s.rstrip())
+    writer.body(nodelist)
+    writer.spaceless = original
+
+
+@node(core_tags.TemplateTagNode)
+def template_tag(writer, node):
+    tag = {
+        'openblock':            writer.block_start_string,
+        'closeblock':           writer.block_end_string,
+        'openvariable':         writer.variable_start_string,
+        'closevariable':        writer.variable_end_string,
+        'opencomment':          writer.comment_start_string,
+        'closecomment':         writer.comment_end_string,
+        'openbrace':            '{',
+        'closebrace':           '}'
+    }.get(node.tagtype)
+    if tag:
+        writer.start_variable()
+        writer.literal(tag)
+        writer.end_variable()
+
+
+@node(core_tags.URLNode)
+def url_tag(writer, node):
+    writer.warn('url node used.  make sure to provide a proper url() '
+                'function', node)
+    if node.asvar:
+        writer.start_block()
+        writer.write('set %s = ' % node.asvar)
+    else:
+        writer.start_variable()
+    autoescape = writer.autoescape
+    writer.write('url(')
+    writer.literal(node.view_name)
+    for arg in node.args:
+        writer.write(', ')
+        writer.node(arg)
+    for key, arg in node.kwargs.items():
+        writer.write(', %s=' % key)
+        writer.node(arg)
+    writer.write(')')
+    if node.asvar:
+        writer.end_block()
+    else:
+        writer.end_variable()
+
+
+@node(core_tags.WidthRatioNode)
+def width_ratio(writer, node):
+    writer.warn('widthratio expanded into formula.  You may want to provide '
+                'a helper function for this calculation', node)
+    writer.start_variable()
+    writer.write('(')
+    writer.node(node.val_expr)
+    writer.write(' / ')
+    writer.node(node.max_expr)
+    writer.write(' * ')
+    writer.write(str(int(node.max_width)))
+    writer.write(')|round|int')
+    writer.end_variable(always_safe=True)
+
+
+@node(core_tags.WithNode)
+def with_block(writer, node):
+    writer.warn('with block expanded into set statement.  This could cause '
+                'variables following that block to be overriden.', node)
+    writer.start_block()
+    writer.write('set %s = ' % node.name)
+    writer.node(node.var)
+    writer.end_block()
+    writer.body(node.nodelist)
+
+
+@node(core_tags.RegroupNode)
+def regroup(writer, node):
+    if node.expression.var.literal:
+        writer.warn('literal in groupby filter used.   Behavior in that '
+                    'situation is undefined and translation is skipped.', node)
+        return
+    elif node.expression.filters:
+        writer.warn('filters in groupby filter used.   Behavior in that '
+                    'situation is undefined which is most likely a bug '
+                    'in your code.  Filters were ignored.', node)
+    writer.start_block()
+    writer.write('set %s = ' % node.var_name)
+    writer.node(node.target)
+    writer.write('|groupby(')
+    writer.literal(node.expression.var.var)
+    writer.write(')')
+    writer.end_block()
+
+
+@node(core_tags.LoadNode)
+def warn_load(writer, node):
+    writer.warn('load statement used which was ignored on conversion', node)
+
+
+@node(i18n_tags.GetAvailableLanguagesNode)
+def get_available_languages(writer, node):
+    writer.warn('make sure to provide a get_available_languages function', node)
+    writer.tag('set %s = get_available_languages()' %
+               writer.translate_variable_name(node.variable))
+
+
+@node(i18n_tags.GetCurrentLanguageNode)
+def get_current_language(writer, node):
+    writer.warn('make sure to provide a get_current_language function', node)
+    writer.tag('set %s = get_current_language()' %
+               writer.translate_variable_name(node.variable))
+
+
+@node(i18n_tags.GetCurrentLanguageBidiNode)
+def get_current_language_bidi(writer, node):
+    writer.warn('make sure to provide a get_current_language_bidi function', node)
+    writer.tag('set %s = get_current_language_bidi()' %
+               writer.translate_variable_name(node.variable))
+
+
+@node(i18n_tags.TranslateNode)
+def simple_gettext(writer, node):
+    writer.warn('i18n system used, make sure to install translations', node)
+    writer.start_variable()
+    writer.write('_(')
+    writer.node(node.value)
+    writer.write(')')
+    writer.end_variable()
+
+
+@node(i18n_tags.BlockTranslateNode)
+def translate_block(writer, node):
+    first_var = []
+    variables = set()
+
+    def touch_var(name):
+        variables.add(name)
+        if not first_var:
+            first_var.append(name)
+
+    def dump_token_list(tokens):
+        for token in tokens:
+            if token.token_type == TOKEN_TEXT:
+                writer.write(token.contents)
+            elif token.token_type == TOKEN_VAR:
+                writer.print_expr(token.contents)
+                touch_var(token.contents)
+
+    writer.warn('i18n system used, make sure to install translations', node)
+    writer.start_block()
+    writer.write('trans')
+    idx = -1
+    for idx, (key, var) in enumerate(node.extra_context.items()):
+        if idx:
+            writer.write(',')
+        writer.write(' %s=' % key)
+        touch_var(key)
+        writer.node(var.filter_expression)
+
+    have_plural = False
+    plural_var = None
+    if node.plural and node.countervar and node.counter:
+        have_plural = True
+        plural_var = node.countervar
+        if plural_var not in variables:
+            if idx > -1:
+                writer.write(',')
+            touch_var(plural_var)
+            writer.write(' %s=' % plural_var)
+            writer.node(node.counter)
+
+    writer.end_block()
+    dump_token_list(node.singular)
+    if node.plural and node.countervar and node.counter:
+        writer.start_block()
+        writer.write('pluralize')
+        if node.countervar != first_var[0]:
+            writer.write(' ' + node.countervar)
+        writer.end_block()
+        dump_token_list(node.plural)
+    writer.tag('endtrans')
+
+@node("SimpleNode")
+def simple_tag(writer, node):
+    """Check if the simple tag exist as a filter in """
+    name = node.tag_name
+    if writer.env and \
+       name not in writer.env.filters and \
+       name not in writer._filters_warned:
+        writer._filters_warned.add(name)
+        writer.warn('Filter %s probably doesn\'t exist in Jinja' %
+                    name)
+        
+    if not node.vars_to_resolve:
+        # No argument, pass the request
+        writer.start_variable()
+        writer.write('request|')
+        writer.write(name)
+        writer.end_variable()
+        return 
+    
+    first_var =  node.vars_to_resolve[0]
+    args = node.vars_to_resolve[1:]
+    writer.start_variable()
+    
+    # Copied from Writer.filters()
+    writer.node(first_var)
+    
+    writer.write('|')
+    writer.write(name)
+    if args:
+        writer.write('(')
+        for idx, var in enumerate(args):
+            if idx:
+                writer.write(', ')
+            if var.var:
+                writer.node(var)
+            else:
+                writer.literal(var.literal)
+        writer.write(')')
+    writer.end_variable()   
+
+# get rid of node now, it shouldn't be used normally
+del node
diff --git a/lib/jinja2/ext/django2jinja/example.py b/lib/jinja2/ext/django2jinja/example.py
new file mode 100644
index 0000000..2d4ab9a
--- /dev/null
+++ b/lib/jinja2/ext/django2jinja/example.py
@@ -0,0 +1,7 @@
+from django.conf import settings
+settings.configure(TEMPLATE_DIRS=['templates'], TEMPLATE_DEBUG=True)
+
+from django2jinja import convert_templates, Writer
+
+writer = Writer(use_jinja_autoescape=True)
+convert_templates('converted', writer=writer)
diff --git a/lib/jinja2/ext/django2jinja/templates/index.html b/lib/jinja2/ext/django2jinja/templates/index.html
new file mode 100644
index 0000000..d0fbe38
--- /dev/null
+++ b/lib/jinja2/ext/django2jinja/templates/index.html
@@ -0,0 +1,58 @@
+{% extends "layout.html" %}
+{% load i18n %}
+{% block title %}Foo{% endblock %}
+{% block page-body %}
+  {{ block.super }}
+  Hello {{ name|cut:"d" }}!
+
+  {% for item in seq reversed %}
+    {% if forloop.index|divisibleby:2 %}
+      <li class="{% cycle 'a' 'b' %}">{{ item }}</li>
+    {% endif %}
+  {% endfor %}
+  {% ifequal foo bar %}
+    haha
+  {% else %}
+    hmm
+  {% endifequal %}
+  {% filter upper %}
+    {% include "subtemplate.html" %}
+    {% include foo %}
+  {% endfilter %}
+  {% spaceless %}
+    Hello World
+      {{ foo }}
+    Hmm
+  {% endspaceless %}
+  {% templatetag opencomment %}...{% templatetag closecomment %}
+  {% url foo a, b, c=d %}
+  {% url foo a, b, c=d as hmm %}
+
+  {% with object.value as value %}
+    <img src='bar.gif' height='10' width='{% widthratio value 200 100 %}'>
+  {% endwith %}
+
+  <pre>{% debug %}</pre>
+
+  {% blocktrans with book|title as book_t and author|title as author_t %}
+  This is {{ book_t }} by {{ author_t }}
+  {% endblocktrans %}
+
+  {% blocktrans count list|length as counter %}
+  There is only one {{ name }} object.
+  {% plural %}
+  There are {{ counter }} {{ name }} objects.
+  {% endblocktrans %}
+
+  {% blocktrans with name|escape as name count list|length as counter %}
+  There is only one {{ name }} object.
+  {% plural %}
+  There are {{ counter }} {{ name }} objects.
+  {% endblocktrans %}
+
+  {% blocktrans %}This string will have {{ value }} inside.{% endblocktrans %}
+
+  <p>{% trans "This is the title." %}</p>
+
+  {% regroup people by gender as grouped %}
+{% endblock %}
diff --git a/lib/jinja2/ext/django2jinja/templates/layout.html b/lib/jinja2/ext/django2jinja/templates/layout.html
new file mode 100644
index 0000000..3f21a12
--- /dev/null
+++ b/lib/jinja2/ext/django2jinja/templates/layout.html
@@ -0,0 +1,4 @@
+<title>{% block title %}{% endblock %}</title>
+<div class="body">
+  {% block page-body %}{% endblock %}
+</div>
diff --git a/lib/jinja2/ext/django2jinja/templates/subtemplate.html b/lib/jinja2/ext/django2jinja/templates/subtemplate.html
new file mode 100644
index 0000000..980a0d5
--- /dev/null
+++ b/lib/jinja2/ext/django2jinja/templates/subtemplate.html
@@ -0,0 +1 @@
+Hello World!
diff --git a/lib/jinja2/ext/djangojinja2.py b/lib/jinja2/ext/djangojinja2.py
new file mode 100644
index 0000000..d24d164
--- /dev/null
+++ b/lib/jinja2/ext/djangojinja2.py
@@ -0,0 +1,86 @@
+# -*- coding: utf-8 -*-
+"""
+    djangojinja2
+    ~~~~~~~~~~~~
+
+    Adds support for Jinja2 to Django.
+
+    Configuration variables:
+
+    ======================= =============================================
+    Key                     Description
+    ======================= =============================================
+    `JINJA2_TEMPLATE_DIRS`  List of template folders
+    `JINJA2_EXTENSIONS`     List of Jinja2 extensions to use
+    `JINJA2_CACHE_SIZE`     The size of the Jinja2 template cache.
+    ======================= =============================================
+
+    :copyright: (c) 2009 by the Jinja Team.
+    :license: BSD.
+"""
+from itertools import chain
+from django.conf import settings
+from django.http import HttpResponse
+from django.core.exceptions import ImproperlyConfigured
+from django.template.context import get_standard_processors
+from django.template import TemplateDoesNotExist
+from jinja2 import Environment, FileSystemLoader, TemplateNotFound
+from jinja2.defaults import DEFAULT_NAMESPACE
+
+
+# the environment is unconfigured until the first template is loaded.
+_jinja_env = None
+
+
+def get_env():
+    """Get the Jinja2 env and initialize it if necessary."""
+    global _jinja_env
+    if _jinja_env is None:
+        _jinja_env = create_env()
+    return _jinja_env
+
+
+def create_env():
+    """Create a new Jinja2 environment."""
+    searchpath = list(settings.JINJA2_TEMPLATE_DIRS)
+    return Environment(loader=FileSystemLoader(searchpath),
+                       auto_reload=settings.TEMPLATE_DEBUG,
+                       cache_size=getattr(settings, 'JINJA2_CACHE_SIZE', 50),
+                       extensions=getattr(settings, 'JINJA2_EXTENSIONS', ()))
+
+
+def get_template(template_name, globals=None):
+    """Load a template."""
+    try:
+        return get_env().get_template(template_name, globals=globals)
+    except TemplateNotFound, e:
+        raise TemplateDoesNotExist(str(e))
+
+
+def select_template(templates, globals=None):
+    """Try to load one of the given templates."""
+    env = get_env()
+    for template in templates:
+        try:
+            return env.get_template(template, globals=globals)
+        except TemplateNotFound:
+            continue
+    raise TemplateDoesNotExist(', '.join(templates))
+
+
+def render_to_string(template_name, context=None, request=None,
+                     processors=None):
+    """Render a template into a string."""
+    context = dict(context or {})
+    if request is not None:
+        context['request'] = request
+        for processor in chain(get_standard_processors(), processors or ()):
+            context.update(processor(request))
+    return get_template(template_name).render(context)
+
+
+def render_to_response(template_name, context=None, request=None,
+                       processors=None, mimetype=None):
+    """Render a template into a response object."""
+    return HttpResponse(render_to_string(template_name, context, request,
+                                         processors), mimetype=mimetype)
diff --git a/lib/jinja2/ext/inlinegettext.py b/lib/jinja2/ext/inlinegettext.py
new file mode 100644
index 0000000..cf4ed5e
--- /dev/null
+++ b/lib/jinja2/ext/inlinegettext.py
@@ -0,0 +1,78 @@
+# -*- coding: utf-8 -*-
+"""
+    Inline Gettext
+    ~~~~~~~~~~~~~~
+
+    An example extension for Jinja2 that supports inline gettext calls.
+    Requires the i18n extension to be loaded.
+
+    :copyright: (c) 2009 by the Jinja Team.
+    :license: BSD.
+"""
+import re
+from jinja2.ext import Extension
+from jinja2.lexer import Token, count_newlines
+from jinja2.exceptions import TemplateSyntaxError
+
+
+_outside_re = re.compile(r'\\?(gettext|_)\(')
+_inside_re = re.compile(r'\\?[()]')
+
+
+class InlineGettext(Extension):
+    """This extension implements support for inline gettext blocks::
+
+        <h1>_(Welcome)</h1>
+        <p>_(This is a paragraph)</p>
+
+    Requires the i18n extension to be loaded and configured.
+    """
+
+    def filter_stream(self, stream):
+        paren_stack = 0
+
+        for token in stream:
+            if token.type is not 'data':
+                yield token
+                continue
+
+            pos = 0
+            lineno = token.lineno
+
+            while 1:
+                if not paren_stack:
+                    match = _outside_re.search(token.value, pos)
+                else:
+                    match = _inside_re.search(token.value, pos)
+                if match is None:
+                    break
+                new_pos = match.start()
+                if new_pos > pos:
+                    preval = token.value[pos:new_pos]
+                    yield Token(lineno, 'data', preval)
+                    lineno += count_newlines(preval)
+                gtok = match.group()
+                if gtok[0] == '\\':
+                    yield Token(lineno, 'data', gtok[1:])
+                elif not paren_stack:
+                    yield Token(lineno, 'block_begin', None)
+                    yield Token(lineno, 'name', 'trans')
+                    yield Token(lineno, 'block_end', None)
+                    paren_stack = 1
+                else:
+                    if gtok == '(' or paren_stack > 1:
+                        yield Token(lineno, 'data', gtok)
+                    paren_stack += gtok == ')' and -1 or 1
+                    if not paren_stack:
+                        yield Token(lineno, 'block_begin', None)
+                        yield Token(lineno, 'name', 'endtrans')
+                        yield Token(lineno, 'block_end', None)
+                pos = match.end()
+
+            if pos < len(token.value):
+                yield Token(lineno, 'data', token.value[pos:])
+
+        if paren_stack:
+            raise TemplateSyntaxError('unclosed gettext expression',
+                                      token.lineno, stream.name,
+                                      stream.filename)
diff --git a/lib/jinja2/ext/jinja.el b/lib/jinja2/ext/jinja.el
new file mode 100644
index 0000000..4cf0c72
--- /dev/null
+++ b/lib/jinja2/ext/jinja.el
@@ -0,0 +1,128 @@
+;;; jinja.el --- Jinja mode highlighting
+;;
+;; Author: Georg Brandl
+;; Copyright: (c) 2009 by the Jinja Team
+;; Last modified: 2008-05-22 23:04 by gbr
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Commentary:
+;;
+;; Mostly ripped off django-mode by Lennart Borgman.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; see the file COPYING.  If not, write to
+;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
+;; Floor, Boston, MA 02110-1301, USA.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Code:
+
+(defconst jinja-font-lock-keywords
+  (list
+;   (cons (rx "{% comment %}" (submatch (0+ anything))
+;             "{% endcomment %}") (list 1 font-lock-comment-face))
+   '("{# ?\\(.*?\\) ?#}" . (1 font-lock-comment-face))
+   '("{%-?\\|-?%}\\|{{\\|}}" . font-lock-preprocessor-face)
+   '("{#\\|#}" . font-lock-comment-delimiter-face)
+   ;; first word in a block is a command
+   '("{%-?[ \t\n]*\\([a-zA-Z_]+\\)" . (1 font-lock-keyword-face))
+   ;; variables
+   '("\\({{ ?\\)\\([^|]*?\\)\\(|.*?\\)? ?}}" . (1 font-lock-variable-name-face))
+   ;; keywords and builtins
+   (cons (rx word-start
+             (or "in" "as" "recursive" "not" "and" "or" "if" "else"
+                 "import" "with" "without" "context")
+             word-end)
+         font-lock-keyword-face)
+   (cons (rx word-start
+             (or "true" "false" "none" "loop" "self" "super")
+             word-end)
+         font-lock-builtin-face)
+   ;; tests
+   '("\\(is\\)[ \t]*\\(not\\)[ \t]*\\([a-zA-Z_]+\\)"
+     (1 font-lock-keyword-face) (2 font-lock-keyword-face)
+     (3 font-lock-function-name-face))
+   ;; builtin filters
+   (cons (rx
+          "|" (* space)
+          (submatch
+           (or "abs" "batch" "capitalize" "capture" "center" "count" "default"
+               "dformat" "dictsort" "e" "escape" "filesizeformat" "first"
+               "float" "format" "getattribute" "getitem" "groupby" "indent"
+               "int" "join" "jsonencode" "last" "length" "lower" "markdown"
+               "pprint" "random" "replace" "reverse" "round" "rst" "slice"
+               "sort" "string" "striptags" "sum" "textile" "title" "trim"
+               "truncate" "upper" "urlencode" "urlize" "wordcount" "wordwrap"
+               "xmlattr")))
+         (list 1 font-lock-builtin-face))
+   )
+   "Minimal highlighting expressions for Jinja mode")
+
+(define-derived-mode jinja-mode nil "Jinja"
+  "Simple Jinja mode for use with `mumamo-mode'.
+This mode only provides syntax highlighting."
+  ;;(set (make-local-variable 'comment-start) "{#")
+  ;;(set (make-local-variable 'comment-end)   "#}")
+  (setq font-lock-defaults '(jinja-font-lock-keywords)))
+
+;; mumamo stuff
+(when (require 'mumamo nil t)
+
+  (defun mumamo-chunk-jinja3 (pos max)
+    "Find {# ... #}"
+    (mumamo-quick-chunk-forward pos max "{#" "#}" 'borders 'jinja-mode))
+
+  (defun mumamo-chunk-jinja2 (pos max)
+    "Find {{ ... }}"
+    (mumamo-quick-chunk-forward pos max "{{" "}}" 'borders 'jinja-mode))
+
+  (defun mumamo-chunk-jinja (pos max)
+    "Find {% ... %}"
+    (mumamo-quick-chunk-forward pos max "{%" "%}" 'borders 'jinja-mode))
+
+;;;###autoload
+  (define-mumamo-multi-major-mode jinja-html-mumamo
+    "Turn on multiple major modes for Jinja with main mode `html-mode'.
+This also covers inlined style and javascript."
+    ("Jinja HTML Family" html-mode
+     (mumamo-chunk-jinja
+      mumamo-chunk-jinja2
+      mumamo-chunk-jinja3
+      mumamo-chunk-inlined-style
+      mumamo-chunk-inlined-script
+      mumamo-chunk-style=
+      mumamo-chunk-onjs=
+      )))
+
+;;;###autoload
+  (define-mumamo-multi-major-mode jinja-nxhtml-mumamo
+    "Turn on multiple major modes for Jinja with main mode `nxhtml-mode'.
+This also covers inlined style and javascript."
+    ("Jinja nXhtml Family" nxhtml-mode
+     (mumamo-chunk-jinja
+      mumamo-chunk-jinja2
+      mumamo-chunk-jinja3
+      mumamo-chunk-inlined-style
+      mumamo-chunk-inlined-script
+      mumamo-chunk-style=
+      mumamo-chunk-onjs=
+      )))
+  )
+
+(provide 'jinja)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; jinja.el ends here
diff --git a/lib/jinja2/jinja2/__init__.py b/lib/jinja2/jinja2/__init__.py
new file mode 100644
index 0000000..0cf967d
--- /dev/null
+++ b/lib/jinja2/jinja2/__init__.py
@@ -0,0 +1,69 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2
+    ~~~~~~
+
+    Jinja2 is a template engine written in pure Python.  It provides a
+    Django inspired non-XML syntax but supports inline expressions and
+    an optional sandboxed environment.
+
+    Nutshell
+    --------
+
+    Here a small example of a Jinja2 template::
+
+        {% extends 'base.html' %}
+        {% block title %}Memberlist{% endblock %}
+        {% block content %}
+          <ul>
+          {% for user in users %}
+            <li><a href="{{ user.url }}">{{ user.username }}</a></li>
+          {% endfor %}
+          </ul>
+        {% endblock %}
+
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+__docformat__ = 'restructuredtext en'
+__version__ = '2.6'
+
+# high level interface
+from jinja2.environment import Environment, Template
+
+# loaders
+from jinja2.loaders import BaseLoader, FileSystemLoader, PackageLoader, \
+     DictLoader, FunctionLoader, PrefixLoader, ChoiceLoader, \
+     ModuleLoader
+
+# bytecode caches
+from jinja2.bccache import BytecodeCache, FileSystemBytecodeCache, \
+     MemcachedBytecodeCache
+
+# undefined types
+from jinja2.runtime import Undefined, DebugUndefined, StrictUndefined
+
+# exceptions
+from jinja2.exceptions import TemplateError, UndefinedError, \
+     TemplateNotFound, TemplatesNotFound, TemplateSyntaxError, \
+     TemplateAssertionError
+
+# decorators and public utilities
+from jinja2.filters import environmentfilter, contextfilter, \
+     evalcontextfilter
+from jinja2.utils import Markup, escape, clear_caches, \
+     environmentfunction, evalcontextfunction, contextfunction, \
+     is_undefined
+
+__all__ = [
+    'Environment', 'Template', 'BaseLoader', 'FileSystemLoader',
+    'PackageLoader', 'DictLoader', 'FunctionLoader', 'PrefixLoader',
+    'ChoiceLoader', 'BytecodeCache', 'FileSystemBytecodeCache',
+    'MemcachedBytecodeCache', 'Undefined', 'DebugUndefined',
+    'StrictUndefined', 'TemplateError', 'UndefinedError', 'TemplateNotFound',
+    'TemplatesNotFound', 'TemplateSyntaxError', 'TemplateAssertionError',
+    'ModuleLoader', 'environmentfilter', 'contextfilter', 'Markup', 'escape',
+    'environmentfunction', 'contextfunction', 'clear_caches', 'is_undefined',
+    'evalcontextfilter', 'evalcontextfunction'
+]
diff --git a/lib/jinja2/jinja2/_debugsupport.c b/lib/jinja2/jinja2/_debugsupport.c
new file mode 100644
index 0000000..e756d8e
--- /dev/null
+++ b/lib/jinja2/jinja2/_debugsupport.c
@@ -0,0 +1,78 @@
+/**
+ * jinja2._debugsupport
+ * ~~~~~~~~~~~~~~~~~~~~
+ *
+ * C implementation of `tb_set_next`.
+ *
+ * :copyright: (c) 2010 by the Jinja Team.
+ * :license: BSD.
+ */
+
+#include <Python.h>
+
+
+static PyObject*
+tb_set_next(PyObject *self, PyObject *args)
+{
+	PyTracebackObject *tb, *old;
+	PyObject *next;
+
+	if (!PyArg_ParseTuple(args, "O!O:tb_set_next", &PyTraceBack_Type, &tb, &next))
+		return NULL;
+	if (next == Py_None)
+		next = NULL;
+	else if (!PyTraceBack_Check(next)) {
+		PyErr_SetString(PyExc_TypeError,
+				"tb_set_next arg 2 must be traceback or None");
+		return NULL;
+	}
+	else
+		Py_INCREF(next);
+
+	old = tb->tb_next;
+	tb->tb_next = (PyTracebackObject*)next;
+	Py_XDECREF(old);
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyMethodDef module_methods[] = {
+	{"tb_set_next", (PyCFunction)tb_set_next, METH_VARARGS,
+	 "Set the tb_next member of a traceback object."},
+	{NULL, NULL, 0, NULL}		/* Sentinel */
+};
+
+
+#if PY_MAJOR_VERSION < 3
+
+#ifndef PyMODINIT_FUNC	/* declarations for DLL import/export */
+#define PyMODINIT_FUNC void
+#endif
+PyMODINIT_FUNC
+init_debugsupport(void)
+{
+	Py_InitModule3("jinja2._debugsupport", module_methods, "");
+}
+
+#else /* Python 3.x module initialization */
+
+static struct PyModuleDef module_definition = {
+        PyModuleDef_HEAD_INIT,
+	"jinja2._debugsupport",
+	NULL,
+	-1,
+	module_methods,
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+PyMODINIT_FUNC
+PyInit__debugsupport(void)
+{
+	return PyModule_Create(&module_definition);
+}
+
+#endif
diff --git a/lib/jinja2/jinja2/_markupsafe/__init__.py b/lib/jinja2/jinja2/_markupsafe/__init__.py
new file mode 100644
index 0000000..ec7bd57
--- /dev/null
+++ b/lib/jinja2/jinja2/_markupsafe/__init__.py
@@ -0,0 +1,225 @@
+# -*- coding: utf-8 -*-
+"""
+    markupsafe
+    ~~~~~~~~~~
+
+    Implements a Markup string.
+
+    :copyright: (c) 2010 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+import re
+from itertools import imap
+
+
+__all__ = ['Markup', 'soft_unicode', 'escape', 'escape_silent']
+
+
+_striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
+_entity_re = re.compile(r'&([^;]+);')
+
+
+class Markup(unicode):
+    r"""Marks a string as being safe for inclusion in HTML/XML output without
+    needing to be escaped.  This implements the `__html__` interface a couple
+    of frameworks and web applications use.  :class:`Markup` is a direct
+    subclass of `unicode` and provides all the methods of `unicode` just that
+    it escapes arguments passed and always returns `Markup`.
+
+    The `escape` function returns markup objects so that double escaping can't
+    happen.
+
+    The constructor of the :class:`Markup` class can be used for three
+    different things:  When passed an unicode object it's assumed to be safe,
+    when passed an object with an HTML representation (has an `__html__`
+    method) that representation is used, otherwise the object passed is
+    converted into a unicode string and then assumed to be safe:
+
+    >>> Markup("Hello <em>World</em>!")
+    Markup(u'Hello <em>World</em>!')
+    >>> class Foo(object):
+    ...  def __html__(self):
+    ...   return '<a href="#">foo</a>'
+    ... 
+    >>> Markup(Foo())
+    Markup(u'<a href="#">foo</a>')
+
+    If you want object passed being always treated as unsafe you can use the
+    :meth:`escape` classmethod to create a :class:`Markup` object:
+
+    >>> Markup.escape("Hello <em>World</em>!")
+    Markup(u'Hello &lt;em&gt;World&lt;/em&gt;!')
+
+    Operations on a markup string are markup aware which means that all
+    arguments are passed through the :func:`escape` function:
+
+    >>> em = Markup("<em>%s</em>")
+    >>> em % "foo & bar"
+    Markup(u'<em>foo &amp; bar</em>')
+    >>> strong = Markup("<strong>%(text)s</strong>")
+    >>> strong % {'text': '<blink>hacker here</blink>'}
+    Markup(u'<strong>&lt;blink&gt;hacker here&lt;/blink&gt;</strong>')
+    >>> Markup("<em>Hello</em> ") + "<foo>"
+    Markup(u'<em>Hello</em> &lt;foo&gt;')
+    """
+    __slots__ = ()
+
+    def __new__(cls, base=u'', encoding=None, errors='strict'):
+        if hasattr(base, '__html__'):
+            base = base.__html__()
+        if encoding is None:
+            return unicode.__new__(cls, base)
+        return unicode.__new__(cls, base, encoding, errors)
+
+    def __html__(self):
+        return self
+
+    def __add__(self, other):
+        if hasattr(other, '__html__') or isinstance(other, basestring):
+            return self.__class__(unicode(self) + unicode(escape(other)))
+        return NotImplemented
+
+    def __radd__(self, other):
+        if hasattr(other, '__html__') or isinstance(other, basestring):
+            return self.__class__(unicode(escape(other)) + unicode(self))
+        return NotImplemented
+
+    def __mul__(self, num):
+        if isinstance(num, (int, long)):
+            return self.__class__(unicode.__mul__(self, num))
+        return NotImplemented
+    __rmul__ = __mul__
+
+    def __mod__(self, arg):
+        if isinstance(arg, tuple):
+            arg = tuple(imap(_MarkupEscapeHelper, arg))
+        else:
+            arg = _MarkupEscapeHelper(arg)
+        return self.__class__(unicode.__mod__(self, arg))
+
+    def __repr__(self):
+        return '%s(%s)' % (
+            self.__class__.__name__,
+            unicode.__repr__(self)
+        )
+
+    def join(self, seq):
+        return self.__class__(unicode.join(self, imap(escape, seq)))
+    join.__doc__ = unicode.join.__doc__
+
+    def split(self, *args, **kwargs):
+        return map(self.__class__, unicode.split(self, *args, **kwargs))
+    split.__doc__ = unicode.split.__doc__
+
+    def rsplit(self, *args, **kwargs):
+        return map(self.__class__, unicode.rsplit(self, *args, **kwargs))
+    rsplit.__doc__ = unicode.rsplit.__doc__
+
+    def splitlines(self, *args, **kwargs):
+        return map(self.__class__, unicode.splitlines(self, *args, **kwargs))
+    splitlines.__doc__ = unicode.splitlines.__doc__
+
+    def unescape(self):
+        r"""Unescape markup again into an unicode string.  This also resolves
+        known HTML4 and XHTML entities:
+
+        >>> Markup("Main &raquo; <em>About</em>").unescape()
+        u'Main \xbb <em>About</em>'
+        """
+        from jinja2._markupsafe._constants import HTML_ENTITIES
+        def handle_match(m):
+            name = m.group(1)
+            if name in HTML_ENTITIES:
+                return unichr(HTML_ENTITIES[name])
+            try:
+                if name[:2] in ('#x', '#X'):
+                    return unichr(int(name[2:], 16))
+                elif name.startswith('#'):
+                    return unichr(int(name[1:]))
+            except ValueError:
+                pass
+            return u''
+        return _entity_re.sub(handle_match, unicode(self))
+
+    def striptags(self):
+        r"""Unescape markup into an unicode string and strip all tags.  This
+        also resolves known HTML4 and XHTML entities.  Whitespace is
+        normalized to one:
+
+        >>> Markup("Main &raquo;  <em>About</em>").striptags()
+        u'Main \xbb About'
+        """
+        stripped = u' '.join(_striptags_re.sub('', self).split())
+        return Markup(stripped).unescape()
+
+    @classmethod
+    def escape(cls, s):
+        """Escape the string.  Works like :func:`escape` with the difference
+        that for subclasses of :class:`Markup` this function would return the
+        correct subclass.
+        """
+        rv = escape(s)
+        if rv.__class__ is not cls:
+            return cls(rv)
+        return rv
+
+    def make_wrapper(name):
+        orig = getattr(unicode, name)
+        def func(self, *args, **kwargs):
+            args = _escape_argspec(list(args), enumerate(args))
+            _escape_argspec(kwargs, kwargs.iteritems())
+            return self.__class__(orig(self, *args, **kwargs))
+        func.__name__ = orig.__name__
+        func.__doc__ = orig.__doc__
+        return func
+
+    for method in '__getitem__', 'capitalize', \
+                  'title', 'lower', 'upper', 'replace', 'ljust', \
+                  'rjust', 'lstrip', 'rstrip', 'center', 'strip', \
+                  'translate', 'expandtabs', 'swapcase', 'zfill':
+        locals()[method] = make_wrapper(method)
+
+    # new in python 2.5
+    if hasattr(unicode, 'partition'):
+        partition = make_wrapper('partition'),
+        rpartition = make_wrapper('rpartition')
+
+    # new in python 2.6
+    if hasattr(unicode, 'format'):
+        format = make_wrapper('format')
+
+    # not in python 3
+    if hasattr(unicode, '__getslice__'):
+        __getslice__ = make_wrapper('__getslice__')
+
+    del method, make_wrapper
+
+
+def _escape_argspec(obj, iterable):
+    """Helper for various string-wrapped functions."""
+    for key, value in iterable:
+        if hasattr(value, '__html__') or isinstance(value, basestring):
+            obj[key] = escape(value)
+    return obj
+
+
+class _MarkupEscapeHelper(object):
+    """Helper for Markup.__mod__"""
+
+    def __init__(self, obj):
+        self.obj = obj
+
+    __getitem__ = lambda s, x: _MarkupEscapeHelper(s.obj[x])
+    __str__ = lambda s: str(escape(s.obj))
+    __unicode__ = lambda s: unicode(escape(s.obj))
+    __repr__ = lambda s: str(escape(repr(s.obj)))
+    __int__ = lambda s: int(s.obj)
+    __float__ = lambda s: float(s.obj)
+
+
+# we have to import it down here as the speedups and native
+# modules imports the markup type which is define above.
+try:
+    from jinja2._markupsafe._speedups import escape, escape_silent, soft_unicode
+except ImportError:
+    from jinja2._markupsafe._native import escape, escape_silent, soft_unicode
diff --git a/lib/jinja2/jinja2/_markupsafe/_bundle.py b/lib/jinja2/jinja2/_markupsafe/_bundle.py
new file mode 100644
index 0000000..e694faf
--- /dev/null
+++ b/lib/jinja2/jinja2/_markupsafe/_bundle.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2._markupsafe._bundle
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    This script pulls in markupsafe from a source folder and
+    bundles it with Jinja2.  It does not pull in the speedups
+    module though.
+
+    :copyright: Copyright 2010 by the Jinja team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
+import sys
+import os
+import re
+
+
+def rewrite_imports(lines):
+    for idx, line in enumerate(lines):
+        new_line = re.sub(r'(import|from)\s+markupsafe\b',
+                          r'\1 jinja2._markupsafe', line)
+        if new_line != line:
+            lines[idx] = new_line
+
+
+def main():
+    if len(sys.argv) != 2:
+        print 'error: only argument is path to markupsafe'
+        sys.exit(1)
+    basedir = os.path.dirname(__file__)
+    markupdir = sys.argv[1]
+    for filename in os.listdir(markupdir):
+        if filename.endswith('.py'):
+            f = open(os.path.join(markupdir, filename))
+            try:
+                lines = list(f)
+            finally:
+                f.close()
+            rewrite_imports(lines)
+            f = open(os.path.join(basedir, filename), 'w')
+            try:
+                for line in lines:
+                    f.write(line)
+            finally:
+                f.close()
+
+
+if __name__ == '__main__':
+    main()
diff --git a/lib/jinja2/jinja2/_markupsafe/_constants.py b/lib/jinja2/jinja2/_markupsafe/_constants.py
new file mode 100644
index 0000000..919bf03
--- /dev/null
+++ b/lib/jinja2/jinja2/_markupsafe/_constants.py
@@ -0,0 +1,267 @@
+# -*- coding: utf-8 -*-
+"""
+    markupsafe._constants
+    ~~~~~~~~~~~~~~~~~~~~~
+
+    Highlevel implementation of the Markup string.
+
+    :copyright: (c) 2010 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+
+
+HTML_ENTITIES = {
+    'AElig': 198,
+    'Aacute': 193,
+    'Acirc': 194,
+    'Agrave': 192,
+    'Alpha': 913,
+    'Aring': 197,
+    'Atilde': 195,
+    'Auml': 196,
+    'Beta': 914,
+    'Ccedil': 199,
+    'Chi': 935,
+    'Dagger': 8225,
+    'Delta': 916,
+    'ETH': 208,
+    'Eacute': 201,
+    'Ecirc': 202,
+    'Egrave': 200,
+    'Epsilon': 917,
+    'Eta': 919,
+    'Euml': 203,
+    'Gamma': 915,
+    'Iacute': 205,
+    'Icirc': 206,
+    'Igrave': 204,
+    'Iota': 921,
+    'Iuml': 207,
+    'Kappa': 922,
+    'Lambda': 923,
+    'Mu': 924,
+    'Ntilde': 209,
+    'Nu': 925,
+    'OElig': 338,
+    'Oacute': 211,
+    'Ocirc': 212,
+    'Ograve': 210,
+    'Omega': 937,
+    'Omicron': 927,
+    'Oslash': 216,
+    'Otilde': 213,
+    'Ouml': 214,
+    'Phi': 934,
+    'Pi': 928,
+    'Prime': 8243,
+    'Psi': 936,
+    'Rho': 929,
+    'Scaron': 352,
+    'Sigma': 931,
+    'THORN': 222,
+    'Tau': 932,
+    'Theta': 920,
+    'Uacute': 218,
+    'Ucirc': 219,
+    'Ugrave': 217,
+    'Upsilon': 933,
+    'Uuml': 220,
+    'Xi': 926,
+    'Yacute': 221,
+    'Yuml': 376,
+    'Zeta': 918,
+    'aacute': 225,
+    'acirc': 226,
+    'acute': 180,
+    'aelig': 230,
+    'agrave': 224,
+    'alefsym': 8501,
+    'alpha': 945,
+    'amp': 38,
+    'and': 8743,
+    'ang': 8736,
+    'apos': 39,
+    'aring': 229,
+    'asymp': 8776,
+    'atilde': 227,
+    'auml': 228,
+    'bdquo': 8222,
+    'beta': 946,
+    'brvbar': 166,
+    'bull': 8226,
+    'cap': 8745,
+    'ccedil': 231,
+    'cedil': 184,
+    'cent': 162,
+    'chi': 967,
+    'circ': 710,
+    'clubs': 9827,
+    'cong': 8773,
+    'copy': 169,
+    'crarr': 8629,
+    'cup': 8746,
+    'curren': 164,
+    'dArr': 8659,
+    'dagger': 8224,
+    'darr': 8595,
+    'deg': 176,
+    'delta': 948,
+    'diams': 9830,
+    'divide': 247,
+    'eacute': 233,
+    'ecirc': 234,
+    'egrave': 232,
+    'empty': 8709,
+    'emsp': 8195,
+    'ensp': 8194,
+    'epsilon': 949,
+    'equiv': 8801,
+    'eta': 951,
+    'eth': 240,
+    'euml': 235,
+    'euro': 8364,
+    'exist': 8707,
+    'fnof': 402,
+    'forall': 8704,
+    'frac12': 189,
+    'frac14': 188,
+    'frac34': 190,
+    'frasl': 8260,
+    'gamma': 947,
+    'ge': 8805,
+    'gt': 62,
+    'hArr': 8660,
+    'harr': 8596,
+    'hearts': 9829,
+    'hellip': 8230,
+    'iacute': 237,
+    'icirc': 238,
+    'iexcl': 161,
+    'igrave': 236,
+    'image': 8465,
+    'infin': 8734,
+    'int': 8747,
+    'iota': 953,
+    'iquest': 191,
+    'isin': 8712,
+    'iuml': 239,
+    'kappa': 954,
+    'lArr': 8656,
+    'lambda': 955,
+    'lang': 9001,
+    'laquo': 171,
+    'larr': 8592,
+    'lceil': 8968,
+    'ldquo': 8220,
+    'le': 8804,
+    'lfloor': 8970,
+    'lowast': 8727,
+    'loz': 9674,
+    'lrm': 8206,
+    'lsaquo': 8249,
+    'lsquo': 8216,
+    'lt': 60,
+    'macr': 175,
+    'mdash': 8212,
+    'micro': 181,
+    'middot': 183,
+    'minus': 8722,
+    'mu': 956,
+    'nabla': 8711,
+    'nbsp': 160,
+    'ndash': 8211,
+    'ne': 8800,
+    'ni': 8715,
+    'not': 172,
+    'notin': 8713,
+    'nsub': 8836,
+    'ntilde': 241,
+    'nu': 957,
+    'oacute': 243,
+    'ocirc': 244,
+    'oelig': 339,
+    'ograve': 242,
+    'oline': 8254,
+    'omega': 969,
+    'omicron': 959,
+    'oplus': 8853,
+    'or': 8744,
+    'ordf': 170,
+    'ordm': 186,
+    'oslash': 248,
+    'otilde': 245,
+    'otimes': 8855,
+    'ouml': 246,
+    'para': 182,
+    'part': 8706,
+    'permil': 8240,
+    'perp': 8869,
+    'phi': 966,
+    'pi': 960,
+    'piv': 982,
+    'plusmn': 177,
+    'pound': 163,
+    'prime': 8242,
+    'prod': 8719,
+    'prop': 8733,
+    'psi': 968,
+    'quot': 34,
+    'rArr': 8658,
+    'radic': 8730,
+    'rang': 9002,
+    'raquo': 187,
+    'rarr': 8594,
+    'rceil': 8969,
+    'rdquo': 8221,
+    'real': 8476,
+    'reg': 174,
+    'rfloor': 8971,
+    'rho': 961,
+    'rlm': 8207,
+    'rsaquo': 8250,
+    'rsquo': 8217,
+    'sbquo': 8218,
+    'scaron': 353,
+    'sdot': 8901,
+    'sect': 167,
+    'shy': 173,
+    'sigma': 963,
+    'sigmaf': 962,
+    'sim': 8764,
+    'spades': 9824,
+    'sub': 8834,
+    'sube': 8838,
+    'sum': 8721,
+    'sup': 8835,
+    'sup1': 185,
+    'sup2': 178,
+    'sup3': 179,
+    'supe': 8839,
+    'szlig': 223,
+    'tau': 964,
+    'there4': 8756,
+    'theta': 952,
+    'thetasym': 977,
+    'thinsp': 8201,
+    'thorn': 254,
+    'tilde': 732,
+    'times': 215,
+    'trade': 8482,
+    'uArr': 8657,
+    'uacute': 250,
+    'uarr': 8593,
+    'ucirc': 251,
+    'ugrave': 249,
+    'uml': 168,
+    'upsih': 978,
+    'upsilon': 965,
+    'uuml': 252,
+    'weierp': 8472,
+    'xi': 958,
+    'yacute': 253,
+    'yen': 165,
+    'yuml': 255,
+    'zeta': 950,
+    'zwj': 8205,
+    'zwnj': 8204
+}
diff --git a/lib/jinja2/jinja2/_markupsafe/_native.py b/lib/jinja2/jinja2/_markupsafe/_native.py
new file mode 100644
index 0000000..7b95828
--- /dev/null
+++ b/lib/jinja2/jinja2/_markupsafe/_native.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+"""
+    markupsafe._native
+    ~~~~~~~~~~~~~~~~~~
+
+    Native Python implementation the C module is not compiled.
+
+    :copyright: (c) 2010 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+from jinja2._markupsafe import Markup
+
+
+def escape(s):
+    """Convert the characters &, <, >, ' and " in string s to HTML-safe
+    sequences.  Use this if you need to display text that might contain
+    such characters in HTML.  Marks return value as markup string.
+    """
+    if hasattr(s, '__html__'):
+        return s.__html__()
+    return Markup(unicode(s)
+        .replace('&', '&amp;')
+        .replace('>', '&gt;')
+        .replace('<', '&lt;')
+        .replace("'", '&#39;')
+        .replace('"', '&#34;')
+    )
+
+
+def escape_silent(s):
+    """Like :func:`escape` but converts `None` into an empty
+    markup string.
+    """
+    if s is None:
+        return Markup()
+    return escape(s)
+
+
+def soft_unicode(s):
+    """Make a string unicode if it isn't already.  That way a markup
+    string is not converted back to unicode.
+    """
+    if not isinstance(s, unicode):
+        s = unicode(s)
+    return s
diff --git a/lib/jinja2/jinja2/_markupsafe/tests.py b/lib/jinja2/jinja2/_markupsafe/tests.py
new file mode 100644
index 0000000..c1ce394
--- /dev/null
+++ b/lib/jinja2/jinja2/_markupsafe/tests.py
@@ -0,0 +1,80 @@
+import gc
+import unittest
+from jinja2._markupsafe import Markup, escape, escape_silent
+
+
+class MarkupTestCase(unittest.TestCase):
+
+    def test_markup_operations(self):
+        # adding two strings should escape the unsafe one
+        unsafe = '<script type="application/x-some-script">alert("foo");</script>'
+        safe = Markup('<em>username</em>')
+        assert unsafe + safe == unicode(escape(unsafe)) + unicode(safe)
+
+        # string interpolations are safe to use too
+        assert Markup('<em>%s</em>') % '<bad user>' == \
+               '<em>&lt;bad user&gt;</em>'
+        assert Markup('<em>%(username)s</em>') % {
+            'username': '<bad user>'
+        } == '<em>&lt;bad user&gt;</em>'
+
+        # an escaped object is markup too
+        assert type(Markup('foo') + 'bar') is Markup
+
+        # and it implements __html__ by returning itself
+        x = Markup("foo")
+        assert x.__html__() is x
+
+        # it also knows how to treat __html__ objects
+        class Foo(object):
+            def __html__(self):
+                return '<em>awesome</em>'
+            def __unicode__(self):
+                return 'awesome'
+        assert Markup(Foo()) == '<em>awesome</em>'
+        assert Markup('<strong>%s</strong>') % Foo() == \
+               '<strong><em>awesome</em></strong>'
+
+        # escaping and unescaping
+        assert escape('"<>&\'') == '&#34;&lt;&gt;&amp;&#39;'
+        assert Markup("<em>Foo &amp; Bar</em>").striptags() == "Foo & Bar"
+        assert Markup("&lt;test&gt;").unescape() == "<test>"
+
+    def test_all_set(self):
+        import jinja2._markupsafe as markup
+        for item in markup.__all__:
+            getattr(markup, item)
+
+    def test_escape_silent(self):
+        assert escape_silent(None) == Markup()
+        assert escape(None) == Markup(None)
+        assert escape_silent('<foo>') == Markup(u'&lt;foo&gt;')
+
+
+class MarkupLeakTestCase(unittest.TestCase):
+
+    def test_markup_leaks(self):
+        counts = set()
+        for count in xrange(20):
+            for item in xrange(1000):
+                escape("foo")
+                escape("<foo>")
+                escape(u"foo")
+                escape(u"<foo>")
+            counts.add(len(gc.get_objects()))
+        assert len(counts) == 1, 'ouch, c extension seems to leak objects'
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(MarkupTestCase))
+
+    # this test only tests the c extension
+    if not hasattr(escape, 'func_code'):
+        suite.addTest(unittest.makeSuite(MarkupLeakTestCase))
+
+    return suite
+
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='suite')
diff --git a/lib/jinja2/jinja2/_stringdefs.py b/lib/jinja2/jinja2/_stringdefs.py
new file mode 100644
index 0000000..1161b7f
--- /dev/null
+++ b/lib/jinja2/jinja2/_stringdefs.py
@@ -0,0 +1,130 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2._stringdefs
+    ~~~~~~~~~~~~~~~~~~
+
+    Strings of all Unicode characters of a certain category.
+    Used for matching in Unicode-aware languages. Run to regenerate.
+
+    Inspired by chartypes_create.py from the MoinMoin project, original
+    implementation from Pygments.
+
+    :copyright: Copyright 2006-2009 by the Jinja team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
+
+Cc = u'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f'
+
+Cf = u'\xad\u0600\u0601\u0602\u0603\u06dd\u070f\u17b4\u17b5\u200b\u200c\u200d\u200e\u200f\u202a\u202b\u202c\u202d\u202e\u2060\u2061\u2062\u2063\u206a\u206b\u206c\u206d\u206e\u206f\ufeff\ufff9\ufffa\ufffb'
+
+Cn = u'\u0242\u0243\u0244\u0245\u0246\u0247\u0248\u0249\u024a\u024b\u024c\u024d\u024e\u024f\u0370\u0371\u0372\u0373\u0376\u0377\u0378\u0379\u037b\u037c\u037d\u037f\u0380\u0381\u0382\u0383\u038b\u038d\u03a2\u03cf\u0487\u04cf\u04fa\u04fb\u04fc\u04fd\u04fe\u04ff\u0510\u0511\u0512\u0513\u0514\u0515\u0516\u0517\u0518\u0519\u051a\u051b\u051c\u051d\u051e\u051f\u0520\u0521\u0522\u0523\u0524\u0525\u0526\u0527\u0528\u0529\u052a\u052b\u052c\u052d\u052e\u052f\u0530\u0557\u0558\u0560\u0588\u058b\u058c\u058d\u058e\u058f\u0590\u05ba\u05c8\u05c9\u05ca\u05cb\u05cc\u05cd\u05ce\u05cf\u05eb\u05ec\u05ed\u05ee\u05ef\u05f5\u05f6\u05f7\u05f8\u05f9\u05fa\u05fb\u05fc\u05fd\u05fe\u05ff\u0604\u0605\u0606\u0607\u0608\u0609\u060a\u0616\u0617\u0618\u0619\u061a\u061c\u061d\u0620\u063b\u063c\u063d\u063e\u063f\u065f\u070e\u074b\u074c\u076e\u076f\u0770\u0771\u0772\u0773\u0774\u0775\u0776\u0777\u0778\u0779\u077a\u077b\u077c\u077d\u077e\u077f\u07b2\u07b3\u07b4\u07b5\u07b6\u07b7\u07b8\u07b9\u07ba\u07bb\u07bc\u07bd\u07be\u07bf\u07c0\u07c1\u07c2\u07c3\u07c4\u07c5\u07c6\u07c7\u07c8\u07c9\u07ca\u07cb\u07cc\u07cd\u07ce\u07cf\u07d0\u07d1\u07d2\u07d3\u07d4\u07d5\u07d6\u07d7\u07d8\u07d9\u07da\u07db\u07dc\u07dd\u07de\u07df\u07e0\u07e1\u07e2\u07e3\u07e4\u07e5\u07e6\u07e7\u07e8\u07e9\u07ea\u07eb\u07ec\u07ed\u07ee\u07ef\u07f0\u07f1\u07f2\u07f3\u07f4\u07f5\u07f6\u07f7\u07f8\u07f9\u07fa\u07fb\u07fc\u07fd\u07fe\u07ff\u0800\u0801\u0802\u0803\u0804\u0805\u0806\u0807\u0808\u0809\u080a\u080b\u080c\u080d\u080e\u080f\u0810\u0811\u0812\u0813\u0814\u0815\u0816\u0817\u0818\u0819\u081a\u081b\u081c\u081d\u081e\u081f\u0820\u0821\u0822\u0823\u0824\u0825\u0826\u0827\u0828\u0829\u082a\u082b\u082c\u082d\u082e\u082f\u0830\u0831\u0832\u0833\u0834\u0835\u0836\u0837\u0838\u0839\u083a\u083b\u083c\u083d\u083e\u083f\u0840\u0841\u0842\u0843\u0844\u0845\u0846\u0847\u0848\u0849\u084a\u084b\u084c\u084d\u084e\u084f\u0850\u0851\u0852\u0853\u0854\u0855\u0856\u0857\u0858\u0859\u085a\u085b\u085c\u085d\u085e\u085f\u0860\u0861\u0862\u0863\u0864\u0865\u0866\u0867\u0868\u0869\u086a\u086b\u086c\u086d\u086e\u086f\u0870\u0871\u0872\u0873\u0874\u0875\u0876\u0877\u0878\u0879\u087a\u087b\u087c\u087d\u087e\u087f\u0880\u0881\u0882\u0883\u0884\u0885\u0886\u0887\u0888\u0889\u088a\u088b\u088c\u088d\u088e\u088f\u0890\u0891\u0892\u0893\u0894\u0895\u0896\u0897\u0898\u0899\u089a\u089b\u089c\u089d\u089e\u089f\u08a0\u08a1\u08a2\u08a3\u08a4\u08a5\u08a6\u08a7\u08a8\u08a9\u08aa\u08ab\u08ac\u08ad\u08ae\u08af\u08b0\u08b1\u08b2\u08b3\u08b4\u08b5\u08b6\u08b7\u08b8\u08b9\u08ba\u08bb\u08bc\u08bd\u08be\u08bf\u08c0\u08c1\u08c2\u08c3\u08c4\u08c5\u08c6\u08c7\u08c8\u08c9\u08ca\u08cb\u08cc\u08cd\u08ce\u08cf\u08d0\u08d1\u08d2\u08d3\u08d4\u08d5\u08d6\u08d7\u08d8\u08d9\u08da\u08db\u08dc\u08dd\u08de\u08df\u08e0\u08e1\u08e2\u08e3\u08e4\u08e5\u08e6\u08e7\u08e8\u08e9\u08ea\u08eb\u08ec\u08ed\u08ee\u08ef\u08f0\u08f1\u08f2\u08f3\u08f4\u08f5\u08f6\u08f7\u08f8\u08f9\u08fa\u08fb\u08fc\u08fd\u08fe\u08ff\u0900\u093a\u093b\u094e\u094f\u0955\u0956\u0957\u0971\u0972\u0973\u0974\u0975\u0976\u0977\u0978\u0979\u097a\u097b\u097c\u097e\u097f\u0980\u0984\u098d\u098e\u0991\u0992\u09a9\u09b1\u09b3\u09b4\u09b5\u09ba\u09bb\u09c5\u09c6\u09c9\u09ca\u09cf\u09d0\u09d1\u09d2\u09d3\u09d4\u09d5\u09d6\u09d8\u09d9\u09da\u09db\u09de\u09e4\u09e5\u09fb\u09fc\u09fd\u09fe\u09ff\u0a00\u0a04\u0a0b\u0a0c\u0a0d\u0a0e\u0a11\u0a12\u0a29\u0a31\u0a34\u0a37\u0a3a\u0a3b\u0a3d\u0a43\u0a44\u0a45\u0a46\u0a49\u0a4a\u0a4e\u0a4f\u0a50\u0a51\u0a52\u0a53\u0a54\u0a55\u0a56\u0a57\u0a58\u0a5d\u0a5f\u0a60\u0a61\u0a62\u0a63\u0a64\u0a65\u0a75\u0a76\u0a77\u0a78\u0a79\u0a7a\u0a7b\u0a7c\u0a7d\u0a7e\u0a7f\u0a80\u0a84\u0a8e\u0a92\u0aa9\u0ab1\u0ab4\u0aba\u0abb\u0ac6\u0aca\u0ace\u0acf\u0ad1\u0ad2\u0ad3\u0ad4\u0ad5\u0ad6\u0ad7\u0ad8\u0ad9\u0ada\u0adb\u0adc\u0add\u0ade\u0adf\u0ae4\u0ae5\u0af0\u0af2\u0af3\u0af4\u0af5\u0af6\u0af7\u0af8\u0af9\u0afa\u0afb\u0afc\u0afd\u0afe\u0aff\u0b00\u0b04\u0b0d\u0b0e\u0b11\u0b12\u0b29\u0b31\u0b34\u0b3a\u0b3b\u0b44\u0b45\u0b46\u0b49\u0b4a\u0b4e\u0b4f\u0b50\u0b51\u0b52\u0b53\u0b54\u0b55\u0b58\u0b59\u0b5a\u0b5b\u0b5e\u0b62\u0b63\u0b64\u0b65\u0b72\u0b73\u0b74\u0b75\u0b76\u0b77\u0b78\u0b79\u0b7a\u0b7b\u0b7c\u0b7d\u0b7e\u0b7f\u0b80\u0b81\u0b84\u0b8b\u0b8c\u0b8d\u0b91\u0b96\u0b97\u0b98\u0b9b\u0b9d\u0ba0\u0ba1\u0ba2\u0ba5\u0ba6\u0ba7\u0bab\u0bac\u0bad\u0bba\u0bbb\u0bbc\u0bbd\u0bc3\u0bc4\u0bc5\u0bc9\u0bce\u0bcf\u0bd0\u0bd1\u0bd2\u0bd3\u0bd4\u0bd5\u0bd6\u0bd8\u0bd9\u0bda\u0bdb\u0bdc\u0bdd\u0bde\u0bdf\u0be0\u0be1\u0be2\u0be3\u0be4\u0be5\u0bfb\u0bfc\u0bfd\u0bfe\u0bff\u0c00\u0c04\u0c0d\u0c11\u0c29\u0c34\u0c3a\u0c3b\u0c3c\u0c3d\u0c45\u0c49\u0c4e\u0c4f\u0c50\u0c51\u0c52\u0c53\u0c54\u0c57\u0c58\u0c59\u0c5a\u0c5b\u0c5c\u0c5d\u0c5e\u0c5f\u0c62\u0c63\u0c64\u0c65\u0c70\u0c71\u0c72\u0c73\u0c74\u0c75\u0c76\u0c77\u0c78\u0c79\u0c7a\u0c7b\u0c7c\u0c7d\u0c7e\u0c7f\u0c80\u0c81\u0c84\u0c8d\u0c91\u0ca9\u0cb4\u0cba\u0cbb\u0cc5\u0cc9\u0cce\u0ccf\u0cd0\u0cd1\u0cd2\u0cd3\u0cd4\u0cd7\u0cd8\u0cd9\u0cda\u0cdb\u0cdc\u0cdd\u0cdf\u0ce2\u0ce3\u0ce4\u0ce5\u0cf0\u0cf1\u0cf2\u0cf3\u0cf4\u0cf5\u0cf6\u0cf7\u0cf8\u0cf9\u0cfa\u0cfb\u0cfc\u0cfd\u0cfe\u0cff\u0d00\u0d01\u0d04\u0d0d\u0d11\u0d29\u0d3a\u0d3b\u0d3c\u0d3d\u0d44\u0d45\u0d49\u0d4e\u0d4f\u0d50\u0d51\u0d52\u0d53\u0d54\u0d55\u0d56\u0d58\u0d59\u0d5a\u0d5b\u0d5c\u0d5d\u0d5e\u0d5f\u0d62\u0d63\u0d64\u0d65\u0d70\u0d71\u0d72\u0d73\u0d74\u0d75\u0d76\u0d77\u0d78\u0d79\u0d7a\u0d7b\u0d7c\u0d7d\u0d7e\u0d7f\u0d80\u0d81\u0d84\u0d97\u0d98\u0d99\u0db2\u0dbc\u0dbe\u0dbf\u0dc7\u0dc8\u0dc9\u0dcb\u0dcc\u0dcd\u0dce\u0dd5\u0dd7\u0de0\u0de1\u0de2\u0de3\u0de4\u0de5\u0de6\u0de7\u0de8\u0de9\u0dea\u0deb\u0dec\u0ded\u0dee\u0def\u0df0\u0df1\u0df5\u0df6\u0df7\u0df8\u0df9\u0dfa\u0dfb\u0dfc\u0dfd\u0dfe\u0dff\u0e00\u0e3b\u0e3c\u0e3d\u0e3e\u0e5c\u0e5d\u0e5e\u0e5f\u0e60\u0e61\u0e62\u0e63\u0e64\u0e65\u0e66\u0e67\u0e68\u0e69\u0e6a\u0e6b\u0e6c\u0e6d\u0e6e\u0e6f\u0e70\u0e71\u0e72\u0e73\u0e74\u0e75\u0e76\u0e77\u0e78\u0e79\u0e7a\u0e7b\u0e7c\u0e7d\u0e7e\u0e7f\u0e80\u0e83\u0e85\u0e86\u0e89\u0e8b\u0e8c\u0e8e\u0e8f\u0e90\u0e91\u0e92\u0e93\u0e98\u0ea0\u0ea4\u0ea6\u0ea8\u0ea9\u0eac\u0eba\u0ebe\u0ebf\u0ec5\u0ec7\u0ece\u0ecf\u0eda\u0edb\u0ede\u0edf\u0ee0\u0ee1\u0ee2\u0ee3\u0ee4\u0ee5\u0ee6\u0ee7\u0ee8\u0ee9\u0eea\u0eeb\u0eec\u0eed\u0eee\u0eef\u0ef0\u0ef1\u0ef2\u0ef3\u0ef4\u0ef5\u0ef6\u0ef7\u0ef8\u0ef9\u0efa\u0efb\u0efc\u0efd\u0efe\u0eff\u0f48\u0f6b\u0f6c\u0f6d\u0f6e\u0f6f\u0f70\u0f8c\u0f8d\u0f8e\u0f8f\u0f98\u0fbd\u0fcd\u0fce\u0fd2\u0fd3\u0fd4\u0fd5\u0fd6\u0fd7\u0fd8\u0fd9\u0fda\u0fdb\u0fdc\u0fdd\u0fde\u0fdf\u0fe0\u0fe1\u0fe2\u0fe3\u0fe4\u0fe5\u0fe6\u0fe7\u0fe8\u0fe9\u0fea\u0feb\u0fec\u0fed\u0fee\u0fef\u0ff0\u0ff1\u0ff2\u0ff3\u0ff4\u0ff5\u0ff6\u0ff7\u0ff8\u0ff9\u0ffa\u0ffb\u0ffc\u0ffd\u0ffe\u0fff\u1022\u1028\u102b\u1033\u1034\u1035\u103a\u103b\u103c\u103d\u103e\u103f\u105a\u105b\u105c\u105d\u105e\u105f\u1060\u1061\u1062\u1063\u1064\u1065\u1066\u1067\u1068\u1069\u106a\u106b\u106c\u106d\u106e\u106f\u1070\u1071\u1072\u1073\u1074\u1075\u1076\u1077\u1078\u1079\u107a\u107b\u107c\u107d\u107e\u107f\u1080\u1081\u1082\u1083\u1084\u1085\u1086\u1087\u1088\u1089\u108a\u108b\u108c\u108d\u108e\u108f\u1090\u1091\u1092\u1093\u1094\u1095\u1096\u1097\u1098\u1099\u109a\u109b\u109c\u109d\u109e\u109f\u10c6\u10c7\u10c8\u10c9\u10ca\u10cb\u10cc\u10cd\u10ce\u10cf\u10fd\u10fe\u10ff\u115a\u115b\u115c\u115d\u115e\u11a3\u11a4\u11a5\u11a6\u11a7\u11fa\u11fb\u11fc\u11fd\u11fe\u11ff\u1249\u124e\u124f\u1257\u1259\u125e\u125f\u1289\u128e\u128f\u12b1\u12b6\u12b7\u12bf\u12c1\u12c6\u12c7\u12d7\u1311\u1316\u1317\u135b\u135c\u135d\u135e\u137d\u137e\u137f\u139a\u139b\u139c\u139d\u139e\u139f\u13f5\u13f6\u13f7\u13f8\u13f9\u13fa\u13fb\u13fc\u13fd\u13fe\u13ff\u1400\u1677\u1678\u1679\u167a\u167b\u167c\u167d\u167e\u167f\u169d\u169e\u169f\u16f1\u16f2\u16f3\u16f4\u16f5\u16f6\u16f7\u16f8\u16f9\u16fa\u16fb\u16fc\u16fd\u16fe\u16ff\u170d\u1715\u1716\u1717\u1718\u1719\u171a\u171b\u171c\u171d\u171e\u171f\u1737\u1738\u1739\u173a\u173b\u173c\u173d\u173e\u173f\u1754\u1755\u1756\u1757\u1758\u1759\u175a\u175b\u175c\u175d\u175e\u175f\u176d\u1771\u1774\u1775\u1776\u1777\u1778\u1779\u177a\u177b\u177c\u177d\u177e\u177f\u17de\u17df\u17ea\u17eb\u17ec\u17ed\u17ee\u17ef\u17fa\u17fb\u17fc\u17fd\u17fe\u17ff\u180f\u181a\u181b\u181c\u181d\u181e\u181f\u1878\u1879\u187a\u187b\u187c\u187d\u187e\u187f\u18aa\u18ab\u18ac\u18ad\u18ae\u18af\u18b0\u18b1\u18b2\u18b3\u18b4\u18b5\u18b6\u18b7\u18b8\u18b9\u18ba\u18bb\u18bc\u18bd\u18be\u18bf\u18c0\u18c1\u18c2\u18c3\u18c4\u18c5\u18c6\u18c7\u18c8\u18c9\u18ca\u18cb\u18cc\u18cd\u18ce\u18cf\u18d0\u18d1\u18d2\u18d3\u18d4\u18d5\u18d6\u18d7\u18d8\u18d9\u18da\u18db\u18dc\u18dd\u18de\u18df\u18e0\u18e1\u18e2\u18e3\u18e4\u18e5\u18e6\u18e7\u18e8\u18e9\u18ea\u18eb\u18ec\u18ed\u18ee\u18ef\u18f0\u18f1\u18f2\u18f3\u18f4\u18f5\u18f6\u18f7\u18f8\u18f9\u18fa\u18fb\u18fc\u18fd\u18fe\u18ff\u191d\u191e\u191f\u192c\u192d\u192e\u192f\u193c\u193d\u193e\u193f\u1941\u1942\u1943\u196e\u196f\u1975\u1976\u1977\u1978\u1979\u197a\u197b\u197c\u197d\u197e\u197f\u19aa\u19ab\u19ac\u19ad\u19ae\u19af\u19ca\u19cb\u19cc\u19cd\u19ce\u19cf\u19da\u19db\u19dc\u19dd\u1a1c\u1a1d\u1a20\u1a21\u1a22\u1a23\u1a24\u1a25\u1a26\u1a27\u1a28\u1a29\u1a2a\u1a2b\u1a2c\u1a2d\u1a2e\u1a2f\u1a30\u1a31\u1a32\u1a33\u1a34\u1a35\u1a36\u1a37\u1a38\u1a39\u1a3a\u1a3b\u1a3c\u1a3d\u1a3e\u1a3f\u1a40\u1a41\u1a42\u1a43\u1a44\u1a45\u1a46\u1a47\u1a48\u1a49\u1a4a\u1a4b\u1a4c\u1a4d\u1a4e\u1a4f\u1a50\u1a51\u1a52\u1a53\u1a54\u1a55\u1a56\u1a57\u1a58\u1a59\u1a5a\u1a5b\u1a5c\u1a5d\u1a5e\u1a5f\u1a60\u1a61\u1a62\u1a63\u1a64\u1a65\u1a66\u1a67\u1a68\u1a69\u1a6a\u1a6b\u1a6c\u1a6d\u1a6e\u1a6f\u1a70\u1a71\u1a72\u1a73\u1a74\u1a75\u1a76\u1a77\u1a78\u1a79\u1a7a\u1a7b\u1a7c\u1a7d\u1a7e\u1a7f\u1a80\u1a81\u1a82\u1a83\u1a84\u1a85\u1a86\u1a87\u1a88\u1a89\u1a8a\u1a8b\u1a8c\u1a8d\u1a8e\u1a8f\u1a90\u1a91\u1a92\u1a93\u1a94\u1a95\u1a96\u1a97\u1a98\u1a99\u1a9a\u1a9b\u1a9c\u1a9d\u1a9e\u1a9f\u1aa0\u1aa1\u1aa2\u1aa3\u1aa4\u1aa5\u1aa6\u1aa7\u1aa8\u1aa9\u1aaa\u1aab\u1aac\u1aad\u1aae\u1aaf\u1ab0\u1ab1\u1ab2\u1ab3\u1ab4\u1ab5\u1ab6\u1ab7\u1ab8\u1ab9\u1aba\u1abb\u1abc\u1abd\u1abe\u1abf\u1ac0\u1ac1\u1ac2\u1ac3\u1ac4\u1ac5\u1ac6\u1ac7\u1ac8\u1ac9\u1aca\u1acb\u1acc\u1acd\u1ace\u1acf\u1ad0\u1ad1\u1ad2\u1ad3\u1ad4\u1ad5\u1ad6\u1ad7\u1ad8\u1ad9\u1ada\u1adb\u1adc\u1add\u1ade\u1adf\u1ae0\u1ae1\u1ae2\u1ae3\u1ae4\u1ae5\u1ae6\u1ae7\u1ae8\u1ae9\u1aea\u1aeb\u1aec\u1aed\u1aee\u1aef\u1af0\u1af1\u1af2\u1af3\u1af4\u1af5\u1af6\u1af7\u1af8\u1af9\u1afa\u1afb\u1afc\u1afd\u1afe\u1aff\u1b00\u1b01\u1b02\u1b03\u1b04\u1b05\u1b06\u1b07\u1b08\u1b09\u1b0a\u1b0b\u1b0c\u1b0d\u1b0e\u1b0f\u1b10\u1b11\u1b12\u1b13\u1b14\u1b15\u1b16\u1b17\u1b18\u1b19\u1b1a\u1b1b\u1b1c\u1b1d\u1b1e\u1b1f\u1b20\u1b21\u1b22\u1b23\u1b24\u1b25\u1b26\u1b27\u1b28\u1b29\u1b2a\u1b2b\u1b2c\u1b2d\u1b2e\u1b2f\u1b30\u1b31\u1b32\u1b33\u1b34\u1b35\u1b36\u1b37\u1b38\u1b39\u1b3a\u1b3b\u1b3c\u1b3d\u1b3e\u1b3f\u1b40\u1b41\u1b42\u1b43\u1b44\u1b45\u1b46\u1b47\u1b48\u1b49\u1b4a\u1b4b\u1b4c\u1b4d\u1b4e\u1b4f\u1b50\u1b51\u1b52\u1b53\u1b54\u1b55\u1b56\u1b57\u1b58\u1b59\u1b5a\u1b5b\u1b5c\u1b5d\u1b5e\u1b5f\u1b60\u1b61\u1b62\u1b63\u1b64\u1b65\u1b66\u1b67\u1b68\u1b69\u1b6a\u1b6b\u1b6c\u1b6d\u1b6e\u1b6f\u1b70\u1b71\u1b72\u1b73\u1b74\u1b75\u1b76\u1b77\u1b78\u1b79\u1b7a\u1b7b\u1b7c\u1b7d\u1b7e\u1b7f\u1b80\u1b81\u1b82\u1b83\u1b84\u1b85\u1b86\u1b87\u1b88\u1b89\u1b8a\u1b8b\u1b8c\u1b8d\u1b8e\u1b8f\u1b90\u1b91\u1b92\u1b93\u1b94\u1b95\u1b96\u1b97\u1b98\u1b99\u1b9a\u1b9b\u1b9c\u1b9d\u1b9e\u1b9f\u1ba0\u1ba1\u1ba2\u1ba3\u1ba4\u1ba5\u1ba6\u1ba7\u1ba8\u1ba9\u1baa\u1bab\u1bac\u1bad\u1bae\u1baf\u1bb0\u1bb1\u1bb2\u1bb3\u1bb4\u1bb5\u1bb6\u1bb7\u1bb8\u1bb9\u1bba\u1bbb\u1bbc\u1bbd\u1bbe\u1bbf\u1bc0\u1bc1\u1bc2\u1bc3\u1bc4\u1bc5\u1bc6\u1bc7\u1bc8\u1bc9\u1bca\u1bcb\u1bcc\u1bcd\u1bce\u1bcf\u1bd0\u1bd1\u1bd2\u1bd3\u1bd4\u1bd5\u1bd6\u1bd7\u1bd8\u1bd9\u1bda\u1bdb\u1bdc\u1bdd\u1bde\u1bdf\u1be0\u1be1\u1be2\u1be3\u1be4\u1be5\u1be6\u1be7\u1be8\u1be9\u1bea\u1beb\u1bec\u1bed\u1bee\u1bef\u1bf0\u1bf1\u1bf2\u1bf3\u1bf4\u1bf5\u1bf6\u1bf7\u1bf8\u1bf9\u1bfa\u1bfb\u1bfc\u1bfd\u1bfe\u1bff\u1c00\u1c01\u1c02\u1c03\u1c04\u1c05\u1c06\u1c07\u1c08\u1c09\u1c0a\u1c0b\u1c0c\u1c0d\u1c0e\u1c0f\u1c10\u1c11\u1c12\u1c13\u1c14\u1c15\u1c16\u1c17\u1c18\u1c19\u1c1a\u1c1b\u1c1c\u1c1d\u1c1e\u1c1f\u1c20\u1c21\u1c22\u1c23\u1c24\u1c25\u1c26\u1c27\u1c28\u1c29\u1c2a\u1c2b\u1c2c\u1c2d\u1c2e\u1c2f\u1c30\u1c31\u1c32\u1c33\u1c34\u1c35\u1c36\u1c37\u1c38\u1c39\u1c3a\u1c3b\u1c3c\u1c3d\u1c3e\u1c3f\u1c40\u1c41\u1c42\u1c43\u1c44\u1c45\u1c46\u1c47\u1c48\u1c49\u1c4a\u1c4b\u1c4c\u1c4d\u1c4e\u1c4f\u1c50\u1c51\u1c52\u1c53\u1c54\u1c55\u1c56\u1c57\u1c58\u1c59\u1c5a\u1c5b\u1c5c\u1c5d\u1c5e\u1c5f\u1c60\u1c61\u1c62\u1c63\u1c64\u1c65\u1c66\u1c67\u1c68\u1c69\u1c6a\u1c6b\u1c6c\u1c6d\u1c6e\u1c6f\u1c70\u1c71\u1c72\u1c73\u1c74\u1c75\u1c76\u1c77\u1c78\u1c79\u1c7a\u1c7b\u1c7c\u1c7d\u1c7e\u1c7f\u1c80\u1c81\u1c82\u1c83\u1c84\u1c85\u1c86\u1c87\u1c88\u1c89\u1c8a\u1c8b\u1c8c\u1c8d\u1c8e\u1c8f\u1c90\u1c91\u1c92\u1c93\u1c94\u1c95\u1c96\u1c97\u1c98\u1c99\u1c9a\u1c9b\u1c9c\u1c9d\u1c9e\u1c9f\u1ca0\u1ca1\u1ca2\u1ca3\u1ca4\u1ca5\u1ca6\u1ca7\u1ca8\u1ca9\u1caa\u1cab\u1cac\u1cad\u1cae\u1caf\u1cb0\u1cb1\u1cb2\u1cb3\u1cb4\u1cb5\u1cb6\u1cb7\u1cb8\u1cb9\u1cba\u1cbb\u1cbc\u1cbd\u1cbe\u1cbf\u1cc0\u1cc1\u1cc2\u1cc3\u1cc4\u1cc5\u1cc6\u1cc7\u1cc8\u1cc9\u1cca\u1ccb\u1ccc\u1ccd\u1cce\u1ccf\u1cd0\u1cd1\u1cd2\u1cd3\u1cd4\u1cd5\u1cd6\u1cd7\u1cd8\u1cd9\u1cda\u1cdb\u1cdc\u1cdd\u1cde\u1cdf\u1ce0\u1ce1\u1ce2\u1ce3\u1ce4\u1ce5\u1ce6\u1ce7\u1ce8\u1ce9\u1cea\u1ceb\u1cec\u1ced\u1cee\u1cef\u1cf0\u1cf1\u1cf2\u1cf3\u1cf4\u1cf5\u1cf6\u1cf7\u1cf8\u1cf9\u1cfa\u1cfb\u1cfc\u1cfd\u1cfe\u1cff\u1dc4\u1dc5\u1dc6\u1dc7\u1dc8\u1dc9\u1dca\u1dcb\u1dcc\u1dcd\u1dce\u1dcf\u1dd0\u1dd1\u1dd2\u1dd3\u1dd4\u1dd5\u1dd6\u1dd7\u1dd8\u1dd9\u1dda\u1ddb\u1ddc\u1ddd\u1dde\u1ddf\u1de0\u1de1\u1de2\u1de3\u1de4\u1de5\u1de6\u1de7\u1de8\u1de9\u1dea\u1deb\u1dec\u1ded\u1dee\u1def\u1df0\u1df1\u1df2\u1df3\u1df4\u1df5\u1df6\u1df7\u1df8\u1df9\u1dfa\u1dfb\u1dfc\u1dfd\u1dfe\u1dff\u1e9c\u1e9d\u1e9e\u1e9f\u1efa\u1efb\u1efc\u1efd\u1efe\u1eff\u1f16\u1f17\u1f1e\u1f1f\u1f46\u1f47\u1f4e\u1f4f\u1f58\u1f5a\u1f5c\u1f5e\u1f7e\u1f7f\u1fb5\u1fc5\u1fd4\u1fd5\u1fdc\u1ff0\u1ff1\u1ff5\u1fff\u2064\u2065\u2066\u2067\u2068\u2069\u2072\u2073\u208f\u2095\u2096\u2097\u2098\u2099\u209a\u209b\u209c\u209d\u209e\u209f\u20b6\u20b7\u20b8\u20b9\u20ba\u20bb\u20bc\u20bd\u20be\u20bf\u20c0\u20c1\u20c2\u20c3\u20c4\u20c5\u20c6\u20c7\u20c8\u20c9\u20ca\u20cb\u20cc\u20cd\u20ce\u20cf\u20ec\u20ed\u20ee\u20ef\u20f0\u20f1\u20f2\u20f3\u20f4\u20f5\u20f6\u20f7\u20f8\u20f9\u20fa\u20fb\u20fc\u20fd\u20fe\u20ff\u214d\u214e\u214f\u2150\u2151\u2152\u2184\u2185\u2186\u2187\u2188\u2189\u218a\u218b\u218c\u218d\u218e\u218f\u23dc\u23dd\u23de\u23df\u23e0\u23e1\u23e2\u23e3\u23e4\u23e5\u23e6\u23e7\u23e8\u23e9\u23ea\u23eb\u23ec\u23ed\u23ee\u23ef\u23f0\u23f1\u23f2\u23f3\u23f4\u23f5\u23f6\u23f7\u23f8\u23f9\u23fa\u23fb\u23fc\u23fd\u23fe\u23ff\u2427\u2428\u2429\u242a\u242b\u242c\u242d\u242e\u242f\u2430\u2431\u2432\u2433\u2434\u2435\u2436\u2437\u2438\u2439\u243a\u243b\u243c\u243d\u243e\u243f\u244b\u244c\u244d\u244e\u244f\u2450\u2451\u2452\u2453\u2454\u2455\u2456\u2457\u2458\u2459\u245a\u245b\u245c\u245d\u245e\u245f\u269d\u269e\u269f\u26b2\u26b3\u26b4\u26b5\u26b6\u26b7\u26b8\u26b9\u26ba\u26bb\u26bc\u26bd\u26be\u26bf\u26c0\u26c1\u26c2\u26c3\u26c4\u26c5\u26c6\u26c7\u26c8\u26c9\u26ca\u26cb\u26cc\u26cd\u26ce\u26cf\u26d0\u26d1\u26d2\u26d3\u26d4\u26d5\u26d6\u26d7\u26d8\u26d9\u26da\u26db\u26dc\u26dd\u26de\u26df\u26e0\u26e1\u26e2\u26e3\u26e4\u26e5\u26e6\u26e7\u26e8\u26e9\u26ea\u26eb\u26ec\u26ed\u26ee\u26ef\u26f0\u26f1\u26f2\u26f3\u26f4\u26f5\u26f6\u26f7\u26f8\u26f9\u26fa\u26fb\u26fc\u26fd\u26fe\u26ff\u2700\u2705\u270a\u270b\u2728\u274c\u274e\u2753\u2754\u2755\u2757\u275f\u2760\u2795\u2796\u2797\u27b0\u27bf\u27c7\u27c8\u27c9\u27ca\u27cb\u27cc\u27cd\u27ce\u27cf\u27ec\u27ed\u27ee\u27ef\u2b14\u2b15\u2b16\u2b17\u2b18\u2b19\u2b1a\u2b1b\u2b1c\u2b1d\u2b1e\u2b1f\u2b20\u2b21\u2b22\u2b23\u2b24\u2b25\u2b26\u2b27\u2b28\u2b29\u2b2a\u2b2b\u2b2c\u2b2d\u2b2e\u2b2f\u2b30\u2b31\u2b32\u2b33\u2b34\u2b35\u2b36\u2b37\u2b38\u2b39\u2b3a\u2b3b\u2b3c\u2b3d\u2b3e\u2b3f\u2b40\u2b41\u2b42\u2b43\u2b44\u2b45\u2b46\u2b47\u2b48\u2b49\u2b4a\u2b4b\u2b4c\u2b4d\u2b4e\u2b4f\u2b50\u2b51\u2b52\u2b53\u2b54\u2b55\u2b56\u2b57\u2b58\u2b59\u2b5a\u2b5b\u2b5c\u2b5d\u2b5e\u2b5f\u2b60\u2b61\u2b62\u2b63\u2b64\u2b65\u2b66\u2b67\u2b68\u2b69\u2b6a\u2b6b\u2b6c\u2b6d\u2b6e\u2b6f\u2b70\u2b71\u2b72\u2b73\u2b74\u2b75\u2b76\u2b77\u2b78\u2b79\u2b7a\u2b7b\u2b7c\u2b7d\u2b7e\u2b7f\u2b80\u2b81\u2b82\u2b83\u2b84\u2b85\u2b86\u2b87\u2b88\u2b89\u2b8a\u2b8b\u2b8c\u2b8d\u2b8e\u2b8f\u2b90\u2b91\u2b92\u2b93\u2b94\u2b95\u2b96\u2b97\u2b98\u2b99\u2b9a\u2b9b\u2b9c\u2b9d\u2b9e\u2b9f\u2ba0\u2ba1\u2ba2\u2ba3\u2ba4\u2ba5\u2ba6\u2ba7\u2ba8\u2ba9\u2baa\u2bab\u2bac\u2bad\u2bae\u2baf\u2bb0\u2bb1\u2bb2\u2bb3\u2bb4\u2bb5\u2bb6\u2bb7\u2bb8\u2bb9\u2bba\u2bbb\u2bbc\u2bbd\u2bbe\u2bbf\u2bc0\u2bc1\u2bc2\u2bc3\u2bc4\u2bc5\u2bc6\u2bc7\u2bc8\u2bc9\u2bca\u2bcb\u2bcc\u2bcd\u2bce\u2bcf\u2bd0\u2bd1\u2bd2\u2bd3\u2bd4\u2bd5\u2bd6\u2bd7\u2bd8\u2bd9\u2bda\u2bdb\u2bdc\u2bdd\u2bde\u2bdf\u2be0\u2be1\u2be2\u2be3\u2be4\u2be5\u2be6\u2be7\u2be8\u2be9\u2bea\u2beb\u2bec\u2bed\u2bee\u2bef\u2bf0\u2bf1\u2bf2\u2bf3\u2bf4\u2bf5\u2bf6\u2bf7\u2bf8\u2bf9\u2bfa\u2bfb\u2bfc\u2bfd\u2bfe\u2bff\u2c2f\u2c5f\u2c60\u2c61\u2c62\u2c63\u2c64\u2c65\u2c66\u2c67\u2c68\u2c69\u2c6a\u2c6b\u2c6c\u2c6d\u2c6e\u2c6f\u2c70\u2c71\u2c72\u2c73\u2c74\u2c75\u2c76\u2c77\u2c78\u2c79\u2c7a\u2c7b\u2c7c\u2c7d\u2c7e\u2c7f\u2ceb\u2cec\u2ced\u2cee\u2cef\u2cf0\u2cf1\u2cf2\u2cf3\u2cf4\u2cf5\u2cf6\u2cf7\u2cf8\u2d26\u2d27\u2d28\u2d29\u2d2a\u2d2b\u2d2c\u2d2d\u2d2e\u2d2f\u2d66\u2d67\u2d68\u2d69\u2d6a\u2d6b\u2d6c\u2d6d\u2d6e\u2d70\u2d71\u2d72\u2d73\u2d74\u2d75\u2d76\u2d77\u2d78\u2d79\u2d7a\u2d7b\u2d7c\u2d7d\u2d7e\u2d7f\u2d97\u2d98\u2d99\u2d9a\u2d9b\u2d9c\u2d9d\u2d9e\u2d9f\u2da7\u2daf\u2db7\u2dbf\u2dc7\u2dcf\u2dd7\u2ddf\u2de0\u2de1\u2de2\u2de3\u2de4\u2de5\u2de6\u2de7\u2de8\u2de9\u2dea\u2deb\u2dec\u2ded\u2dee\u2def\u2df0\u2df1\u2df2\u2df3\u2df4\u2df5\u2df6\u2df7\u2df8\u2df9\u2dfa\u2dfb\u2dfc\u2dfd\u2dfe\u2dff\u2e18\u2e19\u2e1a\u2e1b\u2e1e\u2e1f\u2e20\u2e21\u2e22\u2e23\u2e24\u2e25\u2e26\u2e27\u2e28\u2e29\u2e2a\u2e2b\u2e2c\u2e2d\u2e2e\u2e2f\u2e30\u2e31\u2e32\u2e33\u2e34\u2e35\u2e36\u2e37\u2e38\u2e39\u2e3a\u2e3b\u2e3c\u2e3d\u2e3e\u2e3f\u2e40\u2e41\u2e42\u2e43\u2e44\u2e45\u2e46\u2e47\u2e48\u2e49\u2e4a\u2e4b\u2e4c\u2e4d\u2e4e\u2e4f\u2e50\u2e51\u2e52\u2e53\u2e54\u2e55\u2e56\u2e57\u2e58\u2e59\u2e5a\u2e5b\u2e5c\u2e5d\u2e5e\u2e5f\u2e60\u2e61\u2e62\u2e63\u2e64\u2e65\u2e66\u2e67\u2e68\u2e69\u2e6a\u2e6b\u2e6c\u2e6d\u2e6e\u2e6f\u2e70\u2e71\u2e72\u2e73\u2e74\u2e75\u2e76\u2e77\u2e78\u2e79\u2e7a\u2e7b\u2e7c\u2e7d\u2e7e\u2e7f\u2e9a\u2ef4\u2ef5\u2ef6\u2ef7\u2ef8\u2ef9\u2efa\u2efb\u2efc\u2efd\u2efe\u2eff\u2fd6\u2fd7\u2fd8\u2fd9\u2fda\u2fdb\u2fdc\u2fdd\u2fde\u2fdf\u2fe0\u2fe1\u2fe2\u2fe3\u2fe4\u2fe5\u2fe6\u2fe7\u2fe8\u2fe9\u2fea\u2feb\u2fec\u2fed\u2fee\u2fef\u2ffc\u2ffd\u2ffe\u2fff\u3040\u3097\u3098\u3100\u3101\u3102\u3103\u3104\u312d\u312e\u312f\u3130\u318f\u31b8\u31b9\u31ba\u31bb\u31bc\u31bd\u31be\u31bf\u31d0\u31d1\u31d2\u31d3\u31d4\u31d5\u31d6\u31d7\u31d8\u31d9\u31da\u31db\u31dc\u31dd\u31de\u31df\u31e0\u31e1\u31e2\u31e3\u31e4\u31e5\u31e6\u31e7\u31e8\u31e9\u31ea\u31eb\u31ec\u31ed\u31ee\u31ef\u321f\u3244\u3245\u3246\u3247\u3248\u3249\u324a\u324b\u324c\u324d\u324e\u324f\u32ff\u4db6\u4db7\u4db8\u4db9\u4dba\u4dbb\u4dbc\u4dbd\u4dbe\u4dbf\u9fbc\u9fbd\u9fbe\u9fbf\u9fc0\u9fc1\u9fc2\u9fc3\u9fc4\u9fc5\u9fc6\u9fc7\u9fc8\u9fc9\u9fca\u9fcb\u9fcc\u9fcd\u9fce\u9fcf\u9fd0\u9fd1\u9fd2\u9fd3\u9fd4\u9fd5\u9fd6\u9fd7\u9fd8\u9fd9\u9fda\u9fdb\u9fdc\u9fdd\u9fde\u9fdf\u9fe0\u9fe1\u9fe2\u9fe3\u9fe4\u9fe5\u9fe6\u9fe7\u9fe8\u9fe9\u9fea\u9feb\u9fec\u9fed\u9fee\u9fef\u9ff0\u9ff1\u9ff2\u9ff3\u9ff4\u9ff5\u9ff6\u9ff7\u9ff8\u9ff9\u9ffa\u9ffb\u9ffc\u9ffd\u9ffe\u9fff\ua48d\ua48e\ua48f\ua4c7\ua4c8\ua4c9\ua4ca\ua4cb\ua4cc\ua4cd\ua4ce\ua4cf\ua4d0\ua4d1\ua4d2\ua4d3\ua4d4\ua4d5\ua4d6\ua4d7\ua4d8\ua4d9\ua4da\ua4db\ua4dc\ua4dd\ua4de\ua4df\ua4e0\ua4e1\ua4e2\ua4e3\ua4e4\ua4e5\ua4e6\ua4e7\ua4e8\ua4e9\ua4ea\ua4eb\ua4ec\ua4ed\ua4ee\ua4ef\ua4f0\ua4f1\ua4f2\ua4f3\ua4f4\ua4f5\ua4f6\ua4f7\ua4f8\ua4f9\ua4fa\ua4fb\ua4fc\ua4fd\ua4fe\ua4ff\ua500\ua501\ua502\ua503\ua504\ua505\ua506\ua507\ua508\ua509\ua50a\ua50b\ua50c\ua50d\ua50e\ua50f\ua510\ua511\ua512\ua513\ua514\ua515\ua516\ua517\ua518\ua519\ua51a\ua51b\ua51c\ua51d\ua51e\ua51f\ua520\ua521\ua522\ua523\ua524\ua525\ua526\ua527\ua528\ua529\ua52a\ua52b\ua52c\ua52d\ua52e\ua52f\ua530\ua531\ua532\ua533\ua534\ua535\ua536\ua537\ua538\ua539\ua53a\ua53b\ua53c\ua53d\ua53e\ua53f\ua540\ua541\ua542\ua543\ua544\ua545\ua546\ua547\ua548\ua549\ua54a\ua54b\ua54c\ua54d\ua54e\ua54f\ua550\ua551\ua552\ua553\ua554\ua555\ua556\ua557\ua558\ua559\ua55a\ua55b\ua55c\ua55d\ua55e\ua55f\ua560\ua561\ua562\ua563\ua564\ua565\ua566\ua567\ua568\ua569\ua56a\ua56b\ua56c\ua56d\ua56e\ua56f\ua570\ua571\ua572\ua573\ua574\ua575\ua576\ua577\ua578\ua579\ua57a\ua57b\ua57c\ua57d\ua57e\ua57f\ua580\ua581\ua582\ua583\ua584\ua585\ua586\ua587\ua588\ua589\ua58a\ua58b\ua58c\ua58d\ua58e\ua58f\ua590\ua591\ua592\ua593\ua594\ua595\ua596\ua597\ua598\ua599\ua59a\ua59b\ua59c\ua59d\ua59e\ua59f\ua5a0\ua5a1\ua5a2\ua5a3\ua5a4\ua5a5\ua5a6\ua5a7\ua5a8\ua5a9\ua5aa\ua5ab\ua5ac\ua5ad\ua5ae\ua5af\ua5b0\ua5b1\ua5b2\ua5b3\ua5b4\ua5b5\ua5b6\ua5b7\ua5b8\ua5b9\ua5ba\ua5bb\ua5bc\ua5bd\ua5be\ua5bf\ua5c0\ua5c1\ua5c2\ua5c3\ua5c4\ua5c5\ua5c6\ua5c7\ua5c8\ua5c9\ua5ca\ua5cb\ua5cc\ua5cd\ua5ce\ua5cf\ua5d0\ua5d1\ua5d2\ua5d3\ua5d4\ua5d5\ua5d6\ua5d7\ua5d8\ua5d9\ua5da\ua5db\ua5dc\ua5dd\ua5de\ua5df\ua5e0\ua5e1\ua5e2\ua5e3\ua5e4\ua5e5\ua5e6\ua5e7\ua5e8\ua5e9\ua5ea\ua5eb\ua5ec\ua5ed\ua5ee\ua5ef\ua5f0\ua5f1\ua5f2\ua5f3\ua5f4\ua5f5\ua5f6\ua5f7\ua5f8\ua5f9\ua5fa\ua5fb\ua5fc\ua5fd\ua5fe\ua5ff\ua600\ua601\ua602\ua603\ua604\ua605\ua606\ua607\ua608\ua609\ua60a\ua60b\ua60c\ua60d\ua60e\ua60f\ua610\ua611\ua612\ua613\ua614\ua615\ua616\ua617\ua618\ua619\ua61a\ua61b\ua61c\ua61d\ua61e\ua61f\ua620\ua621\ua622\ua623\ua624\ua625\ua626\ua627\ua628\ua629\ua62a\ua62b\ua62c\ua62d\ua62e\ua62f\ua630\ua631\ua632\ua633\ua634\ua635\ua636\ua637\ua638\ua639\ua63a\ua63b\ua63c\ua63d\ua63e\ua63f\ua640\ua641\ua642\ua643\ua644\ua645\ua646\ua647\ua648\ua649\ua64a\ua64b\ua64c\ua64d\ua64e\ua64f\ua650\ua651\ua652\ua653\ua654\ua655\ua656\ua657\ua658\ua659\ua65a\ua65b\ua65c\ua65d\ua65e\ua65f\ua660\ua661\ua662\ua663\ua664\ua665\ua666\ua667\ua668\ua669\ua66a\ua66b\ua66c\ua66d\ua66e\ua66f\ua670\ua671\ua672\ua673\ua674\ua675\ua676\ua677\ua678\ua679\ua67a\ua67b\ua67c\ua67d\ua67e\ua67f\ua680\ua681\ua682\ua683\ua684\ua685\ua686\ua687\ua688\ua689\ua68a\ua68b\ua68c\ua68d\ua68e\ua68f\ua690\ua691\ua692\ua693\ua694\ua695\ua696\ua697\ua698\ua699\ua69a\ua69b\ua69c\ua69d\ua69e\ua69f\ua6a0\ua6a1\ua6a2\ua6a3\ua6a4\ua6a5\ua6a6\ua6a7\ua6a8\ua6a9\ua6aa\ua6ab\ua6ac\ua6ad\ua6ae\ua6af\ua6b0\ua6b1\ua6b2\ua6b3\ua6b4\ua6b5\ua6b6\ua6b7\ua6b8\ua6b9\ua6ba\ua6bb\ua6bc\ua6bd\ua6be\ua6bf\ua6c0\ua6c1\ua6c2\ua6c3\ua6c4\ua6c5\ua6c6\ua6c7\ua6c8\ua6c9\ua6ca\ua6cb\ua6cc\ua6cd\ua6ce\ua6cf\ua6d0\ua6d1\ua6d2\ua6d3\ua6d4\ua6d5\ua6d6\ua6d7\ua6d8\ua6d9\ua6da\ua6db\ua6dc\ua6dd\ua6de\ua6df\ua6e0\ua6e1\ua6e2\ua6e3\ua6e4\ua6e5\ua6e6\ua6e7\ua6e8\ua6e9\ua6ea\ua6eb\ua6ec\ua6ed\ua6ee\ua6ef\ua6f0\ua6f1\ua6f2\ua6f3\ua6f4\ua6f5\ua6f6\ua6f7\ua6f8\ua6f9\ua6fa\ua6fb\ua6fc\ua6fd\ua6fe\ua6ff\ua717\ua718\ua719\ua71a\ua71b\ua71c\ua71d\ua71e\ua71f\ua720\ua721\ua722\ua723\ua724\ua725\ua726\ua727\ua728\ua729\ua72a\ua72b\ua72c\ua72d\ua72e\ua72f\ua730\ua731\ua732\ua733\ua734\ua735\ua736\ua737\ua738\ua739\ua73a\ua73b\ua73c\ua73d\ua73e\ua73f\ua740\ua741\ua742\ua743\ua744\ua745\ua746\ua747\ua748\ua749\ua74a\ua74b\ua74c\ua74d\ua74e\ua74f\ua750\ua751\ua752\ua753\ua754\ua755\ua756\ua757\ua758\ua759\ua75a\ua75b\ua75c\ua75d\ua75e\ua75f\ua760\ua761\ua762\ua763\ua764\ua765\ua766\ua767\ua768\ua769\ua76a\ua76b\ua76c\ua76d\ua76e\ua76f\ua770\ua771\ua772\ua773\ua774\ua775\ua776\ua777\ua778\ua779\ua77a\ua77b\ua77c\ua77d\ua77e\ua77f\ua780\ua781\ua782\ua783\ua784\ua785\ua786\ua787\ua788\ua789\ua78a\ua78b\ua78c\ua78d\ua78e\ua78f\ua790\ua791\ua792\ua793\ua794\ua795\ua796\ua797\ua798\ua799\ua79a\ua79b\ua79c\ua79d\ua79e\ua79f\ua7a0\ua7a1\ua7a2\ua7a3\ua7a4\ua7a5\ua7a6\ua7a7\ua7a8\ua7a9\ua7aa\ua7ab\ua7ac\ua7ad\ua7ae\ua7af\ua7b0\ua7b1\ua7b2\ua7b3\ua7b4\ua7b5\ua7b6\ua7b7\ua7b8\ua7b9\ua7ba\ua7bb\ua7bc\ua7bd\ua7be\ua7bf\ua7c0\ua7c1\ua7c2\ua7c3\ua7c4\ua7c5\ua7c6\ua7c7\ua7c8\ua7c9\ua7ca\ua7cb\ua7cc\ua7cd\ua7ce\ua7cf\ua7d0\ua7d1\ua7d2\ua7d3\ua7d4\ua7d5\ua7d6\ua7d7\ua7d8\ua7d9\ua7da\ua7db\ua7dc\ua7dd\ua7de\ua7df\ua7e0\ua7e1\ua7e2\ua7e3\ua7e4\ua7e5\ua7e6\ua7e7\ua7e8\ua7e9\ua7ea\ua7eb\ua7ec\ua7ed\ua7ee\ua7ef\ua7f0\ua7f1\ua7f2\ua7f3\ua7f4\ua7f5\ua7f6\ua7f7\ua7f8\ua7f9\ua7fa\ua7fb\ua7fc\ua7fd\ua7fe\ua7ff\ua82c\ua82d\ua82e\ua82f\ua830\ua831\ua832\ua833\ua834\ua835\ua836\ua837\ua838\ua839\ua83a\ua83b\ua83c\ua83d\ua83e\ua83f\ua840\ua841\ua842\ua843\ua844\ua845\ua846\ua847\ua848\ua849\ua84a\ua84b\ua84c\ua84d\ua84e\ua84f\ua850\ua851\ua852\ua853\ua854\ua855\ua856\ua857\ua858\ua859\ua85a\ua85b\ua85c\ua85d\ua85e\ua85f\ua860\ua861\ua862\ua863\ua864\ua865\ua866\ua867\ua868\ua869\ua86a\ua86b\ua86c\ua86d\ua86e\ua86f\ua870\ua871\ua872\ua873\ua874\ua875\ua876\ua877\ua878\ua879\ua87a\ua87b\ua87c\ua87d\ua87e\ua87f\ua880\ua881\ua882\ua883\ua884\ua885\ua886\ua887\ua888\ua889\ua88a\ua88b\ua88c\ua88d\ua88e\ua88f\ua890\ua891\ua892\ua893\ua894\ua895\ua896\ua897\ua898\ua899\ua89a\ua89b\ua89c\ua89d\ua89e\ua89f\ua8a0\ua8a1\ua8a2\ua8a3\ua8a4\ua8a5\ua8a6\ua8a7\ua8a8\ua8a9\ua8aa\ua8ab\ua8ac\ua8ad\ua8ae\ua8af\ua8b0\ua8b1\ua8b2\ua8b3\ua8b4\ua8b5\ua8b6\ua8b7\ua8b8\ua8b9\ua8ba\ua8bb\ua8bc\ua8bd\ua8be\ua8bf\ua8c0\ua8c1\ua8c2\ua8c3\ua8c4\ua8c5\ua8c6\ua8c7\ua8c8\ua8c9\ua8ca\ua8cb\ua8cc\ua8cd\ua8ce\ua8cf\ua8d0\ua8d1\ua8d2\ua8d3\ua8d4\ua8d5\ua8d6\ua8d7\ua8d8\ua8d9\ua8da\ua8db\ua8dc\ua8dd\ua8de\ua8df\ua8e0\ua8e1\ua8e2\ua8e3\ua8e4\ua8e5\ua8e6\ua8e7\ua8e8\ua8e9\ua8ea\ua8eb\ua8ec\ua8ed\ua8ee\ua8ef\ua8f0\ua8f1\ua8f2\ua8f3\ua8f4\ua8f5\ua8f6\ua8f7\ua8f8\ua8f9\ua8fa\ua8fb\ua8fc\ua8fd\ua8fe\ua8ff\ua900\ua901\ua902\ua903\ua904\ua905\ua906\ua907\ua908\ua909\ua90a\ua90b\ua90c\ua90d\ua90e\ua90f\ua910\ua911\ua912\ua913\ua914\ua915\ua916\ua917\ua918\ua919\ua91a\ua91b\ua91c\ua91d\ua91e\ua91f\ua920\ua921\ua922\ua923\ua924\ua925\ua926\ua927\ua928\ua929\ua92a\ua92b\ua92c\ua92d\ua92e\ua92f\ua930\ua931\ua932\ua933\ua934\ua935\ua936\ua937\ua938\ua939\ua93a\ua93b\ua93c\ua93d\ua93e\ua93f\ua940\ua941\ua942\ua943\ua944\ua945\ua946\ua947\ua948\ua949\ua94a\ua94b\ua94c\ua94d\ua94e\ua94f\ua950\ua951\ua952\ua953\ua954\ua955\ua956\ua957\ua958\ua959\ua95a\ua95b\ua95c\ua95d\ua95e\ua95f\ua960\ua961\ua962\ua963\ua964\ua965\ua966\ua967\ua968\ua969\ua96a\ua96b\ua96c\ua96d\ua96e\ua96f\ua970\ua971\ua972\ua973\ua974\ua975\ua976\ua977\ua978\ua979\ua97a\ua97b\ua97c\ua97d\ua97e\ua97f\ua980\ua981\ua982\ua983\ua984\ua985\ua986\ua987\ua988\ua989\ua98a\ua98b\ua98c\ua98d\ua98e\ua98f\ua990\ua991\ua992\ua993\ua994\ua995\ua996\ua997\ua998\ua999\ua99a\ua99b\ua99c\ua99d\ua99e\ua99f\ua9a0\ua9a1\ua9a2\ua9a3\ua9a4\ua9a5\ua9a6\ua9a7\ua9a8\ua9a9\ua9aa\ua9ab\ua9ac\ua9ad\ua9ae\ua9af\ua9b0\ua9b1\ua9b2\ua9b3\ua9b4\ua9b5\ua9b6\ua9b7\ua9b8\ua9b9\ua9ba\ua9bb\ua9bc\ua9bd\ua9be\ua9bf\ua9c0\ua9c1\ua9c2\ua9c3\ua9c4\ua9c5\ua9c6\ua9c7\ua9c8\ua9c9\ua9ca\ua9cb\ua9cc\ua9cd\ua9ce\ua9cf\ua9d0\ua9d1\ua9d2\ua9d3\ua9d4\ua9d5\ua9d6\ua9d7\ua9d8\ua9d9\ua9da\ua9db\ua9dc\ua9dd\ua9de\ua9df\ua9e0\ua9e1\ua9e2\ua9e3\ua9e4\ua9e5\ua9e6\ua9e7\ua9e8\ua9e9\ua9ea\ua9eb\ua9ec\ua9ed\ua9ee\ua9ef\ua9f0\ua9f1\ua9f2\ua9f3\ua9f4\ua9f5\ua9f6\ua9f7\ua9f8\ua9f9\ua9fa\ua9fb\ua9fc\ua9fd\ua9fe\ua9ff\uaa00\uaa01\uaa02\uaa03\uaa04\uaa05\uaa06\uaa07\uaa08\uaa09\uaa0a\uaa0b\uaa0c\uaa0d\uaa0e\uaa0f\uaa10\uaa11\uaa12\uaa13\uaa14\uaa15\uaa16\uaa17\uaa18\uaa19\uaa1a\uaa1b\uaa1c\uaa1d\uaa1e\uaa1f\uaa20\uaa21\uaa22\uaa23\uaa24\uaa25\uaa26\uaa27\uaa28\uaa29\uaa2a\uaa2b\uaa2c\uaa2d\uaa2e\uaa2f\uaa30\uaa31\uaa32\uaa33\uaa34\uaa35\uaa36\uaa37\uaa38\uaa39\uaa3a\uaa3b\uaa3c\uaa3d\uaa3e\uaa3f\uaa40\uaa41\uaa42\uaa43\uaa44\uaa45\uaa46\uaa47\uaa48\uaa49\uaa4a\uaa4b\uaa4c\uaa4d\uaa4e\uaa4f\uaa50\uaa51\uaa52\uaa53\uaa54\uaa55\uaa56\uaa57\uaa58\uaa59\uaa5a\uaa5b\uaa5c\uaa5d\uaa5e\uaa5f\uaa60\uaa61\uaa62\uaa63\uaa64\uaa65\uaa66\uaa67\uaa68\uaa69\uaa6a\uaa6b\uaa6c\uaa6d\uaa6e\uaa6f\uaa70\uaa71\uaa72\uaa73\uaa74\uaa75\uaa76\uaa77\uaa78\uaa79\uaa7a\uaa7b\uaa7c\uaa7d\uaa7e\uaa7f\uaa80\uaa81\uaa82\uaa83\uaa84\uaa85\uaa86\uaa87\uaa88\uaa89\uaa8a\uaa8b\uaa8c\uaa8d\uaa8e\uaa8f\uaa90\uaa91\uaa92\uaa93\uaa94\uaa95\uaa96\uaa97\uaa98\uaa99\uaa9a\uaa9b\uaa9c\uaa9d\uaa9e\uaa9f\uaaa0\uaaa1\uaaa2\uaaa3\uaaa4\uaaa5\uaaa6\uaaa7\uaaa8\uaaa9\uaaaa\uaaab\uaaac\uaaad\uaaae\uaaaf\uaab0\uaab1\uaab2\uaab3\uaab4\uaab5\uaab6\uaab7\uaab8\uaab9\uaaba\uaabb\uaabc\uaabd\uaabe\uaabf\uaac0\uaac1\uaac2\uaac3\uaac4\uaac5\uaac6\uaac7\uaac8\uaac9\uaaca\uaacb\uaacc\uaacd\uaace\uaacf\uaad0\uaad1\uaad2\uaad3\uaad4\uaad5\uaad6\uaad7\uaad8\uaad9\uaada\uaadb\uaadc\uaadd\uaade\uaadf\uaae0\uaae1\uaae2\uaae3\uaae4\uaae5\uaae6\uaae7\uaae8\uaae9\uaaea\uaaeb\uaaec\uaaed\uaaee\uaaef\uaaf0\uaaf1\uaaf2\uaaf3\uaaf4\uaaf5\uaaf6\uaaf7\uaaf8\uaaf9\uaafa\uaafb\uaafc\uaafd\uaafe\uaaff\uab00\uab01\uab02\uab03\uab04\uab05\uab06\uab07\uab08\uab09\uab0a\uab0b\uab0c\uab0d\uab0e\uab0f\uab10\uab11\uab12\uab13\uab14\uab15\uab16\uab17\uab18\uab19\uab1a\uab1b\uab1c\uab1d\uab1e\uab1f\uab20\uab21\uab22\uab23\uab24\uab25\uab26\uab27\uab28\uab29\uab2a\uab2b\uab2c\uab2d\uab2e\uab2f\uab30\uab31\uab32\uab33\uab34\uab35\uab36\uab37\uab38\uab39\uab3a\uab3b\uab3c\uab3d\uab3e\uab3f\uab40\uab41\uab42\uab43\uab44\uab45\uab46\uab47\uab48\uab49\uab4a\uab4b\uab4c\uab4d\uab4e\uab4f\uab50\uab51\uab52\uab53\uab54\uab55\uab56\uab57\uab58\uab59\uab5a\uab5b\uab5c\uab5d\uab5e\uab5f\uab60\uab61\uab62\uab63\uab64\uab65\uab66\uab67\uab68\uab69\uab6a\uab6b\uab6c\uab6d\uab6e\uab6f\uab70\uab71\uab72\uab73\uab74\uab75\uab76\uab77\uab78\uab79\uab7a\uab7b\uab7c\uab7d\uab7e\uab7f\uab80\uab81\uab82\uab83\uab84\uab85\uab86\uab87\uab88\uab89\uab8a\uab8b\uab8c\uab8d\uab8e\uab8f\uab90\uab91\uab92\uab93\uab94\uab95\uab96\uab97\uab98\uab99\uab9a\uab9b\uab9c\uab9d\uab9e\uab9f\uaba0\uaba1\uaba2\uaba3\uaba4\uaba5\uaba6\uaba7\uaba8\uaba9\uabaa\uabab\uabac\uabad\uabae\uabaf\uabb0\uabb1\uabb2\uabb3\uabb4\uabb5\uabb6\uabb7\uabb8\uabb9\uabba\uabbb\uabbc\uabbd\uabbe\uabbf\uabc0\uabc1\uabc2\uabc3\uabc4\uabc5\uabc6\uabc7\uabc8\uabc9\uabca\uabcb\uabcc\uabcd\uabce\uabcf\uabd0\uabd1\uabd2\uabd3\uabd4\uabd5\uabd6\uabd7\uabd8\uabd9\uabda\uabdb\uabdc\uabdd\uabde\uabdf\uabe0\uabe1\uabe2\uabe3\uabe4\uabe5\uabe6\uabe7\uabe8\uabe9\uabea\uabeb\uabec\uabed\uabee\uabef\uabf0\uabf1\uabf2\uabf3\uabf4\uabf5\uabf6\uabf7\uabf8\uabf9\uabfa\uabfb\uabfc\uabfd\uabfe\uabff\ud7a4\ud7a5\ud7a6\ud7a7\ud7a8\ud7a9\ud7aa\ud7ab\ud7ac\ud7ad\ud7ae\ud7af\ud7b0\ud7b1\ud7b2\ud7b3\ud7b4\ud7b5\ud7b6\ud7b7\ud7b8\ud7b9\ud7ba\ud7bb\ud7bc\ud7bd\ud7be\ud7bf\ud7c0\ud7c1\ud7c2\ud7c3\ud7c4\ud7c5\ud7c6\ud7c7\ud7c8\ud7c9\ud7ca\ud7cb\ud7cc\ud7cd\ud7ce\ud7cf\ud7d0\ud7d1\ud7d2\ud7d3\ud7d4\ud7d5\ud7d6\ud7d7\ud7d8\ud7d9\ud7da\ud7db\ud7dc\ud7dd\ud7de\ud7df\ud7e0\ud7e1\ud7e2\ud7e3\ud7e4\ud7e5\ud7e6\ud7e7\ud7e8\ud7e9\ud7ea\ud7eb\ud7ec\ud7ed\ud7ee\ud7ef\ud7f0\ud7f1\ud7f2\ud7f3\ud7f4\ud7f5\ud7f6\ud7f7\ud7f8\ud7f9\ud7fa\ud7fb\ud7fc\ud7fd\ud7fe\ud7ff\ufa2e\ufa2f\ufa6b\ufa6c\ufa6d\ufa6e\ufa6f\ufada\ufadb\ufadc\ufadd\ufade\ufadf\ufae0\ufae1\ufae2\ufae3\ufae4\ufae5\ufae6\ufae7\ufae8\ufae9\ufaea\ufaeb\ufaec\ufaed\ufaee\ufaef\ufaf0\ufaf1\ufaf2\ufaf3\ufaf4\ufaf5\ufaf6\ufaf7\ufaf8\ufaf9\ufafa\ufafb\ufafc\ufafd\ufafe\ufaff\ufb07\ufb08\ufb09\ufb0a\ufb0b\ufb0c\ufb0d\ufb0e\ufb0f\ufb10\ufb11\ufb12\ufb18\ufb19\ufb1a\ufb1b\ufb1c\ufb37\ufb3d\ufb3f\ufb42\ufb45\ufbb2\ufbb3\ufbb4\ufbb5\ufbb6\ufbb7\ufbb8\ufbb9\ufbba\ufbbb\ufbbc\ufbbd\ufbbe\ufbbf\ufbc0\ufbc1\ufbc2\ufbc3\ufbc4\ufbc5\ufbc6\ufbc7\ufbc8\ufbc9\ufbca\ufbcb\ufbcc\ufbcd\ufbce\ufbcf\ufbd0\ufbd1\ufbd2\ufd40\ufd41\ufd42\ufd43\ufd44\ufd45\ufd46\ufd47\ufd48\ufd49\ufd4a\ufd4b\ufd4c\ufd4d\ufd4e\ufd4f\ufd90\ufd91\ufdc8\ufdc9\ufdca\ufdcb\ufdcc\ufdcd\ufdce\ufdcf\ufdd0\ufdd1\ufdd2\ufdd3\ufdd4\ufdd5\ufdd6\ufdd7\ufdd8\ufdd9\ufdda\ufddb\ufddc\ufddd\ufdde\ufddf\ufde0\ufde1\ufde2\ufde3\ufde4\ufde5\ufde6\ufde7\ufde8\ufde9\ufdea\ufdeb\ufdec\ufded\ufdee\ufdef\ufdfe\ufdff\ufe1a\ufe1b\ufe1c\ufe1d\ufe1e\ufe1f\ufe24\ufe25\ufe26\ufe27\ufe28\ufe29\ufe2a\ufe2b\ufe2c\ufe2d\ufe2e\ufe2f\ufe53\ufe67\ufe6c\ufe6d\ufe6e\ufe6f\ufe75\ufefd\ufefe\uff00\uffbf\uffc0\uffc1\uffc8\uffc9\uffd0\uffd1\uffd8\uffd9\uffdd\uffde\uffdf\uffe7\uffef\ufff0\ufff1\ufff2\ufff3\ufff4\ufff5\ufff6\ufff7\ufff8\ufffe'
+
+Co = u'\ue000\ue001\ue002\ue003\ue004\ue005\ue006\ue007\ue008\ue009\ue00a\ue00b\ue00c\ue00d\ue00e\ue00f\ue010\ue011\ue012\ue013\ue014\ue015\ue016\ue017\ue018\ue019\ue01a\ue01b\ue01c\ue01d\ue01e\ue01f\ue020\ue021\ue022\ue023\ue024\ue025\ue026\ue027\ue028\ue029\ue02a\ue02b\ue02c\ue02d\ue02e\ue02f\ue030\ue031\ue032\ue033\ue034\ue035\ue036\ue037\ue038\ue039\ue03a\ue03b\ue03c\ue03d\ue03e\ue03f\ue040\ue041\ue042\ue043\ue044\ue045\ue046\ue047\ue048\ue049\ue04a\ue04b\ue04c\ue04d\ue04e\ue04f\ue050\ue051\ue052\ue053\ue054\ue055\ue056\ue057\ue058\ue059\ue05a\ue05b\ue05c\ue05d\ue05e\ue05f\ue060\ue061\ue062\ue063\ue064\ue065\ue066\ue067\ue068\ue069\ue06a\ue06b\ue06c\ue06d\ue06e\ue06f\ue070\ue071\ue072\ue073\ue074\ue075\ue076\ue077\ue078\ue079\ue07a\ue07b\ue07c\ue07d\ue07e\ue07f\ue080\ue081\ue082\ue083\ue084\ue085\ue086\ue087\ue088\ue089\ue08a\ue08b\ue08c\ue08d\ue08e\ue08f\ue090\ue091\ue092\ue093\ue094\ue095\ue096\ue097\ue098\ue099\ue09a\ue09b\ue09c\ue09d\ue09e\ue09f\ue0a0\ue0a1\ue0a2\ue0a3\ue0a4\ue0a5\ue0a6\ue0a7\ue0a8\ue0a9\ue0aa\ue0ab\ue0ac\ue0ad\ue0ae\ue0af\ue0b0\ue0b1\ue0b2\ue0b3\ue0b4\ue0b5\ue0b6\ue0b7\ue0b8\ue0b9\ue0ba\ue0bb\ue0bc\ue0bd\ue0be\ue0bf\ue0c0\ue0c1\ue0c2\ue0c3\ue0c4\ue0c5\ue0c6\ue0c7\ue0c8\ue0c9\ue0ca\ue0cb\ue0cc\ue0cd\ue0ce\ue0cf\ue0d0\ue0d1\ue0d2\ue0d3\ue0d4\ue0d5\ue0d6\ue0d7\ue0d8\ue0d9\ue0da\ue0db\ue0dc\ue0dd\ue0de\ue0df\ue0e0\ue0e1\ue0e2\ue0e3\ue0e4\ue0e5\ue0e6\ue0e7\ue0e8\ue0e9\ue0ea\ue0eb\ue0ec\ue0ed\ue0ee\ue0ef\ue0f0\ue0f1\ue0f2\ue0f3\ue0f4\ue0f5\ue0f6\ue0f7\ue0f8\ue0f9\ue0fa\ue0fb\ue0fc\ue0fd\ue0fe\ue0ff\ue100\ue101\ue102\ue103\ue104\ue105\ue106\ue107\ue108\ue109\ue10a\ue10b\ue10c\ue10d\ue10e\ue10f\ue110\ue111\ue112\ue113\ue114\ue115\ue116\ue117\ue118\ue119\ue11a\ue11b\ue11c\ue11d\ue11e\ue11f\ue120\ue121\ue122\ue123\ue124\ue125\ue126\ue127\ue128\ue129\ue12a\ue12b\ue12c\ue12d\ue12e\ue12f\ue130\ue131\ue132\ue133\ue134\ue135\ue136\ue137\ue138\ue139\ue13a\ue13b\ue13c\ue13d\ue13e\ue13f\ue140\ue141\ue142\ue143\ue144\ue145\ue146\ue147\ue148\ue149\ue14a\ue14b\ue14c\ue14d\ue14e\ue14f\ue150\ue151\ue152\ue153\ue154\ue155\ue156\ue157\ue158\ue159\ue15a\ue15b\ue15c\ue15d\ue15e\ue15f\ue160\ue161\ue162\ue163\ue164\ue165\ue166\ue167\ue168\ue169\ue16a\ue16b\ue16c\ue16d\ue16e\ue16f\ue170\ue171\ue172\ue173\ue174\ue175\ue176\ue177\ue178\ue179\ue17a\ue17b\ue17c\ue17d\ue17e\ue17f\ue180\ue181\ue182\ue183\ue184\ue185\ue186\ue187\ue188\ue189\ue18a\ue18b\ue18c\ue18d\ue18e\ue18f\ue190\ue191\ue192\ue193\ue194\ue195\ue196\ue197\ue198\ue199\ue19a\ue19b\ue19c\ue19d\ue19e\ue19f\ue1a0\ue1a1\ue1a2\ue1a3\ue1a4\ue1a5\ue1a6\ue1a7\ue1a8\ue1a9\ue1aa\ue1ab\ue1ac\ue1ad\ue1ae\ue1af\ue1b0\ue1b1\ue1b2\ue1b3\ue1b4\ue1b5\ue1b6\ue1b7\ue1b8\ue1b9\ue1ba\ue1bb\ue1bc\ue1bd\ue1be\ue1bf\ue1c0\ue1c1\ue1c2\ue1c3\ue1c4\ue1c5\ue1c6\ue1c7\ue1c8\ue1c9\ue1ca\ue1cb\ue1cc\ue1cd\ue1ce\ue1cf\ue1d0\ue1d1\ue1d2\ue1d3\ue1d4\ue1d5\ue1d6\ue1d7\ue1d8\ue1d9\ue1da\ue1db\ue1dc\ue1dd\ue1de\ue1df\ue1e0\ue1e1\ue1e2\ue1e3\ue1e4\ue1e5\ue1e6\ue1e7\ue1e8\ue1e9\ue1ea\ue1eb\ue1ec\ue1ed\ue1ee\ue1ef\ue1f0\ue1f1\ue1f2\ue1f3\ue1f4\ue1f5\ue1f6\ue1f7\ue1f8\ue1f9\ue1fa\ue1fb\ue1fc\ue1fd\ue1fe\ue1ff\ue200\ue201\ue202\ue203\ue204\ue205\ue206\ue207\ue208\ue209\ue20a\ue20b\ue20c\ue20d\ue20e\ue20f\ue210\ue211\ue212\ue213\ue214\ue215\ue216\ue217\ue218\ue219\ue21a\ue21b\ue21c\ue21d\ue21e\ue21f\ue220\ue221\ue222\ue223\ue224\ue225\ue226\ue227\ue228\ue229\ue22a\ue22b\ue22c\ue22d\ue22e\ue22f\ue230\ue231\ue232\ue233\ue234\ue235\ue236\ue237\ue238\ue239\ue23a\ue23b\ue23c\ue23d\ue23e\ue23f\ue240\ue241\ue242\ue243\ue244\ue245\ue246\ue247\ue248\ue249\ue24a\ue24b\ue24c\ue24d\ue24e\ue24f\ue250\ue251\ue252\ue253\ue254\ue255\ue256\ue257\ue258\ue259\ue25a\ue25b\ue25c\ue25d\ue25e\ue25f\ue260\ue261\ue262\ue263\ue264\ue265\ue266\ue267\ue268\ue269\ue26a\ue26b\ue26c\ue26d\ue26e\ue26f\ue270\ue271\ue272\ue273\ue274\ue275\ue276\ue277\ue278\ue279\ue27a\ue27b\ue27c\ue27d\ue27e\ue27f\ue280\ue281\ue282\ue283\ue284\ue285\ue286\ue287\ue288\ue289\ue28a\ue28b\ue28c\ue28d\ue28e\ue28f\ue290\ue291\ue292\ue293\ue294\ue295\ue296\ue297\ue298\ue299\ue29a\ue29b\ue29c\ue29d\ue29e\ue29f\ue2a0\ue2a1\ue2a2\ue2a3\ue2a4\ue2a5\ue2a6\ue2a7\ue2a8\ue2a9\ue2aa\ue2ab\ue2ac\ue2ad\ue2ae\ue2af\ue2b0\ue2b1\ue2b2\ue2b3\ue2b4\ue2b5\ue2b6\ue2b7\ue2b8\ue2b9\ue2ba\ue2bb\ue2bc\ue2bd\ue2be\ue2bf\ue2c0\ue2c1\ue2c2\ue2c3\ue2c4\ue2c5\ue2c6\ue2c7\ue2c8\ue2c9\ue2ca\ue2cb\ue2cc\ue2cd\ue2ce\ue2cf\ue2d0\ue2d1\ue2d2\ue2d3\ue2d4\ue2d5\ue2d6\ue2d7\ue2d8\ue2d9\ue2da\ue2db\ue2dc\ue2dd\ue2de\ue2df\ue2e0\ue2e1\ue2e2\ue2e3\ue2e4\ue2e5\ue2e6\ue2e7\ue2e8\ue2e9\ue2ea\ue2eb\ue2ec\ue2ed\ue2ee\ue2ef\ue2f0\ue2f1\ue2f2\ue2f3\ue2f4\ue2f5\ue2f6\ue2f7\ue2f8\ue2f9\ue2fa\ue2fb\ue2fc\ue2fd\ue2fe\ue2ff\ue300\ue301\ue302\ue303\ue304\ue305\ue306\ue307\ue308\ue309\ue30a\ue30b\ue30c\ue30d\ue30e\ue30f\ue310\ue311\ue312\ue313\ue314\ue315\ue316\ue317\ue318\ue319\ue31a\ue31b\ue31c\ue31d\ue31e\ue31f\ue320\ue321\ue322\ue323\ue324\ue325\ue326\ue327\ue328\ue329\ue32a\ue32b\ue32c\ue32d\ue32e\ue32f\ue330\ue331\ue332\ue333\ue334\ue335\ue336\ue337\ue338\ue339\ue33a\ue33b\ue33c\ue33d\ue33e\ue33f\ue340\ue341\ue342\ue343\ue344\ue345\ue346\ue347\ue348\ue349\ue34a\ue34b\ue34c\ue34d\ue34e\ue34f\ue350\ue351\ue352\ue353\ue354\ue355\ue356\ue357\ue358\ue359\ue35a\ue35b\ue35c\ue35d\ue35e\ue35f\ue360\ue361\ue362\ue363\ue364\ue365\ue366\ue367\ue368\ue369\ue36a\ue36b\ue36c\ue36d\ue36e\ue36f\ue370\ue371\ue372\ue373\ue374\ue375\ue376\ue377\ue378\ue379\ue37a\ue37b\ue37c\ue37d\ue37e\ue37f\ue380\ue381\ue382\ue383\ue384\ue385\ue386\ue387\ue388\ue389\ue38a\ue38b\ue38c\ue38d\ue38e\ue38f\ue390\ue391\ue392\ue393\ue394\ue395\ue396\ue397\ue398\ue399\ue39a\ue39b\ue39c\ue39d\ue39e\ue39f\ue3a0\ue3a1\ue3a2\ue3a3\ue3a4\ue3a5\ue3a6\ue3a7\ue3a8\ue3a9\ue3aa\ue3ab\ue3ac\ue3ad\ue3ae\ue3af\ue3b0\ue3b1\ue3b2\ue3b3\ue3b4\ue3b5\ue3b6\ue3b7\ue3b8\ue3b9\ue3ba\ue3bb\ue3bc\ue3bd\ue3be\ue3bf\ue3c0\ue3c1\ue3c2\ue3c3\ue3c4\ue3c5\ue3c6\ue3c7\ue3c8\ue3c9\ue3ca\ue3cb\ue3cc\ue3cd\ue3ce\ue3cf\ue3d0\ue3d1\ue3d2\ue3d3\ue3d4\ue3d5\ue3d6\ue3d7\ue3d8\ue3d9\ue3da\ue3db\ue3dc\ue3dd\ue3de\ue3df\ue3e0\ue3e1\ue3e2\ue3e3\ue3e4\ue3e5\ue3e6\ue3e7\ue3e8\ue3e9\ue3ea\ue3eb\ue3ec\ue3ed\ue3ee\ue3ef\ue3f0\ue3f1\ue3f2\ue3f3\ue3f4\ue3f5\ue3f6\ue3f7\ue3f8\ue3f9\ue3fa\ue3fb\ue3fc\ue3fd\ue3fe\ue3ff\ue400\ue401\ue402\ue403\ue404\ue405\ue406\ue407\ue408\ue409\ue40a\ue40b\ue40c\ue40d\ue40e\ue40f\ue410\ue411\ue412\ue413\ue414\ue415\ue416\ue417\ue418\ue419\ue41a\ue41b\ue41c\ue41d\ue41e\ue41f\ue420\ue421\ue422\ue423\ue424\ue425\ue426\ue427\ue428\ue429\ue42a\ue42b\ue42c\ue42d\ue42e\ue42f\ue430\ue431\ue432\ue433\ue434\ue435\ue436\ue437\ue438\ue439\ue43a\ue43b\ue43c\ue43d\ue43e\ue43f\ue440\ue441\ue442\ue443\ue444\ue445\ue446\ue447\ue448\ue449\ue44a\ue44b\ue44c\ue44d\ue44e\ue44f\ue450\ue451\ue452\ue453\ue454\ue455\ue456\ue457\ue458\ue459\ue45a\ue45b\ue45c\ue45d\ue45e\ue45f\ue460\ue461\ue462\ue463\ue464\ue465\ue466\ue467\ue468\ue469\ue46a\ue46b\ue46c\ue46d\ue46e\ue46f\ue470\ue471\ue472\ue473\ue474\ue475\ue476\ue477\ue478\ue479\ue47a\ue47b\ue47c\ue47d\ue47e\ue47f\ue480\ue481\ue482\ue483\ue484\ue485\ue486\ue487\ue488\ue489\ue48a\ue48b\ue48c\ue48d\ue48e\ue48f\ue490\ue491\ue492\ue493\ue494\ue495\ue496\ue497\ue498\ue499\ue49a\ue49b\ue49c\ue49d\ue49e\ue49f\ue4a0\ue4a1\ue4a2\ue4a3\ue4a4\ue4a5\ue4a6\ue4a7\ue4a8\ue4a9\ue4aa\ue4ab\ue4ac\ue4ad\ue4ae\ue4af\ue4b0\ue4b1\ue4b2\ue4b3\ue4b4\ue4b5\ue4b6\ue4b7\ue4b8\ue4b9\ue4ba\ue4bb\ue4bc\ue4bd\ue4be\ue4bf\ue4c0\ue4c1\ue4c2\ue4c3\ue4c4\ue4c5\ue4c6\ue4c7\ue4c8\ue4c9\ue4ca\ue4cb\ue4cc\ue4cd\ue4ce\ue4cf\ue4d0\ue4d1\ue4d2\ue4d3\ue4d4\ue4d5\ue4d6\ue4d7\ue4d8\ue4d9\ue4da\ue4db\ue4dc\ue4dd\ue4de\ue4df\ue4e0\ue4e1\ue4e2\ue4e3\ue4e4\ue4e5\ue4e6\ue4e7\ue4e8\ue4e9\ue4ea\ue4eb\ue4ec\ue4ed\ue4ee\ue4ef\ue4f0\ue4f1\ue4f2\ue4f3\ue4f4\ue4f5\ue4f6\ue4f7\ue4f8\ue4f9\ue4fa\ue4fb\ue4fc\ue4fd\ue4fe\ue4ff\ue500\ue501\ue502\ue503\ue504\ue505\ue506\ue507\ue508\ue509\ue50a\ue50b\ue50c\ue50d\ue50e\ue50f\ue510\ue511\ue512\ue513\ue514\ue515\ue516\ue517\ue518\ue519\ue51a\ue51b\ue51c\ue51d\ue51e\ue51f\ue520\ue521\ue522\ue523\ue524\ue525\ue526\ue527\ue528\ue529\ue52a\ue52b\ue52c\ue52d\ue52e\ue52f\ue530\ue531\ue532\ue533\ue534\ue535\ue536\ue537\ue538\ue539\ue53a\ue53b\ue53c\ue53d\ue53e\ue53f\ue540\ue541\ue542\ue543\ue544\ue545\ue546\ue547\ue548\ue549\ue54a\ue54b\ue54c\ue54d\ue54e\ue54f\ue550\ue551\ue552\ue553\ue554\ue555\ue556\ue557\ue558\ue559\ue55a\ue55b\ue55c\ue55d\ue55e\ue55f\ue560\ue561\ue562\ue563\ue564\ue565\ue566\ue567\ue568\ue569\ue56a\ue56b\ue56c\ue56d\ue56e\ue56f\ue570\ue571\ue572\ue573\ue574\ue575\ue576\ue577\ue578\ue579\ue57a\ue57b\ue57c\ue57d\ue57e\ue57f\ue580\ue581\ue582\ue583\ue584\ue585\ue586\ue587\ue588\ue589\ue58a\ue58b\ue58c\ue58d\ue58e\ue58f\ue590\ue591\ue592\ue593\ue594\ue595\ue596\ue597\ue598\ue599\ue59a\ue59b\ue59c\ue59d\ue59e\ue59f\ue5a0\ue5a1\ue5a2\ue5a3\ue5a4\ue5a5\ue5a6\ue5a7\ue5a8\ue5a9\ue5aa\ue5ab\ue5ac\ue5ad\ue5ae\ue5af\ue5b0\ue5b1\ue5b2\ue5b3\ue5b4\ue5b5\ue5b6\ue5b7\ue5b8\ue5b9\ue5ba\ue5bb\ue5bc\ue5bd\ue5be\ue5bf\ue5c0\ue5c1\ue5c2\ue5c3\ue5c4\ue5c5\ue5c6\ue5c7\ue5c8\ue5c9\ue5ca\ue5cb\ue5cc\ue5cd\ue5ce\ue5cf\ue5d0\ue5d1\ue5d2\ue5d3\ue5d4\ue5d5\ue5d6\ue5d7\ue5d8\ue5d9\ue5da\ue5db\ue5dc\ue5dd\ue5de\ue5df\ue5e0\ue5e1\ue5e2\ue5e3\ue5e4\ue5e5\ue5e6\ue5e7\ue5e8\ue5e9\ue5ea\ue5eb\ue5ec\ue5ed\ue5ee\ue5ef\ue5f0\ue5f1\ue5f2\ue5f3\ue5f4\ue5f5\ue5f6\ue5f7\ue5f8\ue5f9\ue5fa\ue5fb\ue5fc\ue5fd\ue5fe\ue5ff\ue600\ue601\ue602\ue603\ue604\ue605\ue606\ue607\ue608\ue609\ue60a\ue60b\ue60c\ue60d\ue60e\ue60f\ue610\ue611\ue612\ue613\ue614\ue615\ue616\ue617\ue618\ue619\ue61a\ue61b\ue61c\ue61d\ue61e\ue61f\ue620\ue621\ue622\ue623\ue624\ue625\ue626\ue627\ue628\ue629\ue62a\ue62b\ue62c\ue62d\ue62e\ue62f\ue630\ue631\ue632\ue633\ue634\ue635\ue636\ue637\ue638\ue639\ue63a\ue63b\ue63c\ue63d\ue63e\ue63f\ue640\ue641\ue642\ue643\ue644\ue645\ue646\ue647\ue648\ue649\ue64a\ue64b\ue64c\ue64d\ue64e\ue64f\ue650\ue651\ue652\ue653\ue654\ue655\ue656\ue657\ue658\ue659\ue65a\ue65b\ue65c\ue65d\ue65e\ue65f\ue660\ue661\ue662\ue663\ue664\ue665\ue666\ue667\ue668\ue669\ue66a\ue66b\ue66c\ue66d\ue66e\ue66f\ue670\ue671\ue672\ue673\ue674\ue675\ue676\ue677\ue678\ue679\ue67a\ue67b\ue67c\ue67d\ue67e\ue67f\ue680\ue681\ue682\ue683\ue684\ue685\ue686\ue687\ue688\ue689\ue68a\ue68b\ue68c\ue68d\ue68e\ue68f\ue690\ue691\ue692\ue693\ue694\ue695\ue696\ue697\ue698\ue699\ue69a\ue69b\ue69c\ue69d\ue69e\ue69f\ue6a0\ue6a1\ue6a2\ue6a3\ue6a4\ue6a5\ue6a6\ue6a7\ue6a8\ue6a9\ue6aa\ue6ab\ue6ac\ue6ad\ue6ae\ue6af\ue6b0\ue6b1\ue6b2\ue6b3\ue6b4\ue6b5\ue6b6\ue6b7\ue6b8\ue6b9\ue6ba\ue6bb\ue6bc\ue6bd\ue6be\ue6bf\ue6c0\ue6c1\ue6c2\ue6c3\ue6c4\ue6c5\ue6c6\ue6c7\ue6c8\ue6c9\ue6ca\ue6cb\ue6cc\ue6cd\ue6ce\ue6cf\ue6d0\ue6d1\ue6d2\ue6d3\ue6d4\ue6d5\ue6d6\ue6d7\ue6d8\ue6d9\ue6da\ue6db\ue6dc\ue6dd\ue6de\ue6df\ue6e0\ue6e1\ue6e2\ue6e3\ue6e4\ue6e5\ue6e6\ue6e7\ue6e8\ue6e9\ue6ea\ue6eb\ue6ec\ue6ed\ue6ee\ue6ef\ue6f0\ue6f1\ue6f2\ue6f3\ue6f4\ue6f5\ue6f6\ue6f7\ue6f8\ue6f9\ue6fa\ue6fb\ue6fc\ue6fd\ue6fe\ue6ff\ue700\ue701\ue702\ue703\ue704\ue705\ue706\ue707\ue708\ue709\ue70a\ue70b\ue70c\ue70d\ue70e\ue70f\ue710\ue711\ue712\ue713\ue714\ue715\ue716\ue717\ue718\ue719\ue71a\ue71b\ue71c\ue71d\ue71e\ue71f\ue720\ue721\ue722\ue723\ue724\ue725\ue726\ue727\ue728\ue729\ue72a\ue72b\ue72c\ue72d\ue72e\ue72f\ue730\ue731\ue732\ue733\ue734\ue735\ue736\ue737\ue738\ue739\ue73a\ue73b\ue73c\ue73d\ue73e\ue73f\ue740\ue741\ue742\ue743\ue744\ue745\ue746\ue747\ue748\ue749\ue74a\ue74b\ue74c\ue74d\ue74e\ue74f\ue750\ue751\ue752\ue753\ue754\ue755\ue756\ue757\ue758\ue759\ue75a\ue75b\ue75c\ue75d\ue75e\ue75f\ue760\ue761\ue762\ue763\ue764\ue765\ue766\ue767\ue768\ue769\ue76a\ue76b\ue76c\ue76d\ue76e\ue76f\ue770\ue771\ue772\ue773\ue774\ue775\ue776\ue777\ue778\ue779\ue77a\ue77b\ue77c\ue77d\ue77e\ue77f\ue780\ue781\ue782\ue783\ue784\ue785\ue786\ue787\ue788\ue789\ue78a\ue78b\ue78c\ue78d\ue78e\ue78f\ue790\ue791\ue792\ue793\ue794\ue795\ue796\ue797\ue798\ue799\ue79a\ue79b\ue79c\ue79d\ue79e\ue79f\ue7a0\ue7a1\ue7a2\ue7a3\ue7a4\ue7a5\ue7a6\ue7a7\ue7a8\ue7a9\ue7aa\ue7ab\ue7ac\ue7ad\ue7ae\ue7af\ue7b0\ue7b1\ue7b2\ue7b3\ue7b4\ue7b5\ue7b6\ue7b7\ue7b8\ue7b9\ue7ba\ue7bb\ue7bc\ue7bd\ue7be\ue7bf\ue7c0\ue7c1\ue7c2\ue7c3\ue7c4\ue7c5\ue7c6\ue7c7\ue7c8\ue7c9\ue7ca\ue7cb\ue7cc\ue7cd\ue7ce\ue7cf\ue7d0\ue7d1\ue7d2\ue7d3\ue7d4\ue7d5\ue7d6\ue7d7\ue7d8\ue7d9\ue7da\ue7db\ue7dc\ue7dd\ue7de\ue7df\ue7e0\ue7e1\ue7e2\ue7e3\ue7e4\ue7e5\ue7e6\ue7e7\ue7e8\ue7e9\ue7ea\ue7eb\ue7ec\ue7ed\ue7ee\ue7ef\ue7f0\ue7f1\ue7f2\ue7f3\ue7f4\ue7f5\ue7f6\ue7f7\ue7f8\ue7f9\ue7fa\ue7fb\ue7fc\ue7fd\ue7fe\ue7ff\ue800\ue801\ue802\ue803\ue804\ue805\ue806\ue807\ue808\ue809\ue80a\ue80b\ue80c\ue80d\ue80e\ue80f\ue810\ue811\ue812\ue813\ue814\ue815\ue816\ue817\ue818\ue819\ue81a\ue81b\ue81c\ue81d\ue81e\ue81f\ue820\ue821\ue822\ue823\ue824\ue825\ue826\ue827\ue828\ue829\ue82a\ue82b\ue82c\ue82d\ue82e\ue82f\ue830\ue831\ue832\ue833\ue834\ue835\ue836\ue837\ue838\ue839\ue83a\ue83b\ue83c\ue83d\ue83e\ue83f\ue840\ue841\ue842\ue843\ue844\ue845\ue846\ue847\ue848\ue849\ue84a\ue84b\ue84c\ue84d\ue84e\ue84f\ue850\ue851\ue852\ue853\ue854\ue855\ue856\ue857\ue858\ue859\ue85a\ue85b\ue85c\ue85d\ue85e\ue85f\ue860\ue861\ue862\ue863\ue864\ue865\ue866\ue867\ue868\ue869\ue86a\ue86b\ue86c\ue86d\ue86e\ue86f\ue870\ue871\ue872\ue873\ue874\ue875\ue876\ue877\ue878\ue879\ue87a\ue87b\ue87c\ue87d\ue87e\ue87f\ue880\ue881\ue882\ue883\ue884\ue885\ue886\ue887\ue888\ue889\ue88a\ue88b\ue88c\ue88d\ue88e\ue88f\ue890\ue891\ue892\ue893\ue894\ue895\ue896\ue897\ue898\ue899\ue89a\ue89b\ue89c\ue89d\ue89e\ue89f\ue8a0\ue8a1\ue8a2\ue8a3\ue8a4\ue8a5\ue8a6\ue8a7\ue8a8\ue8a9\ue8aa\ue8ab\ue8ac\ue8ad\ue8ae\ue8af\ue8b0\ue8b1\ue8b2\ue8b3\ue8b4\ue8b5\ue8b6\ue8b7\ue8b8\ue8b9\ue8ba\ue8bb\ue8bc\ue8bd\ue8be\ue8bf\ue8c0\ue8c1\ue8c2\ue8c3\ue8c4\ue8c5\ue8c6\ue8c7\ue8c8\ue8c9\ue8ca\ue8cb\ue8cc\ue8cd\ue8ce\ue8cf\ue8d0\ue8d1\ue8d2\ue8d3\ue8d4\ue8d5\ue8d6\ue8d7\ue8d8\ue8d9\ue8da\ue8db\ue8dc\ue8dd\ue8de\ue8df\ue8e0\ue8e1\ue8e2\ue8e3\ue8e4\ue8e5\ue8e6\ue8e7\ue8e8\ue8e9\ue8ea\ue8eb\ue8ec\ue8ed\ue8ee\ue8ef\ue8f0\ue8f1\ue8f2\ue8f3\ue8f4\ue8f5\ue8f6\ue8f7\ue8f8\ue8f9\ue8fa\ue8fb\ue8fc\ue8fd\ue8fe\ue8ff\ue900\ue901\ue902\ue903\ue904\ue905\ue906\ue907\ue908\ue909\ue90a\ue90b\ue90c\ue90d\ue90e\ue90f\ue910\ue911\ue912\ue913\ue914\ue915\ue916\ue917\ue918\ue919\ue91a\ue91b\ue91c\ue91d\ue91e\ue91f\ue920\ue921\ue922\ue923\ue924\ue925\ue926\ue927\ue928\ue929\ue92a\ue92b\ue92c\ue92d\ue92e\ue92f\ue930\ue931\ue932\ue933\ue934\ue935\ue936\ue937\ue938\ue939\ue93a\ue93b\ue93c\ue93d\ue93e\ue93f\ue940\ue941\ue942\ue943\ue944\ue945\ue946\ue947\ue948\ue949\ue94a\ue94b\ue94c\ue94d\ue94e\ue94f\ue950\ue951\ue952\ue953\ue954\ue955\ue956\ue957\ue958\ue959\ue95a\ue95b\ue95c\ue95d\ue95e\ue95f\ue960\ue961\ue962\ue963\ue964\ue965\ue966\ue967\ue968\ue969\ue96a\ue96b\ue96c\ue96d\ue96e\ue96f\ue970\ue971\ue972\ue973\ue974\ue975\ue976\ue977\ue978\ue979\ue97a\ue97b\ue97c\ue97d\ue97e\ue97f\ue980\ue981\ue982\ue983\ue984\ue985\ue986\ue987\ue988\ue989\ue98a\ue98b\ue98c\ue98d\ue98e\ue98f\ue990\ue991\ue992\ue993\ue994\ue995\ue996\ue997\ue998\ue999\ue99a\ue99b\ue99c\ue99d\ue99e\ue99f\ue9a0\ue9a1\ue9a2\ue9a3\ue9a4\ue9a5\ue9a6\ue9a7\ue9a8\ue9a9\ue9aa\ue9ab\ue9ac\ue9ad\ue9ae\ue9af\ue9b0\ue9b1\ue9b2\ue9b3\ue9b4\ue9b5\ue9b6\ue9b7\ue9b8\ue9b9\ue9ba\ue9bb\ue9bc\ue9bd\ue9be\ue9bf\ue9c0\ue9c1\ue9c2\ue9c3\ue9c4\ue9c5\ue9c6\ue9c7\ue9c8\ue9c9\ue9ca\ue9cb\ue9cc\ue9cd\ue9ce\ue9cf\ue9d0\ue9d1\ue9d2\ue9d3\ue9d4\ue9d5\ue9d6\ue9d7\ue9d8\ue9d9\ue9da\ue9db\ue9dc\ue9dd\ue9de\ue9df\ue9e0\ue9e1\ue9e2\ue9e3\ue9e4\ue9e5\ue9e6\ue9e7\ue9e8\ue9e9\ue9ea\ue9eb\ue9ec\ue9ed\ue9ee\ue9ef\ue9f0\ue9f1\ue9f2\ue9f3\ue9f4\ue9f5\ue9f6\ue9f7\ue9f8\ue9f9\ue9fa\ue9fb\ue9fc\ue9fd\ue9fe\ue9ff\uea00\uea01\uea02\uea03\uea04\uea05\uea06\uea07\uea08\uea09\uea0a\uea0b\uea0c\uea0d\uea0e\uea0f\uea10\uea11\uea12\uea13\uea14\uea15\uea16\uea17\uea18\uea19\uea1a\uea1b\uea1c\uea1d\uea1e\uea1f\uea20\uea21\uea22\uea23\uea24\uea25\uea26\uea27\uea28\uea29\uea2a\uea2b\uea2c\uea2d\uea2e\uea2f\uea30\uea31\uea32\uea33\uea34\uea35\uea36\uea37\uea38\uea39\uea3a\uea3b\uea3c\uea3d\uea3e\uea3f\uea40\uea41\uea42\uea43\uea44\uea45\uea46\uea47\uea48\uea49\uea4a\uea4b\uea4c\uea4d\uea4e\uea4f\uea50\uea51\uea52\uea53\uea54\uea55\uea56\uea57\uea58\uea59\uea5a\uea5b\uea5c\uea5d\uea5e\uea5f\uea60\uea61\uea62\uea63\uea64\uea65\uea66\uea67\uea68\uea69\uea6a\uea6b\uea6c\uea6d\uea6e\uea6f\uea70\uea71\uea72\uea73\uea74\uea75\uea76\uea77\uea78\uea79\uea7a\uea7b\uea7c\uea7d\uea7e\uea7f\uea80\uea81\uea82\uea83\uea84\uea85\uea86\uea87\uea88\uea89\uea8a\uea8b\uea8c\uea8d\uea8e\uea8f\uea90\uea91\uea92\uea93\uea94\uea95\uea96\uea97\uea98\uea99\uea9a\uea9b\uea9c\uea9d\uea9e\uea9f\ueaa0\ueaa1\ueaa2\ueaa3\ueaa4\ueaa5\ueaa6\ueaa7\ueaa8\ueaa9\ueaaa\ueaab\ueaac\ueaad\ueaae\ueaaf\ueab0\ueab1\ueab2\ueab3\ueab4\ueab5\ueab6\ueab7\ueab8\ueab9\ueaba\ueabb\ueabc\ueabd\ueabe\ueabf\ueac0\ueac1\ueac2\ueac3\ueac4\ueac5\ueac6\ueac7\ueac8\ueac9\ueaca\ueacb\ueacc\ueacd\ueace\ueacf\uead0\uead1\uead2\uead3\uead4\uead5\uead6\uead7\uead8\uead9\ueada\ueadb\ueadc\ueadd\ueade\ueadf\ueae0\ueae1\ueae2\ueae3\ueae4\ueae5\ueae6\ueae7\ueae8\ueae9\ueaea\ueaeb\ueaec\ueaed\ueaee\ueaef\ueaf0\ueaf1\ueaf2\ueaf3\ueaf4\ueaf5\ueaf6\ueaf7\ueaf8\ueaf9\ueafa\ueafb\ueafc\ueafd\ueafe\ueaff\ueb00\ueb01\ueb02\ueb03\ueb04\ueb05\ueb06\ueb07\ueb08\ueb09\ueb0a\ueb0b\ueb0c\ueb0d\ueb0e\ueb0f\ueb10\ueb11\ueb12\ueb13\ueb14\ueb15\ueb16\ueb17\ueb18\ueb19\ueb1a\ueb1b\ueb1c\ueb1d\ueb1e\ueb1f\ueb20\ueb21\ueb22\ueb23\ueb24\ueb25\ueb26\ueb27\ueb28\ueb29\ueb2a\ueb2b\ueb2c\ueb2d\ueb2e\ueb2f\ueb30\ueb31\ueb32\ueb33\ueb34\ueb35\ueb36\ueb37\ueb38\ueb39\ueb3a\ueb3b\ueb3c\ueb3d\ueb3e\ueb3f\ueb40\ueb41\ueb42\ueb43\ueb44\ueb45\ueb46\ueb47\ueb48\ueb49\ueb4a\ueb4b\ueb4c\ueb4d\ueb4e\ueb4f\ueb50\ueb51\ueb52\ueb53\ueb54\ueb55\ueb56\ueb57\ueb58\ueb59\ueb5a\ueb5b\ueb5c\ueb5d\ueb5e\ueb5f\ueb60\ueb61\ueb62\ueb63\ueb64\ueb65\ueb66\ueb67\ueb68\ueb69\ueb6a\ueb6b\ueb6c\ueb6d\ueb6e\ueb6f\ueb70\ueb71\ueb72\ueb73\ueb74\ueb75\ueb76\ueb77\ueb78\ueb79\ueb7a\ueb7b\ueb7c\ueb7d\ueb7e\ueb7f\ueb80\ueb81\ueb82\ueb83\ueb84\ueb85\ueb86\ueb87\ueb88\ueb89\ueb8a\ueb8b\ueb8c\ueb8d\ueb8e\ueb8f\ueb90\ueb91\ueb92\ueb93\ueb94\ueb95\ueb96\ueb97\ueb98\ueb99\ueb9a\ueb9b\ueb9c\ueb9d\ueb9e\ueb9f\ueba0\ueba1\ueba2\ueba3\ueba4\ueba5\ueba6\ueba7\ueba8\ueba9\uebaa\uebab\uebac\uebad\uebae\uebaf\uebb0\uebb1\uebb2\uebb3\uebb4\uebb5\uebb6\uebb7\uebb8\uebb9\uebba\uebbb\uebbc\uebbd\uebbe\uebbf\uebc0\uebc1\uebc2\uebc3\uebc4\uebc5\uebc6\uebc7\uebc8\uebc9\uebca\uebcb\uebcc\uebcd\uebce\uebcf\uebd0\uebd1\uebd2\uebd3\uebd4\uebd5\uebd6\uebd7\uebd8\uebd9\uebda\uebdb\uebdc\uebdd\uebde\uebdf\uebe0\uebe1\uebe2\uebe3\uebe4\uebe5\uebe6\uebe7\uebe8\uebe9\uebea\uebeb\uebec\uebed\uebee\uebef\uebf0\uebf1\uebf2\uebf3\uebf4\uebf5\uebf6\uebf7\uebf8\uebf9\uebfa\uebfb\uebfc\uebfd\uebfe\uebff\uec00\uec01\uec02\uec03\uec04\uec05\uec06\uec07\uec08\uec09\uec0a\uec0b\uec0c\uec0d\uec0e\uec0f\uec10\uec11\uec12\uec13\uec14\uec15\uec16\uec17\uec18\uec19\uec1a\uec1b\uec1c\uec1d\uec1e\uec1f\uec20\uec21\uec22\uec23\uec24\uec25\uec26\uec27\uec28\uec29\uec2a\uec2b\uec2c\uec2d\uec2e\uec2f\uec30\uec31\uec32\uec33\uec34\uec35\uec36\uec37\uec38\uec39\uec3a\uec3b\uec3c\uec3d\uec3e\uec3f\uec40\uec41\uec42\uec43\uec44\uec45\uec46\uec47\uec48\uec49\uec4a\uec4b\uec4c\uec4d\uec4e\uec4f\uec50\uec51\uec52\uec53\uec54\uec55\uec56\uec57\uec58\uec59\uec5a\uec5b\uec5c\uec5d\uec5e\uec5f\uec60\uec61\uec62\uec63\uec64\uec65\uec66\uec67\uec68\uec69\uec6a\uec6b\uec6c\uec6d\uec6e\uec6f\uec70\uec71\uec72\uec73\uec74\uec75\uec76\uec77\uec78\uec79\uec7a\uec7b\uec7c\uec7d\uec7e\uec7f\uec80\uec81\uec82\uec83\uec84\uec85\uec86\uec87\uec88\uec89\uec8a\uec8b\uec8c\uec8d\uec8e\uec8f\uec90\uec91\uec92\uec93\uec94\uec95\uec96\uec97\uec98\uec99\uec9a\uec9b\uec9c\uec9d\uec9e\uec9f\ueca0\ueca1\ueca2\ueca3\ueca4\ueca5\ueca6\ueca7\ueca8\ueca9\uecaa\uecab\uecac\uecad\uecae\uecaf\uecb0\uecb1\uecb2\uecb3\uecb4\uecb5\uecb6\uecb7\uecb8\uecb9\uecba\uecbb\uecbc\uecbd\uecbe\uecbf\uecc0\uecc1\uecc2\uecc3\uecc4\uecc5\uecc6\uecc7\uecc8\uecc9\uecca\ueccb\ueccc\ueccd\uecce\ueccf\uecd0\uecd1\uecd2\uecd3\uecd4\uecd5\uecd6\uecd7\uecd8\uecd9\uecda\uecdb\uecdc\uecdd\uecde\uecdf\uece0\uece1\uece2\uece3\uece4\uece5\uece6\uece7\uece8\uece9\uecea\ueceb\uecec\ueced\uecee\uecef\uecf0\uecf1\uecf2\uecf3\uecf4\uecf5\uecf6\uecf7\uecf8\uecf9\uecfa\uecfb\uecfc\uecfd\uecfe\uecff\ued00\ued01\ued02\ued03\ued04\ued05\ued06\ued07\ued08\ued09\ued0a\ued0b\ued0c\ued0d\ued0e\ued0f\ued10\ued11\ued12\ued13\ued14\ued15\ued16\ued17\ued18\ued19\ued1a\ued1b\ued1c\ued1d\ued1e\ued1f\ued20\ued21\ued22\ued23\ued24\ued25\ued26\ued27\ued28\ued29\ued2a\ued2b\ued2c\ued2d\ued2e\ued2f\ued30\ued31\ued32\ued33\ued34\ued35\ued36\ued37\ued38\ued39\ued3a\ued3b\ued3c\ued3d\ued3e\ued3f\ued40\ued41\ued42\ued43\ued44\ued45\ued46\ued47\ued48\ued49\ued4a\ued4b\ued4c\ued4d\ued4e\ued4f\ued50\ued51\ued52\ued53\ued54\ued55\ued56\ued57\ued58\ued59\ued5a\ued5b\ued5c\ued5d\ued5e\ued5f\ued60\ued61\ued62\ued63\ued64\ued65\ued66\ued67\ued68\ued69\ued6a\ued6b\ued6c\ued6d\ued6e\ued6f\ued70\ued71\ued72\ued73\ued74\ued75\ued76\ued77\ued78\ued79\ued7a\ued7b\ued7c\ued7d\ued7e\ued7f\ued80\ued81\ued82\ued83\ued84\ued85\ued86\ued87\ued88\ued89\ued8a\ued8b\ued8c\ued8d\ued8e\ued8f\ued90\ued91\ued92\ued93\ued94\ued95\ued96\ued97\ued98\ued99\ued9a\ued9b\ued9c\ued9d\ued9e\ued9f\ueda0\ueda1\ueda2\ueda3\ueda4\ueda5\ueda6\ueda7\ueda8\ueda9\uedaa\uedab\uedac\uedad\uedae\uedaf\uedb0\uedb1\uedb2\uedb3\uedb4\uedb5\uedb6\uedb7\uedb8\uedb9\uedba\uedbb\uedbc\uedbd\uedbe\uedbf\uedc0\uedc1\uedc2\uedc3\uedc4\uedc5\uedc6\uedc7\uedc8\uedc9\uedca\uedcb\uedcc\uedcd\uedce\uedcf\uedd0\uedd1\uedd2\uedd3\uedd4\uedd5\uedd6\uedd7\uedd8\uedd9\uedda\ueddb\ueddc\ueddd\uedde\ueddf\uede0\uede1\uede2\uede3\uede4\uede5\uede6\uede7\uede8\uede9\uedea\uedeb\uedec\ueded\uedee\uedef\uedf0\uedf1\uedf2\uedf3\uedf4\uedf5\uedf6\uedf7\uedf8\uedf9\uedfa\uedfb\uedfc\uedfd\uedfe\uedff\uee00\uee01\uee02\uee03\uee04\uee05\uee06\uee07\uee08\uee09\uee0a\uee0b\uee0c\uee0d\uee0e\uee0f\uee10\uee11\uee12\uee13\uee14\uee15\uee16\uee17\uee18\uee19\uee1a\uee1b\uee1c\uee1d\uee1e\uee1f\uee20\uee21\uee22\uee23\uee24\uee25\uee26\uee27\uee28\uee29\uee2a\uee2b\uee2c\uee2d\uee2e\uee2f\uee30\uee31\uee32\uee33\uee34\uee35\uee36\uee37\uee38\uee39\uee3a\uee3b\uee3c\uee3d\uee3e\uee3f\uee40\uee41\uee42\uee43\uee44\uee45\uee46\uee47\uee48\uee49\uee4a\uee4b\uee4c\uee4d\uee4e\uee4f\uee50\uee51\uee52\uee53\uee54\uee55\uee56\uee57\uee58\uee59\uee5a\uee5b\uee5c\uee5d\uee5e\uee5f\uee60\uee61\uee62\uee63\uee64\uee65\uee66\uee67\uee68\uee69\uee6a\uee6b\uee6c\uee6d\uee6e\uee6f\uee70\uee71\uee72\uee73\uee74\uee75\uee76\uee77\uee78\uee79\uee7a\uee7b\uee7c\uee7d\uee7e\uee7f\uee80\uee81\uee82\uee83\uee84\uee85\uee86\uee87\uee88\uee89\uee8a\uee8b\uee8c\uee8d\uee8e\uee8f\uee90\uee91\uee92\uee93\uee94\uee95\uee96\uee97\uee98\uee99\uee9a\uee9b\uee9c\uee9d\uee9e\uee9f\ueea0\ueea1\ueea2\ueea3\ueea4\ueea5\ueea6\ueea7\ueea8\ueea9\ueeaa\ueeab\ueeac\ueead\ueeae\ueeaf\ueeb0\ueeb1\ueeb2\ueeb3\ueeb4\ueeb5\ueeb6\ueeb7\ueeb8\ueeb9\ueeba\ueebb\ueebc\ueebd\ueebe\ueebf\ueec0\ueec1\ueec2\ueec3\ueec4\ueec5\ueec6\ueec7\ueec8\ueec9\ueeca\ueecb\ueecc\ueecd\ueece\ueecf\ueed0\ueed1\ueed2\ueed3\ueed4\ueed5\ueed6\ueed7\ueed8\ueed9\ueeda\ueedb\ueedc\ueedd\ueede\ueedf\ueee0\ueee1\ueee2\ueee3\ueee4\ueee5\ueee6\ueee7\ueee8\ueee9\ueeea\ueeeb\ueeec\ueeed\ueeee\ueeef\ueef0\ueef1\ueef2\ueef3\ueef4\ueef5\ueef6\ueef7\ueef8\ueef9\ueefa\ueefb\ueefc\ueefd\ueefe\ueeff\uef00\uef01\uef02\uef03\uef04\uef05\uef06\uef07\uef08\uef09\uef0a\uef0b\uef0c\uef0d\uef0e\uef0f\uef10\uef11\uef12\uef13\uef14\uef15\uef16\uef17\uef18\uef19\uef1a\uef1b\uef1c\uef1d\uef1e\uef1f\uef20\uef21\uef22\uef23\uef24\uef25\uef26\uef27\uef28\uef29\uef2a\uef2b\uef2c\uef2d\uef2e\uef2f\uef30\uef31\uef32\uef33\uef34\uef35\uef36\uef37\uef38\uef39\uef3a\uef3b\uef3c\uef3d\uef3e\uef3f\uef40\uef41\uef42\uef43\uef44\uef45\uef46\uef47\uef48\uef49\uef4a\uef4b\uef4c\uef4d\uef4e\uef4f\uef50\uef51\uef52\uef53\uef54\uef55\uef56\uef57\uef58\uef59\uef5a\uef5b\uef5c\uef5d\uef5e\uef5f\uef60\uef61\uef62\uef63\uef64\uef65\uef66\uef67\uef68\uef69\uef6a\uef6b\uef6c\uef6d\uef6e\uef6f\uef70\uef71\uef72\uef73\uef74\uef75\uef76\uef77\uef78\uef79\uef7a\uef7b\uef7c\uef7d\uef7e\uef7f\uef80\uef81\uef82\uef83\uef84\uef85\uef86\uef87\uef88\uef89\uef8a\uef8b\uef8c\uef8d\uef8e\uef8f\uef90\uef91\uef92\uef93\uef94\uef95\uef96\uef97\uef98\uef99\uef9a\uef9b\uef9c\uef9d\uef9e\uef9f\uefa0\uefa1\uefa2\uefa3\uefa4\uefa5\uefa6\uefa7\uefa8\uefa9\uefaa\uefab\uefac\uefad\uefae\uefaf\uefb0\uefb1\uefb2\uefb3\uefb4\uefb5\uefb6\uefb7\uefb8\uefb9\uefba\uefbb\uefbc\uefbd\uefbe\uefbf\uefc0\uefc1\uefc2\uefc3\uefc4\uefc5\uefc6\uefc7\uefc8\uefc9\uefca\uefcb\uefcc\uefcd\uefce\uefcf\uefd0\uefd1\uefd2\uefd3\uefd4\uefd5\uefd6\uefd7\uefd8\uefd9\uefda\uefdb\uefdc\uefdd\uefde\uefdf\uefe0\uefe1\uefe2\uefe3\uefe4\uefe5\uefe6\uefe7\uefe8\uefe9\uefea\uefeb\uefec\uefed\uefee\uefef\ueff0\ueff1\ueff2\ueff3\ueff4\ueff5\ueff6\ueff7\ueff8\ueff9\ueffa\ueffb\ueffc\ueffd\ueffe\uefff\uf000\uf001\uf002\uf003\uf004\uf005\uf006\uf007\uf008\uf009\uf00a\uf00b\uf00c\uf00d\uf00e\uf00f\uf010\uf011\uf012\uf013\uf014\uf015\uf016\uf017\uf018\uf019\uf01a\uf01b\uf01c\uf01d\uf01e\uf01f\uf020\uf021\uf022\uf023\uf024\uf025\uf026\uf027\uf028\uf029\uf02a\uf02b\uf02c\uf02d\uf02e\uf02f\uf030\uf031\uf032\uf033\uf034\uf035\uf036\uf037\uf038\uf039\uf03a\uf03b\uf03c\uf03d\uf03e\uf03f\uf040\uf041\uf042\uf043\uf044\uf045\uf046\uf047\uf048\uf049\uf04a\uf04b\uf04c\uf04d\uf04e\uf04f\uf050\uf051\uf052\uf053\uf054\uf055\uf056\uf057\uf058\uf059\uf05a\uf05b\uf05c\uf05d\uf05e\uf05f\uf060\uf061\uf062\uf063\uf064\uf065\uf066\uf067\uf068\uf069\uf06a\uf06b\uf06c\uf06d\uf06e\uf06f\uf070\uf071\uf072\uf073\uf074\uf075\uf076\uf077\uf078\uf079\uf07a\uf07b\uf07c\uf07d\uf07e\uf07f\uf080\uf081\uf082\uf083\uf084\uf085\uf086\uf087\uf088\uf089\uf08a\uf08b\uf08c\uf08d\uf08e\uf08f\uf090\uf091\uf092\uf093\uf094\uf095\uf096\uf097\uf098\uf099\uf09a\uf09b\uf09c\uf09d\uf09e\uf09f\uf0a0\uf0a1\uf0a2\uf0a3\uf0a4\uf0a5\uf0a6\uf0a7\uf0a8\uf0a9\uf0aa\uf0ab\uf0ac\uf0ad\uf0ae\uf0af\uf0b0\uf0b1\uf0b2\uf0b3\uf0b4\uf0b5\uf0b6\uf0b7\uf0b8\uf0b9\uf0ba\uf0bb\uf0bc\uf0bd\uf0be\uf0bf\uf0c0\uf0c1\uf0c2\uf0c3\uf0c4\uf0c5\uf0c6\uf0c7\uf0c8\uf0c9\uf0ca\uf0cb\uf0cc\uf0cd\uf0ce\uf0cf\uf0d0\uf0d1\uf0d2\uf0d3\uf0d4\uf0d5\uf0d6\uf0d7\uf0d8\uf0d9\uf0da\uf0db\uf0dc\uf0dd\uf0de\uf0df\uf0e0\uf0e1\uf0e2\uf0e3\uf0e4\uf0e5\uf0e6\uf0e7\uf0e8\uf0e9\uf0ea\uf0eb\uf0ec\uf0ed\uf0ee\uf0ef\uf0f0\uf0f1\uf0f2\uf0f3\uf0f4\uf0f5\uf0f6\uf0f7\uf0f8\uf0f9\uf0fa\uf0fb\uf0fc\uf0fd\uf0fe\uf0ff\uf100\uf101\uf102\uf103\uf104\uf105\uf106\uf107\uf108\uf109\uf10a\uf10b\uf10c\uf10d\uf10e\uf10f\uf110\uf111\uf112\uf113\uf114\uf115\uf116\uf117\uf118\uf119\uf11a\uf11b\uf11c\uf11d\uf11e\uf11f\uf120\uf121\uf122\uf123\uf124\uf125\uf126\uf127\uf128\uf129\uf12a\uf12b\uf12c\uf12d\uf12e\uf12f\uf130\uf131\uf132\uf133\uf134\uf135\uf136\uf137\uf138\uf139\uf13a\uf13b\uf13c\uf13d\uf13e\uf13f\uf140\uf141\uf142\uf143\uf144\uf145\uf146\uf147\uf148\uf149\uf14a\uf14b\uf14c\uf14d\uf14e\uf14f\uf150\uf151\uf152\uf153\uf154\uf155\uf156\uf157\uf158\uf159\uf15a\uf15b\uf15c\uf15d\uf15e\uf15f\uf160\uf161\uf162\uf163\uf164\uf165\uf166\uf167\uf168\uf169\uf16a\uf16b\uf16c\uf16d\uf16e\uf16f\uf170\uf171\uf172\uf173\uf174\uf175\uf176\uf177\uf178\uf179\uf17a\uf17b\uf17c\uf17d\uf17e\uf17f\uf180\uf181\uf182\uf183\uf184\uf185\uf186\uf187\uf188\uf189\uf18a\uf18b\uf18c\uf18d\uf18e\uf18f\uf190\uf191\uf192\uf193\uf194\uf195\uf196\uf197\uf198\uf199\uf19a\uf19b\uf19c\uf19d\uf19e\uf19f\uf1a0\uf1a1\uf1a2\uf1a3\uf1a4\uf1a5\uf1a6\uf1a7\uf1a8\uf1a9\uf1aa\uf1ab\uf1ac\uf1ad\uf1ae\uf1af\uf1b0\uf1b1\uf1b2\uf1b3\uf1b4\uf1b5\uf1b6\uf1b7\uf1b8\uf1b9\uf1ba\uf1bb\uf1bc\uf1bd\uf1be\uf1bf\uf1c0\uf1c1\uf1c2\uf1c3\uf1c4\uf1c5\uf1c6\uf1c7\uf1c8\uf1c9\uf1ca\uf1cb\uf1cc\uf1cd\uf1ce\uf1cf\uf1d0\uf1d1\uf1d2\uf1d3\uf1d4\uf1d5\uf1d6\uf1d7\uf1d8\uf1d9\uf1da\uf1db\uf1dc\uf1dd\uf1de\uf1df\uf1e0\uf1e1\uf1e2\uf1e3\uf1e4\uf1e5\uf1e6\uf1e7\uf1e8\uf1e9\uf1ea\uf1eb\uf1ec\uf1ed\uf1ee\uf1ef\uf1f0\uf1f1\uf1f2\uf1f3\uf1f4\uf1f5\uf1f6\uf1f7\uf1f8\uf1f9\uf1fa\uf1fb\uf1fc\uf1fd\uf1fe\uf1ff\uf200\uf201\uf202\uf203\uf204\uf205\uf206\uf207\uf208\uf209\uf20a\uf20b\uf20c\uf20d\uf20e\uf20f\uf210\uf211\uf212\uf213\uf214\uf215\uf216\uf217\uf218\uf219\uf21a\uf21b\uf21c\uf21d\uf21e\uf21f\uf220\uf221\uf222\uf223\uf224\uf225\uf226\uf227\uf228\uf229\uf22a\uf22b\uf22c\uf22d\uf22e\uf22f\uf230\uf231\uf232\uf233\uf234\uf235\uf236\uf237\uf238\uf239\uf23a\uf23b\uf23c\uf23d\uf23e\uf23f\uf240\uf241\uf242\uf243\uf244\uf245\uf246\uf247\uf248\uf249\uf24a\uf24b\uf24c\uf24d\uf24e\uf24f\uf250\uf251\uf252\uf253\uf254\uf255\uf256\uf257\uf258\uf259\uf25a\uf25b\uf25c\uf25d\uf25e\uf25f\uf260\uf261\uf262\uf263\uf264\uf265\uf266\uf267\uf268\uf269\uf26a\uf26b\uf26c\uf26d\uf26e\uf26f\uf270\uf271\uf272\uf273\uf274\uf275\uf276\uf277\uf278\uf279\uf27a\uf27b\uf27c\uf27d\uf27e\uf27f\uf280\uf281\uf282\uf283\uf284\uf285\uf286\uf287\uf288\uf289\uf28a\uf28b\uf28c\uf28d\uf28e\uf28f\uf290\uf291\uf292\uf293\uf294\uf295\uf296\uf297\uf298\uf299\uf29a\uf29b\uf29c\uf29d\uf29e\uf29f\uf2a0\uf2a1\uf2a2\uf2a3\uf2a4\uf2a5\uf2a6\uf2a7\uf2a8\uf2a9\uf2aa\uf2ab\uf2ac\uf2ad\uf2ae\uf2af\uf2b0\uf2b1\uf2b2\uf2b3\uf2b4\uf2b5\uf2b6\uf2b7\uf2b8\uf2b9\uf2ba\uf2bb\uf2bc\uf2bd\uf2be\uf2bf\uf2c0\uf2c1\uf2c2\uf2c3\uf2c4\uf2c5\uf2c6\uf2c7\uf2c8\uf2c9\uf2ca\uf2cb\uf2cc\uf2cd\uf2ce\uf2cf\uf2d0\uf2d1\uf2d2\uf2d3\uf2d4\uf2d5\uf2d6\uf2d7\uf2d8\uf2d9\uf2da\uf2db\uf2dc\uf2dd\uf2de\uf2df\uf2e0\uf2e1\uf2e2\uf2e3\uf2e4\uf2e5\uf2e6\uf2e7\uf2e8\uf2e9\uf2ea\uf2eb\uf2ec\uf2ed\uf2ee\uf2ef\uf2f0\uf2f1\uf2f2\uf2f3\uf2f4\uf2f5\uf2f6\uf2f7\uf2f8\uf2f9\uf2fa\uf2fb\uf2fc\uf2fd\uf2fe\uf2ff\uf300\uf301\uf302\uf303\uf304\uf305\uf306\uf307\uf308\uf309\uf30a\uf30b\uf30c\uf30d\uf30e\uf30f\uf310\uf311\uf312\uf313\uf314\uf315\uf316\uf317\uf318\uf319\uf31a\uf31b\uf31c\uf31d\uf31e\uf31f\uf320\uf321\uf322\uf323\uf324\uf325\uf326\uf327\uf328\uf329\uf32a\uf32b\uf32c\uf32d\uf32e\uf32f\uf330\uf331\uf332\uf333\uf334\uf335\uf336\uf337\uf338\uf339\uf33a\uf33b\uf33c\uf33d\uf33e\uf33f\uf340\uf341\uf342\uf343\uf344\uf345\uf346\uf347\uf348\uf349\uf34a\uf34b\uf34c\uf34d\uf34e\uf34f\uf350\uf351\uf352\uf353\uf354\uf355\uf356\uf357\uf358\uf359\uf35a\uf35b\uf35c\uf35d\uf35e\uf35f\uf360\uf361\uf362\uf363\uf364\uf365\uf366\uf367\uf368\uf369\uf36a\uf36b\uf36c\uf36d\uf36e\uf36f\uf370\uf371\uf372\uf373\uf374\uf375\uf376\uf377\uf378\uf379\uf37a\uf37b\uf37c\uf37d\uf37e\uf37f\uf380\uf381\uf382\uf383\uf384\uf385\uf386\uf387\uf388\uf389\uf38a\uf38b\uf38c\uf38d\uf38e\uf38f\uf390\uf391\uf392\uf393\uf394\uf395\uf396\uf397\uf398\uf399\uf39a\uf39b\uf39c\uf39d\uf39e\uf39f\uf3a0\uf3a1\uf3a2\uf3a3\uf3a4\uf3a5\uf3a6\uf3a7\uf3a8\uf3a9\uf3aa\uf3ab\uf3ac\uf3ad\uf3ae\uf3af\uf3b0\uf3b1\uf3b2\uf3b3\uf3b4\uf3b5\uf3b6\uf3b7\uf3b8\uf3b9\uf3ba\uf3bb\uf3bc\uf3bd\uf3be\uf3bf\uf3c0\uf3c1\uf3c2\uf3c3\uf3c4\uf3c5\uf3c6\uf3c7\uf3c8\uf3c9\uf3ca\uf3cb\uf3cc\uf3cd\uf3ce\uf3cf\uf3d0\uf3d1\uf3d2\uf3d3\uf3d4\uf3d5\uf3d6\uf3d7\uf3d8\uf3d9\uf3da\uf3db\uf3dc\uf3dd\uf3de\uf3df\uf3e0\uf3e1\uf3e2\uf3e3\uf3e4\uf3e5\uf3e6\uf3e7\uf3e8\uf3e9\uf3ea\uf3eb\uf3ec\uf3ed\uf3ee\uf3ef\uf3f0\uf3f1\uf3f2\uf3f3\uf3f4\uf3f5\uf3f6\uf3f7\uf3f8\uf3f9\uf3fa\uf3fb\uf3fc\uf3fd\uf3fe\uf3ff\uf400\uf401\uf402\uf403\uf404\uf405\uf406\uf407\uf408\uf409\uf40a\uf40b\uf40c\uf40d\uf40e\uf40f\uf410\uf411\uf412\uf413\uf414\uf415\uf416\uf417\uf418\uf419\uf41a\uf41b\uf41c\uf41d\uf41e\uf41f\uf420\uf421\uf422\uf423\uf424\uf425\uf426\uf427\uf428\uf429\uf42a\uf42b\uf42c\uf42d\uf42e\uf42f\uf430\uf431\uf432\uf433\uf434\uf435\uf436\uf437\uf438\uf439\uf43a\uf43b\uf43c\uf43d\uf43e\uf43f\uf440\uf441\uf442\uf443\uf444\uf445\uf446\uf447\uf448\uf449\uf44a\uf44b\uf44c\uf44d\uf44e\uf44f\uf450\uf451\uf452\uf453\uf454\uf455\uf456\uf457\uf458\uf459\uf45a\uf45b\uf45c\uf45d\uf45e\uf45f\uf460\uf461\uf462\uf463\uf464\uf465\uf466\uf467\uf468\uf469\uf46a\uf46b\uf46c\uf46d\uf46e\uf46f\uf470\uf471\uf472\uf473\uf474\uf475\uf476\uf477\uf478\uf479\uf47a\uf47b\uf47c\uf47d\uf47e\uf47f\uf480\uf481\uf482\uf483\uf484\uf485\uf486\uf487\uf488\uf489\uf48a\uf48b\uf48c\uf48d\uf48e\uf48f\uf490\uf491\uf492\uf493\uf494\uf495\uf496\uf497\uf498\uf499\uf49a\uf49b\uf49c\uf49d\uf49e\uf49f\uf4a0\uf4a1\uf4a2\uf4a3\uf4a4\uf4a5\uf4a6\uf4a7\uf4a8\uf4a9\uf4aa\uf4ab\uf4ac\uf4ad\uf4ae\uf4af\uf4b0\uf4b1\uf4b2\uf4b3\uf4b4\uf4b5\uf4b6\uf4b7\uf4b8\uf4b9\uf4ba\uf4bb\uf4bc\uf4bd\uf4be\uf4bf\uf4c0\uf4c1\uf4c2\uf4c3\uf4c4\uf4c5\uf4c6\uf4c7\uf4c8\uf4c9\uf4ca\uf4cb\uf4cc\uf4cd\uf4ce\uf4cf\uf4d0\uf4d1\uf4d2\uf4d3\uf4d4\uf4d5\uf4d6\uf4d7\uf4d8\uf4d9\uf4da\uf4db\uf4dc\uf4dd\uf4de\uf4df\uf4e0\uf4e1\uf4e2\uf4e3\uf4e4\uf4e5\uf4e6\uf4e7\uf4e8\uf4e9\uf4ea\uf4eb\uf4ec\uf4ed\uf4ee\uf4ef\uf4f0\uf4f1\uf4f2\uf4f3\uf4f4\uf4f5\uf4f6\uf4f7\uf4f8\uf4f9\uf4fa\uf4fb\uf4fc\uf4fd\uf4fe\uf4ff\uf500\uf501\uf502\uf503\uf504\uf505\uf506\uf507\uf508\uf509\uf50a\uf50b\uf50c\uf50d\uf50e\uf50f\uf510\uf511\uf512\uf513\uf514\uf515\uf516\uf517\uf518\uf519\uf51a\uf51b\uf51c\uf51d\uf51e\uf51f\uf520\uf521\uf522\uf523\uf524\uf525\uf526\uf527\uf528\uf529\uf52a\uf52b\uf52c\uf52d\uf52e\uf52f\uf530\uf531\uf532\uf533\uf534\uf535\uf536\uf537\uf538\uf539\uf53a\uf53b\uf53c\uf53d\uf53e\uf53f\uf540\uf541\uf542\uf543\uf544\uf545\uf546\uf547\uf548\uf549\uf54a\uf54b\uf54c\uf54d\uf54e\uf54f\uf550\uf551\uf552\uf553\uf554\uf555\uf556\uf557\uf558\uf559\uf55a\uf55b\uf55c\uf55d\uf55e\uf55f\uf560\uf561\uf562\uf563\uf564\uf565\uf566\uf567\uf568\uf569\uf56a\uf56b\uf56c\uf56d\uf56e\uf56f\uf570\uf571\uf572\uf573\uf574\uf575\uf576\uf577\uf578\uf579\uf57a\uf57b\uf57c\uf57d\uf57e\uf57f\uf580\uf581\uf582\uf583\uf584\uf585\uf586\uf587\uf588\uf589\uf58a\uf58b\uf58c\uf58d\uf58e\uf58f\uf590\uf591\uf592\uf593\uf594\uf595\uf596\uf597\uf598\uf599\uf59a\uf59b\uf59c\uf59d\uf59e\uf59f\uf5a0\uf5a1\uf5a2\uf5a3\uf5a4\uf5a5\uf5a6\uf5a7\uf5a8\uf5a9\uf5aa\uf5ab\uf5ac\uf5ad\uf5ae\uf5af\uf5b0\uf5b1\uf5b2\uf5b3\uf5b4\uf5b5\uf5b6\uf5b7\uf5b8\uf5b9\uf5ba\uf5bb\uf5bc\uf5bd\uf5be\uf5bf\uf5c0\uf5c1\uf5c2\uf5c3\uf5c4\uf5c5\uf5c6\uf5c7\uf5c8\uf5c9\uf5ca\uf5cb\uf5cc\uf5cd\uf5ce\uf5cf\uf5d0\uf5d1\uf5d2\uf5d3\uf5d4\uf5d5\uf5d6\uf5d7\uf5d8\uf5d9\uf5da\uf5db\uf5dc\uf5dd\uf5de\uf5df\uf5e0\uf5e1\uf5e2\uf5e3\uf5e4\uf5e5\uf5e6\uf5e7\uf5e8\uf5e9\uf5ea\uf5eb\uf5ec\uf5ed\uf5ee\uf5ef\uf5f0\uf5f1\uf5f2\uf5f3\uf5f4\uf5f5\uf5f6\uf5f7\uf5f8\uf5f9\uf5fa\uf5fb\uf5fc\uf5fd\uf5fe\uf5ff\uf600\uf601\uf602\uf603\uf604\uf605\uf606\uf607\uf608\uf609\uf60a\uf60b\uf60c\uf60d\uf60e\uf60f\uf610\uf611\uf612\uf613\uf614\uf615\uf616\uf617\uf618\uf619\uf61a\uf61b\uf61c\uf61d\uf61e\uf61f\uf620\uf621\uf622\uf623\uf624\uf625\uf626\uf627\uf628\uf629\uf62a\uf62b\uf62c\uf62d\uf62e\uf62f\uf630\uf631\uf632\uf633\uf634\uf635\uf636\uf637\uf638\uf639\uf63a\uf63b\uf63c\uf63d\uf63e\uf63f\uf640\uf641\uf642\uf643\uf644\uf645\uf646\uf647\uf648\uf649\uf64a\uf64b\uf64c\uf64d\uf64e\uf64f\uf650\uf651\uf652\uf653\uf654\uf655\uf656\uf657\uf658\uf659\uf65a\uf65b\uf65c\uf65d\uf65e\uf65f\uf660\uf661\uf662\uf663\uf664\uf665\uf666\uf667\uf668\uf669\uf66a\uf66b\uf66c\uf66d\uf66e\uf66f\uf670\uf671\uf672\uf673\uf674\uf675\uf676\uf677\uf678\uf679\uf67a\uf67b\uf67c\uf67d\uf67e\uf67f\uf680\uf681\uf682\uf683\uf684\uf685\uf686\uf687\uf688\uf689\uf68a\uf68b\uf68c\uf68d\uf68e\uf68f\uf690\uf691\uf692\uf693\uf694\uf695\uf696\uf697\uf698\uf699\uf69a\uf69b\uf69c\uf69d\uf69e\uf69f\uf6a0\uf6a1\uf6a2\uf6a3\uf6a4\uf6a5\uf6a6\uf6a7\uf6a8\uf6a9\uf6aa\uf6ab\uf6ac\uf6ad\uf6ae\uf6af\uf6b0\uf6b1\uf6b2\uf6b3\uf6b4\uf6b5\uf6b6\uf6b7\uf6b8\uf6b9\uf6ba\uf6bb\uf6bc\uf6bd\uf6be\uf6bf\uf6c0\uf6c1\uf6c2\uf6c3\uf6c4\uf6c5\uf6c6\uf6c7\uf6c8\uf6c9\uf6ca\uf6cb\uf6cc\uf6cd\uf6ce\uf6cf\uf6d0\uf6d1\uf6d2\uf6d3\uf6d4\uf6d5\uf6d6\uf6d7\uf6d8\uf6d9\uf6da\uf6db\uf6dc\uf6dd\uf6de\uf6df\uf6e0\uf6e1\uf6e2\uf6e3\uf6e4\uf6e5\uf6e6\uf6e7\uf6e8\uf6e9\uf6ea\uf6eb\uf6ec\uf6ed\uf6ee\uf6ef\uf6f0\uf6f1\uf6f2\uf6f3\uf6f4\uf6f5\uf6f6\uf6f7\uf6f8\uf6f9\uf6fa\uf6fb\uf6fc\uf6fd\uf6fe\uf6ff\uf700\uf701\uf702\uf703\uf704\uf705\uf706\uf707\uf708\uf709\uf70a\uf70b\uf70c\uf70d\uf70e\uf70f\uf710\uf711\uf712\uf713\uf714\uf715\uf716\uf717\uf718\uf719\uf71a\uf71b\uf71c\uf71d\uf71e\uf71f\uf720\uf721\uf722\uf723\uf724\uf725\uf726\uf727\uf728\uf729\uf72a\uf72b\uf72c\uf72d\uf72e\uf72f\uf730\uf731\uf732\uf733\uf734\uf735\uf736\uf737\uf738\uf739\uf73a\uf73b\uf73c\uf73d\uf73e\uf73f\uf740\uf741\uf742\uf743\uf744\uf745\uf746\uf747\uf748\uf749\uf74a\uf74b\uf74c\uf74d\uf74e\uf74f\uf750\uf751\uf752\uf753\uf754\uf755\uf756\uf757\uf758\uf759\uf75a\uf75b\uf75c\uf75d\uf75e\uf75f\uf760\uf761\uf762\uf763\uf764\uf765\uf766\uf767\uf768\uf769\uf76a\uf76b\uf76c\uf76d\uf76e\uf76f\uf770\uf771\uf772\uf773\uf774\uf775\uf776\uf777\uf778\uf779\uf77a\uf77b\uf77c\uf77d\uf77e\uf77f\uf780\uf781\uf782\uf783\uf784\uf785\uf786\uf787\uf788\uf789\uf78a\uf78b\uf78c\uf78d\uf78e\uf78f\uf790\uf791\uf792\uf793\uf794\uf795\uf796\uf797\uf798\uf799\uf79a\uf79b\uf79c\uf79d\uf79e\uf79f\uf7a0\uf7a1\uf7a2\uf7a3\uf7a4\uf7a5\uf7a6\uf7a7\uf7a8\uf7a9\uf7aa\uf7ab\uf7ac\uf7ad\uf7ae\uf7af\uf7b0\uf7b1\uf7b2\uf7b3\uf7b4\uf7b5\uf7b6\uf7b7\uf7b8\uf7b9\uf7ba\uf7bb\uf7bc\uf7bd\uf7be\uf7bf\uf7c0\uf7c1\uf7c2\uf7c3\uf7c4\uf7c5\uf7c6\uf7c7\uf7c8\uf7c9\uf7ca\uf7cb\uf7cc\uf7cd\uf7ce\uf7cf\uf7d0\uf7d1\uf7d2\uf7d3\uf7d4\uf7d5\uf7d6\uf7d7\uf7d8\uf7d9\uf7da\uf7db\uf7dc\uf7dd\uf7de\uf7df\uf7e0\uf7e1\uf7e2\uf7e3\uf7e4\uf7e5\uf7e6\uf7e7\uf7e8\uf7e9\uf7ea\uf7eb\uf7ec\uf7ed\uf7ee\uf7ef\uf7f0\uf7f1\uf7f2\uf7f3\uf7f4\uf7f5\uf7f6\uf7f7\uf7f8\uf7f9\uf7fa\uf7fb\uf7fc\uf7fd\uf7fe\uf7ff\uf800\uf801\uf802\uf803\uf804\uf805\uf806\uf807\uf808\uf809\uf80a\uf80b\uf80c\uf80d\uf80e\uf80f\uf810\uf811\uf812\uf813\uf814\uf815\uf816\uf817\uf818\uf819\uf81a\uf81b\uf81c\uf81d\uf81e\uf81f\uf820\uf821\uf822\uf823\uf824\uf825\uf826\uf827\uf828\uf829\uf82a\uf82b\uf82c\uf82d\uf82e\uf82f\uf830\uf831\uf832\uf833\uf834\uf835\uf836\uf837\uf838\uf839\uf83a\uf83b\uf83c\uf83d\uf83e\uf83f\uf840\uf841\uf842\uf843\uf844\uf845\uf846\uf847\uf848\uf849\uf84a\uf84b\uf84c\uf84d\uf84e\uf84f\uf850\uf851\uf852\uf853\uf854\uf855\uf856\uf857\uf858\uf859\uf85a\uf85b\uf85c\uf85d\uf85e\uf85f\uf860\uf861\uf862\uf863\uf864\uf865\uf866\uf867\uf868\uf869\uf86a\uf86b\uf86c\uf86d\uf86e\uf86f\uf870\uf871\uf872\uf873\uf874\uf875\uf876\uf877\uf878\uf879\uf87a\uf87b\uf87c\uf87d\uf87e\uf87f\uf880\uf881\uf882\uf883\uf884\uf885\uf886\uf887\uf888\uf889\uf88a\uf88b\uf88c\uf88d\uf88e\uf88f\uf890\uf891\uf892\uf893\uf894\uf895\uf896\uf897\uf898\uf899\uf89a\uf89b\uf89c\uf89d\uf89e\uf89f\uf8a0\uf8a1\uf8a2\uf8a3\uf8a4\uf8a5\uf8a6\uf8a7\uf8a8\uf8a9\uf8aa\uf8ab\uf8ac\uf8ad\uf8ae\uf8af\uf8b0\uf8b1\uf8b2\uf8b3\uf8b4\uf8b5\uf8b6\uf8b7\uf8b8\uf8b9\uf8ba\uf8bb\uf8bc\uf8bd\uf8be\uf8bf\uf8c0\uf8c1\uf8c2\uf8c3\uf8c4\uf8c5\uf8c6\uf8c7\uf8c8\uf8c9\uf8ca\uf8cb\uf8cc\uf8cd\uf8ce\uf8cf\uf8d0\uf8d1\uf8d2\uf8d3\uf8d4\uf8d5\uf8d6\uf8d7\uf8d8\uf8d9\uf8da\uf8db\uf8dc\uf8dd\uf8de\uf8df\uf8e0\uf8e1\uf8e2\uf8e3\uf8e4\uf8e5\uf8e6\uf8e7\uf8e8\uf8e9\uf8ea\uf8eb\uf8ec\uf8ed\uf8ee\uf8ef\uf8f0\uf8f1\uf8f2\uf8f3\uf8f4\uf8f5\uf8f6\uf8f7\uf8f8\uf8f9\uf8fa\uf8fb\uf8fc\uf8fd\uf8fe\uf8ff'
+
+try:
+    Cs = eval(r"'\ud800\ud801\ud802\ud803\ud804\ud805\ud806\ud807\ud808\ud809\ud80a\ud80b\ud80c\ud80d\ud80e\ud80f\ud810\ud811\ud812\ud813\ud814\ud815\ud816\ud817\ud818\ud819\ud81a\ud81b\ud81c\ud81d\ud81e\ud81f\ud820\ud821\ud822\ud823\ud824\ud825\ud826\ud827\ud828\ud829\ud82a\ud82b\ud82c\ud82d\ud82e\ud82f\ud830\ud831\ud832\ud833\ud834\ud835\ud836\ud837\ud838\ud839\ud83a\ud83b\ud83c\ud83d\ud83e\ud83f\ud840\ud841\ud842\ud843\ud844\ud845\ud846\ud847\ud848\ud849\ud84a\ud84b\ud84c\ud84d\ud84e\ud84f\ud850\ud851\ud852\ud853\ud854\ud855\ud856\ud857\ud858\ud859\ud85a\ud85b\ud85c\ud85d\ud85e\ud85f\ud860\ud861\ud862\ud863\ud864\ud865\ud866\ud867\ud868\ud869\ud86a\ud86b\ud86c\ud86d\ud86e\ud86f\ud870\ud871\ud872\ud873\ud874\ud875\ud876\ud877\ud878\ud879\ud87a\ud87b\ud87c\ud87d\ud87e\ud87f\ud880\ud881\ud882\ud883\ud884\ud885\ud886\ud887\ud888\ud889\ud88a\ud88b\ud88c\ud88d\ud88e\ud88f\ud890\ud891\ud892\ud893\ud894\ud895\ud896\ud897\ud898\ud899\ud89a\ud89b\ud89c\ud89d\ud89e\ud89f\ud8a0\ud8a1\ud8a2\ud8a3\ud8a4\ud8a5\ud8a6\ud8a7\ud8a8\ud8a9\ud8aa\ud8ab\ud8ac\ud8ad\ud8ae\ud8af\ud8b0\ud8b1\ud8b2\ud8b3\ud8b4\ud8b5\ud8b6\ud8b7\ud8b8\ud8b9\ud8ba\ud8bb\ud8bc\ud8bd\ud8be\ud8bf\ud8c0\ud8c1\ud8c2\ud8c3\ud8c4\ud8c5\ud8c6\ud8c7\ud8c8\ud8c9\ud8ca\ud8cb\ud8cc\ud8cd\ud8ce\ud8cf\ud8d0\ud8d1\ud8d2\ud8d3\ud8d4\ud8d5\ud8d6\ud8d7\ud8d8\ud8d9\ud8da\ud8db\ud8dc\ud8dd\ud8de\ud8df\ud8e0\ud8e1\ud8e2\ud8e3\ud8e4\ud8e5\ud8e6\ud8e7\ud8e8\ud8e9\ud8ea\ud8eb\ud8ec\ud8ed\ud8ee\ud8ef\ud8f0\ud8f1\ud8f2\ud8f3\ud8f4\ud8f5\ud8f6\ud8f7\ud8f8\ud8f9\ud8fa\ud8fb\ud8fc\ud8fd\ud8fe\ud8ff\ud900\ud901\ud902\ud903\ud904\ud905\ud906\ud907\ud908\ud909\ud90a\ud90b\ud90c\ud90d\ud90e\ud90f\ud910\ud911\ud912\ud913\ud914\ud915\ud916\ud917\ud918\ud919\ud91a\ud91b\ud91c\ud91d\ud91e\ud91f\ud920\ud921\ud922\ud923\ud924\ud925\ud926\ud927\ud928\ud929\ud92a\ud92b\ud92c\ud92d\ud92e\ud92f\ud930\ud931\ud932\ud933\ud934\ud935\ud936\ud937\ud938\ud939\ud93a\ud93b\ud93c\ud93d\ud93e\ud93f\ud940\ud941\ud942\ud943\ud944\ud945\ud946\ud947\ud948\ud949\ud94a\ud94b\ud94c\ud94d\ud94e\ud94f\ud950\ud951\ud952\ud953\ud954\ud955\ud956\ud957\ud958\ud959\ud95a\ud95b\ud95c\ud95d\ud95e\ud95f\ud960\ud961\ud962\ud963\ud964\ud965\ud966\ud967\ud968\ud969\ud96a\ud96b\ud96c\ud96d\ud96e\ud96f\ud970\ud971\ud972\ud973\ud974\ud975\ud976\ud977\ud978\ud979\ud97a\ud97b\ud97c\ud97d\ud97e\ud97f\ud980\ud981\ud982\ud983\ud984\ud985\ud986\ud987\ud988\ud989\ud98a\ud98b\ud98c\ud98d\ud98e\ud98f\ud990\ud991\ud992\ud993\ud994\ud995\ud996\ud997\ud998\ud999\ud99a\ud99b\ud99c\ud99d\ud99e\ud99f\ud9a0\ud9a1\ud9a2\ud9a3\ud9a4\ud9a5\ud9a6\ud9a7\ud9a8\ud9a9\ud9aa\ud9ab\ud9ac\ud9ad\ud9ae\ud9af\ud9b0\ud9b1\ud9b2\ud9b3\ud9b4\ud9b5\ud9b6\ud9b7\ud9b8\ud9b9\ud9ba\ud9bb\ud9bc\ud9bd\ud9be\ud9bf\ud9c0\ud9c1\ud9c2\ud9c3\ud9c4\ud9c5\ud9c6\ud9c7\ud9c8\ud9c9\ud9ca\ud9cb\ud9cc\ud9cd\ud9ce\ud9cf\ud9d0\ud9d1\ud9d2\ud9d3\ud9d4\ud9d5\ud9d6\ud9d7\ud9d8\ud9d9\ud9da\ud9db\ud9dc\ud9dd\ud9de\ud9df\ud9e0\ud9e1\ud9e2\ud9e3\ud9e4\ud9e5\ud9e6\ud9e7\ud9e8\ud9e9\ud9ea\ud9eb\ud9ec\ud9ed\ud9ee\ud9ef\ud9f0\ud9f1\ud9f2\ud9f3\ud9f4\ud9f5\ud9f6\ud9f7\ud9f8\ud9f9\ud9fa\ud9fb\ud9fc\ud9fd\ud9fe\ud9ff\uda00\uda01\uda02\uda03\uda04\uda05\uda06\uda07\uda08\uda09\uda0a\uda0b\uda0c\uda0d\uda0e\uda0f\uda10\uda11\uda12\uda13\uda14\uda15\uda16\uda17\uda18\uda19\uda1a\uda1b\uda1c\uda1d\uda1e\uda1f\uda20\uda21\uda22\uda23\uda24\uda25\uda26\uda27\uda28\uda29\uda2a\uda2b\uda2c\uda2d\uda2e\uda2f\uda30\uda31\uda32\uda33\uda34\uda35\uda36\uda37\uda38\uda39\uda3a\uda3b\uda3c\uda3d\uda3e\uda3f\uda40\uda41\uda42\uda43\uda44\uda45\uda46\uda47\uda48\uda49\uda4a\uda4b\uda4c\uda4d\uda4e\uda4f\uda50\uda51\uda52\uda53\uda54\uda55\uda56\uda57\uda58\uda59\uda5a\uda5b\uda5c\uda5d\uda5e\uda5f\uda60\uda61\uda62\uda63\uda64\uda65\uda66\uda67\uda68\uda69\uda6a\uda6b\uda6c\uda6d\uda6e\uda6f\uda70\uda71\uda72\uda73\uda74\uda75\uda76\uda77\uda78\uda79\uda7a\uda7b\uda7c\uda7d\uda7e\uda7f\uda80\uda81\uda82\uda83\uda84\uda85\uda86\uda87\uda88\uda89\uda8a\uda8b\uda8c\uda8d\uda8e\uda8f\uda90\uda91\uda92\uda93\uda94\uda95\uda96\uda97\uda98\uda99\uda9a\uda9b\uda9c\uda9d\uda9e\uda9f\udaa0\udaa1\udaa2\udaa3\udaa4\udaa5\udaa6\udaa7\udaa8\udaa9\udaaa\udaab\udaac\udaad\udaae\udaaf\udab0\udab1\udab2\udab3\udab4\udab5\udab6\udab7\udab8\udab9\udaba\udabb\udabc\udabd\udabe\udabf\udac0\udac1\udac2\udac3\udac4\udac5\udac6\udac7\udac8\udac9\udaca\udacb\udacc\udacd\udace\udacf\udad0\udad1\udad2\udad3\udad4\udad5\udad6\udad7\udad8\udad9\udada\udadb\udadc\udadd\udade\udadf\udae0\udae1\udae2\udae3\udae4\udae5\udae6\udae7\udae8\udae9\udaea\udaeb\udaec\udaed\udaee\udaef\udaf0\udaf1\udaf2\udaf3\udaf4\udaf5\udaf6\udaf7\udaf8\udaf9\udafa\udafb\udafc\udafd\udafe\udaff\udb00\udb01\udb02\udb03\udb04\udb05\udb06\udb07\udb08\udb09\udb0a\udb0b\udb0c\udb0d\udb0e\udb0f\udb10\udb11\udb12\udb13\udb14\udb15\udb16\udb17\udb18\udb19\udb1a\udb1b\udb1c\udb1d\udb1e\udb1f\udb20\udb21\udb22\udb23\udb24\udb25\udb26\udb27\udb28\udb29\udb2a\udb2b\udb2c\udb2d\udb2e\udb2f\udb30\udb31\udb32\udb33\udb34\udb35\udb36\udb37\udb38\udb39\udb3a\udb3b\udb3c\udb3d\udb3e\udb3f\udb40\udb41\udb42\udb43\udb44\udb45\udb46\udb47\udb48\udb49\udb4a\udb4b\udb4c\udb4d\udb4e\udb4f\udb50\udb51\udb52\udb53\udb54\udb55\udb56\udb57\udb58\udb59\udb5a\udb5b\udb5c\udb5d\udb5e\udb5f\udb60\udb61\udb62\udb63\udb64\udb65\udb66\udb67\udb68\udb69\udb6a\udb6b\udb6c\udb6d\udb6e\udb6f\udb70\udb71\udb72\udb73\udb74\udb75\udb76\udb77\udb78\udb79\udb7a\udb7b\udb7c\udb7d\udb7e\udb7f\udb80\udb81\udb82\udb83\udb84\udb85\udb86\udb87\udb88\udb89\udb8a\udb8b\udb8c\udb8d\udb8e\udb8f\udb90\udb91\udb92\udb93\udb94\udb95\udb96\udb97\udb98\udb99\udb9a\udb9b\udb9c\udb9d\udb9e\udb9f\udba0\udba1\udba2\udba3\udba4\udba5\udba6\udba7\udba8\udba9\udbaa\udbab\udbac\udbad\udbae\udbaf\udbb0\udbb1\udbb2\udbb3\udbb4\udbb5\udbb6\udbb7\udbb8\udbb9\udbba\udbbb\udbbc\udbbd\udbbe\udbbf\udbc0\udbc1\udbc2\udbc3\udbc4\udbc5\udbc6\udbc7\udbc8\udbc9\udbca\udbcb\udbcc\udbcd\udbce\udbcf\udbd0\udbd1\udbd2\udbd3\udbd4\udbd5\udbd6\udbd7\udbd8\udbd9\udbda\udbdb\udbdc\udbdd\udbde\udbdf\udbe0\udbe1\udbe2\udbe3\udbe4\udbe5\udbe6\udbe7\udbe8\udbe9\udbea\udbeb\udbec\udbed\udbee\udbef\udbf0\udbf1\udbf2\udbf3\udbf4\udbf5\udbf6\udbf7\udbf8\udbf9\udbfa\udbfb\udbfc\udbfd\udbfe\U0010fc00\udc01\udc02\udc03\udc04\udc05\udc06\udc07\udc08\udc09\udc0a\udc0b\udc0c\udc0d\udc0e\udc0f\udc10\udc11\udc12\udc13\udc14\udc15\udc16\udc17\udc18\udc19\udc1a\udc1b\udc1c\udc1d\udc1e\udc1f\udc20\udc21\udc22\udc23\udc24\udc25\udc26\udc27\udc28\udc29\udc2a\udc2b\udc2c\udc2d\udc2e\udc2f\udc30\udc31\udc32\udc33\udc34\udc35\udc36\udc37\udc38\udc39\udc3a\udc3b\udc3c\udc3d\udc3e\udc3f\udc40\udc41\udc42\udc43\udc44\udc45\udc46\udc47\udc48\udc49\udc4a\udc4b\udc4c\udc4d\udc4e\udc4f\udc50\udc51\udc52\udc53\udc54\udc55\udc56\udc57\udc58\udc59\udc5a\udc5b\udc5c\udc5d\udc5e\udc5f\udc60\udc61\udc62\udc63\udc64\udc65\udc66\udc67\udc68\udc69\udc6a\udc6b\udc6c\udc6d\udc6e\udc6f\udc70\udc71\udc72\udc73\udc74\udc75\udc76\udc77\udc78\udc79\udc7a\udc7b\udc7c\udc7d\udc7e\udc7f\udc80\udc81\udc82\udc83\udc84\udc85\udc86\udc87\udc88\udc89\udc8a\udc8b\udc8c\udc8d\udc8e\udc8f\udc90\udc91\udc92\udc93\udc94\udc95\udc96\udc97\udc98\udc99\udc9a\udc9b\udc9c\udc9d\udc9e\udc9f\udca0\udca1\udca2\udca3\udca4\udca5\udca6\udca7\udca8\udca9\udcaa\udcab\udcac\udcad\udcae\udcaf\udcb0\udcb1\udcb2\udcb3\udcb4\udcb5\udcb6\udcb7\udcb8\udcb9\udcba\udcbb\udcbc\udcbd\udcbe\udcbf\udcc0\udcc1\udcc2\udcc3\udcc4\udcc5\udcc6\udcc7\udcc8\udcc9\udcca\udccb\udccc\udccd\udcce\udccf\udcd0\udcd1\udcd2\udcd3\udcd4\udcd5\udcd6\udcd7\udcd8\udcd9\udcda\udcdb\udcdc\udcdd\udcde\udcdf\udce0\udce1\udce2\udce3\udce4\udce5\udce6\udce7\udce8\udce9\udcea\udceb\udcec\udced\udcee\udcef\udcf0\udcf1\udcf2\udcf3\udcf4\udcf5\udcf6\udcf7\udcf8\udcf9\udcfa\udcfb\udcfc\udcfd\udcfe\udcff\udd00\udd01\udd02\udd03\udd04\udd05\udd06\udd07\udd08\udd09\udd0a\udd0b\udd0c\udd0d\udd0e\udd0f\udd10\udd11\udd12\udd13\udd14\udd15\udd16\udd17\udd18\udd19\udd1a\udd1b\udd1c\udd1d\udd1e\udd1f\udd20\udd21\udd22\udd23\udd24\udd25\udd26\udd27\udd28\udd29\udd2a\udd2b\udd2c\udd2d\udd2e\udd2f\udd30\udd31\udd32\udd33\udd34\udd35\udd36\udd37\udd38\udd39\udd3a\udd3b\udd3c\udd3d\udd3e\udd3f\udd40\udd41\udd42\udd43\udd44\udd45\udd46\udd47\udd48\udd49\udd4a\udd4b\udd4c\udd4d\udd4e\udd4f\udd50\udd51\udd52\udd53\udd54\udd55\udd56\udd57\udd58\udd59\udd5a\udd5b\udd5c\udd5d\udd5e\udd5f\udd60\udd61\udd62\udd63\udd64\udd65\udd66\udd67\udd68\udd69\udd6a\udd6b\udd6c\udd6d\udd6e\udd6f\udd70\udd71\udd72\udd73\udd74\udd75\udd76\udd77\udd78\udd79\udd7a\udd7b\udd7c\udd7d\udd7e\udd7f\udd80\udd81\udd82\udd83\udd84\udd85\udd86\udd87\udd88\udd89\udd8a\udd8b\udd8c\udd8d\udd8e\udd8f\udd90\udd91\udd92\udd93\udd94\udd95\udd96\udd97\udd98\udd99\udd9a\udd9b\udd9c\udd9d\udd9e\udd9f\udda0\udda1\udda2\udda3\udda4\udda5\udda6\udda7\udda8\udda9\uddaa\uddab\uddac\uddad\uddae\uddaf\uddb0\uddb1\uddb2\uddb3\uddb4\uddb5\uddb6\uddb7\uddb8\uddb9\uddba\uddbb\uddbc\uddbd\uddbe\uddbf\uddc0\uddc1\uddc2\uddc3\uddc4\uddc5\uddc6\uddc7\uddc8\uddc9\uddca\uddcb\uddcc\uddcd\uddce\uddcf\uddd0\uddd1\uddd2\uddd3\uddd4\uddd5\uddd6\uddd7\uddd8\uddd9\uddda\udddb\udddc\udddd\uddde\udddf\udde0\udde1\udde2\udde3\udde4\udde5\udde6\udde7\udde8\udde9\uddea\uddeb\uddec\udded\uddee\uddef\uddf0\uddf1\uddf2\uddf3\uddf4\uddf5\uddf6\uddf7\uddf8\uddf9\uddfa\uddfb\uddfc\uddfd\uddfe\uddff\ude00\ude01\ude02\ude03\ude04\ude05\ude06\ude07\ude08\ude09\ude0a\ude0b\ude0c\ude0d\ude0e\ude0f\ude10\ude11\ude12\ude13\ude14\ude15\ude16\ude17\ude18\ude19\ude1a\ude1b\ude1c\ude1d\ude1e\ude1f\ude20\ude21\ude22\ude23\ude24\ude25\ude26\ude27\ude28\ude29\ude2a\ude2b\ude2c\ude2d\ude2e\ude2f\ude30\ude31\ude32\ude33\ude34\ude35\ude36\ude37\ude38\ude39\ude3a\ude3b\ude3c\ude3d\ude3e\ude3f\ude40\ude41\ude42\ude43\ude44\ude45\ude46\ude47\ude48\ude49\ude4a\ude4b\ude4c\ude4d\ude4e\ude4f\ude50\ude51\ude52\ude53\ude54\ude55\ude56\ude57\ude58\ude59\ude5a\ude5b\ude5c\ude5d\ude5e\ude5f\ude60\ude61\ude62\ude63\ude64\ude65\ude66\ude67\ude68\ude69\ude6a\ude6b\ude6c\ude6d\ude6e\ude6f\ude70\ude71\ude72\ude73\ude74\ude75\ude76\ude77\ude78\ude79\ude7a\ude7b\ude7c\ude7d\ude7e\ude7f\ude80\ude81\ude82\ude83\ude84\ude85\ude86\ude87\ude88\ude89\ude8a\ude8b\ude8c\ude8d\ude8e\ude8f\ude90\ude91\ude92\ude93\ude94\ude95\ude96\ude97\ude98\ude99\ude9a\ude9b\ude9c\ude9d\ude9e\ude9f\udea0\udea1\udea2\udea3\udea4\udea5\udea6\udea7\udea8\udea9\udeaa\udeab\udeac\udead\udeae\udeaf\udeb0\udeb1\udeb2\udeb3\udeb4\udeb5\udeb6\udeb7\udeb8\udeb9\udeba\udebb\udebc\udebd\udebe\udebf\udec0\udec1\udec2\udec3\udec4\udec5\udec6\udec7\udec8\udec9\udeca\udecb\udecc\udecd\udece\udecf\uded0\uded1\uded2\uded3\uded4\uded5\uded6\uded7\uded8\uded9\udeda\udedb\udedc\udedd\udede\udedf\udee0\udee1\udee2\udee3\udee4\udee5\udee6\udee7\udee8\udee9\udeea\udeeb\udeec\udeed\udeee\udeef\udef0\udef1\udef2\udef3\udef4\udef5\udef6\udef7\udef8\udef9\udefa\udefb\udefc\udefd\udefe\udeff\udf00\udf01\udf02\udf03\udf04\udf05\udf06\udf07\udf08\udf09\udf0a\udf0b\udf0c\udf0d\udf0e\udf0f\udf10\udf11\udf12\udf13\udf14\udf15\udf16\udf17\udf18\udf19\udf1a\udf1b\udf1c\udf1d\udf1e\udf1f\udf20\udf21\udf22\udf23\udf24\udf25\udf26\udf27\udf28\udf29\udf2a\udf2b\udf2c\udf2d\udf2e\udf2f\udf30\udf31\udf32\udf33\udf34\udf35\udf36\udf37\udf38\udf39\udf3a\udf3b\udf3c\udf3d\udf3e\udf3f\udf40\udf41\udf42\udf43\udf44\udf45\udf46\udf47\udf48\udf49\udf4a\udf4b\udf4c\udf4d\udf4e\udf4f\udf50\udf51\udf52\udf53\udf54\udf55\udf56\udf57\udf58\udf59\udf5a\udf5b\udf5c\udf5d\udf5e\udf5f\udf60\udf61\udf62\udf63\udf64\udf65\udf66\udf67\udf68\udf69\udf6a\udf6b\udf6c\udf6d\udf6e\udf6f\udf70\udf71\udf72\udf73\udf74\udf75\udf76\udf77\udf78\udf79\udf7a\udf7b\udf7c\udf7d\udf7e\udf7f\udf80\udf81\udf82\udf83\udf84\udf85\udf86\udf87\udf88\udf89\udf8a\udf8b\udf8c\udf8d\udf8e\udf8f\udf90\udf91\udf92\udf93\udf94\udf95\udf96\udf97\udf98\udf99\udf9a\udf9b\udf9c\udf9d\udf9e\udf9f\udfa0\udfa1\udfa2\udfa3\udfa4\udfa5\udfa6\udfa7\udfa8\udfa9\udfaa\udfab\udfac\udfad\udfae\udfaf\udfb0\udfb1\udfb2\udfb3\udfb4\udfb5\udfb6\udfb7\udfb8\udfb9\udfba\udfbb\udfbc\udfbd\udfbe\udfbf\udfc0\udfc1\udfc2\udfc3\udfc4\udfc5\udfc6\udfc7\udfc8\udfc9\udfca\udfcb\udfcc\udfcd\udfce\udfcf\udfd0\udfd1\udfd2\udfd3\udfd4\udfd5\udfd6\udfd7\udfd8\udfd9\udfda\udfdb\udfdc\udfdd\udfde\udfdf\udfe0\udfe1\udfe2\udfe3\udfe4\udfe5\udfe6\udfe7\udfe8\udfe9\udfea\udfeb\udfec\udfed\udfee\udfef\udff0\udff1\udff2\udff3\udff4\udff5\udff6\udff7\udff8\udff9\udffa\udffb\udffc\udffd\udffe\udfff'")
+except UnicodeDecodeError:
+    Cs = '' # Jython can't handle isolated surrogates
+
+Ll = u'abcdefghijklmnopqrstuvwxyz\xaa\xb5\xba\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff\u0101\u0103\u0105\u0107\u0109\u010b\u010d\u010f\u0111\u0113\u0115\u0117\u0119\u011b\u011d\u011f\u0121\u0123\u0125\u0127\u0129\u012b\u012d\u012f\u0131\u0133\u0135\u0137\u0138\u013a\u013c\u013e\u0140\u0142\u0144\u0146\u0148\u0149\u014b\u014d\u014f\u0151\u0153\u0155\u0157\u0159\u015b\u015d\u015f\u0161\u0163\u0165\u0167\u0169\u016b\u016d\u016f\u0171\u0173\u0175\u0177\u017a\u017c\u017e\u017f\u0180\u0183\u0185\u0188\u018c\u018d\u0192\u0195\u0199\u019a\u019b\u019e\u01a1\u01a3\u01a5\u01a8\u01aa\u01ab\u01ad\u01b0\u01b4\u01b6\u01b9\u01ba\u01bd\u01be\u01bf\u01c6\u01c9\u01cc\u01ce\u01d0\u01d2\u01d4\u01d6\u01d8\u01da\u01dc\u01dd\u01df\u01e1\u01e3\u01e5\u01e7\u01e9\u01eb\u01ed\u01ef\u01f0\u01f3\u01f5\u01f9\u01fb\u01fd\u01ff\u0201\u0203\u0205\u0207\u0209\u020b\u020d\u020f\u0211\u0213\u0215\u0217\u0219\u021b\u021d\u021f\u0221\u0223\u0225\u0227\u0229\u022b\u022d\u022f\u0231\u0233\u0234\u0235\u0236\u0237\u0238\u0239\u023c\u023f\u0240\u0250\u0251\u0252\u0253\u0254\u0255\u0256\u0257\u0258\u0259\u025a\u025b\u025c\u025d\u025e\u025f\u0260\u0261\u0262\u0263\u0264\u0265\u0266\u0267\u0268\u0269\u026a\u026b\u026c\u026d\u026e\u026f\u0270\u0271\u0272\u0273\u0274\u0275\u0276\u0277\u0278\u0279\u027a\u027b\u027c\u027d\u027e\u027f\u0280\u0281\u0282\u0283\u0284\u0285\u0286\u0287\u0288\u0289\u028a\u028b\u028c\u028d\u028e\u028f\u0290\u0291\u0292\u0293\u0294\u0295\u0296\u0297\u0298\u0299\u029a\u029b\u029c\u029d\u029e\u029f\u02a0\u02a1\u02a2\u02a3\u02a4\u02a5\u02a6\u02a7\u02a8\u02a9\u02aa\u02ab\u02ac\u02ad\u02ae\u02af\u0390\u03ac\u03ad\u03ae\u03af\u03b0\u03b1\u03b2\u03b3\u03b4\u03b5\u03b6\u03b7\u03b8\u03b9\u03ba\u03bb\u03bc\u03bd\u03be\u03bf\u03c0\u03c1\u03c2\u03c3\u03c4\u03c5\u03c6\u03c7\u03c8\u03c9\u03ca\u03cb\u03cc\u03cd\u03ce\u03d0\u03d1\u03d5\u03d6\u03d7\u03d9\u03db\u03dd\u03df\u03e1\u03e3\u03e5\u03e7\u03e9\u03eb\u03ed\u03ef\u03f0\u03f1\u03f2\u03f3\u03f5\u03f8\u03fb\u03fc\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f\u0450\u0451\u0452\u0453\u0454\u0455\u0456\u0457\u0458\u0459\u045a\u045b\u045c\u045d\u045e\u045f\u0461\u0463\u0465\u0467\u0469\u046b\u046d\u046f\u0471\u0473\u0475\u0477\u0479\u047b\u047d\u047f\u0481\u048b\u048d\u048f\u0491\u0493\u0495\u0497\u0499\u049b\u049d\u049f\u04a1\u04a3\u04a5\u04a7\u04a9\u04ab\u04ad\u04af\u04b1\u04b3\u04b5\u04b7\u04b9\u04bb\u04bd\u04bf\u04c2\u04c4\u04c6\u04c8\u04ca\u04cc\u04ce\u04d1\u04d3\u04d5\u04d7\u04d9\u04db\u04dd\u04df\u04e1\u04e3\u04e5\u04e7\u04e9\u04eb\u04ed\u04ef\u04f1\u04f3\u04f5\u04f7\u04f9\u0501\u0503\u0505\u0507\u0509\u050b\u050d\u050f\u0561\u0562\u0563\u0564\u0565\u0566\u0567\u0568\u0569\u056a\u056b\u056c\u056d\u056e\u056f\u0570\u0571\u0572\u0573\u0574\u0575\u0576\u0577\u0578\u0579\u057a\u057b\u057c\u057d\u057e\u057f\u0580\u0581\u0582\u0583\u0584\u0585\u0586\u0587\u1d00\u1d01\u1d02\u1d03\u1d04\u1d05\u1d06\u1d07\u1d08\u1d09\u1d0a\u1d0b\u1d0c\u1d0d\u1d0e\u1d0f\u1d10\u1d11\u1d12\u1d13\u1d14\u1d15\u1d16\u1d17\u1d18\u1d19\u1d1a\u1d1b\u1d1c\u1d1d\u1d1e\u1d1f\u1d20\u1d21\u1d22\u1d23\u1d24\u1d25\u1d26\u1d27\u1d28\u1d29\u1d2a\u1d2b\u1d62\u1d63\u1d64\u1d65\u1d66\u1d67\u1d68\u1d69\u1d6a\u1d6b\u1d6c\u1d6d\u1d6e\u1d6f\u1d70\u1d71\u1d72\u1d73\u1d74\u1d75\u1d76\u1d77\u1d79\u1d7a\u1d7b\u1d7c\u1d7d\u1d7e\u1d7f\u1d80\u1d81\u1d82\u1d83\u1d84\u1d85\u1d86\u1d87\u1d88\u1d89\u1d8a\u1d8b\u1d8c\u1d8d\u1d8e\u1d8f\u1d90\u1d91\u1d92\u1d93\u1d94\u1d95\u1d96\u1d97\u1d98\u1d99\u1d9a\u1e01\u1e03\u1e05\u1e07\u1e09\u1e0b\u1e0d\u1e0f\u1e11\u1e13\u1e15\u1e17\u1e19\u1e1b\u1e1d\u1e1f\u1e21\u1e23\u1e25\u1e27\u1e29\u1e2b\u1e2d\u1e2f\u1e31\u1e33\u1e35\u1e37\u1e39\u1e3b\u1e3d\u1e3f\u1e41\u1e43\u1e45\u1e47\u1e49\u1e4b\u1e4d\u1e4f\u1e51\u1e53\u1e55\u1e57\u1e59\u1e5b\u1e5d\u1e5f\u1e61\u1e63\u1e65\u1e67\u1e69\u1e6b\u1e6d\u1e6f\u1e71\u1e73\u1e75\u1e77\u1e79\u1e7b\u1e7d\u1e7f\u1e81\u1e83\u1e85\u1e87\u1e89\u1e8b\u1e8d\u1e8f\u1e91\u1e93\u1e95\u1e96\u1e97\u1e98\u1e99\u1e9a\u1e9b\u1ea1\u1ea3\u1ea5\u1ea7\u1ea9\u1eab\u1ead\u1eaf\u1eb1\u1eb3\u1eb5\u1eb7\u1eb9\u1ebb\u1ebd\u1ebf\u1ec1\u1ec3\u1ec5\u1ec7\u1ec9\u1ecb\u1ecd\u1ecf\u1ed1\u1ed3\u1ed5\u1ed7\u1ed9\u1edb\u1edd\u1edf\u1ee1\u1ee3\u1ee5\u1ee7\u1ee9\u1eeb\u1eed\u1eef\u1ef1\u1ef3\u1ef5\u1ef7\u1ef9\u1f00\u1f01\u1f02\u1f03\u1f04\u1f05\u1f06\u1f07\u1f10\u1f11\u1f12\u1f13\u1f14\u1f15\u1f20\u1f21\u1f22\u1f23\u1f24\u1f25\u1f26\u1f27\u1f30\u1f31\u1f32\u1f33\u1f34\u1f35\u1f36\u1f37\u1f40\u1f41\u1f42\u1f43\u1f44\u1f45\u1f50\u1f51\u1f52\u1f53\u1f54\u1f55\u1f56\u1f57\u1f60\u1f61\u1f62\u1f63\u1f64\u1f65\u1f66\u1f67\u1f70\u1f71\u1f72\u1f73\u1f74\u1f75\u1f76\u1f77\u1f78\u1f79\u1f7a\u1f7b\u1f7c\u1f7d\u1f80\u1f81\u1f82\u1f83\u1f84\u1f85\u1f86\u1f87\u1f90\u1f91\u1f92\u1f93\u1f94\u1f95\u1f96\u1f97\u1fa0\u1fa1\u1fa2\u1fa3\u1fa4\u1fa5\u1fa6\u1fa7\u1fb0\u1fb1\u1fb2\u1fb3\u1fb4\u1fb6\u1fb7\u1fbe\u1fc2\u1fc3\u1fc4\u1fc6\u1fc7\u1fd0\u1fd1\u1fd2\u1fd3\u1fd6\u1fd7\u1fe0\u1fe1\u1fe2\u1fe3\u1fe4\u1fe5\u1fe6\u1fe7\u1ff2\u1ff3\u1ff4\u1ff6\u1ff7\u2071\u207f\u210a\u210e\u210f\u2113\u212f\u2134\u2139\u213c\u213d\u2146\u2147\u2148\u2149\u2c30\u2c31\u2c32\u2c33\u2c34\u2c35\u2c36\u2c37\u2c38\u2c39\u2c3a\u2c3b\u2c3c\u2c3d\u2c3e\u2c3f\u2c40\u2c41\u2c42\u2c43\u2c44\u2c45\u2c46\u2c47\u2c48\u2c49\u2c4a\u2c4b\u2c4c\u2c4d\u2c4e\u2c4f\u2c50\u2c51\u2c52\u2c53\u2c54\u2c55\u2c56\u2c57\u2c58\u2c59\u2c5a\u2c5b\u2c5c\u2c5d\u2c5e\u2c81\u2c83\u2c85\u2c87\u2c89\u2c8b\u2c8d\u2c8f\u2c91\u2c93\u2c95\u2c97\u2c99\u2c9b\u2c9d\u2c9f\u2ca1\u2ca3\u2ca5\u2ca7\u2ca9\u2cab\u2cad\u2caf\u2cb1\u2cb3\u2cb5\u2cb7\u2cb9\u2cbb\u2cbd\u2cbf\u2cc1\u2cc3\u2cc5\u2cc7\u2cc9\u2ccb\u2ccd\u2ccf\u2cd1\u2cd3\u2cd5\u2cd7\u2cd9\u2cdb\u2cdd\u2cdf\u2ce1\u2ce3\u2ce4\u2d00\u2d01\u2d02\u2d03\u2d04\u2d05\u2d06\u2d07\u2d08\u2d09\u2d0a\u2d0b\u2d0c\u2d0d\u2d0e\u2d0f\u2d10\u2d11\u2d12\u2d13\u2d14\u2d15\u2d16\u2d17\u2d18\u2d19\u2d1a\u2d1b\u2d1c\u2d1d\u2d1e\u2d1f\u2d20\u2d21\u2d22\u2d23\u2d24\u2d25\ufb00\ufb01\ufb02\ufb03\ufb04\ufb05\ufb06\ufb13\ufb14\ufb15\ufb16\ufb17\uff41\uff42\uff43\uff44\uff45\uff46\uff47\uff48\uff49\uff4a\uff4b\uff4c\uff4d\uff4e\uff4f\uff50\uff51\uff52\uff53\uff54\uff55\uff56\uff57\uff58\uff59\uff5a'
+
+Lm = u'\u02b0\u02b1\u02b2\u02b3\u02b4\u02b5\u02b6\u02b7\u02b8\u02b9\u02ba\u02bb\u02bc\u02bd\u02be\u02bf\u02c0\u02c1\u02c6\u02c7\u02c8\u02c9\u02ca\u02cb\u02cc\u02cd\u02ce\u02cf\u02d0\u02d1\u02e0\u02e1\u02e2\u02e3\u02e4\u02ee\u037a\u0559\u0640\u06e5\u06e6\u0e46\u0ec6\u10fc\u17d7\u1843\u1d2c\u1d2d\u1d2e\u1d2f\u1d30\u1d31\u1d32\u1d33\u1d34\u1d35\u1d36\u1d37\u1d38\u1d39\u1d3a\u1d3b\u1d3c\u1d3d\u1d3e\u1d3f\u1d40\u1d41\u1d42\u1d43\u1d44\u1d45\u1d46\u1d47\u1d48\u1d49\u1d4a\u1d4b\u1d4c\u1d4d\u1d4e\u1d4f\u1d50\u1d51\u1d52\u1d53\u1d54\u1d55\u1d56\u1d57\u1d58\u1d59\u1d5a\u1d5b\u1d5c\u1d5d\u1d5e\u1d5f\u1d60\u1d61\u1d78\u1d9b\u1d9c\u1d9d\u1d9e\u1d9f\u1da0\u1da1\u1da2\u1da3\u1da4\u1da5\u1da6\u1da7\u1da8\u1da9\u1daa\u1dab\u1dac\u1dad\u1dae\u1daf\u1db0\u1db1\u1db2\u1db3\u1db4\u1db5\u1db6\u1db7\u1db8\u1db9\u1dba\u1dbb\u1dbc\u1dbd\u1dbe\u1dbf\u2090\u2091\u2092\u2093\u2094\u2d6f\u3005\u3031\u3032\u3033\u3034\u3035\u303b\u309d\u309e\u30fc\u30fd\u30fe\ua015\uff70\uff9e\uff9f'
+
+Lo = u'\u01bb\u01c0\u01c1\u01c2\u01c3\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9\u05da\u05db\u05dc\u05dd\u05de\u05df\u05e0\u05e1\u05e2\u05e3\u05e4\u05e5\u05e6\u05e7\u05e8\u05e9\u05ea\u05f0\u05f1\u05f2\u0621\u0622\u0623\u0624\u0625\u0626\u0627\u0628\u0629\u062a\u062b\u062c\u062d\u062e\u062f\u0630\u0631\u0632\u0633\u0634\u0635\u0636\u0637\u0638\u0639\u063a\u0641\u0642\u0643\u0644\u0645\u0646\u0647\u0648\u0649\u064a\u066e\u066f\u0671\u0672\u0673\u0674\u0675\u0676\u0677\u0678\u0679\u067a\u067b\u067c\u067d\u067e\u067f\u0680\u0681\u0682\u0683\u0684\u0685\u0686\u0687\u0688\u0689\u068a\u068b\u068c\u068d\u068e\u068f\u0690\u0691\u0692\u0693\u0694\u0695\u0696\u0697\u0698\u0699\u069a\u069b\u069c\u069d\u069e\u069f\u06a0\u06a1\u06a2\u06a3\u06a4\u06a5\u06a6\u06a7\u06a8\u06a9\u06aa\u06ab\u06ac\u06ad\u06ae\u06af\u06b0\u06b1\u06b2\u06b3\u06b4\u06b5\u06b6\u06b7\u06b8\u06b9\u06ba\u06bb\u06bc\u06bd\u06be\u06bf\u06c0\u06c1\u06c2\u06c3\u06c4\u06c5\u06c6\u06c7\u06c8\u06c9\u06ca\u06cb\u06cc\u06cd\u06ce\u06cf\u06d0\u06d1\u06d2\u06d3\u06d5\u06ee\u06ef\u06fa\u06fb\u06fc\u06ff\u0710\u0712\u0713\u0714\u0715\u0716\u0717\u0718\u0719\u071a\u071b\u071c\u071d\u071e\u071f\u0720\u0721\u0722\u0723\u0724\u0725\u0726\u0727\u0728\u0729\u072a\u072b\u072c\u072d\u072e\u072f\u074d\u074e\u074f\u0750\u0751\u0752\u0753\u0754\u0755\u0756\u0757\u0758\u0759\u075a\u075b\u075c\u075d\u075e\u075f\u0760\u0761\u0762\u0763\u0764\u0765\u0766\u0767\u0768\u0769\u076a\u076b\u076c\u076d\u0780\u0781\u0782\u0783\u0784\u0785\u0786\u0787\u0788\u0789\u078a\u078b\u078c\u078d\u078e\u078f\u0790\u0791\u0792\u0793\u0794\u0795\u0796\u0797\u0798\u0799\u079a\u079b\u079c\u079d\u079e\u079f\u07a0\u07a1\u07a2\u07a3\u07a4\u07a5\u07b1\u0904\u0905\u0906\u0907\u0908\u0909\u090a\u090b\u090c\u090d\u090e\u090f\u0910\u0911\u0912\u0913\u0914\u0915\u0916\u0917\u0918\u0919\u091a\u091b\u091c\u091d\u091e\u091f\u0920\u0921\u0922\u0923\u0924\u0925\u0926\u0927\u0928\u0929\u092a\u092b\u092c\u092d\u092e\u092f\u0930\u0931\u0932\u0933\u0934\u0935\u0936\u0937\u0938\u0939\u093d\u0950\u0958\u0959\u095a\u095b\u095c\u095d\u095e\u095f\u0960\u0961\u097d\u0985\u0986\u0987\u0988\u0989\u098a\u098b\u098c\u098f\u0990\u0993\u0994\u0995\u0996\u0997\u0998\u0999\u099a\u099b\u099c\u099d\u099e\u099f\u09a0\u09a1\u09a2\u09a3\u09a4\u09a5\u09a6\u09a7\u09a8\u09aa\u09ab\u09ac\u09ad\u09ae\u09af\u09b0\u09b2\u09b6\u09b7\u09b8\u09b9\u09bd\u09ce\u09dc\u09dd\u09df\u09e0\u09e1\u09f0\u09f1\u0a05\u0a06\u0a07\u0a08\u0a09\u0a0a\u0a0f\u0a10\u0a13\u0a14\u0a15\u0a16\u0a17\u0a18\u0a19\u0a1a\u0a1b\u0a1c\u0a1d\u0a1e\u0a1f\u0a20\u0a21\u0a22\u0a23\u0a24\u0a25\u0a26\u0a27\u0a28\u0a2a\u0a2b\u0a2c\u0a2d\u0a2e\u0a2f\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59\u0a5a\u0a5b\u0a5c\u0a5e\u0a72\u0a73\u0a74\u0a85\u0a86\u0a87\u0a88\u0a89\u0a8a\u0a8b\u0a8c\u0a8d\u0a8f\u0a90\u0a91\u0a93\u0a94\u0a95\u0a96\u0a97\u0a98\u0a99\u0a9a\u0a9b\u0a9c\u0a9d\u0a9e\u0a9f\u0aa0\u0aa1\u0aa2\u0aa3\u0aa4\u0aa5\u0aa6\u0aa7\u0aa8\u0aaa\u0aab\u0aac\u0aad\u0aae\u0aaf\u0ab0\u0ab2\u0ab3\u0ab5\u0ab6\u0ab7\u0ab8\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05\u0b06\u0b07\u0b08\u0b09\u0b0a\u0b0b\u0b0c\u0b0f\u0b10\u0b13\u0b14\u0b15\u0b16\u0b17\u0b18\u0b19\u0b1a\u0b1b\u0b1c\u0b1d\u0b1e\u0b1f\u0b20\u0b21\u0b22\u0b23\u0b24\u0b25\u0b26\u0b27\u0b28\u0b2a\u0b2b\u0b2c\u0b2d\u0b2e\u0b2f\u0b30\u0b32\u0b33\u0b35\u0b36\u0b37\u0b38\u0b39\u0b3d\u0b5c\u0b5d\u0b5f\u0b60\u0b61\u0b71\u0b83\u0b85\u0b86\u0b87\u0b88\u0b89\u0b8a\u0b8e\u0b8f\u0b90\u0b92\u0b93\u0b94\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8\u0ba9\u0baa\u0bae\u0baf\u0bb0\u0bb1\u0bb2\u0bb3\u0bb4\u0bb5\u0bb6\u0bb7\u0bb8\u0bb9\u0c05\u0c06\u0c07\u0c08\u0c09\u0c0a\u0c0b\u0c0c\u0c0e\u0c0f\u0c10\u0c12\u0c13\u0c14\u0c15\u0c16\u0c17\u0c18\u0c19\u0c1a\u0c1b\u0c1c\u0c1d\u0c1e\u0c1f\u0c20\u0c21\u0c22\u0c23\u0c24\u0c25\u0c26\u0c27\u0c28\u0c2a\u0c2b\u0c2c\u0c2d\u0c2e\u0c2f\u0c30\u0c31\u0c32\u0c33\u0c35\u0c36\u0c37\u0c38\u0c39\u0c60\u0c61\u0c85\u0c86\u0c87\u0c88\u0c89\u0c8a\u0c8b\u0c8c\u0c8e\u0c8f\u0c90\u0c92\u0c93\u0c94\u0c95\u0c96\u0c97\u0c98\u0c99\u0c9a\u0c9b\u0c9c\u0c9d\u0c9e\u0c9f\u0ca0\u0ca1\u0ca2\u0ca3\u0ca4\u0ca5\u0ca6\u0ca7\u0ca8\u0caa\u0cab\u0cac\u0cad\u0cae\u0caf\u0cb0\u0cb1\u0cb2\u0cb3\u0cb5\u0cb6\u0cb7\u0cb8\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0d05\u0d06\u0d07\u0d08\u0d09\u0d0a\u0d0b\u0d0c\u0d0e\u0d0f\u0d10\u0d12\u0d13\u0d14\u0d15\u0d16\u0d17\u0d18\u0d19\u0d1a\u0d1b\u0d1c\u0d1d\u0d1e\u0d1f\u0d20\u0d21\u0d22\u0d23\u0d24\u0d25\u0d26\u0d27\u0d28\u0d2a\u0d2b\u0d2c\u0d2d\u0d2e\u0d2f\u0d30\u0d31\u0d32\u0d33\u0d34\u0d35\u0d36\u0d37\u0d38\u0d39\u0d60\u0d61\u0d85\u0d86\u0d87\u0d88\u0d89\u0d8a\u0d8b\u0d8c\u0d8d\u0d8e\u0d8f\u0d90\u0d91\u0d92\u0d93\u0d94\u0d95\u0d96\u0d9a\u0d9b\u0d9c\u0d9d\u0d9e\u0d9f\u0da0\u0da1\u0da2\u0da3\u0da4\u0da5\u0da6\u0da7\u0da8\u0da9\u0daa\u0dab\u0dac\u0dad\u0dae\u0daf\u0db0\u0db1\u0db3\u0db4\u0db5\u0db6\u0db7\u0db8\u0db9\u0dba\u0dbb\u0dbd\u0dc0\u0dc1\u0dc2\u0dc3\u0dc4\u0dc5\u0dc6\u0e01\u0e02\u0e03\u0e04\u0e05\u0e06\u0e07\u0e08\u0e09\u0e0a\u0e0b\u0e0c\u0e0d\u0e0e\u0e0f\u0e10\u0e11\u0e12\u0e13\u0e14\u0e15\u0e16\u0e17\u0e18\u0e19\u0e1a\u0e1b\u0e1c\u0e1d\u0e1e\u0e1f\u0e20\u0e21\u0e22\u0e23\u0e24\u0e25\u0e26\u0e27\u0e28\u0e29\u0e2a\u0e2b\u0e2c\u0e2d\u0e2e\u0e2f\u0e30\u0e32\u0e33\u0e40\u0e41\u0e42\u0e43\u0e44\u0e45\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94\u0e95\u0e96\u0e97\u0e99\u0e9a\u0e9b\u0e9c\u0e9d\u0e9e\u0e9f\u0ea1\u0ea2\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead\u0eae\u0eaf\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0\u0ec1\u0ec2\u0ec3\u0ec4\u0edc\u0edd\u0f00\u0f40\u0f41\u0f42\u0f43\u0f44\u0f45\u0f46\u0f47\u0f49\u0f4a\u0f4b\u0f4c\u0f4d\u0f4e\u0f4f\u0f50\u0f51\u0f52\u0f53\u0f54\u0f55\u0f56\u0f57\u0f58\u0f59\u0f5a\u0f5b\u0f5c\u0f5d\u0f5e\u0f5f\u0f60\u0f61\u0f62\u0f63\u0f64\u0f65\u0f66\u0f67\u0f68\u0f69\u0f6a\u0f88\u0f89\u0f8a\u0f8b\u1000\u1001\u1002\u1003\u1004\u1005\u1006\u1007\u1008\u1009\u100a\u100b\u100c\u100d\u100e\u100f\u1010\u1011\u1012\u1013\u1014\u1015\u1016\u1017\u1018\u1019\u101a\u101b\u101c\u101d\u101e\u101f\u1020\u1021\u1023\u1024\u1025\u1026\u1027\u1029\u102a\u1050\u1051\u1052\u1053\u1054\u1055\u10d0\u10d1\u10d2\u10d3\u10d4\u10d5\u10d6\u10d7\u10d8\u10d9\u10da\u10db\u10dc\u10dd\u10de\u10df\u10e0\u10e1\u10e2\u10e3\u10e4\u10e5\u10e6\u10e7\u10e8\u10e9\u10ea\u10eb\u10ec\u10ed\u10ee\u10ef\u10f0\u10f1\u10f2\u10f3\u10f4\u10f5\u10f6\u10f7\u10f8\u10f9\u10fa\u1100\u1101\u1102\u1103\u1104\u1105\u1106\u1107\u1108\u1109\u110a\u110b\u110c\u110d\u110e\u110f\u1110\u1111\u1112\u1113\u1114\u1115\u1116\u1117\u1118\u1119\u111a\u111b\u111c\u111d\u111e\u111f\u1120\u1121\u1122\u1123\u1124\u1125\u1126\u1127\u1128\u1129\u112a\u112b\u112c\u112d\u112e\u112f\u1130\u1131\u1132\u1133\u1134\u1135\u1136\u1137\u1138\u1139\u113a\u113b\u113c\u113d\u113e\u113f\u1140\u1141\u1142\u1143\u1144\u1145\u1146\u1147\u1148\u1149\u114a\u114b\u114c\u114d\u114e\u114f\u1150\u1151\u1152\u1153\u1154\u1155\u1156\u1157\u1158\u1159\u115f\u1160\u1161\u1162\u1163\u1164\u1165\u1166\u1167\u1168\u1169\u116a\u116b\u116c\u116d\u116e\u116f\u1170\u1171\u1172\u1173\u1174\u1175\u1176\u1177\u1178\u1179\u117a\u117b\u117c\u117d\u117e\u117f\u1180\u1181\u1182\u1183\u1184\u1185\u1186\u1187\u1188\u1189\u118a\u118b\u118c\u118d\u118e\u118f\u1190\u1191\u1192\u1193\u1194\u1195\u1196\u1197\u1198\u1199\u119a\u119b\u119c\u119d\u119e\u119f\u11a0\u11a1\u11a2\u11a8\u11a9\u11aa\u11ab\u11ac\u11ad\u11ae\u11af\u11b0\u11b1\u11b2\u11b3\u11b4\u11b5\u11b6\u11b7\u11b8\u11b9\u11ba\u11bb\u11bc\u11bd\u11be\u11bf\u11c0\u11c1\u11c2\u11c3\u11c4\u11c5\u11c6\u11c7\u11c8\u11c9\u11ca\u11cb\u11cc\u11cd\u11ce\u11cf\u11d0\u11d1\u11d2\u11d3\u11d4\u11d5\u11d6\u11d7\u11d8\u11d9\u11da\u11db\u11dc\u11dd\u11de\u11df\u11e0\u11e1\u11e2\u11e3\u11e4\u11e5\u11e6\u11e7\u11e8\u11e9\u11ea\u11eb\u11ec\u11ed\u11ee\u11ef\u11f0\u11f1\u11f2\u11f3\u11f4\u11f5\u11f6\u11f7\u11f8\u11f9\u1200\u1201\u1202\u1203\u1204\u1205\u1206\u1207\u1208\u1209\u120a\u120b\u120c\u120d\u120e\u120f\u1210\u1211\u1212\u1213\u1214\u1215\u1216\u1217\u1218\u1219\u121a\u121b\u121c\u121d\u121e\u121f\u1220\u1221\u1222\u1223\u1224\u1225\u1226\u1227\u1228\u1229\u122a\u122b\u122c\u122d\u122e\u122f\u1230\u1231\u1232\u1233\u1234\u1235\u1236\u1237\u1238\u1239\u123a\u123b\u123c\u123d\u123e\u123f\u1240\u1241\u1242\u1243\u1244\u1245\u1246\u1247\u1248\u124a\u124b\u124c\u124d\u1250\u1251\u1252\u1253\u1254\u1255\u1256\u1258\u125a\u125b\u125c\u125d\u1260\u1261\u1262\u1263\u1264\u1265\u1266\u1267\u1268\u1269\u126a\u126b\u126c\u126d\u126e\u126f\u1270\u1271\u1272\u1273\u1274\u1275\u1276\u1277\u1278\u1279\u127a\u127b\u127c\u127d\u127e\u127f\u1280\u1281\u1282\u1283\u1284\u1285\u1286\u1287\u1288\u128a\u128b\u128c\u128d\u1290\u1291\u1292\u1293\u1294\u1295\u1296\u1297\u1298\u1299\u129a\u129b\u129c\u129d\u129e\u129f\u12a0\u12a1\u12a2\u12a3\u12a4\u12a5\u12a6\u12a7\u12a8\u12a9\u12aa\u12ab\u12ac\u12ad\u12ae\u12af\u12b0\u12b2\u12b3\u12b4\u12b5\u12b8\u12b9\u12ba\u12bb\u12bc\u12bd\u12be\u12c0\u12c2\u12c3\u12c4\u12c5\u12c8\u12c9\u12ca\u12cb\u12cc\u12cd\u12ce\u12cf\u12d0\u12d1\u12d2\u12d3\u12d4\u12d5\u12d6\u12d8\u12d9\u12da\u12db\u12dc\u12dd\u12de\u12df\u12e0\u12e1\u12e2\u12e3\u12e4\u12e5\u12e6\u12e7\u12e8\u12e9\u12ea\u12eb\u12ec\u12ed\u12ee\u12ef\u12f0\u12f1\u12f2\u12f3\u12f4\u12f5\u12f6\u12f7\u12f8\u12f9\u12fa\u12fb\u12fc\u12fd\u12fe\u12ff\u1300\u1301\u1302\u1303\u1304\u1305\u1306\u1307\u1308\u1309\u130a\u130b\u130c\u130d\u130e\u130f\u1310\u1312\u1313\u1314\u1315\u1318\u1319\u131a\u131b\u131c\u131d\u131e\u131f\u1320\u1321\u1322\u1323\u1324\u1325\u1326\u1327\u1328\u1329\u132a\u132b\u132c\u132d\u132e\u132f\u1330\u1331\u1332\u1333\u1334\u1335\u1336\u1337\u1338\u1339\u133a\u133b\u133c\u133d\u133e\u133f\u1340\u1341\u1342\u1343\u1344\u1345\u1346\u1347\u1348\u1349\u134a\u134b\u134c\u134d\u134e\u134f\u1350\u1351\u1352\u1353\u1354\u1355\u1356\u1357\u1358\u1359\u135a\u1380\u1381\u1382\u1383\u1384\u1385\u1386\u1387\u1388\u1389\u138a\u138b\u138c\u138d\u138e\u138f\u13a0\u13a1\u13a2\u13a3\u13a4\u13a5\u13a6\u13a7\u13a8\u13a9\u13aa\u13ab\u13ac\u13ad\u13ae\u13af\u13b0\u13b1\u13b2\u13b3\u13b4\u13b5\u13b6\u13b7\u13b8\u13b9\u13ba\u13bb\u13bc\u13bd\u13be\u13bf\u13c0\u13c1\u13c2\u13c3\u13c4\u13c5\u13c6\u13c7\u13c8\u13c9\u13ca\u13cb\u13cc\u13cd\u13ce\u13cf\u13d0\u13d1\u13d2\u13d3\u13d4\u13d5\u13d6\u13d7\u13d8\u13d9\u13da\u13db\u13dc\u13dd\u13de\u13df\u13e0\u13e1\u13e2\u13e3\u13e4\u13e5\u13e6\u13e7\u13e8\u13e9\u13ea\u13eb\u13ec\u13ed\u13ee\u13ef\u13f0\u13f1\u13f2\u13f3\u13f4\u1401\u1402\u1403\u1404\u1405\u1406\u1407\u1408\u1409\u140a\u140b\u140c\u140d\u140e\u140f\u1410\u1411\u1412\u1413\u1414\u1415\u1416\u1417\u1418\u1419\u141a\u141b\u141c\u141d\u141e\u141f\u1420\u1421\u1422\u1423\u1424\u1425\u1426\u1427\u1428\u1429\u142a\u142b\u142c\u142d\u142e\u142f\u1430\u1431\u1432\u1433\u1434\u1435\u1436\u1437\u1438\u1439\u143a\u143b\u143c\u143d\u143e\u143f\u1440\u1441\u1442\u1443\u1444\u1445\u1446\u1447\u1448\u1449\u144a\u144b\u144c\u144d\u144e\u144f\u1450\u1451\u1452\u1453\u1454\u1455\u1456\u1457\u1458\u1459\u145a\u145b\u145c\u145d\u145e\u145f\u1460\u1461\u1462\u1463\u1464\u1465\u1466\u1467\u1468\u1469\u146a\u146b\u146c\u146d\u146e\u146f\u1470\u1471\u1472\u1473\u1474\u1475\u1476\u1477\u1478\u1479\u147a\u147b\u147c\u147d\u147e\u147f\u1480\u1481\u1482\u1483\u1484\u1485\u1486\u1487\u1488\u1489\u148a\u148b\u148c\u148d\u148e\u148f\u1490\u1491\u1492\u1493\u1494\u1495\u1496\u1497\u1498\u1499\u149a\u149b\u149c\u149d\u149e\u149f\u14a0\u14a1\u14a2\u14a3\u14a4\u14a5\u14a6\u14a7\u14a8\u14a9\u14aa\u14ab\u14ac\u14ad\u14ae\u14af\u14b0\u14b1\u14b2\u14b3\u14b4\u14b5\u14b6\u14b7\u14b8\u14b9\u14ba\u14bb\u14bc\u14bd\u14be\u14bf\u14c0\u14c1\u14c2\u14c3\u14c4\u14c5\u14c6\u14c7\u14c8\u14c9\u14ca\u14cb\u14cc\u14cd\u14ce\u14cf\u14d0\u14d1\u14d2\u14d3\u14d4\u14d5\u14d6\u14d7\u14d8\u14d9\u14da\u14db\u14dc\u14dd\u14de\u14df\u14e0\u14e1\u14e2\u14e3\u14e4\u14e5\u14e6\u14e7\u14e8\u14e9\u14ea\u14eb\u14ec\u14ed\u14ee\u14ef\u14f0\u14f1\u14f2\u14f3\u14f4\u14f5\u14f6\u14f7\u14f8\u14f9\u14fa\u14fb\u14fc\u14fd\u14fe\u14ff\u1500\u1501\u1502\u1503\u1504\u1505\u1506\u1507\u1508\u1509\u150a\u150b\u150c\u150d\u150e\u150f\u1510\u1511\u1512\u1513\u1514\u1515\u1516\u1517\u1518\u1519\u151a\u151b\u151c\u151d\u151e\u151f\u1520\u1521\u1522\u1523\u1524\u1525\u1526\u1527\u1528\u1529\u152a\u152b\u152c\u152d\u152e\u152f\u1530\u1531\u1532\u1533\u1534\u1535\u1536\u1537\u1538\u1539\u153a\u153b\u153c\u153d\u153e\u153f\u1540\u1541\u1542\u1543\u1544\u1545\u1546\u1547\u1548\u1549\u154a\u154b\u154c\u154d\u154e\u154f\u1550\u1551\u1552\u1553\u1554\u1555\u1556\u1557\u1558\u1559\u155a\u155b\u155c\u155d\u155e\u155f\u1560\u1561\u1562\u1563\u1564\u1565\u1566\u1567\u1568\u1569\u156a\u156b\u156c\u156d\u156e\u156f\u1570\u1571\u1572\u1573\u1574\u1575\u1576\u1577\u1578\u1579\u157a\u157b\u157c\u157d\u157e\u157f\u1580\u1581\u1582\u1583\u1584\u1585\u1586\u1587\u1588\u1589\u158a\u158b\u158c\u158d\u158e\u158f\u1590\u1591\u1592\u1593\u1594\u1595\u1596\u1597\u1598\u1599\u159a\u159b\u159c\u159d\u159e\u159f\u15a0\u15a1\u15a2\u15a3\u15a4\u15a5\u15a6\u15a7\u15a8\u15a9\u15aa\u15ab\u15ac\u15ad\u15ae\u15af\u15b0\u15b1\u15b2\u15b3\u15b4\u15b5\u15b6\u15b7\u15b8\u15b9\u15ba\u15bb\u15bc\u15bd\u15be\u15bf\u15c0\u15c1\u15c2\u15c3\u15c4\u15c5\u15c6\u15c7\u15c8\u15c9\u15ca\u15cb\u15cc\u15cd\u15ce\u15cf\u15d0\u15d1\u15d2\u15d3\u15d4\u15d5\u15d6\u15d7\u15d8\u15d9\u15da\u15db\u15dc\u15dd\u15de\u15df\u15e0\u15e1\u15e2\u15e3\u15e4\u15e5\u15e6\u15e7\u15e8\u15e9\u15ea\u15eb\u15ec\u15ed\u15ee\u15ef\u15f0\u15f1\u15f2\u15f3\u15f4\u15f5\u15f6\u15f7\u15f8\u15f9\u15fa\u15fb\u15fc\u15fd\u15fe\u15ff\u1600\u1601\u1602\u1603\u1604\u1605\u1606\u1607\u1608\u1609\u160a\u160b\u160c\u160d\u160e\u160f\u1610\u1611\u1612\u1613\u1614\u1615\u1616\u1617\u1618\u1619\u161a\u161b\u161c\u161d\u161e\u161f\u1620\u1621\u1622\u1623\u1624\u1625\u1626\u1627\u1628\u1629\u162a\u162b\u162c\u162d\u162e\u162f\u1630\u1631\u1632\u1633\u1634\u1635\u1636\u1637\u1638\u1639\u163a\u163b\u163c\u163d\u163e\u163f\u1640\u1641\u1642\u1643\u1644\u1645\u1646\u1647\u1648\u1649\u164a\u164b\u164c\u164d\u164e\u164f\u1650\u1651\u1652\u1653\u1654\u1655\u1656\u1657\u1658\u1659\u165a\u165b\u165c\u165d\u165e\u165f\u1660\u1661\u1662\u1663\u1664\u1665\u1666\u1667\u1668\u1669\u166a\u166b\u166c\u166f\u1670\u1671\u1672\u1673\u1674\u1675\u1676\u1681\u1682\u1683\u1684\u1685\u1686\u1687\u1688\u1689\u168a\u168b\u168c\u168d\u168e\u168f\u1690\u1691\u1692\u1693\u1694\u1695\u1696\u1697\u1698\u1699\u169a\u16a0\u16a1\u16a2\u16a3\u16a4\u16a5\u16a6\u16a7\u16a8\u16a9\u16aa\u16ab\u16ac\u16ad\u16ae\u16af\u16b0\u16b1\u16b2\u16b3\u16b4\u16b5\u16b6\u16b7\u16b8\u16b9\u16ba\u16bb\u16bc\u16bd\u16be\u16bf\u16c0\u16c1\u16c2\u16c3\u16c4\u16c5\u16c6\u16c7\u16c8\u16c9\u16ca\u16cb\u16cc\u16cd\u16ce\u16cf\u16d0\u16d1\u16d2\u16d3\u16d4\u16d5\u16d6\u16d7\u16d8\u16d9\u16da\u16db\u16dc\u16dd\u16de\u16df\u16e0\u16e1\u16e2\u16e3\u16e4\u16e5\u16e6\u16e7\u16e8\u16e9\u16ea\u1700\u1701\u1702\u1703\u1704\u1705\u1706\u1707\u1708\u1709\u170a\u170b\u170c\u170e\u170f\u1710\u1711\u1720\u1721\u1722\u1723\u1724\u1725\u1726\u1727\u1728\u1729\u172a\u172b\u172c\u172d\u172e\u172f\u1730\u1731\u1740\u1741\u1742\u1743\u1744\u1745\u1746\u1747\u1748\u1749\u174a\u174b\u174c\u174d\u174e\u174f\u1750\u1751\u1760\u1761\u1762\u1763\u1764\u1765\u1766\u1767\u1768\u1769\u176a\u176b\u176c\u176e\u176f\u1770\u1780\u1781\u1782\u1783\u1784\u1785\u1786\u1787\u1788\u1789\u178a\u178b\u178c\u178d\u178e\u178f\u1790\u1791\u1792\u1793\u1794\u1795\u1796\u1797\u1798\u1799\u179a\u179b\u179c\u179d\u179e\u179f\u17a0\u17a1\u17a2\u17a3\u17a4\u17a5\u17a6\u17a7\u17a8\u17a9\u17aa\u17ab\u17ac\u17ad\u17ae\u17af\u17b0\u17b1\u17b2\u17b3\u17dc\u1820\u1821\u1822\u1823\u1824\u1825\u1826\u1827\u1828\u1829\u182a\u182b\u182c\u182d\u182e\u182f\u1830\u1831\u1832\u1833\u1834\u1835\u1836\u1837\u1838\u1839\u183a\u183b\u183c\u183d\u183e\u183f\u1840\u1841\u1842\u1844\u1845\u1846\u1847\u1848\u1849\u184a\u184b\u184c\u184d\u184e\u184f\u1850\u1851\u1852\u1853\u1854\u1855\u1856\u1857\u1858\u1859\u185a\u185b\u185c\u185d\u185e\u185f\u1860\u1861\u1862\u1863\u1864\u1865\u1866\u1867\u1868\u1869\u186a\u186b\u186c\u186d\u186e\u186f\u1870\u1871\u1872\u1873\u1874\u1875\u1876\u1877\u1880\u1881\u1882\u1883\u1884\u1885\u1886\u1887\u1888\u1889\u188a\u188b\u188c\u188d\u188e\u188f\u1890\u1891\u1892\u1893\u1894\u1895\u1896\u1897\u1898\u1899\u189a\u189b\u189c\u189d\u189e\u189f\u18a0\u18a1\u18a2\u18a3\u18a4\u18a5\u18a6\u18a7\u18a8\u1900\u1901\u1902\u1903\u1904\u1905\u1906\u1907\u1908\u1909\u190a\u190b\u190c\u190d\u190e\u190f\u1910\u1911\u1912\u1913\u1914\u1915\u1916\u1917\u1918\u1919\u191a\u191b\u191c\u1950\u1951\u1952\u1953\u1954\u1955\u1956\u1957\u1958\u1959\u195a\u195b\u195c\u195d\u195e\u195f\u1960\u1961\u1962\u1963\u1964\u1965\u1966\u1967\u1968\u1969\u196a\u196b\u196c\u196d\u1970\u1971\u1972\u1973\u1974\u1980\u1981\u1982\u1983\u1984\u1985\u1986\u1987\u1988\u1989\u198a\u198b\u198c\u198d\u198e\u198f\u1990\u1991\u1992\u1993\u1994\u1995\u1996\u1997\u1998\u1999\u199a\u199b\u199c\u199d\u199e\u199f\u19a0\u19a1\u19a2\u19a3\u19a4\u19a5\u19a6\u19a7\u19a8\u19a9\u19c1\u19c2\u19c3\u19c4\u19c5\u19c6\u19c7\u1a00\u1a01\u1a02\u1a03\u1a04\u1a05\u1a06\u1a07\u1a08\u1a09\u1a0a\u1a0b\u1a0c\u1a0d\u1a0e\u1a0f\u1a10\u1a11\u1a12\u1a13\u1a14\u1a15\u1a16\u2135\u2136\u2137\u2138\u2d30\u2d31\u2d32\u2d33\u2d34\u2d35\u2d36\u2d37\u2d38\u2d39\u2d3a\u2d3b\u2d3c\u2d3d\u2d3e\u2d3f\u2d40\u2d41\u2d42\u2d43\u2d44\u2d45\u2d46\u2d47\u2d48\u2d49\u2d4a\u2d4b\u2d4c\u2d4d\u2d4e\u2d4f\u2d50\u2d51\u2d52\u2d53\u2d54\u2d55\u2d56\u2d57\u2d58\u2d59\u2d5a\u2d5b\u2d5c\u2d5d\u2d5e\u2d5f\u2d60\u2d61\u2d62\u2d63\u2d64\u2d65\u2d80\u2d81\u2d82\u2d83\u2d84\u2d85\u2d86\u2d87\u2d88\u2d89\u2d8a\u2d8b\u2d8c\u2d8d\u2d8e\u2d8f\u2d90\u2d91\u2d92\u2d93\u2d94\u2d95\u2d96\u2da0\u2da1\u2da2\u2da3\u2da4\u2da5\u2da6\u2da8\u2da9\u2daa\u2dab\u2dac\u2dad\u2dae\u2db0\u2db1\u2db2\u2db3\u2db4\u2db5\u2db6\u2db8\u2db9\u2dba\u2dbb\u2dbc\u2dbd\u2dbe\u2dc0\u2dc1\u2dc2\u2dc3\u2dc4\u2dc5\u2dc6\u2dc8\u2dc9\u2dca\u2dcb\u2dcc\u2dcd\u2dce\u2dd0\u2dd1\u2dd2\u2dd3\u2dd4\u2dd5\u2dd6\u2dd8\u2dd9\u2dda\u2ddb\u2ddc\u2ddd\u2dde\u3006\u303c\u3041\u3042\u3043\u3044\u3045\u3046\u3047\u3048\u3049\u304a\u304b\u304c\u304d\u304e\u304f\u3050\u3051\u3052\u3053\u3054\u3055\u3056\u3057\u3058\u3059\u305a\u305b\u305c\u305d\u305e\u305f\u3060\u3061\u3062\u3063\u3064\u3065\u3066\u3067\u3068\u3069\u306a\u306b\u306c\u306d\u306e\u306f\u3070\u3071\u3072\u3073\u3074\u3075\u3076\u3077\u3078\u3079\u307a\u307b\u307c\u307d\u307e\u307f\u3080\u3081\u3082\u3083\u3084\u3085\u3086\u3087\u3088\u3089\u308a\u308b\u308c\u308d\u308e\u308f\u3090\u3091\u3092\u3093\u3094\u3095\u3096\u309f\u30a1\u30a2\u30a3\u30a4\u30a5\u30a6\u30a7\u30a8\u30a9\u30aa\u30ab\u30ac\u30ad\u30ae\u30af\u30b0\u30b1\u30b2\u30b3\u30b4\u30b5\u30b6\u30b7\u30b8\u30b9\u30ba\u30bb\u30bc\u30bd\u30be\u30bf\u30c0\u30c1\u30c2\u30c3\u30c4\u30c5\u30c6\u30c7\u30c8\u30c9\u30ca\u30cb\u30cc\u30cd\u30ce\u30cf\u30d0\u30d1\u30d2\u30d3\u30d4\u30d5\u30d6\u30d7\u30d8\u30d9\u30da\u30db\u30dc\u30dd\u30de\u30df\u30e0\u30e1\u30e2\u30e3\u30e4\u30e5\u30e6\u30e7\u30e8\u30e9\u30ea\u30eb\u30ec\u30ed\u30ee\u30ef\u30f0\u30f1\u30f2\u30f3\u30f4\u30f5\u30f6\u30f7\u30f8\u30f9\u30fa\u30ff\u3105\u3106\u3107\u3108\u3109\u310a\u310b\u310c\u310d\u310e\u310f\u3110\u3111\u3112\u3113\u3114\u3115\u3116\u3117\u3118\u3119\u311a\u311b\u311c\u311d\u311e\u311f\u3120\u3121\u3122\u3123\u3124\u3125\u3126\u3127\u3128\u3129\u312a\u312b\u312c\u3131\u3132\u3133\u3134\u3135\u3136\u3137\u3138\u3139\u313a\u313b\u313c\u313d\u313e\u313f\u3140\u3141\u3142\u3143\u3144\u3145\u3146\u3147\u3148\u3149\u314a\u314b\u314c\u314d\u314e\u314f\u3150\u3151\u3152\u3153\u3154\u3155\u3156\u3157\u3158\u3159\u315a\u315b\u315c\u315d\u315e\u315f\u3160\u3161\u3162\u3163\u3164\u3165\u3166\u3167\u3168\u3169\u316a\u316b\u316c\u316d\u316e\u316f\u3170\u3171\u3172\u3173\u3174\u3175\u3176\u3177\u3178\u3179\u317a\u317b\u317c\u317d\u317e\u317f\u3180\u3181\u3182\u3183\u3184\u3185\u3186\u3187\u3188\u3189\u318a\u318b\u318c\u318d\u318e\u31a0\u31a1\u31a2\u31a3\u31a4\u31a5\u31a6\u31a7\u31a8\u31a9\u31aa\u31ab\u31ac\u31ad\u31ae\u31af\u31b0\u31b1\u31b2\u31b3\u31b4\u31b5\u31b6\u31b7\u31f0\u31f1\u31f2\u31f3\u31f4\u31f5\u31f6\u31f7\u31f8\u31f9\u31fa\u31fb\u31fc\u31fd\u31fe\u31ff\u3400\u3401\u3402\u3403\u3404\u3405\u3406\u3407\u3408\u3409\u340a\u340b\u340c\u340d\u340e\u340f\u3410\u3411\u3412\u3413\u3414\u3415\u3416\u3417\u3418\u3419\u341a\u341b\u341c\u341d\u341e\u341f\u3420\u3421\u3422\u3423\u3424\u3425\u3426\u3427\u3428\u3429\u342a\u342b\u342c\u342d\u342e\u342f\u3430\u3431\u3432\u3433\u3434\u3435\u3436\u3437\u3438\u3439\u343a\u343b\u343c\u343d\u343e\u343f\u3440\u3441\u3442\u3443\u3444\u3445\u3446\u3447\u3448\u3449\u344a\u344b\u344c\u344d\u344e\u344f\u3450\u3451\u3452\u3453\u3454\u3455\u3456\u3457\u3458\u3459\u345a\u345b\u345c\u345d\u345e\u345f\u3460\u3461\u3462\u3463\u3464\u3465\u3466\u3467\u3468\u3469\u346a\u346b\u346c\u346d\u346e\u346f\u3470\u3471\u3472\u3473\u3474\u3475\u3476\u3477\u3478\u3479\u347a\u347b\u347c\u347d\u347e\u347f\u3480\u3481\u3482\u3483\u3484\u3485\u3486\u3487\u3488\u3489\u348a\u348b\u348c\u348d\u348e\u348f\u3490\u3491\u3492\u3493\u3494\u3495\u3496\u3497\u3498\u3499\u349a\u349b\u349c\u349d\u349e\u349f\u34a0\u34a1\u34a2\u34a3\u34a4\u34a5\u34a6\u34a7\u34a8\u34a9\u34aa\u34ab\u34ac\u34ad\u34ae\u34af\u34b0\u34b1\u34b2\u34b3\u34b4\u34b5\u34b6\u34b7\u34b8\u34b9\u34ba\u34bb\u34bc\u34bd\u34be\u34bf\u34c0\u34c1\u34c2\u34c3\u34c4\u34c5\u34c6\u34c7\u34c8\u34c9\u34ca\u34cb\u34cc\u34cd\u34ce\u34cf\u34d0\u34d1\u34d2\u34d3\u34d4\u34d5\u34d6\u34d7\u34d8\u34d9\u34da\u34db\u34dc\u34dd\u34de\u34df\u34e0\u34e1\u34e2\u34e3\u34e4\u34e5\u34e6\u34e7\u34e8\u34e9\u34ea\u34eb\u34ec\u34ed\u34ee\u34ef\u34f0\u34f1\u34f2\u34f3\u34f4\u34f5\u34f6\u34f7\u34f8\u34f9\u34fa\u34fb\u34fc\u34fd\u34fe\u34ff\u3500\u3501\u3502\u3503\u3504\u3505\u3506\u3507\u3508\u3509\u350a\u350b\u350c\u350d\u350e\u350f\u3510\u3511\u3512\u3513\u3514\u3515\u3516\u3517\u3518\u3519\u351a\u351b\u351c\u351d\u351e\u351f\u3520\u3521\u3522\u3523\u3524\u3525\u3526\u3527\u3528\u3529\u352a\u352b\u352c\u352d\u352e\u352f\u3530\u3531\u3532\u3533\u3534\u3535\u3536\u3537\u3538\u3539\u353a\u353b\u353c\u353d\u353e\u353f\u3540\u3541\u3542\u3543\u3544\u3545\u3546\u3547\u3548\u3549\u354a\u354b\u354c\u354d\u354e\u354f\u3550\u3551\u3552\u3553\u3554\u3555\u3556\u3557\u3558\u3559\u355a\u355b\u355c\u355d\u355e\u355f\u3560\u3561\u3562\u3563\u3564\u3565\u3566\u3567\u3568\u3569\u356a\u356b\u356c\u356d\u356e\u356f\u3570\u3571\u3572\u3573\u3574\u3575\u3576\u3577\u3578\u3579\u357a\u357b\u357c\u357d\u357e\u357f\u3580\u3581\u3582\u3583\u3584\u3585\u3586\u3587\u3588\u3589\u358a\u358b\u358c\u358d\u358e\u358f\u3590\u3591\u3592\u3593\u3594\u3595\u3596\u3597\u3598\u3599\u359a\u359b\u359c\u359d\u359e\u359f\u35a0\u35a1\u35a2\u35a3\u35a4\u35a5\u35a6\u35a7\u35a8\u35a9\u35aa\u35ab\u35ac\u35ad\u35ae\u35af\u35b0\u35b1\u35b2\u35b3\u35b4\u35b5\u35b6\u35b7\u35b8\u35b9\u35ba\u35bb\u35bc\u35bd\u35be\u35bf\u35c0\u35c1\u35c2\u35c3\u35c4\u35c5\u35c6\u35c7\u35c8\u35c9\u35ca\u35cb\u35cc\u35cd\u35ce\u35cf\u35d0\u35d1\u35d2\u35d3\u35d4\u35d5\u35d6\u35d7\u35d8\u35d9\u35da\u35db\u35dc\u35dd\u35de\u35df\u35e0\u35e1\u35e2\u35e3\u35e4\u35e5\u35e6\u35e7\u35e8\u35e9\u35ea\u35eb\u35ec\u35ed\u35ee\u35ef\u35f0\u35f1\u35f2\u35f3\u35f4\u35f5\u35f6\u35f7\u35f8\u35f9\u35fa\u35fb\u35fc\u35fd\u35fe\u35ff\u3600\u3601\u3602\u3603\u3604\u3605\u3606\u3607\u3608\u3609\u360a\u360b\u360c\u360d\u360e\u360f\u3610\u3611\u3612\u3613\u3614\u3615\u3616\u3617\u3618\u3619\u361a\u361b\u361c\u361d\u361e\u361f\u3620\u3621\u3622\u3623\u3624\u3625\u3626\u3627\u3628\u3629\u362a\u362b\u362c\u362d\u362e\u362f\u3630\u3631\u3632\u3633\u3634\u3635\u3636\u3637\u3638\u3639\u363a\u363b\u363c\u363d\u363e\u363f\u3640\u3641\u3642\u3643\u3644\u3645\u3646\u3647\u3648\u3649\u364a\u364b\u364c\u364d\u364e\u364f\u3650\u3651\u3652\u3653\u3654\u3655\u3656\u3657\u3658\u3659\u365a\u365b\u365c\u365d\u365e\u365f\u3660\u3661\u3662\u3663\u3664\u3665\u3666\u3667\u3668\u3669\u366a\u366b\u366c\u366d\u366e\u366f\u3670\u3671\u3672\u3673\u3674\u3675\u3676\u3677\u3678\u3679\u367a\u367b\u367c\u367d\u367e\u367f\u3680\u3681\u3682\u3683\u3684\u3685\u3686\u3687\u3688\u3689\u368a\u368b\u368c\u368d\u368e\u368f\u3690\u3691\u3692\u3693\u3694\u3695\u3696\u3697\u3698\u3699\u369a\u369b\u369c\u369d\u369e\u369f\u36a0\u36a1\u36a2\u36a3\u36a4\u36a5\u36a6\u36a7\u36a8\u36a9\u36aa\u36ab\u36ac\u36ad\u36ae\u36af\u36b0\u36b1\u36b2\u36b3\u36b4\u36b5\u36b6\u36b7\u36b8\u36b9\u36ba\u36bb\u36bc\u36bd\u36be\u36bf\u36c0\u36c1\u36c2\u36c3\u36c4\u36c5\u36c6\u36c7\u36c8\u36c9\u36ca\u36cb\u36cc\u36cd\u36ce\u36cf\u36d0\u36d1\u36d2\u36d3\u36d4\u36d5\u36d6\u36d7\u36d8\u36d9\u36da\u36db\u36dc\u36dd\u36de\u36df\u36e0\u36e1\u36e2\u36e3\u36e4\u36e5\u36e6\u36e7\u36e8\u36e9\u36ea\u36eb\u36ec\u36ed\u36ee\u36ef\u36f0\u36f1\u36f2\u36f3\u36f4\u36f5\u36f6\u36f7\u36f8\u36f9\u36fa\u36fb\u36fc\u36fd\u36fe\u36ff\u3700\u3701\u3702\u3703\u3704\u3705\u3706\u3707\u3708\u3709\u370a\u370b\u370c\u370d\u370e\u370f\u3710\u3711\u3712\u3713\u3714\u3715\u3716\u3717\u3718\u3719\u371a\u371b\u371c\u371d\u371e\u371f\u3720\u3721\u3722\u3723\u3724\u3725\u3726\u3727\u3728\u3729\u372a\u372b\u372c\u372d\u372e\u372f\u3730\u3731\u3732\u3733\u3734\u3735\u3736\u3737\u3738\u3739\u373a\u373b\u373c\u373d\u373e\u373f\u3740\u3741\u3742\u3743\u3744\u3745\u3746\u3747\u3748\u3749\u374a\u374b\u374c\u374d\u374e\u374f\u3750\u3751\u3752\u3753\u3754\u3755\u3756\u3757\u3758\u3759\u375a\u375b\u375c\u375d\u375e\u375f\u3760\u3761\u3762\u3763\u3764\u3765\u3766\u3767\u3768\u3769\u376a\u376b\u376c\u376d\u376e\u376f\u3770\u3771\u3772\u3773\u3774\u3775\u3776\u3777\u3778\u3779\u377a\u377b\u377c\u377d\u377e\u377f\u3780\u3781\u3782\u3783\u3784\u3785\u3786\u3787\u3788\u3789\u378a\u378b\u378c\u378d\u378e\u378f\u3790\u3791\u3792\u3793\u3794\u3795\u3796\u3797\u3798\u3799\u379a\u379b\u379c\u379d\u379e\u379f\u37a0\u37a1\u37a2\u37a3\u37a4\u37a5\u37a6\u37a7\u37a8\u37a9\u37aa\u37ab\u37ac\u37ad\u37ae\u37af\u37b0\u37b1\u37b2\u37b3\u37b4\u37b5\u37b6\u37b7\u37b8\u37b9\u37ba\u37bb\u37bc\u37bd\u37be\u37bf\u37c0\u37c1\u37c2\u37c3\u37c4\u37c5\u37c6\u37c7\u37c8\u37c9\u37ca\u37cb\u37cc\u37cd\u37ce\u37cf\u37d0\u37d1\u37d2\u37d3\u37d4\u37d5\u37d6\u37d7\u37d8\u37d9\u37da\u37db\u37dc\u37dd\u37de\u37df\u37e0\u37e1\u37e2\u37e3\u37e4\u37e5\u37e6\u37e7\u37e8\u37e9\u37ea\u37eb\u37ec\u37ed\u37ee\u37ef\u37f0\u37f1\u37f2\u37f3\u37f4\u37f5\u37f6\u37f7\u37f8\u37f9\u37fa\u37fb\u37fc\u37fd\u37fe\u37ff\u3800\u3801\u3802\u3803\u3804\u3805\u3806\u3807\u3808\u3809\u380a\u380b\u380c\u380d\u380e\u380f\u3810\u3811\u3812\u3813\u3814\u3815\u3816\u3817\u3818\u3819\u381a\u381b\u381c\u381d\u381e\u381f\u3820\u3821\u3822\u3823\u3824\u3825\u3826\u3827\u3828\u3829\u382a\u382b\u382c\u382d\u382e\u382f\u3830\u3831\u3832\u3833\u3834\u3835\u3836\u3837\u3838\u3839\u383a\u383b\u383c\u383d\u383e\u383f\u3840\u3841\u3842\u3843\u3844\u3845\u3846\u3847\u3848\u3849\u384a\u384b\u384c\u384d\u384e\u384f\u3850\u3851\u3852\u3853\u3854\u3855\u3856\u3857\u3858\u3859\u385a\u385b\u385c\u385d\u385e\u385f\u3860\u3861\u3862\u3863\u3864\u3865\u3866\u3867\u3868\u3869\u386a\u386b\u386c\u386d\u386e\u386f\u3870\u3871\u3872\u3873\u3874\u3875\u3876\u3877\u3878\u3879\u387a\u387b\u387c\u387d\u387e\u387f\u3880\u3881\u3882\u3883\u3884\u3885\u3886\u3887\u3888\u3889\u388a\u388b\u388c\u388d\u388e\u388f\u3890\u3891\u3892\u3893\u3894\u3895\u3896\u3897\u3898\u3899\u389a\u389b\u389c\u389d\u389e\u389f\u38a0\u38a1\u38a2\u38a3\u38a4\u38a5\u38a6\u38a7\u38a8\u38a9\u38aa\u38ab\u38ac\u38ad\u38ae\u38af\u38b0\u38b1\u38b2\u38b3\u38b4\u38b5\u38b6\u38b7\u38b8\u38b9\u38ba\u38bb\u38bc\u38bd\u38be\u38bf\u38c0\u38c1\u38c2\u38c3\u38c4\u38c5\u38c6\u38c7\u38c8\u38c9\u38ca\u38cb\u38cc\u38cd\u38ce\u38cf\u38d0\u38d1\u38d2\u38d3\u38d4\u38d5\u38d6\u38d7\u38d8\u38d9\u38da\u38db\u38dc\u38dd\u38de\u38df\u38e0\u38e1\u38e2\u38e3\u38e4\u38e5\u38e6\u38e7\u38e8\u38e9\u38ea\u38eb\u38ec\u38ed\u38ee\u38ef\u38f0\u38f1\u38f2\u38f3\u38f4\u38f5\u38f6\u38f7\u38f8\u38f9\u38fa\u38fb\u38fc\u38fd\u38fe\u38ff\u3900\u3901\u3902\u3903\u3904\u3905\u3906\u3907\u3908\u3909\u390a\u390b\u390c\u390d\u390e\u390f\u3910\u3911\u3912\u3913\u3914\u3915\u3916\u3917\u3918\u3919\u391a\u391b\u391c\u391d\u391e\u391f\u3920\u3921\u3922\u3923\u3924\u3925\u3926\u3927\u3928\u3929\u392a\u392b\u392c\u392d\u392e\u392f\u3930\u3931\u3932\u3933\u3934\u3935\u3936\u3937\u3938\u3939\u393a\u393b\u393c\u393d\u393e\u393f\u3940\u3941\u3942\u3943\u3944\u3945\u3946\u3947\u3948\u3949\u394a\u394b\u394c\u394d\u394e\u394f\u3950\u3951\u3952\u3953\u3954\u3955\u3956\u3957\u3958\u3959\u395a\u395b\u395c\u395d\u395e\u395f\u3960\u3961\u3962\u3963\u3964\u3965\u3966\u3967\u3968\u3969\u396a\u396b\u396c\u396d\u396e\u396f\u3970\u3971\u3972\u3973\u3974\u3975\u3976\u3977\u3978\u3979\u397a\u397b\u397c\u397d\u397e\u397f\u3980\u3981\u3982\u3983\u3984\u3985\u3986\u3987\u3988\u3989\u398a\u398b\u398c\u398d\u398e\u398f\u3990\u3991\u3992\u3993\u3994\u3995\u3996\u3997\u3998\u3999\u399a\u399b\u399c\u399d\u399e\u399f\u39a0\u39a1\u39a2\u39a3\u39a4\u39a5\u39a6\u39a7\u39a8\u39a9\u39aa\u39ab\u39ac\u39ad\u39ae\u39af\u39b0\u39b1\u39b2\u39b3\u39b4\u39b5\u39b6\u39b7\u39b8\u39b9\u39ba\u39bb\u39bc\u39bd\u39be\u39bf\u39c0\u39c1\u39c2\u39c3\u39c4\u39c5\u39c6\u39c7\u39c8\u39c9\u39ca\u39cb\u39cc\u39cd\u39ce\u39cf\u39d0\u39d1\u39d2\u39d3\u39d4\u39d5\u39d6\u39d7\u39d8\u39d9\u39da\u39db\u39dc\u39dd\u39de\u39df\u39e0\u39e1\u39e2\u39e3\u39e4\u39e5\u39e6\u39e7\u39e8\u39e9\u39ea\u39eb\u39ec\u39ed\u39ee\u39ef\u39f0\u39f1\u39f2\u39f3\u39f4\u39f5\u39f6\u39f7\u39f8\u39f9\u39fa\u39fb\u39fc\u39fd\u39fe\u39ff\u3a00\u3a01\u3a02\u3a03\u3a04\u3a05\u3a06\u3a07\u3a08\u3a09\u3a0a\u3a0b\u3a0c\u3a0d\u3a0e\u3a0f\u3a10\u3a11\u3a12\u3a13\u3a14\u3a15\u3a16\u3a17\u3a18\u3a19\u3a1a\u3a1b\u3a1c\u3a1d\u3a1e\u3a1f\u3a20\u3a21\u3a22\u3a23\u3a24\u3a25\u3a26\u3a27\u3a28\u3a29\u3a2a\u3a2b\u3a2c\u3a2d\u3a2e\u3a2f\u3a30\u3a31\u3a32\u3a33\u3a34\u3a35\u3a36\u3a37\u3a38\u3a39\u3a3a\u3a3b\u3a3c\u3a3d\u3a3e\u3a3f\u3a40\u3a41\u3a42\u3a43\u3a44\u3a45\u3a46\u3a47\u3a48\u3a49\u3a4a\u3a4b\u3a4c\u3a4d\u3a4e\u3a4f\u3a50\u3a51\u3a52\u3a53\u3a54\u3a55\u3a56\u3a57\u3a58\u3a59\u3a5a\u3a5b\u3a5c\u3a5d\u3a5e\u3a5f\u3a60\u3a61\u3a62\u3a63\u3a64\u3a65\u3a66\u3a67\u3a68\u3a69\u3a6a\u3a6b\u3a6c\u3a6d\u3a6e\u3a6f\u3a70\u3a71\u3a72\u3a73\u3a74\u3a75\u3a76\u3a77\u3a78\u3a79\u3a7a\u3a7b\u3a7c\u3a7d\u3a7e\u3a7f\u3a80\u3a81\u3a82\u3a83\u3a84\u3a85\u3a86\u3a87\u3a88\u3a89\u3a8a\u3a8b\u3a8c\u3a8d\u3a8e\u3a8f\u3a90\u3a91\u3a92\u3a93\u3a94\u3a95\u3a96\u3a97\u3a98\u3a99\u3a9a\u3a9b\u3a9c\u3a9d\u3a9e\u3a9f\u3aa0\u3aa1\u3aa2\u3aa3\u3aa4\u3aa5\u3aa6\u3aa7\u3aa8\u3aa9\u3aaa\u3aab\u3aac\u3aad\u3aae\u3aaf\u3ab0\u3ab1\u3ab2\u3ab3\u3ab4\u3ab5\u3ab6\u3ab7\u3ab8\u3ab9\u3aba\u3abb\u3abc\u3abd\u3abe\u3abf\u3ac0\u3ac1\u3ac2\u3ac3\u3ac4\u3ac5\u3ac6\u3ac7\u3ac8\u3ac9\u3aca\u3acb\u3acc\u3acd\u3ace\u3acf\u3ad0\u3ad1\u3ad2\u3ad3\u3ad4\u3ad5\u3ad6\u3ad7\u3ad8\u3ad9\u3ada\u3adb\u3adc\u3add\u3ade\u3adf\u3ae0\u3ae1\u3ae2\u3ae3\u3ae4\u3ae5\u3ae6\u3ae7\u3ae8\u3ae9\u3aea\u3aeb\u3aec\u3aed\u3aee\u3aef\u3af0\u3af1\u3af2\u3af3\u3af4\u3af5\u3af6\u3af7\u3af8\u3af9\u3afa\u3afb\u3afc\u3afd\u3afe\u3aff\u3b00\u3b01\u3b02\u3b03\u3b04\u3b05\u3b06\u3b07\u3b08\u3b09\u3b0a\u3b0b\u3b0c\u3b0d\u3b0e\u3b0f\u3b10\u3b11\u3b12\u3b13\u3b14\u3b15\u3b16\u3b17\u3b18\u3b19\u3b1a\u3b1b\u3b1c\u3b1d\u3b1e\u3b1f\u3b20\u3b21\u3b22\u3b23\u3b24\u3b25\u3b26\u3b27\u3b28\u3b29\u3b2a\u3b2b\u3b2c\u3b2d\u3b2e\u3b2f\u3b30\u3b31\u3b32\u3b33\u3b34\u3b35\u3b36\u3b37\u3b38\u3b39\u3b3a\u3b3b\u3b3c\u3b3d\u3b3e\u3b3f\u3b40\u3b41\u3b42\u3b43\u3b44\u3b45\u3b46\u3b47\u3b48\u3b49\u3b4a\u3b4b\u3b4c\u3b4d\u3b4e\u3b4f\u3b50\u3b51\u3b52\u3b53\u3b54\u3b55\u3b56\u3b57\u3b58\u3b59\u3b5a\u3b5b\u3b5c\u3b5d\u3b5e\u3b5f\u3b60\u3b61\u3b62\u3b63\u3b64\u3b65\u3b66\u3b67\u3b68\u3b69\u3b6a\u3b6b\u3b6c\u3b6d\u3b6e\u3b6f\u3b70\u3b71\u3b72\u3b73\u3b74\u3b75\u3b76\u3b77\u3b78\u3b79\u3b7a\u3b7b\u3b7c\u3b7d\u3b7e\u3b7f\u3b80\u3b81\u3b82\u3b83\u3b84\u3b85\u3b86\u3b87\u3b88\u3b89\u3b8a\u3b8b\u3b8c\u3b8d\u3b8e\u3b8f\u3b90\u3b91\u3b92\u3b93\u3b94\u3b95\u3b96\u3b97\u3b98\u3b99\u3b9a\u3b9b\u3b9c\u3b9d\u3b9e\u3b9f\u3ba0\u3ba1\u3ba2\u3ba3\u3ba4\u3ba5\u3ba6\u3ba7\u3ba8\u3ba9\u3baa\u3bab\u3bac\u3bad\u3bae\u3baf\u3bb0\u3bb1\u3bb2\u3bb3\u3bb4\u3bb5\u3bb6\u3bb7\u3bb8\u3bb9\u3bba\u3bbb\u3bbc\u3bbd\u3bbe\u3bbf\u3bc0\u3bc1\u3bc2\u3bc3\u3bc4\u3bc5\u3bc6\u3bc7\u3bc8\u3bc9\u3bca\u3bcb\u3bcc\u3bcd\u3bce\u3bcf\u3bd0\u3bd1\u3bd2\u3bd3\u3bd4\u3bd5\u3bd6\u3bd7\u3bd8\u3bd9\u3bda\u3bdb\u3bdc\u3bdd\u3bde\u3bdf\u3be0\u3be1\u3be2\u3be3\u3be4\u3be5\u3be6\u3be7\u3be8\u3be9\u3bea\u3beb\u3bec\u3bed\u3bee\u3bef\u3bf0\u3bf1\u3bf2\u3bf3\u3bf4\u3bf5\u3bf6\u3bf7\u3bf8\u3bf9\u3bfa\u3bfb\u3bfc\u3bfd\u3bfe\u3bff\u3c00\u3c01\u3c02\u3c03\u3c04\u3c05\u3c06\u3c07\u3c08\u3c09\u3c0a\u3c0b\u3c0c\u3c0d\u3c0e\u3c0f\u3c10\u3c11\u3c12\u3c13\u3c14\u3c15\u3c16\u3c17\u3c18\u3c19\u3c1a\u3c1b\u3c1c\u3c1d\u3c1e\u3c1f\u3c20\u3c21\u3c22\u3c23\u3c24\u3c25\u3c26\u3c27\u3c28\u3c29\u3c2a\u3c2b\u3c2c\u3c2d\u3c2e\u3c2f\u3c30\u3c31\u3c32\u3c33\u3c34\u3c35\u3c36\u3c37\u3c38\u3c39\u3c3a\u3c3b\u3c3c\u3c3d\u3c3e\u3c3f\u3c40\u3c41\u3c42\u3c43\u3c44\u3c45\u3c46\u3c47\u3c48\u3c49\u3c4a\u3c4b\u3c4c\u3c4d\u3c4e\u3c4f\u3c50\u3c51\u3c52\u3c53\u3c54\u3c55\u3c56\u3c57\u3c58\u3c59\u3c5a\u3c5b\u3c5c\u3c5d\u3c5e\u3c5f\u3c60\u3c61\u3c62\u3c63\u3c64\u3c65\u3c66\u3c67\u3c68\u3c69\u3c6a\u3c6b\u3c6c\u3c6d\u3c6e\u3c6f\u3c70\u3c71\u3c72\u3c73\u3c74\u3c75\u3c76\u3c77\u3c78\u3c79\u3c7a\u3c7b\u3c7c\u3c7d\u3c7e\u3c7f\u3c80\u3c81\u3c82\u3c83\u3c84\u3c85\u3c86\u3c87\u3c88\u3c89\u3c8a\u3c8b\u3c8c\u3c8d\u3c8e\u3c8f\u3c90\u3c91\u3c92\u3c93\u3c94\u3c95\u3c96\u3c97\u3c98\u3c99\u3c9a\u3c9b\u3c9c\u3c9d\u3c9e\u3c9f\u3ca0\u3ca1\u3ca2\u3ca3\u3ca4\u3ca5\u3ca6\u3ca7\u3ca8\u3ca9\u3caa\u3cab\u3cac\u3cad\u3cae\u3caf\u3cb0\u3cb1\u3cb2\u3cb3\u3cb4\u3cb5\u3cb6\u3cb7\u3cb8\u3cb9\u3cba\u3cbb\u3cbc\u3cbd\u3cbe\u3cbf\u3cc0\u3cc1\u3cc2\u3cc3\u3cc4\u3cc5\u3cc6\u3cc7\u3cc8\u3cc9\u3cca\u3ccb\u3ccc\u3ccd\u3cce\u3ccf\u3cd0\u3cd1\u3cd2\u3cd3\u3cd4\u3cd5\u3cd6\u3cd7\u3cd8\u3cd9\u3cda\u3cdb\u3cdc\u3cdd\u3cde\u3cdf\u3ce0\u3ce1\u3ce2\u3ce3\u3ce4\u3ce5\u3ce6\u3ce7\u3ce8\u3ce9\u3cea\u3ceb\u3cec\u3ced\u3cee\u3cef\u3cf0\u3cf1\u3cf2\u3cf3\u3cf4\u3cf5\u3cf6\u3cf7\u3cf8\u3cf9\u3cfa\u3cfb\u3cfc\u3cfd\u3cfe\u3cff\u3d00\u3d01\u3d02\u3d03\u3d04\u3d05\u3d06\u3d07\u3d08\u3d09\u3d0a\u3d0b\u3d0c\u3d0d\u3d0e\u3d0f\u3d10\u3d11\u3d12\u3d13\u3d14\u3d15\u3d16\u3d17\u3d18\u3d19\u3d1a\u3d1b\u3d1c\u3d1d\u3d1e\u3d1f\u3d20\u3d21\u3d22\u3d23\u3d24\u3d25\u3d26\u3d27\u3d28\u3d29\u3d2a\u3d2b\u3d2c\u3d2d\u3d2e\u3d2f\u3d30\u3d31\u3d32\u3d33\u3d34\u3d35\u3d36\u3d37\u3d38\u3d39\u3d3a\u3d3b\u3d3c\u3d3d\u3d3e\u3d3f\u3d40\u3d41\u3d42\u3d43\u3d44\u3d45\u3d46\u3d47\u3d48\u3d49\u3d4a\u3d4b\u3d4c\u3d4d\u3d4e\u3d4f\u3d50\u3d51\u3d52\u3d53\u3d54\u3d55\u3d56\u3d57\u3d58\u3d59\u3d5a\u3d5b\u3d5c\u3d5d\u3d5e\u3d5f\u3d60\u3d61\u3d62\u3d63\u3d64\u3d65\u3d66\u3d67\u3d68\u3d69\u3d6a\u3d6b\u3d6c\u3d6d\u3d6e\u3d6f\u3d70\u3d71\u3d72\u3d73\u3d74\u3d75\u3d76\u3d77\u3d78\u3d79\u3d7a\u3d7b\u3d7c\u3d7d\u3d7e\u3d7f\u3d80\u3d81\u3d82\u3d83\u3d84\u3d85\u3d86\u3d87\u3d88\u3d89\u3d8a\u3d8b\u3d8c\u3d8d\u3d8e\u3d8f\u3d90\u3d91\u3d92\u3d93\u3d94\u3d95\u3d96\u3d97\u3d98\u3d99\u3d9a\u3d9b\u3d9c\u3d9d\u3d9e\u3d9f\u3da0\u3da1\u3da2\u3da3\u3da4\u3da5\u3da6\u3da7\u3da8\u3da9\u3daa\u3dab\u3dac\u3dad\u3dae\u3daf\u3db0\u3db1\u3db2\u3db3\u3db4\u3db5\u3db6\u3db7\u3db8\u3db9\u3dba\u3dbb\u3dbc\u3dbd\u3dbe\u3dbf\u3dc0\u3dc1\u3dc2\u3dc3\u3dc4\u3dc5\u3dc6\u3dc7\u3dc8\u3dc9\u3dca\u3dcb\u3dcc\u3dcd\u3dce\u3dcf\u3dd0\u3dd1\u3dd2\u3dd3\u3dd4\u3dd5\u3dd6\u3dd7\u3dd8\u3dd9\u3dda\u3ddb\u3ddc\u3ddd\u3dde\u3ddf\u3de0\u3de1\u3de2\u3de3\u3de4\u3de5\u3de6\u3de7\u3de8\u3de9\u3dea\u3deb\u3dec\u3ded\u3dee\u3def\u3df0\u3df1\u3df2\u3df3\u3df4\u3df5\u3df6\u3df7\u3df8\u3df9\u3dfa\u3dfb\u3dfc\u3dfd\u3dfe\u3dff\u3e00\u3e01\u3e02\u3e03\u3e04\u3e05\u3e06\u3e07\u3e08\u3e09\u3e0a\u3e0b\u3e0c\u3e0d\u3e0e\u3e0f\u3e10\u3e11\u3e12\u3e13\u3e14\u3e15\u3e16\u3e17\u3e18\u3e19\u3e1a\u3e1b\u3e1c\u3e1d\u3e1e\u3e1f\u3e20\u3e21\u3e22\u3e23\u3e24\u3e25\u3e26\u3e27\u3e28\u3e29\u3e2a\u3e2b\u3e2c\u3e2d\u3e2e\u3e2f\u3e30\u3e31\u3e32\u3e33\u3e34\u3e35\u3e36\u3e37\u3e38\u3e39\u3e3a\u3e3b\u3e3c\u3e3d\u3e3e\u3e3f\u3e40\u3e41\u3e42\u3e43\u3e44\u3e45\u3e46\u3e47\u3e48\u3e49\u3e4a\u3e4b\u3e4c\u3e4d\u3e4e\u3e4f\u3e50\u3e51\u3e52\u3e53\u3e54\u3e55\u3e56\u3e57\u3e58\u3e59\u3e5a\u3e5b\u3e5c\u3e5d\u3e5e\u3e5f\u3e60\u3e61\u3e62\u3e63\u3e64\u3e65\u3e66\u3e67\u3e68\u3e69\u3e6a\u3e6b\u3e6c\u3e6d\u3e6e\u3e6f\u3e70\u3e71\u3e72\u3e73\u3e74\u3e75\u3e76\u3e77\u3e78\u3e79\u3e7a\u3e7b\u3e7c\u3e7d\u3e7e\u3e7f\u3e80\u3e81\u3e82\u3e83\u3e84\u3e85\u3e86\u3e87\u3e88\u3e89\u3e8a\u3e8b\u3e8c\u3e8d\u3e8e\u3e8f\u3e90\u3e91\u3e92\u3e93\u3e94\u3e95\u3e96\u3e97\u3e98\u3e99\u3e9a\u3e9b\u3e9c\u3e9d\u3e9e\u3e9f\u3ea0\u3ea1\u3ea2\u3ea3\u3ea4\u3ea5\u3ea6\u3ea7\u3ea8\u3ea9\u3eaa\u3eab\u3eac\u3ead\u3eae\u3eaf\u3eb0\u3eb1\u3eb2\u3eb3\u3eb4\u3eb5\u3eb6\u3eb7\u3eb8\u3eb9\u3eba\u3ebb\u3ebc\u3ebd\u3ebe\u3ebf\u3ec0\u3ec1\u3ec2\u3ec3\u3ec4\u3ec5\u3ec6\u3ec7\u3ec8\u3ec9\u3eca\u3ecb\u3ecc\u3ecd\u3ece\u3ecf\u3ed0\u3ed1\u3ed2\u3ed3\u3ed4\u3ed5\u3ed6\u3ed7\u3ed8\u3ed9\u3eda\u3edb\u3edc\u3edd\u3ede\u3edf\u3ee0\u3ee1\u3ee2\u3ee3\u3ee4\u3ee5\u3ee6\u3ee7\u3ee8\u3ee9\u3eea\u3eeb\u3eec\u3eed\u3eee\u3eef\u3ef0\u3ef1\u3ef2\u3ef3\u3ef4\u3ef5\u3ef6\u3ef7\u3ef8\u3ef9\u3efa\u3efb\u3efc\u3efd\u3efe\u3eff\u3f00\u3f01\u3f02\u3f03\u3f04\u3f05\u3f06\u3f07\u3f08\u3f09\u3f0a\u3f0b\u3f0c\u3f0d\u3f0e\u3f0f\u3f10\u3f11\u3f12\u3f13\u3f14\u3f15\u3f16\u3f17\u3f18\u3f19\u3f1a\u3f1b\u3f1c\u3f1d\u3f1e\u3f1f\u3f20\u3f21\u3f22\u3f23\u3f24\u3f25\u3f26\u3f27\u3f28\u3f29\u3f2a\u3f2b\u3f2c\u3f2d\u3f2e\u3f2f\u3f30\u3f31\u3f32\u3f33\u3f34\u3f35\u3f36\u3f37\u3f38\u3f39\u3f3a\u3f3b\u3f3c\u3f3d\u3f3e\u3f3f\u3f40\u3f41\u3f42\u3f43\u3f44\u3f45\u3f46\u3f47\u3f48\u3f49\u3f4a\u3f4b\u3f4c\u3f4d\u3f4e\u3f4f\u3f50\u3f51\u3f52\u3f53\u3f54\u3f55\u3f56\u3f57\u3f58\u3f59\u3f5a\u3f5b\u3f5c\u3f5d\u3f5e\u3f5f\u3f60\u3f61\u3f62\u3f63\u3f64\u3f65\u3f66\u3f67\u3f68\u3f69\u3f6a\u3f6b\u3f6c\u3f6d\u3f6e\u3f6f\u3f70\u3f71\u3f72\u3f73\u3f74\u3f75\u3f76\u3f77\u3f78\u3f79\u3f7a\u3f7b\u3f7c\u3f7d\u3f7e\u3f7f\u3f80\u3f81\u3f82\u3f83\u3f84\u3f85\u3f86\u3f87\u3f88\u3f89\u3f8a\u3f8b\u3f8c\u3f8d\u3f8e\u3f8f\u3f90\u3f91\u3f92\u3f93\u3f94\u3f95\u3f96\u3f97\u3f98\u3f99\u3f9a\u3f9b\u3f9c\u3f9d\u3f9e\u3f9f\u3fa0\u3fa1\u3fa2\u3fa3\u3fa4\u3fa5\u3fa6\u3fa7\u3fa8\u3fa9\u3faa\u3fab\u3fac\u3fad\u3fae\u3faf\u3fb0\u3fb1\u3fb2\u3fb3\u3fb4\u3fb5\u3fb6\u3fb7\u3fb8\u3fb9\u3fba\u3fbb\u3fbc\u3fbd\u3fbe\u3fbf\u3fc0\u3fc1\u3fc2\u3fc3\u3fc4\u3fc5\u3fc6\u3fc7\u3fc8\u3fc9\u3fca\u3fcb\u3fcc\u3fcd\u3fce\u3fcf\u3fd0\u3fd1\u3fd2\u3fd3\u3fd4\u3fd5\u3fd6\u3fd7\u3fd8\u3fd9\u3fda\u3fdb\u3fdc\u3fdd\u3fde\u3fdf\u3fe0\u3fe1\u3fe2\u3fe3\u3fe4\u3fe5\u3fe6\u3fe7\u3fe8\u3fe9\u3fea\u3feb\u3fec\u3fed\u3fee\u3fef\u3ff0\u3ff1\u3ff2\u3ff3\u3ff4\u3ff5\u3ff6\u3ff7\u3ff8\u3ff9\u3ffa\u3ffb\u3ffc\u3ffd\u3ffe\u3fff\u4000\u4001\u4002\u4003\u4004\u4005\u4006\u4007\u4008\u4009\u400a\u400b\u400c\u400d\u400e\u400f\u4010\u4011\u4012\u4013\u4014\u4015\u4016\u4017\u4018\u4019\u401a\u401b\u401c\u401d\u401e\u401f\u4020\u4021\u4022\u4023\u4024\u4025\u4026\u4027\u4028\u4029\u402a\u402b\u402c\u402d\u402e\u402f\u4030\u4031\u4032\u4033\u4034\u4035\u4036\u4037\u4038\u4039\u403a\u403b\u403c\u403d\u403e\u403f\u4040\u4041\u4042\u4043\u4044\u4045\u4046\u4047\u4048\u4049\u404a\u404b\u404c\u404d\u404e\u404f\u4050\u4051\u4052\u4053\u4054\u4055\u4056\u4057\u4058\u4059\u405a\u405b\u405c\u405d\u405e\u405f\u4060\u4061\u4062\u4063\u4064\u4065\u4066\u4067\u4068\u4069\u406a\u406b\u406c\u406d\u406e\u406f\u4070\u4071\u4072\u4073\u4074\u4075\u4076\u4077\u4078\u4079\u407a\u407b\u407c\u407d\u407e\u407f\u4080\u4081\u4082\u4083\u4084\u4085\u4086\u4087\u4088\u4089\u408a\u408b\u408c\u408d\u408e\u408f\u4090\u4091\u4092\u4093\u4094\u4095\u4096\u4097\u4098\u4099\u409a\u409b\u409c\u409d\u409e\u409f\u40a0\u40a1\u40a2\u40a3\u40a4\u40a5\u40a6\u40a7\u40a8\u40a9\u40aa\u40ab\u40ac\u40ad\u40ae\u40af\u40b0\u40b1\u40b2\u40b3\u40b4\u40b5\u40b6\u40b7\u40b8\u40b9\u40ba\u40bb\u40bc\u40bd\u40be\u40bf\u40c0\u40c1\u40c2\u40c3\u40c4\u40c5\u40c6\u40c7\u40c8\u40c9\u40ca\u40cb\u40cc\u40cd\u40ce\u40cf\u40d0\u40d1\u40d2\u40d3\u40d4\u40d5\u40d6\u40d7\u40d8\u40d9\u40da\u40db\u40dc\u40dd\u40de\u40df\u40e0\u40e1\u40e2\u40e3\u40e4\u40e5\u40e6\u40e7\u40e8\u40e9\u40ea\u40eb\u40ec\u40ed\u40ee\u40ef\u40f0\u40f1\u40f2\u40f3\u40f4\u40f5\u40f6\u40f7\u40f8\u40f9\u40fa\u40fb\u40fc\u40fd\u40fe\u40ff\u4100\u4101\u4102\u4103\u4104\u4105\u4106\u4107\u4108\u4109\u410a\u410b\u410c\u410d\u410e\u410f\u4110\u4111\u4112\u4113\u4114\u4115\u4116\u4117\u4118\u4119\u411a\u411b\u411c\u411d\u411e\u411f\u4120\u4121\u4122\u4123\u4124\u4125\u4126\u4127\u4128\u4129\u412a\u412b\u412c\u412d\u412e\u412f\u4130\u4131\u4132\u4133\u4134\u4135\u4136\u4137\u4138\u4139\u413a\u413b\u413c\u413d\u413e\u413f\u4140\u4141\u4142\u4143\u4144\u4145\u4146\u4147\u4148\u4149\u414a\u414b\u414c\u414d\u414e\u414f\u4150\u4151\u4152\u4153\u4154\u4155\u4156\u4157\u4158\u4159\u415a\u415b\u415c\u415d\u415e\u415f\u4160\u4161\u4162\u4163\u4164\u4165\u4166\u4167\u4168\u4169\u416a\u416b\u416c\u416d\u416e\u416f\u4170\u4171\u4172\u4173\u4174\u4175\u4176\u4177\u4178\u4179\u417a\u417b\u417c\u417d\u417e\u417f\u4180\u4181\u4182\u4183\u4184\u4185\u4186\u4187\u4188\u4189\u418a\u418b\u418c\u418d\u418e\u418f\u4190\u4191\u4192\u4193\u4194\u4195\u4196\u4197\u4198\u4199\u419a\u419b\u419c\u419d\u419e\u419f\u41a0\u41a1\u41a2\u41a3\u41a4\u41a5\u41a6\u41a7\u41a8\u41a9\u41aa\u41ab\u41ac\u41ad\u41ae\u41af\u41b0\u41b1\u41b2\u41b3\u41b4\u41b5\u41b6\u41b7\u41b8\u41b9\u41ba\u41bb\u41bc\u41bd\u41be\u41bf\u41c0\u41c1\u41c2\u41c3\u41c4\u41c5\u41c6\u41c7\u41c8\u41c9\u41ca\u41cb\u41cc\u41cd\u41ce\u41cf\u41d0\u41d1\u41d2\u41d3\u41d4\u41d5\u41d6\u41d7\u41d8\u41d9\u41da\u41db\u41dc\u41dd\u41de\u41df\u41e0\u41e1\u41e2\u41e3\u41e4\u41e5\u41e6\u41e7\u41e8\u41e9\u41ea\u41eb\u41ec\u41ed\u41ee\u41ef\u41f0\u41f1\u41f2\u41f3\u41f4\u41f5\u41f6\u41f7\u41f8\u41f9\u41fa\u41fb\u41fc\u41fd\u41fe\u41ff\u4200\u4201\u4202\u4203\u4204\u4205\u4206\u4207\u4208\u4209\u420a\u420b\u420c\u420d\u420e\u420f\u4210\u4211\u4212\u4213\u4214\u4215\u4216\u4217\u4218\u4219\u421a\u421b\u421c\u421d\u421e\u421f\u4220\u4221\u4222\u4223\u4224\u4225\u4226\u4227\u4228\u4229\u422a\u422b\u422c\u422d\u422e\u422f\u4230\u4231\u4232\u4233\u4234\u4235\u4236\u4237\u4238\u4239\u423a\u423b\u423c\u423d\u423e\u423f\u4240\u4241\u4242\u4243\u4244\u4245\u4246\u4247\u4248\u4249\u424a\u424b\u424c\u424d\u424e\u424f\u4250\u4251\u4252\u4253\u4254\u4255\u4256\u4257\u4258\u4259\u425a\u425b\u425c\u425d\u425e\u425f\u4260\u4261\u4262\u4263\u4264\u4265\u4266\u4267\u4268\u4269\u426a\u426b\u426c\u426d\u426e\u426f\u4270\u4271\u4272\u4273\u4274\u4275\u4276\u4277\u4278\u4279\u427a\u427b\u427c\u427d\u427e\u427f\u4280\u4281\u4282\u4283\u4284\u4285\u4286\u4287\u4288\u4289\u428a\u428b\u428c\u428d\u428e\u428f\u4290\u4291\u4292\u4293\u4294\u4295\u4296\u4297\u4298\u4299\u429a\u429b\u429c\u429d\u429e\u429f\u42a0\u42a1\u42a2\u42a3\u42a4\u42a5\u42a6\u42a7\u42a8\u42a9\u42aa\u42ab\u42ac\u42ad\u42ae\u42af\u42b0\u42b1\u42b2\u42b3\u42b4\u42b5\u42b6\u42b7\u42b8\u42b9\u42ba\u42bb\u42bc\u42bd\u42be\u42bf\u42c0\u42c1\u42c2\u42c3\u42c4\u42c5\u42c6\u42c7\u42c8\u42c9\u42ca\u42cb\u42cc\u42cd\u42ce\u42cf\u42d0\u42d1\u42d2\u42d3\u42d4\u42d5\u42d6\u42d7\u42d8\u42d9\u42da\u42db\u42dc\u42dd\u42de\u42df\u42e0\u42e1\u42e2\u42e3\u42e4\u42e5\u42e6\u42e7\u42e8\u42e9\u42ea\u42eb\u42ec\u42ed\u42ee\u42ef\u42f0\u42f1\u42f2\u42f3\u42f4\u42f5\u42f6\u42f7\u42f8\u42f9\u42fa\u42fb\u42fc\u42fd\u42fe\u42ff\u4300\u4301\u4302\u4303\u4304\u4305\u4306\u4307\u4308\u4309\u430a\u430b\u430c\u430d\u430e\u430f\u4310\u4311\u4312\u4313\u4314\u4315\u4316\u4317\u4318\u4319\u431a\u431b\u431c\u431d\u431e\u431f\u4320\u4321\u4322\u4323\u4324\u4325\u4326\u4327\u4328\u4329\u432a\u432b\u432c\u432d\u432e\u432f\u4330\u4331\u4332\u4333\u4334\u4335\u4336\u4337\u4338\u4339\u433a\u433b\u433c\u433d\u433e\u433f\u4340\u4341\u4342\u4343\u4344\u4345\u4346\u4347\u4348\u4349\u434a\u434b\u434c\u434d\u434e\u434f\u4350\u4351\u4352\u4353\u4354\u4355\u4356\u4357\u4358\u4359\u435a\u435b\u435c\u435d\u435e\u435f\u4360\u4361\u4362\u4363\u4364\u4365\u4366\u4367\u4368\u4369\u436a\u436b\u436c\u436d\u436e\u436f\u4370\u4371\u4372\u4373\u4374\u4375\u4376\u4377\u4378\u4379\u437a\u437b\u437c\u437d\u437e\u437f\u4380\u4381\u4382\u4383\u4384\u4385\u4386\u4387\u4388\u4389\u438a\u438b\u438c\u438d\u438e\u438f\u4390\u4391\u4392\u4393\u4394\u4395\u4396\u4397\u4398\u4399\u439a\u439b\u439c\u439d\u439e\u439f\u43a0\u43a1\u43a2\u43a3\u43a4\u43a5\u43a6\u43a7\u43a8\u43a9\u43aa\u43ab\u43ac\u43ad\u43ae\u43af\u43b0\u43b1\u43b2\u43b3\u43b4\u43b5\u43b6\u43b7\u43b8\u43b9\u43ba\u43bb\u43bc\u43bd\u43be\u43bf\u43c0\u43c1\u43c2\u43c3\u43c4\u43c5\u43c6\u43c7\u43c8\u43c9\u43ca\u43cb\u43cc\u43cd\u43ce\u43cf\u43d0\u43d1\u43d2\u43d3\u43d4\u43d5\u43d6\u43d7\u43d8\u43d9\u43da\u43db\u43dc\u43dd\u43de\u43df\u43e0\u43e1\u43e2\u43e3\u43e4\u43e5\u43e6\u43e7\u43e8\u43e9\u43ea\u43eb\u43ec\u43ed\u43ee\u43ef\u43f0\u43f1\u43f2\u43f3\u43f4\u43f5\u43f6\u43f7\u43f8\u43f9\u43fa\u43fb\u43fc\u43fd\u43fe\u43ff\u4400\u4401\u4402\u4403\u4404\u4405\u4406\u4407\u4408\u4409\u440a\u440b\u440c\u440d\u440e\u440f\u4410\u4411\u4412\u4413\u4414\u4415\u4416\u4417\u4418\u4419\u441a\u441b\u441c\u441d\u441e\u441f\u4420\u4421\u4422\u4423\u4424\u4425\u4426\u4427\u4428\u4429\u442a\u442b\u442c\u442d\u442e\u442f\u4430\u4431\u4432\u4433\u4434\u4435\u4436\u4437\u4438\u4439\u443a\u443b\u443c\u443d\u443e\u443f\u4440\u4441\u4442\u4443\u4444\u4445\u4446\u4447\u4448\u4449\u444a\u444b\u444c\u444d\u444e\u444f\u4450\u4451\u4452\u4453\u4454\u4455\u4456\u4457\u4458\u4459\u445a\u445b\u445c\u445d\u445e\u445f\u4460\u4461\u4462\u4463\u4464\u4465\u4466\u4467\u4468\u4469\u446a\u446b\u446c\u446d\u446e\u446f\u4470\u4471\u4472\u4473\u4474\u4475\u4476\u4477\u4478\u4479\u447a\u447b\u447c\u447d\u447e\u447f\u4480\u4481\u4482\u4483\u4484\u4485\u4486\u4487\u4488\u4489\u448a\u448b\u448c\u448d\u448e\u448f\u4490\u4491\u4492\u4493\u4494\u4495\u4496\u4497\u4498\u4499\u449a\u449b\u449c\u449d\u449e\u449f\u44a0\u44a1\u44a2\u44a3\u44a4\u44a5\u44a6\u44a7\u44a8\u44a9\u44aa\u44ab\u44ac\u44ad\u44ae\u44af\u44b0\u44b1\u44b2\u44b3\u44b4\u44b5\u44b6\u44b7\u44b8\u44b9\u44ba\u44bb\u44bc\u44bd\u44be\u44bf\u44c0\u44c1\u44c2\u44c3\u44c4\u44c5\u44c6\u44c7\u44c8\u44c9\u44ca\u44cb\u44cc\u44cd\u44ce\u44cf\u44d0\u44d1\u44d2\u44d3\u44d4\u44d5\u44d6\u44d7\u44d8\u44d9\u44da\u44db\u44dc\u44dd\u44de\u44df\u44e0\u44e1\u44e2\u44e3\u44e4\u44e5\u44e6\u44e7\u44e8\u44e9\u44ea\u44eb\u44ec\u44ed\u44ee\u44ef\u44f0\u44f1\u44f2\u44f3\u44f4\u44f5\u44f6\u44f7\u44f8\u44f9\u44fa\u44fb\u44fc\u44fd\u44fe\u44ff\u4500\u4501\u4502\u4503\u4504\u4505\u4506\u4507\u4508\u4509\u450a\u450b\u450c\u450d\u450e\u450f\u4510\u4511\u4512\u4513\u4514\u4515\u4516\u4517\u4518\u4519\u451a\u451b\u451c\u451d\u451e\u451f\u4520\u4521\u4522\u4523\u4524\u4525\u4526\u4527\u4528\u4529\u452a\u452b\u452c\u452d\u452e\u452f\u4530\u4531\u4532\u4533\u4534\u4535\u4536\u4537\u4538\u4539\u453a\u453b\u453c\u453d\u453e\u453f\u4540\u4541\u4542\u4543\u4544\u4545\u4546\u4547\u4548\u4549\u454a\u454b\u454c\u454d\u454e\u454f\u4550\u4551\u4552\u4553\u4554\u4555\u4556\u4557\u4558\u4559\u455a\u455b\u455c\u455d\u455e\u455f\u4560\u4561\u4562\u4563\u4564\u4565\u4566\u4567\u4568\u4569\u456a\u456b\u456c\u456d\u456e\u456f\u4570\u4571\u4572\u4573\u4574\u4575\u4576\u4577\u4578\u4579\u457a\u457b\u457c\u457d\u457e\u457f\u4580\u4581\u4582\u4583\u4584\u4585\u4586\u4587\u4588\u4589\u458a\u458b\u458c\u458d\u458e\u458f\u4590\u4591\u4592\u4593\u4594\u4595\u4596\u4597\u4598\u4599\u459a\u459b\u459c\u459d\u459e\u459f\u45a0\u45a1\u45a2\u45a3\u45a4\u45a5\u45a6\u45a7\u45a8\u45a9\u45aa\u45ab\u45ac\u45ad\u45ae\u45af\u45b0\u45b1\u45b2\u45b3\u45b4\u45b5\u45b6\u45b7\u45b8\u45b9\u45ba\u45bb\u45bc\u45bd\u45be\u45bf\u45c0\u45c1\u45c2\u45c3\u45c4\u45c5\u45c6\u45c7\u45c8\u45c9\u45ca\u45cb\u45cc\u45cd\u45ce\u45cf\u45d0\u45d1\u45d2\u45d3\u45d4\u45d5\u45d6\u45d7\u45d8\u45d9\u45da\u45db\u45dc\u45dd\u45de\u45df\u45e0\u45e1\u45e2\u45e3\u45e4\u45e5\u45e6\u45e7\u45e8\u45e9\u45ea\u45eb\u45ec\u45ed\u45ee\u45ef\u45f0\u45f1\u45f2\u45f3\u45f4\u45f5\u45f6\u45f7\u45f8\u45f9\u45fa\u45fb\u45fc\u45fd\u45fe\u45ff\u4600\u4601\u4602\u4603\u4604\u4605\u4606\u4607\u4608\u4609\u460a\u460b\u460c\u460d\u460e\u460f\u4610\u4611\u4612\u4613\u4614\u4615\u4616\u4617\u4618\u4619\u461a\u461b\u461c\u461d\u461e\u461f\u4620\u4621\u4622\u4623\u4624\u4625\u4626\u4627\u4628\u4629\u462a\u462b\u462c\u462d\u462e\u462f\u4630\u4631\u4632\u4633\u4634\u4635\u4636\u4637\u4638\u4639\u463a\u463b\u463c\u463d\u463e\u463f\u4640\u4641\u4642\u4643\u4644\u4645\u4646\u4647\u4648\u4649\u464a\u464b\u464c\u464d\u464e\u464f\u4650\u4651\u4652\u4653\u4654\u4655\u4656\u4657\u4658\u4659\u465a\u465b\u465c\u465d\u465e\u465f\u4660\u4661\u4662\u4663\u4664\u4665\u4666\u4667\u4668\u4669\u466a\u466b\u466c\u466d\u466e\u466f\u4670\u4671\u4672\u4673\u4674\u4675\u4676\u4677\u4678\u4679\u467a\u467b\u467c\u467d\u467e\u467f\u4680\u4681\u4682\u4683\u4684\u4685\u4686\u4687\u4688\u4689\u468a\u468b\u468c\u468d\u468e\u468f\u4690\u4691\u4692\u4693\u4694\u4695\u4696\u4697\u4698\u4699\u469a\u469b\u469c\u469d\u469e\u469f\u46a0\u46a1\u46a2\u46a3\u46a4\u46a5\u46a6\u46a7\u46a8\u46a9\u46aa\u46ab\u46ac\u46ad\u46ae\u46af\u46b0\u46b1\u46b2\u46b3\u46b4\u46b5\u46b6\u46b7\u46b8\u46b9\u46ba\u46bb\u46bc\u46bd\u46be\u46bf\u46c0\u46c1\u46c2\u46c3\u46c4\u46c5\u46c6\u46c7\u46c8\u46c9\u46ca\u46cb\u46cc\u46cd\u46ce\u46cf\u46d0\u46d1\u46d2\u46d3\u46d4\u46d5\u46d6\u46d7\u46d8\u46d9\u46da\u46db\u46dc\u46dd\u46de\u46df\u46e0\u46e1\u46e2\u46e3\u46e4\u46e5\u46e6\u46e7\u46e8\u46e9\u46ea\u46eb\u46ec\u46ed\u46ee\u46ef\u46f0\u46f1\u46f2\u46f3\u46f4\u46f5\u46f6\u46f7\u46f8\u46f9\u46fa\u46fb\u46fc\u46fd\u46fe\u46ff\u4700\u4701\u4702\u4703\u4704\u4705\u4706\u4707\u4708\u4709\u470a\u470b\u470c\u470d\u470e\u470f\u4710\u4711\u4712\u4713\u4714\u4715\u4716\u4717\u4718\u4719\u471a\u471b\u471c\u471d\u471e\u471f\u4720\u4721\u4722\u4723\u4724\u4725\u4726\u4727\u4728\u4729\u472a\u472b\u472c\u472d\u472e\u472f\u4730\u4731\u4732\u4733\u4734\u4735\u4736\u4737\u4738\u4739\u473a\u473b\u473c\u473d\u473e\u473f\u4740\u4741\u4742\u4743\u4744\u4745\u4746\u4747\u4748\u4749\u474a\u474b\u474c\u474d\u474e\u474f\u4750\u4751\u4752\u4753\u4754\u4755\u4756\u4757\u4758\u4759\u475a\u475b\u475c\u475d\u475e\u475f\u4760\u4761\u4762\u4763\u4764\u4765\u4766\u4767\u4768\u4769\u476a\u476b\u476c\u476d\u476e\u476f\u4770\u4771\u4772\u4773\u4774\u4775\u4776\u4777\u4778\u4779\u477a\u477b\u477c\u477d\u477e\u477f\u4780\u4781\u4782\u4783\u4784\u4785\u4786\u4787\u4788\u4789\u478a\u478b\u478c\u478d\u478e\u478f\u4790\u4791\u4792\u4793\u4794\u4795\u4796\u4797\u4798\u4799\u479a\u479b\u479c\u479d\u479e\u479f\u47a0\u47a1\u47a2\u47a3\u47a4\u47a5\u47a6\u47a7\u47a8\u47a9\u47aa\u47ab\u47ac\u47ad\u47ae\u47af\u47b0\u47b1\u47b2\u47b3\u47b4\u47b5\u47b6\u47b7\u47b8\u47b9\u47ba\u47bb\u47bc\u47bd\u47be\u47bf\u47c0\u47c1\u47c2\u47c3\u47c4\u47c5\u47c6\u47c7\u47c8\u47c9\u47ca\u47cb\u47cc\u47cd\u47ce\u47cf\u47d0\u47d1\u47d2\u47d3\u47d4\u47d5\u47d6\u47d7\u47d8\u47d9\u47da\u47db\u47dc\u47dd\u47de\u47df\u47e0\u47e1\u47e2\u47e3\u47e4\u47e5\u47e6\u47e7\u47e8\u47e9\u47ea\u47eb\u47ec\u47ed\u47ee\u47ef\u47f0\u47f1\u47f2\u47f3\u47f4\u47f5\u47f6\u47f7\u47f8\u47f9\u47fa\u47fb\u47fc\u47fd\u47fe\u47ff\u4800\u4801\u4802\u4803\u4804\u4805\u4806\u4807\u4808\u4809\u480a\u480b\u480c\u480d\u480e\u480f\u4810\u4811\u4812\u4813\u4814\u4815\u4816\u4817\u4818\u4819\u481a\u481b\u481c\u481d\u481e\u481f\u4820\u4821\u4822\u4823\u4824\u4825\u4826\u4827\u4828\u4829\u482a\u482b\u482c\u482d\u482e\u482f\u4830\u4831\u4832\u4833\u4834\u4835\u4836\u4837\u4838\u4839\u483a\u483b\u483c\u483d\u483e\u483f\u4840\u4841\u4842\u4843\u4844\u4845\u4846\u4847\u4848\u4849\u484a\u484b\u484c\u484d\u484e\u484f\u4850\u4851\u4852\u4853\u4854\u4855\u4856\u4857\u4858\u4859\u485a\u485b\u485c\u485d\u485e\u485f\u4860\u4861\u4862\u4863\u4864\u4865\u4866\u4867\u4868\u4869\u486a\u486b\u486c\u486d\u486e\u486f\u4870\u4871\u4872\u4873\u4874\u4875\u4876\u4877\u4878\u4879\u487a\u487b\u487c\u487d\u487e\u487f\u4880\u4881\u4882\u4883\u4884\u4885\u4886\u4887\u4888\u4889\u488a\u488b\u488c\u488d\u488e\u488f\u4890\u4891\u4892\u4893\u4894\u4895\u4896\u4897\u4898\u4899\u489a\u489b\u489c\u489d\u489e\u489f\u48a0\u48a1\u48a2\u48a3\u48a4\u48a5\u48a6\u48a7\u48a8\u48a9\u48aa\u48ab\u48ac\u48ad\u48ae\u48af\u48b0\u48b1\u48b2\u48b3\u48b4\u48b5\u48b6\u48b7\u48b8\u48b9\u48ba\u48bb\u48bc\u48bd\u48be\u48bf\u48c0\u48c1\u48c2\u48c3\u48c4\u48c5\u48c6\u48c7\u48c8\u48c9\u48ca\u48cb\u48cc\u48cd\u48ce\u48cf\u48d0\u48d1\u48d2\u48d3\u48d4\u48d5\u48d6\u48d7\u48d8\u48d9\u48da\u48db\u48dc\u48dd\u48de\u48df\u48e0\u48e1\u48e2\u48e3\u48e4\u48e5\u48e6\u48e7\u48e8\u48e9\u48ea\u48eb\u48ec\u48ed\u48ee\u48ef\u48f0\u48f1\u48f2\u48f3\u48f4\u48f5\u48f6\u48f7\u48f8\u48f9\u48fa\u48fb\u48fc\u48fd\u48fe\u48ff\u4900\u4901\u4902\u4903\u4904\u4905\u4906\u4907\u4908\u4909\u490a\u490b\u490c\u490d\u490e\u490f\u4910\u4911\u4912\u4913\u4914\u4915\u4916\u4917\u4918\u4919\u491a\u491b\u491c\u491d\u491e\u491f\u4920\u4921\u4922\u4923\u4924\u4925\u4926\u4927\u4928\u4929\u492a\u492b\u492c\u492d\u492e\u492f\u4930\u4931\u4932\u4933\u4934\u4935\u4936\u4937\u4938\u4939\u493a\u493b\u493c\u493d\u493e\u493f\u4940\u4941\u4942\u4943\u4944\u4945\u4946\u4947\u4948\u4949\u494a\u494b\u494c\u494d\u494e\u494f\u4950\u4951\u4952\u4953\u4954\u4955\u4956\u4957\u4958\u4959\u495a\u495b\u495c\u495d\u495e\u495f\u4960\u4961\u4962\u4963\u4964\u4965\u4966\u4967\u4968\u4969\u496a\u496b\u496c\u496d\u496e\u496f\u4970\u4971\u4972\u4973\u4974\u4975\u4976\u4977\u4978\u4979\u497a\u497b\u497c\u497d\u497e\u497f\u4980\u4981\u4982\u4983\u4984\u4985\u4986\u4987\u4988\u4989\u498a\u498b\u498c\u498d\u498e\u498f\u4990\u4991\u4992\u4993\u4994\u4995\u4996\u4997\u4998\u4999\u499a\u499b\u499c\u499d\u499e\u499f\u49a0\u49a1\u49a2\u49a3\u49a4\u49a5\u49a6\u49a7\u49a8\u49a9\u49aa\u49ab\u49ac\u49ad\u49ae\u49af\u49b0\u49b1\u49b2\u49b3\u49b4\u49b5\u49b6\u49b7\u49b8\u49b9\u49ba\u49bb\u49bc\u49bd\u49be\u49bf\u49c0\u49c1\u49c2\u49c3\u49c4\u49c5\u49c6\u49c7\u49c8\u49c9\u49ca\u49cb\u49cc\u49cd\u49ce\u49cf\u49d0\u49d1\u49d2\u49d3\u49d4\u49d5\u49d6\u49d7\u49d8\u49d9\u49da\u49db\u49dc\u49dd\u49de\u49df\u49e0\u49e1\u49e2\u49e3\u49e4\u49e5\u49e6\u49e7\u49e8\u49e9\u49ea\u49eb\u49ec\u49ed\u49ee\u49ef\u49f0\u49f1\u49f2\u49f3\u49f4\u49f5\u49f6\u49f7\u49f8\u49f9\u49fa\u49fb\u49fc\u49fd\u49fe\u49ff\u4a00\u4a01\u4a02\u4a03\u4a04\u4a05\u4a06\u4a07\u4a08\u4a09\u4a0a\u4a0b\u4a0c\u4a0d\u4a0e\u4a0f\u4a10\u4a11\u4a12\u4a13\u4a14\u4a15\u4a16\u4a17\u4a18\u4a19\u4a1a\u4a1b\u4a1c\u4a1d\u4a1e\u4a1f\u4a20\u4a21\u4a22\u4a23\u4a24\u4a25\u4a26\u4a27\u4a28\u4a29\u4a2a\u4a2b\u4a2c\u4a2d\u4a2e\u4a2f\u4a30\u4a31\u4a32\u4a33\u4a34\u4a35\u4a36\u4a37\u4a38\u4a39\u4a3a\u4a3b\u4a3c\u4a3d\u4a3e\u4a3f\u4a40\u4a41\u4a42\u4a43\u4a44\u4a45\u4a46\u4a47\u4a48\u4a49\u4a4a\u4a4b\u4a4c\u4a4d\u4a4e\u4a4f\u4a50\u4a51\u4a52\u4a53\u4a54\u4a55\u4a56\u4a57\u4a58\u4a59\u4a5a\u4a5b\u4a5c\u4a5d\u4a5e\u4a5f\u4a60\u4a61\u4a62\u4a63\u4a64\u4a65\u4a66\u4a67\u4a68\u4a69\u4a6a\u4a6b\u4a6c\u4a6d\u4a6e\u4a6f\u4a70\u4a71\u4a72\u4a73\u4a74\u4a75\u4a76\u4a77\u4a78\u4a79\u4a7a\u4a7b\u4a7c\u4a7d\u4a7e\u4a7f\u4a80\u4a81\u4a82\u4a83\u4a84\u4a85\u4a86\u4a87\u4a88\u4a89\u4a8a\u4a8b\u4a8c\u4a8d\u4a8e\u4a8f\u4a90\u4a91\u4a92\u4a93\u4a94\u4a95\u4a96\u4a97\u4a98\u4a99\u4a9a\u4a9b\u4a9c\u4a9d\u4a9e\u4a9f\u4aa0\u4aa1\u4aa2\u4aa3\u4aa4\u4aa5\u4aa6\u4aa7\u4aa8\u4aa9\u4aaa\u4aab\u4aac\u4aad\u4aae\u4aaf\u4ab0\u4ab1\u4ab2\u4ab3\u4ab4\u4ab5\u4ab6\u4ab7\u4ab8\u4ab9\u4aba\u4abb\u4abc\u4abd\u4abe\u4abf\u4ac0\u4ac1\u4ac2\u4ac3\u4ac4\u4ac5\u4ac6\u4ac7\u4ac8\u4ac9\u4aca\u4acb\u4acc\u4acd\u4ace\u4acf\u4ad0\u4ad1\u4ad2\u4ad3\u4ad4\u4ad5\u4ad6\u4ad7\u4ad8\u4ad9\u4ada\u4adb\u4adc\u4add\u4ade\u4adf\u4ae0\u4ae1\u4ae2\u4ae3\u4ae4\u4ae5\u4ae6\u4ae7\u4ae8\u4ae9\u4aea\u4aeb\u4aec\u4aed\u4aee\u4aef\u4af0\u4af1\u4af2\u4af3\u4af4\u4af5\u4af6\u4af7\u4af8\u4af9\u4afa\u4afb\u4afc\u4afd\u4afe\u4aff\u4b00\u4b01\u4b02\u4b03\u4b04\u4b05\u4b06\u4b07\u4b08\u4b09\u4b0a\u4b0b\u4b0c\u4b0d\u4b0e\u4b0f\u4b10\u4b11\u4b12\u4b13\u4b14\u4b15\u4b16\u4b17\u4b18\u4b19\u4b1a\u4b1b\u4b1c\u4b1d\u4b1e\u4b1f\u4b20\u4b21\u4b22\u4b23\u4b24\u4b25\u4b26\u4b27\u4b28\u4b29\u4b2a\u4b2b\u4b2c\u4b2d\u4b2e\u4b2f\u4b30\u4b31\u4b32\u4b33\u4b34\u4b35\u4b36\u4b37\u4b38\u4b39\u4b3a\u4b3b\u4b3c\u4b3d\u4b3e\u4b3f\u4b40\u4b41\u4b42\u4b43\u4b44\u4b45\u4b46\u4b47\u4b48\u4b49\u4b4a\u4b4b\u4b4c\u4b4d\u4b4e\u4b4f\u4b50\u4b51\u4b52\u4b53\u4b54\u4b55\u4b56\u4b57\u4b58\u4b59\u4b5a\u4b5b\u4b5c\u4b5d\u4b5e\u4b5f\u4b60\u4b61\u4b62\u4b63\u4b64\u4b65\u4b66\u4b67\u4b68\u4b69\u4b6a\u4b6b\u4b6c\u4b6d\u4b6e\u4b6f\u4b70\u4b71\u4b72\u4b73\u4b74\u4b75\u4b76\u4b77\u4b78\u4b79\u4b7a\u4b7b\u4b7c\u4b7d\u4b7e\u4b7f\u4b80\u4b81\u4b82\u4b83\u4b84\u4b85\u4b86\u4b87\u4b88\u4b89\u4b8a\u4b8b\u4b8c\u4b8d\u4b8e\u4b8f\u4b90\u4b91\u4b92\u4b93\u4b94\u4b95\u4b96\u4b97\u4b98\u4b99\u4b9a\u4b9b\u4b9c\u4b9d\u4b9e\u4b9f\u4ba0\u4ba1\u4ba2\u4ba3\u4ba4\u4ba5\u4ba6\u4ba7\u4ba8\u4ba9\u4baa\u4bab\u4bac\u4bad\u4bae\u4baf\u4bb0\u4bb1\u4bb2\u4bb3\u4bb4\u4bb5\u4bb6\u4bb7\u4bb8\u4bb9\u4bba\u4bbb\u4bbc\u4bbd\u4bbe\u4bbf\u4bc0\u4bc1\u4bc2\u4bc3\u4bc4\u4bc5\u4bc6\u4bc7\u4bc8\u4bc9\u4bca\u4bcb\u4bcc\u4bcd\u4bce\u4bcf\u4bd0\u4bd1\u4bd2\u4bd3\u4bd4\u4bd5\u4bd6\u4bd7\u4bd8\u4bd9\u4bda\u4bdb\u4bdc\u4bdd\u4bde\u4bdf\u4be0\u4be1\u4be2\u4be3\u4be4\u4be5\u4be6\u4be7\u4be8\u4be9\u4bea\u4beb\u4bec\u4bed\u4bee\u4bef\u4bf0\u4bf1\u4bf2\u4bf3\u4bf4\u4bf5\u4bf6\u4bf7\u4bf8\u4bf9\u4bfa\u4bfb\u4bfc\u4bfd\u4bfe\u4bff\u4c00\u4c01\u4c02\u4c03\u4c04\u4c05\u4c06\u4c07\u4c08\u4c09\u4c0a\u4c0b\u4c0c\u4c0d\u4c0e\u4c0f\u4c10\u4c11\u4c12\u4c13\u4c14\u4c15\u4c16\u4c17\u4c18\u4c19\u4c1a\u4c1b\u4c1c\u4c1d\u4c1e\u4c1f\u4c20\u4c21\u4c22\u4c23\u4c24\u4c25\u4c26\u4c27\u4c28\u4c29\u4c2a\u4c2b\u4c2c\u4c2d\u4c2e\u4c2f\u4c30\u4c31\u4c32\u4c33\u4c34\u4c35\u4c36\u4c37\u4c38\u4c39\u4c3a\u4c3b\u4c3c\u4c3d\u4c3e\u4c3f\u4c40\u4c41\u4c42\u4c43\u4c44\u4c45\u4c46\u4c47\u4c48\u4c49\u4c4a\u4c4b\u4c4c\u4c4d\u4c4e\u4c4f\u4c50\u4c51\u4c52\u4c53\u4c54\u4c55\u4c56\u4c57\u4c58\u4c59\u4c5a\u4c5b\u4c5c\u4c5d\u4c5e\u4c5f\u4c60\u4c61\u4c62\u4c63\u4c64\u4c65\u4c66\u4c67\u4c68\u4c69\u4c6a\u4c6b\u4c6c\u4c6d\u4c6e\u4c6f\u4c70\u4c71\u4c72\u4c73\u4c74\u4c75\u4c76\u4c77\u4c78\u4c79\u4c7a\u4c7b\u4c7c\u4c7d\u4c7e\u4c7f\u4c80\u4c81\u4c82\u4c83\u4c84\u4c85\u4c86\u4c87\u4c88\u4c89\u4c8a\u4c8b\u4c8c\u4c8d\u4c8e\u4c8f\u4c90\u4c91\u4c92\u4c93\u4c94\u4c95\u4c96\u4c97\u4c98\u4c99\u4c9a\u4c9b\u4c9c\u4c9d\u4c9e\u4c9f\u4ca0\u4ca1\u4ca2\u4ca3\u4ca4\u4ca5\u4ca6\u4ca7\u4ca8\u4ca9\u4caa\u4cab\u4cac\u4cad\u4cae\u4caf\u4cb0\u4cb1\u4cb2\u4cb3\u4cb4\u4cb5\u4cb6\u4cb7\u4cb8\u4cb9\u4cba\u4cbb\u4cbc\u4cbd\u4cbe\u4cbf\u4cc0\u4cc1\u4cc2\u4cc3\u4cc4\u4cc5\u4cc6\u4cc7\u4cc8\u4cc9\u4cca\u4ccb\u4ccc\u4ccd\u4cce\u4ccf\u4cd0\u4cd1\u4cd2\u4cd3\u4cd4\u4cd5\u4cd6\u4cd7\u4cd8\u4cd9\u4cda\u4cdb\u4cdc\u4cdd\u4cde\u4cdf\u4ce0\u4ce1\u4ce2\u4ce3\u4ce4\u4ce5\u4ce6\u4ce7\u4ce8\u4ce9\u4cea\u4ceb\u4cec\u4ced\u4cee\u4cef\u4cf0\u4cf1\u4cf2\u4cf3\u4cf4\u4cf5\u4cf6\u4cf7\u4cf8\u4cf9\u4cfa\u4cfb\u4cfc\u4cfd\u4cfe\u4cff\u4d00\u4d01\u4d02\u4d03\u4d04\u4d05\u4d06\u4d07\u4d08\u4d09\u4d0a\u4d0b\u4d0c\u4d0d\u4d0e\u4d0f\u4d10\u4d11\u4d12\u4d13\u4d14\u4d15\u4d16\u4d17\u4d18\u4d19\u4d1a\u4d1b\u4d1c\u4d1d\u4d1e\u4d1f\u4d20\u4d21\u4d22\u4d23\u4d24\u4d25\u4d26\u4d27\u4d28\u4d29\u4d2a\u4d2b\u4d2c\u4d2d\u4d2e\u4d2f\u4d30\u4d31\u4d32\u4d33\u4d34\u4d35\u4d36\u4d37\u4d38\u4d39\u4d3a\u4d3b\u4d3c\u4d3d\u4d3e\u4d3f\u4d40\u4d41\u4d42\u4d43\u4d44\u4d45\u4d46\u4d47\u4d48\u4d49\u4d4a\u4d4b\u4d4c\u4d4d\u4d4e\u4d4f\u4d50\u4d51\u4d52\u4d53\u4d54\u4d55\u4d56\u4d57\u4d58\u4d59\u4d5a\u4d5b\u4d5c\u4d5d\u4d5e\u4d5f\u4d60\u4d61\u4d62\u4d63\u4d64\u4d65\u4d66\u4d67\u4d68\u4d69\u4d6a\u4d6b\u4d6c\u4d6d\u4d6e\u4d6f\u4d70\u4d71\u4d72\u4d73\u4d74\u4d75\u4d76\u4d77\u4d78\u4d79\u4d7a\u4d7b\u4d7c\u4d7d\u4d7e\u4d7f\u4d80\u4d81\u4d82\u4d83\u4d84\u4d85\u4d86\u4d87\u4d88\u4d89\u4d8a\u4d8b\u4d8c\u4d8d\u4d8e\u4d8f\u4d90\u4d91\u4d92\u4d93\u4d94\u4d95\u4d96\u4d97\u4d98\u4d99\u4d9a\u4d9b\u4d9c\u4d9d\u4d9e\u4d9f\u4da0\u4da1\u4da2\u4da3\u4da4\u4da5\u4da6\u4da7\u4da8\u4da9\u4daa\u4dab\u4dac\u4dad\u4dae\u4daf\u4db0\u4db1\u4db2\u4db3\u4db4\u4db5\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05\u4e06\u4e07\u4e08\u4e09\u4e0a\u4e0b\u4e0c\u4e0d\u4e0e\u4e0f\u4e10\u4e11\u4e12\u4e13\u4e14\u4e15\u4e16\u4e17\u4e18\u4e19\u4e1a\u4e1b\u4e1c\u4e1d\u4e1e\u4e1f\u4e20\u4e21\u4e22\u4e23\u4e24\u4e25\u4e26\u4e27\u4e28\u4e29\u4e2a\u4e2b\u4e2c\u4e2d\u4e2e\u4e2f\u4e30\u4e31\u4e32\u4e33\u4e34\u4e35\u4e36\u4e37\u4e38\u4e39\u4e3a\u4e3b\u4e3c\u4e3d\u4e3e\u4e3f\u4e40\u4e41\u4e42\u4e43\u4e44\u4e45\u4e46\u4e47\u4e48\u4e49\u4e4a\u4e4b\u4e4c\u4e4d\u4e4e\u4e4f\u4e50\u4e51\u4e52\u4e53\u4e54\u4e55\u4e56\u4e57\u4e58\u4e59\u4e5a\u4e5b\u4e5c\u4e5d\u4e5e\u4e5f\u4e60\u4e61\u4e62\u4e63\u4e64\u4e65\u4e66\u4e67\u4e68\u4e69\u4e6a\u4e6b\u4e6c\u4e6d\u4e6e\u4e6f\u4e70\u4e71\u4e72\u4e73\u4e74\u4e75\u4e76\u4e77\u4e78\u4e79\u4e7a\u4e7b\u4e7c\u4e7d\u4e7e\u4e7f\u4e80\u4e81\u4e82\u4e83\u4e84\u4e85\u4e86\u4e87\u4e88\u4e89\u4e8a\u4e8b\u4e8c\u4e8d\u4e8e\u4e8f\u4e90\u4e91\u4e92\u4e93\u4e94\u4e95\u4e96\u4e97\u4e98\u4e99\u4e9a\u4e9b\u4e9c\u4e9d\u4e9e\u4e9f\u4ea0\u4ea1\u4ea2\u4ea3\u4ea4\u4ea5\u4ea6\u4ea7\u4ea8\u4ea9\u4eaa\u4eab\u4eac\u4ead\u4eae\u4eaf\u4eb0\u4eb1\u4eb2\u4eb3\u4eb4\u4eb5\u4eb6\u4eb7\u4eb8\u4eb9\u4eba\u4ebb\u4ebc\u4ebd\u4ebe\u4ebf\u4ec0\u4ec1\u4ec2\u4ec3\u4ec4\u4ec5\u4ec6\u4ec7\u4ec8\u4ec9\u4eca\u4ecb\u4ecc\u4ecd\u4ece\u4ecf\u4ed0\u4ed1\u4ed2\u4ed3\u4ed4\u4ed5\u4ed6\u4ed7\u4ed8\u4ed9\u4eda\u4edb\u4edc\u4edd\u4ede\u4edf\u4ee0\u4ee1\u4ee2\u4ee3\u4ee4\u4ee5\u4ee6\u4ee7\u4ee8\u4ee9\u4eea\u4eeb\u4eec\u4eed\u4eee\u4eef\u4ef0\u4ef1\u4ef2\u4ef3\u4ef4\u4ef5\u4ef6\u4ef7\u4ef8\u4ef9\u4efa\u4efb\u4efc\u4efd\u4efe\u4eff\u4f00\u4f01\u4f02\u4f03\u4f04\u4f05\u4f06\u4f07\u4f08\u4f09\u4f0a\u4f0b\u4f0c\u4f0d\u4f0e\u4f0f\u4f10\u4f11\u4f12\u4f13\u4f14\u4f15\u4f16\u4f17\u4f18\u4f19\u4f1a\u4f1b\u4f1c\u4f1d\u4f1e\u4f1f\u4f20\u4f21\u4f22\u4f23\u4f24\u4f25\u4f26\u4f27\u4f28\u4f29\u4f2a\u4f2b\u4f2c\u4f2d\u4f2e\u4f2f\u4f30\u4f31\u4f32\u4f33\u4f34\u4f35\u4f36\u4f37\u4f38\u4f39\u4f3a\u4f3b\u4f3c\u4f3d\u4f3e\u4f3f\u4f40\u4f41\u4f42\u4f43\u4f44\u4f45\u4f46\u4f47\u4f48\u4f49\u4f4a\u4f4b\u4f4c\u4f4d\u4f4e\u4f4f\u4f50\u4f51\u4f52\u4f53\u4f54\u4f55\u4f56\u4f57\u4f58\u4f59\u4f5a\u4f5b\u4f5c\u4f5d\u4f5e\u4f5f\u4f60\u4f61\u4f62\u4f63\u4f64\u4f65\u4f66\u4f67\u4f68\u4f69\u4f6a\u4f6b\u4f6c\u4f6d\u4f6e\u4f6f\u4f70\u4f71\u4f72\u4f73\u4f74\u4f75\u4f76\u4f77\u4f78\u4f79\u4f7a\u4f7b\u4f7c\u4f7d\u4f7e\u4f7f\u4f80\u4f81\u4f82\u4f83\u4f84\u4f85\u4f86\u4f87\u4f88\u4f89\u4f8a\u4f8b\u4f8c\u4f8d\u4f8e\u4f8f\u4f90\u4f91\u4f92\u4f93\u4f94\u4f95\u4f96\u4f97\u4f98\u4f99\u4f9a\u4f9b\u4f9c\u4f9d\u4f9e\u4f9f\u4fa0\u4fa1\u4fa2\u4fa3\u4fa4\u4fa5\u4fa6\u4fa7\u4fa8\u4fa9\u4faa\u4fab\u4fac\u4fad\u4fae\u4faf\u4fb0\u4fb1\u4fb2\u4fb3\u4fb4\u4fb5\u4fb6\u4fb7\u4fb8\u4fb9\u4fba\u4fbb\u4fbc\u4fbd\u4fbe\u4fbf\u4fc0\u4fc1\u4fc2\u4fc3\u4fc4\u4fc5\u4fc6\u4fc7\u4fc8\u4fc9\u4fca\u4fcb\u4fcc\u4fcd\u4fce\u4fcf\u4fd0\u4fd1\u4fd2\u4fd3\u4fd4\u4fd5\u4fd6\u4fd7\u4fd8\u4fd9\u4fda\u4fdb\u4fdc\u4fdd\u4fde\u4fdf\u4fe0\u4fe1\u4fe2\u4fe3\u4fe4\u4fe5\u4fe6\u4fe7\u4fe8\u4fe9\u4fea\u4feb\u4fec\u4fed\u4fee\u4fef\u4ff0\u4ff1\u4ff2\u4ff3\u4ff4\u4ff5\u4ff6\u4ff7\u4ff8\u4ff9\u4ffa\u4ffb\u4ffc\u4ffd\u4ffe\u4fff\u5000\u5001\u5002\u5003\u5004\u5005\u5006\u5007\u5008\u5009\u500a\u500b\u500c\u500d\u500e\u500f\u5010\u5011\u5012\u5013\u5014\u5015\u5016\u5017\u5018\u5019\u501a\u501b\u501c\u501d\u501e\u501f\u5020\u5021\u5022\u5023\u5024\u5025\u5026\u5027\u5028\u5029\u502a\u502b\u502c\u502d\u502e\u502f\u5030\u5031\u5032\u5033\u5034\u5035\u5036\u5037\u5038\u5039\u503a\u503b\u503c\u503d\u503e\u503f\u5040\u5041\u5042\u5043\u5044\u5045\u5046\u5047\u5048\u5049\u504a\u504b\u504c\u504d\u504e\u504f\u5050\u5051\u5052\u5053\u5054\u5055\u5056\u5057\u5058\u5059\u505a\u505b\u505c\u505d\u505e\u505f\u5060\u5061\u5062\u5063\u5064\u5065\u5066\u5067\u5068\u5069\u506a\u506b\u506c\u506d\u506e\u506f\u5070\u5071\u5072\u5073\u5074\u5075\u5076\u5077\u5078\u5079\u507a\u507b\u507c\u507d\u507e\u507f\u5080\u5081\u5082\u5083\u5084\u5085\u5086\u5087\u5088\u5089\u508a\u508b\u508c\u508d\u508e\u508f\u5090\u5091\u5092\u5093\u5094\u5095\u5096\u5097\u5098\u5099\u509a\u509b\u509c\u509d\u509e\u509f\u50a0\u50a1\u50a2\u50a3\u50a4\u50a5\u50a6\u50a7\u50a8\u50a9\u50aa\u50ab\u50ac\u50ad\u50ae\u50af\u50b0\u50b1\u50b2\u50b3\u50b4\u50b5\u50b6\u50b7\u50b8\u50b9\u50ba\u50bb\u50bc\u50bd\u50be\u50bf\u50c0\u50c1\u50c2\u50c3\u50c4\u50c5\u50c6\u50c7\u50c8\u50c9\u50ca\u50cb\u50cc\u50cd\u50ce\u50cf\u50d0\u50d1\u50d2\u50d3\u50d4\u50d5\u50d6\u50d7\u50d8\u50d9\u50da\u50db\u50dc\u50dd\u50de\u50df\u50e0\u50e1\u50e2\u50e3\u50e4\u50e5\u50e6\u50e7\u50e8\u50e9\u50ea\u50eb\u50ec\u50ed\u50ee\u50ef\u50f0\u50f1\u50f2\u50f3\u50f4\u50f5\u50f6\u50f7\u50f8\u50f9\u50fa\u50fb\u50fc\u50fd\u50fe\u50ff\u5100\u5101\u5102\u5103\u5104\u5105\u5106\u5107\u5108\u5109\u510a\u510b\u510c\u510d\u510e\u510f\u5110\u5111\u5112\u5113\u5114\u5115\u5116\u5117\u5118\u5119\u511a\u511b\u511c\u511d\u511e\u511f\u5120\u5121\u5122\u5123\u5124\u5125\u5126\u5127\u5128\u5129\u512a\u512b\u512c\u512d\u512e\u512f\u5130\u5131\u5132\u5133\u5134\u5135\u5136\u5137\u5138\u5139\u513a\u513b\u513c\u513d\u513e\u513f\u5140\u5141\u5142\u5143\u5144\u5145\u5146\u5147\u5148\u5149\u514a\u514b\u514c\u514d\u514e\u514f\u5150\u5151\u5152\u5153\u5154\u5155\u5156\u5157\u5158\u5159\u515a\u515b\u515c\u515d\u515e\u515f\u5160\u5161\u5162\u5163\u5164\u5165\u5166\u5167\u5168\u5169\u516a\u516b\u516c\u516d\u516e\u516f\u5170\u5171\u5172\u5173\u5174\u5175\u5176\u5177\u5178\u5179\u517a\u517b\u517c\u517d\u517e\u517f\u5180\u5181\u5182\u5183\u5184\u5185\u5186\u5187\u5188\u5189\u518a\u518b\u518c\u518d\u518e\u518f\u5190\u5191\u5192\u5193\u5194\u5195\u5196\u5197\u5198\u5199\u519a\u519b\u519c\u519d\u519e\u519f\u51a0\u51a1\u51a2\u51a3\u51a4\u51a5\u51a6\u51a7\u51a8\u51a9\u51aa\u51ab\u51ac\u51ad\u51ae\u51af\u51b0\u51b1\u51b2\u51b3\u51b4\u51b5\u51b6\u51b7\u51b8\u51b9\u51ba\u51bb\u51bc\u51bd\u51be\u51bf\u51c0\u51c1\u51c2\u51c3\u51c4\u51c5\u51c6\u51c7\u51c8\u51c9\u51ca\u51cb\u51cc\u51cd\u51ce\u51cf\u51d0\u51d1\u51d2\u51d3\u51d4\u51d5\u51d6\u51d7\u51d8\u51d9\u51da\u51db\u51dc\u51dd\u51de\u51df\u51e0\u51e1\u51e2\u51e3\u51e4\u51e5\u51e6\u51e7\u51e8\u51e9\u51ea\u51eb\u51ec\u51ed\u51ee\u51ef\u51f0\u51f1\u51f2\u51f3\u51f4\u51f5\u51f6\u51f7\u51f8\u51f9\u51fa\u51fb\u51fc\u51fd\u51fe\u51ff\u5200\u5201\u5202\u5203\u5204\u5205\u5206\u5207\u5208\u5209\u520a\u520b\u520c\u520d\u520e\u520f\u5210\u5211\u5212\u5213\u5214\u5215\u5216\u5217\u5218\u5219\u521a\u521b\u521c\u521d\u521e\u521f\u5220\u5221\u5222\u5223\u5224\u5225\u5226\u5227\u5228\u5229\u522a\u522b\u522c\u522d\u522e\u522f\u5230\u5231\u5232\u5233\u5234\u5235\u5236\u5237\u5238\u5239\u523a\u523b\u523c\u523d\u523e\u523f\u5240\u5241\u5242\u5243\u5244\u5245\u5246\u5247\u5248\u5249\u524a\u524b\u524c\u524d\u524e\u524f\u5250\u5251\u5252\u5253\u5254\u5255\u5256\u5257\u5258\u5259\u525a\u525b\u525c\u525d\u525e\u525f\u5260\u5261\u5262\u5263\u5264\u5265\u5266\u5267\u5268\u5269\u526a\u526b\u526c\u526d\u526e\u526f\u5270\u5271\u5272\u5273\u5274\u5275\u5276\u5277\u5278\u5279\u527a\u527b\u527c\u527d\u527e\u527f\u5280\u5281\u5282\u5283\u5284\u5285\u5286\u5287\u5288\u5289\u528a\u528b\u528c\u528d\u528e\u528f\u5290\u5291\u5292\u5293\u5294\u5295\u5296\u5297\u5298\u5299\u529a\u529b\u529c\u529d\u529e\u529f\u52a0\u52a1\u52a2\u52a3\u52a4\u52a5\u52a6\u52a7\u52a8\u52a9\u52aa\u52ab\u52ac\u52ad\u52ae\u52af\u52b0\u52b1\u52b2\u52b3\u52b4\u52b5\u52b6\u52b7\u52b8\u52b9\u52ba\u52bb\u52bc\u52bd\u52be\u52bf\u52c0\u52c1\u52c2\u52c3\u52c4\u52c5\u52c6\u52c7\u52c8\u52c9\u52ca\u52cb\u52cc\u52cd\u52ce\u52cf\u52d0\u52d1\u52d2\u52d3\u52d4\u52d5\u52d6\u52d7\u52d8\u52d9\u52da\u52db\u52dc\u52dd\u52de\u52df\u52e0\u52e1\u52e2\u52e3\u52e4\u52e5\u52e6\u52e7\u52e8\u52e9\u52ea\u52eb\u52ec\u52ed\u52ee\u52ef\u52f0\u52f1\u52f2\u52f3\u52f4\u52f5\u52f6\u52f7\u52f8\u52f9\u52fa\u52fb\u52fc\u52fd\u52fe\u52ff\u5300\u5301\u5302\u5303\u5304\u5305\u5306\u5307\u5308\u5309\u530a\u530b\u530c\u530d\u530e\u530f\u5310\u5311\u5312\u5313\u5314\u5315\u5316\u5317\u5318\u5319\u531a\u531b\u531c\u531d\u531e\u531f\u5320\u5321\u5322\u5323\u5324\u5325\u5326\u5327\u5328\u5329\u532a\u532b\u532c\u532d\u532e\u532f\u5330\u5331\u5332\u5333\u5334\u5335\u5336\u5337\u5338\u5339\u533a\u533b\u533c\u533d\u533e\u533f\u5340\u5341\u5342\u5343\u5344\u5345\u5346\u5347\u5348\u5349\u534a\u534b\u534c\u534d\u534e\u534f\u5350\u5351\u5352\u5353\u5354\u5355\u5356\u5357\u5358\u5359\u535a\u535b\u535c\u535d\u535e\u535f\u5360\u5361\u5362\u5363\u5364\u5365\u5366\u5367\u5368\u5369\u536a\u536b\u536c\u536d\u536e\u536f\u5370\u5371\u5372\u5373\u5374\u5375\u5376\u5377\u5378\u5379\u537a\u537b\u537c\u537d\u537e\u537f\u5380\u5381\u5382\u5383\u5384\u5385\u5386\u5387\u5388\u5389\u538a\u538b\u538c\u538d\u538e\u538f\u5390\u5391\u5392\u5393\u5394\u5395\u5396\u5397\u5398\u5399\u539a\u539b\u539c\u539d\u539e\u539f\u53a0\u53a1\u53a2\u53a3\u53a4\u53a5\u53a6\u53a7\u53a8\u53a9\u53aa\u53ab\u53ac\u53ad\u53ae\u53af\u53b0\u53b1\u53b2\u53b3\u53b4\u53b5\u53b6\u53b7\u53b8\u53b9\u53ba\u53bb\u53bc\u53bd\u53be\u53bf\u53c0\u53c1\u53c2\u53c3\u53c4\u53c5\u53c6\u53c7\u53c8\u53c9\u53ca\u53cb\u53cc\u53cd\u53ce\u53cf\u53d0\u53d1\u53d2\u53d3\u53d4\u53d5\u53d6\u53d7\u53d8\u53d9\u53da\u53db\u53dc\u53dd\u53de\u53df\u53e0\u53e1\u53e2\u53e3\u53e4\u53e5\u53e6\u53e7\u53e8\u53e9\u53ea\u53eb\u53ec\u53ed\u53ee\u53ef\u53f0\u53f1\u53f2\u53f3\u53f4\u53f5\u53f6\u53f7\u53f8\u53f9\u53fa\u53fb\u53fc\u53fd\u53fe\u53ff\u5400\u5401\u5402\u5403\u5404\u5405\u5406\u5407\u5408\u5409\u540a\u540b\u540c\u540d\u540e\u540f\u5410\u5411\u5412\u5413\u5414\u5415\u5416\u5417\u5418\u5419\u541a\u541b\u541c\u541d\u541e\u541f\u5420\u5421\u5422\u5423\u5424\u5425\u5426\u5427\u5428\u5429\u542a\u542b\u542c\u542d\u542e\u542f\u5430\u5431\u5432\u5433\u5434\u5435\u5436\u5437\u5438\u5439\u543a\u543b\u543c\u543d\u543e\u543f\u5440\u5441\u5442\u5443\u5444\u5445\u5446\u5447\u5448\u5449\u544a\u544b\u544c\u544d\u544e\u544f\u5450\u5451\u5452\u5453\u5454\u5455\u5456\u5457\u5458\u5459\u545a\u545b\u545c\u545d\u545e\u545f\u5460\u5461\u5462\u5463\u5464\u5465\u5466\u5467\u5468\u5469\u546a\u546b\u546c\u546d\u546e\u546f\u5470\u5471\u5472\u5473\u5474\u5475\u5476\u5477\u5478\u5479\u547a\u547b\u547c\u547d\u547e\u547f\u5480\u5481\u5482\u5483\u5484\u5485\u5486\u5487\u5488\u5489\u548a\u548b\u548c\u548d\u548e\u548f\u5490\u5491\u5492\u5493\u5494\u5495\u5496\u5497\u5498\u5499\u549a\u549b\u549c\u549d\u549e\u549f\u54a0\u54a1\u54a2\u54a3\u54a4\u54a5\u54a6\u54a7\u54a8\u54a9\u54aa\u54ab\u54ac\u54ad\u54ae\u54af\u54b0\u54b1\u54b2\u54b3\u54b4\u54b5\u54b6\u54b7\u54b8\u54b9\u54ba\u54bb\u54bc\u54bd\u54be\u54bf\u54c0\u54c1\u54c2\u54c3\u54c4\u54c5\u54c6\u54c7\u54c8\u54c9\u54ca\u54cb\u54cc\u54cd\u54ce\u54cf\u54d0\u54d1\u54d2\u54d3\u54d4\u54d5\u54d6\u54d7\u54d8\u54d9\u54da\u54db\u54dc\u54dd\u54de\u54df\u54e0\u54e1\u54e2\u54e3\u54e4\u54e5\u54e6\u54e7\u54e8\u54e9\u54ea\u54eb\u54ec\u54ed\u54ee\u54ef\u54f0\u54f1\u54f2\u54f3\u54f4\u54f5\u54f6\u54f7\u54f8\u54f9\u54fa\u54fb\u54fc\u54fd\u54fe\u54ff\u5500\u5501\u5502\u5503\u5504\u5505\u5506\u5507\u5508\u5509\u550a\u550b\u550c\u550d\u550e\u550f\u5510\u5511\u5512\u5513\u5514\u5515\u5516\u5517\u5518\u5519\u551a\u551b\u551c\u551d\u551e\u551f\u5520\u5521\u5522\u5523\u5524\u5525\u5526\u5527\u5528\u5529\u552a\u552b\u552c\u552d\u552e\u552f\u5530\u5531\u5532\u5533\u5534\u5535\u5536\u5537\u5538\u5539\u553a\u553b\u553c\u553d\u553e\u553f\u5540\u5541\u5542\u5543\u5544\u5545\u5546\u5547\u5548\u5549\u554a\u554b\u554c\u554d\u554e\u554f\u5550\u5551\u5552\u5553\u5554\u5555\u5556\u5557\u5558\u5559\u555a\u555b\u555c\u555d\u555e\u555f\u5560\u5561\u5562\u5563\u5564\u5565\u5566\u5567\u5568\u5569\u556a\u556b\u556c\u556d\u556e\u556f\u5570\u5571\u5572\u5573\u5574\u5575\u5576\u5577\u5578\u5579\u557a\u557b\u557c\u557d\u557e\u557f\u5580\u5581\u5582\u5583\u5584\u5585\u5586\u5587\u5588\u5589\u558a\u558b\u558c\u558d\u558e\u558f\u5590\u5591\u5592\u5593\u5594\u5595\u5596\u5597\u5598\u5599\u559a\u559b\u559c\u559d\u559e\u559f\u55a0\u55a1\u55a2\u55a3\u55a4\u55a5\u55a6\u55a7\u55a8\u55a9\u55aa\u55ab\u55ac\u55ad\u55ae\u55af\u55b0\u55b1\u55b2\u55b3\u55b4\u55b5\u55b6\u55b7\u55b8\u55b9\u55ba\u55bb\u55bc\u55bd\u55be\u55bf\u55c0\u55c1\u55c2\u55c3\u55c4\u55c5\u55c6\u55c7\u55c8\u55c9\u55ca\u55cb\u55cc\u55cd\u55ce\u55cf\u55d0\u55d1\u55d2\u55d3\u55d4\u55d5\u55d6\u55d7\u55d8\u55d9\u55da\u55db\u55dc\u55dd\u55de\u55df\u55e0\u55e1\u55e2\u55e3\u55e4\u55e5\u55e6\u55e7\u55e8\u55e9\u55ea\u55eb\u55ec\u55ed\u55ee\u55ef\u55f0\u55f1\u55f2\u55f3\u55f4\u55f5\u55f6\u55f7\u55f8\u55f9\u55fa\u55fb\u55fc\u55fd\u55fe\u55ff\u5600\u5601\u5602\u5603\u5604\u5605\u5606\u5607\u5608\u5609\u560a\u560b\u560c\u560d\u560e\u560f\u5610\u5611\u5612\u5613\u5614\u5615\u5616\u5617\u5618\u5619\u561a\u561b\u561c\u561d\u561e\u561f\u5620\u5621\u5622\u5623\u5624\u5625\u5626\u5627\u5628\u5629\u562a\u562b\u562c\u562d\u562e\u562f\u5630\u5631\u5632\u5633\u5634\u5635\u5636\u5637\u5638\u5639\u563a\u563b\u563c\u563d\u563e\u563f\u5640\u5641\u5642\u5643\u5644\u5645\u5646\u5647\u5648\u5649\u564a\u564b\u564c\u564d\u564e\u564f\u5650\u5651\u5652\u5653\u5654\u5655\u5656\u5657\u5658\u5659\u565a\u565b\u565c\u565d\u565e\u565f\u5660\u5661\u5662\u5663\u5664\u5665\u5666\u5667\u5668\u5669\u566a\u566b\u566c\u566d\u566e\u566f\u5670\u5671\u5672\u5673\u5674\u5675\u5676\u5677\u5678\u5679\u567a\u567b\u567c\u567d\u567e\u567f\u5680\u5681\u5682\u5683\u5684\u5685\u5686\u5687\u5688\u5689\u568a\u568b\u568c\u568d\u568e\u568f\u5690\u5691\u5692\u5693\u5694\u5695\u5696\u5697\u5698\u5699\u569a\u569b\u569c\u569d\u569e\u569f\u56a0\u56a1\u56a2\u56a3\u56a4\u56a5\u56a6\u56a7\u56a8\u56a9\u56aa\u56ab\u56ac\u56ad\u56ae\u56af\u56b0\u56b1\u56b2\u56b3\u56b4\u56b5\u56b6\u56b7\u56b8\u56b9\u56ba\u56bb\u56bc\u56bd\u56be\u56bf\u56c0\u56c1\u56c2\u56c3\u56c4\u56c5\u56c6\u56c7\u56c8\u56c9\u56ca\u56cb\u56cc\u56cd\u56ce\u56cf\u56d0\u56d1\u56d2\u56d3\u56d4\u56d5\u56d6\u56d7\u56d8\u56d9\u56da\u56db\u56dc\u56dd\u56de\u56df\u56e0\u56e1\u56e2\u56e3\u56e4\u56e5\u56e6\u56e7\u56e8\u56e9\u56ea\u56eb\u56ec\u56ed\u56ee\u56ef\u56f0\u56f1\u56f2\u56f3\u56f4\u56f5\u56f6\u56f7\u56f8\u56f9\u56fa\u56fb\u56fc\u56fd\u56fe\u56ff\u5700\u5701\u5702\u5703\u5704\u5705\u5706\u5707\u5708\u5709\u570a\u570b\u570c\u570d\u570e\u570f\u5710\u5711\u5712\u5713\u5714\u5715\u5716\u5717\u5718\u5719\u571a\u571b\u571c\u571d\u571e\u571f\u5720\u5721\u5722\u5723\u5724\u5725\u5726\u5727\u5728\u5729\u572a\u572b\u572c\u572d\u572e\u572f\u5730\u5731\u5732\u5733\u5734\u5735\u5736\u5737\u5738\u5739\u573a\u573b\u573c\u573d\u573e\u573f\u5740\u5741\u5742\u5743\u5744\u5745\u5746\u5747\u5748\u5749\u574a\u574b\u574c\u574d\u574e\u574f\u5750\u5751\u5752\u5753\u5754\u5755\u5756\u5757\u5758\u5759\u575a\u575b\u575c\u575d\u575e\u575f\u5760\u5761\u5762\u5763\u5764\u5765\u5766\u5767\u5768\u5769\u576a\u576b\u576c\u576d\u576e\u576f\u5770\u5771\u5772\u5773\u5774\u5775\u5776\u5777\u5778\u5779\u577a\u577b\u577c\u577d\u577e\u577f\u5780\u5781\u5782\u5783\u5784\u5785\u5786\u5787\u5788\u5789\u578a\u578b\u578c\u578d\u578e\u578f\u5790\u5791\u5792\u5793\u5794\u5795\u5796\u5797\u5798\u5799\u579a\u579b\u579c\u579d\u579e\u579f\u57a0\u57a1\u57a2\u57a3\u57a4\u57a5\u57a6\u57a7\u57a8\u57a9\u57aa\u57ab\u57ac\u57ad\u57ae\u57af\u57b0\u57b1\u57b2\u57b3\u57b4\u57b5\u57b6\u57b7\u57b8\u57b9\u57ba\u57bb\u57bc\u57bd\u57be\u57bf\u57c0\u57c1\u57c2\u57c3\u57c4\u57c5\u57c6\u57c7\u57c8\u57c9\u57ca\u57cb\u57cc\u57cd\u57ce\u57cf\u57d0\u57d1\u57d2\u57d3\u57d4\u57d5\u57d6\u57d7\u57d8\u57d9\u57da\u57db\u57dc\u57dd\u57de\u57df\u57e0\u57e1\u57e2\u57e3\u57e4\u57e5\u57e6\u57e7\u57e8\u57e9\u57ea\u57eb\u57ec\u57ed\u57ee\u57ef\u57f0\u57f1\u57f2\u57f3\u57f4\u57f5\u57f6\u57f7\u57f8\u57f9\u57fa\u57fb\u57fc\u57fd\u57fe\u57ff\u5800\u5801\u5802\u5803\u5804\u5805\u5806\u5807\u5808\u5809\u580a\u580b\u580c\u580d\u580e\u580f\u5810\u5811\u5812\u5813\u5814\u5815\u5816\u5817\u5818\u5819\u581a\u581b\u581c\u581d\u581e\u581f\u5820\u5821\u5822\u5823\u5824\u5825\u5826\u5827\u5828\u5829\u582a\u582b\u582c\u582d\u582e\u582f\u5830\u5831\u5832\u5833\u5834\u5835\u5836\u5837\u5838\u5839\u583a\u583b\u583c\u583d\u583e\u583f\u5840\u5841\u5842\u5843\u5844\u5845\u5846\u5847\u5848\u5849\u584a\u584b\u584c\u584d\u584e\u584f\u5850\u5851\u5852\u5853\u5854\u5855\u5856\u5857\u5858\u5859\u585a\u585b\u585c\u585d\u585e\u585f\u5860\u5861\u5862\u5863\u5864\u5865\u5866\u5867\u5868\u5869\u586a\u586b\u586c\u586d\u586e\u586f\u5870\u5871\u5872\u5873\u5874\u5875\u5876\u5877\u5878\u5879\u587a\u587b\u587c\u587d\u587e\u587f\u5880\u5881\u5882\u5883\u5884\u5885\u5886\u5887\u5888\u5889\u588a\u588b\u588c\u588d\u588e\u588f\u5890\u5891\u5892\u5893\u5894\u5895\u5896\u5897\u5898\u5899\u589a\u589b\u589c\u589d\u589e\u589f\u58a0\u58a1\u58a2\u58a3\u58a4\u58a5\u58a6\u58a7\u58a8\u58a9\u58aa\u58ab\u58ac\u58ad\u58ae\u58af\u58b0\u58b1\u58b2\u58b3\u58b4\u58b5\u58b6\u58b7\u58b8\u58b9\u58ba\u58bb\u58bc\u58bd\u58be\u58bf\u58c0\u58c1\u58c2\u58c3\u58c4\u58c5\u58c6\u58c7\u58c8\u58c9\u58ca\u58cb\u58cc\u58cd\u58ce\u58cf\u58d0\u58d1\u58d2\u58d3\u58d4\u58d5\u58d6\u58d7\u58d8\u58d9\u58da\u58db\u58dc\u58dd\u58de\u58df\u58e0\u58e1\u58e2\u58e3\u58e4\u58e5\u58e6\u58e7\u58e8\u58e9\u58ea\u58eb\u58ec\u58ed\u58ee\u58ef\u58f0\u58f1\u58f2\u58f3\u58f4\u58f5\u58f6\u58f7\u58f8\u58f9\u58fa\u58fb\u58fc\u58fd\u58fe\u58ff\u5900\u5901\u5902\u5903\u5904\u5905\u5906\u5907\u5908\u5909\u590a\u590b\u590c\u590d\u590e\u590f\u5910\u5911\u5912\u5913\u5914\u5915\u5916\u5917\u5918\u5919\u591a\u591b\u591c\u591d\u591e\u591f\u5920\u5921\u5922\u5923\u5924\u5925\u5926\u5927\u5928\u5929\u592a\u592b\u592c\u592d\u592e\u592f\u5930\u5931\u5932\u5933\u5934\u5935\u5936\u5937\u5938\u5939\u593a\u593b\u593c\u593d\u593e\u593f\u5940\u5941\u5942\u5943\u5944\u5945\u5946\u5947\u5948\u5949\u594a\u594b\u594c\u594d\u594e\u594f\u5950\u5951\u5952\u5953\u5954\u5955\u5956\u5957\u5958\u5959\u595a\u595b\u595c\u595d\u595e\u595f\u5960\u5961\u5962\u5963\u5964\u5965\u5966\u5967\u5968\u5969\u596a\u596b\u596c\u596d\u596e\u596f\u5970\u5971\u5972\u5973\u5974\u5975\u5976\u5977\u5978\u5979\u597a\u597b\u597c\u597d\u597e\u597f\u5980\u5981\u5982\u5983\u5984\u5985\u5986\u5987\u5988\u5989\u598a\u598b\u598c\u598d\u598e\u598f\u5990\u5991\u5992\u5993\u5994\u5995\u5996\u5997\u5998\u5999\u599a\u599b\u599c\u599d\u599e\u599f\u59a0\u59a1\u59a2\u59a3\u59a4\u59a5\u59a6\u59a7\u59a8\u59a9\u59aa\u59ab\u59ac\u59ad\u59ae\u59af\u59b0\u59b1\u59b2\u59b3\u59b4\u59b5\u59b6\u59b7\u59b8\u59b9\u59ba\u59bb\u59bc\u59bd\u59be\u59bf\u59c0\u59c1\u59c2\u59c3\u59c4\u59c5\u59c6\u59c7\u59c8\u59c9\u59ca\u59cb\u59cc\u59cd\u59ce\u59cf\u59d0\u59d1\u59d2\u59d3\u59d4\u59d5\u59d6\u59d7\u59d8\u59d9\u59da\u59db\u59dc\u59dd\u59de\u59df\u59e0\u59e1\u59e2\u59e3\u59e4\u59e5\u59e6\u59e7\u59e8\u59e9\u59ea\u59eb\u59ec\u59ed\u59ee\u59ef\u59f0\u59f1\u59f2\u59f3\u59f4\u59f5\u59f6\u59f7\u59f8\u59f9\u59fa\u59fb\u59fc\u59fd\u59fe\u59ff\u5a00\u5a01\u5a02\u5a03\u5a04\u5a05\u5a06\u5a07\u5a08\u5a09\u5a0a\u5a0b\u5a0c\u5a0d\u5a0e\u5a0f\u5a10\u5a11\u5a12\u5a13\u5a14\u5a15\u5a16\u5a17\u5a18\u5a19\u5a1a\u5a1b\u5a1c\u5a1d\u5a1e\u5a1f\u5a20\u5a21\u5a22\u5a23\u5a24\u5a25\u5a26\u5a27\u5a28\u5a29\u5a2a\u5a2b\u5a2c\u5a2d\u5a2e\u5a2f\u5a30\u5a31\u5a32\u5a33\u5a34\u5a35\u5a36\u5a37\u5a38\u5a39\u5a3a\u5a3b\u5a3c\u5a3d\u5a3e\u5a3f\u5a40\u5a41\u5a42\u5a43\u5a44\u5a45\u5a46\u5a47\u5a48\u5a49\u5a4a\u5a4b\u5a4c\u5a4d\u5a4e\u5a4f\u5a50\u5a51\u5a52\u5a53\u5a54\u5a55\u5a56\u5a57\u5a58\u5a59\u5a5a\u5a5b\u5a5c\u5a5d\u5a5e\u5a5f\u5a60\u5a61\u5a62\u5a63\u5a64\u5a65\u5a66\u5a67\u5a68\u5a69\u5a6a\u5a6b\u5a6c\u5a6d\u5a6e\u5a6f\u5a70\u5a71\u5a72\u5a73\u5a74\u5a75\u5a76\u5a77\u5a78\u5a79\u5a7a\u5a7b\u5a7c\u5a7d\u5a7e\u5a7f\u5a80\u5a81\u5a82\u5a83\u5a84\u5a85\u5a86\u5a87\u5a88\u5a89\u5a8a\u5a8b\u5a8c\u5a8d\u5a8e\u5a8f\u5a90\u5a91\u5a92\u5a93\u5a94\u5a95\u5a96\u5a97\u5a98\u5a99\u5a9a\u5a9b\u5a9c\u5a9d\u5a9e\u5a9f\u5aa0\u5aa1\u5aa2\u5aa3\u5aa4\u5aa5\u5aa6\u5aa7\u5aa8\u5aa9\u5aaa\u5aab\u5aac\u5aad\u5aae\u5aaf\u5ab0\u5ab1\u5ab2\u5ab3\u5ab4\u5ab5\u5ab6\u5ab7\u5ab8\u5ab9\u5aba\u5abb\u5abc\u5abd\u5abe\u5abf\u5ac0\u5ac1\u5ac2\u5ac3\u5ac4\u5ac5\u5ac6\u5ac7\u5ac8\u5ac9\u5aca\u5acb\u5acc\u5acd\u5ace\u5acf\u5ad0\u5ad1\u5ad2\u5ad3\u5ad4\u5ad5\u5ad6\u5ad7\u5ad8\u5ad9\u5ada\u5adb\u5adc\u5add\u5ade\u5adf\u5ae0\u5ae1\u5ae2\u5ae3\u5ae4\u5ae5\u5ae6\u5ae7\u5ae8\u5ae9\u5aea\u5aeb\u5aec\u5aed\u5aee\u5aef\u5af0\u5af1\u5af2\u5af3\u5af4\u5af5\u5af6\u5af7\u5af8\u5af9\u5afa\u5afb\u5afc\u5afd\u5afe\u5aff\u5b00\u5b01\u5b02\u5b03\u5b04\u5b05\u5b06\u5b07\u5b08\u5b09\u5b0a\u5b0b\u5b0c\u5b0d\u5b0e\u5b0f\u5b10\u5b11\u5b12\u5b13\u5b14\u5b15\u5b16\u5b17\u5b18\u5b19\u5b1a\u5b1b\u5b1c\u5b1d\u5b1e\u5b1f\u5b20\u5b21\u5b22\u5b23\u5b24\u5b25\u5b26\u5b27\u5b28\u5b29\u5b2a\u5b2b\u5b2c\u5b2d\u5b2e\u5b2f\u5b30\u5b31\u5b32\u5b33\u5b34\u5b35\u5b36\u5b37\u5b38\u5b39\u5b3a\u5b3b\u5b3c\u5b3d\u5b3e\u5b3f\u5b40\u5b41\u5b42\u5b43\u5b44\u5b45\u5b46\u5b47\u5b48\u5b49\u5b4a\u5b4b\u5b4c\u5b4d\u5b4e\u5b4f\u5b50\u5b51\u5b52\u5b53\u5b54\u5b55\u5b56\u5b57\u5b58\u5b59\u5b5a\u5b5b\u5b5c\u5b5d\u5b5e\u5b5f\u5b60\u5b61\u5b62\u5b63\u5b64\u5b65\u5b66\u5b67\u5b68\u5b69\u5b6a\u5b6b\u5b6c\u5b6d\u5b6e\u5b6f\u5b70\u5b71\u5b72\u5b73\u5b74\u5b75\u5b76\u5b77\u5b78\u5b79\u5b7a\u5b7b\u5b7c\u5b7d\u5b7e\u5b7f\u5b80\u5b81\u5b82\u5b83\u5b84\u5b85\u5b86\u5b87\u5b88\u5b89\u5b8a\u5b8b\u5b8c\u5b8d\u5b8e\u5b8f\u5b90\u5b91\u5b92\u5b93\u5b94\u5b95\u5b96\u5b97\u5b98\u5b99\u5b9a\u5b9b\u5b9c\u5b9d\u5b9e\u5b9f\u5ba0\u5ba1\u5ba2\u5ba3\u5ba4\u5ba5\u5ba6\u5ba7\u5ba8\u5ba9\u5baa\u5bab\u5bac\u5bad\u5bae\u5baf\u5bb0\u5bb1\u5bb2\u5bb3\u5bb4\u5bb5\u5bb6\u5bb7\u5bb8\u5bb9\u5bba\u5bbb\u5bbc\u5bbd\u5bbe\u5bbf\u5bc0\u5bc1\u5bc2\u5bc3\u5bc4\u5bc5\u5bc6\u5bc7\u5bc8\u5bc9\u5bca\u5bcb\u5bcc\u5bcd\u5bce\u5bcf\u5bd0\u5bd1\u5bd2\u5bd3\u5bd4\u5bd5\u5bd6\u5bd7\u5bd8\u5bd9\u5bda\u5bdb\u5bdc\u5bdd\u5bde\u5bdf\u5be0\u5be1\u5be2\u5be3\u5be4\u5be5\u5be6\u5be7\u5be8\u5be9\u5bea\u5beb\u5bec\u5bed\u5bee\u5bef\u5bf0\u5bf1\u5bf2\u5bf3\u5bf4\u5bf5\u5bf6\u5bf7\u5bf8\u5bf9\u5bfa\u5bfb\u5bfc\u5bfd\u5bfe\u5bff\u5c00\u5c01\u5c02\u5c03\u5c04\u5c05\u5c06\u5c07\u5c08\u5c09\u5c0a\u5c0b\u5c0c\u5c0d\u5c0e\u5c0f\u5c10\u5c11\u5c12\u5c13\u5c14\u5c15\u5c16\u5c17\u5c18\u5c19\u5c1a\u5c1b\u5c1c\u5c1d\u5c1e\u5c1f\u5c20\u5c21\u5c22\u5c23\u5c24\u5c25\u5c26\u5c27\u5c28\u5c29\u5c2a\u5c2b\u5c2c\u5c2d\u5c2e\u5c2f\u5c30\u5c31\u5c32\u5c33\u5c34\u5c35\u5c36\u5c37\u5c38\u5c39\u5c3a\u5c3b\u5c3c\u5c3d\u5c3e\u5c3f\u5c40\u5c41\u5c42\u5c43\u5c44\u5c45\u5c46\u5c47\u5c48\u5c49\u5c4a\u5c4b\u5c4c\u5c4d\u5c4e\u5c4f\u5c50\u5c51\u5c52\u5c53\u5c54\u5c55\u5c56\u5c57\u5c58\u5c59\u5c5a\u5c5b\u5c5c\u5c5d\u5c5e\u5c5f\u5c60\u5c61\u5c62\u5c63\u5c64\u5c65\u5c66\u5c67\u5c68\u5c69\u5c6a\u5c6b\u5c6c\u5c6d\u5c6e\u5c6f\u5c70\u5c71\u5c72\u5c73\u5c74\u5c75\u5c76\u5c77\u5c78\u5c79\u5c7a\u5c7b\u5c7c\u5c7d\u5c7e\u5c7f\u5c80\u5c81\u5c82\u5c83\u5c84\u5c85\u5c86\u5c87\u5c88\u5c89\u5c8a\u5c8b\u5c8c\u5c8d\u5c8e\u5c8f\u5c90\u5c91\u5c92\u5c93\u5c94\u5c95\u5c96\u5c97\u5c98\u5c99\u5c9a\u5c9b\u5c9c\u5c9d\u5c9e\u5c9f\u5ca0\u5ca1\u5ca2\u5ca3\u5ca4\u5ca5\u5ca6\u5ca7\u5ca8\u5ca9\u5caa\u5cab\u5cac\u5cad\u5cae\u5caf\u5cb0\u5cb1\u5cb2\u5cb3\u5cb4\u5cb5\u5cb6\u5cb7\u5cb8\u5cb9\u5cba\u5cbb\u5cbc\u5cbd\u5cbe\u5cbf\u5cc0\u5cc1\u5cc2\u5cc3\u5cc4\u5cc5\u5cc6\u5cc7\u5cc8\u5cc9\u5cca\u5ccb\u5ccc\u5ccd\u5cce\u5ccf\u5cd0\u5cd1\u5cd2\u5cd3\u5cd4\u5cd5\u5cd6\u5cd7\u5cd8\u5cd9\u5cda\u5cdb\u5cdc\u5cdd\u5cde\u5cdf\u5ce0\u5ce1\u5ce2\u5ce3\u5ce4\u5ce5\u5ce6\u5ce7\u5ce8\u5ce9\u5cea\u5ceb\u5cec\u5ced\u5cee\u5cef\u5cf0\u5cf1\u5cf2\u5cf3\u5cf4\u5cf5\u5cf6\u5cf7\u5cf8\u5cf9\u5cfa\u5cfb\u5cfc\u5cfd\u5cfe\u5cff\u5d00\u5d01\u5d02\u5d03\u5d04\u5d05\u5d06\u5d07\u5d08\u5d09\u5d0a\u5d0b\u5d0c\u5d0d\u5d0e\u5d0f\u5d10\u5d11\u5d12\u5d13\u5d14\u5d15\u5d16\u5d17\u5d18\u5d19\u5d1a\u5d1b\u5d1c\u5d1d\u5d1e\u5d1f\u5d20\u5d21\u5d22\u5d23\u5d24\u5d25\u5d26\u5d27\u5d28\u5d29\u5d2a\u5d2b\u5d2c\u5d2d\u5d2e\u5d2f\u5d30\u5d31\u5d32\u5d33\u5d34\u5d35\u5d36\u5d37\u5d38\u5d39\u5d3a\u5d3b\u5d3c\u5d3d\u5d3e\u5d3f\u5d40\u5d41\u5d42\u5d43\u5d44\u5d45\u5d46\u5d47\u5d48\u5d49\u5d4a\u5d4b\u5d4c\u5d4d\u5d4e\u5d4f\u5d50\u5d51\u5d52\u5d53\u5d54\u5d55\u5d56\u5d57\u5d58\u5d59\u5d5a\u5d5b\u5d5c\u5d5d\u5d5e\u5d5f\u5d60\u5d61\u5d62\u5d63\u5d64\u5d65\u5d66\u5d67\u5d68\u5d69\u5d6a\u5d6b\u5d6c\u5d6d\u5d6e\u5d6f\u5d70\u5d71\u5d72\u5d73\u5d74\u5d75\u5d76\u5d77\u5d78\u5d79\u5d7a\u5d7b\u5d7c\u5d7d\u5d7e\u5d7f\u5d80\u5d81\u5d82\u5d83\u5d84\u5d85\u5d86\u5d87\u5d88\u5d89\u5d8a\u5d8b\u5d8c\u5d8d\u5d8e\u5d8f\u5d90\u5d91\u5d92\u5d93\u5d94\u5d95\u5d96\u5d97\u5d98\u5d99\u5d9a\u5d9b\u5d9c\u5d9d\u5d9e\u5d9f\u5da0\u5da1\u5da2\u5da3\u5da4\u5da5\u5da6\u5da7\u5da8\u5da9\u5daa\u5dab\u5dac\u5dad\u5dae\u5daf\u5db0\u5db1\u5db2\u5db3\u5db4\u5db5\u5db6\u5db7\u5db8\u5db9\u5dba\u5dbb\u5dbc\u5dbd\u5dbe\u5dbf\u5dc0\u5dc1\u5dc2\u5dc3\u5dc4\u5dc5\u5dc6\u5dc7\u5dc8\u5dc9\u5dca\u5dcb\u5dcc\u5dcd\u5dce\u5dcf\u5dd0\u5dd1\u5dd2\u5dd3\u5dd4\u5dd5\u5dd6\u5dd7\u5dd8\u5dd9\u5dda\u5ddb\u5ddc\u5ddd\u5dde\u5ddf\u5de0\u5de1\u5de2\u5de3\u5de4\u5de5\u5de6\u5de7\u5de8\u5de9\u5dea\u5deb\u5dec\u5ded\u5dee\u5def\u5df0\u5df1\u5df2\u5df3\u5df4\u5df5\u5df6\u5df7\u5df8\u5df9\u5dfa\u5dfb\u5dfc\u5dfd\u5dfe\u5dff\u5e00\u5e01\u5e02\u5e03\u5e04\u5e05\u5e06\u5e07\u5e08\u5e09\u5e0a\u5e0b\u5e0c\u5e0d\u5e0e\u5e0f\u5e10\u5e11\u5e12\u5e13\u5e14\u5e15\u5e16\u5e17\u5e18\u5e19\u5e1a\u5e1b\u5e1c\u5e1d\u5e1e\u5e1f\u5e20\u5e21\u5e22\u5e23\u5e24\u5e25\u5e26\u5e27\u5e28\u5e29\u5e2a\u5e2b\u5e2c\u5e2d\u5e2e\u5e2f\u5e30\u5e31\u5e32\u5e33\u5e34\u5e35\u5e36\u5e37\u5e38\u5e39\u5e3a\u5e3b\u5e3c\u5e3d\u5e3e\u5e3f\u5e40\u5e41\u5e42\u5e43\u5e44\u5e45\u5e46\u5e47\u5e48\u5e49\u5e4a\u5e4b\u5e4c\u5e4d\u5e4e\u5e4f\u5e50\u5e51\u5e52\u5e53\u5e54\u5e55\u5e56\u5e57\u5e58\u5e59\u5e5a\u5e5b\u5e5c\u5e5d\u5e5e\u5e5f\u5e60\u5e61\u5e62\u5e63\u5e64\u5e65\u5e66\u5e67\u5e68\u5e69\u5e6a\u5e6b\u5e6c\u5e6d\u5e6e\u5e6f\u5e70\u5e71\u5e72\u5e73\u5e74\u5e75\u5e76\u5e77\u5e78\u5e79\u5e7a\u5e7b\u5e7c\u5e7d\u5e7e\u5e7f\u5e80\u5e81\u5e82\u5e83\u5e84\u5e85\u5e86\u5e87\u5e88\u5e89\u5e8a\u5e8b\u5e8c\u5e8d\u5e8e\u5e8f\u5e90\u5e91\u5e92\u5e93\u5e94\u5e95\u5e96\u5e97\u5e98\u5e99\u5e9a\u5e9b\u5e9c\u5e9d\u5e9e\u5e9f\u5ea0\u5ea1\u5ea2\u5ea3\u5ea4\u5ea5\u5ea6\u5ea7\u5ea8\u5ea9\u5eaa\u5eab\u5eac\u5ead\u5eae\u5eaf\u5eb0\u5eb1\u5eb2\u5eb3\u5eb4\u5eb5\u5eb6\u5eb7\u5eb8\u5eb9\u5eba\u5ebb\u5ebc\u5ebd\u5ebe\u5ebf\u5ec0\u5ec1\u5ec2\u5ec3\u5ec4\u5ec5\u5ec6\u5ec7\u5ec8\u5ec9\u5eca\u5ecb\u5ecc\u5ecd\u5ece\u5ecf\u5ed0\u5ed1\u5ed2\u5ed3\u5ed4\u5ed5\u5ed6\u5ed7\u5ed8\u5ed9\u5eda\u5edb\u5edc\u5edd\u5ede\u5edf\u5ee0\u5ee1\u5ee2\u5ee3\u5ee4\u5ee5\u5ee6\u5ee7\u5ee8\u5ee9\u5eea\u5eeb\u5eec\u5eed\u5eee\u5eef\u5ef0\u5ef1\u5ef2\u5ef3\u5ef4\u5ef5\u5ef6\u5ef7\u5ef8\u5ef9\u5efa\u5efb\u5efc\u5efd\u5efe\u5eff\u5f00\u5f01\u5f02\u5f03\u5f04\u5f05\u5f06\u5f07\u5f08\u5f09\u5f0a\u5f0b\u5f0c\u5f0d\u5f0e\u5f0f\u5f10\u5f11\u5f12\u5f13\u5f14\u5f15\u5f16\u5f17\u5f18\u5f19\u5f1a\u5f1b\u5f1c\u5f1d\u5f1e\u5f1f\u5f20\u5f21\u5f22\u5f23\u5f24\u5f25\u5f26\u5f27\u5f28\u5f29\u5f2a\u5f2b\u5f2c\u5f2d\u5f2e\u5f2f\u5f30\u5f31\u5f32\u5f33\u5f34\u5f35\u5f36\u5f37\u5f38\u5f39\u5f3a\u5f3b\u5f3c\u5f3d\u5f3e\u5f3f\u5f40\u5f41\u5f42\u5f43\u5f44\u5f45\u5f46\u5f47\u5f48\u5f49\u5f4a\u5f4b\u5f4c\u5f4d\u5f4e\u5f4f\u5f50\u5f51\u5f52\u5f53\u5f54\u5f55\u5f56\u5f57\u5f58\u5f59\u5f5a\u5f5b\u5f5c\u5f5d\u5f5e\u5f5f\u5f60\u5f61\u5f62\u5f63\u5f64\u5f65\u5f66\u5f67\u5f68\u5f69\u5f6a\u5f6b\u5f6c\u5f6d\u5f6e\u5f6f\u5f70\u5f71\u5f72\u5f73\u5f74\u5f75\u5f76\u5f77\u5f78\u5f79\u5f7a\u5f7b\u5f7c\u5f7d\u5f7e\u5f7f\u5f80\u5f81\u5f82\u5f83\u5f84\u5f85\u5f86\u5f87\u5f88\u5f89\u5f8a\u5f8b\u5f8c\u5f8d\u5f8e\u5f8f\u5f90\u5f91\u5f92\u5f93\u5f94\u5f95\u5f96\u5f97\u5f98\u5f99\u5f9a\u5f9b\u5f9c\u5f9d\u5f9e\u5f9f\u5fa0\u5fa1\u5fa2\u5fa3\u5fa4\u5fa5\u5fa6\u5fa7\u5fa8\u5fa9\u5faa\u5fab\u5fac\u5fad\u5fae\u5faf\u5fb0\u5fb1\u5fb2\u5fb3\u5fb4\u5fb5\u5fb6\u5fb7\u5fb8\u5fb9\u5fba\u5fbb\u5fbc\u5fbd\u5fbe\u5fbf\u5fc0\u5fc1\u5fc2\u5fc3\u5fc4\u5fc5\u5fc6\u5fc7\u5fc8\u5fc9\u5fca\u5fcb\u5fcc\u5fcd\u5fce\u5fcf\u5fd0\u5fd1\u5fd2\u5fd3\u5fd4\u5fd5\u5fd6\u5fd7\u5fd8\u5fd9\u5fda\u5fdb\u5fdc\u5fdd\u5fde\u5fdf\u5fe0\u5fe1\u5fe2\u5fe3\u5fe4\u5fe5\u5fe6\u5fe7\u5fe8\u5fe9\u5fea\u5feb\u5fec\u5fed\u5fee\u5fef\u5ff0\u5ff1\u5ff2\u5ff3\u5ff4\u5ff5\u5ff6\u5ff7\u5ff8\u5ff9\u5ffa\u5ffb\u5ffc\u5ffd\u5ffe\u5fff\u6000\u6001\u6002\u6003\u6004\u6005\u6006\u6007\u6008\u6009\u600a\u600b\u600c\u600d\u600e\u600f\u6010\u6011\u6012\u6013\u6014\u6015\u6016\u6017\u6018\u6019\u601a\u601b\u601c\u601d\u601e\u601f\u6020\u6021\u6022\u6023\u6024\u6025\u6026\u6027\u6028\u6029\u602a\u602b\u602c\u602d\u602e\u602f\u6030\u6031\u6032\u6033\u6034\u6035\u6036\u6037\u6038\u6039\u603a\u603b\u603c\u603d\u603e\u603f\u6040\u6041\u6042\u6043\u6044\u6045\u6046\u6047\u6048\u6049\u604a\u604b\u604c\u604d\u604e\u604f\u6050\u6051\u6052\u6053\u6054\u6055\u6056\u6057\u6058\u6059\u605a\u605b\u605c\u605d\u605e\u605f\u6060\u6061\u6062\u6063\u6064\u6065\u6066\u6067\u6068\u6069\u606a\u606b\u606c\u606d\u606e\u606f\u6070\u6071\u6072\u6073\u6074\u6075\u6076\u6077\u6078\u6079\u607a\u607b\u607c\u607d\u607e\u607f\u6080\u6081\u6082\u6083\u6084\u6085\u6086\u6087\u6088\u6089\u608a\u608b\u608c\u608d\u608e\u608f\u6090\u6091\u6092\u6093\u6094\u6095\u6096\u6097\u6098\u6099\u609a\u609b\u609c\u609d\u609e\u609f\u60a0\u60a1\u60a2\u60a3\u60a4\u60a5\u60a6\u60a7\u60a8\u60a9\u60aa\u60ab\u60ac\u60ad\u60ae\u60af\u60b0\u60b1\u60b2\u60b3\u60b4\u60b5\u60b6\u60b7\u60b8\u60b9\u60ba\u60bb\u60bc\u60bd\u60be\u60bf\u60c0\u60c1\u60c2\u60c3\u60c4\u60c5\u60c6\u60c7\u60c8\u60c9\u60ca\u60cb\u60cc\u60cd\u60ce\u60cf\u60d0\u60d1\u60d2\u60d3\u60d4\u60d5\u60d6\u60d7\u60d8\u60d9\u60da\u60db\u60dc\u60dd\u60de\u60df\u60e0\u60e1\u60e2\u60e3\u60e4\u60e5\u60e6\u60e7\u60e8\u60e9\u60ea\u60eb\u60ec\u60ed\u60ee\u60ef\u60f0\u60f1\u60f2\u60f3\u60f4\u60f5\u60f6\u60f7\u60f8\u60f9\u60fa\u60fb\u60fc\u60fd\u60fe\u60ff\u6100\u6101\u6102\u6103\u6104\u6105\u6106\u6107\u6108\u6109\u610a\u610b\u610c\u610d\u610e\u610f\u6110\u6111\u6112\u6113\u6114\u6115\u6116\u6117\u6118\u6119\u611a\u611b\u611c\u611d\u611e\u611f\u6120\u6121\u6122\u6123\u6124\u6125\u6126\u6127\u6128\u6129\u612a\u612b\u612c\u612d\u612e\u612f\u6130\u6131\u6132\u6133\u6134\u6135\u6136\u6137\u6138\u6139\u613a\u613b\u613c\u613d\u613e\u613f\u6140\u6141\u6142\u6143\u6144\u6145\u6146\u6147\u6148\u6149\u614a\u614b\u614c\u614d\u614e\u614f\u6150\u6151\u6152\u6153\u6154\u6155\u6156\u6157\u6158\u6159\u615a\u615b\u615c\u615d\u615e\u615f\u6160\u6161\u6162\u6163\u6164\u6165\u6166\u6167\u6168\u6169\u616a\u616b\u616c\u616d\u616e\u616f\u6170\u6171\u6172\u6173\u6174\u6175\u6176\u6177\u6178\u6179\u617a\u617b\u617c\u617d\u617e\u617f\u6180\u6181\u6182\u6183\u6184\u6185\u6186\u6187\u6188\u6189\u618a\u618b\u618c\u618d\u618e\u618f\u6190\u6191\u6192\u6193\u6194\u6195\u6196\u6197\u6198\u6199\u619a\u619b\u619c\u619d\u619e\u619f\u61a0\u61a1\u61a2\u61a3\u61a4\u61a5\u61a6\u61a7\u61a8\u61a9\u61aa\u61ab\u61ac\u61ad\u61ae\u61af\u61b0\u61b1\u61b2\u61b3\u61b4\u61b5\u61b6\u61b7\u61b8\u61b9\u61ba\u61bb\u61bc\u61bd\u61be\u61bf\u61c0\u61c1\u61c2\u61c3\u61c4\u61c5\u61c6\u61c7\u61c8\u61c9\u61ca\u61cb\u61cc\u61cd\u61ce\u61cf\u61d0\u61d1\u61d2\u61d3\u61d4\u61d5\u61d6\u61d7\u61d8\u61d9\u61da\u61db\u61dc\u61dd\u61de\u61df\u61e0\u61e1\u61e2\u61e3\u61e4\u61e5\u61e6\u61e7\u61e8\u61e9\u61ea\u61eb\u61ec\u61ed\u61ee\u61ef\u61f0\u61f1\u61f2\u61f3\u61f4\u61f5\u61f6\u61f7\u61f8\u61f9\u61fa\u61fb\u61fc\u61fd\u61fe\u61ff\u6200\u6201\u6202\u6203\u6204\u6205\u6206\u6207\u6208\u6209\u620a\u620b\u620c\u620d\u620e\u620f\u6210\u6211\u6212\u6213\u6214\u6215\u6216\u6217\u6218\u6219\u621a\u621b\u621c\u621d\u621e\u621f\u6220\u6221\u6222\u6223\u6224\u6225\u6226\u6227\u6228\u6229\u622a\u622b\u622c\u622d\u622e\u622f\u6230\u6231\u6232\u6233\u6234\u6235\u6236\u6237\u6238\u6239\u623a\u623b\u623c\u623d\u623e\u623f\u6240\u6241\u6242\u6243\u6244\u6245\u6246\u6247\u6248\u6249\u624a\u624b\u624c\u624d\u624e\u624f\u6250\u6251\u6252\u6253\u6254\u6255\u6256\u6257\u6258\u6259\u625a\u625b\u625c\u625d\u625e\u625f\u6260\u6261\u6262\u6263\u6264\u6265\u6266\u6267\u6268\u6269\u626a\u626b\u626c\u626d\u626e\u626f\u6270\u6271\u6272\u6273\u6274\u6275\u6276\u6277\u6278\u6279\u627a\u627b\u627c\u627d\u627e\u627f\u6280\u6281\u6282\u6283\u6284\u6285\u6286\u6287\u6288\u6289\u628a\u628b\u628c\u628d\u628e\u628f\u6290\u6291\u6292\u6293\u6294\u6295\u6296\u6297\u6298\u6299\u629a\u629b\u629c\u629d\u629e\u629f\u62a0\u62a1\u62a2\u62a3\u62a4\u62a5\u62a6\u62a7\u62a8\u62a9\u62aa\u62ab\u62ac\u62ad\u62ae\u62af\u62b0\u62b1\u62b2\u62b3\u62b4\u62b5\u62b6\u62b7\u62b8\u62b9\u62ba\u62bb\u62bc\u62bd\u62be\u62bf\u62c0\u62c1\u62c2\u62c3\u62c4\u62c5\u62c6\u62c7\u62c8\u62c9\u62ca\u62cb\u62cc\u62cd\u62ce\u62cf\u62d0\u62d1\u62d2\u62d3\u62d4\u62d5\u62d6\u62d7\u62d8\u62d9\u62da\u62db\u62dc\u62dd\u62de\u62df\u62e0\u62e1\u62e2\u62e3\u62e4\u62e5\u62e6\u62e7\u62e8\u62e9\u62ea\u62eb\u62ec\u62ed\u62ee\u62ef\u62f0\u62f1\u62f2\u62f3\u62f4\u62f5\u62f6\u62f7\u62f8\u62f9\u62fa\u62fb\u62fc\u62fd\u62fe\u62ff\u6300\u6301\u6302\u6303\u6304\u6305\u6306\u6307\u6308\u6309\u630a\u630b\u630c\u630d\u630e\u630f\u6310\u6311\u6312\u6313\u6314\u6315\u6316\u6317\u6318\u6319\u631a\u631b\u631c\u631d\u631e\u631f\u6320\u6321\u6322\u6323\u6324\u6325\u6326\u6327\u6328\u6329\u632a\u632b\u632c\u632d\u632e\u632f\u6330\u6331\u6332\u6333\u6334\u6335\u6336\u6337\u6338\u6339\u633a\u633b\u633c\u633d\u633e\u633f\u6340\u6341\u6342\u6343\u6344\u6345\u6346\u6347\u6348\u6349\u634a\u634b\u634c\u634d\u634e\u634f\u6350\u6351\u6352\u6353\u6354\u6355\u6356\u6357\u6358\u6359\u635a\u635b\u635c\u635d\u635e\u635f\u6360\u6361\u6362\u6363\u6364\u6365\u6366\u6367\u6368\u6369\u636a\u636b\u636c\u636d\u636e\u636f\u6370\u6371\u6372\u6373\u6374\u6375\u6376\u6377\u6378\u6379\u637a\u637b\u637c\u637d\u637e\u637f\u6380\u6381\u6382\u6383\u6384\u6385\u6386\u6387\u6388\u6389\u638a\u638b\u638c\u638d\u638e\u638f\u6390\u6391\u6392\u6393\u6394\u6395\u6396\u6397\u6398\u6399\u639a\u639b\u639c\u639d\u639e\u639f\u63a0\u63a1\u63a2\u63a3\u63a4\u63a5\u63a6\u63a7\u63a8\u63a9\u63aa\u63ab\u63ac\u63ad\u63ae\u63af\u63b0\u63b1\u63b2\u63b3\u63b4\u63b5\u63b6\u63b7\u63b8\u63b9\u63ba\u63bb\u63bc\u63bd\u63be\u63bf\u63c0\u63c1\u63c2\u63c3\u63c4\u63c5\u63c6\u63c7\u63c8\u63c9\u63ca\u63cb\u63cc\u63cd\u63ce\u63cf\u63d0\u63d1\u63d2\u63d3\u63d4\u63d5\u63d6\u63d7\u63d8\u63d9\u63da\u63db\u63dc\u63dd\u63de\u63df\u63e0\u63e1\u63e2\u63e3\u63e4\u63e5\u63e6\u63e7\u63e8\u63e9\u63ea\u63eb\u63ec\u63ed\u63ee\u63ef\u63f0\u63f1\u63f2\u63f3\u63f4\u63f5\u63f6\u63f7\u63f8\u63f9\u63fa\u63fb\u63fc\u63fd\u63fe\u63ff\u6400\u6401\u6402\u6403\u6404\u6405\u6406\u6407\u6408\u6409\u640a\u640b\u640c\u640d\u640e\u640f\u6410\u6411\u6412\u6413\u6414\u6415\u6416\u6417\u6418\u6419\u641a\u641b\u641c\u641d\u641e\u641f\u6420\u6421\u6422\u6423\u6424\u6425\u6426\u6427\u6428\u6429\u642a\u642b\u642c\u642d\u642e\u642f\u6430\u6431\u6432\u6433\u6434\u6435\u6436\u6437\u6438\u6439\u643a\u643b\u643c\u643d\u643e\u643f\u6440\u6441\u6442\u6443\u6444\u6445\u6446\u6447\u6448\u6449\u644a\u644b\u644c\u644d\u644e\u644f\u6450\u6451\u6452\u6453\u6454\u6455\u6456\u6457\u6458\u6459\u645a\u645b\u645c\u645d\u645e\u645f\u6460\u6461\u6462\u6463\u6464\u6465\u6466\u6467\u6468\u6469\u646a\u646b\u646c\u646d\u646e\u646f\u6470\u6471\u6472\u6473\u6474\u6475\u6476\u6477\u6478\u6479\u647a\u647b\u647c\u647d\u647e\u647f\u6480\u6481\u6482\u6483\u6484\u6485\u6486\u6487\u6488\u6489\u648a\u648b\u648c\u648d\u648e\u648f\u6490\u6491\u6492\u6493\u6494\u6495\u6496\u6497\u6498\u6499\u649a\u649b\u649c\u649d\u649e\u649f\u64a0\u64a1\u64a2\u64a3\u64a4\u64a5\u64a6\u64a7\u64a8\u64a9\u64aa\u64ab\u64ac\u64ad\u64ae\u64af\u64b0\u64b1\u64b2\u64b3\u64b4\u64b5\u64b6\u64b7\u64b8\u64b9\u64ba\u64bb\u64bc\u64bd\u64be\u64bf\u64c0\u64c1\u64c2\u64c3\u64c4\u64c5\u64c6\u64c7\u64c8\u64c9\u64ca\u64cb\u64cc\u64cd\u64ce\u64cf\u64d0\u64d1\u64d2\u64d3\u64d4\u64d5\u64d6\u64d7\u64d8\u64d9\u64da\u64db\u64dc\u64dd\u64de\u64df\u64e0\u64e1\u64e2\u64e3\u64e4\u64e5\u64e6\u64e7\u64e8\u64e9\u64ea\u64eb\u64ec\u64ed\u64ee\u64ef\u64f0\u64f1\u64f2\u64f3\u64f4\u64f5\u64f6\u64f7\u64f8\u64f9\u64fa\u64fb\u64fc\u64fd\u64fe\u64ff\u6500\u6501\u6502\u6503\u6504\u6505\u6506\u6507\u6508\u6509\u650a\u650b\u650c\u650d\u650e\u650f\u6510\u6511\u6512\u6513\u6514\u6515\u6516\u6517\u6518\u6519\u651a\u651b\u651c\u651d\u651e\u651f\u6520\u6521\u6522\u6523\u6524\u6525\u6526\u6527\u6528\u6529\u652a\u652b\u652c\u652d\u652e\u652f\u6530\u6531\u6532\u6533\u6534\u6535\u6536\u6537\u6538\u6539\u653a\u653b\u653c\u653d\u653e\u653f\u6540\u6541\u6542\u6543\u6544\u6545\u6546\u6547\u6548\u6549\u654a\u654b\u654c\u654d\u654e\u654f\u6550\u6551\u6552\u6553\u6554\u6555\u6556\u6557\u6558\u6559\u655a\u655b\u655c\u655d\u655e\u655f\u6560\u6561\u6562\u6563\u6564\u6565\u6566\u6567\u6568\u6569\u656a\u656b\u656c\u656d\u656e\u656f\u6570\u6571\u6572\u6573\u6574\u6575\u6576\u6577\u6578\u6579\u657a\u657b\u657c\u657d\u657e\u657f\u6580\u6581\u6582\u6583\u6584\u6585\u6586\u6587\u6588\u6589\u658a\u658b\u658c\u658d\u658e\u658f\u6590\u6591\u6592\u6593\u6594\u6595\u6596\u6597\u6598\u6599\u659a\u659b\u659c\u659d\u659e\u659f\u65a0\u65a1\u65a2\u65a3\u65a4\u65a5\u65a6\u65a7\u65a8\u65a9\u65aa\u65ab\u65ac\u65ad\u65ae\u65af\u65b0\u65b1\u65b2\u65b3\u65b4\u65b5\u65b6\u65b7\u65b8\u65b9\u65ba\u65bb\u65bc\u65bd\u65be\u65bf\u65c0\u65c1\u65c2\u65c3\u65c4\u65c5\u65c6\u65c7\u65c8\u65c9\u65ca\u65cb\u65cc\u65cd\u65ce\u65cf\u65d0\u65d1\u65d2\u65d3\u65d4\u65d5\u65d6\u65d7\u65d8\u65d9\u65da\u65db\u65dc\u65dd\u65de\u65df\u65e0\u65e1\u65e2\u65e3\u65e4\u65e5\u65e6\u65e7\u65e8\u65e9\u65ea\u65eb\u65ec\u65ed\u65ee\u65ef\u65f0\u65f1\u65f2\u65f3\u65f4\u65f5\u65f6\u65f7\u65f8\u65f9\u65fa\u65fb\u65fc\u65fd\u65fe\u65ff\u6600\u6601\u6602\u6603\u6604\u6605\u6606\u6607\u6608\u6609\u660a\u660b\u660c\u660d\u660e\u660f\u6610\u6611\u6612\u6613\u6614\u6615\u6616\u6617\u6618\u6619\u661a\u661b\u661c\u661d\u661e\u661f\u6620\u6621\u6622\u6623\u6624\u6625\u6626\u6627\u6628\u6629\u662a\u662b\u662c\u662d\u662e\u662f\u6630\u6631\u6632\u6633\u6634\u6635\u6636\u6637\u6638\u6639\u663a\u663b\u663c\u663d\u663e\u663f\u6640\u6641\u6642\u6643\u6644\u6645\u6646\u6647\u6648\u6649\u664a\u664b\u664c\u664d\u664e\u664f\u6650\u6651\u6652\u6653\u6654\u6655\u6656\u6657\u6658\u6659\u665a\u665b\u665c\u665d\u665e\u665f\u6660\u6661\u6662\u6663\u6664\u6665\u6666\u6667\u6668\u6669\u666a\u666b\u666c\u666d\u666e\u666f\u6670\u6671\u6672\u6673\u6674\u6675\u6676\u6677\u6678\u6679\u667a\u667b\u667c\u667d\u667e\u667f\u6680\u6681\u6682\u6683\u6684\u6685\u6686\u6687\u6688\u6689\u668a\u668b\u668c\u668d\u668e\u668f\u6690\u6691\u6692\u6693\u6694\u6695\u6696\u6697\u6698\u6699\u669a\u669b\u669c\u669d\u669e\u669f\u66a0\u66a1\u66a2\u66a3\u66a4\u66a5\u66a6\u66a7\u66a8\u66a9\u66aa\u66ab\u66ac\u66ad\u66ae\u66af\u66b0\u66b1\u66b2\u66b3\u66b4\u66b5\u66b6\u66b7\u66b8\u66b9\u66ba\u66bb\u66bc\u66bd\u66be\u66bf\u66c0\u66c1\u66c2\u66c3\u66c4\u66c5\u66c6\u66c7\u66c8\u66c9\u66ca\u66cb\u66cc\u66cd\u66ce\u66cf\u66d0\u66d1\u66d2\u66d3\u66d4\u66d5\u66d6\u66d7\u66d8\u66d9\u66da\u66db\u66dc\u66dd\u66de\u66df\u66e0\u66e1\u66e2\u66e3\u66e4\u66e5\u66e6\u66e7\u66e8\u66e9\u66ea\u66eb\u66ec\u66ed\u66ee\u66ef\u66f0\u66f1\u66f2\u66f3\u66f4\u66f5\u66f6\u66f7\u66f8\u66f9\u66fa\u66fb\u66fc\u66fd\u66fe\u66ff\u6700\u6701\u6702\u6703\u6704\u6705\u6706\u6707\u6708\u6709\u670a\u670b\u670c\u670d\u670e\u670f\u6710\u6711\u6712\u6713\u6714\u6715\u6716\u6717\u6718\u6719\u671a\u671b\u671c\u671d\u671e\u671f\u6720\u6721\u6722\u6723\u6724\u6725\u6726\u6727\u6728\u6729\u672a\u672b\u672c\u672d\u672e\u672f\u6730\u6731\u6732\u6733\u6734\u6735\u6736\u6737\u6738\u6739\u673a\u673b\u673c\u673d\u673e\u673f\u6740\u6741\u6742\u6743\u6744\u6745\u6746\u6747\u6748\u6749\u674a\u674b\u674c\u674d\u674e\u674f\u6750\u6751\u6752\u6753\u6754\u6755\u6756\u6757\u6758\u6759\u675a\u675b\u675c\u675d\u675e\u675f\u6760\u6761\u6762\u6763\u6764\u6765\u6766\u6767\u6768\u6769\u676a\u676b\u676c\u676d\u676e\u676f\u6770\u6771\u6772\u6773\u6774\u6775\u6776\u6777\u6778\u6779\u677a\u677b\u677c\u677d\u677e\u677f\u6780\u6781\u6782\u6783\u6784\u6785\u6786\u6787\u6788\u6789\u678a\u678b\u678c\u678d\u678e\u678f\u6790\u6791\u6792\u6793\u6794\u6795\u6796\u6797\u6798\u6799\u679a\u679b\u679c\u679d\u679e\u679f\u67a0\u67a1\u67a2\u67a3\u67a4\u67a5\u67a6\u67a7\u67a8\u67a9\u67aa\u67ab\u67ac\u67ad\u67ae\u67af\u67b0\u67b1\u67b2\u67b3\u67b4\u67b5\u67b6\u67b7\u67b8\u67b9\u67ba\u67bb\u67bc\u67bd\u67be\u67bf\u67c0\u67c1\u67c2\u67c3\u67c4\u67c5\u67c6\u67c7\u67c8\u67c9\u67ca\u67cb\u67cc\u67cd\u67ce\u67cf\u67d0\u67d1\u67d2\u67d3\u67d4\u67d5\u67d6\u67d7\u67d8\u67d9\u67da\u67db\u67dc\u67dd\u67de\u67df\u67e0\u67e1\u67e2\u67e3\u67e4\u67e5\u67e6\u67e7\u67e8\u67e9\u67ea\u67eb\u67ec\u67ed\u67ee\u67ef\u67f0\u67f1\u67f2\u67f3\u67f4\u67f5\u67f6\u67f7\u67f8\u67f9\u67fa\u67fb\u67fc\u67fd\u67fe\u67ff\u6800\u6801\u6802\u6803\u6804\u6805\u6806\u6807\u6808\u6809\u680a\u680b\u680c\u680d\u680e\u680f\u6810\u6811\u6812\u6813\u6814\u6815\u6816\u6817\u6818\u6819\u681a\u681b\u681c\u681d\u681e\u681f\u6820\u6821\u6822\u6823\u6824\u6825\u6826\u6827\u6828\u6829\u682a\u682b\u682c\u682d\u682e\u682f\u6830\u6831\u6832\u6833\u6834\u6835\u6836\u6837\u6838\u6839\u683a\u683b\u683c\u683d\u683e\u683f\u6840\u6841\u6842\u6843\u6844\u6845\u6846\u6847\u6848\u6849\u684a\u684b\u684c\u684d\u684e\u684f\u6850\u6851\u6852\u6853\u6854\u6855\u6856\u6857\u6858\u6859\u685a\u685b\u685c\u685d\u685e\u685f\u6860\u6861\u6862\u6863\u6864\u6865\u6866\u6867\u6868\u6869\u686a\u686b\u686c\u686d\u686e\u686f\u6870\u6871\u6872\u6873\u6874\u6875\u6876\u6877\u6878\u6879\u687a\u687b\u687c\u687d\u687e\u687f\u6880\u6881\u6882\u6883\u6884\u6885\u6886\u6887\u6888\u6889\u688a\u688b\u688c\u688d\u688e\u688f\u6890\u6891\u6892\u6893\u6894\u6895\u6896\u6897\u6898\u6899\u689a\u689b\u689c\u689d\u689e\u689f\u68a0\u68a1\u68a2\u68a3\u68a4\u68a5\u68a6\u68a7\u68a8\u68a9\u68aa\u68ab\u68ac\u68ad\u68ae\u68af\u68b0\u68b1\u68b2\u68b3\u68b4\u68b5\u68b6\u68b7\u68b8\u68b9\u68ba\u68bb\u68bc\u68bd\u68be\u68bf\u68c0\u68c1\u68c2\u68c3\u68c4\u68c5\u68c6\u68c7\u68c8\u68c9\u68ca\u68cb\u68cc\u68cd\u68ce\u68cf\u68d0\u68d1\u68d2\u68d3\u68d4\u68d5\u68d6\u68d7\u68d8\u68d9\u68da\u68db\u68dc\u68dd\u68de\u68df\u68e0\u68e1\u68e2\u68e3\u68e4\u68e5\u68e6\u68e7\u68e8\u68e9\u68ea\u68eb\u68ec\u68ed\u68ee\u68ef\u68f0\u68f1\u68f2\u68f3\u68f4\u68f5\u68f6\u68f7\u68f8\u68f9\u68fa\u68fb\u68fc\u68fd\u68fe\u68ff\u6900\u6901\u6902\u6903\u6904\u6905\u6906\u6907\u6908\u6909\u690a\u690b\u690c\u690d\u690e\u690f\u6910\u6911\u6912\u6913\u6914\u6915\u6916\u6917\u6918\u6919\u691a\u691b\u691c\u691d\u691e\u691f\u6920\u6921\u6922\u6923\u6924\u6925\u6926\u6927\u6928\u6929\u692a\u692b\u692c\u692d\u692e\u692f\u6930\u6931\u6932\u6933\u6934\u6935\u6936\u6937\u6938\u6939\u693a\u693b\u693c\u693d\u693e\u693f\u6940\u6941\u6942\u6943\u6944\u6945\u6946\u6947\u6948\u6949\u694a\u694b\u694c\u694d\u694e\u694f\u6950\u6951\u6952\u6953\u6954\u6955\u6956\u6957\u6958\u6959\u695a\u695b\u695c\u695d\u695e\u695f\u6960\u6961\u6962\u6963\u6964\u6965\u6966\u6967\u6968\u6969\u696a\u696b\u696c\u696d\u696e\u696f\u6970\u6971\u6972\u6973\u6974\u6975\u6976\u6977\u6978\u6979\u697a\u697b\u697c\u697d\u697e\u697f\u6980\u6981\u6982\u6983\u6984\u6985\u6986\u6987\u6988\u6989\u698a\u698b\u698c\u698d\u698e\u698f\u6990\u6991\u6992\u6993\u6994\u6995\u6996\u6997\u6998\u6999\u699a\u699b\u699c\u699d\u699e\u699f\u69a0\u69a1\u69a2\u69a3\u69a4\u69a5\u69a6\u69a7\u69a8\u69a9\u69aa\u69ab\u69ac\u69ad\u69ae\u69af\u69b0\u69b1\u69b2\u69b3\u69b4\u69b5\u69b6\u69b7\u69b8\u69b9\u69ba\u69bb\u69bc\u69bd\u69be\u69bf\u69c0\u69c1\u69c2\u69c3\u69c4\u69c5\u69c6\u69c7\u69c8\u69c9\u69ca\u69cb\u69cc\u69cd\u69ce\u69cf\u69d0\u69d1\u69d2\u69d3\u69d4\u69d5\u69d6\u69d7\u69d8\u69d9\u69da\u69db\u69dc\u69dd\u69de\u69df\u69e0\u69e1\u69e2\u69e3\u69e4\u69e5\u69e6\u69e7\u69e8\u69e9\u69ea\u69eb\u69ec\u69ed\u69ee\u69ef\u69f0\u69f1\u69f2\u69f3\u69f4\u69f5\u69f6\u69f7\u69f8\u69f9\u69fa\u69fb\u69fc\u69fd\u69fe\u69ff\u6a00\u6a01\u6a02\u6a03\u6a04\u6a05\u6a06\u6a07\u6a08\u6a09\u6a0a\u6a0b\u6a0c\u6a0d\u6a0e\u6a0f\u6a10\u6a11\u6a12\u6a13\u6a14\u6a15\u6a16\u6a17\u6a18\u6a19\u6a1a\u6a1b\u6a1c\u6a1d\u6a1e\u6a1f\u6a20\u6a21\u6a22\u6a23\u6a24\u6a25\u6a26\u6a27\u6a28\u6a29\u6a2a\u6a2b\u6a2c\u6a2d\u6a2e\u6a2f\u6a30\u6a31\u6a32\u6a33\u6a34\u6a35\u6a36\u6a37\u6a38\u6a39\u6a3a\u6a3b\u6a3c\u6a3d\u6a3e\u6a3f\u6a40\u6a41\u6a42\u6a43\u6a44\u6a45\u6a46\u6a47\u6a48\u6a49\u6a4a\u6a4b\u6a4c\u6a4d\u6a4e\u6a4f\u6a50\u6a51\u6a52\u6a53\u6a54\u6a55\u6a56\u6a57\u6a58\u6a59\u6a5a\u6a5b\u6a5c\u6a5d\u6a5e\u6a5f\u6a60\u6a61\u6a62\u6a63\u6a64\u6a65\u6a66\u6a67\u6a68\u6a69\u6a6a\u6a6b\u6a6c\u6a6d\u6a6e\u6a6f\u6a70\u6a71\u6a72\u6a73\u6a74\u6a75\u6a76\u6a77\u6a78\u6a79\u6a7a\u6a7b\u6a7c\u6a7d\u6a7e\u6a7f\u6a80\u6a81\u6a82\u6a83\u6a84\u6a85\u6a86\u6a87\u6a88\u6a89\u6a8a\u6a8b\u6a8c\u6a8d\u6a8e\u6a8f\u6a90\u6a91\u6a92\u6a93\u6a94\u6a95\u6a96\u6a97\u6a98\u6a99\u6a9a\u6a9b\u6a9c\u6a9d\u6a9e\u6a9f\u6aa0\u6aa1\u6aa2\u6aa3\u6aa4\u6aa5\u6aa6\u6aa7\u6aa8\u6aa9\u6aaa\u6aab\u6aac\u6aad\u6aae\u6aaf\u6ab0\u6ab1\u6ab2\u6ab3\u6ab4\u6ab5\u6ab6\u6ab7\u6ab8\u6ab9\u6aba\u6abb\u6abc\u6abd\u6abe\u6abf\u6ac0\u6ac1\u6ac2\u6ac3\u6ac4\u6ac5\u6ac6\u6ac7\u6ac8\u6ac9\u6aca\u6acb\u6acc\u6acd\u6ace\u6acf\u6ad0\u6ad1\u6ad2\u6ad3\u6ad4\u6ad5\u6ad6\u6ad7\u6ad8\u6ad9\u6ada\u6adb\u6adc\u6add\u6ade\u6adf\u6ae0\u6ae1\u6ae2\u6ae3\u6ae4\u6ae5\u6ae6\u6ae7\u6ae8\u6ae9\u6aea\u6aeb\u6aec\u6aed\u6aee\u6aef\u6af0\u6af1\u6af2\u6af3\u6af4\u6af5\u6af6\u6af7\u6af8\u6af9\u6afa\u6afb\u6afc\u6afd\u6afe\u6aff\u6b00\u6b01\u6b02\u6b03\u6b04\u6b05\u6b06\u6b07\u6b08\u6b09\u6b0a\u6b0b\u6b0c\u6b0d\u6b0e\u6b0f\u6b10\u6b11\u6b12\u6b13\u6b14\u6b15\u6b16\u6b17\u6b18\u6b19\u6b1a\u6b1b\u6b1c\u6b1d\u6b1e\u6b1f\u6b20\u6b21\u6b22\u6b23\u6b24\u6b25\u6b26\u6b27\u6b28\u6b29\u6b2a\u6b2b\u6b2c\u6b2d\u6b2e\u6b2f\u6b30\u6b31\u6b32\u6b33\u6b34\u6b35\u6b36\u6b37\u6b38\u6b39\u6b3a\u6b3b\u6b3c\u6b3d\u6b3e\u6b3f\u6b40\u6b41\u6b42\u6b43\u6b44\u6b45\u6b46\u6b47\u6b48\u6b49\u6b4a\u6b4b\u6b4c\u6b4d\u6b4e\u6b4f\u6b50\u6b51\u6b52\u6b53\u6b54\u6b55\u6b56\u6b57\u6b58\u6b59\u6b5a\u6b5b\u6b5c\u6b5d\u6b5e\u6b5f\u6b60\u6b61\u6b62\u6b63\u6b64\u6b65\u6b66\u6b67\u6b68\u6b69\u6b6a\u6b6b\u6b6c\u6b6d\u6b6e\u6b6f\u6b70\u6b71\u6b72\u6b73\u6b74\u6b75\u6b76\u6b77\u6b78\u6b79\u6b7a\u6b7b\u6b7c\u6b7d\u6b7e\u6b7f\u6b80\u6b81\u6b82\u6b83\u6b84\u6b85\u6b86\u6b87\u6b88\u6b89\u6b8a\u6b8b\u6b8c\u6b8d\u6b8e\u6b8f\u6b90\u6b91\u6b92\u6b93\u6b94\u6b95\u6b96\u6b97\u6b98\u6b99\u6b9a\u6b9b\u6b9c\u6b9d\u6b9e\u6b9f\u6ba0\u6ba1\u6ba2\u6ba3\u6ba4\u6ba5\u6ba6\u6ba7\u6ba8\u6ba9\u6baa\u6bab\u6bac\u6bad\u6bae\u6baf\u6bb0\u6bb1\u6bb2\u6bb3\u6bb4\u6bb5\u6bb6\u6bb7\u6bb8\u6bb9\u6bba\u6bbb\u6bbc\u6bbd\u6bbe\u6bbf\u6bc0\u6bc1\u6bc2\u6bc3\u6bc4\u6bc5\u6bc6\u6bc7\u6bc8\u6bc9\u6bca\u6bcb\u6bcc\u6bcd\u6bce\u6bcf\u6bd0\u6bd1\u6bd2\u6bd3\u6bd4\u6bd5\u6bd6\u6bd7\u6bd8\u6bd9\u6bda\u6bdb\u6bdc\u6bdd\u6bde\u6bdf\u6be0\u6be1\u6be2\u6be3\u6be4\u6be5\u6be6\u6be7\u6be8\u6be9\u6bea\u6beb\u6bec\u6bed\u6bee\u6bef\u6bf0\u6bf1\u6bf2\u6bf3\u6bf4\u6bf5\u6bf6\u6bf7\u6bf8\u6bf9\u6bfa\u6bfb\u6bfc\u6bfd\u6bfe\u6bff\u6c00\u6c01\u6c02\u6c03\u6c04\u6c05\u6c06\u6c07\u6c08\u6c09\u6c0a\u6c0b\u6c0c\u6c0d\u6c0e\u6c0f\u6c10\u6c11\u6c12\u6c13\u6c14\u6c15\u6c16\u6c17\u6c18\u6c19\u6c1a\u6c1b\u6c1c\u6c1d\u6c1e\u6c1f\u6c20\u6c21\u6c22\u6c23\u6c24\u6c25\u6c26\u6c27\u6c28\u6c29\u6c2a\u6c2b\u6c2c\u6c2d\u6c2e\u6c2f\u6c30\u6c31\u6c32\u6c33\u6c34\u6c35\u6c36\u6c37\u6c38\u6c39\u6c3a\u6c3b\u6c3c\u6c3d\u6c3e\u6c3f\u6c40\u6c41\u6c42\u6c43\u6c44\u6c45\u6c46\u6c47\u6c48\u6c49\u6c4a\u6c4b\u6c4c\u6c4d\u6c4e\u6c4f\u6c50\u6c51\u6c52\u6c53\u6c54\u6c55\u6c56\u6c57\u6c58\u6c59\u6c5a\u6c5b\u6c5c\u6c5d\u6c5e\u6c5f\u6c60\u6c61\u6c62\u6c63\u6c64\u6c65\u6c66\u6c67\u6c68\u6c69\u6c6a\u6c6b\u6c6c\u6c6d\u6c6e\u6c6f\u6c70\u6c71\u6c72\u6c73\u6c74\u6c75\u6c76\u6c77\u6c78\u6c79\u6c7a\u6c7b\u6c7c\u6c7d\u6c7e\u6c7f\u6c80\u6c81\u6c82\u6c83\u6c84\u6c85\u6c86\u6c87\u6c88\u6c89\u6c8a\u6c8b\u6c8c\u6c8d\u6c8e\u6c8f\u6c90\u6c91\u6c92\u6c93\u6c94\u6c95\u6c96\u6c97\u6c98\u6c99\u6c9a\u6c9b\u6c9c\u6c9d\u6c9e\u6c9f\u6ca0\u6ca1\u6ca2\u6ca3\u6ca4\u6ca5\u6ca6\u6ca7\u6ca8\u6ca9\u6caa\u6cab\u6cac\u6cad\u6cae\u6caf\u6cb0\u6cb1\u6cb2\u6cb3\u6cb4\u6cb5\u6cb6\u6cb7\u6cb8\u6cb9\u6cba\u6cbb\u6cbc\u6cbd\u6cbe\u6cbf\u6cc0\u6cc1\u6cc2\u6cc3\u6cc4\u6cc5\u6cc6\u6cc7\u6cc8\u6cc9\u6cca\u6ccb\u6ccc\u6ccd\u6cce\u6ccf\u6cd0\u6cd1\u6cd2\u6cd3\u6cd4\u6cd5\u6cd6\u6cd7\u6cd8\u6cd9\u6cda\u6cdb\u6cdc\u6cdd\u6cde\u6cdf\u6ce0\u6ce1\u6ce2\u6ce3\u6ce4\u6ce5\u6ce6\u6ce7\u6ce8\u6ce9\u6cea\u6ceb\u6cec\u6ced\u6cee\u6cef\u6cf0\u6cf1\u6cf2\u6cf3\u6cf4\u6cf5\u6cf6\u6cf7\u6cf8\u6cf9\u6cfa\u6cfb\u6cfc\u6cfd\u6cfe\u6cff\u6d00\u6d01\u6d02\u6d03\u6d04\u6d05\u6d06\u6d07\u6d08\u6d09\u6d0a\u6d0b\u6d0c\u6d0d\u6d0e\u6d0f\u6d10\u6d11\u6d12\u6d13\u6d14\u6d15\u6d16\u6d17\u6d18\u6d19\u6d1a\u6d1b\u6d1c\u6d1d\u6d1e\u6d1f\u6d20\u6d21\u6d22\u6d23\u6d24\u6d25\u6d26\u6d27\u6d28\u6d29\u6d2a\u6d2b\u6d2c\u6d2d\u6d2e\u6d2f\u6d30\u6d31\u6d32\u6d33\u6d34\u6d35\u6d36\u6d37\u6d38\u6d39\u6d3a\u6d3b\u6d3c\u6d3d\u6d3e\u6d3f\u6d40\u6d41\u6d42\u6d43\u6d44\u6d45\u6d46\u6d47\u6d48\u6d49\u6d4a\u6d4b\u6d4c\u6d4d\u6d4e\u6d4f\u6d50\u6d51\u6d52\u6d53\u6d54\u6d55\u6d56\u6d57\u6d58\u6d59\u6d5a\u6d5b\u6d5c\u6d5d\u6d5e\u6d5f\u6d60\u6d61\u6d62\u6d63\u6d64\u6d65\u6d66\u6d67\u6d68\u6d69\u6d6a\u6d6b\u6d6c\u6d6d\u6d6e\u6d6f\u6d70\u6d71\u6d72\u6d73\u6d74\u6d75\u6d76\u6d77\u6d78\u6d79\u6d7a\u6d7b\u6d7c\u6d7d\u6d7e\u6d7f\u6d80\u6d81\u6d82\u6d83\u6d84\u6d85\u6d86\u6d87\u6d88\u6d89\u6d8a\u6d8b\u6d8c\u6d8d\u6d8e\u6d8f\u6d90\u6d91\u6d92\u6d93\u6d94\u6d95\u6d96\u6d97\u6d98\u6d99\u6d9a\u6d9b\u6d9c\u6d9d\u6d9e\u6d9f\u6da0\u6da1\u6da2\u6da3\u6da4\u6da5\u6da6\u6da7\u6da8\u6da9\u6daa\u6dab\u6dac\u6dad\u6dae\u6daf\u6db0\u6db1\u6db2\u6db3\u6db4\u6db5\u6db6\u6db7\u6db8\u6db9\u6dba\u6dbb\u6dbc\u6dbd\u6dbe\u6dbf\u6dc0\u6dc1\u6dc2\u6dc3\u6dc4\u6dc5\u6dc6\u6dc7\u6dc8\u6dc9\u6dca\u6dcb\u6dcc\u6dcd\u6dce\u6dcf\u6dd0\u6dd1\u6dd2\u6dd3\u6dd4\u6dd5\u6dd6\u6dd7\u6dd8\u6dd9\u6dda\u6ddb\u6ddc\u6ddd\u6dde\u6ddf\u6de0\u6de1\u6de2\u6de3\u6de4\u6de5\u6de6\u6de7\u6de8\u6de9\u6dea\u6deb\u6dec\u6ded\u6dee\u6def\u6df0\u6df1\u6df2\u6df3\u6df4\u6df5\u6df6\u6df7\u6df8\u6df9\u6dfa\u6dfb\u6dfc\u6dfd\u6dfe\u6dff\u6e00\u6e01\u6e02\u6e03\u6e04\u6e05\u6e06\u6e07\u6e08\u6e09\u6e0a\u6e0b\u6e0c\u6e0d\u6e0e\u6e0f\u6e10\u6e11\u6e12\u6e13\u6e14\u6e15\u6e16\u6e17\u6e18\u6e19\u6e1a\u6e1b\u6e1c\u6e1d\u6e1e\u6e1f\u6e20\u6e21\u6e22\u6e23\u6e24\u6e25\u6e26\u6e27\u6e28\u6e29\u6e2a\u6e2b\u6e2c\u6e2d\u6e2e\u6e2f\u6e30\u6e31\u6e32\u6e33\u6e34\u6e35\u6e36\u6e37\u6e38\u6e39\u6e3a\u6e3b\u6e3c\u6e3d\u6e3e\u6e3f\u6e40\u6e41\u6e42\u6e43\u6e44\u6e45\u6e46\u6e47\u6e48\u6e49\u6e4a\u6e4b\u6e4c\u6e4d\u6e4e\u6e4f\u6e50\u6e51\u6e52\u6e53\u6e54\u6e55\u6e56\u6e57\u6e58\u6e59\u6e5a\u6e5b\u6e5c\u6e5d\u6e5e\u6e5f\u6e60\u6e61\u6e62\u6e63\u6e64\u6e65\u6e66\u6e67\u6e68\u6e69\u6e6a\u6e6b\u6e6c\u6e6d\u6e6e\u6e6f\u6e70\u6e71\u6e72\u6e73\u6e74\u6e75\u6e76\u6e77\u6e78\u6e79\u6e7a\u6e7b\u6e7c\u6e7d\u6e7e\u6e7f\u6e80\u6e81\u6e82\u6e83\u6e84\u6e85\u6e86\u6e87\u6e88\u6e89\u6e8a\u6e8b\u6e8c\u6e8d\u6e8e\u6e8f\u6e90\u6e91\u6e92\u6e93\u6e94\u6e95\u6e96\u6e97\u6e98\u6e99\u6e9a\u6e9b\u6e9c\u6e9d\u6e9e\u6e9f\u6ea0\u6ea1\u6ea2\u6ea3\u6ea4\u6ea5\u6ea6\u6ea7\u6ea8\u6ea9\u6eaa\u6eab\u6eac\u6ead\u6eae\u6eaf\u6eb0\u6eb1\u6eb2\u6eb3\u6eb4\u6eb5\u6eb6\u6eb7\u6eb8\u6eb9\u6eba\u6ebb\u6ebc\u6ebd\u6ebe\u6ebf\u6ec0\u6ec1\u6ec2\u6ec3\u6ec4\u6ec5\u6ec6\u6ec7\u6ec8\u6ec9\u6eca\u6ecb\u6ecc\u6ecd\u6ece\u6ecf\u6ed0\u6ed1\u6ed2\u6ed3\u6ed4\u6ed5\u6ed6\u6ed7\u6ed8\u6ed9\u6eda\u6edb\u6edc\u6edd\u6ede\u6edf\u6ee0\u6ee1\u6ee2\u6ee3\u6ee4\u6ee5\u6ee6\u6ee7\u6ee8\u6ee9\u6eea\u6eeb\u6eec\u6eed\u6eee\u6eef\u6ef0\u6ef1\u6ef2\u6ef3\u6ef4\u6ef5\u6ef6\u6ef7\u6ef8\u6ef9\u6efa\u6efb\u6efc\u6efd\u6efe\u6eff\u6f00\u6f01\u6f02\u6f03\u6f04\u6f05\u6f06\u6f07\u6f08\u6f09\u6f0a\u6f0b\u6f0c\u6f0d\u6f0e\u6f0f\u6f10\u6f11\u6f12\u6f13\u6f14\u6f15\u6f16\u6f17\u6f18\u6f19\u6f1a\u6f1b\u6f1c\u6f1d\u6f1e\u6f1f\u6f20\u6f21\u6f22\u6f23\u6f24\u6f25\u6f26\u6f27\u6f28\u6f29\u6f2a\u6f2b\u6f2c\u6f2d\u6f2e\u6f2f\u6f30\u6f31\u6f32\u6f33\u6f34\u6f35\u6f36\u6f37\u6f38\u6f39\u6f3a\u6f3b\u6f3c\u6f3d\u6f3e\u6f3f\u6f40\u6f41\u6f42\u6f43\u6f44\u6f45\u6f46\u6f47\u6f48\u6f49\u6f4a\u6f4b\u6f4c\u6f4d\u6f4e\u6f4f\u6f50\u6f51\u6f52\u6f53\u6f54\u6f55\u6f56\u6f57\u6f58\u6f59\u6f5a\u6f5b\u6f5c\u6f5d\u6f5e\u6f5f\u6f60\u6f61\u6f62\u6f63\u6f64\u6f65\u6f66\u6f67\u6f68\u6f69\u6f6a\u6f6b\u6f6c\u6f6d\u6f6e\u6f6f\u6f70\u6f71\u6f72\u6f73\u6f74\u6f75\u6f76\u6f77\u6f78\u6f79\u6f7a\u6f7b\u6f7c\u6f7d\u6f7e\u6f7f\u6f80\u6f81\u6f82\u6f83\u6f84\u6f85\u6f86\u6f87\u6f88\u6f89\u6f8a\u6f8b\u6f8c\u6f8d\u6f8e\u6f8f\u6f90\u6f91\u6f92\u6f93\u6f94\u6f95\u6f96\u6f97\u6f98\u6f99\u6f9a\u6f9b\u6f9c\u6f9d\u6f9e\u6f9f\u6fa0\u6fa1\u6fa2\u6fa3\u6fa4\u6fa5\u6fa6\u6fa7\u6fa8\u6fa9\u6faa\u6fab\u6fac\u6fad\u6fae\u6faf\u6fb0\u6fb1\u6fb2\u6fb3\u6fb4\u6fb5\u6fb6\u6fb7\u6fb8\u6fb9\u6fba\u6fbb\u6fbc\u6fbd\u6fbe\u6fbf\u6fc0\u6fc1\u6fc2\u6fc3\u6fc4\u6fc5\u6fc6\u6fc7\u6fc8\u6fc9\u6fca\u6fcb\u6fcc\u6fcd\u6fce\u6fcf\u6fd0\u6fd1\u6fd2\u6fd3\u6fd4\u6fd5\u6fd6\u6fd7\u6fd8\u6fd9\u6fda\u6fdb\u6fdc\u6fdd\u6fde\u6fdf\u6fe0\u6fe1\u6fe2\u6fe3\u6fe4\u6fe5\u6fe6\u6fe7\u6fe8\u6fe9\u6fea\u6feb\u6fec\u6fed\u6fee\u6fef\u6ff0\u6ff1\u6ff2\u6ff3\u6ff4\u6ff5\u6ff6\u6ff7\u6ff8\u6ff9\u6ffa\u6ffb\u6ffc\u6ffd\u6ffe\u6fff\u7000\u7001\u7002\u7003\u7004\u7005\u7006\u7007\u7008\u7009\u700a\u700b\u700c\u700d\u700e\u700f\u7010\u7011\u7012\u7013\u7014\u7015\u7016\u7017\u7018\u7019\u701a\u701b\u701c\u701d\u701e\u701f\u7020\u7021\u7022\u7023\u7024\u7025\u7026\u7027\u7028\u7029\u702a\u702b\u702c\u702d\u702e\u702f\u7030\u7031\u7032\u7033\u7034\u7035\u7036\u7037\u7038\u7039\u703a\u703b\u703c\u703d\u703e\u703f\u7040\u7041\u7042\u7043\u7044\u7045\u7046\u7047\u7048\u7049\u704a\u704b\u704c\u704d\u704e\u704f\u7050\u7051\u7052\u7053\u7054\u7055\u7056\u7057\u7058\u7059\u705a\u705b\u705c\u705d\u705e\u705f\u7060\u7061\u7062\u7063\u7064\u7065\u7066\u7067\u7068\u7069\u706a\u706b\u706c\u706d\u706e\u706f\u7070\u7071\u7072\u7073\u7074\u7075\u7076\u7077\u7078\u7079\u707a\u707b\u707c\u707d\u707e\u707f\u7080\u7081\u7082\u7083\u7084\u7085\u7086\u7087\u7088\u7089\u708a\u708b\u708c\u708d\u708e\u708f\u7090\u7091\u7092\u7093\u7094\u7095\u7096\u7097\u7098\u7099\u709a\u709b\u709c\u709d\u709e\u709f\u70a0\u70a1\u70a2\u70a3\u70a4\u70a5\u70a6\u70a7\u70a8\u70a9\u70aa\u70ab\u70ac\u70ad\u70ae\u70af\u70b0\u70b1\u70b2\u70b3\u70b4\u70b5\u70b6\u70b7\u70b8\u70b9\u70ba\u70bb\u70bc\u70bd\u70be\u70bf\u70c0\u70c1\u70c2\u70c3\u70c4\u70c5\u70c6\u70c7\u70c8\u70c9\u70ca\u70cb\u70cc\u70cd\u70ce\u70cf\u70d0\u70d1\u70d2\u70d3\u70d4\u70d5\u70d6\u70d7\u70d8\u70d9\u70da\u70db\u70dc\u70dd\u70de\u70df\u70e0\u70e1\u70e2\u70e3\u70e4\u70e5\u70e6\u70e7\u70e8\u70e9\u70ea\u70eb\u70ec\u70ed\u70ee\u70ef\u70f0\u70f1\u70f2\u70f3\u70f4\u70f5\u70f6\u70f7\u70f8\u70f9\u70fa\u70fb\u70fc\u70fd\u70fe\u70ff\u7100\u7101\u7102\u7103\u7104\u7105\u7106\u7107\u7108\u7109\u710a\u710b\u710c\u710d\u710e\u710f\u7110\u7111\u7112\u7113\u7114\u7115\u7116\u7117\u7118\u7119\u711a\u711b\u711c\u711d\u711e\u711f\u7120\u7121\u7122\u7123\u7124\u7125\u7126\u7127\u7128\u7129\u712a\u712b\u712c\u712d\u712e\u712f\u7130\u7131\u7132\u7133\u7134\u7135\u7136\u7137\u7138\u7139\u713a\u713b\u713c\u713d\u713e\u713f\u7140\u7141\u7142\u7143\u7144\u7145\u7146\u7147\u7148\u7149\u714a\u714b\u714c\u714d\u714e\u714f\u7150\u7151\u7152\u7153\u7154\u7155\u7156\u7157\u7158\u7159\u715a\u715b\u715c\u715d\u715e\u715f\u7160\u7161\u7162\u7163\u7164\u7165\u7166\u7167\u7168\u7169\u716a\u716b\u716c\u716d\u716e\u716f\u7170\u7171\u7172\u7173\u7174\u7175\u7176\u7177\u7178\u7179\u717a\u717b\u717c\u717d\u717e\u717f\u7180\u7181\u7182\u7183\u7184\u7185\u7186\u7187\u7188\u7189\u718a\u718b\u718c\u718d\u718e\u718f\u7190\u7191\u7192\u7193\u7194\u7195\u7196\u7197\u7198\u7199\u719a\u719b\u719c\u719d\u719e\u719f\u71a0\u71a1\u71a2\u71a3\u71a4\u71a5\u71a6\u71a7\u71a8\u71a9\u71aa\u71ab\u71ac\u71ad\u71ae\u71af\u71b0\u71b1\u71b2\u71b3\u71b4\u71b5\u71b6\u71b7\u71b8\u71b9\u71ba\u71bb\u71bc\u71bd\u71be\u71bf\u71c0\u71c1\u71c2\u71c3\u71c4\u71c5\u71c6\u71c7\u71c8\u71c9\u71ca\u71cb\u71cc\u71cd\u71ce\u71cf\u71d0\u71d1\u71d2\u71d3\u71d4\u71d5\u71d6\u71d7\u71d8\u71d9\u71da\u71db\u71dc\u71dd\u71de\u71df\u71e0\u71e1\u71e2\u71e3\u71e4\u71e5\u71e6\u71e7\u71e8\u71e9\u71ea\u71eb\u71ec\u71ed\u71ee\u71ef\u71f0\u71f1\u71f2\u71f3\u71f4\u71f5\u71f6\u71f7\u71f8\u71f9\u71fa\u71fb\u71fc\u71fd\u71fe\u71ff\u7200\u7201\u7202\u7203\u7204\u7205\u7206\u7207\u7208\u7209\u720a\u720b\u720c\u720d\u720e\u720f\u7210\u7211\u7212\u7213\u7214\u7215\u7216\u7217\u7218\u7219\u721a\u721b\u721c\u721d\u721e\u721f\u7220\u7221\u7222\u7223\u7224\u7225\u7226\u7227\u7228\u7229\u722a\u722b\u722c\u722d\u722e\u722f\u7230\u7231\u7232\u7233\u7234\u7235\u7236\u7237\u7238\u7239\u723a\u723b\u723c\u723d\u723e\u723f\u7240\u7241\u7242\u7243\u7244\u7245\u7246\u7247\u7248\u7249\u724a\u724b\u724c\u724d\u724e\u724f\u7250\u7251\u7252\u7253\u7254\u7255\u7256\u7257\u7258\u7259\u725a\u725b\u725c\u725d\u725e\u725f\u7260\u7261\u7262\u7263\u7264\u7265\u7266\u7267\u7268\u7269\u726a\u726b\u726c\u726d\u726e\u726f\u7270\u7271\u7272\u7273\u7274\u7275\u7276\u7277\u7278\u7279\u727a\u727b\u727c\u727d\u727e\u727f\u7280\u7281\u7282\u7283\u7284\u7285\u7286\u7287\u7288\u7289\u728a\u728b\u728c\u728d\u728e\u728f\u7290\u7291\u7292\u7293\u7294\u7295\u7296\u7297\u7298\u7299\u729a\u729b\u729c\u729d\u729e\u729f\u72a0\u72a1\u72a2\u72a3\u72a4\u72a5\u72a6\u72a7\u72a8\u72a9\u72aa\u72ab\u72ac\u72ad\u72ae\u72af\u72b0\u72b1\u72b2\u72b3\u72b4\u72b5\u72b6\u72b7\u72b8\u72b9\u72ba\u72bb\u72bc\u72bd\u72be\u72bf\u72c0\u72c1\u72c2\u72c3\u72c4\u72c5\u72c6\u72c7\u72c8\u72c9\u72ca\u72cb\u72cc\u72cd\u72ce\u72cf\u72d0\u72d1\u72d2\u72d3\u72d4\u72d5\u72d6\u72d7\u72d8\u72d9\u72da\u72db\u72dc\u72dd\u72de\u72df\u72e0\u72e1\u72e2\u72e3\u72e4\u72e5\u72e6\u72e7\u72e8\u72e9\u72ea\u72eb\u72ec\u72ed\u72ee\u72ef\u72f0\u72f1\u72f2\u72f3\u72f4\u72f5\u72f6\u72f7\u72f8\u72f9\u72fa\u72fb\u72fc\u72fd\u72fe\u72ff\u7300\u7301\u7302\u7303\u7304\u7305\u7306\u7307\u7308\u7309\u730a\u730b\u730c\u730d\u730e\u730f\u7310\u7311\u7312\u7313\u7314\u7315\u7316\u7317\u7318\u7319\u731a\u731b\u731c\u731d\u731e\u731f\u7320\u7321\u7322\u7323\u7324\u7325\u7326\u7327\u7328\u7329\u732a\u732b\u732c\u732d\u732e\u732f\u7330\u7331\u7332\u7333\u7334\u7335\u7336\u7337\u7338\u7339\u733a\u733b\u733c\u733d\u733e\u733f\u7340\u7341\u7342\u7343\u7344\u7345\u7346\u7347\u7348\u7349\u734a\u734b\u734c\u734d\u734e\u734f\u7350\u7351\u7352\u7353\u7354\u7355\u7356\u7357\u7358\u7359\u735a\u735b\u735c\u735d\u735e\u735f\u7360\u7361\u7362\u7363\u7364\u7365\u7366\u7367\u7368\u7369\u736a\u736b\u736c\u736d\u736e\u736f\u7370\u7371\u7372\u7373\u7374\u7375\u7376\u7377\u7378\u7379\u737a\u737b\u737c\u737d\u737e\u737f\u7380\u7381\u7382\u7383\u7384\u7385\u7386\u7387\u7388\u7389\u738a\u738b\u738c\u738d\u738e\u738f\u7390\u7391\u7392\u7393\u7394\u7395\u7396\u7397\u7398\u7399\u739a\u739b\u739c\u739d\u739e\u739f\u73a0\u73a1\u73a2\u73a3\u73a4\u73a5\u73a6\u73a7\u73a8\u73a9\u73aa\u73ab\u73ac\u73ad\u73ae\u73af\u73b0\u73b1\u73b2\u73b3\u73b4\u73b5\u73b6\u73b7\u73b8\u73b9\u73ba\u73bb\u73bc\u73bd\u73be\u73bf\u73c0\u73c1\u73c2\u73c3\u73c4\u73c5\u73c6\u73c7\u73c8\u73c9\u73ca\u73cb\u73cc\u73cd\u73ce\u73cf\u73d0\u73d1\u73d2\u73d3\u73d4\u73d5\u73d6\u73d7\u73d8\u73d9\u73da\u73db\u73dc\u73dd\u73de\u73df\u73e0\u73e1\u73e2\u73e3\u73e4\u73e5\u73e6\u73e7\u73e8\u73e9\u73ea\u73eb\u73ec\u73ed\u73ee\u73ef\u73f0\u73f1\u73f2\u73f3\u73f4\u73f5\u73f6\u73f7\u73f8\u73f9\u73fa\u73fb\u73fc\u73fd\u73fe\u73ff\u7400\u7401\u7402\u7403\u7404\u7405\u7406\u7407\u7408\u7409\u740a\u740b\u740c\u740d\u740e\u740f\u7410\u7411\u7412\u7413\u7414\u7415\u7416\u7417\u7418\u7419\u741a\u741b\u741c\u741d\u741e\u741f\u7420\u7421\u7422\u7423\u7424\u7425\u7426\u7427\u7428\u7429\u742a\u742b\u742c\u742d\u742e\u742f\u7430\u7431\u7432\u7433\u7434\u7435\u7436\u7437\u7438\u7439\u743a\u743b\u743c\u743d\u743e\u743f\u7440\u7441\u7442\u7443\u7444\u7445\u7446\u7447\u7448\u7449\u744a\u744b\u744c\u744d\u744e\u744f\u7450\u7451\u7452\u7453\u7454\u7455\u7456\u7457\u7458\u7459\u745a\u745b\u745c\u745d\u745e\u745f\u7460\u7461\u7462\u7463\u7464\u7465\u7466\u7467\u7468\u7469\u746a\u746b\u746c\u746d\u746e\u746f\u7470\u7471\u7472\u7473\u7474\u7475\u7476\u7477\u7478\u7479\u747a\u747b\u747c\u747d\u747e\u747f\u7480\u7481\u7482\u7483\u7484\u7485\u7486\u7487\u7488\u7489\u748a\u748b\u748c\u748d\u748e\u748f\u7490\u7491\u7492\u7493\u7494\u7495\u7496\u7497\u7498\u7499\u749a\u749b\u749c\u749d\u749e\u749f\u74a0\u74a1\u74a2\u74a3\u74a4\u74a5\u74a6\u74a7\u74a8\u74a9\u74aa\u74ab\u74ac\u74ad\u74ae\u74af\u74b0\u74b1\u74b2\u74b3\u74b4\u74b5\u74b6\u74b7\u74b8\u74b9\u74ba\u74bb\u74bc\u74bd\u74be\u74bf\u74c0\u74c1\u74c2\u74c3\u74c4\u74c5\u74c6\u74c7\u74c8\u74c9\u74ca\u74cb\u74cc\u74cd\u74ce\u74cf\u74d0\u74d1\u74d2\u74d3\u74d4\u74d5\u74d6\u74d7\u74d8\u74d9\u74da\u74db\u74dc\u74dd\u74de\u74df\u74e0\u74e1\u74e2\u74e3\u74e4\u74e5\u74e6\u74e7\u74e8\u74e9\u74ea\u74eb\u74ec\u74ed\u74ee\u74ef\u74f0\u74f1\u74f2\u74f3\u74f4\u74f5\u74f6\u74f7\u74f8\u74f9\u74fa\u74fb\u74fc\u74fd\u74fe\u74ff\u7500\u7501\u7502\u7503\u7504\u7505\u7506\u7507\u7508\u7509\u750a\u750b\u750c\u750d\u750e\u750f\u7510\u7511\u7512\u7513\u7514\u7515\u7516\u7517\u7518\u7519\u751a\u751b\u751c\u751d\u751e\u751f\u7520\u7521\u7522\u7523\u7524\u7525\u7526\u7527\u7528\u7529\u752a\u752b\u752c\u752d\u752e\u752f\u7530\u7531\u7532\u7533\u7534\u7535\u7536\u7537\u7538\u7539\u753a\u753b\u753c\u753d\u753e\u753f\u7540\u7541\u7542\u7543\u7544\u7545\u7546\u7547\u7548\u7549\u754a\u754b\u754c\u754d\u754e\u754f\u7550\u7551\u7552\u7553\u7554\u7555\u7556\u7557\u7558\u7559\u755a\u755b\u755c\u755d\u755e\u755f\u7560\u7561\u7562\u7563\u7564\u7565\u7566\u7567\u7568\u7569\u756a\u756b\u756c\u756d\u756e\u756f\u7570\u7571\u7572\u7573\u7574\u7575\u7576\u7577\u7578\u7579\u757a\u757b\u757c\u757d\u757e\u757f\u7580\u7581\u7582\u7583\u7584\u7585\u7586\u7587\u7588\u7589\u758a\u758b\u758c\u758d\u758e\u758f\u7590\u7591\u7592\u7593\u7594\u7595\u7596\u7597\u7598\u7599\u759a\u759b\u759c\u759d\u759e\u759f\u75a0\u75a1\u75a2\u75a3\u75a4\u75a5\u75a6\u75a7\u75a8\u75a9\u75aa\u75ab\u75ac\u75ad\u75ae\u75af\u75b0\u75b1\u75b2\u75b3\u75b4\u75b5\u75b6\u75b7\u75b8\u75b9\u75ba\u75bb\u75bc\u75bd\u75be\u75bf\u75c0\u75c1\u75c2\u75c3\u75c4\u75c5\u75c6\u75c7\u75c8\u75c9\u75ca\u75cb\u75cc\u75cd\u75ce\u75cf\u75d0\u75d1\u75d2\u75d3\u75d4\u75d5\u75d6\u75d7\u75d8\u75d9\u75da\u75db\u75dc\u75dd\u75de\u75df\u75e0\u75e1\u75e2\u75e3\u75e4\u75e5\u75e6\u75e7\u75e8\u75e9\u75ea\u75eb\u75ec\u75ed\u75ee\u75ef\u75f0\u75f1\u75f2\u75f3\u75f4\u75f5\u75f6\u75f7\u75f8\u75f9\u75fa\u75fb\u75fc\u75fd\u75fe\u75ff\u7600\u7601\u7602\u7603\u7604\u7605\u7606\u7607\u7608\u7609\u760a\u760b\u760c\u760d\u760e\u760f\u7610\u7611\u7612\u7613\u7614\u7615\u7616\u7617\u7618\u7619\u761a\u761b\u761c\u761d\u761e\u761f\u7620\u7621\u7622\u7623\u7624\u7625\u7626\u7627\u7628\u7629\u762a\u762b\u762c\u762d\u762e\u762f\u7630\u7631\u7632\u7633\u7634\u7635\u7636\u7637\u7638\u7639\u763a\u763b\u763c\u763d\u763e\u763f\u7640\u7641\u7642\u7643\u7644\u7645\u7646\u7647\u7648\u7649\u764a\u764b\u764c\u764d\u764e\u764f\u7650\u7651\u7652\u7653\u7654\u7655\u7656\u7657\u7658\u7659\u765a\u765b\u765c\u765d\u765e\u765f\u7660\u7661\u7662\u7663\u7664\u7665\u7666\u7667\u7668\u7669\u766a\u766b\u766c\u766d\u766e\u766f\u7670\u7671\u7672\u7673\u7674\u7675\u7676\u7677\u7678\u7679\u767a\u767b\u767c\u767d\u767e\u767f\u7680\u7681\u7682\u7683\u7684\u7685\u7686\u7687\u7688\u7689\u768a\u768b\u768c\u768d\u768e\u768f\u7690\u7691\u7692\u7693\u7694\u7695\u7696\u7697\u7698\u7699\u769a\u769b\u769c\u769d\u769e\u769f\u76a0\u76a1\u76a2\u76a3\u76a4\u76a5\u76a6\u76a7\u76a8\u76a9\u76aa\u76ab\u76ac\u76ad\u76ae\u76af\u76b0\u76b1\u76b2\u76b3\u76b4\u76b5\u76b6\u76b7\u76b8\u76b9\u76ba\u76bb\u76bc\u76bd\u76be\u76bf\u76c0\u76c1\u76c2\u76c3\u76c4\u76c5\u76c6\u76c7\u76c8\u76c9\u76ca\u76cb\u76cc\u76cd\u76ce\u76cf\u76d0\u76d1\u76d2\u76d3\u76d4\u76d5\u76d6\u76d7\u76d8\u76d9\u76da\u76db\u76dc\u76dd\u76de\u76df\u76e0\u76e1\u76e2\u76e3\u76e4\u76e5\u76e6\u76e7\u76e8\u76e9\u76ea\u76eb\u76ec\u76ed\u76ee\u76ef\u76f0\u76f1\u76f2\u76f3\u76f4\u76f5\u76f6\u76f7\u76f8\u76f9\u76fa\u76fb\u76fc\u76fd\u76fe\u76ff\u7700\u7701\u7702\u7703\u7704\u7705\u7706\u7707\u7708\u7709\u770a\u770b\u770c\u770d\u770e\u770f\u7710\u7711\u7712\u7713\u7714\u7715\u7716\u7717\u7718\u7719\u771a\u771b\u771c\u771d\u771e\u771f\u7720\u7721\u7722\u7723\u7724\u7725\u7726\u7727\u7728\u7729\u772a\u772b\u772c\u772d\u772e\u772f\u7730\u7731\u7732\u7733\u7734\u7735\u7736\u7737\u7738\u7739\u773a\u773b\u773c\u773d\u773e\u773f\u7740\u7741\u7742\u7743\u7744\u7745\u7746\u7747\u7748\u7749\u774a\u774b\u774c\u774d\u774e\u774f\u7750\u7751\u7752\u7753\u7754\u7755\u7756\u7757\u7758\u7759\u775a\u775b\u775c\u775d\u775e\u775f\u7760\u7761\u7762\u7763\u7764\u7765\u7766\u7767\u7768\u7769\u776a\u776b\u776c\u776d\u776e\u776f\u7770\u7771\u7772\u7773\u7774\u7775\u7776\u7777\u7778\u7779\u777a\u777b\u777c\u777d\u777e\u777f\u7780\u7781\u7782\u7783\u7784\u7785\u7786\u7787\u7788\u7789\u778a\u778b\u778c\u778d\u778e\u778f\u7790\u7791\u7792\u7793\u7794\u7795\u7796\u7797\u7798\u7799\u779a\u779b\u779c\u779d\u779e\u779f\u77a0\u77a1\u77a2\u77a3\u77a4\u77a5\u77a6\u77a7\u77a8\u77a9\u77aa\u77ab\u77ac\u77ad\u77ae\u77af\u77b0\u77b1\u77b2\u77b3\u77b4\u77b5\u77b6\u77b7\u77b8\u77b9\u77ba\u77bb\u77bc\u77bd\u77be\u77bf\u77c0\u77c1\u77c2\u77c3\u77c4\u77c5\u77c6\u77c7\u77c8\u77c9\u77ca\u77cb\u77cc\u77cd\u77ce\u77cf\u77d0\u77d1\u77d2\u77d3\u77d4\u77d5\u77d6\u77d7\u77d8\u77d9\u77da\u77db\u77dc\u77dd\u77de\u77df\u77e0\u77e1\u77e2\u77e3\u77e4\u77e5\u77e6\u77e7\u77e8\u77e9\u77ea\u77eb\u77ec\u77ed\u77ee\u77ef\u77f0\u77f1\u77f2\u77f3\u77f4\u77f5\u77f6\u77f7\u77f8\u77f9\u77fa\u77fb\u77fc\u77fd\u77fe\u77ff\u7800\u7801\u7802\u7803\u7804\u7805\u7806\u7807\u7808\u7809\u780a\u780b\u780c\u780d\u780e\u780f\u7810\u7811\u7812\u7813\u7814\u7815\u7816\u7817\u7818\u7819\u781a\u781b\u781c\u781d\u781e\u781f\u7820\u7821\u7822\u7823\u7824\u7825\u7826\u7827\u7828\u7829\u782a\u782b\u782c\u782d\u782e\u782f\u7830\u7831\u7832\u7833\u7834\u7835\u7836\u7837\u7838\u7839\u783a\u783b\u783c\u783d\u783e\u783f\u7840\u7841\u7842\u7843\u7844\u7845\u7846\u7847\u7848\u7849\u784a\u784b\u784c\u784d\u784e\u784f\u7850\u7851\u7852\u7853\u7854\u7855\u7856\u7857\u7858\u7859\u785a\u785b\u785c\u785d\u785e\u785f\u7860\u7861\u7862\u7863\u7864\u7865\u7866\u7867\u7868\u7869\u786a\u786b\u786c\u786d\u786e\u786f\u7870\u7871\u7872\u7873\u7874\u7875\u7876\u7877\u7878\u7879\u787a\u787b\u787c\u787d\u787e\u787f\u7880\u7881\u7882\u7883\u7884\u7885\u7886\u7887\u7888\u7889\u788a\u788b\u788c\u788d\u788e\u788f\u7890\u7891\u7892\u7893\u7894\u7895\u7896\u7897\u7898\u7899\u789a\u789b\u789c\u789d\u789e\u789f\u78a0\u78a1\u78a2\u78a3\u78a4\u78a5\u78a6\u78a7\u78a8\u78a9\u78aa\u78ab\u78ac\u78ad\u78ae\u78af\u78b0\u78b1\u78b2\u78b3\u78b4\u78b5\u78b6\u78b7\u78b8\u78b9\u78ba\u78bb\u78bc\u78bd\u78be\u78bf\u78c0\u78c1\u78c2\u78c3\u78c4\u78c5\u78c6\u78c7\u78c8\u78c9\u78ca\u78cb\u78cc\u78cd\u78ce\u78cf\u78d0\u78d1\u78d2\u78d3\u78d4\u78d5\u78d6\u78d7\u78d8\u78d9\u78da\u78db\u78dc\u78dd\u78de\u78df\u78e0\u78e1\u78e2\u78e3\u78e4\u78e5\u78e6\u78e7\u78e8\u78e9\u78ea\u78eb\u78ec\u78ed\u78ee\u78ef\u78f0\u78f1\u78f2\u78f3\u78f4\u78f5\u78f6\u78f7\u78f8\u78f9\u78fa\u78fb\u78fc\u78fd\u78fe\u78ff\u7900\u7901\u7902\u7903\u7904\u7905\u7906\u7907\u7908\u7909\u790a\u790b\u790c\u790d\u790e\u790f\u7910\u7911\u7912\u7913\u7914\u7915\u7916\u7917\u7918\u7919\u791a\u791b\u791c\u791d\u791e\u791f\u7920\u7921\u7922\u7923\u7924\u7925\u7926\u7927\u7928\u7929\u792a\u792b\u792c\u792d\u792e\u792f\u7930\u7931\u7932\u7933\u7934\u7935\u7936\u7937\u7938\u7939\u793a\u793b\u793c\u793d\u793e\u793f\u7940\u7941\u7942\u7943\u7944\u7945\u7946\u7947\u7948\u7949\u794a\u794b\u794c\u794d\u794e\u794f\u7950\u7951\u7952\u7953\u7954\u7955\u7956\u7957\u7958\u7959\u795a\u795b\u795c\u795d\u795e\u795f\u7960\u7961\u7962\u7963\u7964\u7965\u7966\u7967\u7968\u7969\u796a\u796b\u796c\u796d\u796e\u796f\u7970\u7971\u7972\u7973\u7974\u7975\u7976\u7977\u7978\u7979\u797a\u797b\u797c\u797d\u797e\u797f\u7980\u7981\u7982\u7983\u7984\u7985\u7986\u7987\u7988\u7989\u798a\u798b\u798c\u798d\u798e\u798f\u7990\u7991\u7992\u7993\u7994\u7995\u7996\u7997\u7998\u7999\u799a\u799b\u799c\u799d\u799e\u799f\u79a0\u79a1\u79a2\u79a3\u79a4\u79a5\u79a6\u79a7\u79a8\u79a9\u79aa\u79ab\u79ac\u79ad\u79ae\u79af\u79b0\u79b1\u79b2\u79b3\u79b4\u79b5\u79b6\u79b7\u79b8\u79b9\u79ba\u79bb\u79bc\u79bd\u79be\u79bf\u79c0\u79c1\u79c2\u79c3\u79c4\u79c5\u79c6\u79c7\u79c8\u79c9\u79ca\u79cb\u79cc\u79cd\u79ce\u79cf\u79d0\u79d1\u79d2\u79d3\u79d4\u79d5\u79d6\u79d7\u79d8\u79d9\u79da\u79db\u79dc\u79dd\u79de\u79df\u79e0\u79e1\u79e2\u79e3\u79e4\u79e5\u79e6\u79e7\u79e8\u79e9\u79ea\u79eb\u79ec\u79ed\u79ee\u79ef\u79f0\u79f1\u79f2\u79f3\u79f4\u79f5\u79f6\u79f7\u79f8\u79f9\u79fa\u79fb\u79fc\u79fd\u79fe\u79ff\u7a00\u7a01\u7a02\u7a03\u7a04\u7a05\u7a06\u7a07\u7a08\u7a09\u7a0a\u7a0b\u7a0c\u7a0d\u7a0e\u7a0f\u7a10\u7a11\u7a12\u7a13\u7a14\u7a15\u7a16\u7a17\u7a18\u7a19\u7a1a\u7a1b\u7a1c\u7a1d\u7a1e\u7a1f\u7a20\u7a21\u7a22\u7a23\u7a24\u7a25\u7a26\u7a27\u7a28\u7a29\u7a2a\u7a2b\u7a2c\u7a2d\u7a2e\u7a2f\u7a30\u7a31\u7a32\u7a33\u7a34\u7a35\u7a36\u7a37\u7a38\u7a39\u7a3a\u7a3b\u7a3c\u7a3d\u7a3e\u7a3f\u7a40\u7a41\u7a42\u7a43\u7a44\u7a45\u7a46\u7a47\u7a48\u7a49\u7a4a\u7a4b\u7a4c\u7a4d\u7a4e\u7a4f\u7a50\u7a51\u7a52\u7a53\u7a54\u7a55\u7a56\u7a57\u7a58\u7a59\u7a5a\u7a5b\u7a5c\u7a5d\u7a5e\u7a5f\u7a60\u7a61\u7a62\u7a63\u7a64\u7a65\u7a66\u7a67\u7a68\u7a69\u7a6a\u7a6b\u7a6c\u7a6d\u7a6e\u7a6f\u7a70\u7a71\u7a72\u7a73\u7a74\u7a75\u7a76\u7a77\u7a78\u7a79\u7a7a\u7a7b\u7a7c\u7a7d\u7a7e\u7a7f\u7a80\u7a81\u7a82\u7a83\u7a84\u7a85\u7a86\u7a87\u7a88\u7a89\u7a8a\u7a8b\u7a8c\u7a8d\u7a8e\u7a8f\u7a90\u7a91\u7a92\u7a93\u7a94\u7a95\u7a96\u7a97\u7a98\u7a99\u7a9a\u7a9b\u7a9c\u7a9d\u7a9e\u7a9f\u7aa0\u7aa1\u7aa2\u7aa3\u7aa4\u7aa5\u7aa6\u7aa7\u7aa8\u7aa9\u7aaa\u7aab\u7aac\u7aad\u7aae\u7aaf\u7ab0\u7ab1\u7ab2\u7ab3\u7ab4\u7ab5\u7ab6\u7ab7\u7ab8\u7ab9\u7aba\u7abb\u7abc\u7abd\u7abe\u7abf\u7ac0\u7ac1\u7ac2\u7ac3\u7ac4\u7ac5\u7ac6\u7ac7\u7ac8\u7ac9\u7aca\u7acb\u7acc\u7acd\u7ace\u7acf\u7ad0\u7ad1\u7ad2\u7ad3\u7ad4\u7ad5\u7ad6\u7ad7\u7ad8\u7ad9\u7ada\u7adb\u7adc\u7add\u7ade\u7adf\u7ae0\u7ae1\u7ae2\u7ae3\u7ae4\u7ae5\u7ae6\u7ae7\u7ae8\u7ae9\u7aea\u7aeb\u7aec\u7aed\u7aee\u7aef\u7af0\u7af1\u7af2\u7af3\u7af4\u7af5\u7af6\u7af7\u7af8\u7af9\u7afa\u7afb\u7afc\u7afd\u7afe\u7aff\u7b00\u7b01\u7b02\u7b03\u7b04\u7b05\u7b06\u7b07\u7b08\u7b09\u7b0a\u7b0b\u7b0c\u7b0d\u7b0e\u7b0f\u7b10\u7b11\u7b12\u7b13\u7b14\u7b15\u7b16\u7b17\u7b18\u7b19\u7b1a\u7b1b\u7b1c\u7b1d\u7b1e\u7b1f\u7b20\u7b21\u7b22\u7b23\u7b24\u7b25\u7b26\u7b27\u7b28\u7b29\u7b2a\u7b2b\u7b2c\u7b2d\u7b2e\u7b2f\u7b30\u7b31\u7b32\u7b33\u7b34\u7b35\u7b36\u7b37\u7b38\u7b39\u7b3a\u7b3b\u7b3c\u7b3d\u7b3e\u7b3f\u7b40\u7b41\u7b42\u7b43\u7b44\u7b45\u7b46\u7b47\u7b48\u7b49\u7b4a\u7b4b\u7b4c\u7b4d\u7b4e\u7b4f\u7b50\u7b51\u7b52\u7b53\u7b54\u7b55\u7b56\u7b57\u7b58\u7b59\u7b5a\u7b5b\u7b5c\u7b5d\u7b5e\u7b5f\u7b60\u7b61\u7b62\u7b63\u7b64\u7b65\u7b66\u7b67\u7b68\u7b69\u7b6a\u7b6b\u7b6c\u7b6d\u7b6e\u7b6f\u7b70\u7b71\u7b72\u7b73\u7b74\u7b75\u7b76\u7b77\u7b78\u7b79\u7b7a\u7b7b\u7b7c\u7b7d\u7b7e\u7b7f\u7b80\u7b81\u7b82\u7b83\u7b84\u7b85\u7b86\u7b87\u7b88\u7b89\u7b8a\u7b8b\u7b8c\u7b8d\u7b8e\u7b8f\u7b90\u7b91\u7b92\u7b93\u7b94\u7b95\u7b96\u7b97\u7b98\u7b99\u7b9a\u7b9b\u7b9c\u7b9d\u7b9e\u7b9f\u7ba0\u7ba1\u7ba2\u7ba3\u7ba4\u7ba5\u7ba6\u7ba7\u7ba8\u7ba9\u7baa\u7bab\u7bac\u7bad\u7bae\u7baf\u7bb0\u7bb1\u7bb2\u7bb3\u7bb4\u7bb5\u7bb6\u7bb7\u7bb8\u7bb9\u7bba\u7bbb\u7bbc\u7bbd\u7bbe\u7bbf\u7bc0\u7bc1\u7bc2\u7bc3\u7bc4\u7bc5\u7bc6\u7bc7\u7bc8\u7bc9\u7bca\u7bcb\u7bcc\u7bcd\u7bce\u7bcf\u7bd0\u7bd1\u7bd2\u7bd3\u7bd4\u7bd5\u7bd6\u7bd7\u7bd8\u7bd9\u7bda\u7bdb\u7bdc\u7bdd\u7bde\u7bdf\u7be0\u7be1\u7be2\u7be3\u7be4\u7be5\u7be6\u7be7\u7be8\u7be9\u7bea\u7beb\u7bec\u7bed\u7bee\u7bef\u7bf0\u7bf1\u7bf2\u7bf3\u7bf4\u7bf5\u7bf6\u7bf7\u7bf8\u7bf9\u7bfa\u7bfb\u7bfc\u7bfd\u7bfe\u7bff\u7c00\u7c01\u7c02\u7c03\u7c04\u7c05\u7c06\u7c07\u7c08\u7c09\u7c0a\u7c0b\u7c0c\u7c0d\u7c0e\u7c0f\u7c10\u7c11\u7c12\u7c13\u7c14\u7c15\u7c16\u7c17\u7c18\u7c19\u7c1a\u7c1b\u7c1c\u7c1d\u7c1e\u7c1f\u7c20\u7c21\u7c22\u7c23\u7c24\u7c25\u7c26\u7c27\u7c28\u7c29\u7c2a\u7c2b\u7c2c\u7c2d\u7c2e\u7c2f\u7c30\u7c31\u7c32\u7c33\u7c34\u7c35\u7c36\u7c37\u7c38\u7c39\u7c3a\u7c3b\u7c3c\u7c3d\u7c3e\u7c3f\u7c40\u7c41\u7c42\u7c43\u7c44\u7c45\u7c46\u7c47\u7c48\u7c49\u7c4a\u7c4b\u7c4c\u7c4d\u7c4e\u7c4f\u7c50\u7c51\u7c52\u7c53\u7c54\u7c55\u7c56\u7c57\u7c58\u7c59\u7c5a\u7c5b\u7c5c\u7c5d\u7c5e\u7c5f\u7c60\u7c61\u7c62\u7c63\u7c64\u7c65\u7c66\u7c67\u7c68\u7c69\u7c6a\u7c6b\u7c6c\u7c6d\u7c6e\u7c6f\u7c70\u7c71\u7c72\u7c73\u7c74\u7c75\u7c76\u7c77\u7c78\u7c79\u7c7a\u7c7b\u7c7c\u7c7d\u7c7e\u7c7f\u7c80\u7c81\u7c82\u7c83\u7c84\u7c85\u7c86\u7c87\u7c88\u7c89\u7c8a\u7c8b\u7c8c\u7c8d\u7c8e\u7c8f\u7c90\u7c91\u7c92\u7c93\u7c94\u7c95\u7c96\u7c97\u7c98\u7c99\u7c9a\u7c9b\u7c9c\u7c9d\u7c9e\u7c9f\u7ca0\u7ca1\u7ca2\u7ca3\u7ca4\u7ca5\u7ca6\u7ca7\u7ca8\u7ca9\u7caa\u7cab\u7cac\u7cad\u7cae\u7caf\u7cb0\u7cb1\u7cb2\u7cb3\u7cb4\u7cb5\u7cb6\u7cb7\u7cb8\u7cb9\u7cba\u7cbb\u7cbc\u7cbd\u7cbe\u7cbf\u7cc0\u7cc1\u7cc2\u7cc3\u7cc4\u7cc5\u7cc6\u7cc7\u7cc8\u7cc9\u7cca\u7ccb\u7ccc\u7ccd\u7cce\u7ccf\u7cd0\u7cd1\u7cd2\u7cd3\u7cd4\u7cd5\u7cd6\u7cd7\u7cd8\u7cd9\u7cda\u7cdb\u7cdc\u7cdd\u7cde\u7cdf\u7ce0\u7ce1\u7ce2\u7ce3\u7ce4\u7ce5\u7ce6\u7ce7\u7ce8\u7ce9\u7cea\u7ceb\u7cec\u7ced\u7cee\u7cef\u7cf0\u7cf1\u7cf2\u7cf3\u7cf4\u7cf5\u7cf6\u7cf7\u7cf8\u7cf9\u7cfa\u7cfb\u7cfc\u7cfd\u7cfe\u7cff\u7d00\u7d01\u7d02\u7d03\u7d04\u7d05\u7d06\u7d07\u7d08\u7d09\u7d0a\u7d0b\u7d0c\u7d0d\u7d0e\u7d0f\u7d10\u7d11\u7d12\u7d13\u7d14\u7d15\u7d16\u7d17\u7d18\u7d19\u7d1a\u7d1b\u7d1c\u7d1d\u7d1e\u7d1f\u7d20\u7d21\u7d22\u7d23\u7d24\u7d25\u7d26\u7d27\u7d28\u7d29\u7d2a\u7d2b\u7d2c\u7d2d\u7d2e\u7d2f\u7d30\u7d31\u7d32\u7d33\u7d34\u7d35\u7d36\u7d37\u7d38\u7d39\u7d3a\u7d3b\u7d3c\u7d3d\u7d3e\u7d3f\u7d40\u7d41\u7d42\u7d43\u7d44\u7d45\u7d46\u7d47\u7d48\u7d49\u7d4a\u7d4b\u7d4c\u7d4d\u7d4e\u7d4f\u7d50\u7d51\u7d52\u7d53\u7d54\u7d55\u7d56\u7d57\u7d58\u7d59\u7d5a\u7d5b\u7d5c\u7d5d\u7d5e\u7d5f\u7d60\u7d61\u7d62\u7d63\u7d64\u7d65\u7d66\u7d67\u7d68\u7d69\u7d6a\u7d6b\u7d6c\u7d6d\u7d6e\u7d6f\u7d70\u7d71\u7d72\u7d73\u7d74\u7d75\u7d76\u7d77\u7d78\u7d79\u7d7a\u7d7b\u7d7c\u7d7d\u7d7e\u7d7f\u7d80\u7d81\u7d82\u7d83\u7d84\u7d85\u7d86\u7d87\u7d88\u7d89\u7d8a\u7d8b\u7d8c\u7d8d\u7d8e\u7d8f\u7d90\u7d91\u7d92\u7d93\u7d94\u7d95\u7d96\u7d97\u7d98\u7d99\u7d9a\u7d9b\u7d9c\u7d9d\u7d9e\u7d9f\u7da0\u7da1\u7da2\u7da3\u7da4\u7da5\u7da6\u7da7\u7da8\u7da9\u7daa\u7dab\u7dac\u7dad\u7dae\u7daf\u7db0\u7db1\u7db2\u7db3\u7db4\u7db5\u7db6\u7db7\u7db8\u7db9\u7dba\u7dbb\u7dbc\u7dbd\u7dbe\u7dbf\u7dc0\u7dc1\u7dc2\u7dc3\u7dc4\u7dc5\u7dc6\u7dc7\u7dc8\u7dc9\u7dca\u7dcb\u7dcc\u7dcd\u7dce\u7dcf\u7dd0\u7dd1\u7dd2\u7dd3\u7dd4\u7dd5\u7dd6\u7dd7\u7dd8\u7dd9\u7dda\u7ddb\u7ddc\u7ddd\u7dde\u7ddf\u7de0\u7de1\u7de2\u7de3\u7de4\u7de5\u7de6\u7de7\u7de8\u7de9\u7dea\u7deb\u7dec\u7ded\u7dee\u7def\u7df0\u7df1\u7df2\u7df3\u7df4\u7df5\u7df6\u7df7\u7df8\u7df9\u7dfa\u7dfb\u7dfc\u7dfd\u7dfe\u7dff\u7e00\u7e01\u7e02\u7e03\u7e04\u7e05\u7e06\u7e07\u7e08\u7e09\u7e0a\u7e0b\u7e0c\u7e0d\u7e0e\u7e0f\u7e10\u7e11\u7e12\u7e13\u7e14\u7e15\u7e16\u7e17\u7e18\u7e19\u7e1a\u7e1b\u7e1c\u7e1d\u7e1e\u7e1f\u7e20\u7e21\u7e22\u7e23\u7e24\u7e25\u7e26\u7e27\u7e28\u7e29\u7e2a\u7e2b\u7e2c\u7e2d\u7e2e\u7e2f\u7e30\u7e31\u7e32\u7e33\u7e34\u7e35\u7e36\u7e37\u7e38\u7e39\u7e3a\u7e3b\u7e3c\u7e3d\u7e3e\u7e3f\u7e40\u7e41\u7e42\u7e43\u7e44\u7e45\u7e46\u7e47\u7e48\u7e49\u7e4a\u7e4b\u7e4c\u7e4d\u7e4e\u7e4f\u7e50\u7e51\u7e52\u7e53\u7e54\u7e55\u7e56\u7e57\u7e58\u7e59\u7e5a\u7e5b\u7e5c\u7e5d\u7e5e\u7e5f\u7e60\u7e61\u7e62\u7e63\u7e64\u7e65\u7e66\u7e67\u7e68\u7e69\u7e6a\u7e6b\u7e6c\u7e6d\u7e6e\u7e6f\u7e70\u7e71\u7e72\u7e73\u7e74\u7e75\u7e76\u7e77\u7e78\u7e79\u7e7a\u7e7b\u7e7c\u7e7d\u7e7e\u7e7f\u7e80\u7e81\u7e82\u7e83\u7e84\u7e85\u7e86\u7e87\u7e88\u7e89\u7e8a\u7e8b\u7e8c\u7e8d\u7e8e\u7e8f\u7e90\u7e91\u7e92\u7e93\u7e94\u7e95\u7e96\u7e97\u7e98\u7e99\u7e9a\u7e9b\u7e9c\u7e9d\u7e9e\u7e9f\u7ea0\u7ea1\u7ea2\u7ea3\u7ea4\u7ea5\u7ea6\u7ea7\u7ea8\u7ea9\u7eaa\u7eab\u7eac\u7ead\u7eae\u7eaf\u7eb0\u7eb1\u7eb2\u7eb3\u7eb4\u7eb5\u7eb6\u7eb7\u7eb8\u7eb9\u7eba\u7ebb\u7ebc\u7ebd\u7ebe\u7ebf\u7ec0\u7ec1\u7ec2\u7ec3\u7ec4\u7ec5\u7ec6\u7ec7\u7ec8\u7ec9\u7eca\u7ecb\u7ecc\u7ecd\u7ece\u7ecf\u7ed0\u7ed1\u7ed2\u7ed3\u7ed4\u7ed5\u7ed6\u7ed7\u7ed8\u7ed9\u7eda\u7edb\u7edc\u7edd\u7ede\u7edf\u7ee0\u7ee1\u7ee2\u7ee3\u7ee4\u7ee5\u7ee6\u7ee7\u7ee8\u7ee9\u7eea\u7eeb\u7eec\u7eed\u7eee\u7eef\u7ef0\u7ef1\u7ef2\u7ef3\u7ef4\u7ef5\u7ef6\u7ef7\u7ef8\u7ef9\u7efa\u7efb\u7efc\u7efd\u7efe\u7eff\u7f00\u7f01\u7f02\u7f03\u7f04\u7f05\u7f06\u7f07\u7f08\u7f09\u7f0a\u7f0b\u7f0c\u7f0d\u7f0e\u7f0f\u7f10\u7f11\u7f12\u7f13\u7f14\u7f15\u7f16\u7f17\u7f18\u7f19\u7f1a\u7f1b\u7f1c\u7f1d\u7f1e\u7f1f\u7f20\u7f21\u7f22\u7f23\u7f24\u7f25\u7f26\u7f27\u7f28\u7f29\u7f2a\u7f2b\u7f2c\u7f2d\u7f2e\u7f2f\u7f30\u7f31\u7f32\u7f33\u7f34\u7f35\u7f36\u7f37\u7f38\u7f39\u7f3a\u7f3b\u7f3c\u7f3d\u7f3e\u7f3f\u7f40\u7f41\u7f42\u7f43\u7f44\u7f45\u7f46\u7f47\u7f48\u7f49\u7f4a\u7f4b\u7f4c\u7f4d\u7f4e\u7f4f\u7f50\u7f51\u7f52\u7f53\u7f54\u7f55\u7f56\u7f57\u7f58\u7f59\u7f5a\u7f5b\u7f5c\u7f5d\u7f5e\u7f5f\u7f60\u7f61\u7f62\u7f63\u7f64\u7f65\u7f66\u7f67\u7f68\u7f69\u7f6a\u7f6b\u7f6c\u7f6d\u7f6e\u7f6f\u7f70\u7f71\u7f72\u7f73\u7f74\u7f75\u7f76\u7f77\u7f78\u7f79\u7f7a\u7f7b\u7f7c\u7f7d\u7f7e\u7f7f\u7f80\u7f81\u7f82\u7f83\u7f84\u7f85\u7f86\u7f87\u7f88\u7f89\u7f8a\u7f8b\u7f8c\u7f8d\u7f8e\u7f8f\u7f90\u7f91\u7f92\u7f93\u7f94\u7f95\u7f96\u7f97\u7f98\u7f99\u7f9a\u7f9b\u7f9c\u7f9d\u7f9e\u7f9f\u7fa0\u7fa1\u7fa2\u7fa3\u7fa4\u7fa5\u7fa6\u7fa7\u7fa8\u7fa9\u7faa\u7fab\u7fac\u7fad\u7fae\u7faf\u7fb0\u7fb1\u7fb2\u7fb3\u7fb4\u7fb5\u7fb6\u7fb7\u7fb8\u7fb9\u7fba\u7fbb\u7fbc\u7fbd\u7fbe\u7fbf\u7fc0\u7fc1\u7fc2\u7fc3\u7fc4\u7fc5\u7fc6\u7fc7\u7fc8\u7fc9\u7fca\u7fcb\u7fcc\u7fcd\u7fce\u7fcf\u7fd0\u7fd1\u7fd2\u7fd3\u7fd4\u7fd5\u7fd6\u7fd7\u7fd8\u7fd9\u7fda\u7fdb\u7fdc\u7fdd\u7fde\u7fdf\u7fe0\u7fe1\u7fe2\u7fe3\u7fe4\u7fe5\u7fe6\u7fe7\u7fe8\u7fe9\u7fea\u7feb\u7fec\u7fed\u7fee\u7fef\u7ff0\u7ff1\u7ff2\u7ff3\u7ff4\u7ff5\u7ff6\u7ff7\u7ff8\u7ff9\u7ffa\u7ffb\u7ffc\u7ffd\u7ffe\u7fff\u8000\u8001\u8002\u8003\u8004\u8005\u8006\u8007\u8008\u8009\u800a\u800b\u800c\u800d\u800e\u800f\u8010\u8011\u8012\u8013\u8014\u8015\u8016\u8017\u8018\u8019\u801a\u801b\u801c\u801d\u801e\u801f\u8020\u8021\u8022\u8023\u8024\u8025\u8026\u8027\u8028\u8029\u802a\u802b\u802c\u802d\u802e\u802f\u8030\u8031\u8032\u8033\u8034\u8035\u8036\u8037\u8038\u8039\u803a\u803b\u803c\u803d\u803e\u803f\u8040\u8041\u8042\u8043\u8044\u8045\u8046\u8047\u8048\u8049\u804a\u804b\u804c\u804d\u804e\u804f\u8050\u8051\u8052\u8053\u8054\u8055\u8056\u8057\u8058\u8059\u805a\u805b\u805c\u805d\u805e\u805f\u8060\u8061\u8062\u8063\u8064\u8065\u8066\u8067\u8068\u8069\u806a\u806b\u806c\u806d\u806e\u806f\u8070\u8071\u8072\u8073\u8074\u8075\u8076\u8077\u8078\u8079\u807a\u807b\u807c\u807d\u807e\u807f\u8080\u8081\u8082\u8083\u8084\u8085\u8086\u8087\u8088\u8089\u808a\u808b\u808c\u808d\u808e\u808f\u8090\u8091\u8092\u8093\u8094\u8095\u8096\u8097\u8098\u8099\u809a\u809b\u809c\u809d\u809e\u809f\u80a0\u80a1\u80a2\u80a3\u80a4\u80a5\u80a6\u80a7\u80a8\u80a9\u80aa\u80ab\u80ac\u80ad\u80ae\u80af\u80b0\u80b1\u80b2\u80b3\u80b4\u80b5\u80b6\u80b7\u80b8\u80b9\u80ba\u80bb\u80bc\u80bd\u80be\u80bf\u80c0\u80c1\u80c2\u80c3\u80c4\u80c5\u80c6\u80c7\u80c8\u80c9\u80ca\u80cb\u80cc\u80cd\u80ce\u80cf\u80d0\u80d1\u80d2\u80d3\u80d4\u80d5\u80d6\u80d7\u80d8\u80d9\u80da\u80db\u80dc\u80dd\u80de\u80df\u80e0\u80e1\u80e2\u80e3\u80e4\u80e5\u80e6\u80e7\u80e8\u80e9\u80ea\u80eb\u80ec\u80ed\u80ee\u80ef\u80f0\u80f1\u80f2\u80f3\u80f4\u80f5\u80f6\u80f7\u80f8\u80f9\u80fa\u80fb\u80fc\u80fd\u80fe\u80ff\u8100\u8101\u8102\u8103\u8104\u8105\u8106\u8107\u8108\u8109\u810a\u810b\u810c\u810d\u810e\u810f\u8110\u8111\u8112\u8113\u8114\u8115\u8116\u8117\u8118\u8119\u811a\u811b\u811c\u811d\u811e\u811f\u8120\u8121\u8122\u8123\u8124\u8125\u8126\u8127\u8128\u8129\u812a\u812b\u812c\u812d\u812e\u812f\u8130\u8131\u8132\u8133\u8134\u8135\u8136\u8137\u8138\u8139\u813a\u813b\u813c\u813d\u813e\u813f\u8140\u8141\u8142\u8143\u8144\u8145\u8146\u8147\u8148\u8149\u814a\u814b\u814c\u814d\u814e\u814f\u8150\u8151\u8152\u8153\u8154\u8155\u8156\u8157\u8158\u8159\u815a\u815b\u815c\u815d\u815e\u815f\u8160\u8161\u8162\u8163\u8164\u8165\u8166\u8167\u8168\u8169\u816a\u816b\u816c\u816d\u816e\u816f\u8170\u8171\u8172\u8173\u8174\u8175\u8176\u8177\u8178\u8179\u817a\u817b\u817c\u817d\u817e\u817f\u8180\u8181\u8182\u8183\u8184\u8185\u8186\u8187\u8188\u8189\u818a\u818b\u818c\u818d\u818e\u818f\u8190\u8191\u8192\u8193\u8194\u8195\u8196\u8197\u8198\u8199\u819a\u819b\u819c\u819d\u819e\u819f\u81a0\u81a1\u81a2\u81a3\u81a4\u81a5\u81a6\u81a7\u81a8\u81a9\u81aa\u81ab\u81ac\u81ad\u81ae\u81af\u81b0\u81b1\u81b2\u81b3\u81b4\u81b5\u81b6\u81b7\u81b8\u81b9\u81ba\u81bb\u81bc\u81bd\u81be\u81bf\u81c0\u81c1\u81c2\u81c3\u81c4\u81c5\u81c6\u81c7\u81c8\u81c9\u81ca\u81cb\u81cc\u81cd\u81ce\u81cf\u81d0\u81d1\u81d2\u81d3\u81d4\u81d5\u81d6\u81d7\u81d8\u81d9\u81da\u81db\u81dc\u81dd\u81de\u81df\u81e0\u81e1\u81e2\u81e3\u81e4\u81e5\u81e6\u81e7\u81e8\u81e9\u81ea\u81eb\u81ec\u81ed\u81ee\u81ef\u81f0\u81f1\u81f2\u81f3\u81f4\u81f5\u81f6\u81f7\u81f8\u81f9\u81fa\u81fb\u81fc\u81fd\u81fe\u81ff\u8200\u8201\u8202\u8203\u8204\u8205\u8206\u8207\u8208\u8209\u820a\u820b\u820c\u820d\u820e\u820f\u8210\u8211\u8212\u8213\u8214\u8215\u8216\u8217\u8218\u8219\u821a\u821b\u821c\u821d\u821e\u821f\u8220\u8221\u8222\u8223\u8224\u8225\u8226\u8227\u8228\u8229\u822a\u822b\u822c\u822d\u822e\u822f\u8230\u8231\u8232\u8233\u8234\u8235\u8236\u8237\u8238\u8239\u823a\u823b\u823c\u823d\u823e\u823f\u8240\u8241\u8242\u8243\u8244\u8245\u8246\u8247\u8248\u8249\u824a\u824b\u824c\u824d\u824e\u824f\u8250\u8251\u8252\u8253\u8254\u8255\u8256\u8257\u8258\u8259\u825a\u825b\u825c\u825d\u825e\u825f\u8260\u8261\u8262\u8263\u8264\u8265\u8266\u8267\u8268\u8269\u826a\u826b\u826c\u826d\u826e\u826f\u8270\u8271\u8272\u8273\u8274\u8275\u8276\u8277\u8278\u8279\u827a\u827b\u827c\u827d\u827e\u827f\u8280\u8281\u8282\u8283\u8284\u8285\u8286\u8287\u8288\u8289\u828a\u828b\u828c\u828d\u828e\u828f\u8290\u8291\u8292\u8293\u8294\u8295\u8296\u8297\u8298\u8299\u829a\u829b\u829c\u829d\u829e\u829f\u82a0\u82a1\u82a2\u82a3\u82a4\u82a5\u82a6\u82a7\u82a8\u82a9\u82aa\u82ab\u82ac\u82ad\u82ae\u82af\u82b0\u82b1\u82b2\u82b3\u82b4\u82b5\u82b6\u82b7\u82b8\u82b9\u82ba\u82bb\u82bc\u82bd\u82be\u82bf\u82c0\u82c1\u82c2\u82c3\u82c4\u82c5\u82c6\u82c7\u82c8\u82c9\u82ca\u82cb\u82cc\u82cd\u82ce\u82cf\u82d0\u82d1\u82d2\u82d3\u82d4\u82d5\u82d6\u82d7\u82d8\u82d9\u82da\u82db\u82dc\u82dd\u82de\u82df\u82e0\u82e1\u82e2\u82e3\u82e4\u82e5\u82e6\u82e7\u82e8\u82e9\u82ea\u82eb\u82ec\u82ed\u82ee\u82ef\u82f0\u82f1\u82f2\u82f3\u82f4\u82f5\u82f6\u82f7\u82f8\u82f9\u82fa\u82fb\u82fc\u82fd\u82fe\u82ff\u8300\u8301\u8302\u8303\u8304\u8305\u8306\u8307\u8308\u8309\u830a\u830b\u830c\u830d\u830e\u830f\u8310\u8311\u8312\u8313\u8314\u8315\u8316\u8317\u8318\u8319\u831a\u831b\u831c\u831d\u831e\u831f\u8320\u8321\u8322\u8323\u8324\u8325\u8326\u8327\u8328\u8329\u832a\u832b\u832c\u832d\u832e\u832f\u8330\u8331\u8332\u8333\u8334\u8335\u8336\u8337\u8338\u8339\u833a\u833b\u833c\u833d\u833e\u833f\u8340\u8341\u8342\u8343\u8344\u8345\u8346\u8347\u8348\u8349\u834a\u834b\u834c\u834d\u834e\u834f\u8350\u8351\u8352\u8353\u8354\u8355\u8356\u8357\u8358\u8359\u835a\u835b\u835c\u835d\u835e\u835f\u8360\u8361\u8362\u8363\u8364\u8365\u8366\u8367\u8368\u8369\u836a\u836b\u836c\u836d\u836e\u836f\u8370\u8371\u8372\u8373\u8374\u8375\u8376\u8377\u8378\u8379\u837a\u837b\u837c\u837d\u837e\u837f\u8380\u8381\u8382\u8383\u8384\u8385\u8386\u8387\u8388\u8389\u838a\u838b\u838c\u838d\u838e\u838f\u8390\u8391\u8392\u8393\u8394\u8395\u8396\u8397\u8398\u8399\u839a\u839b\u839c\u839d\u839e\u839f\u83a0\u83a1\u83a2\u83a3\u83a4\u83a5\u83a6\u83a7\u83a8\u83a9\u83aa\u83ab\u83ac\u83ad\u83ae\u83af\u83b0\u83b1\u83b2\u83b3\u83b4\u83b5\u83b6\u83b7\u83b8\u83b9\u83ba\u83bb\u83bc\u83bd\u83be\u83bf\u83c0\u83c1\u83c2\u83c3\u83c4\u83c5\u83c6\u83c7\u83c8\u83c9\u83ca\u83cb\u83cc\u83cd\u83ce\u83cf\u83d0\u83d1\u83d2\u83d3\u83d4\u83d5\u83d6\u83d7\u83d8\u83d9\u83da\u83db\u83dc\u83dd\u83de\u83df\u83e0\u83e1\u83e2\u83e3\u83e4\u83e5\u83e6\u83e7\u83e8\u83e9\u83ea\u83eb\u83ec\u83ed\u83ee\u83ef\u83f0\u83f1\u83f2\u83f3\u83f4\u83f5\u83f6\u83f7\u83f8\u83f9\u83fa\u83fb\u83fc\u83fd\u83fe\u83ff\u8400\u8401\u8402\u8403\u8404\u8405\u8406\u8407\u8408\u8409\u840a\u840b\u840c\u840d\u840e\u840f\u8410\u8411\u8412\u8413\u8414\u8415\u8416\u8417\u8418\u8419\u841a\u841b\u841c\u841d\u841e\u841f\u8420\u8421\u8422\u8423\u8424\u8425\u8426\u8427\u8428\u8429\u842a\u842b\u842c\u842d\u842e\u842f\u8430\u8431\u8432\u8433\u8434\u8435\u8436\u8437\u8438\u8439\u843a\u843b\u843c\u843d\u843e\u843f\u8440\u8441\u8442\u8443\u8444\u8445\u8446\u8447\u8448\u8449\u844a\u844b\u844c\u844d\u844e\u844f\u8450\u8451\u8452\u8453\u8454\u8455\u8456\u8457\u8458\u8459\u845a\u845b\u845c\u845d\u845e\u845f\u8460\u8461\u8462\u8463\u8464\u8465\u8466\u8467\u8468\u8469\u846a\u846b\u846c\u846d\u846e\u846f\u8470\u8471\u8472\u8473\u8474\u8475\u8476\u8477\u8478\u8479\u847a\u847b\u847c\u847d\u847e\u847f\u8480\u8481\u8482\u8483\u8484\u8485\u8486\u8487\u8488\u8489\u848a\u848b\u848c\u848d\u848e\u848f\u8490\u8491\u8492\u8493\u8494\u8495\u8496\u8497\u8498\u8499\u849a\u849b\u849c\u849d\u849e\u849f\u84a0\u84a1\u84a2\u84a3\u84a4\u84a5\u84a6\u84a7\u84a8\u84a9\u84aa\u84ab\u84ac\u84ad\u84ae\u84af\u84b0\u84b1\u84b2\u84b3\u84b4\u84b5\u84b6\u84b7\u84b8\u84b9\u84ba\u84bb\u84bc\u84bd\u84be\u84bf\u84c0\u84c1\u84c2\u84c3\u84c4\u84c5\u84c6\u84c7\u84c8\u84c9\u84ca\u84cb\u84cc\u84cd\u84ce\u84cf\u84d0\u84d1\u84d2\u84d3\u84d4\u84d5\u84d6\u84d7\u84d8\u84d9\u84da\u84db\u84dc\u84dd\u84de\u84df\u84e0\u84e1\u84e2\u84e3\u84e4\u84e5\u84e6\u84e7\u84e8\u84e9\u84ea\u84eb\u84ec\u84ed\u84ee\u84ef\u84f0\u84f1\u84f2\u84f3\u84f4\u84f5\u84f6\u84f7\u84f8\u84f9\u84fa\u84fb\u84fc\u84fd\u84fe\u84ff\u8500\u8501\u8502\u8503\u8504\u8505\u8506\u8507\u8508\u8509\u850a\u850b\u850c\u850d\u850e\u850f\u8510\u8511\u8512\u8513\u8514\u8515\u8516\u8517\u8518\u8519\u851a\u851b\u851c\u851d\u851e\u851f\u8520\u8521\u8522\u8523\u8524\u8525\u8526\u8527\u8528\u8529\u852a\u852b\u852c\u852d\u852e\u852f\u8530\u8531\u8532\u8533\u8534\u8535\u8536\u8537\u8538\u8539\u853a\u853b\u853c\u853d\u853e\u853f\u8540\u8541\u8542\u8543\u8544\u8545\u8546\u8547\u8548\u8549\u854a\u854b\u854c\u854d\u854e\u854f\u8550\u8551\u8552\u8553\u8554\u8555\u8556\u8557\u8558\u8559\u855a\u855b\u855c\u855d\u855e\u855f\u8560\u8561\u8562\u8563\u8564\u8565\u8566\u8567\u8568\u8569\u856a\u856b\u856c\u856d\u856e\u856f\u8570\u8571\u8572\u8573\u8574\u8575\u8576\u8577\u8578\u8579\u857a\u857b\u857c\u857d\u857e\u857f\u8580\u8581\u8582\u8583\u8584\u8585\u8586\u8587\u8588\u8589\u858a\u858b\u858c\u858d\u858e\u858f\u8590\u8591\u8592\u8593\u8594\u8595\u8596\u8597\u8598\u8599\u859a\u859b\u859c\u859d\u859e\u859f\u85a0\u85a1\u85a2\u85a3\u85a4\u85a5\u85a6\u85a7\u85a8\u85a9\u85aa\u85ab\u85ac\u85ad\u85ae\u85af\u85b0\u85b1\u85b2\u85b3\u85b4\u85b5\u85b6\u85b7\u85b8\u85b9\u85ba\u85bb\u85bc\u85bd\u85be\u85bf\u85c0\u85c1\u85c2\u85c3\u85c4\u85c5\u85c6\u85c7\u85c8\u85c9\u85ca\u85cb\u85cc\u85cd\u85ce\u85cf\u85d0\u85d1\u85d2\u85d3\u85d4\u85d5\u85d6\u85d7\u85d8\u85d9\u85da\u85db\u85dc\u85dd\u85de\u85df\u85e0\u85e1\u85e2\u85e3\u85e4\u85e5\u85e6\u85e7\u85e8\u85e9\u85ea\u85eb\u85ec\u85ed\u85ee\u85ef\u85f0\u85f1\u85f2\u85f3\u85f4\u85f5\u85f6\u85f7\u85f8\u85f9\u85fa\u85fb\u85fc\u85fd\u85fe\u85ff\u8600\u8601\u8602\u8603\u8604\u8605\u8606\u8607\u8608\u8609\u860a\u860b\u860c\u860d\u860e\u860f\u8610\u8611\u8612\u8613\u8614\u8615\u8616\u8617\u8618\u8619\u861a\u861b\u861c\u861d\u861e\u861f\u8620\u8621\u8622\u8623\u8624\u8625\u8626\u8627\u8628\u8629\u862a\u862b\u862c\u862d\u862e\u862f\u8630\u8631\u8632\u8633\u8634\u8635\u8636\u8637\u8638\u8639\u863a\u863b\u863c\u863d\u863e\u863f\u8640\u8641\u8642\u8643\u8644\u8645\u8646\u8647\u8648\u8649\u864a\u864b\u864c\u864d\u864e\u864f\u8650\u8651\u8652\u8653\u8654\u8655\u8656\u8657\u8658\u8659\u865a\u865b\u865c\u865d\u865e\u865f\u8660\u8661\u8662\u8663\u8664\u8665\u8666\u8667\u8668\u8669\u866a\u866b\u866c\u866d\u866e\u866f\u8670\u8671\u8672\u8673\u8674\u8675\u8676\u8677\u8678\u8679\u867a\u867b\u867c\u867d\u867e\u867f\u8680\u8681\u8682\u8683\u8684\u8685\u8686\u8687\u8688\u8689\u868a\u868b\u868c\u868d\u868e\u868f\u8690\u8691\u8692\u8693\u8694\u8695\u8696\u8697\u8698\u8699\u869a\u869b\u869c\u869d\u869e\u869f\u86a0\u86a1\u86a2\u86a3\u86a4\u86a5\u86a6\u86a7\u86a8\u86a9\u86aa\u86ab\u86ac\u86ad\u86ae\u86af\u86b0\u86b1\u86b2\u86b3\u86b4\u86b5\u86b6\u86b7\u86b8\u86b9\u86ba\u86bb\u86bc\u86bd\u86be\u86bf\u86c0\u86c1\u86c2\u86c3\u86c4\u86c5\u86c6\u86c7\u86c8\u86c9\u86ca\u86cb\u86cc\u86cd\u86ce\u86cf\u86d0\u86d1\u86d2\u86d3\u86d4\u86d5\u86d6\u86d7\u86d8\u86d9\u86da\u86db\u86dc\u86dd\u86de\u86df\u86e0\u86e1\u86e2\u86e3\u86e4\u86e5\u86e6\u86e7\u86e8\u86e9\u86ea\u86eb\u86ec\u86ed\u86ee\u86ef\u86f0\u86f1\u86f2\u86f3\u86f4\u86f5\u86f6\u86f7\u86f8\u86f9\u86fa\u86fb\u86fc\u86fd\u86fe\u86ff\u8700\u8701\u8702\u8703\u8704\u8705\u8706\u8707\u8708\u8709\u870a\u870b\u870c\u870d\u870e\u870f\u8710\u8711\u8712\u8713\u8714\u8715\u8716\u8717\u8718\u8719\u871a\u871b\u871c\u871d\u871e\u871f\u8720\u8721\u8722\u8723\u8724\u8725\u8726\u8727\u8728\u8729\u872a\u872b\u872c\u872d\u872e\u872f\u8730\u8731\u8732\u8733\u8734\u8735\u8736\u8737\u8738\u8739\u873a\u873b\u873c\u873d\u873e\u873f\u8740\u8741\u8742\u8743\u8744\u8745\u8746\u8747\u8748\u8749\u874a\u874b\u874c\u874d\u874e\u874f\u8750\u8751\u8752\u8753\u8754\u8755\u8756\u8757\u8758\u8759\u875a\u875b\u875c\u875d\u875e\u875f\u8760\u8761\u8762\u8763\u8764\u8765\u8766\u8767\u8768\u8769\u876a\u876b\u876c\u876d\u876e\u876f\u8770\u8771\u8772\u8773\u8774\u8775\u8776\u8777\u8778\u8779\u877a\u877b\u877c\u877d\u877e\u877f\u8780\u8781\u8782\u8783\u8784\u8785\u8786\u8787\u8788\u8789\u878a\u878b\u878c\u878d\u878e\u878f\u8790\u8791\u8792\u8793\u8794\u8795\u8796\u8797\u8798\u8799\u879a\u879b\u879c\u879d\u879e\u879f\u87a0\u87a1\u87a2\u87a3\u87a4\u87a5\u87a6\u87a7\u87a8\u87a9\u87aa\u87ab\u87ac\u87ad\u87ae\u87af\u87b0\u87b1\u87b2\u87b3\u87b4\u87b5\u87b6\u87b7\u87b8\u87b9\u87ba\u87bb\u87bc\u87bd\u87be\u87bf\u87c0\u87c1\u87c2\u87c3\u87c4\u87c5\u87c6\u87c7\u87c8\u87c9\u87ca\u87cb\u87cc\u87cd\u87ce\u87cf\u87d0\u87d1\u87d2\u87d3\u87d4\u87d5\u87d6\u87d7\u87d8\u87d9\u87da\u87db\u87dc\u87dd\u87de\u87df\u87e0\u87e1\u87e2\u87e3\u87e4\u87e5\u87e6\u87e7\u87e8\u87e9\u87ea\u87eb\u87ec\u87ed\u87ee\u87ef\u87f0\u87f1\u87f2\u87f3\u87f4\u87f5\u87f6\u87f7\u87f8\u87f9\u87fa\u87fb\u87fc\u87fd\u87fe\u87ff\u8800\u8801\u8802\u8803\u8804\u8805\u8806\u8807\u8808\u8809\u880a\u880b\u880c\u880d\u880e\u880f\u8810\u8811\u8812\u8813\u8814\u8815\u8816\u8817\u8818\u8819\u881a\u881b\u881c\u881d\u881e\u881f\u8820\u8821\u8822\u8823\u8824\u8825\u8826\u8827\u8828\u8829\u882a\u882b\u882c\u882d\u882e\u882f\u8830\u8831\u8832\u8833\u8834\u8835\u8836\u8837\u8838\u8839\u883a\u883b\u883c\u883d\u883e\u883f\u8840\u8841\u8842\u8843\u8844\u8845\u8846\u8847\u8848\u8849\u884a\u884b\u884c\u884d\u884e\u884f\u8850\u8851\u8852\u8853\u8854\u8855\u8856\u8857\u8858\u8859\u885a\u885b\u885c\u885d\u885e\u885f\u8860\u8861\u8862\u8863\u8864\u8865\u8866\u8867\u8868\u8869\u886a\u886b\u886c\u886d\u886e\u886f\u8870\u8871\u8872\u8873\u8874\u8875\u8876\u8877\u8878\u8879\u887a\u887b\u887c\u887d\u887e\u887f\u8880\u8881\u8882\u8883\u8884\u8885\u8886\u8887\u8888\u8889\u888a\u888b\u888c\u888d\u888e\u888f\u8890\u8891\u8892\u8893\u8894\u8895\u8896\u8897\u8898\u8899\u889a\u889b\u889c\u889d\u889e\u889f\u88a0\u88a1\u88a2\u88a3\u88a4\u88a5\u88a6\u88a7\u88a8\u88a9\u88aa\u88ab\u88ac\u88ad\u88ae\u88af\u88b0\u88b1\u88b2\u88b3\u88b4\u88b5\u88b6\u88b7\u88b8\u88b9\u88ba\u88bb\u88bc\u88bd\u88be\u88bf\u88c0\u88c1\u88c2\u88c3\u88c4\u88c5\u88c6\u88c7\u88c8\u88c9\u88ca\u88cb\u88cc\u88cd\u88ce\u88cf\u88d0\u88d1\u88d2\u88d3\u88d4\u88d5\u88d6\u88d7\u88d8\u88d9\u88da\u88db\u88dc\u88dd\u88de\u88df\u88e0\u88e1\u88e2\u88e3\u88e4\u88e5\u88e6\u88e7\u88e8\u88e9\u88ea\u88eb\u88ec\u88ed\u88ee\u88ef\u88f0\u88f1\u88f2\u88f3\u88f4\u88f5\u88f6\u88f7\u88f8\u88f9\u88fa\u88fb\u88fc\u88fd\u88fe\u88ff\u8900\u8901\u8902\u8903\u8904\u8905\u8906\u8907\u8908\u8909\u890a\u890b\u890c\u890d\u890e\u890f\u8910\u8911\u8912\u8913\u8914\u8915\u8916\u8917\u8918\u8919\u891a\u891b\u891c\u891d\u891e\u891f\u8920\u8921\u8922\u8923\u8924\u8925\u8926\u8927\u8928\u8929\u892a\u892b\u892c\u892d\u892e\u892f\u8930\u8931\u8932\u8933\u8934\u8935\u8936\u8937\u8938\u8939\u893a\u893b\u893c\u893d\u893e\u893f\u8940\u8941\u8942\u8943\u8944\u8945\u8946\u8947\u8948\u8949\u894a\u894b\u894c\u894d\u894e\u894f\u8950\u8951\u8952\u8953\u8954\u8955\u8956\u8957\u8958\u8959\u895a\u895b\u895c\u895d\u895e\u895f\u8960\u8961\u8962\u8963\u8964\u8965\u8966\u8967\u8968\u8969\u896a\u896b\u896c\u896d\u896e\u896f\u8970\u8971\u8972\u8973\u8974\u8975\u8976\u8977\u8978\u8979\u897a\u897b\u897c\u897d\u897e\u897f\u8980\u8981\u8982\u8983\u8984\u8985\u8986\u8987\u8988\u8989\u898a\u898b\u898c\u898d\u898e\u898f\u8990\u8991\u8992\u8993\u8994\u8995\u8996\u8997\u8998\u8999\u899a\u899b\u899c\u899d\u899e\u899f\u89a0\u89a1\u89a2\u89a3\u89a4\u89a5\u89a6\u89a7\u89a8\u89a9\u89aa\u89ab\u89ac\u89ad\u89ae\u89af\u89b0\u89b1\u89b2\u89b3\u89b4\u89b5\u89b6\u89b7\u89b8\u89b9\u89ba\u89bb\u89bc\u89bd\u89be\u89bf\u89c0\u89c1\u89c2\u89c3\u89c4\u89c5\u89c6\u89c7\u89c8\u89c9\u89ca\u89cb\u89cc\u89cd\u89ce\u89cf\u89d0\u89d1\u89d2\u89d3\u89d4\u89d5\u89d6\u89d7\u89d8\u89d9\u89da\u89db\u89dc\u89dd\u89de\u89df\u89e0\u89e1\u89e2\u89e3\u89e4\u89e5\u89e6\u89e7\u89e8\u89e9\u89ea\u89eb\u89ec\u89ed\u89ee\u89ef\u89f0\u89f1\u89f2\u89f3\u89f4\u89f5\u89f6\u89f7\u89f8\u89f9\u89fa\u89fb\u89fc\u89fd\u89fe\u89ff\u8a00\u8a01\u8a02\u8a03\u8a04\u8a05\u8a06\u8a07\u8a08\u8a09\u8a0a\u8a0b\u8a0c\u8a0d\u8a0e\u8a0f\u8a10\u8a11\u8a12\u8a13\u8a14\u8a15\u8a16\u8a17\u8a18\u8a19\u8a1a\u8a1b\u8a1c\u8a1d\u8a1e\u8a1f\u8a20\u8a21\u8a22\u8a23\u8a24\u8a25\u8a26\u8a27\u8a28\u8a29\u8a2a\u8a2b\u8a2c\u8a2d\u8a2e\u8a2f\u8a30\u8a31\u8a32\u8a33\u8a34\u8a35\u8a36\u8a37\u8a38\u8a39\u8a3a\u8a3b\u8a3c\u8a3d\u8a3e\u8a3f\u8a40\u8a41\u8a42\u8a43\u8a44\u8a45\u8a46\u8a47\u8a48\u8a49\u8a4a\u8a4b\u8a4c\u8a4d\u8a4e\u8a4f\u8a50\u8a51\u8a52\u8a53\u8a54\u8a55\u8a56\u8a57\u8a58\u8a59\u8a5a\u8a5b\u8a5c\u8a5d\u8a5e\u8a5f\u8a60\u8a61\u8a62\u8a63\u8a64\u8a65\u8a66\u8a67\u8a68\u8a69\u8a6a\u8a6b\u8a6c\u8a6d\u8a6e\u8a6f\u8a70\u8a71\u8a72\u8a73\u8a74\u8a75\u8a76\u8a77\u8a78\u8a79\u8a7a\u8a7b\u8a7c\u8a7d\u8a7e\u8a7f\u8a80\u8a81\u8a82\u8a83\u8a84\u8a85\u8a86\u8a87\u8a88\u8a89\u8a8a\u8a8b\u8a8c\u8a8d\u8a8e\u8a8f\u8a90\u8a91\u8a92\u8a93\u8a94\u8a95\u8a96\u8a97\u8a98\u8a99\u8a9a\u8a9b\u8a9c\u8a9d\u8a9e\u8a9f\u8aa0\u8aa1\u8aa2\u8aa3\u8aa4\u8aa5\u8aa6\u8aa7\u8aa8\u8aa9\u8aaa\u8aab\u8aac\u8aad\u8aae\u8aaf\u8ab0\u8ab1\u8ab2\u8ab3\u8ab4\u8ab5\u8ab6\u8ab7\u8ab8\u8ab9\u8aba\u8abb\u8abc\u8abd\u8abe\u8abf\u8ac0\u8ac1\u8ac2\u8ac3\u8ac4\u8ac5\u8ac6\u8ac7\u8ac8\u8ac9\u8aca\u8acb\u8acc\u8acd\u8ace\u8acf\u8ad0\u8ad1\u8ad2\u8ad3\u8ad4\u8ad5\u8ad6\u8ad7\u8ad8\u8ad9\u8ada\u8adb\u8adc\u8add\u8ade\u8adf\u8ae0\u8ae1\u8ae2\u8ae3\u8ae4\u8ae5\u8ae6\u8ae7\u8ae8\u8ae9\u8aea\u8aeb\u8aec\u8aed\u8aee\u8aef\u8af0\u8af1\u8af2\u8af3\u8af4\u8af5\u8af6\u8af7\u8af8\u8af9\u8afa\u8afb\u8afc\u8afd\u8afe\u8aff\u8b00\u8b01\u8b02\u8b03\u8b04\u8b05\u8b06\u8b07\u8b08\u8b09\u8b0a\u8b0b\u8b0c\u8b0d\u8b0e\u8b0f\u8b10\u8b11\u8b12\u8b13\u8b14\u8b15\u8b16\u8b17\u8b18\u8b19\u8b1a\u8b1b\u8b1c\u8b1d\u8b1e\u8b1f\u8b20\u8b21\u8b22\u8b23\u8b24\u8b25\u8b26\u8b27\u8b28\u8b29\u8b2a\u8b2b\u8b2c\u8b2d\u8b2e\u8b2f\u8b30\u8b31\u8b32\u8b33\u8b34\u8b35\u8b36\u8b37\u8b38\u8b39\u8b3a\u8b3b\u8b3c\u8b3d\u8b3e\u8b3f\u8b40\u8b41\u8b42\u8b43\u8b44\u8b45\u8b46\u8b47\u8b48\u8b49\u8b4a\u8b4b\u8b4c\u8b4d\u8b4e\u8b4f\u8b50\u8b51\u8b52\u8b53\u8b54\u8b55\u8b56\u8b57\u8b58\u8b59\u8b5a\u8b5b\u8b5c\u8b5d\u8b5e\u8b5f\u8b60\u8b61\u8b62\u8b63\u8b64\u8b65\u8b66\u8b67\u8b68\u8b69\u8b6a\u8b6b\u8b6c\u8b6d\u8b6e\u8b6f\u8b70\u8b71\u8b72\u8b73\u8b74\u8b75\u8b76\u8b77\u8b78\u8b79\u8b7a\u8b7b\u8b7c\u8b7d\u8b7e\u8b7f\u8b80\u8b81\u8b82\u8b83\u8b84\u8b85\u8b86\u8b87\u8b88\u8b89\u8b8a\u8b8b\u8b8c\u8b8d\u8b8e\u8b8f\u8b90\u8b91\u8b92\u8b93\u8b94\u8b95\u8b96\u8b97\u8b98\u8b99\u8b9a\u8b9b\u8b9c\u8b9d\u8b9e\u8b9f\u8ba0\u8ba1\u8ba2\u8ba3\u8ba4\u8ba5\u8ba6\u8ba7\u8ba8\u8ba9\u8baa\u8bab\u8bac\u8bad\u8bae\u8baf\u8bb0\u8bb1\u8bb2\u8bb3\u8bb4\u8bb5\u8bb6\u8bb7\u8bb8\u8bb9\u8bba\u8bbb\u8bbc\u8bbd\u8bbe\u8bbf\u8bc0\u8bc1\u8bc2\u8bc3\u8bc4\u8bc5\u8bc6\u8bc7\u8bc8\u8bc9\u8bca\u8bcb\u8bcc\u8bcd\u8bce\u8bcf\u8bd0\u8bd1\u8bd2\u8bd3\u8bd4\u8bd5\u8bd6\u8bd7\u8bd8\u8bd9\u8bda\u8bdb\u8bdc\u8bdd\u8bde\u8bdf\u8be0\u8be1\u8be2\u8be3\u8be4\u8be5\u8be6\u8be7\u8be8\u8be9\u8bea\u8beb\u8bec\u8bed\u8bee\u8bef\u8bf0\u8bf1\u8bf2\u8bf3\u8bf4\u8bf5\u8bf6\u8bf7\u8bf8\u8bf9\u8bfa\u8bfb\u8bfc\u8bfd\u8bfe\u8bff\u8c00\u8c01\u8c02\u8c03\u8c04\u8c05\u8c06\u8c07\u8c08\u8c09\u8c0a\u8c0b\u8c0c\u8c0d\u8c0e\u8c0f\u8c10\u8c11\u8c12\u8c13\u8c14\u8c15\u8c16\u8c17\u8c18\u8c19\u8c1a\u8c1b\u8c1c\u8c1d\u8c1e\u8c1f\u8c20\u8c21\u8c22\u8c23\u8c24\u8c25\u8c26\u8c27\u8c28\u8c29\u8c2a\u8c2b\u8c2c\u8c2d\u8c2e\u8c2f\u8c30\u8c31\u8c32\u8c33\u8c34\u8c35\u8c36\u8c37\u8c38\u8c39\u8c3a\u8c3b\u8c3c\u8c3d\u8c3e\u8c3f\u8c40\u8c41\u8c42\u8c43\u8c44\u8c45\u8c46\u8c47\u8c48\u8c49\u8c4a\u8c4b\u8c4c\u8c4d\u8c4e\u8c4f\u8c50\u8c51\u8c52\u8c53\u8c54\u8c55\u8c56\u8c57\u8c58\u8c59\u8c5a\u8c5b\u8c5c\u8c5d\u8c5e\u8c5f\u8c60\u8c61\u8c62\u8c63\u8c64\u8c65\u8c66\u8c67\u8c68\u8c69\u8c6a\u8c6b\u8c6c\u8c6d\u8c6e\u8c6f\u8c70\u8c71\u8c72\u8c73\u8c74\u8c75\u8c76\u8c77\u8c78\u8c79\u8c7a\u8c7b\u8c7c\u8c7d\u8c7e\u8c7f\u8c80\u8c81\u8c82\u8c83\u8c84\u8c85\u8c86\u8c87\u8c88\u8c89\u8c8a\u8c8b\u8c8c\u8c8d\u8c8e\u8c8f\u8c90\u8c91\u8c92\u8c93\u8c94\u8c95\u8c96\u8c97\u8c98\u8c99\u8c9a\u8c9b\u8c9c\u8c9d\u8c9e\u8c9f\u8ca0\u8ca1\u8ca2\u8ca3\u8ca4\u8ca5\u8ca6\u8ca7\u8ca8\u8ca9\u8caa\u8cab\u8cac\u8cad\u8cae\u8caf\u8cb0\u8cb1\u8cb2\u8cb3\u8cb4\u8cb5\u8cb6\u8cb7\u8cb8\u8cb9\u8cba\u8cbb\u8cbc\u8cbd\u8cbe\u8cbf\u8cc0\u8cc1\u8cc2\u8cc3\u8cc4\u8cc5\u8cc6\u8cc7\u8cc8\u8cc9\u8cca\u8ccb\u8ccc\u8ccd\u8cce\u8ccf\u8cd0\u8cd1\u8cd2\u8cd3\u8cd4\u8cd5\u8cd6\u8cd7\u8cd8\u8cd9\u8cda\u8cdb\u8cdc\u8cdd\u8cde\u8cdf\u8ce0\u8ce1\u8ce2\u8ce3\u8ce4\u8ce5\u8ce6\u8ce7\u8ce8\u8ce9\u8cea\u8ceb\u8cec\u8ced\u8cee\u8cef\u8cf0\u8cf1\u8cf2\u8cf3\u8cf4\u8cf5\u8cf6\u8cf7\u8cf8\u8cf9\u8cfa\u8cfb\u8cfc\u8cfd\u8cfe\u8cff\u8d00\u8d01\u8d02\u8d03\u8d04\u8d05\u8d06\u8d07\u8d08\u8d09\u8d0a\u8d0b\u8d0c\u8d0d\u8d0e\u8d0f\u8d10\u8d11\u8d12\u8d13\u8d14\u8d15\u8d16\u8d17\u8d18\u8d19\u8d1a\u8d1b\u8d1c\u8d1d\u8d1e\u8d1f\u8d20\u8d21\u8d22\u8d23\u8d24\u8d25\u8d26\u8d27\u8d28\u8d29\u8d2a\u8d2b\u8d2c\u8d2d\u8d2e\u8d2f\u8d30\u8d31\u8d32\u8d33\u8d34\u8d35\u8d36\u8d37\u8d38\u8d39\u8d3a\u8d3b\u8d3c\u8d3d\u8d3e\u8d3f\u8d40\u8d41\u8d42\u8d43\u8d44\u8d45\u8d46\u8d47\u8d48\u8d49\u8d4a\u8d4b\u8d4c\u8d4d\u8d4e\u8d4f\u8d50\u8d51\u8d52\u8d53\u8d54\u8d55\u8d56\u8d57\u8d58\u8d59\u8d5a\u8d5b\u8d5c\u8d5d\u8d5e\u8d5f\u8d60\u8d61\u8d62\u8d63\u8d64\u8d65\u8d66\u8d67\u8d68\u8d69\u8d6a\u8d6b\u8d6c\u8d6d\u8d6e\u8d6f\u8d70\u8d71\u8d72\u8d73\u8d74\u8d75\u8d76\u8d77\u8d78\u8d79\u8d7a\u8d7b\u8d7c\u8d7d\u8d7e\u8d7f\u8d80\u8d81\u8d82\u8d83\u8d84\u8d85\u8d86\u8d87\u8d88\u8d89\u8d8a\u8d8b\u8d8c\u8d8d\u8d8e\u8d8f\u8d90\u8d91\u8d92\u8d93\u8d94\u8d95\u8d96\u8d97\u8d98\u8d99\u8d9a\u8d9b\u8d9c\u8d9d\u8d9e\u8d9f\u8da0\u8da1\u8da2\u8da3\u8da4\u8da5\u8da6\u8da7\u8da8\u8da9\u8daa\u8dab\u8dac\u8dad\u8dae\u8daf\u8db0\u8db1\u8db2\u8db3\u8db4\u8db5\u8db6\u8db7\u8db8\u8db9\u8dba\u8dbb\u8dbc\u8dbd\u8dbe\u8dbf\u8dc0\u8dc1\u8dc2\u8dc3\u8dc4\u8dc5\u8dc6\u8dc7\u8dc8\u8dc9\u8dca\u8dcb\u8dcc\u8dcd\u8dce\u8dcf\u8dd0\u8dd1\u8dd2\u8dd3\u8dd4\u8dd5\u8dd6\u8dd7\u8dd8\u8dd9\u8dda\u8ddb\u8ddc\u8ddd\u8dde\u8ddf\u8de0\u8de1\u8de2\u8de3\u8de4\u8de5\u8de6\u8de7\u8de8\u8de9\u8dea\u8deb\u8dec\u8ded\u8dee\u8def\u8df0\u8df1\u8df2\u8df3\u8df4\u8df5\u8df6\u8df7\u8df8\u8df9\u8dfa\u8dfb\u8dfc\u8dfd\u8dfe\u8dff\u8e00\u8e01\u8e02\u8e03\u8e04\u8e05\u8e06\u8e07\u8e08\u8e09\u8e0a\u8e0b\u8e0c\u8e0d\u8e0e\u8e0f\u8e10\u8e11\u8e12\u8e13\u8e14\u8e15\u8e16\u8e17\u8e18\u8e19\u8e1a\u8e1b\u8e1c\u8e1d\u8e1e\u8e1f\u8e20\u8e21\u8e22\u8e23\u8e24\u8e25\u8e26\u8e27\u8e28\u8e29\u8e2a\u8e2b\u8e2c\u8e2d\u8e2e\u8e2f\u8e30\u8e31\u8e32\u8e33\u8e34\u8e35\u8e36\u8e37\u8e38\u8e39\u8e3a\u8e3b\u8e3c\u8e3d\u8e3e\u8e3f\u8e40\u8e41\u8e42\u8e43\u8e44\u8e45\u8e46\u8e47\u8e48\u8e49\u8e4a\u8e4b\u8e4c\u8e4d\u8e4e\u8e4f\u8e50\u8e51\u8e52\u8e53\u8e54\u8e55\u8e56\u8e57\u8e58\u8e59\u8e5a\u8e5b\u8e5c\u8e5d\u8e5e\u8e5f\u8e60\u8e61\u8e62\u8e63\u8e64\u8e65\u8e66\u8e67\u8e68\u8e69\u8e6a\u8e6b\u8e6c\u8e6d\u8e6e\u8e6f\u8e70\u8e71\u8e72\u8e73\u8e74\u8e75\u8e76\u8e77\u8e78\u8e79\u8e7a\u8e7b\u8e7c\u8e7d\u8e7e\u8e7f\u8e80\u8e81\u8e82\u8e83\u8e84\u8e85\u8e86\u8e87\u8e88\u8e89\u8e8a\u8e8b\u8e8c\u8e8d\u8e8e\u8e8f\u8e90\u8e91\u8e92\u8e93\u8e94\u8e95\u8e96\u8e97\u8e98\u8e99\u8e9a\u8e9b\u8e9c\u8e9d\u8e9e\u8e9f\u8ea0\u8ea1\u8ea2\u8ea3\u8ea4\u8ea5\u8ea6\u8ea7\u8ea8\u8ea9\u8eaa\u8eab\u8eac\u8ead\u8eae\u8eaf\u8eb0\u8eb1\u8eb2\u8eb3\u8eb4\u8eb5\u8eb6\u8eb7\u8eb8\u8eb9\u8eba\u8ebb\u8ebc\u8ebd\u8ebe\u8ebf\u8ec0\u8ec1\u8ec2\u8ec3\u8ec4\u8ec5\u8ec6\u8ec7\u8ec8\u8ec9\u8eca\u8ecb\u8ecc\u8ecd\u8ece\u8ecf\u8ed0\u8ed1\u8ed2\u8ed3\u8ed4\u8ed5\u8ed6\u8ed7\u8ed8\u8ed9\u8eda\u8edb\u8edc\u8edd\u8ede\u8edf\u8ee0\u8ee1\u8ee2\u8ee3\u8ee4\u8ee5\u8ee6\u8ee7\u8ee8\u8ee9\u8eea\u8eeb\u8eec\u8eed\u8eee\u8eef\u8ef0\u8ef1\u8ef2\u8ef3\u8ef4\u8ef5\u8ef6\u8ef7\u8ef8\u8ef9\u8efa\u8efb\u8efc\u8efd\u8efe\u8eff\u8f00\u8f01\u8f02\u8f03\u8f04\u8f05\u8f06\u8f07\u8f08\u8f09\u8f0a\u8f0b\u8f0c\u8f0d\u8f0e\u8f0f\u8f10\u8f11\u8f12\u8f13\u8f14\u8f15\u8f16\u8f17\u8f18\u8f19\u8f1a\u8f1b\u8f1c\u8f1d\u8f1e\u8f1f\u8f20\u8f21\u8f22\u8f23\u8f24\u8f25\u8f26\u8f27\u8f28\u8f29\u8f2a\u8f2b\u8f2c\u8f2d\u8f2e\u8f2f\u8f30\u8f31\u8f32\u8f33\u8f34\u8f35\u8f36\u8f37\u8f38\u8f39\u8f3a\u8f3b\u8f3c\u8f3d\u8f3e\u8f3f\u8f40\u8f41\u8f42\u8f43\u8f44\u8f45\u8f46\u8f47\u8f48\u8f49\u8f4a\u8f4b\u8f4c\u8f4d\u8f4e\u8f4f\u8f50\u8f51\u8f52\u8f53\u8f54\u8f55\u8f56\u8f57\u8f58\u8f59\u8f5a\u8f5b\u8f5c\u8f5d\u8f5e\u8f5f\u8f60\u8f61\u8f62\u8f63\u8f64\u8f65\u8f66\u8f67\u8f68\u8f69\u8f6a\u8f6b\u8f6c\u8f6d\u8f6e\u8f6f\u8f70\u8f71\u8f72\u8f73\u8f74\u8f75\u8f76\u8f77\u8f78\u8f79\u8f7a\u8f7b\u8f7c\u8f7d\u8f7e\u8f7f\u8f80\u8f81\u8f82\u8f83\u8f84\u8f85\u8f86\u8f87\u8f88\u8f89\u8f8a\u8f8b\u8f8c\u8f8d\u8f8e\u8f8f\u8f90\u8f91\u8f92\u8f93\u8f94\u8f95\u8f96\u8f97\u8f98\u8f99\u8f9a\u8f9b\u8f9c\u8f9d\u8f9e\u8f9f\u8fa0\u8fa1\u8fa2\u8fa3\u8fa4\u8fa5\u8fa6\u8fa7\u8fa8\u8fa9\u8faa\u8fab\u8fac\u8fad\u8fae\u8faf\u8fb0\u8fb1\u8fb2\u8fb3\u8fb4\u8fb5\u8fb6\u8fb7\u8fb8\u8fb9\u8fba\u8fbb\u8fbc\u8fbd\u8fbe\u8fbf\u8fc0\u8fc1\u8fc2\u8fc3\u8fc4\u8fc5\u8fc6\u8fc7\u8fc8\u8fc9\u8fca\u8fcb\u8fcc\u8fcd\u8fce\u8fcf\u8fd0\u8fd1\u8fd2\u8fd3\u8fd4\u8fd5\u8fd6\u8fd7\u8fd8\u8fd9\u8fda\u8fdb\u8fdc\u8fdd\u8fde\u8fdf\u8fe0\u8fe1\u8fe2\u8fe3\u8fe4\u8fe5\u8fe6\u8fe7\u8fe8\u8fe9\u8fea\u8feb\u8fec\u8fed\u8fee\u8fef\u8ff0\u8ff1\u8ff2\u8ff3\u8ff4\u8ff5\u8ff6\u8ff7\u8ff8\u8ff9\u8ffa\u8ffb\u8ffc\u8ffd\u8ffe\u8fff\u9000\u9001\u9002\u9003\u9004\u9005\u9006\u9007\u9008\u9009\u900a\u900b\u900c\u900d\u900e\u900f\u9010\u9011\u9012\u9013\u9014\u9015\u9016\u9017\u9018\u9019\u901a\u901b\u901c\u901d\u901e\u901f\u9020\u9021\u9022\u9023\u9024\u9025\u9026\u9027\u9028\u9029\u902a\u902b\u902c\u902d\u902e\u902f\u9030\u9031\u9032\u9033\u9034\u9035\u9036\u9037\u9038\u9039\u903a\u903b\u903c\u903d\u903e\u903f\u9040\u9041\u9042\u9043\u9044\u9045\u9046\u9047\u9048\u9049\u904a\u904b\u904c\u904d\u904e\u904f\u9050\u9051\u9052\u9053\u9054\u9055\u9056\u9057\u9058\u9059\u905a\u905b\u905c\u905d\u905e\u905f\u9060\u9061\u9062\u9063\u9064\u9065\u9066\u9067\u9068\u9069\u906a\u906b\u906c\u906d\u906e\u906f\u9070\u9071\u9072\u9073\u9074\u9075\u9076\u9077\u9078\u9079\u907a\u907b\u907c\u907d\u907e\u907f\u9080\u9081\u9082\u9083\u9084\u9085\u9086\u9087\u9088\u9089\u908a\u908b\u908c\u908d\u908e\u908f\u9090\u9091\u9092\u9093\u9094\u9095\u9096\u9097\u9098\u9099\u909a\u909b\u909c\u909d\u909e\u909f\u90a0\u90a1\u90a2\u90a3\u90a4\u90a5\u90a6\u90a7\u90a8\u90a9\u90aa\u90ab\u90ac\u90ad\u90ae\u90af\u90b0\u90b1\u90b2\u90b3\u90b4\u90b5\u90b6\u90b7\u90b8\u90b9\u90ba\u90bb\u90bc\u90bd\u90be\u90bf\u90c0\u90c1\u90c2\u90c3\u90c4\u90c5\u90c6\u90c7\u90c8\u90c9\u90ca\u90cb\u90cc\u90cd\u90ce\u90cf\u90d0\u90d1\u90d2\u90d3\u90d4\u90d5\u90d6\u90d7\u90d8\u90d9\u90da\u90db\u90dc\u90dd\u90de\u90df\u90e0\u90e1\u90e2\u90e3\u90e4\u90e5\u90e6\u90e7\u90e8\u90e9\u90ea\u90eb\u90ec\u90ed\u90ee\u90ef\u90f0\u90f1\u90f2\u90f3\u90f4\u90f5\u90f6\u90f7\u90f8\u90f9\u90fa\u90fb\u90fc\u90fd\u90fe\u90ff\u9100\u9101\u9102\u9103\u9104\u9105\u9106\u9107\u9108\u9109\u910a\u910b\u910c\u910d\u910e\u910f\u9110\u9111\u9112\u9113\u9114\u9115\u9116\u9117\u9118\u9119\u911a\u911b\u911c\u911d\u911e\u911f\u9120\u9121\u9122\u9123\u9124\u9125\u9126\u9127\u9128\u9129\u912a\u912b\u912c\u912d\u912e\u912f\u9130\u9131\u9132\u9133\u9134\u9135\u9136\u9137\u9138\u9139\u913a\u913b\u913c\u913d\u913e\u913f\u9140\u9141\u9142\u9143\u9144\u9145\u9146\u9147\u9148\u9149\u914a\u914b\u914c\u914d\u914e\u914f\u9150\u9151\u9152\u9153\u9154\u9155\u9156\u9157\u9158\u9159\u915a\u915b\u915c\u915d\u915e\u915f\u9160\u9161\u9162\u9163\u9164\u9165\u9166\u9167\u9168\u9169\u916a\u916b\u916c\u916d\u916e\u916f\u9170\u9171\u9172\u9173\u9174\u9175\u9176\u9177\u9178\u9179\u917a\u917b\u917c\u917d\u917e\u917f\u9180\u9181\u9182\u9183\u9184\u9185\u9186\u9187\u9188\u9189\u918a\u918b\u918c\u918d\u918e\u918f\u9190\u9191\u9192\u9193\u9194\u9195\u9196\u9197\u9198\u9199\u919a\u919b\u919c\u919d\u919e\u919f\u91a0\u91a1\u91a2\u91a3\u91a4\u91a5\u91a6\u91a7\u91a8\u91a9\u91aa\u91ab\u91ac\u91ad\u91ae\u91af\u91b0\u91b1\u91b2\u91b3\u91b4\u91b5\u91b6\u91b7\u91b8\u91b9\u91ba\u91bb\u91bc\u91bd\u91be\u91bf\u91c0\u91c1\u91c2\u91c3\u91c4\u91c5\u91c6\u91c7\u91c8\u91c9\u91ca\u91cb\u91cc\u91cd\u91ce\u91cf\u91d0\u91d1\u91d2\u91d3\u91d4\u91d5\u91d6\u91d7\u91d8\u91d9\u91da\u91db\u91dc\u91dd\u91de\u91df\u91e0\u91e1\u91e2\u91e3\u91e4\u91e5\u91e6\u91e7\u91e8\u91e9\u91ea\u91eb\u91ec\u91ed\u91ee\u91ef\u91f0\u91f1\u91f2\u91f3\u91f4\u91f5\u91f6\u91f7\u91f8\u91f9\u91fa\u91fb\u91fc\u91fd\u91fe\u91ff\u9200\u9201\u9202\u9203\u9204\u9205\u9206\u9207\u9208\u9209\u920a\u920b\u920c\u920d\u920e\u920f\u9210\u9211\u9212\u9213\u9214\u9215\u9216\u9217\u9218\u9219\u921a\u921b\u921c\u921d\u921e\u921f\u9220\u9221\u9222\u9223\u9224\u9225\u9226\u9227\u9228\u9229\u922a\u922b\u922c\u922d\u922e\u922f\u9230\u9231\u9232\u9233\u9234\u9235\u9236\u9237\u9238\u9239\u923a\u923b\u923c\u923d\u923e\u923f\u9240\u9241\u9242\u9243\u9244\u9245\u9246\u9247\u9248\u9249\u924a\u924b\u924c\u924d\u924e\u924f\u9250\u9251\u9252\u9253\u9254\u9255\u9256\u9257\u9258\u9259\u925a\u925b\u925c\u925d\u925e\u925f\u9260\u9261\u9262\u9263\u9264\u9265\u9266\u9267\u9268\u9269\u926a\u926b\u926c\u926d\u926e\u926f\u9270\u9271\u9272\u9273\u9274\u9275\u9276\u9277\u9278\u9279\u927a\u927b\u927c\u927d\u927e\u927f\u9280\u9281\u9282\u9283\u9284\u9285\u9286\u9287\u9288\u9289\u928a\u928b\u928c\u928d\u928e\u928f\u9290\u9291\u9292\u9293\u9294\u9295\u9296\u9297\u9298\u9299\u929a\u929b\u929c\u929d\u929e\u929f\u92a0\u92a1\u92a2\u92a3\u92a4\u92a5\u92a6\u92a7\u92a8\u92a9\u92aa\u92ab\u92ac\u92ad\u92ae\u92af\u92b0\u92b1\u92b2\u92b3\u92b4\u92b5\u92b6\u92b7\u92b8\u92b9\u92ba\u92bb\u92bc\u92bd\u92be\u92bf\u92c0\u92c1\u92c2\u92c3\u92c4\u92c5\u92c6\u92c7\u92c8\u92c9\u92ca\u92cb\u92cc\u92cd\u92ce\u92cf\u92d0\u92d1\u92d2\u92d3\u92d4\u92d5\u92d6\u92d7\u92d8\u92d9\u92da\u92db\u92dc\u92dd\u92de\u92df\u92e0\u92e1\u92e2\u92e3\u92e4\u92e5\u92e6\u92e7\u92e8\u92e9\u92ea\u92eb\u92ec\u92ed\u92ee\u92ef\u92f0\u92f1\u92f2\u92f3\u92f4\u92f5\u92f6\u92f7\u92f8\u92f9\u92fa\u92fb\u92fc\u92fd\u92fe\u92ff\u9300\u9301\u9302\u9303\u9304\u9305\u9306\u9307\u9308\u9309\u930a\u930b\u930c\u930d\u930e\u930f\u9310\u9311\u9312\u9313\u9314\u9315\u9316\u9317\u9318\u9319\u931a\u931b\u931c\u931d\u931e\u931f\u9320\u9321\u9322\u9323\u9324\u9325\u9326\u9327\u9328\u9329\u932a\u932b\u932c\u932d\u932e\u932f\u9330\u9331\u9332\u9333\u9334\u9335\u9336\u9337\u9338\u9339\u933a\u933b\u933c\u933d\u933e\u933f\u9340\u9341\u9342\u9343\u9344\u9345\u9346\u9347\u9348\u9349\u934a\u934b\u934c\u934d\u934e\u934f\u9350\u9351\u9352\u9353\u9354\u9355\u9356\u9357\u9358\u9359\u935a\u935b\u935c\u935d\u935e\u935f\u9360\u9361\u9362\u9363\u9364\u9365\u9366\u9367\u9368\u9369\u936a\u936b\u936c\u936d\u936e\u936f\u9370\u9371\u9372\u9373\u9374\u9375\u9376\u9377\u9378\u9379\u937a\u937b\u937c\u937d\u937e\u937f\u9380\u9381\u9382\u9383\u9384\u9385\u9386\u9387\u9388\u9389\u938a\u938b\u938c\u938d\u938e\u938f\u9390\u9391\u9392\u9393\u9394\u9395\u9396\u9397\u9398\u9399\u939a\u939b\u939c\u939d\u939e\u939f\u93a0\u93a1\u93a2\u93a3\u93a4\u93a5\u93a6\u93a7\u93a8\u93a9\u93aa\u93ab\u93ac\u93ad\u93ae\u93af\u93b0\u93b1\u93b2\u93b3\u93b4\u93b5\u93b6\u93b7\u93b8\u93b9\u93ba\u93bb\u93bc\u93bd\u93be\u93bf\u93c0\u93c1\u93c2\u93c3\u93c4\u93c5\u93c6\u93c7\u93c8\u93c9\u93ca\u93cb\u93cc\u93cd\u93ce\u93cf\u93d0\u93d1\u93d2\u93d3\u93d4\u93d5\u93d6\u93d7\u93d8\u93d9\u93da\u93db\u93dc\u93dd\u93de\u93df\u93e0\u93e1\u93e2\u93e3\u93e4\u93e5\u93e6\u93e7\u93e8\u93e9\u93ea\u93eb\u93ec\u93ed\u93ee\u93ef\u93f0\u93f1\u93f2\u93f3\u93f4\u93f5\u93f6\u93f7\u93f8\u93f9\u93fa\u93fb\u93fc\u93fd\u93fe\u93ff\u9400\u9401\u9402\u9403\u9404\u9405\u9406\u9407\u9408\u9409\u940a\u940b\u940c\u940d\u940e\u940f\u9410\u9411\u9412\u9413\u9414\u9415\u9416\u9417\u9418\u9419\u941a\u941b\u941c\u941d\u941e\u941f\u9420\u9421\u9422\u9423\u9424\u9425\u9426\u9427\u9428\u9429\u942a\u942b\u942c\u942d\u942e\u942f\u9430\u9431\u9432\u9433\u9434\u9435\u9436\u9437\u9438\u9439\u943a\u943b\u943c\u943d\u943e\u943f\u9440\u9441\u9442\u9443\u9444\u9445\u9446\u9447\u9448\u9449\u944a\u944b\u944c\u944d\u944e\u944f\u9450\u9451\u9452\u9453\u9454\u9455\u9456\u9457\u9458\u9459\u945a\u945b\u945c\u945d\u945e\u945f\u9460\u9461\u9462\u9463\u9464\u9465\u9466\u9467\u9468\u9469\u946a\u946b\u946c\u946d\u946e\u946f\u9470\u9471\u9472\u9473\u9474\u9475\u9476\u9477\u9478\u9479\u947a\u947b\u947c\u947d\u947e\u947f\u9480\u9481\u9482\u9483\u9484\u9485\u9486\u9487\u9488\u9489\u948a\u948b\u948c\u948d\u948e\u948f\u9490\u9491\u9492\u9493\u9494\u9495\u9496\u9497\u9498\u9499\u949a\u949b\u949c\u949d\u949e\u949f\u94a0\u94a1\u94a2\u94a3\u94a4\u94a5\u94a6\u94a7\u94a8\u94a9\u94aa\u94ab\u94ac\u94ad\u94ae\u94af\u94b0\u94b1\u94b2\u94b3\u94b4\u94b5\u94b6\u94b7\u94b8\u94b9\u94ba\u94bb\u94bc\u94bd\u94be\u94bf\u94c0\u94c1\u94c2\u94c3\u94c4\u94c5\u94c6\u94c7\u94c8\u94c9\u94ca\u94cb\u94cc\u94cd\u94ce\u94cf\u94d0\u94d1\u94d2\u94d3\u94d4\u94d5\u94d6\u94d7\u94d8\u94d9\u94da\u94db\u94dc\u94dd\u94de\u94df\u94e0\u94e1\u94e2\u94e3\u94e4\u94e5\u94e6\u94e7\u94e8\u94e9\u94ea\u94eb\u94ec\u94ed\u94ee\u94ef\u94f0\u94f1\u94f2\u94f3\u94f4\u94f5\u94f6\u94f7\u94f8\u94f9\u94fa\u94fb\u94fc\u94fd\u94fe\u94ff\u9500\u9501\u9502\u9503\u9504\u9505\u9506\u9507\u9508\u9509\u950a\u950b\u950c\u950d\u950e\u950f\u9510\u9511\u9512\u9513\u9514\u9515\u9516\u9517\u9518\u9519\u951a\u951b\u951c\u951d\u951e\u951f\u9520\u9521\u9522\u9523\u9524\u9525\u9526\u9527\u9528\u9529\u952a\u952b\u952c\u952d\u952e\u952f\u9530\u9531\u9532\u9533\u9534\u9535\u9536\u9537\u9538\u9539\u953a\u953b\u953c\u953d\u953e\u953f\u9540\u9541\u9542\u9543\u9544\u9545\u9546\u9547\u9548\u9549\u954a\u954b\u954c\u954d\u954e\u954f\u9550\u9551\u9552\u9553\u9554\u9555\u9556\u9557\u9558\u9559\u955a\u955b\u955c\u955d\u955e\u955f\u9560\u9561\u9562\u9563\u9564\u9565\u9566\u9567\u9568\u9569\u956a\u956b\u956c\u956d\u956e\u956f\u9570\u9571\u9572\u9573\u9574\u9575\u9576\u9577\u9578\u9579\u957a\u957b\u957c\u957d\u957e\u957f\u9580\u9581\u9582\u9583\u9584\u9585\u9586\u9587\u9588\u9589\u958a\u958b\u958c\u958d\u958e\u958f\u9590\u9591\u9592\u9593\u9594\u9595\u9596\u9597\u9598\u9599\u959a\u959b\u959c\u959d\u959e\u959f\u95a0\u95a1\u95a2\u95a3\u95a4\u95a5\u95a6\u95a7\u95a8\u95a9\u95aa\u95ab\u95ac\u95ad\u95ae\u95af\u95b0\u95b1\u95b2\u95b3\u95b4\u95b5\u95b6\u95b7\u95b8\u95b9\u95ba\u95bb\u95bc\u95bd\u95be\u95bf\u95c0\u95c1\u95c2\u95c3\u95c4\u95c5\u95c6\u95c7\u95c8\u95c9\u95ca\u95cb\u95cc\u95cd\u95ce\u95cf\u95d0\u95d1\u95d2\u95d3\u95d4\u95d5\u95d6\u95d7\u95d8\u95d9\u95da\u95db\u95dc\u95dd\u95de\u95df\u95e0\u95e1\u95e2\u95e3\u95e4\u95e5\u95e6\u95e7\u95e8\u95e9\u95ea\u95eb\u95ec\u95ed\u95ee\u95ef\u95f0\u95f1\u95f2\u95f3\u95f4\u95f5\u95f6\u95f7\u95f8\u95f9\u95fa\u95fb\u95fc\u95fd\u95fe\u95ff\u9600\u9601\u9602\u9603\u9604\u9605\u9606\u9607\u9608\u9609\u960a\u960b\u960c\u960d\u960e\u960f\u9610\u9611\u9612\u9613\u9614\u9615\u9616\u9617\u9618\u9619\u961a\u961b\u961c\u961d\u961e\u961f\u9620\u9621\u9622\u9623\u9624\u9625\u9626\u9627\u9628\u9629\u962a\u962b\u962c\u962d\u962e\u962f\u9630\u9631\u9632\u9633\u9634\u9635\u9636\u9637\u9638\u9639\u963a\u963b\u963c\u963d\u963e\u963f\u9640\u9641\u9642\u9643\u9644\u9645\u9646\u9647\u9648\u9649\u964a\u964b\u964c\u964d\u964e\u964f\u9650\u9651\u9652\u9653\u9654\u9655\u9656\u9657\u9658\u9659\u965a\u965b\u965c\u965d\u965e\u965f\u9660\u9661\u9662\u9663\u9664\u9665\u9666\u9667\u9668\u9669\u966a\u966b\u966c\u966d\u966e\u966f\u9670\u9671\u9672\u9673\u9674\u9675\u9676\u9677\u9678\u9679\u967a\u967b\u967c\u967d\u967e\u967f\u9680\u9681\u9682\u9683\u9684\u9685\u9686\u9687\u9688\u9689\u968a\u968b\u968c\u968d\u968e\u968f\u9690\u9691\u9692\u9693\u9694\u9695\u9696\u9697\u9698\u9699\u969a\u969b\u969c\u969d\u969e\u969f\u96a0\u96a1\u96a2\u96a3\u96a4\u96a5\u96a6\u96a7\u96a8\u96a9\u96aa\u96ab\u96ac\u96ad\u96ae\u96af\u96b0\u96b1\u96b2\u96b3\u96b4\u96b5\u96b6\u96b7\u96b8\u96b9\u96ba\u96bb\u96bc\u96bd\u96be\u96bf\u96c0\u96c1\u96c2\u96c3\u96c4\u96c5\u96c6\u96c7\u96c8\u96c9\u96ca\u96cb\u96cc\u96cd\u96ce\u96cf\u96d0\u96d1\u96d2\u96d3\u96d4\u96d5\u96d6\u96d7\u96d8\u96d9\u96da\u96db\u96dc\u96dd\u96de\u96df\u96e0\u96e1\u96e2\u96e3\u96e4\u96e5\u96e6\u96e7\u96e8\u96e9\u96ea\u96eb\u96ec\u96ed\u96ee\u96ef\u96f0\u96f1\u96f2\u96f3\u96f4\u96f5\u96f6\u96f7\u96f8\u96f9\u96fa\u96fb\u96fc\u96fd\u96fe\u96ff\u9700\u9701\u9702\u9703\u9704\u9705\u9706\u9707\u9708\u9709\u970a\u970b\u970c\u970d\u970e\u970f\u9710\u9711\u9712\u9713\u9714\u9715\u9716\u9717\u9718\u9719\u971a\u971b\u971c\u971d\u971e\u971f\u9720\u9721\u9722\u9723\u9724\u9725\u9726\u9727\u9728\u9729\u972a\u972b\u972c\u972d\u972e\u972f\u9730\u9731\u9732\u9733\u9734\u9735\u9736\u9737\u9738\u9739\u973a\u973b\u973c\u973d\u973e\u973f\u9740\u9741\u9742\u9743\u9744\u9745\u9746\u9747\u9748\u9749\u974a\u974b\u974c\u974d\u974e\u974f\u9750\u9751\u9752\u9753\u9754\u9755\u9756\u9757\u9758\u9759\u975a\u975b\u975c\u975d\u975e\u975f\u9760\u9761\u9762\u9763\u9764\u9765\u9766\u9767\u9768\u9769\u976a\u976b\u976c\u976d\u976e\u976f\u9770\u9771\u9772\u9773\u9774\u9775\u9776\u9777\u9778\u9779\u977a\u977b\u977c\u977d\u977e\u977f\u9780\u9781\u9782\u9783\u9784\u9785\u9786\u9787\u9788\u9789\u978a\u978b\u978c\u978d\u978e\u978f\u9790\u9791\u9792\u9793\u9794\u9795\u9796\u9797\u9798\u9799\u979a\u979b\u979c\u979d\u979e\u979f\u97a0\u97a1\u97a2\u97a3\u97a4\u97a5\u97a6\u97a7\u97a8\u97a9\u97aa\u97ab\u97ac\u97ad\u97ae\u97af\u97b0\u97b1\u97b2\u97b3\u97b4\u97b5\u97b6\u97b7\u97b8\u97b9\u97ba\u97bb\u97bc\u97bd\u97be\u97bf\u97c0\u97c1\u97c2\u97c3\u97c4\u97c5\u97c6\u97c7\u97c8\u97c9\u97ca\u97cb\u97cc\u97cd\u97ce\u97cf\u97d0\u97d1\u97d2\u97d3\u97d4\u97d5\u97d6\u97d7\u97d8\u97d9\u97da\u97db\u97dc\u97dd\u97de\u97df\u97e0\u97e1\u97e2\u97e3\u97e4\u97e5\u97e6\u97e7\u97e8\u97e9\u97ea\u97eb\u97ec\u97ed\u97ee\u97ef\u97f0\u97f1\u97f2\u97f3\u97f4\u97f5\u97f6\u97f7\u97f8\u97f9\u97fa\u97fb\u97fc\u97fd\u97fe\u97ff\u9800\u9801\u9802\u9803\u9804\u9805\u9806\u9807\u9808\u9809\u980a\u980b\u980c\u980d\u980e\u980f\u9810\u9811\u9812\u9813\u9814\u9815\u9816\u9817\u9818\u9819\u981a\u981b\u981c\u981d\u981e\u981f\u9820\u9821\u9822\u9823\u9824\u9825\u9826\u9827\u9828\u9829\u982a\u982b\u982c\u982d\u982e\u982f\u9830\u9831\u9832\u9833\u9834\u9835\u9836\u9837\u9838\u9839\u983a\u983b\u983c\u983d\u983e\u983f\u9840\u9841\u9842\u9843\u9844\u9845\u9846\u9847\u9848\u9849\u984a\u984b\u984c\u984d\u984e\u984f\u9850\u9851\u9852\u9853\u9854\u9855\u9856\u9857\u9858\u9859\u985a\u985b\u985c\u985d\u985e\u985f\u9860\u9861\u9862\u9863\u9864\u9865\u9866\u9867\u9868\u9869\u986a\u986b\u986c\u986d\u986e\u986f\u9870\u9871\u9872\u9873\u9874\u9875\u9876\u9877\u9878\u9879\u987a\u987b\u987c\u987d\u987e\u987f\u9880\u9881\u9882\u9883\u9884\u9885\u9886\u9887\u9888\u9889\u988a\u988b\u988c\u988d\u988e\u988f\u9890\u9891\u9892\u9893\u9894\u9895\u9896\u9897\u9898\u9899\u989a\u989b\u989c\u989d\u989e\u989f\u98a0\u98a1\u98a2\u98a3\u98a4\u98a5\u98a6\u98a7\u98a8\u98a9\u98aa\u98ab\u98ac\u98ad\u98ae\u98af\u98b0\u98b1\u98b2\u98b3\u98b4\u98b5\u98b6\u98b7\u98b8\u98b9\u98ba\u98bb\u98bc\u98bd\u98be\u98bf\u98c0\u98c1\u98c2\u98c3\u98c4\u98c5\u98c6\u98c7\u98c8\u98c9\u98ca\u98cb\u98cc\u98cd\u98ce\u98cf\u98d0\u98d1\u98d2\u98d3\u98d4\u98d5\u98d6\u98d7\u98d8\u98d9\u98da\u98db\u98dc\u98dd\u98de\u98df\u98e0\u98e1\u98e2\u98e3\u98e4\u98e5\u98e6\u98e7\u98e8\u98e9\u98ea\u98eb\u98ec\u98ed\u98ee\u98ef\u98f0\u98f1\u98f2\u98f3\u98f4\u98f5\u98f6\u98f7\u98f8\u98f9\u98fa\u98fb\u98fc\u98fd\u98fe\u98ff\u9900\u9901\u9902\u9903\u9904\u9905\u9906\u9907\u9908\u9909\u990a\u990b\u990c\u990d\u990e\u990f\u9910\u9911\u9912\u9913\u9914\u9915\u9916\u9917\u9918\u9919\u991a\u991b\u991c\u991d\u991e\u991f\u9920\u9921\u9922\u9923\u9924\u9925\u9926\u9927\u9928\u9929\u992a\u992b\u992c\u992d\u992e\u992f\u9930\u9931\u9932\u9933\u9934\u9935\u9936\u9937\u9938\u9939\u993a\u993b\u993c\u993d\u993e\u993f\u9940\u9941\u9942\u9943\u9944\u9945\u9946\u9947\u9948\u9949\u994a\u994b\u994c\u994d\u994e\u994f\u9950\u9951\u9952\u9953\u9954\u9955\u9956\u9957\u9958\u9959\u995a\u995b\u995c\u995d\u995e\u995f\u9960\u9961\u9962\u9963\u9964\u9965\u9966\u9967\u9968\u9969\u996a\u996b\u996c\u996d\u996e\u996f\u9970\u9971\u9972\u9973\u9974\u9975\u9976\u9977\u9978\u9979\u997a\u997b\u997c\u997d\u997e\u997f\u9980\u9981\u9982\u9983\u9984\u9985\u9986\u9987\u9988\u9989\u998a\u998b\u998c\u998d\u998e\u998f\u9990\u9991\u9992\u9993\u9994\u9995\u9996\u9997\u9998\u9999\u999a\u999b\u999c\u999d\u999e\u999f\u99a0\u99a1\u99a2\u99a3\u99a4\u99a5\u99a6\u99a7\u99a8\u99a9\u99aa\u99ab\u99ac\u99ad\u99ae\u99af\u99b0\u99b1\u99b2\u99b3\u99b4\u99b5\u99b6\u99b7\u99b8\u99b9\u99ba\u99bb\u99bc\u99bd\u99be\u99bf\u99c0\u99c1\u99c2\u99c3\u99c4\u99c5\u99c6\u99c7\u99c8\u99c9\u99ca\u99cb\u99cc\u99cd\u99ce\u99cf\u99d0\u99d1\u99d2\u99d3\u99d4\u99d5\u99d6\u99d7\u99d8\u99d9\u99da\u99db\u99dc\u99dd\u99de\u99df\u99e0\u99e1\u99e2\u99e3\u99e4\u99e5\u99e6\u99e7\u99e8\u99e9\u99ea\u99eb\u99ec\u99ed\u99ee\u99ef\u99f0\u99f1\u99f2\u99f3\u99f4\u99f5\u99f6\u99f7\u99f8\u99f9\u99fa\u99fb\u99fc\u99fd\u99fe\u99ff\u9a00\u9a01\u9a02\u9a03\u9a04\u9a05\u9a06\u9a07\u9a08\u9a09\u9a0a\u9a0b\u9a0c\u9a0d\u9a0e\u9a0f\u9a10\u9a11\u9a12\u9a13\u9a14\u9a15\u9a16\u9a17\u9a18\u9a19\u9a1a\u9a1b\u9a1c\u9a1d\u9a1e\u9a1f\u9a20\u9a21\u9a22\u9a23\u9a24\u9a25\u9a26\u9a27\u9a28\u9a29\u9a2a\u9a2b\u9a2c\u9a2d\u9a2e\u9a2f\u9a30\u9a31\u9a32\u9a33\u9a34\u9a35\u9a36\u9a37\u9a38\u9a39\u9a3a\u9a3b\u9a3c\u9a3d\u9a3e\u9a3f\u9a40\u9a41\u9a42\u9a43\u9a44\u9a45\u9a46\u9a47\u9a48\u9a49\u9a4a\u9a4b\u9a4c\u9a4d\u9a4e\u9a4f\u9a50\u9a51\u9a52\u9a53\u9a54\u9a55\u9a56\u9a57\u9a58\u9a59\u9a5a\u9a5b\u9a5c\u9a5d\u9a5e\u9a5f\u9a60\u9a61\u9a62\u9a63\u9a64\u9a65\u9a66\u9a67\u9a68\u9a69\u9a6a\u9a6b\u9a6c\u9a6d\u9a6e\u9a6f\u9a70\u9a71\u9a72\u9a73\u9a74\u9a75\u9a76\u9a77\u9a78\u9a79\u9a7a\u9a7b\u9a7c\u9a7d\u9a7e\u9a7f\u9a80\u9a81\u9a82\u9a83\u9a84\u9a85\u9a86\u9a87\u9a88\u9a89\u9a8a\u9a8b\u9a8c\u9a8d\u9a8e\u9a8f\u9a90\u9a91\u9a92\u9a93\u9a94\u9a95\u9a96\u9a97\u9a98\u9a99\u9a9a\u9a9b\u9a9c\u9a9d\u9a9e\u9a9f\u9aa0\u9aa1\u9aa2\u9aa3\u9aa4\u9aa5\u9aa6\u9aa7\u9aa8\u9aa9\u9aaa\u9aab\u9aac\u9aad\u9aae\u9aaf\u9ab0\u9ab1\u9ab2\u9ab3\u9ab4\u9ab5\u9ab6\u9ab7\u9ab8\u9ab9\u9aba\u9abb\u9abc\u9abd\u9abe\u9abf\u9ac0\u9ac1\u9ac2\u9ac3\u9ac4\u9ac5\u9ac6\u9ac7\u9ac8\u9ac9\u9aca\u9acb\u9acc\u9acd\u9ace\u9acf\u9ad0\u9ad1\u9ad2\u9ad3\u9ad4\u9ad5\u9ad6\u9ad7\u9ad8\u9ad9\u9ada\u9adb\u9adc\u9add\u9ade\u9adf\u9ae0\u9ae1\u9ae2\u9ae3\u9ae4\u9ae5\u9ae6\u9ae7\u9ae8\u9ae9\u9aea\u9aeb\u9aec\u9aed\u9aee\u9aef\u9af0\u9af1\u9af2\u9af3\u9af4\u9af5\u9af6\u9af7\u9af8\u9af9\u9afa\u9afb\u9afc\u9afd\u9afe\u9aff\u9b00\u9b01\u9b02\u9b03\u9b04\u9b05\u9b06\u9b07\u9b08\u9b09\u9b0a\u9b0b\u9b0c\u9b0d\u9b0e\u9b0f\u9b10\u9b11\u9b12\u9b13\u9b14\u9b15\u9b16\u9b17\u9b18\u9b19\u9b1a\u9b1b\u9b1c\u9b1d\u9b1e\u9b1f\u9b20\u9b21\u9b22\u9b23\u9b24\u9b25\u9b26\u9b27\u9b28\u9b29\u9b2a\u9b2b\u9b2c\u9b2d\u9b2e\u9b2f\u9b30\u9b31\u9b32\u9b33\u9b34\u9b35\u9b36\u9b37\u9b38\u9b39\u9b3a\u9b3b\u9b3c\u9b3d\u9b3e\u9b3f\u9b40\u9b41\u9b42\u9b43\u9b44\u9b45\u9b46\u9b47\u9b48\u9b49\u9b4a\u9b4b\u9b4c\u9b4d\u9b4e\u9b4f\u9b50\u9b51\u9b52\u9b53\u9b54\u9b55\u9b56\u9b57\u9b58\u9b59\u9b5a\u9b5b\u9b5c\u9b5d\u9b5e\u9b5f\u9b60\u9b61\u9b62\u9b63\u9b64\u9b65\u9b66\u9b67\u9b68\u9b69\u9b6a\u9b6b\u9b6c\u9b6d\u9b6e\u9b6f\u9b70\u9b71\u9b72\u9b73\u9b74\u9b75\u9b76\u9b77\u9b78\u9b79\u9b7a\u9b7b\u9b7c\u9b7d\u9b7e\u9b7f\u9b80\u9b81\u9b82\u9b83\u9b84\u9b85\u9b86\u9b87\u9b88\u9b89\u9b8a\u9b8b\u9b8c\u9b8d\u9b8e\u9b8f\u9b90\u9b91\u9b92\u9b93\u9b94\u9b95\u9b96\u9b97\u9b98\u9b99\u9b9a\u9b9b\u9b9c\u9b9d\u9b9e\u9b9f\u9ba0\u9ba1\u9ba2\u9ba3\u9ba4\u9ba5\u9ba6\u9ba7\u9ba8\u9ba9\u9baa\u9bab\u9bac\u9bad\u9bae\u9baf\u9bb0\u9bb1\u9bb2\u9bb3\u9bb4\u9bb5\u9bb6\u9bb7\u9bb8\u9bb9\u9bba\u9bbb\u9bbc\u9bbd\u9bbe\u9bbf\u9bc0\u9bc1\u9bc2\u9bc3\u9bc4\u9bc5\u9bc6\u9bc7\u9bc8\u9bc9\u9bca\u9bcb\u9bcc\u9bcd\u9bce\u9bcf\u9bd0\u9bd1\u9bd2\u9bd3\u9bd4\u9bd5\u9bd6\u9bd7\u9bd8\u9bd9\u9bda\u9bdb\u9bdc\u9bdd\u9bde\u9bdf\u9be0\u9be1\u9be2\u9be3\u9be4\u9be5\u9be6\u9be7\u9be8\u9be9\u9bea\u9beb\u9bec\u9bed\u9bee\u9bef\u9bf0\u9bf1\u9bf2\u9bf3\u9bf4\u9bf5\u9bf6\u9bf7\u9bf8\u9bf9\u9bfa\u9bfb\u9bfc\u9bfd\u9bfe\u9bff\u9c00\u9c01\u9c02\u9c03\u9c04\u9c05\u9c06\u9c07\u9c08\u9c09\u9c0a\u9c0b\u9c0c\u9c0d\u9c0e\u9c0f\u9c10\u9c11\u9c12\u9c13\u9c14\u9c15\u9c16\u9c17\u9c18\u9c19\u9c1a\u9c1b\u9c1c\u9c1d\u9c1e\u9c1f\u9c20\u9c21\u9c22\u9c23\u9c24\u9c25\u9c26\u9c27\u9c28\u9c29\u9c2a\u9c2b\u9c2c\u9c2d\u9c2e\u9c2f\u9c30\u9c31\u9c32\u9c33\u9c34\u9c35\u9c36\u9c37\u9c38\u9c39\u9c3a\u9c3b\u9c3c\u9c3d\u9c3e\u9c3f\u9c40\u9c41\u9c42\u9c43\u9c44\u9c45\u9c46\u9c47\u9c48\u9c49\u9c4a\u9c4b\u9c4c\u9c4d\u9c4e\u9c4f\u9c50\u9c51\u9c52\u9c53\u9c54\u9c55\u9c56\u9c57\u9c58\u9c59\u9c5a\u9c5b\u9c5c\u9c5d\u9c5e\u9c5f\u9c60\u9c61\u9c62\u9c63\u9c64\u9c65\u9c66\u9c67\u9c68\u9c69\u9c6a\u9c6b\u9c6c\u9c6d\u9c6e\u9c6f\u9c70\u9c71\u9c72\u9c73\u9c74\u9c75\u9c76\u9c77\u9c78\u9c79\u9c7a\u9c7b\u9c7c\u9c7d\u9c7e\u9c7f\u9c80\u9c81\u9c82\u9c83\u9c84\u9c85\u9c86\u9c87\u9c88\u9c89\u9c8a\u9c8b\u9c8c\u9c8d\u9c8e\u9c8f\u9c90\u9c91\u9c92\u9c93\u9c94\u9c95\u9c96\u9c97\u9c98\u9c99\u9c9a\u9c9b\u9c9c\u9c9d\u9c9e\u9c9f\u9ca0\u9ca1\u9ca2\u9ca3\u9ca4\u9ca5\u9ca6\u9ca7\u9ca8\u9ca9\u9caa\u9cab\u9cac\u9cad\u9cae\u9caf\u9cb0\u9cb1\u9cb2\u9cb3\u9cb4\u9cb5\u9cb6\u9cb7\u9cb8\u9cb9\u9cba\u9cbb\u9cbc\u9cbd\u9cbe\u9cbf\u9cc0\u9cc1\u9cc2\u9cc3\u9cc4\u9cc5\u9cc6\u9cc7\u9cc8\u9cc9\u9cca\u9ccb\u9ccc\u9ccd\u9cce\u9ccf\u9cd0\u9cd1\u9cd2\u9cd3\u9cd4\u9cd5\u9cd6\u9cd7\u9cd8\u9cd9\u9cda\u9cdb\u9cdc\u9cdd\u9cde\u9cdf\u9ce0\u9ce1\u9ce2\u9ce3\u9ce4\u9ce5\u9ce6\u9ce7\u9ce8\u9ce9\u9cea\u9ceb\u9cec\u9ced\u9cee\u9cef\u9cf0\u9cf1\u9cf2\u9cf3\u9cf4\u9cf5\u9cf6\u9cf7\u9cf8\u9cf9\u9cfa\u9cfb\u9cfc\u9cfd\u9cfe\u9cff\u9d00\u9d01\u9d02\u9d03\u9d04\u9d05\u9d06\u9d07\u9d08\u9d09\u9d0a\u9d0b\u9d0c\u9d0d\u9d0e\u9d0f\u9d10\u9d11\u9d12\u9d13\u9d14\u9d15\u9d16\u9d17\u9d18\u9d19\u9d1a\u9d1b\u9d1c\u9d1d\u9d1e\u9d1f\u9d20\u9d21\u9d22\u9d23\u9d24\u9d25\u9d26\u9d27\u9d28\u9d29\u9d2a\u9d2b\u9d2c\u9d2d\u9d2e\u9d2f\u9d30\u9d31\u9d32\u9d33\u9d34\u9d35\u9d36\u9d37\u9d38\u9d39\u9d3a\u9d3b\u9d3c\u9d3d\u9d3e\u9d3f\u9d40\u9d41\u9d42\u9d43\u9d44\u9d45\u9d46\u9d47\u9d48\u9d49\u9d4a\u9d4b\u9d4c\u9d4d\u9d4e\u9d4f\u9d50\u9d51\u9d52\u9d53\u9d54\u9d55\u9d56\u9d57\u9d58\u9d59\u9d5a\u9d5b\u9d5c\u9d5d\u9d5e\u9d5f\u9d60\u9d61\u9d62\u9d63\u9d64\u9d65\u9d66\u9d67\u9d68\u9d69\u9d6a\u9d6b\u9d6c\u9d6d\u9d6e\u9d6f\u9d70\u9d71\u9d72\u9d73\u9d74\u9d75\u9d76\u9d77\u9d78\u9d79\u9d7a\u9d7b\u9d7c\u9d7d\u9d7e\u9d7f\u9d80\u9d81\u9d82\u9d83\u9d84\u9d85\u9d86\u9d87\u9d88\u9d89\u9d8a\u9d8b\u9d8c\u9d8d\u9d8e\u9d8f\u9d90\u9d91\u9d92\u9d93\u9d94\u9d95\u9d96\u9d97\u9d98\u9d99\u9d9a\u9d9b\u9d9c\u9d9d\u9d9e\u9d9f\u9da0\u9da1\u9da2\u9da3\u9da4\u9da5\u9da6\u9da7\u9da8\u9da9\u9daa\u9dab\u9dac\u9dad\u9dae\u9daf\u9db0\u9db1\u9db2\u9db3\u9db4\u9db5\u9db6\u9db7\u9db8\u9db9\u9dba\u9dbb\u9dbc\u9dbd\u9dbe\u9dbf\u9dc0\u9dc1\u9dc2\u9dc3\u9dc4\u9dc5\u9dc6\u9dc7\u9dc8\u9dc9\u9dca\u9dcb\u9dcc\u9dcd\u9dce\u9dcf\u9dd0\u9dd1\u9dd2\u9dd3\u9dd4\u9dd5\u9dd6\u9dd7\u9dd8\u9dd9\u9dda\u9ddb\u9ddc\u9ddd\u9dde\u9ddf\u9de0\u9de1\u9de2\u9de3\u9de4\u9de5\u9de6\u9de7\u9de8\u9de9\u9dea\u9deb\u9dec\u9ded\u9dee\u9def\u9df0\u9df1\u9df2\u9df3\u9df4\u9df5\u9df6\u9df7\u9df8\u9df9\u9dfa\u9dfb\u9dfc\u9dfd\u9dfe\u9dff\u9e00\u9e01\u9e02\u9e03\u9e04\u9e05\u9e06\u9e07\u9e08\u9e09\u9e0a\u9e0b\u9e0c\u9e0d\u9e0e\u9e0f\u9e10\u9e11\u9e12\u9e13\u9e14\u9e15\u9e16\u9e17\u9e18\u9e19\u9e1a\u9e1b\u9e1c\u9e1d\u9e1e\u9e1f\u9e20\u9e21\u9e22\u9e23\u9e24\u9e25\u9e26\u9e27\u9e28\u9e29\u9e2a\u9e2b\u9e2c\u9e2d\u9e2e\u9e2f\u9e30\u9e31\u9e32\u9e33\u9e34\u9e35\u9e36\u9e37\u9e38\u9e39\u9e3a\u9e3b\u9e3c\u9e3d\u9e3e\u9e3f\u9e40\u9e41\u9e42\u9e43\u9e44\u9e45\u9e46\u9e47\u9e48\u9e49\u9e4a\u9e4b\u9e4c\u9e4d\u9e4e\u9e4f\u9e50\u9e51\u9e52\u9e53\u9e54\u9e55\u9e56\u9e57\u9e58\u9e59\u9e5a\u9e5b\u9e5c\u9e5d\u9e5e\u9e5f\u9e60\u9e61\u9e62\u9e63\u9e64\u9e65\u9e66\u9e67\u9e68\u9e69\u9e6a\u9e6b\u9e6c\u9e6d\u9e6e\u9e6f\u9e70\u9e71\u9e72\u9e73\u9e74\u9e75\u9e76\u9e77\u9e78\u9e79\u9e7a\u9e7b\u9e7c\u9e7d\u9e7e\u9e7f\u9e80\u9e81\u9e82\u9e83\u9e84\u9e85\u9e86\u9e87\u9e88\u9e89\u9e8a\u9e8b\u9e8c\u9e8d\u9e8e\u9e8f\u9e90\u9e91\u9e92\u9e93\u9e94\u9e95\u9e96\u9e97\u9e98\u9e99\u9e9a\u9e9b\u9e9c\u9e9d\u9e9e\u9e9f\u9ea0\u9ea1\u9ea2\u9ea3\u9ea4\u9ea5\u9ea6\u9ea7\u9ea8\u9ea9\u9eaa\u9eab\u9eac\u9ead\u9eae\u9eaf\u9eb0\u9eb1\u9eb2\u9eb3\u9eb4\u9eb5\u9eb6\u9eb7\u9eb8\u9eb9\u9eba\u9ebb\u9ebc\u9ebd\u9ebe\u9ebf\u9ec0\u9ec1\u9ec2\u9ec3\u9ec4\u9ec5\u9ec6\u9ec7\u9ec8\u9ec9\u9eca\u9ecb\u9ecc\u9ecd\u9ece\u9ecf\u9ed0\u9ed1\u9ed2\u9ed3\u9ed4\u9ed5\u9ed6\u9ed7\u9ed8\u9ed9\u9eda\u9edb\u9edc\u9edd\u9ede\u9edf\u9ee0\u9ee1\u9ee2\u9ee3\u9ee4\u9ee5\u9ee6\u9ee7\u9ee8\u9ee9\u9eea\u9eeb\u9eec\u9eed\u9eee\u9eef\u9ef0\u9ef1\u9ef2\u9ef3\u9ef4\u9ef5\u9ef6\u9ef7\u9ef8\u9ef9\u9efa\u9efb\u9efc\u9efd\u9efe\u9eff\u9f00\u9f01\u9f02\u9f03\u9f04\u9f05\u9f06\u9f07\u9f08\u9f09\u9f0a\u9f0b\u9f0c\u9f0d\u9f0e\u9f0f\u9f10\u9f11\u9f12\u9f13\u9f14\u9f15\u9f16\u9f17\u9f18\u9f19\u9f1a\u9f1b\u9f1c\u9f1d\u9f1e\u9f1f\u9f20\u9f21\u9f22\u9f23\u9f24\u9f25\u9f26\u9f27\u9f28\u9f29\u9f2a\u9f2b\u9f2c\u9f2d\u9f2e\u9f2f\u9f30\u9f31\u9f32\u9f33\u9f34\u9f35\u9f36\u9f37\u9f38\u9f39\u9f3a\u9f3b\u9f3c\u9f3d\u9f3e\u9f3f\u9f40\u9f41\u9f42\u9f43\u9f44\u9f45\u9f46\u9f47\u9f48\u9f49\u9f4a\u9f4b\u9f4c\u9f4d\u9f4e\u9f4f\u9f50\u9f51\u9f52\u9f53\u9f54\u9f55\u9f56\u9f57\u9f58\u9f59\u9f5a\u9f5b\u9f5c\u9f5d\u9f5e\u9f5f\u9f60\u9f61\u9f62\u9f63\u9f64\u9f65\u9f66\u9f67\u9f68\u9f69\u9f6a\u9f6b\u9f6c\u9f6d\u9f6e\u9f6f\u9f70\u9f71\u9f72\u9f73\u9f74\u9f75\u9f76\u9f77\u9f78\u9f79\u9f7a\u9f7b\u9f7c\u9f7d\u9f7e\u9f7f\u9f80\u9f81\u9f82\u9f83\u9f84\u9f85\u9f86\u9f87\u9f88\u9f89\u9f8a\u9f8b\u9f8c\u9f8d\u9f8e\u9f8f\u9f90\u9f91\u9f92\u9f93\u9f94\u9f95\u9f96\u9f97\u9f98\u9f99\u9f9a\u9f9b\u9f9c\u9f9d\u9f9e\u9f9f\u9fa0\u9fa1\u9fa2\u9fa3\u9fa4\u9fa5\u9fa6\u9fa7\u9fa8\u9fa9\u9faa\u9fab\u9fac\u9fad\u9fae\u9faf\u9fb0\u9fb1\u9fb2\u9fb3\u9fb4\u9fb5\u9fb6\u9fb7\u9fb8\u9fb9\u9fba\u9fbb\ua000\ua001\ua002\ua003\ua004\ua005\ua006\ua007\ua008\ua009\ua00a\ua00b\ua00c\ua00d\ua00e\ua00f\ua010\ua011\ua012\ua013\ua014\ua016\ua017\ua018\ua019\ua01a\ua01b\ua01c\ua01d\ua01e\ua01f\ua020\ua021\ua022\ua023\ua024\ua025\ua026\ua027\ua028\ua029\ua02a\ua02b\ua02c\ua02d\ua02e\ua02f\ua030\ua031\ua032\ua033\ua034\ua035\ua036\ua037\ua038\ua039\ua03a\ua03b\ua03c\ua03d\ua03e\ua03f\ua040\ua041\ua042\ua043\ua044\ua045\ua046\ua047\ua048\ua049\ua04a\ua04b\ua04c\ua04d\ua04e\ua04f\ua050\ua051\ua052\ua053\ua054\ua055\ua056\ua057\ua058\ua059\ua05a\ua05b\ua05c\ua05d\ua05e\ua05f\ua060\ua061\ua062\ua063\ua064\ua065\ua066\ua067\ua068\ua069\ua06a\ua06b\ua06c\ua06d\ua06e\ua06f\ua070\ua071\ua072\ua073\ua074\ua075\ua076\ua077\ua078\ua079\ua07a\ua07b\ua07c\ua07d\ua07e\ua07f\ua080\ua081\ua082\ua083\ua084\ua085\ua086\ua087\ua088\ua089\ua08a\ua08b\ua08c\ua08d\ua08e\ua08f\ua090\ua091\ua092\ua093\ua094\ua095\ua096\ua097\ua098\ua099\ua09a\ua09b\ua09c\ua09d\ua09e\ua09f\ua0a0\ua0a1\ua0a2\ua0a3\ua0a4\ua0a5\ua0a6\ua0a7\ua0a8\ua0a9\ua0aa\ua0ab\ua0ac\ua0ad\ua0ae\ua0af\ua0b0\ua0b1\ua0b2\ua0b3\ua0b4\ua0b5\ua0b6\ua0b7\ua0b8\ua0b9\ua0ba\ua0bb\ua0bc\ua0bd\ua0be\ua0bf\ua0c0\ua0c1\ua0c2\ua0c3\ua0c4\ua0c5\ua0c6\ua0c7\ua0c8\ua0c9\ua0ca\ua0cb\ua0cc\ua0cd\ua0ce\ua0cf\ua0d0\ua0d1\ua0d2\ua0d3\ua0d4\ua0d5\ua0d6\ua0d7\ua0d8\ua0d9\ua0da\ua0db\ua0dc\ua0dd\ua0de\ua0df\ua0e0\ua0e1\ua0e2\ua0e3\ua0e4\ua0e5\ua0e6\ua0e7\ua0e8\ua0e9\ua0ea\ua0eb\ua0ec\ua0ed\ua0ee\ua0ef\ua0f0\ua0f1\ua0f2\ua0f3\ua0f4\ua0f5\ua0f6\ua0f7\ua0f8\ua0f9\ua0fa\ua0fb\ua0fc\ua0fd\ua0fe\ua0ff\ua100\ua101\ua102\ua103\ua104\ua105\ua106\ua107\ua108\ua109\ua10a\ua10b\ua10c\ua10d\ua10e\ua10f\ua110\ua111\ua112\ua113\ua114\ua115\ua116\ua117\ua118\ua119\ua11a\ua11b\ua11c\ua11d\ua11e\ua11f\ua120\ua121\ua122\ua123\ua124\ua125\ua126\ua127\ua128\ua129\ua12a\ua12b\ua12c\ua12d\ua12e\ua12f\ua130\ua131\ua132\ua133\ua134\ua135\ua136\ua137\ua138\ua139\ua13a\ua13b\ua13c\ua13d\ua13e\ua13f\ua140\ua141\ua142\ua143\ua144\ua145\ua146\ua147\ua148\ua149\ua14a\ua14b\ua14c\ua14d\ua14e\ua14f\ua150\ua151\ua152\ua153\ua154\ua155\ua156\ua157\ua158\ua159\ua15a\ua15b\ua15c\ua15d\ua15e\ua15f\ua160\ua161\ua162\ua163\ua164\ua165\ua166\ua167\ua168\ua169\ua16a\ua16b\ua16c\ua16d\ua16e\ua16f\ua170\ua171\ua172\ua173\ua174\ua175\ua176\ua177\ua178\ua179\ua17a\ua17b\ua17c\ua17d\ua17e\ua17f\ua180\ua181\ua182\ua183\ua184\ua185\ua186\ua187\ua188\ua189\ua18a\ua18b\ua18c\ua18d\ua18e\ua18f\ua190\ua191\ua192\ua193\ua194\ua195\ua196\ua197\ua198\ua199\ua19a\ua19b\ua19c\ua19d\ua19e\ua19f\ua1a0\ua1a1\ua1a2\ua1a3\ua1a4\ua1a5\ua1a6\ua1a7\ua1a8\ua1a9\ua1aa\ua1ab\ua1ac\ua1ad\ua1ae\ua1af\ua1b0\ua1b1\ua1b2\ua1b3\ua1b4\ua1b5\ua1b6\ua1b7\ua1b8\ua1b9\ua1ba\ua1bb\ua1bc\ua1bd\ua1be\ua1bf\ua1c0\ua1c1\ua1c2\ua1c3\ua1c4\ua1c5\ua1c6\ua1c7\ua1c8\ua1c9\ua1ca\ua1cb\ua1cc\ua1cd\ua1ce\ua1cf\ua1d0\ua1d1\ua1d2\ua1d3\ua1d4\ua1d5\ua1d6\ua1d7\ua1d8\ua1d9\ua1da\ua1db\ua1dc\ua1dd\ua1de\ua1df\ua1e0\ua1e1\ua1e2\ua1e3\ua1e4\ua1e5\ua1e6\ua1e7\ua1e8\ua1e9\ua1ea\ua1eb\ua1ec\ua1ed\ua1ee\ua1ef\ua1f0\ua1f1\ua1f2\ua1f3\ua1f4\ua1f5\ua1f6\ua1f7\ua1f8\ua1f9\ua1fa\ua1fb\ua1fc\ua1fd\ua1fe\ua1ff\ua200\ua201\ua202\ua203\ua204\ua205\ua206\ua207\ua208\ua209\ua20a\ua20b\ua20c\ua20d\ua20e\ua20f\ua210\ua211\ua212\ua213\ua214\ua215\ua216\ua217\ua218\ua219\ua21a\ua21b\ua21c\ua21d\ua21e\ua21f\ua220\ua221\ua222\ua223\ua224\ua225\ua226\ua227\ua228\ua229\ua22a\ua22b\ua22c\ua22d\ua22e\ua22f\ua230\ua231\ua232\ua233\ua234\ua235\ua236\ua237\ua238\ua239\ua23a\ua23b\ua23c\ua23d\ua23e\ua23f\ua240\ua241\ua242\ua243\ua244\ua245\ua246\ua247\ua248\ua249\ua24a\ua24b\ua24c\ua24d\ua24e\ua24f\ua250\ua251\ua252\ua253\ua254\ua255\ua256\ua257\ua258\ua259\ua25a\ua25b\ua25c\ua25d\ua25e\ua25f\ua260\ua261\ua262\ua263\ua264\ua265\ua266\ua267\ua268\ua269\ua26a\ua26b\ua26c\ua26d\ua26e\ua26f\ua270\ua271\ua272\ua273\ua274\ua275\ua276\ua277\ua278\ua279\ua27a\ua27b\ua27c\ua27d\ua27e\ua27f\ua280\ua281\ua282\ua283\ua284\ua285\ua286\ua287\ua288\ua289\ua28a\ua28b\ua28c\ua28d\ua28e\ua28f\ua290\ua291\ua292\ua293\ua294\ua295\ua296\ua297\ua298\ua299\ua29a\ua29b\ua29c\ua29d\ua29e\ua29f\ua2a0\ua2a1\ua2a2\ua2a3\ua2a4\ua2a5\ua2a6\ua2a7\ua2a8\ua2a9\ua2aa\ua2ab\ua2ac\ua2ad\ua2ae\ua2af\ua2b0\ua2b1\ua2b2\ua2b3\ua2b4\ua2b5\ua2b6\ua2b7\ua2b8\ua2b9\ua2ba\ua2bb\ua2bc\ua2bd\ua2be\ua2bf\ua2c0\ua2c1\ua2c2\ua2c3\ua2c4\ua2c5\ua2c6\ua2c7\ua2c8\ua2c9\ua2ca\ua2cb\ua2cc\ua2cd\ua2ce\ua2cf\ua2d0\ua2d1\ua2d2\ua2d3\ua2d4\ua2d5\ua2d6\ua2d7\ua2d8\ua2d9\ua2da\ua2db\ua2dc\ua2dd\ua2de\ua2df\ua2e0\ua2e1\ua2e2\ua2e3\ua2e4\ua2e5\ua2e6\ua2e7\ua2e8\ua2e9\ua2ea\ua2eb\ua2ec\ua2ed\ua2ee\ua2ef\ua2f0\ua2f1\ua2f2\ua2f3\ua2f4\ua2f5\ua2f6\ua2f7\ua2f8\ua2f9\ua2fa\ua2fb\ua2fc\ua2fd\ua2fe\ua2ff\ua300\ua301\ua302\ua303\ua304\ua305\ua306\ua307\ua308\ua309\ua30a\ua30b\ua30c\ua30d\ua30e\ua30f\ua310\ua311\ua312\ua313\ua314\ua315\ua316\ua317\ua318\ua319\ua31a\ua31b\ua31c\ua31d\ua31e\ua31f\ua320\ua321\ua322\ua323\ua324\ua325\ua326\ua327\ua328\ua329\ua32a\ua32b\ua32c\ua32d\ua32e\ua32f\ua330\ua331\ua332\ua333\ua334\ua335\ua336\ua337\ua338\ua339\ua33a\ua33b\ua33c\ua33d\ua33e\ua33f\ua340\ua341\ua342\ua343\ua344\ua345\ua346\ua347\ua348\ua349\ua34a\ua34b\ua34c\ua34d\ua34e\ua34f\ua350\ua351\ua352\ua353\ua354\ua355\ua356\ua357\ua358\ua359\ua35a\ua35b\ua35c\ua35d\ua35e\ua35f\ua360\ua361\ua362\ua363\ua364\ua365\ua366\ua367\ua368\ua369\ua36a\ua36b\ua36c\ua36d\ua36e\ua36f\ua370\ua371\ua372\ua373\ua374\ua375\ua376\ua377\ua378\ua379\ua37a\ua37b\ua37c\ua37d\ua37e\ua37f\ua380\ua381\ua382\ua383\ua384\ua385\ua386\ua387\ua388\ua389\ua38a\ua38b\ua38c\ua38d\ua38e\ua38f\ua390\ua391\ua392\ua393\ua394\ua395\ua396\ua397\ua398\ua399\ua39a\ua39b\ua39c\ua39d\ua39e\ua39f\ua3a0\ua3a1\ua3a2\ua3a3\ua3a4\ua3a5\ua3a6\ua3a7\ua3a8\ua3a9\ua3aa\ua3ab\ua3ac\ua3ad\ua3ae\ua3af\ua3b0\ua3b1\ua3b2\ua3b3\ua3b4\ua3b5\ua3b6\ua3b7\ua3b8\ua3b9\ua3ba\ua3bb\ua3bc\ua3bd\ua3be\ua3bf\ua3c0\ua3c1\ua3c2\ua3c3\ua3c4\ua3c5\ua3c6\ua3c7\ua3c8\ua3c9\ua3ca\ua3cb\ua3cc\ua3cd\ua3ce\ua3cf\ua3d0\ua3d1\ua3d2\ua3d3\ua3d4\ua3d5\ua3d6\ua3d7\ua3d8\ua3d9\ua3da\ua3db\ua3dc\ua3dd\ua3de\ua3df\ua3e0\ua3e1\ua3e2\ua3e3\ua3e4\ua3e5\ua3e6\ua3e7\ua3e8\ua3e9\ua3ea\ua3eb\ua3ec\ua3ed\ua3ee\ua3ef\ua3f0\ua3f1\ua3f2\ua3f3\ua3f4\ua3f5\ua3f6\ua3f7\ua3f8\ua3f9\ua3fa\ua3fb\ua3fc\ua3fd\ua3fe\ua3ff\ua400\ua401\ua402\ua403\ua404\ua405\ua406\ua407\ua408\ua409\ua40a\ua40b\ua40c\ua40d\ua40e\ua40f\ua410\ua411\ua412\ua413\ua414\ua415\ua416\ua417\ua418\ua419\ua41a\ua41b\ua41c\ua41d\ua41e\ua41f\ua420\ua421\ua422\ua423\ua424\ua425\ua426\ua427\ua428\ua429\ua42a\ua42b\ua42c\ua42d\ua42e\ua42f\ua430\ua431\ua432\ua433\ua434\ua435\ua436\ua437\ua438\ua439\ua43a\ua43b\ua43c\ua43d\ua43e\ua43f\ua440\ua441\ua442\ua443\ua444\ua445\ua446\ua447\ua448\ua449\ua44a\ua44b\ua44c\ua44d\ua44e\ua44f\ua450\ua451\ua452\ua453\ua454\ua455\ua456\ua457\ua458\ua459\ua45a\ua45b\ua45c\ua45d\ua45e\ua45f\ua460\ua461\ua462\ua463\ua464\ua465\ua466\ua467\ua468\ua469\ua46a\ua46b\ua46c\ua46d\ua46e\ua46f\ua470\ua471\ua472\ua473\ua474\ua475\ua476\ua477\ua478\ua479\ua47a\ua47b\ua47c\ua47d\ua47e\ua47f\ua480\ua481\ua482\ua483\ua484\ua485\ua486\ua487\ua488\ua489\ua48a\ua48b\ua48c\ua800\ua801\ua803\ua804\ua805\ua807\ua808\ua809\ua80a\ua80c\ua80d\ua80e\ua80f\ua810\ua811\ua812\ua813\ua814\ua815\ua816\ua817\ua818\ua819\ua81a\ua81b\ua81c\ua81d\ua81e\ua81f\ua820\ua821\ua822\uac00\uac01\uac02\uac03\uac04\uac05\uac06\uac07\uac08\uac09\uac0a\uac0b\uac0c\uac0d\uac0e\uac0f\uac10\uac11\uac12\uac13\uac14\uac15\uac16\uac17\uac18\uac19\uac1a\uac1b\uac1c\uac1d\uac1e\uac1f\uac20\uac21\uac22\uac23\uac24\uac25\uac26\uac27\uac28\uac29\uac2a\uac2b\uac2c\uac2d\uac2e\uac2f\uac30\uac31\uac32\uac33\uac34\uac35\uac36\uac37\uac38\uac39\uac3a\uac3b\uac3c\uac3d\uac3e\uac3f\uac40\uac41\uac42\uac43\uac44\uac45\uac46\uac47\uac48\uac49\uac4a\uac4b\uac4c\uac4d\uac4e\uac4f\uac50\uac51\uac52\uac53\uac54\uac55\uac56\uac57\uac58\uac59\uac5a\uac5b\uac5c\uac5d\uac5e\uac5f\uac60\uac61\uac62\uac63\uac64\uac65\uac66\uac67\uac68\uac69\uac6a\uac6b\uac6c\uac6d\uac6e\uac6f\uac70\uac71\uac72\uac73\uac74\uac75\uac76\uac77\uac78\uac79\uac7a\uac7b\uac7c\uac7d\uac7e\uac7f\uac80\uac81\uac82\uac83\uac84\uac85\uac86\uac87\uac88\uac89\uac8a\uac8b\uac8c\uac8d\uac8e\uac8f\uac90\uac91\uac92\uac93\uac94\uac95\uac96\uac97\uac98\uac99\uac9a\uac9b\uac9c\uac9d\uac9e\uac9f\uaca0\uaca1\uaca2\uaca3\uaca4\uaca5\uaca6\uaca7\uaca8\uaca9\uacaa\uacab\uacac\uacad\uacae\uacaf\uacb0\uacb1\uacb2\uacb3\uacb4\uacb5\uacb6\uacb7\uacb8\uacb9\uacba\uacbb\uacbc\uacbd\uacbe\uacbf\uacc0\uacc1\uacc2\uacc3\uacc4\uacc5\uacc6\uacc7\uacc8\uacc9\uacca\uaccb\uaccc\uaccd\uacce\uaccf\uacd0\uacd1\uacd2\uacd3\uacd4\uacd5\uacd6\uacd7\uacd8\uacd9\uacda\uacdb\uacdc\uacdd\uacde\uacdf\uace0\uace1\uace2\uace3\uace4\uace5\uace6\uace7\uace8\uace9\uacea\uaceb\uacec\uaced\uacee\uacef\uacf0\uacf1\uacf2\uacf3\uacf4\uacf5\uacf6\uacf7\uacf8\uacf9\uacfa\uacfb\uacfc\uacfd\uacfe\uacff\uad00\uad01\uad02\uad03\uad04\uad05\uad06\uad07\uad08\uad09\uad0a\uad0b\uad0c\uad0d\uad0e\uad0f\uad10\uad11\uad12\uad13\uad14\uad15\uad16\uad17\uad18\uad19\uad1a\uad1b\uad1c\uad1d\uad1e\uad1f\uad20\uad21\uad22\uad23\uad24\uad25\uad26\uad27\uad28\uad29\uad2a\uad2b\uad2c\uad2d\uad2e\uad2f\uad30\uad31\uad32\uad33\uad34\uad35\uad36\uad37\uad38\uad39\uad3a\uad3b\uad3c\uad3d\uad3e\uad3f\uad40\uad41\uad42\uad43\uad44\uad45\uad46\uad47\uad48\uad49\uad4a\uad4b\uad4c\uad4d\uad4e\uad4f\uad50\uad51\uad52\uad53\uad54\uad55\uad56\uad57\uad58\uad59\uad5a\uad5b\uad5c\uad5d\uad5e\uad5f\uad60\uad61\uad62\uad63\uad64\uad65\uad66\uad67\uad68\uad69\uad6a\uad6b\uad6c\uad6d\uad6e\uad6f\uad70\uad71\uad72\uad73\uad74\uad75\uad76\uad77\uad78\uad79\uad7a\uad7b\uad7c\uad7d\uad7e\uad7f\uad80\uad81\uad82\uad83\uad84\uad85\uad86\uad87\uad88\uad89\uad8a\uad8b\uad8c\uad8d\uad8e\uad8f\uad90\uad91\uad92\uad93\uad94\uad95\uad96\uad97\uad98\uad99\uad9a\uad9b\uad9c\uad9d\uad9e\uad9f\uada0\uada1\uada2\uada3\uada4\uada5\uada6\uada7\uada8\uada9\uadaa\uadab\uadac\uadad\uadae\uadaf\uadb0\uadb1\uadb2\uadb3\uadb4\uadb5\uadb6\uadb7\uadb8\uadb9\uadba\uadbb\uadbc\uadbd\uadbe\uadbf\uadc0\uadc1\uadc2\uadc3\uadc4\uadc5\uadc6\uadc7\uadc8\uadc9\uadca\uadcb\uadcc\uadcd\uadce\uadcf\uadd0\uadd1\uadd2\uadd3\uadd4\uadd5\uadd6\uadd7\uadd8\uadd9\uadda\uaddb\uaddc\uaddd\uadde\uaddf\uade0\uade1\uade2\uade3\uade4\uade5\uade6\uade7\uade8\uade9\uadea\uadeb\uadec\uaded\uadee\uadef\uadf0\uadf1\uadf2\uadf3\uadf4\uadf5\uadf6\uadf7\uadf8\uadf9\uadfa\uadfb\uadfc\uadfd\uadfe\uadff\uae00\uae01\uae02\uae03\uae04\uae05\uae06\uae07\uae08\uae09\uae0a\uae0b\uae0c\uae0d\uae0e\uae0f\uae10\uae11\uae12\uae13\uae14\uae15\uae16\uae17\uae18\uae19\uae1a\uae1b\uae1c\uae1d\uae1e\uae1f\uae20\uae21\uae22\uae23\uae24\uae25\uae26\uae27\uae28\uae29\uae2a\uae2b\uae2c\uae2d\uae2e\uae2f\uae30\uae31\uae32\uae33\uae34\uae35\uae36\uae37\uae38\uae39\uae3a\uae3b\uae3c\uae3d\uae3e\uae3f\uae40\uae41\uae42\uae43\uae44\uae45\uae46\uae47\uae48\uae49\uae4a\uae4b\uae4c\uae4d\uae4e\uae4f\uae50\uae51\uae52\uae53\uae54\uae55\uae56\uae57\uae58\uae59\uae5a\uae5b\uae5c\uae5d\uae5e\uae5f\uae60\uae61\uae62\uae63\uae64\uae65\uae66\uae67\uae68\uae69\uae6a\uae6b\uae6c\uae6d\uae6e\uae6f\uae70\uae71\uae72\uae73\uae74\uae75\uae76\uae77\uae78\uae79\uae7a\uae7b\uae7c\uae7d\uae7e\uae7f\uae80\uae81\uae82\uae83\uae84\uae85\uae86\uae87\uae88\uae89\uae8a\uae8b\uae8c\uae8d\uae8e\uae8f\uae90\uae91\uae92\uae93\uae94\uae95\uae96\uae97\uae98\uae99\uae9a\uae9b\uae9c\uae9d\uae9e\uae9f\uaea0\uaea1\uaea2\uaea3\uaea4\uaea5\uaea6\uaea7\uaea8\uaea9\uaeaa\uaeab\uaeac\uaead\uaeae\uaeaf\uaeb0\uaeb1\uaeb2\uaeb3\uaeb4\uaeb5\uaeb6\uaeb7\uaeb8\uaeb9\uaeba\uaebb\uaebc\uaebd\uaebe\uaebf\uaec0\uaec1\uaec2\uaec3\uaec4\uaec5\uaec6\uaec7\uaec8\uaec9\uaeca\uaecb\uaecc\uaecd\uaece\uaecf\uaed0\uaed1\uaed2\uaed3\uaed4\uaed5\uaed6\uaed7\uaed8\uaed9\uaeda\uaedb\uaedc\uaedd\uaede\uaedf\uaee0\uaee1\uaee2\uaee3\uaee4\uaee5\uaee6\uaee7\uaee8\uaee9\uaeea\uaeeb\uaeec\uaeed\uaeee\uaeef\uaef0\uaef1\uaef2\uaef3\uaef4\uaef5\uaef6\uaef7\uaef8\uaef9\uaefa\uaefb\uaefc\uaefd\uaefe\uaeff\uaf00\uaf01\uaf02\uaf03\uaf04\uaf05\uaf06\uaf07\uaf08\uaf09\uaf0a\uaf0b\uaf0c\uaf0d\uaf0e\uaf0f\uaf10\uaf11\uaf12\uaf13\uaf14\uaf15\uaf16\uaf17\uaf18\uaf19\uaf1a\uaf1b\uaf1c\uaf1d\uaf1e\uaf1f\uaf20\uaf21\uaf22\uaf23\uaf24\uaf25\uaf26\uaf27\uaf28\uaf29\uaf2a\uaf2b\uaf2c\uaf2d\uaf2e\uaf2f\uaf30\uaf31\uaf32\uaf33\uaf34\uaf35\uaf36\uaf37\uaf38\uaf39\uaf3a\uaf3b\uaf3c\uaf3d\uaf3e\uaf3f\uaf40\uaf41\uaf42\uaf43\uaf44\uaf45\uaf46\uaf47\uaf48\uaf49\uaf4a\uaf4b\uaf4c\uaf4d\uaf4e\uaf4f\uaf50\uaf51\uaf52\uaf53\uaf54\uaf55\uaf56\uaf57\uaf58\uaf59\uaf5a\uaf5b\uaf5c\uaf5d\uaf5e\uaf5f\uaf60\uaf61\uaf62\uaf63\uaf64\uaf65\uaf66\uaf67\uaf68\uaf69\uaf6a\uaf6b\uaf6c\uaf6d\uaf6e\uaf6f\uaf70\uaf71\uaf72\uaf73\uaf74\uaf75\uaf76\uaf77\uaf78\uaf79\uaf7a\uaf7b\uaf7c\uaf7d\uaf7e\uaf7f\uaf80\uaf81\uaf82\uaf83\uaf84\uaf85\uaf86\uaf87\uaf88\uaf89\uaf8a\uaf8b\uaf8c\uaf8d\uaf8e\uaf8f\uaf90\uaf91\uaf92\uaf93\uaf94\uaf95\uaf96\uaf97\uaf98\uaf99\uaf9a\uaf9b\uaf9c\uaf9d\uaf9e\uaf9f\uafa0\uafa1\uafa2\uafa3\uafa4\uafa5\uafa6\uafa7\uafa8\uafa9\uafaa\uafab\uafac\uafad\uafae\uafaf\uafb0\uafb1\uafb2\uafb3\uafb4\uafb5\uafb6\uafb7\uafb8\uafb9\uafba\uafbb\uafbc\uafbd\uafbe\uafbf\uafc0\uafc1\uafc2\uafc3\uafc4\uafc5\uafc6\uafc7\uafc8\uafc9\uafca\uafcb\uafcc\uafcd\uafce\uafcf\uafd0\uafd1\uafd2\uafd3\uafd4\uafd5\uafd6\uafd7\uafd8\uafd9\uafda\uafdb\uafdc\uafdd\uafde\uafdf\uafe0\uafe1\uafe2\uafe3\uafe4\uafe5\uafe6\uafe7\uafe8\uafe9\uafea\uafeb\uafec\uafed\uafee\uafef\uaff0\uaff1\uaff2\uaff3\uaff4\uaff5\uaff6\uaff7\uaff8\uaff9\uaffa\uaffb\uaffc\uaffd\uaffe\uafff\ub000\ub001\ub002\ub003\ub004\ub005\ub006\ub007\ub008\ub009\ub00a\ub00b\ub00c\ub00d\ub00e\ub00f\ub010\ub011\ub012\ub013\ub014\ub015\ub016\ub017\ub018\ub019\ub01a\ub01b\ub01c\ub01d\ub01e\ub01f\ub020\ub021\ub022\ub023\ub024\ub025\ub026\ub027\ub028\ub029\ub02a\ub02b\ub02c\ub02d\ub02e\ub02f\ub030\ub031\ub032\ub033\ub034\ub035\ub036\ub037\ub038\ub039\ub03a\ub03b\ub03c\ub03d\ub03e\ub03f\ub040\ub041\ub042\ub043\ub044\ub045\ub046\ub047\ub048\ub049\ub04a\ub04b\ub04c\ub04d\ub04e\ub04f\ub050\ub051\ub052\ub053\ub054\ub055\ub056\ub057\ub058\ub059\ub05a\ub05b\ub05c\ub05d\ub05e\ub05f\ub060\ub061\ub062\ub063\ub064\ub065\ub066\ub067\ub068\ub069\ub06a\ub06b\ub06c\ub06d\ub06e\ub06f\ub070\ub071\ub072\ub073\ub074\ub075\ub076\ub077\ub078\ub079\ub07a\ub07b\ub07c\ub07d\ub07e\ub07f\ub080\ub081\ub082\ub083\ub084\ub085\ub086\ub087\ub088\ub089\ub08a\ub08b\ub08c\ub08d\ub08e\ub08f\ub090\ub091\ub092\ub093\ub094\ub095\ub096\ub097\ub098\ub099\ub09a\ub09b\ub09c\ub09d\ub09e\ub09f\ub0a0\ub0a1\ub0a2\ub0a3\ub0a4\ub0a5\ub0a6\ub0a7\ub0a8\ub0a9\ub0aa\ub0ab\ub0ac\ub0ad\ub0ae\ub0af\ub0b0\ub0b1\ub0b2\ub0b3\ub0b4\ub0b5\ub0b6\ub0b7\ub0b8\ub0b9\ub0ba\ub0bb\ub0bc\ub0bd\ub0be\ub0bf\ub0c0\ub0c1\ub0c2\ub0c3\ub0c4\ub0c5\ub0c6\ub0c7\ub0c8\ub0c9\ub0ca\ub0cb\ub0cc\ub0cd\ub0ce\ub0cf\ub0d0\ub0d1\ub0d2\ub0d3\ub0d4\ub0d5\ub0d6\ub0d7\ub0d8\ub0d9\ub0da\ub0db\ub0dc\ub0dd\ub0de\ub0df\ub0e0\ub0e1\ub0e2\ub0e3\ub0e4\ub0e5\ub0e6\ub0e7\ub0e8\ub0e9\ub0ea\ub0eb\ub0ec\ub0ed\ub0ee\ub0ef\ub0f0\ub0f1\ub0f2\ub0f3\ub0f4\ub0f5\ub0f6\ub0f7\ub0f8\ub0f9\ub0fa\ub0fb\ub0fc\ub0fd\ub0fe\ub0ff\ub100\ub101\ub102\ub103\ub104\ub105\ub106\ub107\ub108\ub109\ub10a\ub10b\ub10c\ub10d\ub10e\ub10f\ub110\ub111\ub112\ub113\ub114\ub115\ub116\ub117\ub118\ub119\ub11a\ub11b\ub11c\ub11d\ub11e\ub11f\ub120\ub121\ub122\ub123\ub124\ub125\ub126\ub127\ub128\ub129\ub12a\ub12b\ub12c\ub12d\ub12e\ub12f\ub130\ub131\ub132\ub133\ub134\ub135\ub136\ub137\ub138\ub139\ub13a\ub13b\ub13c\ub13d\ub13e\ub13f\ub140\ub141\ub142\ub143\ub144\ub145\ub146\ub147\ub148\ub149\ub14a\ub14b\ub14c\ub14d\ub14e\ub14f\ub150\ub151\ub152\ub153\ub154\ub155\ub156\ub157\ub158\ub159\ub15a\ub15b\ub15c\ub15d\ub15e\ub15f\ub160\ub161\ub162\ub163\ub164\ub165\ub166\ub167\ub168\ub169\ub16a\ub16b\ub16c\ub16d\ub16e\ub16f\ub170\ub171\ub172\ub173\ub174\ub175\ub176\ub177\ub178\ub179\ub17a\ub17b\ub17c\ub17d\ub17e\ub17f\ub180\ub181\ub182\ub183\ub184\ub185\ub186\ub187\ub188\ub189\ub18a\ub18b\ub18c\ub18d\ub18e\ub18f\ub190\ub191\ub192\ub193\ub194\ub195\ub196\ub197\ub198\ub199\ub19a\ub19b\ub19c\ub19d\ub19e\ub19f\ub1a0\ub1a1\ub1a2\ub1a3\ub1a4\ub1a5\ub1a6\ub1a7\ub1a8\ub1a9\ub1aa\ub1ab\ub1ac\ub1ad\ub1ae\ub1af\ub1b0\ub1b1\ub1b2\ub1b3\ub1b4\ub1b5\ub1b6\ub1b7\ub1b8\ub1b9\ub1ba\ub1bb\ub1bc\ub1bd\ub1be\ub1bf\ub1c0\ub1c1\ub1c2\ub1c3\ub1c4\ub1c5\ub1c6\ub1c7\ub1c8\ub1c9\ub1ca\ub1cb\ub1cc\ub1cd\ub1ce\ub1cf\ub1d0\ub1d1\ub1d2\ub1d3\ub1d4\ub1d5\ub1d6\ub1d7\ub1d8\ub1d9\ub1da\ub1db\ub1dc\ub1dd\ub1de\ub1df\ub1e0\ub1e1\ub1e2\ub1e3\ub1e4\ub1e5\ub1e6\ub1e7\ub1e8\ub1e9\ub1ea\ub1eb\ub1ec\ub1ed\ub1ee\ub1ef\ub1f0\ub1f1\ub1f2\ub1f3\ub1f4\ub1f5\ub1f6\ub1f7\ub1f8\ub1f9\ub1fa\ub1fb\ub1fc\ub1fd\ub1fe\ub1ff\ub200\ub201\ub202\ub203\ub204\ub205\ub206\ub207\ub208\ub209\ub20a\ub20b\ub20c\ub20d\ub20e\ub20f\ub210\ub211\ub212\ub213\ub214\ub215\ub216\ub217\ub218\ub219\ub21a\ub21b\ub21c\ub21d\ub21e\ub21f\ub220\ub221\ub222\ub223\ub224\ub225\ub226\ub227\ub228\ub229\ub22a\ub22b\ub22c\ub22d\ub22e\ub22f\ub230\ub231\ub232\ub233\ub234\ub235\ub236\ub237\ub238\ub239\ub23a\ub23b\ub23c\ub23d\ub23e\ub23f\ub240\ub241\ub242\ub243\ub244\ub245\ub246\ub247\ub248\ub249\ub24a\ub24b\ub24c\ub24d\ub24e\ub24f\ub250\ub251\ub252\ub253\ub254\ub255\ub256\ub257\ub258\ub259\ub25a\ub25b\ub25c\ub25d\ub25e\ub25f\ub260\ub261\ub262\ub263\ub264\ub265\ub266\ub267\ub268\ub269\ub26a\ub26b\ub26c\ub26d\ub26e\ub26f\ub270\ub271\ub272\ub273\ub274\ub275\ub276\ub277\ub278\ub279\ub27a\ub27b\ub27c\ub27d\ub27e\ub27f\ub280\ub281\ub282\ub283\ub284\ub285\ub286\ub287\ub288\ub289\ub28a\ub28b\ub28c\ub28d\ub28e\ub28f\ub290\ub291\ub292\ub293\ub294\ub295\ub296\ub297\ub298\ub299\ub29a\ub29b\ub29c\ub29d\ub29e\ub29f\ub2a0\ub2a1\ub2a2\ub2a3\ub2a4\ub2a5\ub2a6\ub2a7\ub2a8\ub2a9\ub2aa\ub2ab\ub2ac\ub2ad\ub2ae\ub2af\ub2b0\ub2b1\ub2b2\ub2b3\ub2b4\ub2b5\ub2b6\ub2b7\ub2b8\ub2b9\ub2ba\ub2bb\ub2bc\ub2bd\ub2be\ub2bf\ub2c0\ub2c1\ub2c2\ub2c3\ub2c4\ub2c5\ub2c6\ub2c7\ub2c8\ub2c9\ub2ca\ub2cb\ub2cc\ub2cd\ub2ce\ub2cf\ub2d0\ub2d1\ub2d2\ub2d3\ub2d4\ub2d5\ub2d6\ub2d7\ub2d8\ub2d9\ub2da\ub2db\ub2dc\ub2dd\ub2de\ub2df\ub2e0\ub2e1\ub2e2\ub2e3\ub2e4\ub2e5\ub2e6\ub2e7\ub2e8\ub2e9\ub2ea\ub2eb\ub2ec\ub2ed\ub2ee\ub2ef\ub2f0\ub2f1\ub2f2\ub2f3\ub2f4\ub2f5\ub2f6\ub2f7\ub2f8\ub2f9\ub2fa\ub2fb\ub2fc\ub2fd\ub2fe\ub2ff\ub300\ub301\ub302\ub303\ub304\ub305\ub306\ub307\ub308\ub309\ub30a\ub30b\ub30c\ub30d\ub30e\ub30f\ub310\ub311\ub312\ub313\ub314\ub315\ub316\ub317\ub318\ub319\ub31a\ub31b\ub31c\ub31d\ub31e\ub31f\ub320\ub321\ub322\ub323\ub324\ub325\ub326\ub327\ub328\ub329\ub32a\ub32b\ub32c\ub32d\ub32e\ub32f\ub330\ub331\ub332\ub333\ub334\ub335\ub336\ub337\ub338\ub339\ub33a\ub33b\ub33c\ub33d\ub33e\ub33f\ub340\ub341\ub342\ub343\ub344\ub345\ub346\ub347\ub348\ub349\ub34a\ub34b\ub34c\ub34d\ub34e\ub34f\ub350\ub351\ub352\ub353\ub354\ub355\ub356\ub357\ub358\ub359\ub35a\ub35b\ub35c\ub35d\ub35e\ub35f\ub360\ub361\ub362\ub363\ub364\ub365\ub366\ub367\ub368\ub369\ub36a\ub36b\ub36c\ub36d\ub36e\ub36f\ub370\ub371\ub372\ub373\ub374\ub375\ub376\ub377\ub378\ub379\ub37a\ub37b\ub37c\ub37d\ub37e\ub37f\ub380\ub381\ub382\ub383\ub384\ub385\ub386\ub387\ub388\ub389\ub38a\ub38b\ub38c\ub38d\ub38e\ub38f\ub390\ub391\ub392\ub393\ub394\ub395\ub396\ub397\ub398\ub399\ub39a\ub39b\ub39c\ub39d\ub39e\ub39f\ub3a0\ub3a1\ub3a2\ub3a3\ub3a4\ub3a5\ub3a6\ub3a7\ub3a8\ub3a9\ub3aa\ub3ab\ub3ac\ub3ad\ub3ae\ub3af\ub3b0\ub3b1\ub3b2\ub3b3\ub3b4\ub3b5\ub3b6\ub3b7\ub3b8\ub3b9\ub3ba\ub3bb\ub3bc\ub3bd\ub3be\ub3bf\ub3c0\ub3c1\ub3c2\ub3c3\ub3c4\ub3c5\ub3c6\ub3c7\ub3c8\ub3c9\ub3ca\ub3cb\ub3cc\ub3cd\ub3ce\ub3cf\ub3d0\ub3d1\ub3d2\ub3d3\ub3d4\ub3d5\ub3d6\ub3d7\ub3d8\ub3d9\ub3da\ub3db\ub3dc\ub3dd\ub3de\ub3df\ub3e0\ub3e1\ub3e2\ub3e3\ub3e4\ub3e5\ub3e6\ub3e7\ub3e8\ub3e9\ub3ea\ub3eb\ub3ec\ub3ed\ub3ee\ub3ef\ub3f0\ub3f1\ub3f2\ub3f3\ub3f4\ub3f5\ub3f6\ub3f7\ub3f8\ub3f9\ub3fa\ub3fb\ub3fc\ub3fd\ub3fe\ub3ff\ub400\ub401\ub402\ub403\ub404\ub405\ub406\ub407\ub408\ub409\ub40a\ub40b\ub40c\ub40d\ub40e\ub40f\ub410\ub411\ub412\ub413\ub414\ub415\ub416\ub417\ub418\ub419\ub41a\ub41b\ub41c\ub41d\ub41e\ub41f\ub420\ub421\ub422\ub423\ub424\ub425\ub426\ub427\ub428\ub429\ub42a\ub42b\ub42c\ub42d\ub42e\ub42f\ub430\ub431\ub432\ub433\ub434\ub435\ub436\ub437\ub438\ub439\ub43a\ub43b\ub43c\ub43d\ub43e\ub43f\ub440\ub441\ub442\ub443\ub444\ub445\ub446\ub447\ub448\ub449\ub44a\ub44b\ub44c\ub44d\ub44e\ub44f\ub450\ub451\ub452\ub453\ub454\ub455\ub456\ub457\ub458\ub459\ub45a\ub45b\ub45c\ub45d\ub45e\ub45f\ub460\ub461\ub462\ub463\ub464\ub465\ub466\ub467\ub468\ub469\ub46a\ub46b\ub46c\ub46d\ub46e\ub46f\ub470\ub471\ub472\ub473\ub474\ub475\ub476\ub477\ub478\ub479\ub47a\ub47b\ub47c\ub47d\ub47e\ub47f\ub480\ub481\ub482\ub483\ub484\ub485\ub486\ub487\ub488\ub489\ub48a\ub48b\ub48c\ub48d\ub48e\ub48f\ub490\ub491\ub492\ub493\ub494\ub495\ub496\ub497\ub498\ub499\ub49a\ub49b\ub49c\ub49d\ub49e\ub49f\ub4a0\ub4a1\ub4a2\ub4a3\ub4a4\ub4a5\ub4a6\ub4a7\ub4a8\ub4a9\ub4aa\ub4ab\ub4ac\ub4ad\ub4ae\ub4af\ub4b0\ub4b1\ub4b2\ub4b3\ub4b4\ub4b5\ub4b6\ub4b7\ub4b8\ub4b9\ub4ba\ub4bb\ub4bc\ub4bd\ub4be\ub4bf\ub4c0\ub4c1\ub4c2\ub4c3\ub4c4\ub4c5\ub4c6\ub4c7\ub4c8\ub4c9\ub4ca\ub4cb\ub4cc\ub4cd\ub4ce\ub4cf\ub4d0\ub4d1\ub4d2\ub4d3\ub4d4\ub4d5\ub4d6\ub4d7\ub4d8\ub4d9\ub4da\ub4db\ub4dc\ub4dd\ub4de\ub4df\ub4e0\ub4e1\ub4e2\ub4e3\ub4e4\ub4e5\ub4e6\ub4e7\ub4e8\ub4e9\ub4ea\ub4eb\ub4ec\ub4ed\ub4ee\ub4ef\ub4f0\ub4f1\ub4f2\ub4f3\ub4f4\ub4f5\ub4f6\ub4f7\ub4f8\ub4f9\ub4fa\ub4fb\ub4fc\ub4fd\ub4fe\ub4ff\ub500\ub501\ub502\ub503\ub504\ub505\ub506\ub507\ub508\ub509\ub50a\ub50b\ub50c\ub50d\ub50e\ub50f\ub510\ub511\ub512\ub513\ub514\ub515\ub516\ub517\ub518\ub519\ub51a\ub51b\ub51c\ub51d\ub51e\ub51f\ub520\ub521\ub522\ub523\ub524\ub525\ub526\ub527\ub528\ub529\ub52a\ub52b\ub52c\ub52d\ub52e\ub52f\ub530\ub531\ub532\ub533\ub534\ub535\ub536\ub537\ub538\ub539\ub53a\ub53b\ub53c\ub53d\ub53e\ub53f\ub540\ub541\ub542\ub543\ub544\ub545\ub546\ub547\ub548\ub549\ub54a\ub54b\ub54c\ub54d\ub54e\ub54f\ub550\ub551\ub552\ub553\ub554\ub555\ub556\ub557\ub558\ub559\ub55a\ub55b\ub55c\ub55d\ub55e\ub55f\ub560\ub561\ub562\ub563\ub564\ub565\ub566\ub567\ub568\ub569\ub56a\ub56b\ub56c\ub56d\ub56e\ub56f\ub570\ub571\ub572\ub573\ub574\ub575\ub576\ub577\ub578\ub579\ub57a\ub57b\ub57c\ub57d\ub57e\ub57f\ub580\ub581\ub582\ub583\ub584\ub585\ub586\ub587\ub588\ub589\ub58a\ub58b\ub58c\ub58d\ub58e\ub58f\ub590\ub591\ub592\ub593\ub594\ub595\ub596\ub597\ub598\ub599\ub59a\ub59b\ub59c\ub59d\ub59e\ub59f\ub5a0\ub5a1\ub5a2\ub5a3\ub5a4\ub5a5\ub5a6\ub5a7\ub5a8\ub5a9\ub5aa\ub5ab\ub5ac\ub5ad\ub5ae\ub5af\ub5b0\ub5b1\ub5b2\ub5b3\ub5b4\ub5b5\ub5b6\ub5b7\ub5b8\ub5b9\ub5ba\ub5bb\ub5bc\ub5bd\ub5be\ub5bf\ub5c0\ub5c1\ub5c2\ub5c3\ub5c4\ub5c5\ub5c6\ub5c7\ub5c8\ub5c9\ub5ca\ub5cb\ub5cc\ub5cd\ub5ce\ub5cf\ub5d0\ub5d1\ub5d2\ub5d3\ub5d4\ub5d5\ub5d6\ub5d7\ub5d8\ub5d9\ub5da\ub5db\ub5dc\ub5dd\ub5de\ub5df\ub5e0\ub5e1\ub5e2\ub5e3\ub5e4\ub5e5\ub5e6\ub5e7\ub5e8\ub5e9\ub5ea\ub5eb\ub5ec\ub5ed\ub5ee\ub5ef\ub5f0\ub5f1\ub5f2\ub5f3\ub5f4\ub5f5\ub5f6\ub5f7\ub5f8\ub5f9\ub5fa\ub5fb\ub5fc\ub5fd\ub5fe\ub5ff\ub600\ub601\ub602\ub603\ub604\ub605\ub606\ub607\ub608\ub609\ub60a\ub60b\ub60c\ub60d\ub60e\ub60f\ub610\ub611\ub612\ub613\ub614\ub615\ub616\ub617\ub618\ub619\ub61a\ub61b\ub61c\ub61d\ub61e\ub61f\ub620\ub621\ub622\ub623\ub624\ub625\ub626\ub627\ub628\ub629\ub62a\ub62b\ub62c\ub62d\ub62e\ub62f\ub630\ub631\ub632\ub633\ub634\ub635\ub636\ub637\ub638\ub639\ub63a\ub63b\ub63c\ub63d\ub63e\ub63f\ub640\ub641\ub642\ub643\ub644\ub645\ub646\ub647\ub648\ub649\ub64a\ub64b\ub64c\ub64d\ub64e\ub64f\ub650\ub651\ub652\ub653\ub654\ub655\ub656\ub657\ub658\ub659\ub65a\ub65b\ub65c\ub65d\ub65e\ub65f\ub660\ub661\ub662\ub663\ub664\ub665\ub666\ub667\ub668\ub669\ub66a\ub66b\ub66c\ub66d\ub66e\ub66f\ub670\ub671\ub672\ub673\ub674\ub675\ub676\ub677\ub678\ub679\ub67a\ub67b\ub67c\ub67d\ub67e\ub67f\ub680\ub681\ub682\ub683\ub684\ub685\ub686\ub687\ub688\ub689\ub68a\ub68b\ub68c\ub68d\ub68e\ub68f\ub690\ub691\ub692\ub693\ub694\ub695\ub696\ub697\ub698\ub699\ub69a\ub69b\ub69c\ub69d\ub69e\ub69f\ub6a0\ub6a1\ub6a2\ub6a3\ub6a4\ub6a5\ub6a6\ub6a7\ub6a8\ub6a9\ub6aa\ub6ab\ub6ac\ub6ad\ub6ae\ub6af\ub6b0\ub6b1\ub6b2\ub6b3\ub6b4\ub6b5\ub6b6\ub6b7\ub6b8\ub6b9\ub6ba\ub6bb\ub6bc\ub6bd\ub6be\ub6bf\ub6c0\ub6c1\ub6c2\ub6c3\ub6c4\ub6c5\ub6c6\ub6c7\ub6c8\ub6c9\ub6ca\ub6cb\ub6cc\ub6cd\ub6ce\ub6cf\ub6d0\ub6d1\ub6d2\ub6d3\ub6d4\ub6d5\ub6d6\ub6d7\ub6d8\ub6d9\ub6da\ub6db\ub6dc\ub6dd\ub6de\ub6df\ub6e0\ub6e1\ub6e2\ub6e3\ub6e4\ub6e5\ub6e6\ub6e7\ub6e8\ub6e9\ub6ea\ub6eb\ub6ec\ub6ed\ub6ee\ub6ef\ub6f0\ub6f1\ub6f2\ub6f3\ub6f4\ub6f5\ub6f6\ub6f7\ub6f8\ub6f9\ub6fa\ub6fb\ub6fc\ub6fd\ub6fe\ub6ff\ub700\ub701\ub702\ub703\ub704\ub705\ub706\ub707\ub708\ub709\ub70a\ub70b\ub70c\ub70d\ub70e\ub70f\ub710\ub711\ub712\ub713\ub714\ub715\ub716\ub717\ub718\ub719\ub71a\ub71b\ub71c\ub71d\ub71e\ub71f\ub720\ub721\ub722\ub723\ub724\ub725\ub726\ub727\ub728\ub729\ub72a\ub72b\ub72c\ub72d\ub72e\ub72f\ub730\ub731\ub732\ub733\ub734\ub735\ub736\ub737\ub738\ub739\ub73a\ub73b\ub73c\ub73d\ub73e\ub73f\ub740\ub741\ub742\ub743\ub744\ub745\ub746\ub747\ub748\ub749\ub74a\ub74b\ub74c\ub74d\ub74e\ub74f\ub750\ub751\ub752\ub753\ub754\ub755\ub756\ub757\ub758\ub759\ub75a\ub75b\ub75c\ub75d\ub75e\ub75f\ub760\ub761\ub762\ub763\ub764\ub765\ub766\ub767\ub768\ub769\ub76a\ub76b\ub76c\ub76d\ub76e\ub76f\ub770\ub771\ub772\ub773\ub774\ub775\ub776\ub777\ub778\ub779\ub77a\ub77b\ub77c\ub77d\ub77e\ub77f\ub780\ub781\ub782\ub783\ub784\ub785\ub786\ub787\ub788\ub789\ub78a\ub78b\ub78c\ub78d\ub78e\ub78f\ub790\ub791\ub792\ub793\ub794\ub795\ub796\ub797\ub798\ub799\ub79a\ub79b\ub79c\ub79d\ub79e\ub79f\ub7a0\ub7a1\ub7a2\ub7a3\ub7a4\ub7a5\ub7a6\ub7a7\ub7a8\ub7a9\ub7aa\ub7ab\ub7ac\ub7ad\ub7ae\ub7af\ub7b0\ub7b1\ub7b2\ub7b3\ub7b4\ub7b5\ub7b6\ub7b7\ub7b8\ub7b9\ub7ba\ub7bb\ub7bc\ub7bd\ub7be\ub7bf\ub7c0\ub7c1\ub7c2\ub7c3\ub7c4\ub7c5\ub7c6\ub7c7\ub7c8\ub7c9\ub7ca\ub7cb\ub7cc\ub7cd\ub7ce\ub7cf\ub7d0\ub7d1\ub7d2\ub7d3\ub7d4\ub7d5\ub7d6\ub7d7\ub7d8\ub7d9\ub7da\ub7db\ub7dc\ub7dd\ub7de\ub7df\ub7e0\ub7e1\ub7e2\ub7e3\ub7e4\ub7e5\ub7e6\ub7e7\ub7e8\ub7e9\ub7ea\ub7eb\ub7ec\ub7ed\ub7ee\ub7ef\ub7f0\ub7f1\ub7f2\ub7f3\ub7f4\ub7f5\ub7f6\ub7f7\ub7f8\ub7f9\ub7fa\ub7fb\ub7fc\ub7fd\ub7fe\ub7ff\ub800\ub801\ub802\ub803\ub804\ub805\ub806\ub807\ub808\ub809\ub80a\ub80b\ub80c\ub80d\ub80e\ub80f\ub810\ub811\ub812\ub813\ub814\ub815\ub816\ub817\ub818\ub819\ub81a\ub81b\ub81c\ub81d\ub81e\ub81f\ub820\ub821\ub822\ub823\ub824\ub825\ub826\ub827\ub828\ub829\ub82a\ub82b\ub82c\ub82d\ub82e\ub82f\ub830\ub831\ub832\ub833\ub834\ub835\ub836\ub837\ub838\ub839\ub83a\ub83b\ub83c\ub83d\ub83e\ub83f\ub840\ub841\ub842\ub843\ub844\ub845\ub846\ub847\ub848\ub849\ub84a\ub84b\ub84c\ub84d\ub84e\ub84f\ub850\ub851\ub852\ub853\ub854\ub855\ub856\ub857\ub858\ub859\ub85a\ub85b\ub85c\ub85d\ub85e\ub85f\ub860\ub861\ub862\ub863\ub864\ub865\ub866\ub867\ub868\ub869\ub86a\ub86b\ub86c\ub86d\ub86e\ub86f\ub870\ub871\ub872\ub873\ub874\ub875\ub876\ub877\ub878\ub879\ub87a\ub87b\ub87c\ub87d\ub87e\ub87f\ub880\ub881\ub882\ub883\ub884\ub885\ub886\ub887\ub888\ub889\ub88a\ub88b\ub88c\ub88d\ub88e\ub88f\ub890\ub891\ub892\ub893\ub894\ub895\ub896\ub897\ub898\ub899\ub89a\ub89b\ub89c\ub89d\ub89e\ub89f\ub8a0\ub8a1\ub8a2\ub8a3\ub8a4\ub8a5\ub8a6\ub8a7\ub8a8\ub8a9\ub8aa\ub8ab\ub8ac\ub8ad\ub8ae\ub8af\ub8b0\ub8b1\ub8b2\ub8b3\ub8b4\ub8b5\ub8b6\ub8b7\ub8b8\ub8b9\ub8ba\ub8bb\ub8bc\ub8bd\ub8be\ub8bf\ub8c0\ub8c1\ub8c2\ub8c3\ub8c4\ub8c5\ub8c6\ub8c7\ub8c8\ub8c9\ub8ca\ub8cb\ub8cc\ub8cd\ub8ce\ub8cf\ub8d0\ub8d1\ub8d2\ub8d3\ub8d4\ub8d5\ub8d6\ub8d7\ub8d8\ub8d9\ub8da\ub8db\ub8dc\ub8dd\ub8de\ub8df\ub8e0\ub8e1\ub8e2\ub8e3\ub8e4\ub8e5\ub8e6\ub8e7\ub8e8\ub8e9\ub8ea\ub8eb\ub8ec\ub8ed\ub8ee\ub8ef\ub8f0\ub8f1\ub8f2\ub8f3\ub8f4\ub8f5\ub8f6\ub8f7\ub8f8\ub8f9\ub8fa\ub8fb\ub8fc\ub8fd\ub8fe\ub8ff\ub900\ub901\ub902\ub903\ub904\ub905\ub906\ub907\ub908\ub909\ub90a\ub90b\ub90c\ub90d\ub90e\ub90f\ub910\ub911\ub912\ub913\ub914\ub915\ub916\ub917\ub918\ub919\ub91a\ub91b\ub91c\ub91d\ub91e\ub91f\ub920\ub921\ub922\ub923\ub924\ub925\ub926\ub927\ub928\ub929\ub92a\ub92b\ub92c\ub92d\ub92e\ub92f\ub930\ub931\ub932\ub933\ub934\ub935\ub936\ub937\ub938\ub939\ub93a\ub93b\ub93c\ub93d\ub93e\ub93f\ub940\ub941\ub942\ub943\ub944\ub945\ub946\ub947\ub948\ub949\ub94a\ub94b\ub94c\ub94d\ub94e\ub94f\ub950\ub951\ub952\ub953\ub954\ub955\ub956\ub957\ub958\ub959\ub95a\ub95b\ub95c\ub95d\ub95e\ub95f\ub960\ub961\ub962\ub963\ub964\ub965\ub966\ub967\ub968\ub969\ub96a\ub96b\ub96c\ub96d\ub96e\ub96f\ub970\ub971\ub972\ub973\ub974\ub975\ub976\ub977\ub978\ub979\ub97a\ub97b\ub97c\ub97d\ub97e\ub97f\ub980\ub981\ub982\ub983\ub984\ub985\ub986\ub987\ub988\ub989\ub98a\ub98b\ub98c\ub98d\ub98e\ub98f\ub990\ub991\ub992\ub993\ub994\ub995\ub996\ub997\ub998\ub999\ub99a\ub99b\ub99c\ub99d\ub99e\ub99f\ub9a0\ub9a1\ub9a2\ub9a3\ub9a4\ub9a5\ub9a6\ub9a7\ub9a8\ub9a9\ub9aa\ub9ab\ub9ac\ub9ad\ub9ae\ub9af\ub9b0\ub9b1\ub9b2\ub9b3\ub9b4\ub9b5\ub9b6\ub9b7\ub9b8\ub9b9\ub9ba\ub9bb\ub9bc\ub9bd\ub9be\ub9bf\ub9c0\ub9c1\ub9c2\ub9c3\ub9c4\ub9c5\ub9c6\ub9c7\ub9c8\ub9c9\ub9ca\ub9cb\ub9cc\ub9cd\ub9ce\ub9cf\ub9d0\ub9d1\ub9d2\ub9d3\ub9d4\ub9d5\ub9d6\ub9d7\ub9d8\ub9d9\ub9da\ub9db\ub9dc\ub9dd\ub9de\ub9df\ub9e0\ub9e1\ub9e2\ub9e3\ub9e4\ub9e5\ub9e6\ub9e7\ub9e8\ub9e9\ub9ea\ub9eb\ub9ec\ub9ed\ub9ee\ub9ef\ub9f0\ub9f1\ub9f2\ub9f3\ub9f4\ub9f5\ub9f6\ub9f7\ub9f8\ub9f9\ub9fa\ub9fb\ub9fc\ub9fd\ub9fe\ub9ff\uba00\uba01\uba02\uba03\uba04\uba05\uba06\uba07\uba08\uba09\uba0a\uba0b\uba0c\uba0d\uba0e\uba0f\uba10\uba11\uba12\uba13\uba14\uba15\uba16\uba17\uba18\uba19\uba1a\uba1b\uba1c\uba1d\uba1e\uba1f\uba20\uba21\uba22\uba23\uba24\uba25\uba26\uba27\uba28\uba29\uba2a\uba2b\uba2c\uba2d\uba2e\uba2f\uba30\uba31\uba32\uba33\uba34\uba35\uba36\uba37\uba38\uba39\uba3a\uba3b\uba3c\uba3d\uba3e\uba3f\uba40\uba41\uba42\uba43\uba44\uba45\uba46\uba47\uba48\uba49\uba4a\uba4b\uba4c\uba4d\uba4e\uba4f\uba50\uba51\uba52\uba53\uba54\uba55\uba56\uba57\uba58\uba59\uba5a\uba5b\uba5c\uba5d\uba5e\uba5f\uba60\uba61\uba62\uba63\uba64\uba65\uba66\uba67\uba68\uba69\uba6a\uba6b\uba6c\uba6d\uba6e\uba6f\uba70\uba71\uba72\uba73\uba74\uba75\uba76\uba77\uba78\uba79\uba7a\uba7b\uba7c\uba7d\uba7e\uba7f\uba80\uba81\uba82\uba83\uba84\uba85\uba86\uba87\uba88\uba89\uba8a\uba8b\uba8c\uba8d\uba8e\uba8f\uba90\uba91\uba92\uba93\uba94\uba95\uba96\uba97\uba98\uba99\uba9a\uba9b\uba9c\uba9d\uba9e\uba9f\ubaa0\ubaa1\ubaa2\ubaa3\ubaa4\ubaa5\ubaa6\ubaa7\ubaa8\ubaa9\ubaaa\ubaab\ubaac\ubaad\ubaae\ubaaf\ubab0\ubab1\ubab2\ubab3\ubab4\ubab5\ubab6\ubab7\ubab8\ubab9\ubaba\ubabb\ubabc\ubabd\ubabe\ubabf\ubac0\ubac1\ubac2\ubac3\ubac4\ubac5\ubac6\ubac7\ubac8\ubac9\ubaca\ubacb\ubacc\ubacd\ubace\ubacf\ubad0\ubad1\ubad2\ubad3\ubad4\ubad5\ubad6\ubad7\ubad8\ubad9\ubada\ubadb\ubadc\ubadd\ubade\ubadf\ubae0\ubae1\ubae2\ubae3\ubae4\ubae5\ubae6\ubae7\ubae8\ubae9\ubaea\ubaeb\ubaec\ubaed\ubaee\ubaef\ubaf0\ubaf1\ubaf2\ubaf3\ubaf4\ubaf5\ubaf6\ubaf7\ubaf8\ubaf9\ubafa\ubafb\ubafc\ubafd\ubafe\ubaff\ubb00\ubb01\ubb02\ubb03\ubb04\ubb05\ubb06\ubb07\ubb08\ubb09\ubb0a\ubb0b\ubb0c\ubb0d\ubb0e\ubb0f\ubb10\ubb11\ubb12\ubb13\ubb14\ubb15\ubb16\ubb17\ubb18\ubb19\ubb1a\ubb1b\ubb1c\ubb1d\ubb1e\ubb1f\ubb20\ubb21\ubb22\ubb23\ubb24\ubb25\ubb26\ubb27\ubb28\ubb29\ubb2a\ubb2b\ubb2c\ubb2d\ubb2e\ubb2f\ubb30\ubb31\ubb32\ubb33\ubb34\ubb35\ubb36\ubb37\ubb38\ubb39\ubb3a\ubb3b\ubb3c\ubb3d\ubb3e\ubb3f\ubb40\ubb41\ubb42\ubb43\ubb44\ubb45\ubb46\ubb47\ubb48\ubb49\ubb4a\ubb4b\ubb4c\ubb4d\ubb4e\ubb4f\ubb50\ubb51\ubb52\ubb53\ubb54\ubb55\ubb56\ubb57\ubb58\ubb59\ubb5a\ubb5b\ubb5c\ubb5d\ubb5e\ubb5f\ubb60\ubb61\ubb62\ubb63\ubb64\ubb65\ubb66\ubb67\ubb68\ubb69\ubb6a\ubb6b\ubb6c\ubb6d\ubb6e\ubb6f\ubb70\ubb71\ubb72\ubb73\ubb74\ubb75\ubb76\ubb77\ubb78\ubb79\ubb7a\ubb7b\ubb7c\ubb7d\ubb7e\ubb7f\ubb80\ubb81\ubb82\ubb83\ubb84\ubb85\ubb86\ubb87\ubb88\ubb89\ubb8a\ubb8b\ubb8c\ubb8d\ubb8e\ubb8f\ubb90\ubb91\ubb92\ubb93\ubb94\ubb95\ubb96\ubb97\ubb98\ubb99\ubb9a\ubb9b\ubb9c\ubb9d\ubb9e\ubb9f\ubba0\ubba1\ubba2\ubba3\ubba4\ubba5\ubba6\ubba7\ubba8\ubba9\ubbaa\ubbab\ubbac\ubbad\ubbae\ubbaf\ubbb0\ubbb1\ubbb2\ubbb3\ubbb4\ubbb5\ubbb6\ubbb7\ubbb8\ubbb9\ubbba\ubbbb\ubbbc\ubbbd\ubbbe\ubbbf\ubbc0\ubbc1\ubbc2\ubbc3\ubbc4\ubbc5\ubbc6\ubbc7\ubbc8\ubbc9\ubbca\ubbcb\ubbcc\ubbcd\ubbce\ubbcf\ubbd0\ubbd1\ubbd2\ubbd3\ubbd4\ubbd5\ubbd6\ubbd7\ubbd8\ubbd9\ubbda\ubbdb\ubbdc\ubbdd\ubbde\ubbdf\ubbe0\ubbe1\ubbe2\ubbe3\ubbe4\ubbe5\ubbe6\ubbe7\ubbe8\ubbe9\ubbea\ubbeb\ubbec\ubbed\ubbee\ubbef\ubbf0\ubbf1\ubbf2\ubbf3\ubbf4\ubbf5\ubbf6\ubbf7\ubbf8\ubbf9\ubbfa\ubbfb\ubbfc\ubbfd\ubbfe\ubbff\ubc00\ubc01\ubc02\ubc03\ubc04\ubc05\ubc06\ubc07\ubc08\ubc09\ubc0a\ubc0b\ubc0c\ubc0d\ubc0e\ubc0f\ubc10\ubc11\ubc12\ubc13\ubc14\ubc15\ubc16\ubc17\ubc18\ubc19\ubc1a\ubc1b\ubc1c\ubc1d\ubc1e\ubc1f\ubc20\ubc21\ubc22\ubc23\ubc24\ubc25\ubc26\ubc27\ubc28\ubc29\ubc2a\ubc2b\ubc2c\ubc2d\ubc2e\ubc2f\ubc30\ubc31\ubc32\ubc33\ubc34\ubc35\ubc36\ubc37\ubc38\ubc39\ubc3a\ubc3b\ubc3c\ubc3d\ubc3e\ubc3f\ubc40\ubc41\ubc42\ubc43\ubc44\ubc45\ubc46\ubc47\ubc48\ubc49\ubc4a\ubc4b\ubc4c\ubc4d\ubc4e\ubc4f\ubc50\ubc51\ubc52\ubc53\ubc54\ubc55\ubc56\ubc57\ubc58\ubc59\ubc5a\ubc5b\ubc5c\ubc5d\ubc5e\ubc5f\ubc60\ubc61\ubc62\ubc63\ubc64\ubc65\ubc66\ubc67\ubc68\ubc69\ubc6a\ubc6b\ubc6c\ubc6d\ubc6e\ubc6f\ubc70\ubc71\ubc72\ubc73\ubc74\ubc75\ubc76\ubc77\ubc78\ubc79\ubc7a\ubc7b\ubc7c\ubc7d\ubc7e\ubc7f\ubc80\ubc81\ubc82\ubc83\ubc84\ubc85\ubc86\ubc87\ubc88\ubc89\ubc8a\ubc8b\ubc8c\ubc8d\ubc8e\ubc8f\ubc90\ubc91\ubc92\ubc93\ubc94\ubc95\ubc96\ubc97\ubc98\ubc99\ubc9a\ubc9b\ubc9c\ubc9d\ubc9e\ubc9f\ubca0\ubca1\ubca2\ubca3\ubca4\ubca5\ubca6\ubca7\ubca8\ubca9\ubcaa\ubcab\ubcac\ubcad\ubcae\ubcaf\ubcb0\ubcb1\ubcb2\ubcb3\ubcb4\ubcb5\ubcb6\ubcb7\ubcb8\ubcb9\ubcba\ubcbb\ubcbc\ubcbd\ubcbe\ubcbf\ubcc0\ubcc1\ubcc2\ubcc3\ubcc4\ubcc5\ubcc6\ubcc7\ubcc8\ubcc9\ubcca\ubccb\ubccc\ubccd\ubcce\ubccf\ubcd0\ubcd1\ubcd2\ubcd3\ubcd4\ubcd5\ubcd6\ubcd7\ubcd8\ubcd9\ubcda\ubcdb\ubcdc\ubcdd\ubcde\ubcdf\ubce0\ubce1\ubce2\ubce3\ubce4\ubce5\ubce6\ubce7\ubce8\ubce9\ubcea\ubceb\ubcec\ubced\ubcee\ubcef\ubcf0\ubcf1\ubcf2\ubcf3\ubcf4\ubcf5\ubcf6\ubcf7\ubcf8\ubcf9\ubcfa\ubcfb\ubcfc\ubcfd\ubcfe\ubcff\ubd00\ubd01\ubd02\ubd03\ubd04\ubd05\ubd06\ubd07\ubd08\ubd09\ubd0a\ubd0b\ubd0c\ubd0d\ubd0e\ubd0f\ubd10\ubd11\ubd12\ubd13\ubd14\ubd15\ubd16\ubd17\ubd18\ubd19\ubd1a\ubd1b\ubd1c\ubd1d\ubd1e\ubd1f\ubd20\ubd21\ubd22\ubd23\ubd24\ubd25\ubd26\ubd27\ubd28\ubd29\ubd2a\ubd2b\ubd2c\ubd2d\ubd2e\ubd2f\ubd30\ubd31\ubd32\ubd33\ubd34\ubd35\ubd36\ubd37\ubd38\ubd39\ubd3a\ubd3b\ubd3c\ubd3d\ubd3e\ubd3f\ubd40\ubd41\ubd42\ubd43\ubd44\ubd45\ubd46\ubd47\ubd48\ubd49\ubd4a\ubd4b\ubd4c\ubd4d\ubd4e\ubd4f\ubd50\ubd51\ubd52\ubd53\ubd54\ubd55\ubd56\ubd57\ubd58\ubd59\ubd5a\ubd5b\ubd5c\ubd5d\ubd5e\ubd5f\ubd60\ubd61\ubd62\ubd63\ubd64\ubd65\ubd66\ubd67\ubd68\ubd69\ubd6a\ubd6b\ubd6c\ubd6d\ubd6e\ubd6f\ubd70\ubd71\ubd72\ubd73\ubd74\ubd75\ubd76\ubd77\ubd78\ubd79\ubd7a\ubd7b\ubd7c\ubd7d\ubd7e\ubd7f\ubd80\ubd81\ubd82\ubd83\ubd84\ubd85\ubd86\ubd87\ubd88\ubd89\ubd8a\ubd8b\ubd8c\ubd8d\ubd8e\ubd8f\ubd90\ubd91\ubd92\ubd93\ubd94\ubd95\ubd96\ubd97\ubd98\ubd99\ubd9a\ubd9b\ubd9c\ubd9d\ubd9e\ubd9f\ubda0\ubda1\ubda2\ubda3\ubda4\ubda5\ubda6\ubda7\ubda8\ubda9\ubdaa\ubdab\ubdac\ubdad\ubdae\ubdaf\ubdb0\ubdb1\ubdb2\ubdb3\ubdb4\ubdb5\ubdb6\ubdb7\ubdb8\ubdb9\ubdba\ubdbb\ubdbc\ubdbd\ubdbe\ubdbf\ubdc0\ubdc1\ubdc2\ubdc3\ubdc4\ubdc5\ubdc6\ubdc7\ubdc8\ubdc9\ubdca\ubdcb\ubdcc\ubdcd\ubdce\ubdcf\ubdd0\ubdd1\ubdd2\ubdd3\ubdd4\ubdd5\ubdd6\ubdd7\ubdd8\ubdd9\ubdda\ubddb\ubddc\ubddd\ubdde\ubddf\ubde0\ubde1\ubde2\ubde3\ubde4\ubde5\ubde6\ubde7\ubde8\ubde9\ubdea\ubdeb\ubdec\ubded\ubdee\ubdef\ubdf0\ubdf1\ubdf2\ubdf3\ubdf4\ubdf5\ubdf6\ubdf7\ubdf8\ubdf9\ubdfa\ubdfb\ubdfc\ubdfd\ubdfe\ubdff\ube00\ube01\ube02\ube03\ube04\ube05\ube06\ube07\ube08\ube09\ube0a\ube0b\ube0c\ube0d\ube0e\ube0f\ube10\ube11\ube12\ube13\ube14\ube15\ube16\ube17\ube18\ube19\ube1a\ube1b\ube1c\ube1d\ube1e\ube1f\ube20\ube21\ube22\ube23\ube24\ube25\ube26\ube27\ube28\ube29\ube2a\ube2b\ube2c\ube2d\ube2e\ube2f\ube30\ube31\ube32\ube33\ube34\ube35\ube36\ube37\ube38\ube39\ube3a\ube3b\ube3c\ube3d\ube3e\ube3f\ube40\ube41\ube42\ube43\ube44\ube45\ube46\ube47\ube48\ube49\ube4a\ube4b\ube4c\ube4d\ube4e\ube4f\ube50\ube51\ube52\ube53\ube54\ube55\ube56\ube57\ube58\ube59\ube5a\ube5b\ube5c\ube5d\ube5e\ube5f\ube60\ube61\ube62\ube63\ube64\ube65\ube66\ube67\ube68\ube69\ube6a\ube6b\ube6c\ube6d\ube6e\ube6f\ube70\ube71\ube72\ube73\ube74\ube75\ube76\ube77\ube78\ube79\ube7a\ube7b\ube7c\ube7d\ube7e\ube7f\ube80\ube81\ube82\ube83\ube84\ube85\ube86\ube87\ube88\ube89\ube8a\ube8b\ube8c\ube8d\ube8e\ube8f\ube90\ube91\ube92\ube93\ube94\ube95\ube96\ube97\ube98\ube99\ube9a\ube9b\ube9c\ube9d\ube9e\ube9f\ubea0\ubea1\ubea2\ubea3\ubea4\ubea5\ubea6\ubea7\ubea8\ubea9\ubeaa\ubeab\ubeac\ubead\ubeae\ubeaf\ubeb0\ubeb1\ubeb2\ubeb3\ubeb4\ubeb5\ubeb6\ubeb7\ubeb8\ubeb9\ubeba\ubebb\ubebc\ubebd\ubebe\ubebf\ubec0\ubec1\ubec2\ubec3\ubec4\ubec5\ubec6\ubec7\ubec8\ubec9\ubeca\ubecb\ubecc\ubecd\ubece\ubecf\ubed0\ubed1\ubed2\ubed3\ubed4\ubed5\ubed6\ubed7\ubed8\ubed9\ubeda\ubedb\ubedc\ubedd\ubede\ubedf\ubee0\ubee1\ubee2\ubee3\ubee4\ubee5\ubee6\ubee7\ubee8\ubee9\ubeea\ubeeb\ubeec\ubeed\ubeee\ubeef\ubef0\ubef1\ubef2\ubef3\ubef4\ubef5\ubef6\ubef7\ubef8\ubef9\ubefa\ubefb\ubefc\ubefd\ubefe\ubeff\ubf00\ubf01\ubf02\ubf03\ubf04\ubf05\ubf06\ubf07\ubf08\ubf09\ubf0a\ubf0b\ubf0c\ubf0d\ubf0e\ubf0f\ubf10\ubf11\ubf12\ubf13\ubf14\ubf15\ubf16\ubf17\ubf18\ubf19\ubf1a\ubf1b\ubf1c\ubf1d\ubf1e\ubf1f\ubf20\ubf21\ubf22\ubf23\ubf24\ubf25\ubf26\ubf27\ubf28\ubf29\ubf2a\ubf2b\ubf2c\ubf2d\ubf2e\ubf2f\ubf30\ubf31\ubf32\ubf33\ubf34\ubf35\ubf36\ubf37\ubf38\ubf39\ubf3a\ubf3b\ubf3c\ubf3d\ubf3e\ubf3f\ubf40\ubf41\ubf42\ubf43\ubf44\ubf45\ubf46\ubf47\ubf48\ubf49\ubf4a\ubf4b\ubf4c\ubf4d\ubf4e\ubf4f\ubf50\ubf51\ubf52\ubf53\ubf54\ubf55\ubf56\ubf57\ubf58\ubf59\ubf5a\ubf5b\ubf5c\ubf5d\ubf5e\ubf5f\ubf60\ubf61\ubf62\ubf63\ubf64\ubf65\ubf66\ubf67\ubf68\ubf69\ubf6a\ubf6b\ubf6c\ubf6d\ubf6e\ubf6f\ubf70\ubf71\ubf72\ubf73\ubf74\ubf75\ubf76\ubf77\ubf78\ubf79\ubf7a\ubf7b\ubf7c\ubf7d\ubf7e\ubf7f\ubf80\ubf81\ubf82\ubf83\ubf84\ubf85\ubf86\ubf87\ubf88\ubf89\ubf8a\ubf8b\ubf8c\ubf8d\ubf8e\ubf8f\ubf90\ubf91\ubf92\ubf93\ubf94\ubf95\ubf96\ubf97\ubf98\ubf99\ubf9a\ubf9b\ubf9c\ubf9d\ubf9e\ubf9f\ubfa0\ubfa1\ubfa2\ubfa3\ubfa4\ubfa5\ubfa6\ubfa7\ubfa8\ubfa9\ubfaa\ubfab\ubfac\ubfad\ubfae\ubfaf\ubfb0\ubfb1\ubfb2\ubfb3\ubfb4\ubfb5\ubfb6\ubfb7\ubfb8\ubfb9\ubfba\ubfbb\ubfbc\ubfbd\ubfbe\ubfbf\ubfc0\ubfc1\ubfc2\ubfc3\ubfc4\ubfc5\ubfc6\ubfc7\ubfc8\ubfc9\ubfca\ubfcb\ubfcc\ubfcd\ubfce\ubfcf\ubfd0\ubfd1\ubfd2\ubfd3\ubfd4\ubfd5\ubfd6\ubfd7\ubfd8\ubfd9\ubfda\ubfdb\ubfdc\ubfdd\ubfde\ubfdf\ubfe0\ubfe1\ubfe2\ubfe3\ubfe4\ubfe5\ubfe6\ubfe7\ubfe8\ubfe9\ubfea\ubfeb\ubfec\ubfed\ubfee\ubfef\ubff0\ubff1\ubff2\ubff3\ubff4\ubff5\ubff6\ubff7\ubff8\ubff9\ubffa\ubffb\ubffc\ubffd\ubffe\ubfff\uc000\uc001\uc002\uc003\uc004\uc005\uc006\uc007\uc008\uc009\uc00a\uc00b\uc00c\uc00d\uc00e\uc00f\uc010\uc011\uc012\uc013\uc014\uc015\uc016\uc017\uc018\uc019\uc01a\uc01b\uc01c\uc01d\uc01e\uc01f\uc020\uc021\uc022\uc023\uc024\uc025\uc026\uc027\uc028\uc029\uc02a\uc02b\uc02c\uc02d\uc02e\uc02f\uc030\uc031\uc032\uc033\uc034\uc035\uc036\uc037\uc038\uc039\uc03a\uc03b\uc03c\uc03d\uc03e\uc03f\uc040\uc041\uc042\uc043\uc044\uc045\uc046\uc047\uc048\uc049\uc04a\uc04b\uc04c\uc04d\uc04e\uc04f\uc050\uc051\uc052\uc053\uc054\uc055\uc056\uc057\uc058\uc059\uc05a\uc05b\uc05c\uc05d\uc05e\uc05f\uc060\uc061\uc062\uc063\uc064\uc065\uc066\uc067\uc068\uc069\uc06a\uc06b\uc06c\uc06d\uc06e\uc06f\uc070\uc071\uc072\uc073\uc074\uc075\uc076\uc077\uc078\uc079\uc07a\uc07b\uc07c\uc07d\uc07e\uc07f\uc080\uc081\uc082\uc083\uc084\uc085\uc086\uc087\uc088\uc089\uc08a\uc08b\uc08c\uc08d\uc08e\uc08f\uc090\uc091\uc092\uc093\uc094\uc095\uc096\uc097\uc098\uc099\uc09a\uc09b\uc09c\uc09d\uc09e\uc09f\uc0a0\uc0a1\uc0a2\uc0a3\uc0a4\uc0a5\uc0a6\uc0a7\uc0a8\uc0a9\uc0aa\uc0ab\uc0ac\uc0ad\uc0ae\uc0af\uc0b0\uc0b1\uc0b2\uc0b3\uc0b4\uc0b5\uc0b6\uc0b7\uc0b8\uc0b9\uc0ba\uc0bb\uc0bc\uc0bd\uc0be\uc0bf\uc0c0\uc0c1\uc0c2\uc0c3\uc0c4\uc0c5\uc0c6\uc0c7\uc0c8\uc0c9\uc0ca\uc0cb\uc0cc\uc0cd\uc0ce\uc0cf\uc0d0\uc0d1\uc0d2\uc0d3\uc0d4\uc0d5\uc0d6\uc0d7\uc0d8\uc0d9\uc0da\uc0db\uc0dc\uc0dd\uc0de\uc0df\uc0e0\uc0e1\uc0e2\uc0e3\uc0e4\uc0e5\uc0e6\uc0e7\uc0e8\uc0e9\uc0ea\uc0eb\uc0ec\uc0ed\uc0ee\uc0ef\uc0f0\uc0f1\uc0f2\uc0f3\uc0f4\uc0f5\uc0f6\uc0f7\uc0f8\uc0f9\uc0fa\uc0fb\uc0fc\uc0fd\uc0fe\uc0ff\uc100\uc101\uc102\uc103\uc104\uc105\uc106\uc107\uc108\uc109\uc10a\uc10b\uc10c\uc10d\uc10e\uc10f\uc110\uc111\uc112\uc113\uc114\uc115\uc116\uc117\uc118\uc119\uc11a\uc11b\uc11c\uc11d\uc11e\uc11f\uc120\uc121\uc122\uc123\uc124\uc125\uc126\uc127\uc128\uc129\uc12a\uc12b\uc12c\uc12d\uc12e\uc12f\uc130\uc131\uc132\uc133\uc134\uc135\uc136\uc137\uc138\uc139\uc13a\uc13b\uc13c\uc13d\uc13e\uc13f\uc140\uc141\uc142\uc143\uc144\uc145\uc146\uc147\uc148\uc149\uc14a\uc14b\uc14c\uc14d\uc14e\uc14f\uc150\uc151\uc152\uc153\uc154\uc155\uc156\uc157\uc158\uc159\uc15a\uc15b\uc15c\uc15d\uc15e\uc15f\uc160\uc161\uc162\uc163\uc164\uc165\uc166\uc167\uc168\uc169\uc16a\uc16b\uc16c\uc16d\uc16e\uc16f\uc170\uc171\uc172\uc173\uc174\uc175\uc176\uc177\uc178\uc179\uc17a\uc17b\uc17c\uc17d\uc17e\uc17f\uc180\uc181\uc182\uc183\uc184\uc185\uc186\uc187\uc188\uc189\uc18a\uc18b\uc18c\uc18d\uc18e\uc18f\uc190\uc191\uc192\uc193\uc194\uc195\uc196\uc197\uc198\uc199\uc19a\uc19b\uc19c\uc19d\uc19e\uc19f\uc1a0\uc1a1\uc1a2\uc1a3\uc1a4\uc1a5\uc1a6\uc1a7\uc1a8\uc1a9\uc1aa\uc1ab\uc1ac\uc1ad\uc1ae\uc1af\uc1b0\uc1b1\uc1b2\uc1b3\uc1b4\uc1b5\uc1b6\uc1b7\uc1b8\uc1b9\uc1ba\uc1bb\uc1bc\uc1bd\uc1be\uc1bf\uc1c0\uc1c1\uc1c2\uc1c3\uc1c4\uc1c5\uc1c6\uc1c7\uc1c8\uc1c9\uc1ca\uc1cb\uc1cc\uc1cd\uc1ce\uc1cf\uc1d0\uc1d1\uc1d2\uc1d3\uc1d4\uc1d5\uc1d6\uc1d7\uc1d8\uc1d9\uc1da\uc1db\uc1dc\uc1dd\uc1de\uc1df\uc1e0\uc1e1\uc1e2\uc1e3\uc1e4\uc1e5\uc1e6\uc1e7\uc1e8\uc1e9\uc1ea\uc1eb\uc1ec\uc1ed\uc1ee\uc1ef\uc1f0\uc1f1\uc1f2\uc1f3\uc1f4\uc1f5\uc1f6\uc1f7\uc1f8\uc1f9\uc1fa\uc1fb\uc1fc\uc1fd\uc1fe\uc1ff\uc200\uc201\uc202\uc203\uc204\uc205\uc206\uc207\uc208\uc209\uc20a\uc20b\uc20c\uc20d\uc20e\uc20f\uc210\uc211\uc212\uc213\uc214\uc215\uc216\uc217\uc218\uc219\uc21a\uc21b\uc21c\uc21d\uc21e\uc21f\uc220\uc221\uc222\uc223\uc224\uc225\uc226\uc227\uc228\uc229\uc22a\uc22b\uc22c\uc22d\uc22e\uc22f\uc230\uc231\uc232\uc233\uc234\uc235\uc236\uc237\uc238\uc239\uc23a\uc23b\uc23c\uc23d\uc23e\uc23f\uc240\uc241\uc242\uc243\uc244\uc245\uc246\uc247\uc248\uc249\uc24a\uc24b\uc24c\uc24d\uc24e\uc24f\uc250\uc251\uc252\uc253\uc254\uc255\uc256\uc257\uc258\uc259\uc25a\uc25b\uc25c\uc25d\uc25e\uc25f\uc260\uc261\uc262\uc263\uc264\uc265\uc266\uc267\uc268\uc269\uc26a\uc26b\uc26c\uc26d\uc26e\uc26f\uc270\uc271\uc272\uc273\uc274\uc275\uc276\uc277\uc278\uc279\uc27a\uc27b\uc27c\uc27d\uc27e\uc27f\uc280\uc281\uc282\uc283\uc284\uc285\uc286\uc287\uc288\uc289\uc28a\uc28b\uc28c\uc28d\uc28e\uc28f\uc290\uc291\uc292\uc293\uc294\uc295\uc296\uc297\uc298\uc299\uc29a\uc29b\uc29c\uc29d\uc29e\uc29f\uc2a0\uc2a1\uc2a2\uc2a3\uc2a4\uc2a5\uc2a6\uc2a7\uc2a8\uc2a9\uc2aa\uc2ab\uc2ac\uc2ad\uc2ae\uc2af\uc2b0\uc2b1\uc2b2\uc2b3\uc2b4\uc2b5\uc2b6\uc2b7\uc2b8\uc2b9\uc2ba\uc2bb\uc2bc\uc2bd\uc2be\uc2bf\uc2c0\uc2c1\uc2c2\uc2c3\uc2c4\uc2c5\uc2c6\uc2c7\uc2c8\uc2c9\uc2ca\uc2cb\uc2cc\uc2cd\uc2ce\uc2cf\uc2d0\uc2d1\uc2d2\uc2d3\uc2d4\uc2d5\uc2d6\uc2d7\uc2d8\uc2d9\uc2da\uc2db\uc2dc\uc2dd\uc2de\uc2df\uc2e0\uc2e1\uc2e2\uc2e3\uc2e4\uc2e5\uc2e6\uc2e7\uc2e8\uc2e9\uc2ea\uc2eb\uc2ec\uc2ed\uc2ee\uc2ef\uc2f0\uc2f1\uc2f2\uc2f3\uc2f4\uc2f5\uc2f6\uc2f7\uc2f8\uc2f9\uc2fa\uc2fb\uc2fc\uc2fd\uc2fe\uc2ff\uc300\uc301\uc302\uc303\uc304\uc305\uc306\uc307\uc308\uc309\uc30a\uc30b\uc30c\uc30d\uc30e\uc30f\uc310\uc311\uc312\uc313\uc314\uc315\uc316\uc317\uc318\uc319\uc31a\uc31b\uc31c\uc31d\uc31e\uc31f\uc320\uc321\uc322\uc323\uc324\uc325\uc326\uc327\uc328\uc329\uc32a\uc32b\uc32c\uc32d\uc32e\uc32f\uc330\uc331\uc332\uc333\uc334\uc335\uc336\uc337\uc338\uc339\uc33a\uc33b\uc33c\uc33d\uc33e\uc33f\uc340\uc341\uc342\uc343\uc344\uc345\uc346\uc347\uc348\uc349\uc34a\uc34b\uc34c\uc34d\uc34e\uc34f\uc350\uc351\uc352\uc353\uc354\uc355\uc356\uc357\uc358\uc359\uc35a\uc35b\uc35c\uc35d\uc35e\uc35f\uc360\uc361\uc362\uc363\uc364\uc365\uc366\uc367\uc368\uc369\uc36a\uc36b\uc36c\uc36d\uc36e\uc36f\uc370\uc371\uc372\uc373\uc374\uc375\uc376\uc377\uc378\uc379\uc37a\uc37b\uc37c\uc37d\uc37e\uc37f\uc380\uc381\uc382\uc383\uc384\uc385\uc386\uc387\uc388\uc389\uc38a\uc38b\uc38c\uc38d\uc38e\uc38f\uc390\uc391\uc392\uc393\uc394\uc395\uc396\uc397\uc398\uc399\uc39a\uc39b\uc39c\uc39d\uc39e\uc39f\uc3a0\uc3a1\uc3a2\uc3a3\uc3a4\uc3a5\uc3a6\uc3a7\uc3a8\uc3a9\uc3aa\uc3ab\uc3ac\uc3ad\uc3ae\uc3af\uc3b0\uc3b1\uc3b2\uc3b3\uc3b4\uc3b5\uc3b6\uc3b7\uc3b8\uc3b9\uc3ba\uc3bb\uc3bc\uc3bd\uc3be\uc3bf\uc3c0\uc3c1\uc3c2\uc3c3\uc3c4\uc3c5\uc3c6\uc3c7\uc3c8\uc3c9\uc3ca\uc3cb\uc3cc\uc3cd\uc3ce\uc3cf\uc3d0\uc3d1\uc3d2\uc3d3\uc3d4\uc3d5\uc3d6\uc3d7\uc3d8\uc3d9\uc3da\uc3db\uc3dc\uc3dd\uc3de\uc3df\uc3e0\uc3e1\uc3e2\uc3e3\uc3e4\uc3e5\uc3e6\uc3e7\uc3e8\uc3e9\uc3ea\uc3eb\uc3ec\uc3ed\uc3ee\uc3ef\uc3f0\uc3f1\uc3f2\uc3f3\uc3f4\uc3f5\uc3f6\uc3f7\uc3f8\uc3f9\uc3fa\uc3fb\uc3fc\uc3fd\uc3fe\uc3ff\uc400\uc401\uc402\uc403\uc404\uc405\uc406\uc407\uc408\uc409\uc40a\uc40b\uc40c\uc40d\uc40e\uc40f\uc410\uc411\uc412\uc413\uc414\uc415\uc416\uc417\uc418\uc419\uc41a\uc41b\uc41c\uc41d\uc41e\uc41f\uc420\uc421\uc422\uc423\uc424\uc425\uc426\uc427\uc428\uc429\uc42a\uc42b\uc42c\uc42d\uc42e\uc42f\uc430\uc431\uc432\uc433\uc434\uc435\uc436\uc437\uc438\uc439\uc43a\uc43b\uc43c\uc43d\uc43e\uc43f\uc440\uc441\uc442\uc443\uc444\uc445\uc446\uc447\uc448\uc449\uc44a\uc44b\uc44c\uc44d\uc44e\uc44f\uc450\uc451\uc452\uc453\uc454\uc455\uc456\uc457\uc458\uc459\uc45a\uc45b\uc45c\uc45d\uc45e\uc45f\uc460\uc461\uc462\uc463\uc464\uc465\uc466\uc467\uc468\uc469\uc46a\uc46b\uc46c\uc46d\uc46e\uc46f\uc470\uc471\uc472\uc473\uc474\uc475\uc476\uc477\uc478\uc479\uc47a\uc47b\uc47c\uc47d\uc47e\uc47f\uc480\uc481\uc482\uc483\uc484\uc485\uc486\uc487\uc488\uc489\uc48a\uc48b\uc48c\uc48d\uc48e\uc48f\uc490\uc491\uc492\uc493\uc494\uc495\uc496\uc497\uc498\uc499\uc49a\uc49b\uc49c\uc49d\uc49e\uc49f\uc4a0\uc4a1\uc4a2\uc4a3\uc4a4\uc4a5\uc4a6\uc4a7\uc4a8\uc4a9\uc4aa\uc4ab\uc4ac\uc4ad\uc4ae\uc4af\uc4b0\uc4b1\uc4b2\uc4b3\uc4b4\uc4b5\uc4b6\uc4b7\uc4b8\uc4b9\uc4ba\uc4bb\uc4bc\uc4bd\uc4be\uc4bf\uc4c0\uc4c1\uc4c2\uc4c3\uc4c4\uc4c5\uc4c6\uc4c7\uc4c8\uc4c9\uc4ca\uc4cb\uc4cc\uc4cd\uc4ce\uc4cf\uc4d0\uc4d1\uc4d2\uc4d3\uc4d4\uc4d5\uc4d6\uc4d7\uc4d8\uc4d9\uc4da\uc4db\uc4dc\uc4dd\uc4de\uc4df\uc4e0\uc4e1\uc4e2\uc4e3\uc4e4\uc4e5\uc4e6\uc4e7\uc4e8\uc4e9\uc4ea\uc4eb\uc4ec\uc4ed\uc4ee\uc4ef\uc4f0\uc4f1\uc4f2\uc4f3\uc4f4\uc4f5\uc4f6\uc4f7\uc4f8\uc4f9\uc4fa\uc4fb\uc4fc\uc4fd\uc4fe\uc4ff\uc500\uc501\uc502\uc503\uc504\uc505\uc506\uc507\uc508\uc509\uc50a\uc50b\uc50c\uc50d\uc50e\uc50f\uc510\uc511\uc512\uc513\uc514\uc515\uc516\uc517\uc518\uc519\uc51a\uc51b\uc51c\uc51d\uc51e\uc51f\uc520\uc521\uc522\uc523\uc524\uc525\uc526\uc527\uc528\uc529\uc52a\uc52b\uc52c\uc52d\uc52e\uc52f\uc530\uc531\uc532\uc533\uc534\uc535\uc536\uc537\uc538\uc539\uc53a\uc53b\uc53c\uc53d\uc53e\uc53f\uc540\uc541\uc542\uc543\uc544\uc545\uc546\uc547\uc548\uc549\uc54a\uc54b\uc54c\uc54d\uc54e\uc54f\uc550\uc551\uc552\uc553\uc554\uc555\uc556\uc557\uc558\uc559\uc55a\uc55b\uc55c\uc55d\uc55e\uc55f\uc560\uc561\uc562\uc563\uc564\uc565\uc566\uc567\uc568\uc569\uc56a\uc56b\uc56c\uc56d\uc56e\uc56f\uc570\uc571\uc572\uc573\uc574\uc575\uc576\uc577\uc578\uc579\uc57a\uc57b\uc57c\uc57d\uc57e\uc57f\uc580\uc581\uc582\uc583\uc584\uc585\uc586\uc587\uc588\uc589\uc58a\uc58b\uc58c\uc58d\uc58e\uc58f\uc590\uc591\uc592\uc593\uc594\uc595\uc596\uc597\uc598\uc599\uc59a\uc59b\uc59c\uc59d\uc59e\uc59f\uc5a0\uc5a1\uc5a2\uc5a3\uc5a4\uc5a5\uc5a6\uc5a7\uc5a8\uc5a9\uc5aa\uc5ab\uc5ac\uc5ad\uc5ae\uc5af\uc5b0\uc5b1\uc5b2\uc5b3\uc5b4\uc5b5\uc5b6\uc5b7\uc5b8\uc5b9\uc5ba\uc5bb\uc5bc\uc5bd\uc5be\uc5bf\uc5c0\uc5c1\uc5c2\uc5c3\uc5c4\uc5c5\uc5c6\uc5c7\uc5c8\uc5c9\uc5ca\uc5cb\uc5cc\uc5cd\uc5ce\uc5cf\uc5d0\uc5d1\uc5d2\uc5d3\uc5d4\uc5d5\uc5d6\uc5d7\uc5d8\uc5d9\uc5da\uc5db\uc5dc\uc5dd\uc5de\uc5df\uc5e0\uc5e1\uc5e2\uc5e3\uc5e4\uc5e5\uc5e6\uc5e7\uc5e8\uc5e9\uc5ea\uc5eb\uc5ec\uc5ed\uc5ee\uc5ef\uc5f0\uc5f1\uc5f2\uc5f3\uc5f4\uc5f5\uc5f6\uc5f7\uc5f8\uc5f9\uc5fa\uc5fb\uc5fc\uc5fd\uc5fe\uc5ff\uc600\uc601\uc602\uc603\uc604\uc605\uc606\uc607\uc608\uc609\uc60a\uc60b\uc60c\uc60d\uc60e\uc60f\uc610\uc611\uc612\uc613\uc614\uc615\uc616\uc617\uc618\uc619\uc61a\uc61b\uc61c\uc61d\uc61e\uc61f\uc620\uc621\uc622\uc623\uc624\uc625\uc626\uc627\uc628\uc629\uc62a\uc62b\uc62c\uc62d\uc62e\uc62f\uc630\uc631\uc632\uc633\uc634\uc635\uc636\uc637\uc638\uc639\uc63a\uc63b\uc63c\uc63d\uc63e\uc63f\uc640\uc641\uc642\uc643\uc644\uc645\uc646\uc647\uc648\uc649\uc64a\uc64b\uc64c\uc64d\uc64e\uc64f\uc650\uc651\uc652\uc653\uc654\uc655\uc656\uc657\uc658\uc659\uc65a\uc65b\uc65c\uc65d\uc65e\uc65f\uc660\uc661\uc662\uc663\uc664\uc665\uc666\uc667\uc668\uc669\uc66a\uc66b\uc66c\uc66d\uc66e\uc66f\uc670\uc671\uc672\uc673\uc674\uc675\uc676\uc677\uc678\uc679\uc67a\uc67b\uc67c\uc67d\uc67e\uc67f\uc680\uc681\uc682\uc683\uc684\uc685\uc686\uc687\uc688\uc689\uc68a\uc68b\uc68c\uc68d\uc68e\uc68f\uc690\uc691\uc692\uc693\uc694\uc695\uc696\uc697\uc698\uc699\uc69a\uc69b\uc69c\uc69d\uc69e\uc69f\uc6a0\uc6a1\uc6a2\uc6a3\uc6a4\uc6a5\uc6a6\uc6a7\uc6a8\uc6a9\uc6aa\uc6ab\uc6ac\uc6ad\uc6ae\uc6af\uc6b0\uc6b1\uc6b2\uc6b3\uc6b4\uc6b5\uc6b6\uc6b7\uc6b8\uc6b9\uc6ba\uc6bb\uc6bc\uc6bd\uc6be\uc6bf\uc6c0\uc6c1\uc6c2\uc6c3\uc6c4\uc6c5\uc6c6\uc6c7\uc6c8\uc6c9\uc6ca\uc6cb\uc6cc\uc6cd\uc6ce\uc6cf\uc6d0\uc6d1\uc6d2\uc6d3\uc6d4\uc6d5\uc6d6\uc6d7\uc6d8\uc6d9\uc6da\uc6db\uc6dc\uc6dd\uc6de\uc6df\uc6e0\uc6e1\uc6e2\uc6e3\uc6e4\uc6e5\uc6e6\uc6e7\uc6e8\uc6e9\uc6ea\uc6eb\uc6ec\uc6ed\uc6ee\uc6ef\uc6f0\uc6f1\uc6f2\uc6f3\uc6f4\uc6f5\uc6f6\uc6f7\uc6f8\uc6f9\uc6fa\uc6fb\uc6fc\uc6fd\uc6fe\uc6ff\uc700\uc701\uc702\uc703\uc704\uc705\uc706\uc707\uc708\uc709\uc70a\uc70b\uc70c\uc70d\uc70e\uc70f\uc710\uc711\uc712\uc713\uc714\uc715\uc716\uc717\uc718\uc719\uc71a\uc71b\uc71c\uc71d\uc71e\uc71f\uc720\uc721\uc722\uc723\uc724\uc725\uc726\uc727\uc728\uc729\uc72a\uc72b\uc72c\uc72d\uc72e\uc72f\uc730\uc731\uc732\uc733\uc734\uc735\uc736\uc737\uc738\uc739\uc73a\uc73b\uc73c\uc73d\uc73e\uc73f\uc740\uc741\uc742\uc743\uc744\uc745\uc746\uc747\uc748\uc749\uc74a\uc74b\uc74c\uc74d\uc74e\uc74f\uc750\uc751\uc752\uc753\uc754\uc755\uc756\uc757\uc758\uc759\uc75a\uc75b\uc75c\uc75d\uc75e\uc75f\uc760\uc761\uc762\uc763\uc764\uc765\uc766\uc767\uc768\uc769\uc76a\uc76b\uc76c\uc76d\uc76e\uc76f\uc770\uc771\uc772\uc773\uc774\uc775\uc776\uc777\uc778\uc779\uc77a\uc77b\uc77c\uc77d\uc77e\uc77f\uc780\uc781\uc782\uc783\uc784\uc785\uc786\uc787\uc788\uc789\uc78a\uc78b\uc78c\uc78d\uc78e\uc78f\uc790\uc791\uc792\uc793\uc794\uc795\uc796\uc797\uc798\uc799\uc79a\uc79b\uc79c\uc79d\uc79e\uc79f\uc7a0\uc7a1\uc7a2\uc7a3\uc7a4\uc7a5\uc7a6\uc7a7\uc7a8\uc7a9\uc7aa\uc7ab\uc7ac\uc7ad\uc7ae\uc7af\uc7b0\uc7b1\uc7b2\uc7b3\uc7b4\uc7b5\uc7b6\uc7b7\uc7b8\uc7b9\uc7ba\uc7bb\uc7bc\uc7bd\uc7be\uc7bf\uc7c0\uc7c1\uc7c2\uc7c3\uc7c4\uc7c5\uc7c6\uc7c7\uc7c8\uc7c9\uc7ca\uc7cb\uc7cc\uc7cd\uc7ce\uc7cf\uc7d0\uc7d1\uc7d2\uc7d3\uc7d4\uc7d5\uc7d6\uc7d7\uc7d8\uc7d9\uc7da\uc7db\uc7dc\uc7dd\uc7de\uc7df\uc7e0\uc7e1\uc7e2\uc7e3\uc7e4\uc7e5\uc7e6\uc7e7\uc7e8\uc7e9\uc7ea\uc7eb\uc7ec\uc7ed\uc7ee\uc7ef\uc7f0\uc7f1\uc7f2\uc7f3\uc7f4\uc7f5\uc7f6\uc7f7\uc7f8\uc7f9\uc7fa\uc7fb\uc7fc\uc7fd\uc7fe\uc7ff\uc800\uc801\uc802\uc803\uc804\uc805\uc806\uc807\uc808\uc809\uc80a\uc80b\uc80c\uc80d\uc80e\uc80f\uc810\uc811\uc812\uc813\uc814\uc815\uc816\uc817\uc818\uc819\uc81a\uc81b\uc81c\uc81d\uc81e\uc81f\uc820\uc821\uc822\uc823\uc824\uc825\uc826\uc827\uc828\uc829\uc82a\uc82b\uc82c\uc82d\uc82e\uc82f\uc830\uc831\uc832\uc833\uc834\uc835\uc836\uc837\uc838\uc839\uc83a\uc83b\uc83c\uc83d\uc83e\uc83f\uc840\uc841\uc842\uc843\uc844\uc845\uc846\uc847\uc848\uc849\uc84a\uc84b\uc84c\uc84d\uc84e\uc84f\uc850\uc851\uc852\uc853\uc854\uc855\uc856\uc857\uc858\uc859\uc85a\uc85b\uc85c\uc85d\uc85e\uc85f\uc860\uc861\uc862\uc863\uc864\uc865\uc866\uc867\uc868\uc869\uc86a\uc86b\uc86c\uc86d\uc86e\uc86f\uc870\uc871\uc872\uc873\uc874\uc875\uc876\uc877\uc878\uc879\uc87a\uc87b\uc87c\uc87d\uc87e\uc87f\uc880\uc881\uc882\uc883\uc884\uc885\uc886\uc887\uc888\uc889\uc88a\uc88b\uc88c\uc88d\uc88e\uc88f\uc890\uc891\uc892\uc893\uc894\uc895\uc896\uc897\uc898\uc899\uc89a\uc89b\uc89c\uc89d\uc89e\uc89f\uc8a0\uc8a1\uc8a2\uc8a3\uc8a4\uc8a5\uc8a6\uc8a7\uc8a8\uc8a9\uc8aa\uc8ab\uc8ac\uc8ad\uc8ae\uc8af\uc8b0\uc8b1\uc8b2\uc8b3\uc8b4\uc8b5\uc8b6\uc8b7\uc8b8\uc8b9\uc8ba\uc8bb\uc8bc\uc8bd\uc8be\uc8bf\uc8c0\uc8c1\uc8c2\uc8c3\uc8c4\uc8c5\uc8c6\uc8c7\uc8c8\uc8c9\uc8ca\uc8cb\uc8cc\uc8cd\uc8ce\uc8cf\uc8d0\uc8d1\uc8d2\uc8d3\uc8d4\uc8d5\uc8d6\uc8d7\uc8d8\uc8d9\uc8da\uc8db\uc8dc\uc8dd\uc8de\uc8df\uc8e0\uc8e1\uc8e2\uc8e3\uc8e4\uc8e5\uc8e6\uc8e7\uc8e8\uc8e9\uc8ea\uc8eb\uc8ec\uc8ed\uc8ee\uc8ef\uc8f0\uc8f1\uc8f2\uc8f3\uc8f4\uc8f5\uc8f6\uc8f7\uc8f8\uc8f9\uc8fa\uc8fb\uc8fc\uc8fd\uc8fe\uc8ff\uc900\uc901\uc902\uc903\uc904\uc905\uc906\uc907\uc908\uc909\uc90a\uc90b\uc90c\uc90d\uc90e\uc90f\uc910\uc911\uc912\uc913\uc914\uc915\uc916\uc917\uc918\uc919\uc91a\uc91b\uc91c\uc91d\uc91e\uc91f\uc920\uc921\uc922\uc923\uc924\uc925\uc926\uc927\uc928\uc929\uc92a\uc92b\uc92c\uc92d\uc92e\uc92f\uc930\uc931\uc932\uc933\uc934\uc935\uc936\uc937\uc938\uc939\uc93a\uc93b\uc93c\uc93d\uc93e\uc93f\uc940\uc941\uc942\uc943\uc944\uc945\uc946\uc947\uc948\uc949\uc94a\uc94b\uc94c\uc94d\uc94e\uc94f\uc950\uc951\uc952\uc953\uc954\uc955\uc956\uc957\uc958\uc959\uc95a\uc95b\uc95c\uc95d\uc95e\uc95f\uc960\uc961\uc962\uc963\uc964\uc965\uc966\uc967\uc968\uc969\uc96a\uc96b\uc96c\uc96d\uc96e\uc96f\uc970\uc971\uc972\uc973\uc974\uc975\uc976\uc977\uc978\uc979\uc97a\uc97b\uc97c\uc97d\uc97e\uc97f\uc980\uc981\uc982\uc983\uc984\uc985\uc986\uc987\uc988\uc989\uc98a\uc98b\uc98c\uc98d\uc98e\uc98f\uc990\uc991\uc992\uc993\uc994\uc995\uc996\uc997\uc998\uc999\uc99a\uc99b\uc99c\uc99d\uc99e\uc99f\uc9a0\uc9a1\uc9a2\uc9a3\uc9a4\uc9a5\uc9a6\uc9a7\uc9a8\uc9a9\uc9aa\uc9ab\uc9ac\uc9ad\uc9ae\uc9af\uc9b0\uc9b1\uc9b2\uc9b3\uc9b4\uc9b5\uc9b6\uc9b7\uc9b8\uc9b9\uc9ba\uc9bb\uc9bc\uc9bd\uc9be\uc9bf\uc9c0\uc9c1\uc9c2\uc9c3\uc9c4\uc9c5\uc9c6\uc9c7\uc9c8\uc9c9\uc9ca\uc9cb\uc9cc\uc9cd\uc9ce\uc9cf\uc9d0\uc9d1\uc9d2\uc9d3\uc9d4\uc9d5\uc9d6\uc9d7\uc9d8\uc9d9\uc9da\uc9db\uc9dc\uc9dd\uc9de\uc9df\uc9e0\uc9e1\uc9e2\uc9e3\uc9e4\uc9e5\uc9e6\uc9e7\uc9e8\uc9e9\uc9ea\uc9eb\uc9ec\uc9ed\uc9ee\uc9ef\uc9f0\uc9f1\uc9f2\uc9f3\uc9f4\uc9f5\uc9f6\uc9f7\uc9f8\uc9f9\uc9fa\uc9fb\uc9fc\uc9fd\uc9fe\uc9ff\uca00\uca01\uca02\uca03\uca04\uca05\uca06\uca07\uca08\uca09\uca0a\uca0b\uca0c\uca0d\uca0e\uca0f\uca10\uca11\uca12\uca13\uca14\uca15\uca16\uca17\uca18\uca19\uca1a\uca1b\uca1c\uca1d\uca1e\uca1f\uca20\uca21\uca22\uca23\uca24\uca25\uca26\uca27\uca28\uca29\uca2a\uca2b\uca2c\uca2d\uca2e\uca2f\uca30\uca31\uca32\uca33\uca34\uca35\uca36\uca37\uca38\uca39\uca3a\uca3b\uca3c\uca3d\uca3e\uca3f\uca40\uca41\uca42\uca43\uca44\uca45\uca46\uca47\uca48\uca49\uca4a\uca4b\uca4c\uca4d\uca4e\uca4f\uca50\uca51\uca52\uca53\uca54\uca55\uca56\uca57\uca58\uca59\uca5a\uca5b\uca5c\uca5d\uca5e\uca5f\uca60\uca61\uca62\uca63\uca64\uca65\uca66\uca67\uca68\uca69\uca6a\uca6b\uca6c\uca6d\uca6e\uca6f\uca70\uca71\uca72\uca73\uca74\uca75\uca76\uca77\uca78\uca79\uca7a\uca7b\uca7c\uca7d\uca7e\uca7f\uca80\uca81\uca82\uca83\uca84\uca85\uca86\uca87\uca88\uca89\uca8a\uca8b\uca8c\uca8d\uca8e\uca8f\uca90\uca91\uca92\uca93\uca94\uca95\uca96\uca97\uca98\uca99\uca9a\uca9b\uca9c\uca9d\uca9e\uca9f\ucaa0\ucaa1\ucaa2\ucaa3\ucaa4\ucaa5\ucaa6\ucaa7\ucaa8\ucaa9\ucaaa\ucaab\ucaac\ucaad\ucaae\ucaaf\ucab0\ucab1\ucab2\ucab3\ucab4\ucab5\ucab6\ucab7\ucab8\ucab9\ucaba\ucabb\ucabc\ucabd\ucabe\ucabf\ucac0\ucac1\ucac2\ucac3\ucac4\ucac5\ucac6\ucac7\ucac8\ucac9\ucaca\ucacb\ucacc\ucacd\ucace\ucacf\ucad0\ucad1\ucad2\ucad3\ucad4\ucad5\ucad6\ucad7\ucad8\ucad9\ucada\ucadb\ucadc\ucadd\ucade\ucadf\ucae0\ucae1\ucae2\ucae3\ucae4\ucae5\ucae6\ucae7\ucae8\ucae9\ucaea\ucaeb\ucaec\ucaed\ucaee\ucaef\ucaf0\ucaf1\ucaf2\ucaf3\ucaf4\ucaf5\ucaf6\ucaf7\ucaf8\ucaf9\ucafa\ucafb\ucafc\ucafd\ucafe\ucaff\ucb00\ucb01\ucb02\ucb03\ucb04\ucb05\ucb06\ucb07\ucb08\ucb09\ucb0a\ucb0b\ucb0c\ucb0d\ucb0e\ucb0f\ucb10\ucb11\ucb12\ucb13\ucb14\ucb15\ucb16\ucb17\ucb18\ucb19\ucb1a\ucb1b\ucb1c\ucb1d\ucb1e\ucb1f\ucb20\ucb21\ucb22\ucb23\ucb24\ucb25\ucb26\ucb27\ucb28\ucb29\ucb2a\ucb2b\ucb2c\ucb2d\ucb2e\ucb2f\ucb30\ucb31\ucb32\ucb33\ucb34\ucb35\ucb36\ucb37\ucb38\ucb39\ucb3a\ucb3b\ucb3c\ucb3d\ucb3e\ucb3f\ucb40\ucb41\ucb42\ucb43\ucb44\ucb45\ucb46\ucb47\ucb48\ucb49\ucb4a\ucb4b\ucb4c\ucb4d\ucb4e\ucb4f\ucb50\ucb51\ucb52\ucb53\ucb54\ucb55\ucb56\ucb57\ucb58\ucb59\ucb5a\ucb5b\ucb5c\ucb5d\ucb5e\ucb5f\ucb60\ucb61\ucb62\ucb63\ucb64\ucb65\ucb66\ucb67\ucb68\ucb69\ucb6a\ucb6b\ucb6c\ucb6d\ucb6e\ucb6f\ucb70\ucb71\ucb72\ucb73\ucb74\ucb75\ucb76\ucb77\ucb78\ucb79\ucb7a\ucb7b\ucb7c\ucb7d\ucb7e\ucb7f\ucb80\ucb81\ucb82\ucb83\ucb84\ucb85\ucb86\ucb87\ucb88\ucb89\ucb8a\ucb8b\ucb8c\ucb8d\ucb8e\ucb8f\ucb90\ucb91\ucb92\ucb93\ucb94\ucb95\ucb96\ucb97\ucb98\ucb99\ucb9a\ucb9b\ucb9c\ucb9d\ucb9e\ucb9f\ucba0\ucba1\ucba2\ucba3\ucba4\ucba5\ucba6\ucba7\ucba8\ucba9\ucbaa\ucbab\ucbac\ucbad\ucbae\ucbaf\ucbb0\ucbb1\ucbb2\ucbb3\ucbb4\ucbb5\ucbb6\ucbb7\ucbb8\ucbb9\ucbba\ucbbb\ucbbc\ucbbd\ucbbe\ucbbf\ucbc0\ucbc1\ucbc2\ucbc3\ucbc4\ucbc5\ucbc6\ucbc7\ucbc8\ucbc9\ucbca\ucbcb\ucbcc\ucbcd\ucbce\ucbcf\ucbd0\ucbd1\ucbd2\ucbd3\ucbd4\ucbd5\ucbd6\ucbd7\ucbd8\ucbd9\ucbda\ucbdb\ucbdc\ucbdd\ucbde\ucbdf\ucbe0\ucbe1\ucbe2\ucbe3\ucbe4\ucbe5\ucbe6\ucbe7\ucbe8\ucbe9\ucbea\ucbeb\ucbec\ucbed\ucbee\ucbef\ucbf0\ucbf1\ucbf2\ucbf3\ucbf4\ucbf5\ucbf6\ucbf7\ucbf8\ucbf9\ucbfa\ucbfb\ucbfc\ucbfd\ucbfe\ucbff\ucc00\ucc01\ucc02\ucc03\ucc04\ucc05\ucc06\ucc07\ucc08\ucc09\ucc0a\ucc0b\ucc0c\ucc0d\ucc0e\ucc0f\ucc10\ucc11\ucc12\ucc13\ucc14\ucc15\ucc16\ucc17\ucc18\ucc19\ucc1a\ucc1b\ucc1c\ucc1d\ucc1e\ucc1f\ucc20\ucc21\ucc22\ucc23\ucc24\ucc25\ucc26\ucc27\ucc28\ucc29\ucc2a\ucc2b\ucc2c\ucc2d\ucc2e\ucc2f\ucc30\ucc31\ucc32\ucc33\ucc34\ucc35\ucc36\ucc37\ucc38\ucc39\ucc3a\ucc3b\ucc3c\ucc3d\ucc3e\ucc3f\ucc40\ucc41\ucc42\ucc43\ucc44\ucc45\ucc46\ucc47\ucc48\ucc49\ucc4a\ucc4b\ucc4c\ucc4d\ucc4e\ucc4f\ucc50\ucc51\ucc52\ucc53\ucc54\ucc55\ucc56\ucc57\ucc58\ucc59\ucc5a\ucc5b\ucc5c\ucc5d\ucc5e\ucc5f\ucc60\ucc61\ucc62\ucc63\ucc64\ucc65\ucc66\ucc67\ucc68\ucc69\ucc6a\ucc6b\ucc6c\ucc6d\ucc6e\ucc6f\ucc70\ucc71\ucc72\ucc73\ucc74\ucc75\ucc76\ucc77\ucc78\ucc79\ucc7a\ucc7b\ucc7c\ucc7d\ucc7e\ucc7f\ucc80\ucc81\ucc82\ucc83\ucc84\ucc85\ucc86\ucc87\ucc88\ucc89\ucc8a\ucc8b\ucc8c\ucc8d\ucc8e\ucc8f\ucc90\ucc91\ucc92\ucc93\ucc94\ucc95\ucc96\ucc97\ucc98\ucc99\ucc9a\ucc9b\ucc9c\ucc9d\ucc9e\ucc9f\ucca0\ucca1\ucca2\ucca3\ucca4\ucca5\ucca6\ucca7\ucca8\ucca9\uccaa\uccab\uccac\uccad\uccae\uccaf\uccb0\uccb1\uccb2\uccb3\uccb4\uccb5\uccb6\uccb7\uccb8\uccb9\uccba\uccbb\uccbc\uccbd\uccbe\uccbf\uccc0\uccc1\uccc2\uccc3\uccc4\uccc5\uccc6\uccc7\uccc8\uccc9\uccca\ucccb\ucccc\ucccd\uccce\ucccf\uccd0\uccd1\uccd2\uccd3\uccd4\uccd5\uccd6\uccd7\uccd8\uccd9\uccda\uccdb\uccdc\uccdd\uccde\uccdf\ucce0\ucce1\ucce2\ucce3\ucce4\ucce5\ucce6\ucce7\ucce8\ucce9\uccea\ucceb\uccec\ucced\uccee\uccef\uccf0\uccf1\uccf2\uccf3\uccf4\uccf5\uccf6\uccf7\uccf8\uccf9\uccfa\uccfb\uccfc\uccfd\uccfe\uccff\ucd00\ucd01\ucd02\ucd03\ucd04\ucd05\ucd06\ucd07\ucd08\ucd09\ucd0a\ucd0b\ucd0c\ucd0d\ucd0e\ucd0f\ucd10\ucd11\ucd12\ucd13\ucd14\ucd15\ucd16\ucd17\ucd18\ucd19\ucd1a\ucd1b\ucd1c\ucd1d\ucd1e\ucd1f\ucd20\ucd21\ucd22\ucd23\ucd24\ucd25\ucd26\ucd27\ucd28\ucd29\ucd2a\ucd2b\ucd2c\ucd2d\ucd2e\ucd2f\ucd30\ucd31\ucd32\ucd33\ucd34\ucd35\ucd36\ucd37\ucd38\ucd39\ucd3a\ucd3b\ucd3c\ucd3d\ucd3e\ucd3f\ucd40\ucd41\ucd42\ucd43\ucd44\ucd45\ucd46\ucd47\ucd48\ucd49\ucd4a\ucd4b\ucd4c\ucd4d\ucd4e\ucd4f\ucd50\ucd51\ucd52\ucd53\ucd54\ucd55\ucd56\ucd57\ucd58\ucd59\ucd5a\ucd5b\ucd5c\ucd5d\ucd5e\ucd5f\ucd60\ucd61\ucd62\ucd63\ucd64\ucd65\ucd66\ucd67\ucd68\ucd69\ucd6a\ucd6b\ucd6c\ucd6d\ucd6e\ucd6f\ucd70\ucd71\ucd72\ucd73\ucd74\ucd75\ucd76\ucd77\ucd78\ucd79\ucd7a\ucd7b\ucd7c\ucd7d\ucd7e\ucd7f\ucd80\ucd81\ucd82\ucd83\ucd84\ucd85\ucd86\ucd87\ucd88\ucd89\ucd8a\ucd8b\ucd8c\ucd8d\ucd8e\ucd8f\ucd90\ucd91\ucd92\ucd93\ucd94\ucd95\ucd96\ucd97\ucd98\ucd99\ucd9a\ucd9b\ucd9c\ucd9d\ucd9e\ucd9f\ucda0\ucda1\ucda2\ucda3\ucda4\ucda5\ucda6\ucda7\ucda8\ucda9\ucdaa\ucdab\ucdac\ucdad\ucdae\ucdaf\ucdb0\ucdb1\ucdb2\ucdb3\ucdb4\ucdb5\ucdb6\ucdb7\ucdb8\ucdb9\ucdba\ucdbb\ucdbc\ucdbd\ucdbe\ucdbf\ucdc0\ucdc1\ucdc2\ucdc3\ucdc4\ucdc5\ucdc6\ucdc7\ucdc8\ucdc9\ucdca\ucdcb\ucdcc\ucdcd\ucdce\ucdcf\ucdd0\ucdd1\ucdd2\ucdd3\ucdd4\ucdd5\ucdd6\ucdd7\ucdd8\ucdd9\ucdda\ucddb\ucddc\ucddd\ucdde\ucddf\ucde0\ucde1\ucde2\ucde3\ucde4\ucde5\ucde6\ucde7\ucde8\ucde9\ucdea\ucdeb\ucdec\ucded\ucdee\ucdef\ucdf0\ucdf1\ucdf2\ucdf3\ucdf4\ucdf5\ucdf6\ucdf7\ucdf8\ucdf9\ucdfa\ucdfb\ucdfc\ucdfd\ucdfe\ucdff\uce00\uce01\uce02\uce03\uce04\uce05\uce06\uce07\uce08\uce09\uce0a\uce0b\uce0c\uce0d\uce0e\uce0f\uce10\uce11\uce12\uce13\uce14\uce15\uce16\uce17\uce18\uce19\uce1a\uce1b\uce1c\uce1d\uce1e\uce1f\uce20\uce21\uce22\uce23\uce24\uce25\uce26\uce27\uce28\uce29\uce2a\uce2b\uce2c\uce2d\uce2e\uce2f\uce30\uce31\uce32\uce33\uce34\uce35\uce36\uce37\uce38\uce39\uce3a\uce3b\uce3c\uce3d\uce3e\uce3f\uce40\uce41\uce42\uce43\uce44\uce45\uce46\uce47\uce48\uce49\uce4a\uce4b\uce4c\uce4d\uce4e\uce4f\uce50\uce51\uce52\uce53\uce54\uce55\uce56\uce57\uce58\uce59\uce5a\uce5b\uce5c\uce5d\uce5e\uce5f\uce60\uce61\uce62\uce63\uce64\uce65\uce66\uce67\uce68\uce69\uce6a\uce6b\uce6c\uce6d\uce6e\uce6f\uce70\uce71\uce72\uce73\uce74\uce75\uce76\uce77\uce78\uce79\uce7a\uce7b\uce7c\uce7d\uce7e\uce7f\uce80\uce81\uce82\uce83\uce84\uce85\uce86\uce87\uce88\uce89\uce8a\uce8b\uce8c\uce8d\uce8e\uce8f\uce90\uce91\uce92\uce93\uce94\uce95\uce96\uce97\uce98\uce99\uce9a\uce9b\uce9c\uce9d\uce9e\uce9f\ucea0\ucea1\ucea2\ucea3\ucea4\ucea5\ucea6\ucea7\ucea8\ucea9\uceaa\uceab\uceac\ucead\uceae\uceaf\uceb0\uceb1\uceb2\uceb3\uceb4\uceb5\uceb6\uceb7\uceb8\uceb9\uceba\ucebb\ucebc\ucebd\ucebe\ucebf\ucec0\ucec1\ucec2\ucec3\ucec4\ucec5\ucec6\ucec7\ucec8\ucec9\uceca\ucecb\ucecc\ucecd\ucece\ucecf\uced0\uced1\uced2\uced3\uced4\uced5\uced6\uced7\uced8\uced9\uceda\ucedb\ucedc\ucedd\ucede\ucedf\ucee0\ucee1\ucee2\ucee3\ucee4\ucee5\ucee6\ucee7\ucee8\ucee9\uceea\uceeb\uceec\uceed\uceee\uceef\ucef0\ucef1\ucef2\ucef3\ucef4\ucef5\ucef6\ucef7\ucef8\ucef9\ucefa\ucefb\ucefc\ucefd\ucefe\uceff\ucf00\ucf01\ucf02\ucf03\ucf04\ucf05\ucf06\ucf07\ucf08\ucf09\ucf0a\ucf0b\ucf0c\ucf0d\ucf0e\ucf0f\ucf10\ucf11\ucf12\ucf13\ucf14\ucf15\ucf16\ucf17\ucf18\ucf19\ucf1a\ucf1b\ucf1c\ucf1d\ucf1e\ucf1f\ucf20\ucf21\ucf22\ucf23\ucf24\ucf25\ucf26\ucf27\ucf28\ucf29\ucf2a\ucf2b\ucf2c\ucf2d\ucf2e\ucf2f\ucf30\ucf31\ucf32\ucf33\ucf34\ucf35\ucf36\ucf37\ucf38\ucf39\ucf3a\ucf3b\ucf3c\ucf3d\ucf3e\ucf3f\ucf40\ucf41\ucf42\ucf43\ucf44\ucf45\ucf46\ucf47\ucf48\ucf49\ucf4a\ucf4b\ucf4c\ucf4d\ucf4e\ucf4f\ucf50\ucf51\ucf52\ucf53\ucf54\ucf55\ucf56\ucf57\ucf58\ucf59\ucf5a\ucf5b\ucf5c\ucf5d\ucf5e\ucf5f\ucf60\ucf61\ucf62\ucf63\ucf64\ucf65\ucf66\ucf67\ucf68\ucf69\ucf6a\ucf6b\ucf6c\ucf6d\ucf6e\ucf6f\ucf70\ucf71\ucf72\ucf73\ucf74\ucf75\ucf76\ucf77\ucf78\ucf79\ucf7a\ucf7b\ucf7c\ucf7d\ucf7e\ucf7f\ucf80\ucf81\ucf82\ucf83\ucf84\ucf85\ucf86\ucf87\ucf88\ucf89\ucf8a\ucf8b\ucf8c\ucf8d\ucf8e\ucf8f\ucf90\ucf91\ucf92\ucf93\ucf94\ucf95\ucf96\ucf97\ucf98\ucf99\ucf9a\ucf9b\ucf9c\ucf9d\ucf9e\ucf9f\ucfa0\ucfa1\ucfa2\ucfa3\ucfa4\ucfa5\ucfa6\ucfa7\ucfa8\ucfa9\ucfaa\ucfab\ucfac\ucfad\ucfae\ucfaf\ucfb0\ucfb1\ucfb2\ucfb3\ucfb4\ucfb5\ucfb6\ucfb7\ucfb8\ucfb9\ucfba\ucfbb\ucfbc\ucfbd\ucfbe\ucfbf\ucfc0\ucfc1\ucfc2\ucfc3\ucfc4\ucfc5\ucfc6\ucfc7\ucfc8\ucfc9\ucfca\ucfcb\ucfcc\ucfcd\ucfce\ucfcf\ucfd0\ucfd1\ucfd2\ucfd3\ucfd4\ucfd5\ucfd6\ucfd7\ucfd8\ucfd9\ucfda\ucfdb\ucfdc\ucfdd\ucfde\ucfdf\ucfe0\ucfe1\ucfe2\ucfe3\ucfe4\ucfe5\ucfe6\ucfe7\ucfe8\ucfe9\ucfea\ucfeb\ucfec\ucfed\ucfee\ucfef\ucff0\ucff1\ucff2\ucff3\ucff4\ucff5\ucff6\ucff7\ucff8\ucff9\ucffa\ucffb\ucffc\ucffd\ucffe\ucfff\ud000\ud001\ud002\ud003\ud004\ud005\ud006\ud007\ud008\ud009\ud00a\ud00b\ud00c\ud00d\ud00e\ud00f\ud010\ud011\ud012\ud013\ud014\ud015\ud016\ud017\ud018\ud019\ud01a\ud01b\ud01c\ud01d\ud01e\ud01f\ud020\ud021\ud022\ud023\ud024\ud025\ud026\ud027\ud028\ud029\ud02a\ud02b\ud02c\ud02d\ud02e\ud02f\ud030\ud031\ud032\ud033\ud034\ud035\ud036\ud037\ud038\ud039\ud03a\ud03b\ud03c\ud03d\ud03e\ud03f\ud040\ud041\ud042\ud043\ud044\ud045\ud046\ud047\ud048\ud049\ud04a\ud04b\ud04c\ud04d\ud04e\ud04f\ud050\ud051\ud052\ud053\ud054\ud055\ud056\ud057\ud058\ud059\ud05a\ud05b\ud05c\ud05d\ud05e\ud05f\ud060\ud061\ud062\ud063\ud064\ud065\ud066\ud067\ud068\ud069\ud06a\ud06b\ud06c\ud06d\ud06e\ud06f\ud070\ud071\ud072\ud073\ud074\ud075\ud076\ud077\ud078\ud079\ud07a\ud07b\ud07c\ud07d\ud07e\ud07f\ud080\ud081\ud082\ud083\ud084\ud085\ud086\ud087\ud088\ud089\ud08a\ud08b\ud08c\ud08d\ud08e\ud08f\ud090\ud091\ud092\ud093\ud094\ud095\ud096\ud097\ud098\ud099\ud09a\ud09b\ud09c\ud09d\ud09e\ud09f\ud0a0\ud0a1\ud0a2\ud0a3\ud0a4\ud0a5\ud0a6\ud0a7\ud0a8\ud0a9\ud0aa\ud0ab\ud0ac\ud0ad\ud0ae\ud0af\ud0b0\ud0b1\ud0b2\ud0b3\ud0b4\ud0b5\ud0b6\ud0b7\ud0b8\ud0b9\ud0ba\ud0bb\ud0bc\ud0bd\ud0be\ud0bf\ud0c0\ud0c1\ud0c2\ud0c3\ud0c4\ud0c5\ud0c6\ud0c7\ud0c8\ud0c9\ud0ca\ud0cb\ud0cc\ud0cd\ud0ce\ud0cf\ud0d0\ud0d1\ud0d2\ud0d3\ud0d4\ud0d5\ud0d6\ud0d7\ud0d8\ud0d9\ud0da\ud0db\ud0dc\ud0dd\ud0de\ud0df\ud0e0\ud0e1\ud0e2\ud0e3\ud0e4\ud0e5\ud0e6\ud0e7\ud0e8\ud0e9\ud0ea\ud0eb\ud0ec\ud0ed\ud0ee\ud0ef\ud0f0\ud0f1\ud0f2\ud0f3\ud0f4\ud0f5\ud0f6\ud0f7\ud0f8\ud0f9\ud0fa\ud0fb\ud0fc\ud0fd\ud0fe\ud0ff\ud100\ud101\ud102\ud103\ud104\ud105\ud106\ud107\ud108\ud109\ud10a\ud10b\ud10c\ud10d\ud10e\ud10f\ud110\ud111\ud112\ud113\ud114\ud115\ud116\ud117\ud118\ud119\ud11a\ud11b\ud11c\ud11d\ud11e\ud11f\ud120\ud121\ud122\ud123\ud124\ud125\ud126\ud127\ud128\ud129\ud12a\ud12b\ud12c\ud12d\ud12e\ud12f\ud130\ud131\ud132\ud133\ud134\ud135\ud136\ud137\ud138\ud139\ud13a\ud13b\ud13c\ud13d\ud13e\ud13f\ud140\ud141\ud142\ud143\ud144\ud145\ud146\ud147\ud148\ud149\ud14a\ud14b\ud14c\ud14d\ud14e\ud14f\ud150\ud151\ud152\ud153\ud154\ud155\ud156\ud157\ud158\ud159\ud15a\ud15b\ud15c\ud15d\ud15e\ud15f\ud160\ud161\ud162\ud163\ud164\ud165\ud166\ud167\ud168\ud169\ud16a\ud16b\ud16c\ud16d\ud16e\ud16f\ud170\ud171\ud172\ud173\ud174\ud175\ud176\ud177\ud178\ud179\ud17a\ud17b\ud17c\ud17d\ud17e\ud17f\ud180\ud181\ud182\ud183\ud184\ud185\ud186\ud187\ud188\ud189\ud18a\ud18b\ud18c\ud18d\ud18e\ud18f\ud190\ud191\ud192\ud193\ud194\ud195\ud196\ud197\ud198\ud199\ud19a\ud19b\ud19c\ud19d\ud19e\ud19f\ud1a0\ud1a1\ud1a2\ud1a3\ud1a4\ud1a5\ud1a6\ud1a7\ud1a8\ud1a9\ud1aa\ud1ab\ud1ac\ud1ad\ud1ae\ud1af\ud1b0\ud1b1\ud1b2\ud1b3\ud1b4\ud1b5\ud1b6\ud1b7\ud1b8\ud1b9\ud1ba\ud1bb\ud1bc\ud1bd\ud1be\ud1bf\ud1c0\ud1c1\ud1c2\ud1c3\ud1c4\ud1c5\ud1c6\ud1c7\ud1c8\ud1c9\ud1ca\ud1cb\ud1cc\ud1cd\ud1ce\ud1cf\ud1d0\ud1d1\ud1d2\ud1d3\ud1d4\ud1d5\ud1d6\ud1d7\ud1d8\ud1d9\ud1da\ud1db\ud1dc\ud1dd\ud1de\ud1df\ud1e0\ud1e1\ud1e2\ud1e3\ud1e4\ud1e5\ud1e6\ud1e7\ud1e8\ud1e9\ud1ea\ud1eb\ud1ec\ud1ed\ud1ee\ud1ef\ud1f0\ud1f1\ud1f2\ud1f3\ud1f4\ud1f5\ud1f6\ud1f7\ud1f8\ud1f9\ud1fa\ud1fb\ud1fc\ud1fd\ud1fe\ud1ff\ud200\ud201\ud202\ud203\ud204\ud205\ud206\ud207\ud208\ud209\ud20a\ud20b\ud20c\ud20d\ud20e\ud20f\ud210\ud211\ud212\ud213\ud214\ud215\ud216\ud217\ud218\ud219\ud21a\ud21b\ud21c\ud21d\ud21e\ud21f\ud220\ud221\ud222\ud223\ud224\ud225\ud226\ud227\ud228\ud229\ud22a\ud22b\ud22c\ud22d\ud22e\ud22f\ud230\ud231\ud232\ud233\ud234\ud235\ud236\ud237\ud238\ud239\ud23a\ud23b\ud23c\ud23d\ud23e\ud23f\ud240\ud241\ud242\ud243\ud244\ud245\ud246\ud247\ud248\ud249\ud24a\ud24b\ud24c\ud24d\ud24e\ud24f\ud250\ud251\ud252\ud253\ud254\ud255\ud256\ud257\ud258\ud259\ud25a\ud25b\ud25c\ud25d\ud25e\ud25f\ud260\ud261\ud262\ud263\ud264\ud265\ud266\ud267\ud268\ud269\ud26a\ud26b\ud26c\ud26d\ud26e\ud26f\ud270\ud271\ud272\ud273\ud274\ud275\ud276\ud277\ud278\ud279\ud27a\ud27b\ud27c\ud27d\ud27e\ud27f\ud280\ud281\ud282\ud283\ud284\ud285\ud286\ud287\ud288\ud289\ud28a\ud28b\ud28c\ud28d\ud28e\ud28f\ud290\ud291\ud292\ud293\ud294\ud295\ud296\ud297\ud298\ud299\ud29a\ud29b\ud29c\ud29d\ud29e\ud29f\ud2a0\ud2a1\ud2a2\ud2a3\ud2a4\ud2a5\ud2a6\ud2a7\ud2a8\ud2a9\ud2aa\ud2ab\ud2ac\ud2ad\ud2ae\ud2af\ud2b0\ud2b1\ud2b2\ud2b3\ud2b4\ud2b5\ud2b6\ud2b7\ud2b8\ud2b9\ud2ba\ud2bb\ud2bc\ud2bd\ud2be\ud2bf\ud2c0\ud2c1\ud2c2\ud2c3\ud2c4\ud2c5\ud2c6\ud2c7\ud2c8\ud2c9\ud2ca\ud2cb\ud2cc\ud2cd\ud2ce\ud2cf\ud2d0\ud2d1\ud2d2\ud2d3\ud2d4\ud2d5\ud2d6\ud2d7\ud2d8\ud2d9\ud2da\ud2db\ud2dc\ud2dd\ud2de\ud2df\ud2e0\ud2e1\ud2e2\ud2e3\ud2e4\ud2e5\ud2e6\ud2e7\ud2e8\ud2e9\ud2ea\ud2eb\ud2ec\ud2ed\ud2ee\ud2ef\ud2f0\ud2f1\ud2f2\ud2f3\ud2f4\ud2f5\ud2f6\ud2f7\ud2f8\ud2f9\ud2fa\ud2fb\ud2fc\ud2fd\ud2fe\ud2ff\ud300\ud301\ud302\ud303\ud304\ud305\ud306\ud307\ud308\ud309\ud30a\ud30b\ud30c\ud30d\ud30e\ud30f\ud310\ud311\ud312\ud313\ud314\ud315\ud316\ud317\ud318\ud319\ud31a\ud31b\ud31c\ud31d\ud31e\ud31f\ud320\ud321\ud322\ud323\ud324\ud325\ud326\ud327\ud328\ud329\ud32a\ud32b\ud32c\ud32d\ud32e\ud32f\ud330\ud331\ud332\ud333\ud334\ud335\ud336\ud337\ud338\ud339\ud33a\ud33b\ud33c\ud33d\ud33e\ud33f\ud340\ud341\ud342\ud343\ud344\ud345\ud346\ud347\ud348\ud349\ud34a\ud34b\ud34c\ud34d\ud34e\ud34f\ud350\ud351\ud352\ud353\ud354\ud355\ud356\ud357\ud358\ud359\ud35a\ud35b\ud35c\ud35d\ud35e\ud35f\ud360\ud361\ud362\ud363\ud364\ud365\ud366\ud367\ud368\ud369\ud36a\ud36b\ud36c\ud36d\ud36e\ud36f\ud370\ud371\ud372\ud373\ud374\ud375\ud376\ud377\ud378\ud379\ud37a\ud37b\ud37c\ud37d\ud37e\ud37f\ud380\ud381\ud382\ud383\ud384\ud385\ud386\ud387\ud388\ud389\ud38a\ud38b\ud38c\ud38d\ud38e\ud38f\ud390\ud391\ud392\ud393\ud394\ud395\ud396\ud397\ud398\ud399\ud39a\ud39b\ud39c\ud39d\ud39e\ud39f\ud3a0\ud3a1\ud3a2\ud3a3\ud3a4\ud3a5\ud3a6\ud3a7\ud3a8\ud3a9\ud3aa\ud3ab\ud3ac\ud3ad\ud3ae\ud3af\ud3b0\ud3b1\ud3b2\ud3b3\ud3b4\ud3b5\ud3b6\ud3b7\ud3b8\ud3b9\ud3ba\ud3bb\ud3bc\ud3bd\ud3be\ud3bf\ud3c0\ud3c1\ud3c2\ud3c3\ud3c4\ud3c5\ud3c6\ud3c7\ud3c8\ud3c9\ud3ca\ud3cb\ud3cc\ud3cd\ud3ce\ud3cf\ud3d0\ud3d1\ud3d2\ud3d3\ud3d4\ud3d5\ud3d6\ud3d7\ud3d8\ud3d9\ud3da\ud3db\ud3dc\ud3dd\ud3de\ud3df\ud3e0\ud3e1\ud3e2\ud3e3\ud3e4\ud3e5\ud3e6\ud3e7\ud3e8\ud3e9\ud3ea\ud3eb\ud3ec\ud3ed\ud3ee\ud3ef\ud3f0\ud3f1\ud3f2\ud3f3\ud3f4\ud3f5\ud3f6\ud3f7\ud3f8\ud3f9\ud3fa\ud3fb\ud3fc\ud3fd\ud3fe\ud3ff\ud400\ud401\ud402\ud403\ud404\ud405\ud406\ud407\ud408\ud409\ud40a\ud40b\ud40c\ud40d\ud40e\ud40f\ud410\ud411\ud412\ud413\ud414\ud415\ud416\ud417\ud418\ud419\ud41a\ud41b\ud41c\ud41d\ud41e\ud41f\ud420\ud421\ud422\ud423\ud424\ud425\ud426\ud427\ud428\ud429\ud42a\ud42b\ud42c\ud42d\ud42e\ud42f\ud430\ud431\ud432\ud433\ud434\ud435\ud436\ud437\ud438\ud439\ud43a\ud43b\ud43c\ud43d\ud43e\ud43f\ud440\ud441\ud442\ud443\ud444\ud445\ud446\ud447\ud448\ud449\ud44a\ud44b\ud44c\ud44d\ud44e\ud44f\ud450\ud451\ud452\ud453\ud454\ud455\ud456\ud457\ud458\ud459\ud45a\ud45b\ud45c\ud45d\ud45e\ud45f\ud460\ud461\ud462\ud463\ud464\ud465\ud466\ud467\ud468\ud469\ud46a\ud46b\ud46c\ud46d\ud46e\ud46f\ud470\ud471\ud472\ud473\ud474\ud475\ud476\ud477\ud478\ud479\ud47a\ud47b\ud47c\ud47d\ud47e\ud47f\ud480\ud481\ud482\ud483\ud484\ud485\ud486\ud487\ud488\ud489\ud48a\ud48b\ud48c\ud48d\ud48e\ud48f\ud490\ud491\ud492\ud493\ud494\ud495\ud496\ud497\ud498\ud499\ud49a\ud49b\ud49c\ud49d\ud49e\ud49f\ud4a0\ud4a1\ud4a2\ud4a3\ud4a4\ud4a5\ud4a6\ud4a7\ud4a8\ud4a9\ud4aa\ud4ab\ud4ac\ud4ad\ud4ae\ud4af\ud4b0\ud4b1\ud4b2\ud4b3\ud4b4\ud4b5\ud4b6\ud4b7\ud4b8\ud4b9\ud4ba\ud4bb\ud4bc\ud4bd\ud4be\ud4bf\ud4c0\ud4c1\ud4c2\ud4c3\ud4c4\ud4c5\ud4c6\ud4c7\ud4c8\ud4c9\ud4ca\ud4cb\ud4cc\ud4cd\ud4ce\ud4cf\ud4d0\ud4d1\ud4d2\ud4d3\ud4d4\ud4d5\ud4d6\ud4d7\ud4d8\ud4d9\ud4da\ud4db\ud4dc\ud4dd\ud4de\ud4df\ud4e0\ud4e1\ud4e2\ud4e3\ud4e4\ud4e5\ud4e6\ud4e7\ud4e8\ud4e9\ud4ea\ud4eb\ud4ec\ud4ed\ud4ee\ud4ef\ud4f0\ud4f1\ud4f2\ud4f3\ud4f4\ud4f5\ud4f6\ud4f7\ud4f8\ud4f9\ud4fa\ud4fb\ud4fc\ud4fd\ud4fe\ud4ff\ud500\ud501\ud502\ud503\ud504\ud505\ud506\ud507\ud508\ud509\ud50a\ud50b\ud50c\ud50d\ud50e\ud50f\ud510\ud511\ud512\ud513\ud514\ud515\ud516\ud517\ud518\ud519\ud51a\ud51b\ud51c\ud51d\ud51e\ud51f\ud520\ud521\ud522\ud523\ud524\ud525\ud526\ud527\ud528\ud529\ud52a\ud52b\ud52c\ud52d\ud52e\ud52f\ud530\ud531\ud532\ud533\ud534\ud535\ud536\ud537\ud538\ud539\ud53a\ud53b\ud53c\ud53d\ud53e\ud53f\ud540\ud541\ud542\ud543\ud544\ud545\ud546\ud547\ud548\ud549\ud54a\ud54b\ud54c\ud54d\ud54e\ud54f\ud550\ud551\ud552\ud553\ud554\ud555\ud556\ud557\ud558\ud559\ud55a\ud55b\ud55c\ud55d\ud55e\ud55f\ud560\ud561\ud562\ud563\ud564\ud565\ud566\ud567\ud568\ud569\ud56a\ud56b\ud56c\ud56d\ud56e\ud56f\ud570\ud571\ud572\ud573\ud574\ud575\ud576\ud577\ud578\ud579\ud57a\ud57b\ud57c\ud57d\ud57e\ud57f\ud580\ud581\ud582\ud583\ud584\ud585\ud586\ud587\ud588\ud589\ud58a\ud58b\ud58c\ud58d\ud58e\ud58f\ud590\ud591\ud592\ud593\ud594\ud595\ud596\ud597\ud598\ud599\ud59a\ud59b\ud59c\ud59d\ud59e\ud59f\ud5a0\ud5a1\ud5a2\ud5a3\ud5a4\ud5a5\ud5a6\ud5a7\ud5a8\ud5a9\ud5aa\ud5ab\ud5ac\ud5ad\ud5ae\ud5af\ud5b0\ud5b1\ud5b2\ud5b3\ud5b4\ud5b5\ud5b6\ud5b7\ud5b8\ud5b9\ud5ba\ud5bb\ud5bc\ud5bd\ud5be\ud5bf\ud5c0\ud5c1\ud5c2\ud5c3\ud5c4\ud5c5\ud5c6\ud5c7\ud5c8\ud5c9\ud5ca\ud5cb\ud5cc\ud5cd\ud5ce\ud5cf\ud5d0\ud5d1\ud5d2\ud5d3\ud5d4\ud5d5\ud5d6\ud5d7\ud5d8\ud5d9\ud5da\ud5db\ud5dc\ud5dd\ud5de\ud5df\ud5e0\ud5e1\ud5e2\ud5e3\ud5e4\ud5e5\ud5e6\ud5e7\ud5e8\ud5e9\ud5ea\ud5eb\ud5ec\ud5ed\ud5ee\ud5ef\ud5f0\ud5f1\ud5f2\ud5f3\ud5f4\ud5f5\ud5f6\ud5f7\ud5f8\ud5f9\ud5fa\ud5fb\ud5fc\ud5fd\ud5fe\ud5ff\ud600\ud601\ud602\ud603\ud604\ud605\ud606\ud607\ud608\ud609\ud60a\ud60b\ud60c\ud60d\ud60e\ud60f\ud610\ud611\ud612\ud613\ud614\ud615\ud616\ud617\ud618\ud619\ud61a\ud61b\ud61c\ud61d\ud61e\ud61f\ud620\ud621\ud622\ud623\ud624\ud625\ud626\ud627\ud628\ud629\ud62a\ud62b\ud62c\ud62d\ud62e\ud62f\ud630\ud631\ud632\ud633\ud634\ud635\ud636\ud637\ud638\ud639\ud63a\ud63b\ud63c\ud63d\ud63e\ud63f\ud640\ud641\ud642\ud643\ud644\ud645\ud646\ud647\ud648\ud649\ud64a\ud64b\ud64c\ud64d\ud64e\ud64f\ud650\ud651\ud652\ud653\ud654\ud655\ud656\ud657\ud658\ud659\ud65a\ud65b\ud65c\ud65d\ud65e\ud65f\ud660\ud661\ud662\ud663\ud664\ud665\ud666\ud667\ud668\ud669\ud66a\ud66b\ud66c\ud66d\ud66e\ud66f\ud670\ud671\ud672\ud673\ud674\ud675\ud676\ud677\ud678\ud679\ud67a\ud67b\ud67c\ud67d\ud67e\ud67f\ud680\ud681\ud682\ud683\ud684\ud685\ud686\ud687\ud688\ud689\ud68a\ud68b\ud68c\ud68d\ud68e\ud68f\ud690\ud691\ud692\ud693\ud694\ud695\ud696\ud697\ud698\ud699\ud69a\ud69b\ud69c\ud69d\ud69e\ud69f\ud6a0\ud6a1\ud6a2\ud6a3\ud6a4\ud6a5\ud6a6\ud6a7\ud6a8\ud6a9\ud6aa\ud6ab\ud6ac\ud6ad\ud6ae\ud6af\ud6b0\ud6b1\ud6b2\ud6b3\ud6b4\ud6b5\ud6b6\ud6b7\ud6b8\ud6b9\ud6ba\ud6bb\ud6bc\ud6bd\ud6be\ud6bf\ud6c0\ud6c1\ud6c2\ud6c3\ud6c4\ud6c5\ud6c6\ud6c7\ud6c8\ud6c9\ud6ca\ud6cb\ud6cc\ud6cd\ud6ce\ud6cf\ud6d0\ud6d1\ud6d2\ud6d3\ud6d4\ud6d5\ud6d6\ud6d7\ud6d8\ud6d9\ud6da\ud6db\ud6dc\ud6dd\ud6de\ud6df\ud6e0\ud6e1\ud6e2\ud6e3\ud6e4\ud6e5\ud6e6\ud6e7\ud6e8\ud6e9\ud6ea\ud6eb\ud6ec\ud6ed\ud6ee\ud6ef\ud6f0\ud6f1\ud6f2\ud6f3\ud6f4\ud6f5\ud6f6\ud6f7\ud6f8\ud6f9\ud6fa\ud6fb\ud6fc\ud6fd\ud6fe\ud6ff\ud700\ud701\ud702\ud703\ud704\ud705\ud706\ud707\ud708\ud709\ud70a\ud70b\ud70c\ud70d\ud70e\ud70f\ud710\ud711\ud712\ud713\ud714\ud715\ud716\ud717\ud718\ud719\ud71a\ud71b\ud71c\ud71d\ud71e\ud71f\ud720\ud721\ud722\ud723\ud724\ud725\ud726\ud727\ud728\ud729\ud72a\ud72b\ud72c\ud72d\ud72e\ud72f\ud730\ud731\ud732\ud733\ud734\ud735\ud736\ud737\ud738\ud739\ud73a\ud73b\ud73c\ud73d\ud73e\ud73f\ud740\ud741\ud742\ud743\ud744\ud745\ud746\ud747\ud748\ud749\ud74a\ud74b\ud74c\ud74d\ud74e\ud74f\ud750\ud751\ud752\ud753\ud754\ud755\ud756\ud757\ud758\ud759\ud75a\ud75b\ud75c\ud75d\ud75e\ud75f\ud760\ud761\ud762\ud763\ud764\ud765\ud766\ud767\ud768\ud769\ud76a\ud76b\ud76c\ud76d\ud76e\ud76f\ud770\ud771\ud772\ud773\ud774\ud775\ud776\ud777\ud778\ud779\ud77a\ud77b\ud77c\ud77d\ud77e\ud77f\ud780\ud781\ud782\ud783\ud784\ud785\ud786\ud787\ud788\ud789\ud78a\ud78b\ud78c\ud78d\ud78e\ud78f\ud790\ud791\ud792\ud793\ud794\ud795\ud796\ud797\ud798\ud799\ud79a\ud79b\ud79c\ud79d\ud79e\ud79f\ud7a0\ud7a1\ud7a2\ud7a3\uf900\uf901\uf902\uf903\uf904\uf905\uf906\uf907\uf908\uf909\uf90a\uf90b\uf90c\uf90d\uf90e\uf90f\uf910\uf911\uf912\uf913\uf914\uf915\uf916\uf917\uf918\uf919\uf91a\uf91b\uf91c\uf91d\uf91e\uf91f\uf920\uf921\uf922\uf923\uf924\uf925\uf926\uf927\uf928\uf929\uf92a\uf92b\uf92c\uf92d\uf92e\uf92f\uf930\uf931\uf932\uf933\uf934\uf935\uf936\uf937\uf938\uf939\uf93a\uf93b\uf93c\uf93d\uf93e\uf93f\uf940\uf941\uf942\uf943\uf944\uf945\uf946\uf947\uf948\uf949\uf94a\uf94b\uf94c\uf94d\uf94e\uf94f\uf950\uf951\uf952\uf953\uf954\uf955\uf956\uf957\uf958\uf959\uf95a\uf95b\uf95c\uf95d\uf95e\uf95f\uf960\uf961\uf962\uf963\uf964\uf965\uf966\uf967\uf968\uf969\uf96a\uf96b\uf96c\uf96d\uf96e\uf96f\uf970\uf971\uf972\uf973\uf974\uf975\uf976\uf977\uf978\uf979\uf97a\uf97b\uf97c\uf97d\uf97e\uf97f\uf980\uf981\uf982\uf983\uf984\uf985\uf986\uf987\uf988\uf989\uf98a\uf98b\uf98c\uf98d\uf98e\uf98f\uf990\uf991\uf992\uf993\uf994\uf995\uf996\uf997\uf998\uf999\uf99a\uf99b\uf99c\uf99d\uf99e\uf99f\uf9a0\uf9a1\uf9a2\uf9a3\uf9a4\uf9a5\uf9a6\uf9a7\uf9a8\uf9a9\uf9aa\uf9ab\uf9ac\uf9ad\uf9ae\uf9af\uf9b0\uf9b1\uf9b2\uf9b3\uf9b4\uf9b5\uf9b6\uf9b7\uf9b8\uf9b9\uf9ba\uf9bb\uf9bc\uf9bd\uf9be\uf9bf\uf9c0\uf9c1\uf9c2\uf9c3\uf9c4\uf9c5\uf9c6\uf9c7\uf9c8\uf9c9\uf9ca\uf9cb\uf9cc\uf9cd\uf9ce\uf9cf\uf9d0\uf9d1\uf9d2\uf9d3\uf9d4\uf9d5\uf9d6\uf9d7\uf9d8\uf9d9\uf9da\uf9db\uf9dc\uf9dd\uf9de\uf9df\uf9e0\uf9e1\uf9e2\uf9e3\uf9e4\uf9e5\uf9e6\uf9e7\uf9e8\uf9e9\uf9ea\uf9eb\uf9ec\uf9ed\uf9ee\uf9ef\uf9f0\uf9f1\uf9f2\uf9f3\uf9f4\uf9f5\uf9f6\uf9f7\uf9f8\uf9f9\uf9fa\uf9fb\uf9fc\uf9fd\uf9fe\uf9ff\ufa00\ufa01\ufa02\ufa03\ufa04\ufa05\ufa06\ufa07\ufa08\ufa09\ufa0a\ufa0b\ufa0c\ufa0d\ufa0e\ufa0f\ufa10\ufa11\ufa12\ufa13\ufa14\ufa15\ufa16\ufa17\ufa18\ufa19\ufa1a\ufa1b\ufa1c\ufa1d\ufa1e\ufa1f\ufa20\ufa21\ufa22\ufa23\ufa24\ufa25\ufa26\ufa27\ufa28\ufa29\ufa2a\ufa2b\ufa2c\ufa2d\ufa30\ufa31\ufa32\ufa33\ufa34\ufa35\ufa36\ufa37\ufa38\ufa39\ufa3a\ufa3b\ufa3c\ufa3d\ufa3e\ufa3f\ufa40\ufa41\ufa42\ufa43\ufa44\ufa45\ufa46\ufa47\ufa48\ufa49\ufa4a\ufa4b\ufa4c\ufa4d\ufa4e\ufa4f\ufa50\ufa51\ufa52\ufa53\ufa54\ufa55\ufa56\ufa57\ufa58\ufa59\ufa5a\ufa5b\ufa5c\ufa5d\ufa5e\ufa5f\ufa60\ufa61\ufa62\ufa63\ufa64\ufa65\ufa66\ufa67\ufa68\ufa69\ufa6a\ufa70\ufa71\ufa72\ufa73\ufa74\ufa75\ufa76\ufa77\ufa78\ufa79\ufa7a\ufa7b\ufa7c\ufa7d\ufa7e\ufa7f\ufa80\ufa81\ufa82\ufa83\ufa84\ufa85\ufa86\ufa87\ufa88\ufa89\ufa8a\ufa8b\ufa8c\ufa8d\ufa8e\ufa8f\ufa90\ufa91\ufa92\ufa93\ufa94\ufa95\ufa96\ufa97\ufa98\ufa99\ufa9a\ufa9b\ufa9c\ufa9d\ufa9e\ufa9f\ufaa0\ufaa1\ufaa2\ufaa3\ufaa4\ufaa5\ufaa6\ufaa7\ufaa8\ufaa9\ufaaa\ufaab\ufaac\ufaad\ufaae\ufaaf\ufab0\ufab1\ufab2\ufab3\ufab4\ufab5\ufab6\ufab7\ufab8\ufab9\ufaba\ufabb\ufabc\ufabd\ufabe\ufabf\ufac0\ufac1\ufac2\ufac3\ufac4\ufac5\ufac6\ufac7\ufac8\ufac9\ufaca\ufacb\ufacc\ufacd\uface\ufacf\ufad0\ufad1\ufad2\ufad3\ufad4\ufad5\ufad6\ufad7\ufad8\ufad9\ufb1d\ufb1f\ufb20\ufb21\ufb22\ufb23\ufb24\ufb25\ufb26\ufb27\ufb28\ufb2a\ufb2b\ufb2c\ufb2d\ufb2e\ufb2f\ufb30\ufb31\ufb32\ufb33\ufb34\ufb35\ufb36\ufb38\ufb39\ufb3a\ufb3b\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46\ufb47\ufb48\ufb49\ufb4a\ufb4b\ufb4c\ufb4d\ufb4e\ufb4f\ufb50\ufb51\ufb52\ufb53\ufb54\ufb55\ufb56\ufb57\ufb58\ufb59\ufb5a\ufb5b\ufb5c\ufb5d\ufb5e\ufb5f\ufb60\ufb61\ufb62\ufb63\ufb64\ufb65\ufb66\ufb67\ufb68\ufb69\ufb6a\ufb6b\ufb6c\ufb6d\ufb6e\ufb6f\ufb70\ufb71\ufb72\ufb73\ufb74\ufb75\ufb76\ufb77\ufb78\ufb79\ufb7a\ufb7b\ufb7c\ufb7d\ufb7e\ufb7f\ufb80\ufb81\ufb82\ufb83\ufb84\ufb85\ufb86\ufb87\ufb88\ufb89\ufb8a\ufb8b\ufb8c\ufb8d\ufb8e\ufb8f\ufb90\ufb91\ufb92\ufb93\ufb94\ufb95\ufb96\ufb97\ufb98\ufb99\ufb9a\ufb9b\ufb9c\ufb9d\ufb9e\ufb9f\ufba0\ufba1\ufba2\ufba3\ufba4\ufba5\ufba6\ufba7\ufba8\ufba9\ufbaa\ufbab\ufbac\ufbad\ufbae\ufbaf\ufbb0\ufbb1\ufbd3\ufbd4\ufbd5\ufbd6\ufbd7\ufbd8\ufbd9\ufbda\ufbdb\ufbdc\ufbdd\ufbde\ufbdf\ufbe0\ufbe1\ufbe2\ufbe3\ufbe4\ufbe5\ufbe6\ufbe7\ufbe8\ufbe9\ufbea\ufbeb\ufbec\ufbed\ufbee\ufbef\ufbf0\ufbf1\ufbf2\ufbf3\ufbf4\ufbf5\ufbf6\ufbf7\ufbf8\ufbf9\ufbfa\ufbfb\ufbfc\ufbfd\ufbfe\ufbff\ufc00\ufc01\ufc02\ufc03\ufc04\ufc05\ufc06\ufc07\ufc08\ufc09\ufc0a\ufc0b\ufc0c\ufc0d\ufc0e\ufc0f\ufc10\ufc11\ufc12\ufc13\ufc14\ufc15\ufc16\ufc17\ufc18\ufc19\ufc1a\ufc1b\ufc1c\ufc1d\ufc1e\ufc1f\ufc20\ufc21\ufc22\ufc23\ufc24\ufc25\ufc26\ufc27\ufc28\ufc29\ufc2a\ufc2b\ufc2c\ufc2d\ufc2e\ufc2f\ufc30\ufc31\ufc32\ufc33\ufc34\ufc35\ufc36\ufc37\ufc38\ufc39\ufc3a\ufc3b\ufc3c\ufc3d\ufc3e\ufc3f\ufc40\ufc41\ufc42\ufc43\ufc44\ufc45\ufc46\ufc47\ufc48\ufc49\ufc4a\ufc4b\ufc4c\ufc4d\ufc4e\ufc4f\ufc50\ufc51\ufc52\ufc53\ufc54\ufc55\ufc56\ufc57\ufc58\ufc59\ufc5a\ufc5b\ufc5c\ufc5d\ufc5e\ufc5f\ufc60\ufc61\ufc62\ufc63\ufc64\ufc65\ufc66\ufc67\ufc68\ufc69\ufc6a\ufc6b\ufc6c\ufc6d\ufc6e\ufc6f\ufc70\ufc71\ufc72\ufc73\ufc74\ufc75\ufc76\ufc77\ufc78\ufc79\ufc7a\ufc7b\ufc7c\ufc7d\ufc7e\ufc7f\ufc80\ufc81\ufc82\ufc83\ufc84\ufc85\ufc86\ufc87\ufc88\ufc89\ufc8a\ufc8b\ufc8c\ufc8d\ufc8e\ufc8f\ufc90\ufc91\ufc92\ufc93\ufc94\ufc95\ufc96\ufc97\ufc98\ufc99\ufc9a\ufc9b\ufc9c\ufc9d\ufc9e\ufc9f\ufca0\ufca1\ufca2\ufca3\ufca4\ufca5\ufca6\ufca7\ufca8\ufca9\ufcaa\ufcab\ufcac\ufcad\ufcae\ufcaf\ufcb0\ufcb1\ufcb2\ufcb3\ufcb4\ufcb5\ufcb6\ufcb7\ufcb8\ufcb9\ufcba\ufcbb\ufcbc\ufcbd\ufcbe\ufcbf\ufcc0\ufcc1\ufcc2\ufcc3\ufcc4\ufcc5\ufcc6\ufcc7\ufcc8\ufcc9\ufcca\ufccb\ufccc\ufccd\ufcce\ufccf\ufcd0\ufcd1\ufcd2\ufcd3\ufcd4\ufcd5\ufcd6\ufcd7\ufcd8\ufcd9\ufcda\ufcdb\ufcdc\ufcdd\ufcde\ufcdf\ufce0\ufce1\ufce2\ufce3\ufce4\ufce5\ufce6\ufce7\ufce8\ufce9\ufcea\ufceb\ufcec\ufced\ufcee\ufcef\ufcf0\ufcf1\ufcf2\ufcf3\ufcf4\ufcf5\ufcf6\ufcf7\ufcf8\ufcf9\ufcfa\ufcfb\ufcfc\ufcfd\ufcfe\ufcff\ufd00\ufd01\ufd02\ufd03\ufd04\ufd05\ufd06\ufd07\ufd08\ufd09\ufd0a\ufd0b\ufd0c\ufd0d\ufd0e\ufd0f\ufd10\ufd11\ufd12\ufd13\ufd14\ufd15\ufd16\ufd17\ufd18\ufd19\ufd1a\ufd1b\ufd1c\ufd1d\ufd1e\ufd1f\ufd20\ufd21\ufd22\ufd23\ufd24\ufd25\ufd26\ufd27\ufd28\ufd29\ufd2a\ufd2b\ufd2c\ufd2d\ufd2e\ufd2f\ufd30\ufd31\ufd32\ufd33\ufd34\ufd35\ufd36\ufd37\ufd38\ufd39\ufd3a\ufd3b\ufd3c\ufd3d\ufd50\ufd51\ufd52\ufd53\ufd54\ufd55\ufd56\ufd57\ufd58\ufd59\ufd5a\ufd5b\ufd5c\ufd5d\ufd5e\ufd5f\ufd60\ufd61\ufd62\ufd63\ufd64\ufd65\ufd66\ufd67\ufd68\ufd69\ufd6a\ufd6b\ufd6c\ufd6d\ufd6e\ufd6f\ufd70\ufd71\ufd72\ufd73\ufd74\ufd75\ufd76\ufd77\ufd78\ufd79\ufd7a\ufd7b\ufd7c\ufd7d\ufd7e\ufd7f\ufd80\ufd81\ufd82\ufd83\ufd84\ufd85\ufd86\ufd87\ufd88\ufd89\ufd8a\ufd8b\ufd8c\ufd8d\ufd8e\ufd8f\ufd92\ufd93\ufd94\ufd95\ufd96\ufd97\ufd98\ufd99\ufd9a\ufd9b\ufd9c\ufd9d\ufd9e\ufd9f\ufda0\ufda1\ufda2\ufda3\ufda4\ufda5\ufda6\ufda7\ufda8\ufda9\ufdaa\ufdab\ufdac\ufdad\ufdae\ufdaf\ufdb0\ufdb1\ufdb2\ufdb3\ufdb4\ufdb5\ufdb6\ufdb7\ufdb8\ufdb9\ufdba\ufdbb\ufdbc\ufdbd\ufdbe\ufdbf\ufdc0\ufdc1\ufdc2\ufdc3\ufdc4\ufdc5\ufdc6\ufdc7\ufdf0\ufdf1\ufdf2\ufdf3\ufdf4\ufdf5\ufdf6\ufdf7\ufdf8\ufdf9\ufdfa\ufdfb\ufe70\ufe71\ufe72\ufe73\ufe74\ufe76\ufe77\ufe78\ufe79\ufe7a\ufe7b\ufe7c\ufe7d\ufe7e\ufe7f\ufe80\ufe81\ufe82\ufe83\ufe84\ufe85\ufe86\ufe87\ufe88\ufe89\ufe8a\ufe8b\ufe8c\ufe8d\ufe8e\ufe8f\ufe90\ufe91\ufe92\ufe93\ufe94\ufe95\ufe96\ufe97\ufe98\ufe99\ufe9a\ufe9b\ufe9c\ufe9d\ufe9e\ufe9f\ufea0\ufea1\ufea2\ufea3\ufea4\ufea5\ufea6\ufea7\ufea8\ufea9\ufeaa\ufeab\ufeac\ufead\ufeae\ufeaf\ufeb0\ufeb1\ufeb2\ufeb3\ufeb4\ufeb5\ufeb6\ufeb7\ufeb8\ufeb9\ufeba\ufebb\ufebc\ufebd\ufebe\ufebf\ufec0\ufec1\ufec2\ufec3\ufec4\ufec5\ufec6\ufec7\ufec8\ufec9\ufeca\ufecb\ufecc\ufecd\ufece\ufecf\ufed0\ufed1\ufed2\ufed3\ufed4\ufed5\ufed6\ufed7\ufed8\ufed9\ufeda\ufedb\ufedc\ufedd\ufede\ufedf\ufee0\ufee1\ufee2\ufee3\ufee4\ufee5\ufee6\ufee7\ufee8\ufee9\ufeea\ufeeb\ufeec\ufeed\ufeee\ufeef\ufef0\ufef1\ufef2\ufef3\ufef4\ufef5\ufef6\ufef7\ufef8\ufef9\ufefa\ufefb\ufefc\uff66\uff67\uff68\uff69\uff6a\uff6b\uff6c\uff6d\uff6e\uff6f\uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79\uff7a\uff7b\uff7c\uff7d\uff7e\uff7f\uff80\uff81\uff82\uff83\uff84\uff85\uff86\uff87\uff88\uff89\uff8a\uff8b\uff8c\uff8d\uff8e\uff8f\uff90\uff91\uff92\uff93\uff94\uff95\uff96\uff97\uff98\uff99\uff9a\uff9b\uff9c\uff9d\uffa0\uffa1\uffa2\uffa3\uffa4\uffa5\uffa6\uffa7\uffa8\uffa9\uffaa\uffab\uffac\uffad\uffae\uffaf\uffb0\uffb1\uffb2\uffb3\uffb4\uffb5\uffb6\uffb7\uffb8\uffb9\uffba\uffbb\uffbc\uffbd\uffbe\uffc2\uffc3\uffc4\uffc5\uffc6\uffc7\uffca\uffcb\uffcc\uffcd\uffce\uffcf\uffd2\uffd3\uffd4\uffd5\uffd6\uffd7\uffda\uffdb\uffdc'
+
+Lt = u'\u01c5\u01c8\u01cb\u01f2\u1f88\u1f89\u1f8a\u1f8b\u1f8c\u1f8d\u1f8e\u1f8f\u1f98\u1f99\u1f9a\u1f9b\u1f9c\u1f9d\u1f9e\u1f9f\u1fa8\u1fa9\u1faa\u1fab\u1fac\u1fad\u1fae\u1faf\u1fbc\u1fcc\u1ffc'
+
+Lu = u'ABCDEFGHIJKLMNOPQRSTUVWXYZ\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd8\xd9\xda\xdb\xdc\xdd\xde\u0100\u0102\u0104\u0106\u0108\u010a\u010c\u010e\u0110\u0112\u0114\u0116\u0118\u011a\u011c\u011e\u0120\u0122\u0124\u0126\u0128\u012a\u012c\u012e\u0130\u0132\u0134\u0136\u0139\u013b\u013d\u013f\u0141\u0143\u0145\u0147\u014a\u014c\u014e\u0150\u0152\u0154\u0156\u0158\u015a\u015c\u015e\u0160\u0162\u0164\u0166\u0168\u016a\u016c\u016e\u0170\u0172\u0174\u0176\u0178\u0179\u017b\u017d\u0181\u0182\u0184\u0186\u0187\u0189\u018a\u018b\u018e\u018f\u0190\u0191\u0193\u0194\u0196\u0197\u0198\u019c\u019d\u019f\u01a0\u01a2\u01a4\u01a6\u01a7\u01a9\u01ac\u01ae\u01af\u01b1\u01b2\u01b3\u01b5\u01b7\u01b8\u01bc\u01c4\u01c7\u01ca\u01cd\u01cf\u01d1\u01d3\u01d5\u01d7\u01d9\u01db\u01de\u01e0\u01e2\u01e4\u01e6\u01e8\u01ea\u01ec\u01ee\u01f1\u01f4\u01f6\u01f7\u01f8\u01fa\u01fc\u01fe\u0200\u0202\u0204\u0206\u0208\u020a\u020c\u020e\u0210\u0212\u0214\u0216\u0218\u021a\u021c\u021e\u0220\u0222\u0224\u0226\u0228\u022a\u022c\u022e\u0230\u0232\u023a\u023b\u023d\u023e\u0241\u0386\u0388\u0389\u038a\u038c\u038e\u038f\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399\u039a\u039b\u039c\u039d\u039e\u039f\u03a0\u03a1\u03a3\u03a4\u03a5\u03a6\u03a7\u03a8\u03a9\u03aa\u03ab\u03d2\u03d3\u03d4\u03d8\u03da\u03dc\u03de\u03e0\u03e2\u03e4\u03e6\u03e8\u03ea\u03ec\u03ee\u03f4\u03f7\u03f9\u03fa\u03fd\u03fe\u03ff\u0400\u0401\u0402\u0403\u0404\u0405\u0406\u0407\u0408\u0409\u040a\u040b\u040c\u040d\u040e\u040f\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0460\u0462\u0464\u0466\u0468\u046a\u046c\u046e\u0470\u0472\u0474\u0476\u0478\u047a\u047c\u047e\u0480\u048a\u048c\u048e\u0490\u0492\u0494\u0496\u0498\u049a\u049c\u049e\u04a0\u04a2\u04a4\u04a6\u04a8\u04aa\u04ac\u04ae\u04b0\u04b2\u04b4\u04b6\u04b8\u04ba\u04bc\u04be\u04c0\u04c1\u04c3\u04c5\u04c7\u04c9\u04cb\u04cd\u04d0\u04d2\u04d4\u04d6\u04d8\u04da\u04dc\u04de\u04e0\u04e2\u04e4\u04e6\u04e8\u04ea\u04ec\u04ee\u04f0\u04f2\u04f4\u04f6\u04f8\u0500\u0502\u0504\u0506\u0508\u050a\u050c\u050e\u0531\u0532\u0533\u0534\u0535\u0536\u0537\u0538\u0539\u053a\u053b\u053c\u053d\u053e\u053f\u0540\u0541\u0542\u0543\u0544\u0545\u0546\u0547\u0548\u0549\u054a\u054b\u054c\u054d\u054e\u054f\u0550\u0551\u0552\u0553\u0554\u0555\u0556\u10a0\u10a1\u10a2\u10a3\u10a4\u10a5\u10a6\u10a7\u10a8\u10a9\u10aa\u10ab\u10ac\u10ad\u10ae\u10af\u10b0\u10b1\u10b2\u10b3\u10b4\u10b5\u10b6\u10b7\u10b8\u10b9\u10ba\u10bb\u10bc\u10bd\u10be\u10bf\u10c0\u10c1\u10c2\u10c3\u10c4\u10c5\u1e00\u1e02\u1e04\u1e06\u1e08\u1e0a\u1e0c\u1e0e\u1e10\u1e12\u1e14\u1e16\u1e18\u1e1a\u1e1c\u1e1e\u1e20\u1e22\u1e24\u1e26\u1e28\u1e2a\u1e2c\u1e2e\u1e30\u1e32\u1e34\u1e36\u1e38\u1e3a\u1e3c\u1e3e\u1e40\u1e42\u1e44\u1e46\u1e48\u1e4a\u1e4c\u1e4e\u1e50\u1e52\u1e54\u1e56\u1e58\u1e5a\u1e5c\u1e5e\u1e60\u1e62\u1e64\u1e66\u1e68\u1e6a\u1e6c\u1e6e\u1e70\u1e72\u1e74\u1e76\u1e78\u1e7a\u1e7c\u1e7e\u1e80\u1e82\u1e84\u1e86\u1e88\u1e8a\u1e8c\u1e8e\u1e90\u1e92\u1e94\u1ea0\u1ea2\u1ea4\u1ea6\u1ea8\u1eaa\u1eac\u1eae\u1eb0\u1eb2\u1eb4\u1eb6\u1eb8\u1eba\u1ebc\u1ebe\u1ec0\u1ec2\u1ec4\u1ec6\u1ec8\u1eca\u1ecc\u1ece\u1ed0\u1ed2\u1ed4\u1ed6\u1ed8\u1eda\u1edc\u1ede\u1ee0\u1ee2\u1ee4\u1ee6\u1ee8\u1eea\u1eec\u1eee\u1ef0\u1ef2\u1ef4\u1ef6\u1ef8\u1f08\u1f09\u1f0a\u1f0b\u1f0c\u1f0d\u1f0e\u1f0f\u1f18\u1f19\u1f1a\u1f1b\u1f1c\u1f1d\u1f28\u1f29\u1f2a\u1f2b\u1f2c\u1f2d\u1f2e\u1f2f\u1f38\u1f39\u1f3a\u1f3b\u1f3c\u1f3d\u1f3e\u1f3f\u1f48\u1f49\u1f4a\u1f4b\u1f4c\u1f4d\u1f59\u1f5b\u1f5d\u1f5f\u1f68\u1f69\u1f6a\u1f6b\u1f6c\u1f6d\u1f6e\u1f6f\u1fb8\u1fb9\u1fba\u1fbb\u1fc8\u1fc9\u1fca\u1fcb\u1fd8\u1fd9\u1fda\u1fdb\u1fe8\u1fe9\u1fea\u1feb\u1fec\u1ff8\u1ff9\u1ffa\u1ffb\u2102\u2107\u210b\u210c\u210d\u2110\u2111\u2112\u2115\u2119\u211a\u211b\u211c\u211d\u2124\u2126\u2128\u212a\u212b\u212c\u212d\u2130\u2131\u2133\u213e\u213f\u2145\u2c00\u2c01\u2c02\u2c03\u2c04\u2c05\u2c06\u2c07\u2c08\u2c09\u2c0a\u2c0b\u2c0c\u2c0d\u2c0e\u2c0f\u2c10\u2c11\u2c12\u2c13\u2c14\u2c15\u2c16\u2c17\u2c18\u2c19\u2c1a\u2c1b\u2c1c\u2c1d\u2c1e\u2c1f\u2c20\u2c21\u2c22\u2c23\u2c24\u2c25\u2c26\u2c27\u2c28\u2c29\u2c2a\u2c2b\u2c2c\u2c2d\u2c2e\u2c80\u2c82\u2c84\u2c86\u2c88\u2c8a\u2c8c\u2c8e\u2c90\u2c92\u2c94\u2c96\u2c98\u2c9a\u2c9c\u2c9e\u2ca0\u2ca2\u2ca4\u2ca6\u2ca8\u2caa\u2cac\u2cae\u2cb0\u2cb2\u2cb4\u2cb6\u2cb8\u2cba\u2cbc\u2cbe\u2cc0\u2cc2\u2cc4\u2cc6\u2cc8\u2cca\u2ccc\u2cce\u2cd0\u2cd2\u2cd4\u2cd6\u2cd8\u2cda\u2cdc\u2cde\u2ce0\u2ce2\uff21\uff22\uff23\uff24\uff25\uff26\uff27\uff28\uff29\uff2a\uff2b\uff2c\uff2d\uff2e\uff2f\uff30\uff31\uff32\uff33\uff34\uff35\uff36\uff37\uff38\uff39\uff3a'
+
+Mc = u'\u0903\u093e\u093f\u0940\u0949\u094a\u094b\u094c\u0982\u0983\u09be\u09bf\u09c0\u09c7\u09c8\u09cb\u09cc\u09d7\u0a03\u0a3e\u0a3f\u0a40\u0a83\u0abe\u0abf\u0ac0\u0ac9\u0acb\u0acc\u0b02\u0b03\u0b3e\u0b40\u0b47\u0b48\u0b4b\u0b4c\u0b57\u0bbe\u0bbf\u0bc1\u0bc2\u0bc6\u0bc7\u0bc8\u0bca\u0bcb\u0bcc\u0bd7\u0c01\u0c02\u0c03\u0c41\u0c42\u0c43\u0c44\u0c82\u0c83\u0cbe\u0cc0\u0cc1\u0cc2\u0cc3\u0cc4\u0cc7\u0cc8\u0cca\u0ccb\u0cd5\u0cd6\u0d02\u0d03\u0d3e\u0d3f\u0d40\u0d46\u0d47\u0d48\u0d4a\u0d4b\u0d4c\u0d57\u0d82\u0d83\u0dcf\u0dd0\u0dd1\u0dd8\u0dd9\u0dda\u0ddb\u0ddc\u0ddd\u0dde\u0ddf\u0df2\u0df3\u0f3e\u0f3f\u0f7f\u102c\u1031\u1038\u1056\u1057\u17b6\u17be\u17bf\u17c0\u17c1\u17c2\u17c3\u17c4\u17c5\u17c7\u17c8\u1923\u1924\u1925\u1926\u1929\u192a\u192b\u1930\u1931\u1933\u1934\u1935\u1936\u1937\u1938\u19b0\u19b1\u19b2\u19b3\u19b4\u19b5\u19b6\u19b7\u19b8\u19b9\u19ba\u19bb\u19bc\u19bd\u19be\u19bf\u19c0\u19c8\u19c9\u1a19\u1a1a\u1a1b\ua802\ua823\ua824\ua827'
+
+Me = u'\u0488\u0489\u06de\u20dd\u20de\u20df\u20e0\u20e2\u20e3\u20e4'
+
+Mn = u'\u0300\u0301\u0302\u0303\u0304\u0305\u0306\u0307\u0308\u0309\u030a\u030b\u030c\u030d\u030e\u030f\u0310\u0311\u0312\u0313\u0314\u0315\u0316\u0317\u0318\u0319\u031a\u031b\u031c\u031d\u031e\u031f\u0320\u0321\u0322\u0323\u0324\u0325\u0326\u0327\u0328\u0329\u032a\u032b\u032c\u032d\u032e\u032f\u0330\u0331\u0332\u0333\u0334\u0335\u0336\u0337\u0338\u0339\u033a\u033b\u033c\u033d\u033e\u033f\u0340\u0341\u0342\u0343\u0344\u0345\u0346\u0347\u0348\u0349\u034a\u034b\u034c\u034d\u034e\u034f\u0350\u0351\u0352\u0353\u0354\u0355\u0356\u0357\u0358\u0359\u035a\u035b\u035c\u035d\u035e\u035f\u0360\u0361\u0362\u0363\u0364\u0365\u0366\u0367\u0368\u0369\u036a\u036b\u036c\u036d\u036e\u036f\u0483\u0484\u0485\u0486\u0591\u0592\u0593\u0594\u0595\u0596\u0597\u0598\u0599\u059a\u059b\u059c\u059d\u059e\u059f\u05a0\u05a1\u05a2\u05a3\u05a4\u05a5\u05a6\u05a7\u05a8\u05a9\u05aa\u05ab\u05ac\u05ad\u05ae\u05af\u05b0\u05b1\u05b2\u05b3\u05b4\u05b5\u05b6\u05b7\u05b8\u05b9\u05bb\u05bc\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610\u0611\u0612\u0613\u0614\u0615\u064b\u064c\u064d\u064e\u064f\u0650\u0651\u0652\u0653\u0654\u0655\u0656\u0657\u0658\u0659\u065a\u065b\u065c\u065d\u065e\u0670\u06d6\u06d7\u06d8\u06d9\u06da\u06db\u06dc\u06df\u06e0\u06e1\u06e2\u06e3\u06e4\u06e7\u06e8\u06ea\u06eb\u06ec\u06ed\u0711\u0730\u0731\u0732\u0733\u0734\u0735\u0736\u0737\u0738\u0739\u073a\u073b\u073c\u073d\u073e\u073f\u0740\u0741\u0742\u0743\u0744\u0745\u0746\u0747\u0748\u0749\u074a\u07a6\u07a7\u07a8\u07a9\u07aa\u07ab\u07ac\u07ad\u07ae\u07af\u07b0\u0901\u0902\u093c\u0941\u0942\u0943\u0944\u0945\u0946\u0947\u0948\u094d\u0951\u0952\u0953\u0954\u0962\u0963\u0981\u09bc\u09c1\u09c2\u09c3\u09c4\u09cd\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b\u0a4c\u0a4d\u0a70\u0a71\u0a81\u0a82\u0abc\u0ac1\u0ac2\u0ac3\u0ac4\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3f\u0b41\u0b42\u0b43\u0b4d\u0b56\u0b82\u0bc0\u0bcd\u0c3e\u0c3f\u0c40\u0c46\u0c47\u0c48\u0c4a\u0c4b\u0c4c\u0c4d\u0c55\u0c56\u0cbc\u0cbf\u0cc6\u0ccc\u0ccd\u0d41\u0d42\u0d43\u0d4d\u0dca\u0dd2\u0dd3\u0dd4\u0dd6\u0e31\u0e34\u0e35\u0e36\u0e37\u0e38\u0e39\u0e3a\u0e47\u0e48\u0e49\u0e4a\u0e4b\u0e4c\u0e4d\u0e4e\u0eb1\u0eb4\u0eb5\u0eb6\u0eb7\u0eb8\u0eb9\u0ebb\u0ebc\u0ec8\u0ec9\u0eca\u0ecb\u0ecc\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71\u0f72\u0f73\u0f74\u0f75\u0f76\u0f77\u0f78\u0f79\u0f7a\u0f7b\u0f7c\u0f7d\u0f7e\u0f80\u0f81\u0f82\u0f83\u0f84\u0f86\u0f87\u0f90\u0f91\u0f92\u0f93\u0f94\u0f95\u0f96\u0f97\u0f99\u0f9a\u0f9b\u0f9c\u0f9d\u0f9e\u0f9f\u0fa0\u0fa1\u0fa2\u0fa3\u0fa4\u0fa5\u0fa6\u0fa7\u0fa8\u0fa9\u0faa\u0fab\u0fac\u0fad\u0fae\u0faf\u0fb0\u0fb1\u0fb2\u0fb3\u0fb4\u0fb5\u0fb6\u0fb7\u0fb8\u0fb9\u0fba\u0fbb\u0fbc\u0fc6\u102d\u102e\u102f\u1030\u1032\u1036\u1037\u1039\u1058\u1059\u135f\u1712\u1713\u1714\u1732\u1733\u1734\u1752\u1753\u1772\u1773\u17b7\u17b8\u17b9\u17ba\u17bb\u17bc\u17bd\u17c6\u17c9\u17ca\u17cb\u17cc\u17cd\u17ce\u17cf\u17d0\u17d1\u17d2\u17d3\u17dd\u180b\u180c\u180d\u18a9\u1920\u1921\u1922\u1927\u1928\u1932\u1939\u193a\u193b\u1a17\u1a18\u1dc0\u1dc1\u1dc2\u1dc3\u20d0\u20d1\u20d2\u20d3\u20d4\u20d5\u20d6\u20d7\u20d8\u20d9\u20da\u20db\u20dc\u20e1\u20e5\u20e6\u20e7\u20e8\u20e9\u20ea\u20eb\u302a\u302b\u302c\u302d\u302e\u302f\u3099\u309a\ua806\ua80b\ua825\ua826\ufb1e\ufe00\ufe01\ufe02\ufe03\ufe04\ufe05\ufe06\ufe07\ufe08\ufe09\ufe0a\ufe0b\ufe0c\ufe0d\ufe0e\ufe0f\ufe20\ufe21\ufe22\ufe23'
+
+Nd = u'0123456789\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669\u06f0\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9\u0966\u0967\u0968\u0969\u096a\u096b\u096c\u096d\u096e\u096f\u09e6\u09e7\u09e8\u09e9\u09ea\u09eb\u09ec\u09ed\u09ee\u09ef\u0a66\u0a67\u0a68\u0a69\u0a6a\u0a6b\u0a6c\u0a6d\u0a6e\u0a6f\u0ae6\u0ae7\u0ae8\u0ae9\u0aea\u0aeb\u0aec\u0aed\u0aee\u0aef\u0b66\u0b67\u0b68\u0b69\u0b6a\u0b6b\u0b6c\u0b6d\u0b6e\u0b6f\u0be6\u0be7\u0be8\u0be9\u0bea\u0beb\u0bec\u0bed\u0bee\u0bef\u0c66\u0c67\u0c68\u0c69\u0c6a\u0c6b\u0c6c\u0c6d\u0c6e\u0c6f\u0ce6\u0ce7\u0ce8\u0ce9\u0cea\u0ceb\u0cec\u0ced\u0cee\u0cef\u0d66\u0d67\u0d68\u0d69\u0d6a\u0d6b\u0d6c\u0d6d\u0d6e\u0d6f\u0e50\u0e51\u0e52\u0e53\u0e54\u0e55\u0e56\u0e57\u0e58\u0e59\u0ed0\u0ed1\u0ed2\u0ed3\u0ed4\u0ed5\u0ed6\u0ed7\u0ed8\u0ed9\u0f20\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\u0f29\u1040\u1041\u1042\u1043\u1044\u1045\u1046\u1047\u1048\u1049\u17e0\u17e1\u17e2\u17e3\u17e4\u17e5\u17e6\u17e7\u17e8\u17e9\u1810\u1811\u1812\u1813\u1814\u1815\u1816\u1817\u1818\u1819\u1946\u1947\u1948\u1949\u194a\u194b\u194c\u194d\u194e\u194f\u19d0\u19d1\u19d2\u19d3\u19d4\u19d5\u19d6\u19d7\u19d8\u19d9\uff10\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19'
+
+Nl = u'\u16ee\u16ef\u16f0\u2160\u2161\u2162\u2163\u2164\u2165\u2166\u2167\u2168\u2169\u216a\u216b\u216c\u216d\u216e\u216f\u2170\u2171\u2172\u2173\u2174\u2175\u2176\u2177\u2178\u2179\u217a\u217b\u217c\u217d\u217e\u217f\u2180\u2181\u2182\u2183\u3007\u3021\u3022\u3023\u3024\u3025\u3026\u3027\u3028\u3029\u3038\u3039\u303a'
+
+No = u'\xb2\xb3\xb9\xbc\xbd\xbe\u09f4\u09f5\u09f6\u09f7\u09f8\u09f9\u0bf0\u0bf1\u0bf2\u0f2a\u0f2b\u0f2c\u0f2d\u0f2e\u0f2f\u0f30\u0f31\u0f32\u0f33\u1369\u136a\u136b\u136c\u136d\u136e\u136f\u1370\u1371\u1372\u1373\u1374\u1375\u1376\u1377\u1378\u1379\u137a\u137b\u137c\u17f0\u17f1\u17f2\u17f3\u17f4\u17f5\u17f6\u17f7\u17f8\u17f9\u2070\u2074\u2075\u2076\u2077\u2078\u2079\u2080\u2081\u2082\u2083\u2084\u2085\u2086\u2087\u2088\u2089\u2153\u2154\u2155\u2156\u2157\u2158\u2159\u215a\u215b\u215c\u215d\u215e\u215f\u2460\u2461\u2462\u2463\u2464\u2465\u2466\u2467\u2468\u2469\u246a\u246b\u246c\u246d\u246e\u246f\u2470\u2471\u2472\u2473\u2474\u2475\u2476\u2477\u2478\u2479\u247a\u247b\u247c\u247d\u247e\u247f\u2480\u2481\u2482\u2483\u2484\u2485\u2486\u2487\u2488\u2489\u248a\u248b\u248c\u248d\u248e\u248f\u2490\u2491\u2492\u2493\u2494\u2495\u2496\u2497\u2498\u2499\u249a\u249b\u24ea\u24eb\u24ec\u24ed\u24ee\u24ef\u24f0\u24f1\u24f2\u24f3\u24f4\u24f5\u24f6\u24f7\u24f8\u24f9\u24fa\u24fb\u24fc\u24fd\u24fe\u24ff\u2776\u2777\u2778\u2779\u277a\u277b\u277c\u277d\u277e\u277f\u2780\u2781\u2782\u2783\u2784\u2785\u2786\u2787\u2788\u2789\u278a\u278b\u278c\u278d\u278e\u278f\u2790\u2791\u2792\u2793\u2cfd\u3192\u3193\u3194\u3195\u3220\u3221\u3222\u3223\u3224\u3225\u3226\u3227\u3228\u3229\u3251\u3252\u3253\u3254\u3255\u3256\u3257\u3258\u3259\u325a\u325b\u325c\u325d\u325e\u325f\u3280\u3281\u3282\u3283\u3284\u3285\u3286\u3287\u3288\u3289\u32b1\u32b2\u32b3\u32b4\u32b5\u32b6\u32b7\u32b8\u32b9\u32ba\u32bb\u32bc\u32bd\u32be\u32bf'
+
+Pc = u'_\u203f\u2040\u2054\ufe33\ufe34\ufe4d\ufe4e\ufe4f\uff3f'
+
+Pd = u'-\u058a\u1806\u2010\u2011\u2012\u2013\u2014\u2015\u2e17\u301c\u3030\u30a0\ufe31\ufe32\ufe58\ufe63\uff0d'
+
+Pe = u')]}\u0f3b\u0f3d\u169c\u2046\u207e\u208e\u232a\u23b5\u2769\u276b\u276d\u276f\u2771\u2773\u2775\u27c6\u27e7\u27e9\u27eb\u2984\u2986\u2988\u298a\u298c\u298e\u2990\u2992\u2994\u2996\u2998\u29d9\u29db\u29fd\u3009\u300b\u300d\u300f\u3011\u3015\u3017\u3019\u301b\u301e\u301f\ufd3f\ufe18\ufe36\ufe38\ufe3a\ufe3c\ufe3e\ufe40\ufe42\ufe44\ufe48\ufe5a\ufe5c\ufe5e\uff09\uff3d\uff5d\uff60\uff63'
+
+Pf = u'\xbb\u2019\u201d\u203a\u2e03\u2e05\u2e0a\u2e0d\u2e1d'
+
+Pi = u'\xab\u2018\u201b\u201c\u201f\u2039\u2e02\u2e04\u2e09\u2e0c\u2e1c'
+
+Po = u'!"#%&\'*,./:;?@\\\xa1\xb7\xbf\u037e\u0387\u055a\u055b\u055c\u055d\u055e\u055f\u0589\u05be\u05c0\u05c3\u05c6\u05f3\u05f4\u060c\u060d\u061b\u061e\u061f\u066a\u066b\u066c\u066d\u06d4\u0700\u0701\u0702\u0703\u0704\u0705\u0706\u0707\u0708\u0709\u070a\u070b\u070c\u070d\u0964\u0965\u0970\u0df4\u0e4f\u0e5a\u0e5b\u0f04\u0f05\u0f06\u0f07\u0f08\u0f09\u0f0a\u0f0b\u0f0c\u0f0d\u0f0e\u0f0f\u0f10\u0f11\u0f12\u0f85\u0fd0\u0fd1\u104a\u104b\u104c\u104d\u104e\u104f\u10fb\u1361\u1362\u1363\u1364\u1365\u1366\u1367\u1368\u166d\u166e\u16eb\u16ec\u16ed\u1735\u1736\u17d4\u17d5\u17d6\u17d8\u17d9\u17da\u1800\u1801\u1802\u1803\u1804\u1805\u1807\u1808\u1809\u180a\u1944\u1945\u19de\u19df\u1a1e\u1a1f\u2016\u2017\u2020\u2021\u2022\u2023\u2024\u2025\u2026\u2027\u2030\u2031\u2032\u2033\u2034\u2035\u2036\u2037\u2038\u203b\u203c\u203d\u203e\u2041\u2042\u2043\u2047\u2048\u2049\u204a\u204b\u204c\u204d\u204e\u204f\u2050\u2051\u2053\u2055\u2056\u2057\u2058\u2059\u205a\u205b\u205c\u205d\u205e\u23b6\u2cf9\u2cfa\u2cfb\u2cfc\u2cfe\u2cff\u2e00\u2e01\u2e06\u2e07\u2e08\u2e0b\u2e0e\u2e0f\u2e10\u2e11\u2e12\u2e13\u2e14\u2e15\u2e16\u3001\u3002\u3003\u303d\u30fb\ufe10\ufe11\ufe12\ufe13\ufe14\ufe15\ufe16\ufe19\ufe30\ufe45\ufe46\ufe49\ufe4a\ufe4b\ufe4c\ufe50\ufe51\ufe52\ufe54\ufe55\ufe56\ufe57\ufe5f\ufe60\ufe61\ufe68\ufe6a\ufe6b\uff01\uff02\uff03\uff05\uff06\uff07\uff0a\uff0c\uff0e\uff0f\uff1a\uff1b\uff1f\uff20\uff3c\uff61\uff64\uff65'
+
+Ps = u'([{\u0f3a\u0f3c\u169b\u201a\u201e\u2045\u207d\u208d\u2329\u23b4\u2768\u276a\u276c\u276e\u2770\u2772\u2774\u27c5\u27e6\u27e8\u27ea\u2983\u2985\u2987\u2989\u298b\u298d\u298f\u2991\u2993\u2995\u2997\u29d8\u29da\u29fc\u3008\u300a\u300c\u300e\u3010\u3014\u3016\u3018\u301a\u301d\ufd3e\ufe17\ufe35\ufe37\ufe39\ufe3b\ufe3d\ufe3f\ufe41\ufe43\ufe47\ufe59\ufe5b\ufe5d\uff08\uff3b\uff5b\uff5f\uff62'
+
+Sc = u'$\xa2\xa3\xa4\xa5\u060b\u09f2\u09f3\u0af1\u0bf9\u0e3f\u17db\u20a0\u20a1\u20a2\u20a3\u20a4\u20a5\u20a6\u20a7\u20a8\u20a9\u20aa\u20ab\u20ac\u20ad\u20ae\u20af\u20b0\u20b1\u20b2\u20b3\u20b4\u20b5\ufdfc\ufe69\uff04\uffe0\uffe1\uffe5\uffe6'
+
+Sk = u'^`\xa8\xaf\xb4\xb8\u02c2\u02c3\u02c4\u02c5\u02d2\u02d3\u02d4\u02d5\u02d6\u02d7\u02d8\u02d9\u02da\u02db\u02dc\u02dd\u02de\u02df\u02e5\u02e6\u02e7\u02e8\u02e9\u02ea\u02eb\u02ec\u02ed\u02ef\u02f0\u02f1\u02f2\u02f3\u02f4\u02f5\u02f6\u02f7\u02f8\u02f9\u02fa\u02fb\u02fc\u02fd\u02fe\u02ff\u0374\u0375\u0384\u0385\u1fbd\u1fbf\u1fc0\u1fc1\u1fcd\u1fce\u1fcf\u1fdd\u1fde\u1fdf\u1fed\u1fee\u1fef\u1ffd\u1ffe\u309b\u309c\ua700\ua701\ua702\ua703\ua704\ua705\ua706\ua707\ua708\ua709\ua70a\ua70b\ua70c\ua70d\ua70e\ua70f\ua710\ua711\ua712\ua713\ua714\ua715\ua716\uff3e\uff40\uffe3'
+
+Sm = u'+<=>|~\xac\xb1\xd7\xf7\u03f6\u2044\u2052\u207a\u207b\u207c\u208a\u208b\u208c\u2140\u2141\u2142\u2143\u2144\u214b\u2190\u2191\u2192\u2193\u2194\u219a\u219b\u21a0\u21a3\u21a6\u21ae\u21ce\u21cf\u21d2\u21d4\u21f4\u21f5\u21f6\u21f7\u21f8\u21f9\u21fa\u21fb\u21fc\u21fd\u21fe\u21ff\u2200\u2201\u2202\u2203\u2204\u2205\u2206\u2207\u2208\u2209\u220a\u220b\u220c\u220d\u220e\u220f\u2210\u2211\u2212\u2213\u2214\u2215\u2216\u2217\u2218\u2219\u221a\u221b\u221c\u221d\u221e\u221f\u2220\u2221\u2222\u2223\u2224\u2225\u2226\u2227\u2228\u2229\u222a\u222b\u222c\u222d\u222e\u222f\u2230\u2231\u2232\u2233\u2234\u2235\u2236\u2237\u2238\u2239\u223a\u223b\u223c\u223d\u223e\u223f\u2240\u2241\u2242\u2243\u2244\u2245\u2246\u2247\u2248\u2249\u224a\u224b\u224c\u224d\u224e\u224f\u2250\u2251\u2252\u2253\u2254\u2255\u2256\u2257\u2258\u2259\u225a\u225b\u225c\u225d\u225e\u225f\u2260\u2261\u2262\u2263\u2264\u2265\u2266\u2267\u2268\u2269\u226a\u226b\u226c\u226d\u226e\u226f\u2270\u2271\u2272\u2273\u2274\u2275\u2276\u2277\u2278\u2279\u227a\u227b\u227c\u227d\u227e\u227f\u2280\u2281\u2282\u2283\u2284\u2285\u2286\u2287\u2288\u2289\u228a\u228b\u228c\u228d\u228e\u228f\u2290\u2291\u2292\u2293\u2294\u2295\u2296\u2297\u2298\u2299\u229a\u229b\u229c\u229d\u229e\u229f\u22a0\u22a1\u22a2\u22a3\u22a4\u22a5\u22a6\u22a7\u22a8\u22a9\u22aa\u22ab\u22ac\u22ad\u22ae\u22af\u22b0\u22b1\u22b2\u22b3\u22b4\u22b5\u22b6\u22b7\u22b8\u22b9\u22ba\u22bb\u22bc\u22bd\u22be\u22bf\u22c0\u22c1\u22c2\u22c3\u22c4\u22c5\u22c6\u22c7\u22c8\u22c9\u22ca\u22cb\u22cc\u22cd\u22ce\u22cf\u22d0\u22d1\u22d2\u22d3\u22d4\u22d5\u22d6\u22d7\u22d8\u22d9\u22da\u22db\u22dc\u22dd\u22de\u22df\u22e0\u22e1\u22e2\u22e3\u22e4\u22e5\u22e6\u22e7\u22e8\u22e9\u22ea\u22eb\u22ec\u22ed\u22ee\u22ef\u22f0\u22f1\u22f2\u22f3\u22f4\u22f5\u22f6\u22f7\u22f8\u22f9\u22fa\u22fb\u22fc\u22fd\u22fe\u22ff\u2308\u2309\u230a\u230b\u2320\u2321\u237c\u239b\u239c\u239d\u239e\u239f\u23a0\u23a1\u23a2\u23a3\u23a4\u23a5\u23a6\u23a7\u23a8\u23a9\u23aa\u23ab\u23ac\u23ad\u23ae\u23af\u23b0\u23b1\u23b2\u23b3\u25b7\u25c1\u25f8\u25f9\u25fa\u25fb\u25fc\u25fd\u25fe\u25ff\u266f\u27c0\u27c1\u27c2\u27c3\u27c4\u27d0\u27d1\u27d2\u27d3\u27d4\u27d5\u27d6\u27d7\u27d8\u27d9\u27da\u27db\u27dc\u27dd\u27de\u27df\u27e0\u27e1\u27e2\u27e3\u27e4\u27e5\u27f0\u27f1\u27f2\u27f3\u27f4\u27f5\u27f6\u27f7\u27f8\u27f9\u27fa\u27fb\u27fc\u27fd\u27fe\u27ff\u2900\u2901\u2902\u2903\u2904\u2905\u2906\u2907\u2908\u2909\u290a\u290b\u290c\u290d\u290e\u290f\u2910\u2911\u2912\u2913\u2914\u2915\u2916\u2917\u2918\u2919\u291a\u291b\u291c\u291d\u291e\u291f\u2920\u2921\u2922\u2923\u2924\u2925\u2926\u2927\u2928\u2929\u292a\u292b\u292c\u292d\u292e\u292f\u2930\u2931\u2932\u2933\u2934\u2935\u2936\u2937\u2938\u2939\u293a\u293b\u293c\u293d\u293e\u293f\u2940\u2941\u2942\u2943\u2944\u2945\u2946\u2947\u2948\u2949\u294a\u294b\u294c\u294d\u294e\u294f\u2950\u2951\u2952\u2953\u2954\u2955\u2956\u2957\u2958\u2959\u295a\u295b\u295c\u295d\u295e\u295f\u2960\u2961\u2962\u2963\u2964\u2965\u2966\u2967\u2968\u2969\u296a\u296b\u296c\u296d\u296e\u296f\u2970\u2971\u2972\u2973\u2974\u2975\u2976\u2977\u2978\u2979\u297a\u297b\u297c\u297d\u297e\u297f\u2980\u2981\u2982\u2999\u299a\u299b\u299c\u299d\u299e\u299f\u29a0\u29a1\u29a2\u29a3\u29a4\u29a5\u29a6\u29a7\u29a8\u29a9\u29aa\u29ab\u29ac\u29ad\u29ae\u29af\u29b0\u29b1\u29b2\u29b3\u29b4\u29b5\u29b6\u29b7\u29b8\u29b9\u29ba\u29bb\u29bc\u29bd\u29be\u29bf\u29c0\u29c1\u29c2\u29c3\u29c4\u29c5\u29c6\u29c7\u29c8\u29c9\u29ca\u29cb\u29cc\u29cd\u29ce\u29cf\u29d0\u29d1\u29d2\u29d3\u29d4\u29d5\u29d6\u29d7\u29dc\u29dd\u29de\u29df\u29e0\u29e1\u29e2\u29e3\u29e4\u29e5\u29e6\u29e7\u29e8\u29e9\u29ea\u29eb\u29ec\u29ed\u29ee\u29ef\u29f0\u29f1\u29f2\u29f3\u29f4\u29f5\u29f6\u29f7\u29f8\u29f9\u29fa\u29fb\u29fe\u29ff\u2a00\u2a01\u2a02\u2a03\u2a04\u2a05\u2a06\u2a07\u2a08\u2a09\u2a0a\u2a0b\u2a0c\u2a0d\u2a0e\u2a0f\u2a10\u2a11\u2a12\u2a13\u2a14\u2a15\u2a16\u2a17\u2a18\u2a19\u2a1a\u2a1b\u2a1c\u2a1d\u2a1e\u2a1f\u2a20\u2a21\u2a22\u2a23\u2a24\u2a25\u2a26\u2a27\u2a28\u2a29\u2a2a\u2a2b\u2a2c\u2a2d\u2a2e\u2a2f\u2a30\u2a31\u2a32\u2a33\u2a34\u2a35\u2a36\u2a37\u2a38\u2a39\u2a3a\u2a3b\u2a3c\u2a3d\u2a3e\u2a3f\u2a40\u2a41\u2a42\u2a43\u2a44\u2a45\u2a46\u2a47\u2a48\u2a49\u2a4a\u2a4b\u2a4c\u2a4d\u2a4e\u2a4f\u2a50\u2a51\u2a52\u2a53\u2a54\u2a55\u2a56\u2a57\u2a58\u2a59\u2a5a\u2a5b\u2a5c\u2a5d\u2a5e\u2a5f\u2a60\u2a61\u2a62\u2a63\u2a64\u2a65\u2a66\u2a67\u2a68\u2a69\u2a6a\u2a6b\u2a6c\u2a6d\u2a6e\u2a6f\u2a70\u2a71\u2a72\u2a73\u2a74\u2a75\u2a76\u2a77\u2a78\u2a79\u2a7a\u2a7b\u2a7c\u2a7d\u2a7e\u2a7f\u2a80\u2a81\u2a82\u2a83\u2a84\u2a85\u2a86\u2a87\u2a88\u2a89\u2a8a\u2a8b\u2a8c\u2a8d\u2a8e\u2a8f\u2a90\u2a91\u2a92\u2a93\u2a94\u2a95\u2a96\u2a97\u2a98\u2a99\u2a9a\u2a9b\u2a9c\u2a9d\u2a9e\u2a9f\u2aa0\u2aa1\u2aa2\u2aa3\u2aa4\u2aa5\u2aa6\u2aa7\u2aa8\u2aa9\u2aaa\u2aab\u2aac\u2aad\u2aae\u2aaf\u2ab0\u2ab1\u2ab2\u2ab3\u2ab4\u2ab5\u2ab6\u2ab7\u2ab8\u2ab9\u2aba\u2abb\u2abc\u2abd\u2abe\u2abf\u2ac0\u2ac1\u2ac2\u2ac3\u2ac4\u2ac5\u2ac6\u2ac7\u2ac8\u2ac9\u2aca\u2acb\u2acc\u2acd\u2ace\u2acf\u2ad0\u2ad1\u2ad2\u2ad3\u2ad4\u2ad5\u2ad6\u2ad7\u2ad8\u2ad9\u2ada\u2adb\u2adc\u2add\u2ade\u2adf\u2ae0\u2ae1\u2ae2\u2ae3\u2ae4\u2ae5\u2ae6\u2ae7\u2ae8\u2ae9\u2aea\u2aeb\u2aec\u2aed\u2aee\u2aef\u2af0\u2af1\u2af2\u2af3\u2af4\u2af5\u2af6\u2af7\u2af8\u2af9\u2afa\u2afb\u2afc\u2afd\u2afe\u2aff\ufb29\ufe62\ufe64\ufe65\ufe66\uff0b\uff1c\uff1d\uff1e\uff5c\uff5e\uffe2\uffe9\uffea\uffeb\uffec'
+
+So = u'\xa6\xa7\xa9\xae\xb0\xb6\u0482\u060e\u060f\u06e9\u06fd\u06fe\u09fa\u0b70\u0bf3\u0bf4\u0bf5\u0bf6\u0bf7\u0bf8\u0bfa\u0f01\u0f02\u0f03\u0f13\u0f14\u0f15\u0f16\u0f17\u0f1a\u0f1b\u0f1c\u0f1d\u0f1e\u0f1f\u0f34\u0f36\u0f38\u0fbe\u0fbf\u0fc0\u0fc1\u0fc2\u0fc3\u0fc4\u0fc5\u0fc7\u0fc8\u0fc9\u0fca\u0fcb\u0fcc\u0fcf\u1360\u1390\u1391\u1392\u1393\u1394\u1395\u1396\u1397\u1398\u1399\u1940\u19e0\u19e1\u19e2\u19e3\u19e4\u19e5\u19e6\u19e7\u19e8\u19e9\u19ea\u19eb\u19ec\u19ed\u19ee\u19ef\u19f0\u19f1\u19f2\u19f3\u19f4\u19f5\u19f6\u19f7\u19f8\u19f9\u19fa\u19fb\u19fc\u19fd\u19fe\u19ff\u2100\u2101\u2103\u2104\u2105\u2106\u2108\u2109\u2114\u2116\u2117\u2118\u211e\u211f\u2120\u2121\u2122\u2123\u2125\u2127\u2129\u212e\u2132\u213a\u213b\u214a\u214c\u2195\u2196\u2197\u2198\u2199\u219c\u219d\u219e\u219f\u21a1\u21a2\u21a4\u21a5\u21a7\u21a8\u21a9\u21aa\u21ab\u21ac\u21ad\u21af\u21b0\u21b1\u21b2\u21b3\u21b4\u21b5\u21b6\u21b7\u21b8\u21b9\u21ba\u21bb\u21bc\u21bd\u21be\u21bf\u21c0\u21c1\u21c2\u21c3\u21c4\u21c5\u21c6\u21c7\u21c8\u21c9\u21ca\u21cb\u21cc\u21cd\u21d0\u21d1\u21d3\u21d5\u21d6\u21d7\u21d8\u21d9\u21da\u21db\u21dc\u21dd\u21de\u21df\u21e0\u21e1\u21e2\u21e3\u21e4\u21e5\u21e6\u21e7\u21e8\u21e9\u21ea\u21eb\u21ec\u21ed\u21ee\u21ef\u21f0\u21f1\u21f2\u21f3\u2300\u2301\u2302\u2303\u2304\u2305\u2306\u2307\u230c\u230d\u230e\u230f\u2310\u2311\u2312\u2313\u2314\u2315\u2316\u2317\u2318\u2319\u231a\u231b\u231c\u231d\u231e\u231f\u2322\u2323\u2324\u2325\u2326\u2327\u2328\u232b\u232c\u232d\u232e\u232f\u2330\u2331\u2332\u2333\u2334\u2335\u2336\u2337\u2338\u2339\u233a\u233b\u233c\u233d\u233e\u233f\u2340\u2341\u2342\u2343\u2344\u2345\u2346\u2347\u2348\u2349\u234a\u234b\u234c\u234d\u234e\u234f\u2350\u2351\u2352\u2353\u2354\u2355\u2356\u2357\u2358\u2359\u235a\u235b\u235c\u235d\u235e\u235f\u2360\u2361\u2362\u2363\u2364\u2365\u2366\u2367\u2368\u2369\u236a\u236b\u236c\u236d\u236e\u236f\u2370\u2371\u2372\u2373\u2374\u2375\u2376\u2377\u2378\u2379\u237a\u237b\u237d\u237e\u237f\u2380\u2381\u2382\u2383\u2384\u2385\u2386\u2387\u2388\u2389\u238a\u238b\u238c\u238d\u238e\u238f\u2390\u2391\u2392\u2393\u2394\u2395\u2396\u2397\u2398\u2399\u239a\u23b7\u23b8\u23b9\u23ba\u23bb\u23bc\u23bd\u23be\u23bf\u23c0\u23c1\u23c2\u23c3\u23c4\u23c5\u23c6\u23c7\u23c8\u23c9\u23ca\u23cb\u23cc\u23cd\u23ce\u23cf\u23d0\u23d1\u23d2\u23d3\u23d4\u23d5\u23d6\u23d7\u23d8\u23d9\u23da\u23db\u2400\u2401\u2402\u2403\u2404\u2405\u2406\u2407\u2408\u2409\u240a\u240b\u240c\u240d\u240e\u240f\u2410\u2411\u2412\u2413\u2414\u2415\u2416\u2417\u2418\u2419\u241a\u241b\u241c\u241d\u241e\u241f\u2420\u2421\u2422\u2423\u2424\u2425\u2426\u2440\u2441\u2442\u2443\u2444\u2445\u2446\u2447\u2448\u2449\u244a\u249c\u249d\u249e\u249f\u24a0\u24a1\u24a2\u24a3\u24a4\u24a5\u24a6\u24a7\u24a8\u24a9\u24aa\u24ab\u24ac\u24ad\u24ae\u24af\u24b0\u24b1\u24b2\u24b3\u24b4\u24b5\u24b6\u24b7\u24b8\u24b9\u24ba\u24bb\u24bc\u24bd\u24be\u24bf\u24c0\u24c1\u24c2\u24c3\u24c4\u24c5\u24c6\u24c7\u24c8\u24c9\u24ca\u24cb\u24cc\u24cd\u24ce\u24cf\u24d0\u24d1\u24d2\u24d3\u24d4\u24d5\u24d6\u24d7\u24d8\u24d9\u24da\u24db\u24dc\u24dd\u24de\u24df\u24e0\u24e1\u24e2\u24e3\u24e4\u24e5\u24e6\u24e7\u24e8\u24e9\u2500\u2501\u2502\u2503\u2504\u2505\u2506\u2507\u2508\u2509\u250a\u250b\u250c\u250d\u250e\u250f\u2510\u2511\u2512\u2513\u2514\u2515\u2516\u2517\u2518\u2519\u251a\u251b\u251c\u251d\u251e\u251f\u2520\u2521\u2522\u2523\u2524\u2525\u2526\u2527\u2528\u2529\u252a\u252b\u252c\u252d\u252e\u252f\u2530\u2531\u2532\u2533\u2534\u2535\u2536\u2537\u2538\u2539\u253a\u253b\u253c\u253d\u253e\u253f\u2540\u2541\u2542\u2543\u2544\u2545\u2546\u2547\u2548\u2549\u254a\u254b\u254c\u254d\u254e\u254f\u2550\u2551\u2552\u2553\u2554\u2555\u2556\u2557\u2558\u2559\u255a\u255b\u255c\u255d\u255e\u255f\u2560\u2561\u2562\u2563\u2564\u2565\u2566\u2567\u2568\u2569\u256a\u256b\u256c\u256d\u256e\u256f\u2570\u2571\u2572\u2573\u2574\u2575\u2576\u2577\u2578\u2579\u257a\u257b\u257c\u257d\u257e\u257f\u2580\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588\u2589\u258a\u258b\u258c\u258d\u258e\u258f\u2590\u2591\u2592\u2593\u2594\u2595\u2596\u2597\u2598\u2599\u259a\u259b\u259c\u259d\u259e\u259f\u25a0\u25a1\u25a2\u25a3\u25a4\u25a5\u25a6\u25a7\u25a8\u25a9\u25aa\u25ab\u25ac\u25ad\u25ae\u25af\u25b0\u25b1\u25b2\u25b3\u25b4\u25b5\u25b6\u25b8\u25b9\u25ba\u25bb\u25bc\u25bd\u25be\u25bf\u25c0\u25c2\u25c3\u25c4\u25c5\u25c6\u25c7\u25c8\u25c9\u25ca\u25cb\u25cc\u25cd\u25ce\u25cf\u25d0\u25d1\u25d2\u25d3\u25d4\u25d5\u25d6\u25d7\u25d8\u25d9\u25da\u25db\u25dc\u25dd\u25de\u25df\u25e0\u25e1\u25e2\u25e3\u25e4\u25e5\u25e6\u25e7\u25e8\u25e9\u25ea\u25eb\u25ec\u25ed\u25ee\u25ef\u25f0\u25f1\u25f2\u25f3\u25f4\u25f5\u25f6\u25f7\u2600\u2601\u2602\u2603\u2604\u2605\u2606\u2607\u2608\u2609\u260a\u260b\u260c\u260d\u260e\u260f\u2610\u2611\u2612\u2613\u2614\u2615\u2616\u2617\u2618\u2619\u261a\u261b\u261c\u261d\u261e\u261f\u2620\u2621\u2622\u2623\u2624\u2625\u2626\u2627\u2628\u2629\u262a\u262b\u262c\u262d\u262e\u262f\u2630\u2631\u2632\u2633\u2634\u2635\u2636\u2637\u2638\u2639\u263a\u263b\u263c\u263d\u263e\u263f\u2640\u2641\u2642\u2643\u2644\u2645\u2646\u2647\u2648\u2649\u264a\u264b\u264c\u264d\u264e\u264f\u2650\u2651\u2652\u2653\u2654\u2655\u2656\u2657\u2658\u2659\u265a\u265b\u265c\u265d\u265e\u265f\u2660\u2661\u2662\u2663\u2664\u2665\u2666\u2667\u2668\u2669\u266a\u266b\u266c\u266d\u266e\u2670\u2671\u2672\u2673\u2674\u2675\u2676\u2677\u2678\u2679\u267a\u267b\u267c\u267d\u267e\u267f\u2680\u2681\u2682\u2683\u2684\u2685\u2686\u2687\u2688\u2689\u268a\u268b\u268c\u268d\u268e\u268f\u2690\u2691\u2692\u2693\u2694\u2695\u2696\u2697\u2698\u2699\u269a\u269b\u269c\u26a0\u26a1\u26a2\u26a3\u26a4\u26a5\u26a6\u26a7\u26a8\u26a9\u26aa\u26ab\u26ac\u26ad\u26ae\u26af\u26b0\u26b1\u2701\u2702\u2703\u2704\u2706\u2707\u2708\u2709\u270c\u270d\u270e\u270f\u2710\u2711\u2712\u2713\u2714\u2715\u2716\u2717\u2718\u2719\u271a\u271b\u271c\u271d\u271e\u271f\u2720\u2721\u2722\u2723\u2724\u2725\u2726\u2727\u2729\u272a\u272b\u272c\u272d\u272e\u272f\u2730\u2731\u2732\u2733\u2734\u2735\u2736\u2737\u2738\u2739\u273a\u273b\u273c\u273d\u273e\u273f\u2740\u2741\u2742\u2743\u2744\u2745\u2746\u2747\u2748\u2749\u274a\u274b\u274d\u274f\u2750\u2751\u2752\u2756\u2758\u2759\u275a\u275b\u275c\u275d\u275e\u2761\u2762\u2763\u2764\u2765\u2766\u2767\u2794\u2798\u2799\u279a\u279b\u279c\u279d\u279e\u279f\u27a0\u27a1\u27a2\u27a3\u27a4\u27a5\u27a6\u27a7\u27a8\u27a9\u27aa\u27ab\u27ac\u27ad\u27ae\u27af\u27b1\u27b2\u27b3\u27b4\u27b5\u27b6\u27b7\u27b8\u27b9\u27ba\u27bb\u27bc\u27bd\u27be\u2800\u2801\u2802\u2803\u2804\u2805\u2806\u2807\u2808\u2809\u280a\u280b\u280c\u280d\u280e\u280f\u2810\u2811\u2812\u2813\u2814\u2815\u2816\u2817\u2818\u2819\u281a\u281b\u281c\u281d\u281e\u281f\u2820\u2821\u2822\u2823\u2824\u2825\u2826\u2827\u2828\u2829\u282a\u282b\u282c\u282d\u282e\u282f\u2830\u2831\u2832\u2833\u2834\u2835\u2836\u2837\u2838\u2839\u283a\u283b\u283c\u283d\u283e\u283f\u2840\u2841\u2842\u2843\u2844\u2845\u2846\u2847\u2848\u2849\u284a\u284b\u284c\u284d\u284e\u284f\u2850\u2851\u2852\u2853\u2854\u2855\u2856\u2857\u2858\u2859\u285a\u285b\u285c\u285d\u285e\u285f\u2860\u2861\u2862\u2863\u2864\u2865\u2866\u2867\u2868\u2869\u286a\u286b\u286c\u286d\u286e\u286f\u2870\u2871\u2872\u2873\u2874\u2875\u2876\u2877\u2878\u2879\u287a\u287b\u287c\u287d\u287e\u287f\u2880\u2881\u2882\u2883\u2884\u2885\u2886\u2887\u2888\u2889\u288a\u288b\u288c\u288d\u288e\u288f\u2890\u2891\u2892\u2893\u2894\u2895\u2896\u2897\u2898\u2899\u289a\u289b\u289c\u289d\u289e\u289f\u28a0\u28a1\u28a2\u28a3\u28a4\u28a5\u28a6\u28a7\u28a8\u28a9\u28aa\u28ab\u28ac\u28ad\u28ae\u28af\u28b0\u28b1\u28b2\u28b3\u28b4\u28b5\u28b6\u28b7\u28b8\u28b9\u28ba\u28bb\u28bc\u28bd\u28be\u28bf\u28c0\u28c1\u28c2\u28c3\u28c4\u28c5\u28c6\u28c7\u28c8\u28c9\u28ca\u28cb\u28cc\u28cd\u28ce\u28cf\u28d0\u28d1\u28d2\u28d3\u28d4\u28d5\u28d6\u28d7\u28d8\u28d9\u28da\u28db\u28dc\u28dd\u28de\u28df\u28e0\u28e1\u28e2\u28e3\u28e4\u28e5\u28e6\u28e7\u28e8\u28e9\u28ea\u28eb\u28ec\u28ed\u28ee\u28ef\u28f0\u28f1\u28f2\u28f3\u28f4\u28f5\u28f6\u28f7\u28f8\u28f9\u28fa\u28fb\u28fc\u28fd\u28fe\u28ff\u2b00\u2b01\u2b02\u2b03\u2b04\u2b05\u2b06\u2b07\u2b08\u2b09\u2b0a\u2b0b\u2b0c\u2b0d\u2b0e\u2b0f\u2b10\u2b11\u2b12\u2b13\u2ce5\u2ce6\u2ce7\u2ce8\u2ce9\u2cea\u2e80\u2e81\u2e82\u2e83\u2e84\u2e85\u2e86\u2e87\u2e88\u2e89\u2e8a\u2e8b\u2e8c\u2e8d\u2e8e\u2e8f\u2e90\u2e91\u2e92\u2e93\u2e94\u2e95\u2e96\u2e97\u2e98\u2e99\u2e9b\u2e9c\u2e9d\u2e9e\u2e9f\u2ea0\u2ea1\u2ea2\u2ea3\u2ea4\u2ea5\u2ea6\u2ea7\u2ea8\u2ea9\u2eaa\u2eab\u2eac\u2ead\u2eae\u2eaf\u2eb0\u2eb1\u2eb2\u2eb3\u2eb4\u2eb5\u2eb6\u2eb7\u2eb8\u2eb9\u2eba\u2ebb\u2ebc\u2ebd\u2ebe\u2ebf\u2ec0\u2ec1\u2ec2\u2ec3\u2ec4\u2ec5\u2ec6\u2ec7\u2ec8\u2ec9\u2eca\u2ecb\u2ecc\u2ecd\u2ece\u2ecf\u2ed0\u2ed1\u2ed2\u2ed3\u2ed4\u2ed5\u2ed6\u2ed7\u2ed8\u2ed9\u2eda\u2edb\u2edc\u2edd\u2ede\u2edf\u2ee0\u2ee1\u2ee2\u2ee3\u2ee4\u2ee5\u2ee6\u2ee7\u2ee8\u2ee9\u2eea\u2eeb\u2eec\u2eed\u2eee\u2eef\u2ef0\u2ef1\u2ef2\u2ef3\u2f00\u2f01\u2f02\u2f03\u2f04\u2f05\u2f06\u2f07\u2f08\u2f09\u2f0a\u2f0b\u2f0c\u2f0d\u2f0e\u2f0f\u2f10\u2f11\u2f12\u2f13\u2f14\u2f15\u2f16\u2f17\u2f18\u2f19\u2f1a\u2f1b\u2f1c\u2f1d\u2f1e\u2f1f\u2f20\u2f21\u2f22\u2f23\u2f24\u2f25\u2f26\u2f27\u2f28\u2f29\u2f2a\u2f2b\u2f2c\u2f2d\u2f2e\u2f2f\u2f30\u2f31\u2f32\u2f33\u2f34\u2f35\u2f36\u2f37\u2f38\u2f39\u2f3a\u2f3b\u2f3c\u2f3d\u2f3e\u2f3f\u2f40\u2f41\u2f42\u2f43\u2f44\u2f45\u2f46\u2f47\u2f48\u2f49\u2f4a\u2f4b\u2f4c\u2f4d\u2f4e\u2f4f\u2f50\u2f51\u2f52\u2f53\u2f54\u2f55\u2f56\u2f57\u2f58\u2f59\u2f5a\u2f5b\u2f5c\u2f5d\u2f5e\u2f5f\u2f60\u2f61\u2f62\u2f63\u2f64\u2f65\u2f66\u2f67\u2f68\u2f69\u2f6a\u2f6b\u2f6c\u2f6d\u2f6e\u2f6f\u2f70\u2f71\u2f72\u2f73\u2f74\u2f75\u2f76\u2f77\u2f78\u2f79\u2f7a\u2f7b\u2f7c\u2f7d\u2f7e\u2f7f\u2f80\u2f81\u2f82\u2f83\u2f84\u2f85\u2f86\u2f87\u2f88\u2f89\u2f8a\u2f8b\u2f8c\u2f8d\u2f8e\u2f8f\u2f90\u2f91\u2f92\u2f93\u2f94\u2f95\u2f96\u2f97\u2f98\u2f99\u2f9a\u2f9b\u2f9c\u2f9d\u2f9e\u2f9f\u2fa0\u2fa1\u2fa2\u2fa3\u2fa4\u2fa5\u2fa6\u2fa7\u2fa8\u2fa9\u2faa\u2fab\u2fac\u2fad\u2fae\u2faf\u2fb0\u2fb1\u2fb2\u2fb3\u2fb4\u2fb5\u2fb6\u2fb7\u2fb8\u2fb9\u2fba\u2fbb\u2fbc\u2fbd\u2fbe\u2fbf\u2fc0\u2fc1\u2fc2\u2fc3\u2fc4\u2fc5\u2fc6\u2fc7\u2fc8\u2fc9\u2fca\u2fcb\u2fcc\u2fcd\u2fce\u2fcf\u2fd0\u2fd1\u2fd2\u2fd3\u2fd4\u2fd5\u2ff0\u2ff1\u2ff2\u2ff3\u2ff4\u2ff5\u2ff6\u2ff7\u2ff8\u2ff9\u2ffa\u2ffb\u3004\u3012\u3013\u3020\u3036\u3037\u303e\u303f\u3190\u3191\u3196\u3197\u3198\u3199\u319a\u319b\u319c\u319d\u319e\u319f\u31c0\u31c1\u31c2\u31c3\u31c4\u31c5\u31c6\u31c7\u31c8\u31c9\u31ca\u31cb\u31cc\u31cd\u31ce\u31cf\u3200\u3201\u3202\u3203\u3204\u3205\u3206\u3207\u3208\u3209\u320a\u320b\u320c\u320d\u320e\u320f\u3210\u3211\u3212\u3213\u3214\u3215\u3216\u3217\u3218\u3219\u321a\u321b\u321c\u321d\u321e\u322a\u322b\u322c\u322d\u322e\u322f\u3230\u3231\u3232\u3233\u3234\u3235\u3236\u3237\u3238\u3239\u323a\u323b\u323c\u323d\u323e\u323f\u3240\u3241\u3242\u3243\u3250\u3260\u3261\u3262\u3263\u3264\u3265\u3266\u3267\u3268\u3269\u326a\u326b\u326c\u326d\u326e\u326f\u3270\u3271\u3272\u3273\u3274\u3275\u3276\u3277\u3278\u3279\u327a\u327b\u327c\u327d\u327e\u327f\u328a\u328b\u328c\u328d\u328e\u328f\u3290\u3291\u3292\u3293\u3294\u3295\u3296\u3297\u3298\u3299\u329a\u329b\u329c\u329d\u329e\u329f\u32a0\u32a1\u32a2\u32a3\u32a4\u32a5\u32a6\u32a7\u32a8\u32a9\u32aa\u32ab\u32ac\u32ad\u32ae\u32af\u32b0\u32c0\u32c1\u32c2\u32c3\u32c4\u32c5\u32c6\u32c7\u32c8\u32c9\u32ca\u32cb\u32cc\u32cd\u32ce\u32cf\u32d0\u32d1\u32d2\u32d3\u32d4\u32d5\u32d6\u32d7\u32d8\u32d9\u32da\u32db\u32dc\u32dd\u32de\u32df\u32e0\u32e1\u32e2\u32e3\u32e4\u32e5\u32e6\u32e7\u32e8\u32e9\u32ea\u32eb\u32ec\u32ed\u32ee\u32ef\u32f0\u32f1\u32f2\u32f3\u32f4\u32f5\u32f6\u32f7\u32f8\u32f9\u32fa\u32fb\u32fc\u32fd\u32fe\u3300\u3301\u3302\u3303\u3304\u3305\u3306\u3307\u3308\u3309\u330a\u330b\u330c\u330d\u330e\u330f\u3310\u3311\u3312\u3313\u3314\u3315\u3316\u3317\u3318\u3319\u331a\u331b\u331c\u331d\u331e\u331f\u3320\u3321\u3322\u3323\u3324\u3325\u3326\u3327\u3328\u3329\u332a\u332b\u332c\u332d\u332e\u332f\u3330\u3331\u3332\u3333\u3334\u3335\u3336\u3337\u3338\u3339\u333a\u333b\u333c\u333d\u333e\u333f\u3340\u3341\u3342\u3343\u3344\u3345\u3346\u3347\u3348\u3349\u334a\u334b\u334c\u334d\u334e\u334f\u3350\u3351\u3352\u3353\u3354\u3355\u3356\u3357\u3358\u3359\u335a\u335b\u335c\u335d\u335e\u335f\u3360\u3361\u3362\u3363\u3364\u3365\u3366\u3367\u3368\u3369\u336a\u336b\u336c\u336d\u336e\u336f\u3370\u3371\u3372\u3373\u3374\u3375\u3376\u3377\u3378\u3379\u337a\u337b\u337c\u337d\u337e\u337f\u3380\u3381\u3382\u3383\u3384\u3385\u3386\u3387\u3388\u3389\u338a\u338b\u338c\u338d\u338e\u338f\u3390\u3391\u3392\u3393\u3394\u3395\u3396\u3397\u3398\u3399\u339a\u339b\u339c\u339d\u339e\u339f\u33a0\u33a1\u33a2\u33a3\u33a4\u33a5\u33a6\u33a7\u33a8\u33a9\u33aa\u33ab\u33ac\u33ad\u33ae\u33af\u33b0\u33b1\u33b2\u33b3\u33b4\u33b5\u33b6\u33b7\u33b8\u33b9\u33ba\u33bb\u33bc\u33bd\u33be\u33bf\u33c0\u33c1\u33c2\u33c3\u33c4\u33c5\u33c6\u33c7\u33c8\u33c9\u33ca\u33cb\u33cc\u33cd\u33ce\u33cf\u33d0\u33d1\u33d2\u33d3\u33d4\u33d5\u33d6\u33d7\u33d8\u33d9\u33da\u33db\u33dc\u33dd\u33de\u33df\u33e0\u33e1\u33e2\u33e3\u33e4\u33e5\u33e6\u33e7\u33e8\u33e9\u33ea\u33eb\u33ec\u33ed\u33ee\u33ef\u33f0\u33f1\u33f2\u33f3\u33f4\u33f5\u33f6\u33f7\u33f8\u33f9\u33fa\u33fb\u33fc\u33fd\u33fe\u33ff\u4dc0\u4dc1\u4dc2\u4dc3\u4dc4\u4dc5\u4dc6\u4dc7\u4dc8\u4dc9\u4dca\u4dcb\u4dcc\u4dcd\u4dce\u4dcf\u4dd0\u4dd1\u4dd2\u4dd3\u4dd4\u4dd5\u4dd6\u4dd7\u4dd8\u4dd9\u4dda\u4ddb\u4ddc\u4ddd\u4dde\u4ddf\u4de0\u4de1\u4de2\u4de3\u4de4\u4de5\u4de6\u4de7\u4de8\u4de9\u4dea\u4deb\u4dec\u4ded\u4dee\u4def\u4df0\u4df1\u4df2\u4df3\u4df4\u4df5\u4df6\u4df7\u4df8\u4df9\u4dfa\u4dfb\u4dfc\u4dfd\u4dfe\u4dff\ua490\ua491\ua492\ua493\ua494\ua495\ua496\ua497\ua498\ua499\ua49a\ua49b\ua49c\ua49d\ua49e\ua49f\ua4a0\ua4a1\ua4a2\ua4a3\ua4a4\ua4a5\ua4a6\ua4a7\ua4a8\ua4a9\ua4aa\ua4ab\ua4ac\ua4ad\ua4ae\ua4af\ua4b0\ua4b1\ua4b2\ua4b3\ua4b4\ua4b5\ua4b6\ua4b7\ua4b8\ua4b9\ua4ba\ua4bb\ua4bc\ua4bd\ua4be\ua4bf\ua4c0\ua4c1\ua4c2\ua4c3\ua4c4\ua4c5\ua4c6\ua828\ua829\ua82a\ua82b\ufdfd\uffe4\uffe8\uffed\uffee\ufffc\ufffd'
+
+Zl = u'\u2028'
+
+Zp = u'\u2029'
+
+Zs = u' \xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
+
+cats = ['Cc', 'Cf', 'Cn', 'Co', 'Cs', 'Ll', 'Lm', 'Lo', 'Lt', 'Lu', 'Mc', 'Me', 'Mn', 'Nd', 'Nl', 'No', 'Pc', 'Pd', 'Pe', 'Pf', 'Pi', 'Po', 'Ps', 'Sc', 'Sk', 'Sm', 'So', 'Zl', 'Zp', 'Zs']
+
+def combine(*args):
+    return u''.join([globals()[cat] for cat in args])
+
+xid_start = u'\u0041-\u005A\u005F\u0061-\u007A\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u01BA\u01BB\u01BC-\u01BF\u01C0-\u01C3\u01C4-\u0241\u0250-\u02AF\u02B0-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EE\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03CE\u03D0-\u03F5\u03F7-\u0481\u048A-\u04CE\u04D0-\u04F9\u0500-\u050F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0621-\u063A\u0640\u0641-\u064A\u066E-\u066F\u0671-\u06D3\u06D5\u06E5-\u06E6\u06EE-\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u076D\u0780-\u07A5\u07B1\u0904-\u0939\u093D\u0950\u0958-\u0961\u097D\u0985-\u098C\u098F-\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC-\u09DD\u09DF-\u09E1\u09F0-\u09F1\u0A05-\u0A0A\u0A0F-\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32-\u0A33\u0A35-\u0A36\u0A38-\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2-\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0-\u0AE1\u0B05-\u0B0C\u0B0F-\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32-\u0B33\u0B35-\u0B39\u0B3D\u0B5C-\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99-\u0B9A\u0B9C\u0B9E-\u0B9F\u0BA3-\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C60-\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0-\u0CE1\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D60-\u0D61\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E40-\u0E45\u0E46\u0E81-\u0E82\u0E84\u0E87-\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA-\u0EAB\u0EAD-\u0EB0\u0EB2\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDD\u0F00\u0F40-\u0F47\u0F49-\u0F6A\u0F88-\u0F8B\u1000-\u1021\u1023-\u1027\u1029-\u102A\u1050-\u1055\u10A0-\u10C5\u10D0-\u10FA\u10FC\u1100-\u1159\u115F-\u11A2\u11A8-\u11F9\u1200-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u1676\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1842\u1843\u1844-\u1877\u1880-\u18A8\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19A9\u19C1-\u19C7\u1A00-\u1A16\u1D00-\u1D2B\u1D2C-\u1D61\u1D62-\u1D77\u1D78\u1D79-\u1D9A\u1D9B-\u1DBF\u1E00-\u1E9B\u1EA0-\u1EF9\u1F00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u2094\u2102\u2107\u210A-\u2113\u2115\u2118\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212E\u212F-\u2131\u2133-\u2134\u2135-\u2138\u2139\u213C-\u213F\u2145-\u2149\u2160-\u2183\u2C00-\u2C2E\u2C30-\u2C5E\u2C80-\u2CE4\u2D00-\u2D25\u2D30-\u2D65\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005\u3006\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303A\u303B\u303C\u3041-\u3096\u309D-\u309E\u309F\u30A1-\u30FA\u30FC-\u30FE\u30FF\u3105-\u312C\u3131-\u318E\u31A0-\u31B7\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FBB\uA000-\uA014\uA015\uA016-\uA48C\uA800-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uAC00-\uD7A3\uF900-\uFA2D\uFA30-\uFA6A\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40-\uFB41\uFB43-\uFB44\uFB46-\uFBB1\uFBD3-\uFC5D\uFC64-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDF9\uFE71\uFE73\uFE77\uFE79\uFE7B\uFE7D\uFE7F-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFF6F\uFF70\uFF71-\uFF9D\uFFA0-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC'
+
+xid_continue = u'\u0030-\u0039\u0041-\u005A\u005F\u0061-\u007A\u00AA\u00B5\u00B7\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u01BA\u01BB\u01BC-\u01BF\u01C0-\u01C3\u01C4-\u0241\u0250-\u02AF\u02B0-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EE\u0300-\u036F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03CE\u03D0-\u03F5\u03F7-\u0481\u0483-\u0486\u048A-\u04CE\u04D0-\u04F9\u0500-\u050F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05B9\u05BB-\u05BD\u05BF\u05C1-\u05C2\u05C4-\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u0615\u0621-\u063A\u0640\u0641-\u064A\u064B-\u065E\u0660-\u0669\u066E-\u066F\u0670\u0671-\u06D3\u06D5\u06D6-\u06DC\u06DF-\u06E4\u06E5-\u06E6\u06E7-\u06E8\u06EA-\u06ED\u06EE-\u06EF\u06F0-\u06F9\u06FA-\u06FC\u06FF\u0710\u0711\u0712-\u072F\u0730-\u074A\u074D-\u076D\u0780-\u07A5\u07A6-\u07B0\u07B1\u0901-\u0902\u0903\u0904-\u0939\u093C\u093D\u093E-\u0940\u0941-\u0948\u0949-\u094C\u094D\u0950\u0951-\u0954\u0958-\u0961\u0962-\u0963\u0966-\u096F\u097D\u0981\u0982-\u0983\u0985-\u098C\u098F-\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC\u09BD\u09BE-\u09C0\u09C1-\u09C4\u09C7-\u09C8\u09CB-\u09CC\u09CD\u09CE\u09D7\u09DC-\u09DD\u09DF-\u09E1\u09E2-\u09E3\u09E6-\u09EF\u09F0-\u09F1\u0A01-\u0A02\u0A03\u0A05-\u0A0A\u0A0F-\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32-\u0A33\u0A35-\u0A36\u0A38-\u0A39\u0A3C\u0A3E-\u0A40\u0A41-\u0A42\u0A47-\u0A48\u0A4B-\u0A4D\u0A59-\u0A5C\u0A5E\u0A66-\u0A6F\u0A70-\u0A71\u0A72-\u0A74\u0A81-\u0A82\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2-\u0AB3\u0AB5-\u0AB9\u0ABC\u0ABD\u0ABE-\u0AC0\u0AC1-\u0AC5\u0AC7-\u0AC8\u0AC9\u0ACB-\u0ACC\u0ACD\u0AD0\u0AE0-\u0AE1\u0AE2-\u0AE3\u0AE6-\u0AEF\u0B01\u0B02-\u0B03\u0B05-\u0B0C\u0B0F-\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32-\u0B33\u0B35-\u0B39\u0B3C\u0B3D\u0B3E\u0B3F\u0B40\u0B41-\u0B43\u0B47-\u0B48\u0B4B-\u0B4C\u0B4D\u0B56\u0B57\u0B5C-\u0B5D\u0B5F-\u0B61\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99-\u0B9A\u0B9C\u0B9E-\u0B9F\u0BA3-\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BBF\u0BC0\u0BC1-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCC\u0BCD\u0BD7\u0BE6-\u0BEF\u0C01-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3E-\u0C40\u0C41-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55-\u0C56\u0C60-\u0C61\u0C66-\u0C6F\u0C82-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC\u0CBD\u0CBE\u0CBF\u0CC0-\u0CC4\u0CC6\u0CC7-\u0CC8\u0CCA-\u0CCB\u0CCC-\u0CCD\u0CD5-\u0CD6\u0CDE\u0CE0-\u0CE1\u0CE6-\u0CEF\u0D02-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D3E-\u0D40\u0D41-\u0D43\u0D46-\u0D48\u0D4A-\u0D4C\u0D4D\u0D57\u0D60-\u0D61\u0D66-\u0D6F\u0D82-\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD1\u0DD2-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2-\u0DF3\u0E01-\u0E30\u0E31\u0E32-\u0E33\u0E34-\u0E3A\u0E40-\u0E45\u0E46\u0E47-\u0E4E\u0E50-\u0E59\u0E81-\u0E82\u0E84\u0E87-\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA-\u0EAB\u0EAD-\u0EB0\u0EB1\u0EB2-\u0EB3\u0EB4-\u0EB9\u0EBB-\u0EBC\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDD\u0F00\u0F18-\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F3F\u0F40-\u0F47\u0F49-\u0F6A\u0F71-\u0F7E\u0F7F\u0F80-\u0F84\u0F86-\u0F87\u0F88-\u0F8B\u0F90-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1021\u1023-\u1027\u1029-\u102A\u102C\u102D-\u1030\u1031\u1032\u1036-\u1037\u1038\u1039\u1040-\u1049\u1050-\u1055\u1056-\u1057\u1058-\u1059\u10A0-\u10C5\u10D0-\u10FA\u10FC\u1100-\u1159\u115F-\u11A2\u11A8-\u11F9\u1200-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135F\u1369-\u1371\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u1676\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1711\u1712-\u1714\u1720-\u1731\u1732-\u1734\u1740-\u1751\u1752-\u1753\u1760-\u176C\u176E-\u1770\u1772-\u1773\u1780-\u17B3\u17B6\u17B7-\u17BD\u17BE-\u17C5\u17C6\u17C7-\u17C8\u17C9-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1842\u1843\u1844-\u1877\u1880-\u18A8\u18A9\u1900-\u191C\u1920-\u1922\u1923-\u1926\u1927-\u1928\u1929-\u192B\u1930-\u1931\u1932\u1933-\u1938\u1939-\u193B\u1946-\u194F\u1950-\u196D\u1970-\u1974\u1980-\u19A9\u19B0-\u19C0\u19C1-\u19C7\u19C8-\u19C9\u19D0-\u19D9\u1A00-\u1A16\u1A17-\u1A18\u1A19-\u1A1B\u1D00-\u1D2B\u1D2C-\u1D61\u1D62-\u1D77\u1D78\u1D79-\u1D9A\u1D9B-\u1DBF\u1DC0-\u1DC3\u1E00-\u1E9B\u1EA0-\u1EF9\u1F00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u203F-\u2040\u2054\u2071\u207F\u2090-\u2094\u20D0-\u20DC\u20E1\u20E5-\u20EB\u2102\u2107\u210A-\u2113\u2115\u2118\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212E\u212F-\u2131\u2133-\u2134\u2135-\u2138\u2139\u213C-\u213F\u2145-\u2149\u2160-\u2183\u2C00-\u2C2E\u2C30-\u2C5E\u2C80-\u2CE4\u2D00-\u2D25\u2D30-\u2D65\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005\u3006\u3007\u3021-\u3029\u302A-\u302F\u3031-\u3035\u3038-\u303A\u303B\u303C\u3041-\u3096\u3099-\u309A\u309D-\u309E\u309F\u30A1-\u30FA\u30FC-\u30FE\u30FF\u3105-\u312C\u3131-\u318E\u31A0-\u31B7\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FBB\uA000-\uA014\uA015\uA016-\uA48C\uA800-\uA801\uA802\uA803-\uA805\uA806\uA807-\uA80A\uA80B\uA80C-\uA822\uA823-\uA824\uA825-\uA826\uA827\uAC00-\uD7A3\uF900-\uFA2D\uFA30-\uFA6A\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1E\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40-\uFB41\uFB43-\uFB44\uFB46-\uFBB1\uFBD3-\uFC5D\uFC64-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDF9\uFE00-\uFE0F\uFE20-\uFE23\uFE33-\uFE34\uFE4D-\uFE4F\uFE71\uFE73\uFE77\uFE79\uFE7B\uFE7D\uFE7F-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFF6F\uFF70\uFF71-\uFF9D\uFF9E-\uFF9F\uFFA0-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC'
+
+def allexcept(*args):
+    newcats = cats[:]
+    for arg in args:
+        newcats.remove(arg)
+    return u''.join([globals()[cat] for cat in newcats])
+
+if __name__ == '__main__':
+    import unicodedata
+
+    categories = {}
+
+    f = open(__file__.rstrip('co'))
+    try:
+        content = f.read()
+    finally:
+        f.close()
+
+    header = content[:content.find('Cc =')]
+    footer = content[content.find("def combine("):]
+
+    for code in range(65535):
+        c = unichr(code)
+        cat = unicodedata.category(c)
+        categories.setdefault(cat, []).append(c)
+
+    f = open(__file__, 'w')
+    f.write(header)
+
+    for cat in sorted(categories):
+        val = u''.join(categories[cat])
+        if cat == 'Cs':
+            # Jython can't handle isolated surrogates
+            f.write("""\
+try:
+    Cs = eval(r"%r")
+except UnicodeDecodeError:
+    Cs = '' # Jython can't handle isolated surrogates\n\n""" % val)
+        else:
+            f.write('%s = %r\n\n' % (cat, val))
+    f.write('cats = %r\n\n' % sorted(categories.keys()))
+
+    f.write(footer)
+    f.close()
diff --git a/lib/jinja2/jinja2/bccache.py b/lib/jinja2/jinja2/bccache.py
new file mode 100644
index 0000000..0b0ccad
--- /dev/null
+++ b/lib/jinja2/jinja2/bccache.py
@@ -0,0 +1,301 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.bccache
+    ~~~~~~~~~~~~~~
+
+    This module implements the bytecode cache system Jinja is optionally
+    using.  This is useful if you have very complex template situations and
+    the compiliation of all those templates slow down your application too
+    much.
+
+    Situations where this is useful are often forking web applications that
+    are initialized on the first request.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD.
+"""
+from os import path, listdir
+import sys
+import marshal
+import tempfile
+import cPickle as pickle
+import fnmatch
+try:
+    from hashlib import sha1
+except ImportError:
+    from sha import new as sha1
+from jinja2.utils import open_if_exists
+
+
+# marshal works better on 3.x, one hack less required
+if sys.version_info > (3, 0):
+    from io import BytesIO
+    marshal_dump = marshal.dump
+    marshal_load = marshal.load
+else:
+    from cStringIO import StringIO as BytesIO
+
+    def marshal_dump(code, f):
+        if isinstance(f, file):
+            marshal.dump(code, f)
+        else:
+            f.write(marshal.dumps(code))
+
+    def marshal_load(f):
+        if isinstance(f, file):
+            return marshal.load(f)
+        return marshal.loads(f.read())
+
+
+bc_version = 2
+
+# magic version used to only change with new jinja versions.  With 2.6
+# we change this to also take Python version changes into account.  The
+# reason for this is that Python tends to segfault if fed earlier bytecode
+# versions because someone thought it would be a good idea to reuse opcodes
+# or make Python incompatible with earlier versions.
+bc_magic = 'j2'.encode('ascii') + \
+    pickle.dumps(bc_version, 2) + \
+    pickle.dumps((sys.version_info[0] << 24) | sys.version_info[1])
+
+
+class Bucket(object):
+    """Buckets are used to store the bytecode for one template.  It's created
+    and initialized by the bytecode cache and passed to the loading functions.
+
+    The buckets get an internal checksum from the cache assigned and use this
+    to automatically reject outdated cache material.  Individual bytecode
+    cache subclasses don't have to care about cache invalidation.
+    """
+
+    def __init__(self, environment, key, checksum):
+        self.environment = environment
+        self.key = key
+        self.checksum = checksum
+        self.reset()
+
+    def reset(self):
+        """Resets the bucket (unloads the bytecode)."""
+        self.code = None
+
+    def load_bytecode(self, f):
+        """Loads bytecode from a file or file like object."""
+        # make sure the magic header is correct
+        magic = f.read(len(bc_magic))
+        if magic != bc_magic:
+            self.reset()
+            return
+        # the source code of the file changed, we need to reload
+        checksum = pickle.load(f)
+        if self.checksum != checksum:
+            self.reset()
+            return
+        self.code = marshal_load(f)
+
+    def write_bytecode(self, f):
+        """Dump the bytecode into the file or file like object passed."""
+        if self.code is None:
+            raise TypeError('can\'t write empty bucket')
+        f.write(bc_magic)
+        pickle.dump(self.checksum, f, 2)
+        marshal_dump(self.code, f)
+
+    def bytecode_from_string(self, string):
+        """Load bytecode from a string."""
+        self.load_bytecode(BytesIO(string))
+
+    def bytecode_to_string(self):
+        """Return the bytecode as string."""
+        out = BytesIO()
+        self.write_bytecode(out)
+        return out.getvalue()
+
+
+class BytecodeCache(object):
+    """To implement your own bytecode cache you have to subclass this class
+    and override :meth:`load_bytecode` and :meth:`dump_bytecode`.  Both of
+    these methods are passed a :class:`~jinja2.bccache.Bucket`.
+
+    A very basic bytecode cache that saves the bytecode on the file system::
+
+        from os import path
+
+        class MyCache(BytecodeCache):
+
+            def __init__(self, directory):
+                self.directory = directory
+
+            def load_bytecode(self, bucket):
+                filename = path.join(self.directory, bucket.key)
+                if path.exists(filename):
+                    with open(filename, 'rb') as f:
+                        bucket.load_bytecode(f)
+
+            def dump_bytecode(self, bucket):
+                filename = path.join(self.directory, bucket.key)
+                with open(filename, 'wb') as f:
+                    bucket.write_bytecode(f)
+
+    A more advanced version of a filesystem based bytecode cache is part of
+    Jinja2.
+    """
+
+    def load_bytecode(self, bucket):
+        """Subclasses have to override this method to load bytecode into a
+        bucket.  If they are not able to find code in the cache for the
+        bucket, it must not do anything.
+        """
+        raise NotImplementedError()
+
+    def dump_bytecode(self, bucket):
+        """Subclasses have to override this method to write the bytecode
+        from a bucket back to the cache.  If it unable to do so it must not
+        fail silently but raise an exception.
+        """
+        raise NotImplementedError()
+
+    def clear(self):
+        """Clears the cache.  This method is not used by Jinja2 but should be
+        implemented to allow applications to clear the bytecode cache used
+        by a particular environment.
+        """
+
+    def get_cache_key(self, name, filename=None):
+        """Returns the unique hash key for this template name."""
+        hash = sha1(name.encode('utf-8'))
+        if filename is not None:
+            filename = '|' + filename
+            if isinstance(filename, unicode):
+                filename = filename.encode('utf-8')
+            hash.update(filename)
+        return hash.hexdigest()
+
+    def get_source_checksum(self, source):
+        """Returns a checksum for the source."""
+        return sha1(source.encode('utf-8')).hexdigest()
+
+    def get_bucket(self, environment, name, filename, source):
+        """Return a cache bucket for the given template.  All arguments are
+        mandatory but filename may be `None`.
+        """
+        key = self.get_cache_key(name, filename)
+        checksum = self.get_source_checksum(source)
+        bucket = Bucket(environment, key, checksum)
+        self.load_bytecode(bucket)
+        return bucket
+
+    def set_bucket(self, bucket):
+        """Put the bucket into the cache."""
+        self.dump_bytecode(bucket)
+
+
+class FileSystemBytecodeCache(BytecodeCache):
+    """A bytecode cache that stores bytecode on the filesystem.  It accepts
+    two arguments: The directory where the cache items are stored and a
+    pattern string that is used to build the filename.
+
+    If no directory is specified the system temporary items folder is used.
+
+    The pattern can be used to have multiple separate caches operate on the
+    same directory.  The default pattern is ``'__jinja2_%s.cache'``.  ``%s``
+    is replaced with the cache key.
+
+    >>> bcc = FileSystemBytecodeCache('/tmp/jinja_cache', '%s.cache')
+
+    This bytecode cache supports clearing of the cache using the clear method.
+    """
+
+    def __init__(self, directory=None, pattern='__jinja2_%s.cache'):
+        if directory is None:
+            directory = tempfile.gettempdir()
+        self.directory = directory
+        self.pattern = pattern
+
+    def _get_cache_filename(self, bucket):
+        return path.join(self.directory, self.pattern % bucket.key)
+
+    def load_bytecode(self, bucket):
+        f = open_if_exists(self._get_cache_filename(bucket), 'rb')
+        if f is not None:
+            try:
+                bucket.load_bytecode(f)
+            finally:
+                f.close()
+
+    def dump_bytecode(self, bucket):
+        f = open(self._get_cache_filename(bucket), 'wb')
+        try:
+            bucket.write_bytecode(f)
+        finally:
+            f.close()
+
+    def clear(self):
+        # imported lazily here because google app-engine doesn't support
+        # write access on the file system and the function does not exist
+        # normally.
+        from os import remove
+        files = fnmatch.filter(listdir(self.directory), self.pattern % '*')
+        for filename in files:
+            try:
+                remove(path.join(self.directory, filename))
+            except OSError:
+                pass
+
+
+class MemcachedBytecodeCache(BytecodeCache):
+    """This class implements a bytecode cache that uses a memcache cache for
+    storing the information.  It does not enforce a specific memcache library
+    (tummy's memcache or cmemcache) but will accept any class that provides
+    the minimal interface required.
+
+    Libraries compatible with this class:
+
+    -   `werkzeug <http://werkzeug.pocoo.org/>`_.contrib.cache
+    -   `python-memcached <http://www.tummy.com/Community/software/python-memcached/>`_
+    -   `cmemcache <http://gijsbert.org/cmemcache/>`_
+
+    (Unfortunately the django cache interface is not compatible because it
+    does not support storing binary data, only unicode.  You can however pass
+    the underlying cache client to the bytecode cache which is available
+    as `django.core.cache.cache._client`.)
+
+    The minimal interface for the client passed to the constructor is this:
+
+    .. class:: MinimalClientInterface
+
+        .. method:: set(key, value[, timeout])
+
+            Stores the bytecode in the cache.  `value` is a string and
+            `timeout` the timeout of the key.  If timeout is not provided
+            a default timeout or no timeout should be assumed, if it's
+            provided it's an integer with the number of seconds the cache
+            item should exist.
+
+        .. method:: get(key)
+
+            Returns the value for the cache key.  If the item does not
+            exist in the cache the return value must be `None`.
+
+    The other arguments to the constructor are the prefix for all keys that
+    is added before the actual cache key and the timeout for the bytecode in
+    the cache system.  We recommend a high (or no) timeout.
+
+    This bytecode cache does not support clearing of used items in the cache.
+    The clear method is a no-operation function.
+    """
+
+    def __init__(self, client, prefix='jinja2/bytecode/', timeout=None):
+        self.client = client
+        self.prefix = prefix
+        self.timeout = timeout
+
+    def load_bytecode(self, bucket):
+        code = self.client.get(self.prefix + bucket.key)
+        if code is not None:
+            bucket.bytecode_from_string(code)
+
+    def dump_bytecode(self, bucket):
+        args = (self.prefix + bucket.key, bucket.bytecode_to_string())
+        if self.timeout is not None:
+            args += (self.timeout,)
+        self.client.set(*args)
diff --git a/lib/jinja2/jinja2/compiler.py b/lib/jinja2/jinja2/compiler.py
new file mode 100644
index 0000000..b21cb38
--- /dev/null
+++ b/lib/jinja2/jinja2/compiler.py
@@ -0,0 +1,1649 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.compiler
+    ~~~~~~~~~~~~~~~
+
+    Compiles nodes into python code.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+from cStringIO import StringIO
+from itertools import chain
+from copy import deepcopy
+from jinja2 import nodes
+from jinja2.nodes import EvalContext
+from jinja2.visitor import NodeVisitor
+from jinja2.exceptions import TemplateAssertionError
+from jinja2.utils import Markup, concat, escape, is_python_keyword, next
+
+
+operators = {
+    'eq':       '==',
+    'ne':       '!=',
+    'gt':       '>',
+    'gteq':     '>=',
+    'lt':       '<',
+    'lteq':     '<=',
+    'in':       'in',
+    'notin':    'not in'
+}
+
+try:
+    exec '(0 if 0 else 0)'
+except SyntaxError:
+    have_condexpr = False
+else:
+    have_condexpr = True
+
+
+# what method to iterate over items do we want to use for dict iteration
+# in generated code?  on 2.x let's go with iteritems, on 3.x with items
+if hasattr(dict, 'iteritems'):
+    dict_item_iter = 'iteritems'
+else:
+    dict_item_iter = 'items'
+
+
+# does if 0: dummy(x) get us x into the scope?
+def unoptimize_before_dead_code():
+    x = 42
+    def f():
+        if 0: dummy(x)
+    return f
+unoptimize_before_dead_code = bool(unoptimize_before_dead_code().func_closure)
+
+
+def generate(node, environment, name, filename, stream=None,
+             defer_init=False):
+    """Generate the python source for a node tree."""
+    if not isinstance(node, nodes.Template):
+        raise TypeError('Can\'t compile non template nodes')
+    generator = CodeGenerator(environment, name, filename, stream, defer_init)
+    generator.visit(node)
+    if stream is None:
+        return generator.stream.getvalue()
+
+
+def has_safe_repr(value):
+    """Does the node have a safe representation?"""
+    if value is None or value is NotImplemented or value is Ellipsis:
+        return True
+    if isinstance(value, (bool, int, long, float, complex, basestring,
+                          xrange, Markup)):
+        return True
+    if isinstance(value, (tuple, list, set, frozenset)):
+        for item in value:
+            if not has_safe_repr(item):
+                return False
+        return True
+    elif isinstance(value, dict):
+        for key, value in value.iteritems():
+            if not has_safe_repr(key):
+                return False
+            if not has_safe_repr(value):
+                return False
+        return True
+    return False
+
+
+def find_undeclared(nodes, names):
+    """Check if the names passed are accessed undeclared.  The return value
+    is a set of all the undeclared names from the sequence of names found.
+    """
+    visitor = UndeclaredNameVisitor(names)
+    try:
+        for node in nodes:
+            visitor.visit(node)
+    except VisitorExit:
+        pass
+    return visitor.undeclared
+
+
+class Identifiers(object):
+    """Tracks the status of identifiers in frames."""
+
+    def __init__(self):
+        # variables that are known to be declared (probably from outer
+        # frames or because they are special for the frame)
+        self.declared = set()
+
+        # undeclared variables from outer scopes
+        self.outer_undeclared = set()
+
+        # names that are accessed without being explicitly declared by
+        # this one or any of the outer scopes.  Names can appear both in
+        # declared and undeclared.
+        self.undeclared = set()
+
+        # names that are declared locally
+        self.declared_locally = set()
+
+        # names that are declared by parameters
+        self.declared_parameter = set()
+
+    def add_special(self, name):
+        """Register a special name like `loop`."""
+        self.undeclared.discard(name)
+        self.declared.add(name)
+
+    def is_declared(self, name):
+        """Check if a name is declared in this or an outer scope."""
+        if name in self.declared_locally or name in self.declared_parameter:
+            return True
+        return name in self.declared
+
+    def copy(self):
+        return deepcopy(self)
+
+
+class Frame(object):
+    """Holds compile time information for us."""
+
+    def __init__(self, eval_ctx, parent=None):
+        self.eval_ctx = eval_ctx
+        self.identifiers = Identifiers()
+
+        # a toplevel frame is the root + soft frames such as if conditions.
+        self.toplevel = False
+
+        # the root frame is basically just the outermost frame, so no if
+        # conditions.  This information is used to optimize inheritance
+        # situations.
+        self.rootlevel = False
+
+        # in some dynamic inheritance situations the compiler needs to add
+        # write tests around output statements.
+        self.require_output_check = parent and parent.require_output_check
+
+        # inside some tags we are using a buffer rather than yield statements.
+        # this for example affects {% filter %} or {% macro %}.  If a frame
+        # is buffered this variable points to the name of the list used as
+        # buffer.
+        self.buffer = None
+
+        # the name of the block we're in, otherwise None.
+        self.block = parent and parent.block or None
+
+        # a set of actually assigned names
+        self.assigned_names = set()
+
+        # the parent of this frame
+        self.parent = parent
+
+        if parent is not None:
+            self.identifiers.declared.update(
+                parent.identifiers.declared |
+                parent.identifiers.declared_parameter |
+                parent.assigned_names
+            )
+            self.identifiers.outer_undeclared.update(
+                parent.identifiers.undeclared -
+                self.identifiers.declared
+            )
+            self.buffer = parent.buffer
+
+    def copy(self):
+        """Create a copy of the current one."""
+        rv = object.__new__(self.__class__)
+        rv.__dict__.update(self.__dict__)
+        rv.identifiers = object.__new__(self.identifiers.__class__)
+        rv.identifiers.__dict__.update(self.identifiers.__dict__)
+        return rv
+
+    def inspect(self, nodes):
+        """Walk the node and check for identifiers.  If the scope is hard (eg:
+        enforce on a python level) overrides from outer scopes are tracked
+        differently.
+        """
+        visitor = FrameIdentifierVisitor(self.identifiers)
+        for node in nodes:
+            visitor.visit(node)
+
+    def find_shadowed(self, extra=()):
+        """Find all the shadowed names.  extra is an iterable of variables
+        that may be defined with `add_special` which may occour scoped.
+        """
+        i = self.identifiers
+        return (i.declared | i.outer_undeclared) & \
+               (i.declared_locally | i.declared_parameter) | \
+               set(x for x in extra if i.is_declared(x))
+
+    def inner(self):
+        """Return an inner frame."""
+        return Frame(self.eval_ctx, self)
+
+    def soft(self):
+        """Return a soft frame.  A soft frame may not be modified as
+        standalone thing as it shares the resources with the frame it
+        was created of, but it's not a rootlevel frame any longer.
+        """
+        rv = self.copy()
+        rv.rootlevel = False
+        return rv
+
+    __copy__ = copy
+
+
+class VisitorExit(RuntimeError):
+    """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
+
+
+class DependencyFinderVisitor(NodeVisitor):
+    """A visitor that collects filter and test calls."""
+
+    def __init__(self):
+        self.filters = set()
+        self.tests = set()
+
+    def visit_Filter(self, node):
+        self.generic_visit(node)
+        self.filters.add(node.name)
+
+    def visit_Test(self, node):
+        self.generic_visit(node)
+        self.tests.add(node.name)
+
+    def visit_Block(self, node):
+        """Stop visiting at blocks."""
+
+
+class UndeclaredNameVisitor(NodeVisitor):
+    """A visitor that checks if a name is accessed without being
+    declared.  This is different from the frame visitor as it will
+    not stop at closure frames.
+    """
+
+    def __init__(self, names):
+        self.names = set(names)
+        self.undeclared = set()
+
+    def visit_Name(self, node):
+        if node.ctx == 'load' and node.name in self.names:
+            self.undeclared.add(node.name)
+            if self.undeclared == self.names:
+                raise VisitorExit()
+        else:
+            self.names.discard(node.name)
+
+    def visit_Block(self, node):
+        """Stop visiting a blocks."""
+
+
+class FrameIdentifierVisitor(NodeVisitor):
+    """A visitor for `Frame.inspect`."""
+
+    def __init__(self, identifiers):
+        self.identifiers = identifiers
+
+    def visit_Name(self, node):
+        """All assignments to names go through this function."""
+        if node.ctx == 'store':
+            self.identifiers.declared_locally.add(node.name)
+        elif node.ctx == 'param':
+            self.identifiers.declared_parameter.add(node.name)
+        elif node.ctx == 'load' and not \
+             self.identifiers.is_declared(node.name):
+            self.identifiers.undeclared.add(node.name)
+
+    def visit_If(self, node):
+        self.visit(node.test)
+        real_identifiers = self.identifiers
+
+        old_names = real_identifiers.declared_locally | \
+                    real_identifiers.declared_parameter
+
+        def inner_visit(nodes):
+            if not nodes:
+                return set()
+            self.identifiers = real_identifiers.copy()
+            for subnode in nodes:
+                self.visit(subnode)
+            rv = self.identifiers.declared_locally - old_names
+            # we have to remember the undeclared variables of this branch
+            # because we will have to pull them.
+            real_identifiers.undeclared.update(self.identifiers.undeclared)
+            self.identifiers = real_identifiers
+            return rv
+
+        body = inner_visit(node.body)
+        else_ = inner_visit(node.else_ or ())
+
+        # the differences between the two branches are also pulled as
+        # undeclared variables
+        real_identifiers.undeclared.update(body.symmetric_difference(else_) -
+                                           real_identifiers.declared)
+
+        # remember those that are declared.
+        real_identifiers.declared_locally.update(body | else_)
+
+    def visit_Macro(self, node):
+        self.identifiers.declared_locally.add(node.name)
+
+    def visit_Import(self, node):
+        self.generic_visit(node)
+        self.identifiers.declared_locally.add(node.target)
+
+    def visit_FromImport(self, node):
+        self.generic_visit(node)
+        for name in node.names:
+            if isinstance(name, tuple):
+                self.identifiers.declared_locally.add(name[1])
+            else:
+                self.identifiers.declared_locally.add(name)
+
+    def visit_Assign(self, node):
+        """Visit assignments in the correct order."""
+        self.visit(node.node)
+        self.visit(node.target)
+
+    def visit_For(self, node):
+        """Visiting stops at for blocks.  However the block sequence
+        is visited as part of the outer scope.
+        """
+        self.visit(node.iter)
+
+    def visit_CallBlock(self, node):
+        self.visit(node.call)
+
+    def visit_FilterBlock(self, node):
+        self.visit(node.filter)
+
+    def visit_Scope(self, node):
+        """Stop visiting at scopes."""
+
+    def visit_Block(self, node):
+        """Stop visiting at blocks."""
+
+
+class CompilerExit(Exception):
+    """Raised if the compiler encountered a situation where it just
+    doesn't make sense to further process the code.  Any block that
+    raises such an exception is not further processed.
+    """
+
+
+class CodeGenerator(NodeVisitor):
+
+    def __init__(self, environment, name, filename, stream=None,
+                 defer_init=False):
+        if stream is None:
+            stream = StringIO()
+        self.environment = environment
+        self.name = name
+        self.filename = filename
+        self.stream = stream
+        self.created_block_context = False
+        self.defer_init = defer_init
+
+        # aliases for imports
+        self.import_aliases = {}
+
+        # a registry for all blocks.  Because blocks are moved out
+        # into the global python scope they are registered here
+        self.blocks = {}
+
+        # the number of extends statements so far
+        self.extends_so_far = 0
+
+        # some templates have a rootlevel extends.  In this case we
+        # can safely assume that we're a child template and do some
+        # more optimizations.
+        self.has_known_extends = False
+
+        # the current line number
+        self.code_lineno = 1
+
+        # registry of all filters and tests (global, not block local)
+        self.tests = {}
+        self.filters = {}
+
+        # the debug information
+        self.debug_info = []
+        self._write_debug_info = None
+
+        # the number of new lines before the next write()
+        self._new_lines = 0
+
+        # the line number of the last written statement
+        self._last_line = 0
+
+        # true if nothing was written so far.
+        self._first_write = True
+
+        # used by the `temporary_identifier` method to get new
+        # unique, temporary identifier
+        self._last_identifier = 0
+
+        # the current indentation
+        self._indentation = 0
+
+    # -- Various compilation helpers
+
+    def fail(self, msg, lineno):
+        """Fail with a :exc:`TemplateAssertionError`."""
+        raise TemplateAssertionError(msg, lineno, self.name, self.filename)
+
+    def temporary_identifier(self):
+        """Get a new unique identifier."""
+        self._last_identifier += 1
+        return 't_%d' % self._last_identifier
+
+    def buffer(self, frame):
+        """Enable buffering for the frame from that point onwards."""
+        frame.buffer = self.temporary_identifier()
+        self.writeline('%s = []' % frame.buffer)
+
+    def return_buffer_contents(self, frame):
+        """Return the buffer contents of the frame."""
+        if frame.eval_ctx.volatile:
+            self.writeline('if context.eval_ctx.autoescape:')
+            self.indent()
+            self.writeline('return Markup(concat(%s))' % frame.buffer)
+            self.outdent()
+            self.writeline('else:')
+            self.indent()
+            self.writeline('return concat(%s)' % frame.buffer)
+            self.outdent()
+        elif frame.eval_ctx.autoescape:
+            self.writeline('return Markup(concat(%s))' % frame.buffer)
+        else:
+            self.writeline('return concat(%s)' % frame.buffer)
+
+    def indent(self):
+        """Indent by one."""
+        self._indentation += 1
+
+    def outdent(self, step=1):
+        """Outdent by step."""
+        self._indentation -= step
+
+    def start_write(self, frame, node=None):
+        """Yield or write into the frame buffer."""
+        if frame.buffer is None:
+            self.writeline('yield ', node)
+        else:
+            self.writeline('%s.append(' % frame.buffer, node)
+
+    def end_write(self, frame):
+        """End the writing process started by `start_write`."""
+        if frame.buffer is not None:
+            self.write(')')
+
+    def simple_write(self, s, frame, node=None):
+        """Simple shortcut for start_write + write + end_write."""
+        self.start_write(frame, node)
+        self.write(s)
+        self.end_write(frame)
+
+    def blockvisit(self, nodes, frame):
+        """Visit a list of nodes as block in a frame.  If the current frame
+        is no buffer a dummy ``if 0: yield None`` is written automatically
+        unless the force_generator parameter is set to False.
+        """
+        if frame.buffer is None:
+            self.writeline('if 0: yield None')
+        else:
+            self.writeline('pass')
+        try:
+            for node in nodes:
+                self.visit(node, frame)
+        except CompilerExit:
+            pass
+
+    def write(self, x):
+        """Write a string into the output stream."""
+        if self._new_lines:
+            if not self._first_write:
+                self.stream.write('\n' * self._new_lines)
+                self.code_lineno += self._new_lines
+                if self._write_debug_info is not None:
+                    self.debug_info.append((self._write_debug_info,
+                                            self.code_lineno))
+                    self._write_debug_info = None
+            self._first_write = False
+            self.stream.write('    ' * self._indentation)
+            self._new_lines = 0
+        self.stream.write(x)
+
+    def writeline(self, x, node=None, extra=0):
+        """Combination of newline and write."""
+        self.newline(node, extra)
+        self.write(x)
+
+    def newline(self, node=None, extra=0):
+        """Add one or more newlines before the next write."""
+        self._new_lines = max(self._new_lines, 1 + extra)
+        if node is not None and node.lineno != self._last_line:
+            self._write_debug_info = node.lineno
+            self._last_line = node.lineno
+
+    def signature(self, node, frame, extra_kwargs=None):
+        """Writes a function call to the stream for the current node.
+        A leading comma is added automatically.  The extra keyword
+        arguments may not include python keywords otherwise a syntax
+        error could occour.  The extra keyword arguments should be given
+        as python dict.
+        """
+        # if any of the given keyword arguments is a python keyword
+        # we have to make sure that no invalid call is created.
+        kwarg_workaround = False
+        for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
+            if is_python_keyword(kwarg):
+                kwarg_workaround = True
+                break
+
+        for arg in node.args:
+            self.write(', ')
+            self.visit(arg, frame)
+
+        if not kwarg_workaround:
+            for kwarg in node.kwargs:
+                self.write(', ')
+                self.visit(kwarg, frame)
+            if extra_kwargs is not None:
+                for key, value in extra_kwargs.iteritems():
+                    self.write(', %s=%s' % (key, value))
+        if node.dyn_args:
+            self.write(', *')
+            self.visit(node.dyn_args, frame)
+
+        if kwarg_workaround:
+            if node.dyn_kwargs is not None:
+                self.write(', **dict({')
+            else:
+                self.write(', **{')
+            for kwarg in node.kwargs:
+                self.write('%r: ' % kwarg.key)
+                self.visit(kwarg.value, frame)
+                self.write(', ')
+            if extra_kwargs is not None:
+                for key, value in extra_kwargs.iteritems():
+                    self.write('%r: %s, ' % (key, value))
+            if node.dyn_kwargs is not None:
+                self.write('}, **')
+                self.visit(node.dyn_kwargs, frame)
+                self.write(')')
+            else:
+                self.write('}')
+
+        elif node.dyn_kwargs is not None:
+            self.write(', **')
+            self.visit(node.dyn_kwargs, frame)
+
+    def pull_locals(self, frame):
+        """Pull all the references identifiers into the local scope."""
+        for name in frame.identifiers.undeclared:
+            self.writeline('l_%s = context.resolve(%r)' % (name, name))
+
+    def pull_dependencies(self, nodes):
+        """Pull all the dependencies."""
+        visitor = DependencyFinderVisitor()
+        for node in nodes:
+            visitor.visit(node)
+        for dependency in 'filters', 'tests':
+            mapping = getattr(self, dependency)
+            for name in getattr(visitor, dependency):
+                if name not in mapping:
+                    mapping[name] = self.temporary_identifier()
+                self.writeline('%s = environment.%s[%r]' %
+                               (mapping[name], dependency, name))
+
+    def unoptimize_scope(self, frame):
+        """Disable Python optimizations for the frame."""
+        # XXX: this is not that nice but it has no real overhead.  It
+        # mainly works because python finds the locals before dead code
+        # is removed.  If that breaks we have to add a dummy function
+        # that just accepts the arguments and does nothing.
+        if frame.identifiers.declared:
+            self.writeline('%sdummy(%s)' % (
+                unoptimize_before_dead_code and 'if 0: ' or '',
+                ', '.join('l_' + name for name in frame.identifiers.declared)
+            ))
+
+    def push_scope(self, frame, extra_vars=()):
+        """This function returns all the shadowed variables in a dict
+        in the form name: alias and will write the required assignments
+        into the current scope.  No indentation takes place.
+
+        This also predefines locally declared variables from the loop
+        body because under some circumstances it may be the case that
+
+        `extra_vars` is passed to `Frame.find_shadowed`.
+        """
+        aliases = {}
+        for name in frame.find_shadowed(extra_vars):
+            aliases[name] = ident = self.temporary_identifier()
+            self.writeline('%s = l_%s' % (ident, name))
+        to_declare = set()
+        for name in frame.identifiers.declared_locally:
+            if name not in aliases:
+                to_declare.add('l_' + name)
+        if to_declare:
+            self.writeline(' = '.join(to_declare) + ' = missing')
+        return aliases
+
+    def pop_scope(self, aliases, frame):
+        """Restore all aliases and delete unused variables."""
+        for name, alias in aliases.iteritems():
+            self.writeline('l_%s = %s' % (name, alias))
+        to_delete = set()
+        for name in frame.identifiers.declared_locally:
+            if name not in aliases:
+                to_delete.add('l_' + name)
+        if to_delete:
+            # we cannot use the del statement here because enclosed
+            # scopes can trigger a SyntaxError:
+            #   a = 42; b = lambda: a; del a
+            self.writeline(' = '.join(to_delete) + ' = missing')
+
+    def function_scoping(self, node, frame, children=None,
+                         find_special=True):
+        """In Jinja a few statements require the help of anonymous
+        functions.  Those are currently macros and call blocks and in
+        the future also recursive loops.  As there is currently
+        technical limitation that doesn't allow reading and writing a
+        variable in a scope where the initial value is coming from an
+        outer scope, this function tries to fall back with a common
+        error message.  Additionally the frame passed is modified so
+        that the argumetns are collected and callers are looked up.
+
+        This will return the modified frame.
+        """
+        # we have to iterate twice over it, make sure that works
+        if children is None:
+            children = node.iter_child_nodes()
+        children = list(children)
+        func_frame = frame.inner()
+        func_frame.inspect(children)
+
+        # variables that are undeclared (accessed before declaration) and
+        # declared locally *and* part of an outside scope raise a template
+        # assertion error. Reason: we can't generate reasonable code from
+        # it without aliasing all the variables.
+        # this could be fixed in Python 3 where we have the nonlocal
+        # keyword or if we switch to bytecode generation
+        overriden_closure_vars = (
+            func_frame.identifiers.undeclared &
+            func_frame.identifiers.declared &
+            (func_frame.identifiers.declared_locally |
+             func_frame.identifiers.declared_parameter)
+        )
+        if overriden_closure_vars:
+            self.fail('It\'s not possible to set and access variables '
+                      'derived from an outer scope! (affects: %s)' %
+                      ', '.join(sorted(overriden_closure_vars)), node.lineno)
+
+        # remove variables from a closure from the frame's undeclared
+        # identifiers.
+        func_frame.identifiers.undeclared -= (
+            func_frame.identifiers.undeclared &
+            func_frame.identifiers.declared
+        )
+
+        # no special variables for this scope, abort early
+        if not find_special:
+            return func_frame
+
+        func_frame.accesses_kwargs = False
+        func_frame.accesses_varargs = False
+        func_frame.accesses_caller = False
+        func_frame.arguments = args = ['l_' + x.name for x in node.args]
+
+        undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
+
+        if 'caller' in undeclared:
+            func_frame.accesses_caller = True
+            func_frame.identifiers.add_special('caller')
+            args.append('l_caller')
+        if 'kwargs' in undeclared:
+            func_frame.accesses_kwargs = True
+            func_frame.identifiers.add_special('kwargs')
+            args.append('l_kwargs')
+        if 'varargs' in undeclared:
+            func_frame.accesses_varargs = True
+            func_frame.identifiers.add_special('varargs')
+            args.append('l_varargs')
+        return func_frame
+
+    def macro_body(self, node, frame, children=None):
+        """Dump the function def of a macro or call block."""
+        frame = self.function_scoping(node, frame, children)
+        # macros are delayed, they never require output checks
+        frame.require_output_check = False
+        args = frame.arguments
+        # XXX: this is an ugly fix for the loop nesting bug
+        # (tests.test_old_bugs.test_loop_call_bug).  This works around
+        # a identifier nesting problem we have in general.  It's just more
+        # likely to happen in loops which is why we work around it.  The
+        # real solution would be "nonlocal" all the identifiers that are
+        # leaking into a new python frame and might be used both unassigned
+        # and assigned.
+        if 'loop' in frame.identifiers.declared:
+            args = args + ['l_loop=l_loop']
+        self.writeline('def macro(%s):' % ', '.join(args), node)
+        self.indent()
+        self.buffer(frame)
+        self.pull_locals(frame)
+        self.blockvisit(node.body, frame)
+        self.return_buffer_contents(frame)
+        self.outdent()
+        return frame
+
+    def macro_def(self, node, frame):
+        """Dump the macro definition for the def created by macro_body."""
+        arg_tuple = ', '.join(repr(x.name) for x in node.args)
+        name = getattr(node, 'name', None)
+        if len(node.args) == 1:
+            arg_tuple += ','
+        self.write('Macro(environment, macro, %r, (%s), (' %
+                   (name, arg_tuple))
+        for arg in node.defaults:
+            self.visit(arg, frame)
+            self.write(', ')
+        self.write('), %r, %r, %r)' % (
+            bool(frame.accesses_kwargs),
+            bool(frame.accesses_varargs),
+            bool(frame.accesses_caller)
+        ))
+
+    def position(self, node):
+        """Return a human readable position for the node."""
+        rv = 'line %d' % node.lineno
+        if self.name is not None:
+            rv += ' in ' + repr(self.name)
+        return rv
+
+    # -- Statement Visitors
+
+    def visit_Template(self, node, frame=None):
+        assert frame is None, 'no root frame allowed'
+        eval_ctx = EvalContext(self.environment, self.name)
+
+        from jinja2.runtime import __all__ as exported
+        self.writeline('from __future__ import division')
+        self.writeline('from jinja2.runtime import ' + ', '.join(exported))
+        if not unoptimize_before_dead_code:
+            self.writeline('dummy = lambda *x: None')
+
+        # if we want a deferred initialization we cannot move the
+        # environment into a local name
+        envenv = not self.defer_init and ', environment=environment' or ''
+
+        # do we have an extends tag at all?  If not, we can save some
+        # overhead by just not processing any inheritance code.
+        have_extends = node.find(nodes.Extends) is not None
+
+        # find all blocks
+        for block in node.find_all(nodes.Block):
+            if block.name in self.blocks:
+                self.fail('block %r defined twice' % block.name, block.lineno)
+            self.blocks[block.name] = block
+
+        # find all imports and import them
+        for import_ in node.find_all(nodes.ImportedName):
+            if import_.importname not in self.import_aliases:
+                imp = import_.importname
+                self.import_aliases[imp] = alias = self.temporary_identifier()
+                if '.' in imp:
+                    module, obj = imp.rsplit('.', 1)
+                    self.writeline('from %s import %s as %s' %
+                                   (module, obj, alias))
+                else:
+                    self.writeline('import %s as %s' % (imp, alias))
+
+        # add the load name
+        self.writeline('name = %r' % self.name)
+
+        # generate the root render function.
+        self.writeline('def root(context%s):' % envenv, extra=1)
+
+        # process the root
+        frame = Frame(eval_ctx)
+        frame.inspect(node.body)
+        frame.toplevel = frame.rootlevel = True
+        frame.require_output_check = have_extends and not self.has_known_extends
+        self.indent()
+        if have_extends:
+            self.writeline('parent_template = None')
+        if 'self' in find_undeclared(node.body, ('self',)):
+            frame.identifiers.add_special('self')
+            self.writeline('l_self = TemplateReference(context)')
+        self.pull_locals(frame)
+        self.pull_dependencies(node.body)
+        self.blockvisit(node.body, frame)
+        self.outdent()
+
+        # make sure that the parent root is called.
+        if have_extends:
+            if not self.has_known_extends:
+                self.indent()
+                self.writeline('if parent_template is not None:')
+            self.indent()
+            self.writeline('for event in parent_template.'
+                           'root_render_func(context):')
+            self.indent()
+            self.writeline('yield event')
+            self.outdent(2 + (not self.has_known_extends))
+
+        # at this point we now have the blocks collected and can visit them too.
+        for name, block in self.blocks.iteritems():
+            block_frame = Frame(eval_ctx)
+            block_frame.inspect(block.body)
+            block_frame.block = name
+            self.writeline('def block_%s(context%s):' % (name, envenv),
+                           block, 1)
+            self.indent()
+            undeclared = find_undeclared(block.body, ('self', 'super'))
+            if 'self' in undeclared:
+                block_frame.identifiers.add_special('self')
+                self.writeline('l_self = TemplateReference(context)')
+            if 'super' in undeclared:
+                block_frame.identifiers.add_special('super')
+                self.writeline('l_super = context.super(%r, '
+                               'block_%s)' % (name, name))
+            self.pull_locals(block_frame)
+            self.pull_dependencies(block.body)
+            self.blockvisit(block.body, block_frame)
+            self.outdent()
+
+        self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
+                                                   for x in self.blocks),
+                       extra=1)
+
+        # add a function that returns the debug info
+        self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
+                                                    in self.debug_info))
+
+    def visit_Block(self, node, frame):
+        """Call a block and register it for the template."""
+        level = 1
+        if frame.toplevel:
+            # if we know that we are a child template, there is no need to
+            # check if we are one
+            if self.has_known_extends:
+                return
+            if self.extends_so_far > 0:
+                self.writeline('if parent_template is None:')
+                self.indent()
+                level += 1
+        context = node.scoped and 'context.derived(locals())' or 'context'
+        self.writeline('for event in context.blocks[%r][0](%s):' % (
+                       node.name, context), node)
+        self.indent()
+        self.simple_write('event', frame)
+        self.outdent(level)
+
+    def visit_Extends(self, node, frame):
+        """Calls the extender."""
+        if not frame.toplevel:
+            self.fail('cannot use extend from a non top-level scope',
+                      node.lineno)
+
+        # if the number of extends statements in general is zero so
+        # far, we don't have to add a check if something extended
+        # the template before this one.
+        if self.extends_so_far > 0:
+
+            # if we have a known extends we just add a template runtime
+            # error into the generated code.  We could catch that at compile
+            # time too, but i welcome it not to confuse users by throwing the
+            # same error at different times just "because we can".
+            if not self.has_known_extends:
+                self.writeline('if parent_template is not None:')
+                self.indent()
+            self.writeline('raise TemplateRuntimeError(%r)' %
+                           'extended multiple times')
+            self.outdent()
+
+            # if we have a known extends already we don't need that code here
+            # as we know that the template execution will end here.
+            if self.has_known_extends:
+                raise CompilerExit()
+
+        self.writeline('parent_template = environment.get_template(', node)
+        self.visit(node.template, frame)
+        self.write(', %r)' % self.name)
+        self.writeline('for name, parent_block in parent_template.'
+                       'blocks.%s():' % dict_item_iter)
+        self.indent()
+        self.writeline('context.blocks.setdefault(name, []).'
+                       'append(parent_block)')
+        self.outdent()
+
+        # if this extends statement was in the root level we can take
+        # advantage of that information and simplify the generated code
+        # in the top level from this point onwards
+        if frame.rootlevel:
+            self.has_known_extends = True
+
+        # and now we have one more
+        self.extends_so_far += 1
+
+    def visit_Include(self, node, frame):
+        """Handles includes."""
+        if node.with_context:
+            self.unoptimize_scope(frame)
+        if node.ignore_missing:
+            self.writeline('try:')
+            self.indent()
+
+        func_name = 'get_or_select_template'
+        if isinstance(node.template, nodes.Const):
+            if isinstance(node.template.value, basestring):
+                func_name = 'get_template'
+            elif isinstance(node.template.value, (tuple, list)):
+                func_name = 'select_template'
+        elif isinstance(node.template, (nodes.Tuple, nodes.List)):
+            func_name = 'select_template'
+
+        self.writeline('template = environment.%s(' % func_name, node)
+        self.visit(node.template, frame)
+        self.write(', %r)' % self.name)
+        if node.ignore_missing:
+            self.outdent()
+            self.writeline('except TemplateNotFound:')
+            self.indent()
+            self.writeline('pass')
+            self.outdent()
+            self.writeline('else:')
+            self.indent()
+
+        if node.with_context:
+            self.writeline('for event in template.root_render_func('
+                           'template.new_context(context.parent, True, '
+                           'locals())):')
+        else:
+            self.writeline('for event in template.module._body_stream:')
+
+        self.indent()
+        self.simple_write('event', frame)
+        self.outdent()
+
+        if node.ignore_missing:
+            self.outdent()
+
+    def visit_Import(self, node, frame):
+        """Visit regular imports."""
+        if node.with_context:
+            self.unoptimize_scope(frame)
+        self.writeline('l_%s = ' % node.target, node)
+        if frame.toplevel:
+            self.write('context.vars[%r] = ' % node.target)
+        self.write('environment.get_template(')
+        self.visit(node.template, frame)
+        self.write(', %r).' % self.name)
+        if node.with_context:
+            self.write('make_module(context.parent, True, locals())')
+        else:
+            self.write('module')
+        if frame.toplevel and not node.target.startswith('_'):
+            self.writeline('context.exported_vars.discard(%r)' % node.target)
+        frame.assigned_names.add(node.target)
+
+    def visit_FromImport(self, node, frame):
+        """Visit named imports."""
+        self.newline(node)
+        self.write('included_template = environment.get_template(')
+        self.visit(node.template, frame)
+        self.write(', %r).' % self.name)
+        if node.with_context:
+            self.write('make_module(context.parent, True)')
+        else:
+            self.write('module')
+
+        var_names = []
+        discarded_names = []
+        for name in node.names:
+            if isinstance(name, tuple):
+                name, alias = name
+            else:
+                alias = name
+            self.writeline('l_%s = getattr(included_template, '
+                           '%r, missing)' % (alias, name))
+            self.writeline('if l_%s is missing:' % alias)
+            self.indent()
+            self.writeline('l_%s = environment.undefined(%r %% '
+                           'included_template.__name__, '
+                           'name=%r)' %
+                           (alias, 'the template %%r (imported on %s) does '
+                           'not export the requested name %s' % (
+                                self.position(node),
+                                repr(name)
+                           ), name))
+            self.outdent()
+            if frame.toplevel:
+                var_names.append(alias)
+                if not alias.startswith('_'):
+                    discarded_names.append(alias)
+            frame.assigned_names.add(alias)
+
+        if var_names:
+            if len(var_names) == 1:
+                name = var_names[0]
+                self.writeline('context.vars[%r] = l_%s' % (name, name))
+            else:
+                self.writeline('context.vars.update({%s})' % ', '.join(
+                    '%r: l_%s' % (name, name) for name in var_names
+                ))
+        if discarded_names:
+            if len(discarded_names) == 1:
+                self.writeline('context.exported_vars.discard(%r)' %
+                               discarded_names[0])
+            else:
+                self.writeline('context.exported_vars.difference_'
+                               'update((%s))' % ', '.join(map(repr, discarded_names)))
+
+    def visit_For(self, node, frame):
+        # when calculating the nodes for the inner frame we have to exclude
+        # the iterator contents from it
+        children = node.iter_child_nodes(exclude=('iter',))
+        if node.recursive:
+            loop_frame = self.function_scoping(node, frame, children,
+                                               find_special=False)
+        else:
+            loop_frame = frame.inner()
+            loop_frame.inspect(children)
+
+        # try to figure out if we have an extended loop.  An extended loop
+        # is necessary if the loop is in recursive mode if the special loop
+        # variable is accessed in the body.
+        extended_loop = node.recursive or 'loop' in \
+                        find_undeclared(node.iter_child_nodes(
+                            only=('body',)), ('loop',))
+
+        # if we don't have an recursive loop we have to find the shadowed
+        # variables at that point.  Because loops can be nested but the loop
+        # variable is a special one we have to enforce aliasing for it.
+        if not node.recursive:
+            aliases = self.push_scope(loop_frame, ('loop',))
+
+        # otherwise we set up a buffer and add a function def
+        else:
+            self.writeline('def loop(reciter, loop_render_func):', node)
+            self.indent()
+            self.buffer(loop_frame)
+            aliases = {}
+
+        # make sure the loop variable is a special one and raise a template
+        # assertion error if a loop tries to write to loop
+        if extended_loop:
+            loop_frame.identifiers.add_special('loop')
+        for name in node.find_all(nodes.Name):
+            if name.ctx == 'store' and name.name == 'loop':
+                self.fail('Can\'t assign to special loop variable '
+                          'in for-loop target', name.lineno)
+
+        self.pull_locals(loop_frame)
+        if node.else_:
+            iteration_indicator = self.temporary_identifier()
+            self.writeline('%s = 1' % iteration_indicator)
+
+        # Create a fake parent loop if the else or test section of a
+        # loop is accessing the special loop variable and no parent loop
+        # exists.
+        if 'loop' not in aliases and 'loop' in find_undeclared(
+           node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
+            self.writeline("l_loop = environment.undefined(%r, name='loop')" %
+                ("'loop' is undefined. the filter section of a loop as well "
+                 "as the else block don't have access to the special 'loop'"
+                 " variable of the current loop.  Because there is no parent "
+                 "loop it's undefined.  Happened in loop on %s" %
+                 self.position(node)))
+
+        self.writeline('for ', node)
+        self.visit(node.target, loop_frame)
+        self.write(extended_loop and ', l_loop in LoopContext(' or ' in ')
+
+        # if we have an extened loop and a node test, we filter in the
+        # "outer frame".
+        if extended_loop and node.test is not None:
+            self.write('(')
+            self.visit(node.target, loop_frame)
+            self.write(' for ')
+            self.visit(node.target, loop_frame)
+            self.write(' in ')
+            if node.recursive:
+                self.write('reciter')
+            else:
+                self.visit(node.iter, loop_frame)
+            self.write(' if (')
+            test_frame = loop_frame.copy()
+            self.visit(node.test, test_frame)
+            self.write('))')
+
+        elif node.recursive:
+            self.write('reciter')
+        else:
+            self.visit(node.iter, loop_frame)
+
+        if node.recursive:
+            self.write(', recurse=loop_render_func):')
+        else:
+            self.write(extended_loop and '):' or ':')
+
+        # tests in not extended loops become a continue
+        if not extended_loop and node.test is not None:
+            self.indent()
+            self.writeline('if not ')
+            self.visit(node.test, loop_frame)
+            self.write(':')
+            self.indent()
+            self.writeline('continue')
+            self.outdent(2)
+
+        self.indent()
+        self.blockvisit(node.body, loop_frame)
+        if node.else_:
+            self.writeline('%s = 0' % iteration_indicator)
+        self.outdent()
+
+        if node.else_:
+            self.writeline('if %s:' % iteration_indicator)
+            self.indent()
+            self.blockvisit(node.else_, loop_frame)
+            self.outdent()
+
+        # reset the aliases if there are any.
+        if not node.recursive:
+            self.pop_scope(aliases, loop_frame)
+
+        # if the node was recursive we have to return the buffer contents
+        # and start the iteration code
+        if node.recursive:
+            self.return_buffer_contents(loop_frame)
+            self.outdent()
+            self.start_write(frame, node)
+            self.write('loop(')
+            self.visit(node.iter, frame)
+            self.write(', loop)')
+            self.end_write(frame)
+
+    def visit_If(self, node, frame):
+        if_frame = frame.soft()
+        self.writeline('if ', node)
+        self.visit(node.test, if_frame)
+        self.write(':')
+        self.indent()
+        self.blockvisit(node.body, if_frame)
+        self.outdent()
+        if node.else_:
+            self.writeline('else:')
+            self.indent()
+            self.blockvisit(node.else_, if_frame)
+            self.outdent()
+
+    def visit_Macro(self, node, frame):
+        macro_frame = self.macro_body(node, frame)
+        self.newline()
+        if frame.toplevel:
+            if not node.name.startswith('_'):
+                self.write('context.exported_vars.add(%r)' % node.name)
+            self.writeline('context.vars[%r] = ' % node.name)
+        self.write('l_%s = ' % node.name)
+        self.macro_def(node, macro_frame)
+        frame.assigned_names.add(node.name)
+
+    def visit_CallBlock(self, node, frame):
+        children = node.iter_child_nodes(exclude=('call',))
+        call_frame = self.macro_body(node, frame, children)
+        self.writeline('caller = ')
+        self.macro_def(node, call_frame)
+        self.start_write(frame, node)
+        self.visit_Call(node.call, call_frame, forward_caller=True)
+        self.end_write(frame)
+
+    def visit_FilterBlock(self, node, frame):
+        filter_frame = frame.inner()
+        filter_frame.inspect(node.iter_child_nodes())
+        aliases = self.push_scope(filter_frame)
+        self.pull_locals(filter_frame)
+        self.buffer(filter_frame)
+        self.blockvisit(node.body, filter_frame)
+        self.start_write(frame, node)
+        self.visit_Filter(node.filter, filter_frame)
+        self.end_write(frame)
+        self.pop_scope(aliases, filter_frame)
+
+    def visit_ExprStmt(self, node, frame):
+        self.newline(node)
+        self.visit(node.node, frame)
+
+    def visit_Output(self, node, frame):
+        # if we have a known extends statement, we don't output anything
+        # if we are in a require_output_check section
+        if self.has_known_extends and frame.require_output_check:
+            return
+
+        if self.environment.finalize:
+            finalize = lambda x: unicode(self.environment.finalize(x))
+        else:
+            finalize = unicode
+
+        # if we are inside a frame that requires output checking, we do so
+        outdent_later = False
+        if frame.require_output_check:
+            self.writeline('if parent_template is None:')
+            self.indent()
+            outdent_later = True
+
+        # try to evaluate as many chunks as possible into a static
+        # string at compile time.
+        body = []
+        for child in node.nodes:
+            try:
+                const = child.as_const(frame.eval_ctx)
+            except nodes.Impossible:
+                body.append(child)
+                continue
+            # the frame can't be volatile here, becaus otherwise the
+            # as_const() function would raise an Impossible exception
+            # at that point.
+            try:
+                if frame.eval_ctx.autoescape:
+                    if hasattr(const, '__html__'):
+                        const = const.__html__()
+                    else:
+                        const = escape(const)
+                const = finalize(const)
+            except Exception:
+                # if something goes wrong here we evaluate the node
+                # at runtime for easier debugging
+                body.append(child)
+                continue
+            if body and isinstance(body[-1], list):
+                body[-1].append(const)
+            else:
+                body.append([const])
+
+        # if we have less than 3 nodes or a buffer we yield or extend/append
+        if len(body) < 3 or frame.buffer is not None:
+            if frame.buffer is not None:
+                # for one item we append, for more we extend
+                if len(body) == 1:
+                    self.writeline('%s.append(' % frame.buffer)
+                else:
+                    self.writeline('%s.extend((' % frame.buffer)
+                self.indent()
+            for item in body:
+                if isinstance(item, list):
+                    val = repr(concat(item))
+                    if frame.buffer is None:
+                        self.writeline('yield ' + val)
+                    else:
+                        self.writeline(val + ', ')
+                else:
+                    if frame.buffer is None:
+                        self.writeline('yield ', item)
+                    else:
+                        self.newline(item)
+                    close = 1
+                    if frame.eval_ctx.volatile:
+                        self.write('(context.eval_ctx.autoescape and'
+                                   ' escape or to_string)(')
+                    elif frame.eval_ctx.autoescape:
+                        self.write('escape(')
+                    else:
+                        self.write('to_string(')
+                    if self.environment.finalize is not None:
+                        self.write('environment.finalize(')
+                        close += 1
+                    self.visit(item, frame)
+                    self.write(')' * close)
+                    if frame.buffer is not None:
+                        self.write(', ')
+            if frame.buffer is not None:
+                # close the open parentheses
+                self.outdent()
+                self.writeline(len(body) == 1 and ')' or '))')
+
+        # otherwise we create a format string as this is faster in that case
+        else:
+            format = []
+            arguments = []
+            for item in body:
+                if isinstance(item, list):
+                    format.append(concat(item).replace('%', '%%'))
+                else:
+                    format.append('%s')
+                    arguments.append(item)
+            self.writeline('yield ')
+            self.write(repr(concat(format)) + ' % (')
+            idx = -1
+            self.indent()
+            for argument in arguments:
+                self.newline(argument)
+                close = 0
+                if frame.eval_ctx.volatile:
+                    self.write('(context.eval_ctx.autoescape and'
+                               ' escape or to_string)(')
+                    close += 1
+                elif frame.eval_ctx.autoescape:
+                    self.write('escape(')
+                    close += 1
+                if self.environment.finalize is not None:
+                    self.write('environment.finalize(')
+                    close += 1
+                self.visit(argument, frame)
+                self.write(')' * close + ', ')
+            self.outdent()
+            self.writeline(')')
+
+        if outdent_later:
+            self.outdent()
+
+    def visit_Assign(self, node, frame):
+        self.newline(node)
+        # toplevel assignments however go into the local namespace and
+        # the current template's context.  We create a copy of the frame
+        # here and add a set so that the Name visitor can add the assigned
+        # names here.
+        if frame.toplevel:
+            assignment_frame = frame.copy()
+            assignment_frame.toplevel_assignments = set()
+        else:
+            assignment_frame = frame
+        self.visit(node.target, assignment_frame)
+        self.write(' = ')
+        self.visit(node.node, frame)
+
+        # make sure toplevel assignments are added to the context.
+        if frame.toplevel:
+            public_names = [x for x in assignment_frame.toplevel_assignments
+                            if not x.startswith('_')]
+            if len(assignment_frame.toplevel_assignments) == 1:
+                name = next(iter(assignment_frame.toplevel_assignments))
+                self.writeline('context.vars[%r] = l_%s' % (name, name))
+            else:
+                self.writeline('context.vars.update({')
+                for idx, name in enumerate(assignment_frame.toplevel_assignments):
+                    if idx:
+                        self.write(', ')
+                    self.write('%r: l_%s' % (name, name))
+                self.write('})')
+            if public_names:
+                if len(public_names) == 1:
+                    self.writeline('context.exported_vars.add(%r)' %
+                                   public_names[0])
+                else:
+                    self.writeline('context.exported_vars.update((%s))' %
+                                   ', '.join(map(repr, public_names)))
+
+    # -- Expression Visitors
+
+    def visit_Name(self, node, frame):
+        if node.ctx == 'store' and frame.toplevel:
+            frame.toplevel_assignments.add(node.name)
+        self.write('l_' + node.name)
+        frame.assigned_names.add(node.name)
+
+    def visit_Const(self, node, frame):
+        val = node.value
+        if isinstance(val, float):
+            self.write(str(val))
+        else:
+            self.write(repr(val))
+
+    def visit_TemplateData(self, node, frame):
+        try:
+            self.write(repr(node.as_const(frame.eval_ctx)))
+        except nodes.Impossible:
+            self.write('(context.eval_ctx.autoescape and Markup or identity)(%r)'
+                       % node.data)
+
+    def visit_Tuple(self, node, frame):
+        self.write('(')
+        idx = -1
+        for idx, item in enumerate(node.items):
+            if idx:
+                self.write(', ')
+            self.visit(item, frame)
+        self.write(idx == 0 and ',)' or ')')
+
+    def visit_List(self, node, frame):
+        self.write('[')
+        for idx, item in enumerate(node.items):
+            if idx:
+                self.write(', ')
+            self.visit(item, frame)
+        self.write(']')
+
+    def visit_Dict(self, node, frame):
+        self.write('{')
+        for idx, item in enumerate(node.items):
+            if idx:
+                self.write(', ')
+            self.visit(item.key, frame)
+            self.write(': ')
+            self.visit(item.value, frame)
+        self.write('}')
+
+    def binop(operator, interceptable=True):
+        def visitor(self, node, frame):
+            if self.environment.sandboxed and \
+               operator in self.environment.intercepted_binops:
+                self.write('environment.call_binop(context, %r, ' % operator)
+                self.visit(node.left, frame)
+                self.write(', ')
+                self.visit(node.right, frame)
+            else:
+                self.write('(')
+                self.visit(node.left, frame)
+                self.write(' %s ' % operator)
+                self.visit(node.right, frame)
+            self.write(')')
+        return visitor
+
+    def uaop(operator, interceptable=True):
+        def visitor(self, node, frame):
+            if self.environment.sandboxed and \
+               operator in self.environment.intercepted_unops:
+                self.write('environment.call_unop(context, %r, ' % operator)
+                self.visit(node.node, frame)
+            else:
+                self.write('(' + operator)
+                self.visit(node.node, frame)
+            self.write(')')
+        return visitor
+
+    visit_Add = binop('+')
+    visit_Sub = binop('-')
+    visit_Mul = binop('*')
+    visit_Div = binop('/')
+    visit_FloorDiv = binop('//')
+    visit_Pow = binop('**')
+    visit_Mod = binop('%')
+    visit_And = binop('and', interceptable=False)
+    visit_Or = binop('or', interceptable=False)
+    visit_Pos = uaop('+')
+    visit_Neg = uaop('-')
+    visit_Not = uaop('not ', interceptable=False)
+    del binop, uaop
+
+    def visit_Concat(self, node, frame):
+        if frame.eval_ctx.volatile:
+            func_name = '(context.eval_ctx.volatile and' \
+                        ' markup_join or unicode_join)'
+        elif frame.eval_ctx.autoescape:
+            func_name = 'markup_join'
+        else:
+            func_name = 'unicode_join'
+        self.write('%s((' % func_name)
+        for arg in node.nodes:
+            self.visit(arg, frame)
+            self.write(', ')
+        self.write('))')
+
+    def visit_Compare(self, node, frame):
+        self.visit(node.expr, frame)
+        for op in node.ops:
+            self.visit(op, frame)
+
+    def visit_Operand(self, node, frame):
+        self.write(' %s ' % operators[node.op])
+        self.visit(node.expr, frame)
+
+    def visit_Getattr(self, node, frame):
+        self.write('environment.getattr(')
+        self.visit(node.node, frame)
+        self.write(', %r)' % node.attr)
+
+    def visit_Getitem(self, node, frame):
+        # slices bypass the environment getitem method.
+        if isinstance(node.arg, nodes.Slice):
+            self.visit(node.node, frame)
+            self.write('[')
+            self.visit(node.arg, frame)
+            self.write(']')
+        else:
+            self.write('environment.getitem(')
+            self.visit(node.node, frame)
+            self.write(', ')
+            self.visit(node.arg, frame)
+            self.write(')')
+
+    def visit_Slice(self, node, frame):
+        if node.start is not None:
+            self.visit(node.start, frame)
+        self.write(':')
+        if node.stop is not None:
+            self.visit(node.stop, frame)
+        if node.step is not None:
+            self.write(':')
+            self.visit(node.step, frame)
+
+    def visit_Filter(self, node, frame):
+        self.write(self.filters[node.name] + '(')
+        func = self.environment.filters.get(node.name)
+        if func is None:
+            self.fail('no filter named %r' % node.name, node.lineno)
+        if getattr(func, 'contextfilter', False):
+            self.write('context, ')
+        elif getattr(func, 'evalcontextfilter', False):
+            self.write('context.eval_ctx, ')
+        elif getattr(func, 'environmentfilter', False):
+            self.write('environment, ')
+
+        # if the filter node is None we are inside a filter block
+        # and want to write to the current buffer
+        if node.node is not None:
+            self.visit(node.node, frame)
+        elif frame.eval_ctx.volatile:
+            self.write('(context.eval_ctx.autoescape and'
+                       ' Markup(concat(%s)) or concat(%s))' %
+                       (frame.buffer, frame.buffer))
+        elif frame.eval_ctx.autoescape:
+            self.write('Markup(concat(%s))' % frame.buffer)
+        else:
+            self.write('concat(%s)' % frame.buffer)
+        self.signature(node, frame)
+        self.write(')')
+
+    def visit_Test(self, node, frame):
+        self.write(self.tests[node.name] + '(')
+        if node.name not in self.environment.tests:
+            self.fail('no test named %r' % node.name, node.lineno)
+        self.visit(node.node, frame)
+        self.signature(node, frame)
+        self.write(')')
+
+    def visit_CondExpr(self, node, frame):
+        def write_expr2():
+            if node.expr2 is not None:
+                return self.visit(node.expr2, frame)
+            self.write('environment.undefined(%r)' % ('the inline if-'
+                       'expression on %s evaluated to false and '
+                       'no else section was defined.' % self.position(node)))
+
+        if not have_condexpr:
+            self.write('((')
+            self.visit(node.test, frame)
+            self.write(') and (')
+            self.visit(node.expr1, frame)
+            self.write(',) or (')
+            write_expr2()
+            self.write(',))[0]')
+        else:
+            self.write('(')
+            self.visit(node.expr1, frame)
+            self.write(' if ')
+            self.visit(node.test, frame)
+            self.write(' else ')
+            write_expr2()
+            self.write(')')
+
+    def visit_Call(self, node, frame, forward_caller=False):
+        if self.environment.sandboxed:
+            self.write('environment.call(context, ')
+        else:
+            self.write('context.call(')
+        self.visit(node.node, frame)
+        extra_kwargs = forward_caller and {'caller': 'caller'} or None
+        self.signature(node, frame, extra_kwargs)
+        self.write(')')
+
+    def visit_Keyword(self, node, frame):
+        self.write(node.key + '=')
+        self.visit(node.value, frame)
+
+    # -- Unused nodes for extensions
+
+    def visit_MarkSafe(self, node, frame):
+        self.write('Markup(')
+        self.visit(node.expr, frame)
+        self.write(')')
+
+    def visit_MarkSafeIfAutoescape(self, node, frame):
+        self.write('(context.eval_ctx.autoescape and Markup or identity)(')
+        self.visit(node.expr, frame)
+        self.write(')')
+
+    def visit_EnvironmentAttribute(self, node, frame):
+        self.write('environment.' + node.name)
+
+    def visit_ExtensionAttribute(self, node, frame):
+        self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
+
+    def visit_ImportedName(self, node, frame):
+        self.write(self.import_aliases[node.importname])
+
+    def visit_InternalName(self, node, frame):
+        self.write(node.name)
+
+    def visit_ContextReference(self, node, frame):
+        self.write('context')
+
+    def visit_Continue(self, node, frame):
+        self.writeline('continue', node)
+
+    def visit_Break(self, node, frame):
+        self.writeline('break', node)
+
+    def visit_Scope(self, node, frame):
+        scope_frame = frame.inner()
+        scope_frame.inspect(node.iter_child_nodes())
+        aliases = self.push_scope(scope_frame)
+        self.pull_locals(scope_frame)
+        self.blockvisit(node.body, scope_frame)
+        self.pop_scope(aliases, scope_frame)
+
+    def visit_EvalContextModifier(self, node, frame):
+        for keyword in node.options:
+            self.writeline('context.eval_ctx.%s = ' % keyword.key)
+            self.visit(keyword.value, frame)
+            try:
+                val = keyword.value.as_const(frame.eval_ctx)
+            except nodes.Impossible:
+                frame.eval_ctx.volatile = True
+            else:
+                setattr(frame.eval_ctx, keyword.key, val)
+
+    def visit_ScopedEvalContextModifier(self, node, frame):
+        old_ctx_name = self.temporary_identifier()
+        safed_ctx = frame.eval_ctx.save()
+        self.writeline('%s = context.eval_ctx.save()' % old_ctx_name)
+        self.visit_EvalContextModifier(node, frame)
+        for child in node.body:
+            self.visit(child, frame)
+        frame.eval_ctx.revert(safed_ctx)
+        self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name)
diff --git a/lib/jinja2/jinja2/constants.py b/lib/jinja2/jinja2/constants.py
new file mode 100644
index 0000000..cab203c
--- /dev/null
+++ b/lib/jinja2/jinja2/constants.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja.constants
+    ~~~~~~~~~~~~~~~
+
+    Various constants.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+
+
+#: list of lorem ipsum words used by the lipsum() helper function
+LOREM_IPSUM_WORDS = u'''\
+a ac accumsan ad adipiscing aenean aliquam aliquet amet ante aptent arcu at
+auctor augue bibendum blandit class commodo condimentum congue consectetuer
+consequat conubia convallis cras cubilia cum curabitur curae cursus dapibus
+diam dictum dictumst dignissim dis dolor donec dui duis egestas eget eleifend
+elementum elit enim erat eros est et etiam eu euismod facilisi facilisis fames
+faucibus felis fermentum feugiat fringilla fusce gravida habitant habitasse hac
+hendrerit hymenaeos iaculis id imperdiet in inceptos integer interdum ipsum
+justo lacinia lacus laoreet lectus leo libero ligula litora lobortis lorem
+luctus maecenas magna magnis malesuada massa mattis mauris metus mi molestie
+mollis montes morbi mus nam nascetur natoque nec neque netus nibh nisi nisl non
+nonummy nostra nulla nullam nunc odio orci ornare parturient pede pellentesque
+penatibus per pharetra phasellus placerat platea porta porttitor posuere
+potenti praesent pretium primis proin pulvinar purus quam quis quisque rhoncus
+ridiculus risus rutrum sagittis sapien scelerisque sed sem semper senectus sit
+sociis sociosqu sodales sollicitudin suscipit suspendisse taciti tellus tempor
+tempus tincidunt torquent tortor tristique turpis ullamcorper ultrices
+ultricies urna ut varius vehicula vel velit venenatis vestibulum vitae vivamus
+viverra volutpat vulputate'''
diff --git a/lib/jinja2/jinja2/debug.py b/lib/jinja2/jinja2/debug.py
new file mode 100644
index 0000000..2af2222
--- /dev/null
+++ b/lib/jinja2/jinja2/debug.py
@@ -0,0 +1,339 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.debug
+    ~~~~~~~~~~~~
+
+    Implements the debug interface for Jinja.  This module does some pretty
+    ugly stuff with the Python traceback system in order to achieve tracebacks
+    with correct line numbers, locals and contents.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import sys
+import traceback
+from types import TracebackType
+from jinja2.utils import CodeType, missing, internal_code
+from jinja2.exceptions import TemplateSyntaxError
+
+# on pypy we can take advantage of transparent proxies
+try:
+    from __pypy__ import tproxy
+except ImportError:
+    tproxy = None
+
+
+# how does the raise helper look like?
+try:
+    exec "raise TypeError, 'foo'"
+except SyntaxError:
+    raise_helper = 'raise __jinja_exception__[1]'
+except TypeError:
+    raise_helper = 'raise __jinja_exception__[0], __jinja_exception__[1]'
+
+
+class TracebackFrameProxy(object):
+    """Proxies a traceback frame."""
+
+    def __init__(self, tb):
+        self.tb = tb
+        self._tb_next = None
+
+    @property
+    def tb_next(self):
+        return self._tb_next
+
+    def set_next(self, next):
+        if tb_set_next is not None:
+            try:
+                tb_set_next(self.tb, next and next.tb or None)
+            except Exception:
+                # this function can fail due to all the hackery it does
+                # on various python implementations.  We just catch errors
+                # down and ignore them if necessary.
+                pass
+        self._tb_next = next
+
+    @property
+    def is_jinja_frame(self):
+        return '__jinja_template__' in self.tb.tb_frame.f_globals
+
+    def __getattr__(self, name):
+        return getattr(self.tb, name)
+
+
+def make_frame_proxy(frame):
+    proxy = TracebackFrameProxy(frame)
+    if tproxy is None:
+        return proxy
+    def operation_handler(operation, *args, **kwargs):
+        if operation in ('__getattribute__', '__getattr__'):
+            return getattr(proxy, args[0])
+        elif operation == '__setattr__':
+            proxy.__setattr__(*args, **kwargs)
+        else:
+            return getattr(proxy, operation)(*args, **kwargs)
+    return tproxy(TracebackType, operation_handler)
+
+
+class ProcessedTraceback(object):
+    """Holds a Jinja preprocessed traceback for priting or reraising."""
+
+    def __init__(self, exc_type, exc_value, frames):
+        assert frames, 'no frames for this traceback?'
+        self.exc_type = exc_type
+        self.exc_value = exc_value
+        self.frames = frames
+
+        # newly concatenate the frames (which are proxies)
+        prev_tb = None
+        for tb in self.frames:
+            if prev_tb is not None:
+                prev_tb.set_next(tb)
+            prev_tb = tb
+        prev_tb.set_next(None)
+
+    def render_as_text(self, limit=None):
+        """Return a string with the traceback."""
+        lines = traceback.format_exception(self.exc_type, self.exc_value,
+                                           self.frames[0], limit=limit)
+        return ''.join(lines).rstrip()
+
+    def render_as_html(self, full=False):
+        """Return a unicode string with the traceback as rendered HTML."""
+        from jinja2.debugrenderer import render_traceback
+        return u'%s\n\n<!--\n%s\n-->' % (
+            render_traceback(self, full=full),
+            self.render_as_text().decode('utf-8', 'replace')
+        )
+
+    @property
+    def is_template_syntax_error(self):
+        """`True` if this is a template syntax error."""
+        return isinstance(self.exc_value, TemplateSyntaxError)
+
+    @property
+    def exc_info(self):
+        """Exception info tuple with a proxy around the frame objects."""
+        return self.exc_type, self.exc_value, self.frames[0]
+
+    @property
+    def standard_exc_info(self):
+        """Standard python exc_info for re-raising"""
+        tb = self.frames[0]
+        # the frame will be an actual traceback (or transparent proxy) if
+        # we are on pypy or a python implementation with support for tproxy
+        if type(tb) is not TracebackType:
+            tb = tb.tb
+        return self.exc_type, self.exc_value, tb
+
+
+def make_traceback(exc_info, source_hint=None):
+    """Creates a processed traceback object from the exc_info."""
+    exc_type, exc_value, tb = exc_info
+    if isinstance(exc_value, TemplateSyntaxError):
+        exc_info = translate_syntax_error(exc_value, source_hint)
+        initial_skip = 0
+    else:
+        initial_skip = 1
+    return translate_exception(exc_info, initial_skip)
+
+
+def translate_syntax_error(error, source=None):
+    """Rewrites a syntax error to please traceback systems."""
+    error.source = source
+    error.translated = True
+    exc_info = (error.__class__, error, None)
+    filename = error.filename
+    if filename is None:
+        filename = '<unknown>'
+    return fake_exc_info(exc_info, filename, error.lineno)
+
+
+def translate_exception(exc_info, initial_skip=0):
+    """If passed an exc_info it will automatically rewrite the exceptions
+    all the way down to the correct line numbers and frames.
+    """
+    tb = exc_info[2]
+    frames = []
+
+    # skip some internal frames if wanted
+    for x in xrange(initial_skip):
+        if tb is not None:
+            tb = tb.tb_next
+    initial_tb = tb
+
+    while tb is not None:
+        # skip frames decorated with @internalcode.  These are internal
+        # calls we can't avoid and that are useless in template debugging
+        # output.
+        if tb.tb_frame.f_code in internal_code:
+            tb = tb.tb_next
+            continue
+
+        # save a reference to the next frame if we override the current
+        # one with a faked one.
+        next = tb.tb_next
+
+        # fake template exceptions
+        template = tb.tb_frame.f_globals.get('__jinja_template__')
+        if template is not None:
+            lineno = template.get_corresponding_lineno(tb.tb_lineno)
+            tb = fake_exc_info(exc_info[:2] + (tb,), template.filename,
+                               lineno)[2]
+
+        frames.append(make_frame_proxy(tb))
+        tb = next
+
+    # if we don't have any exceptions in the frames left, we have to
+    # reraise it unchanged.
+    # XXX: can we backup here?  when could this happen?
+    if not frames:
+        raise exc_info[0], exc_info[1], exc_info[2]
+
+    return ProcessedTraceback(exc_info[0], exc_info[1], frames)
+
+
+def fake_exc_info(exc_info, filename, lineno):
+    """Helper for `translate_exception`."""
+    exc_type, exc_value, tb = exc_info
+
+    # figure the real context out
+    if tb is not None:
+        real_locals = tb.tb_frame.f_locals.copy()
+        ctx = real_locals.get('context')
+        if ctx:
+            locals = ctx.get_all()
+        else:
+            locals = {}
+        for name, value in real_locals.iteritems():
+            if name.startswith('l_') and value is not missing:
+                locals[name[2:]] = value
+
+        # if there is a local called __jinja_exception__, we get
+        # rid of it to not break the debug functionality.
+        locals.pop('__jinja_exception__', None)
+    else:
+        locals = {}
+
+    # assamble fake globals we need
+    globals = {
+        '__name__':             filename,
+        '__file__':             filename,
+        '__jinja_exception__':  exc_info[:2],
+
+        # we don't want to keep the reference to the template around
+        # to not cause circular dependencies, but we mark it as Jinja
+        # frame for the ProcessedTraceback
+        '__jinja_template__':   None
+    }
+
+    # and fake the exception
+    code = compile('\n' * (lineno - 1) + raise_helper, filename, 'exec')
+
+    # if it's possible, change the name of the code.  This won't work
+    # on some python environments such as google appengine
+    try:
+        if tb is None:
+            location = 'template'
+        else:
+            function = tb.tb_frame.f_code.co_name
+            if function == 'root':
+                location = 'top-level template code'
+            elif function.startswith('block_'):
+                location = 'block "%s"' % function[6:]
+            else:
+                location = 'template'
+        code = CodeType(0, code.co_nlocals, code.co_stacksize,
+                        code.co_flags, code.co_code, code.co_consts,
+                        code.co_names, code.co_varnames, filename,
+                        location, code.co_firstlineno,
+                        code.co_lnotab, (), ())
+    except:
+        pass
+
+    # execute the code and catch the new traceback
+    try:
+        exec code in globals, locals
+    except:
+        exc_info = sys.exc_info()
+        new_tb = exc_info[2].tb_next
+
+    # return without this frame
+    return exc_info[:2] + (new_tb,)
+
+
+def _init_ugly_crap():
+    """This function implements a few ugly things so that we can patch the
+    traceback objects.  The function returned allows resetting `tb_next` on
+    any python traceback object.  Do not attempt to use this on non cpython
+    interpreters
+    """
+    import ctypes
+    from types import TracebackType
+
+    # figure out side of _Py_ssize_t
+    if hasattr(ctypes.pythonapi, 'Py_InitModule4_64'):
+        _Py_ssize_t = ctypes.c_int64
+    else:
+        _Py_ssize_t = ctypes.c_int
+
+    # regular python
+    class _PyObject(ctypes.Structure):
+        pass
+    _PyObject._fields_ = [
+        ('ob_refcnt', _Py_ssize_t),
+        ('ob_type', ctypes.POINTER(_PyObject))
+    ]
+
+    # python with trace
+    if hasattr(sys, 'getobjects'):
+        class _PyObject(ctypes.Structure):
+            pass
+        _PyObject._fields_ = [
+            ('_ob_next', ctypes.POINTER(_PyObject)),
+            ('_ob_prev', ctypes.POINTER(_PyObject)),
+            ('ob_refcnt', _Py_ssize_t),
+            ('ob_type', ctypes.POINTER(_PyObject))
+        ]
+
+    class _Traceback(_PyObject):
+        pass
+    _Traceback._fields_ = [
+        ('tb_next', ctypes.POINTER(_Traceback)),
+        ('tb_frame', ctypes.POINTER(_PyObject)),
+        ('tb_lasti', ctypes.c_int),
+        ('tb_lineno', ctypes.c_int)
+    ]
+
+    def tb_set_next(tb, next):
+        """Set the tb_next attribute of a traceback object."""
+        if not (isinstance(tb, TracebackType) and
+                (next is None or isinstance(next, TracebackType))):
+            raise TypeError('tb_set_next arguments must be traceback objects')
+        obj = _Traceback.from_address(id(tb))
+        if tb.tb_next is not None:
+            old = _Traceback.from_address(id(tb.tb_next))
+            old.ob_refcnt -= 1
+        if next is None:
+            obj.tb_next = ctypes.POINTER(_Traceback)()
+        else:
+            next = _Traceback.from_address(id(next))
+            next.ob_refcnt += 1
+            obj.tb_next = ctypes.pointer(next)
+
+    return tb_set_next
+
+
+# try to get a tb_set_next implementation if we don't have transparent
+# proxies.
+tb_set_next = None
+if tproxy is None:
+    try:
+        from jinja2._debugsupport import tb_set_next
+    except ImportError:
+        try:
+            tb_set_next = _init_ugly_crap()
+        except:
+            pass
+    del _init_ugly_crap
diff --git a/lib/jinja2/jinja2/defaults.py b/lib/jinja2/jinja2/defaults.py
new file mode 100644
index 0000000..d2d4544
--- /dev/null
+++ b/lib/jinja2/jinja2/defaults.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.defaults
+    ~~~~~~~~~~~~~~~
+
+    Jinja default filters and tags.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+from jinja2.utils import generate_lorem_ipsum, Cycler, Joiner
+
+
+# defaults for the parser / lexer
+BLOCK_START_STRING = '{%'
+BLOCK_END_STRING = '%}'
+VARIABLE_START_STRING = '{{'
+VARIABLE_END_STRING = '}}'
+COMMENT_START_STRING = '{#'
+COMMENT_END_STRING = '#}'
+LINE_STATEMENT_PREFIX = None
+LINE_COMMENT_PREFIX = None
+TRIM_BLOCKS = False
+NEWLINE_SEQUENCE = '\n'
+
+
+# default filters, tests and namespace
+from jinja2.filters import FILTERS as DEFAULT_FILTERS
+from jinja2.tests import TESTS as DEFAULT_TESTS
+DEFAULT_NAMESPACE = {
+    'range':        xrange,
+    'dict':         lambda **kw: kw,
+    'lipsum':       generate_lorem_ipsum,
+    'cycler':       Cycler,
+    'joiner':       Joiner
+}
+
+
+# export all constants
+__all__ = tuple(x for x in locals().keys() if x.isupper())
diff --git a/lib/jinja2/jinja2/environment.py b/lib/jinja2/jinja2/environment.py
new file mode 100644
index 0000000..7a9a59f
--- /dev/null
+++ b/lib/jinja2/jinja2/environment.py
@@ -0,0 +1,1121 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.environment
+    ~~~~~~~~~~~~~~~~~~
+
+    Provides a class that holds runtime and parsing time options.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import os
+import sys
+from jinja2 import nodes
+from jinja2.defaults import *
+from jinja2.lexer import get_lexer, TokenStream
+from jinja2.parser import Parser
+from jinja2.optimizer import optimize
+from jinja2.compiler import generate
+from jinja2.runtime import Undefined, new_context
+from jinja2.exceptions import TemplateSyntaxError, TemplateNotFound, \
+     TemplatesNotFound
+from jinja2.utils import import_string, LRUCache, Markup, missing, \
+     concat, consume, internalcode, _encode_filename
+
+
+# for direct template usage we have up to ten living environments
+_spontaneous_environments = LRUCache(10)
+
+# the function to create jinja traceback objects.  This is dynamically
+# imported on the first exception in the exception handler.
+_make_traceback = None
+
+
+def get_spontaneous_environment(*args):
+    """Return a new spontaneous environment.  A spontaneous environment is an
+    unnamed and unaccessible (in theory) environment that is used for
+    templates generated from a string and not from the file system.
+    """
+    try:
+        env = _spontaneous_environments.get(args)
+    except TypeError:
+        return Environment(*args)
+    if env is not None:
+        return env
+    _spontaneous_environments[args] = env = Environment(*args)
+    env.shared = True
+    return env
+
+
+def create_cache(size):
+    """Return the cache class for the given size."""
+    if size == 0:
+        return None
+    if size < 0:
+        return {}
+    return LRUCache(size)
+
+
+def copy_cache(cache):
+    """Create an empty copy of the given cache."""
+    if cache is None:
+        return None
+    elif type(cache) is dict:
+        return {}
+    return LRUCache(cache.capacity)
+
+
+def load_extensions(environment, extensions):
+    """Load the extensions from the list and bind it to the environment.
+    Returns a dict of instanciated environments.
+    """
+    result = {}
+    for extension in extensions:
+        if isinstance(extension, basestring):
+            extension = import_string(extension)
+        result[extension.identifier] = extension(environment)
+    return result
+
+
+def _environment_sanity_check(environment):
+    """Perform a sanity check on the environment."""
+    assert issubclass(environment.undefined, Undefined), 'undefined must ' \
+           'be a subclass of undefined because filters depend on it.'
+    assert environment.block_start_string != \
+           environment.variable_start_string != \
+           environment.comment_start_string, 'block, variable and comment ' \
+           'start strings must be different'
+    assert environment.newline_sequence in ('\r', '\r\n', '\n'), \
+           'newline_sequence set to unknown line ending string.'
+    return environment
+
+
+class Environment(object):
+    r"""The core component of Jinja is the `Environment`.  It contains
+    important shared variables like configuration, filters, tests,
+    globals and others.  Instances of this class may be modified if
+    they are not shared and if no template was loaded so far.
+    Modifications on environments after the first template was loaded
+    will lead to surprising effects and undefined behavior.
+
+    Here the possible initialization parameters:
+
+        `block_start_string`
+            The string marking the begin of a block.  Defaults to ``'{%'``.
+
+        `block_end_string`
+            The string marking the end of a block.  Defaults to ``'%}'``.
+
+        `variable_start_string`
+            The string marking the begin of a print statement.
+            Defaults to ``'{{'``.
+
+        `variable_end_string`
+            The string marking the end of a print statement.  Defaults to
+            ``'}}'``.
+
+        `comment_start_string`
+            The string marking the begin of a comment.  Defaults to ``'{#'``.
+
+        `comment_end_string`
+            The string marking the end of a comment.  Defaults to ``'#}'``.
+
+        `line_statement_prefix`
+            If given and a string, this will be used as prefix for line based
+            statements.  See also :ref:`line-statements`.
+
+        `line_comment_prefix`
+            If given and a string, this will be used as prefix for line based
+            based comments.  See also :ref:`line-statements`.
+
+            .. versionadded:: 2.2
+
+        `trim_blocks`
+            If this is set to ``True`` the first newline after a block is
+            removed (block, not variable tag!).  Defaults to `False`.
+
+        `newline_sequence`
+            The sequence that starts a newline.  Must be one of ``'\r'``,
+            ``'\n'`` or ``'\r\n'``.  The default is ``'\n'`` which is a
+            useful default for Linux and OS X systems as well as web
+            applications.
+
+        `extensions`
+            List of Jinja extensions to use.  This can either be import paths
+            as strings or extension classes.  For more information have a
+            look at :ref:`the extensions documentation <jinja-extensions>`.
+
+        `optimized`
+            should the optimizer be enabled?  Default is `True`.
+
+        `undefined`
+            :class:`Undefined` or a subclass of it that is used to represent
+            undefined values in the template.
+
+        `finalize`
+            A callable that can be used to process the result of a variable
+            expression before it is output.  For example one can convert
+            `None` implicitly into an empty string here.
+
+        `autoescape`
+            If set to true the XML/HTML autoescaping feature is enabled by
+            default.  For more details about auto escaping see
+            :class:`~jinja2.utils.Markup`.  As of Jinja 2.4 this can also
+            be a callable that is passed the template name and has to
+            return `True` or `False` depending on autoescape should be
+            enabled by default.
+
+            .. versionchanged:: 2.4
+               `autoescape` can now be a function
+
+        `loader`
+            The template loader for this environment.
+
+        `cache_size`
+            The size of the cache.  Per default this is ``50`` which means
+            that if more than 50 templates are loaded the loader will clean
+            out the least recently used template.  If the cache size is set to
+            ``0`` templates are recompiled all the time, if the cache size is
+            ``-1`` the cache will not be cleaned.
+
+        `auto_reload`
+            Some loaders load templates from locations where the template
+            sources may change (ie: file system or database).  If
+            `auto_reload` is set to `True` (default) every time a template is
+            requested the loader checks if the source changed and if yes, it
+            will reload the template.  For higher performance it's possible to
+            disable that.
+
+        `bytecode_cache`
+            If set to a bytecode cache object, this object will provide a
+            cache for the internal Jinja bytecode so that templates don't
+            have to be parsed if they were not changed.
+
+            See :ref:`bytecode-cache` for more information.
+    """
+
+    #: if this environment is sandboxed.  Modifying this variable won't make
+    #: the environment sandboxed though.  For a real sandboxed environment
+    #: have a look at jinja2.sandbox.  This flag alone controls the code
+    #: generation by the compiler.
+    sandboxed = False
+
+    #: True if the environment is just an overlay
+    overlayed = False
+
+    #: the environment this environment is linked to if it is an overlay
+    linked_to = None
+
+    #: shared environments have this set to `True`.  A shared environment
+    #: must not be modified
+    shared = False
+
+    #: these are currently EXPERIMENTAL undocumented features.
+    exception_handler = None
+    exception_formatter = None
+
+    def __init__(self,
+                 block_start_string=BLOCK_START_STRING,
+                 block_end_string=BLOCK_END_STRING,
+                 variable_start_string=VARIABLE_START_STRING,
+                 variable_end_string=VARIABLE_END_STRING,
+                 comment_start_string=COMMENT_START_STRING,
+                 comment_end_string=COMMENT_END_STRING,
+                 line_statement_prefix=LINE_STATEMENT_PREFIX,
+                 line_comment_prefix=LINE_COMMENT_PREFIX,
+                 trim_blocks=TRIM_BLOCKS,
+                 newline_sequence=NEWLINE_SEQUENCE,
+                 extensions=(),
+                 optimized=True,
+                 undefined=Undefined,
+                 finalize=None,
+                 autoescape=False,
+                 loader=None,
+                 cache_size=50,
+                 auto_reload=True,
+                 bytecode_cache=None):
+        # !!Important notice!!
+        #   The constructor accepts quite a few arguments that should be
+        #   passed by keyword rather than position.  However it's important to
+        #   not change the order of arguments because it's used at least
+        #   internally in those cases:
+        #       -   spontaneus environments (i18n extension and Template)
+        #       -   unittests
+        #   If parameter changes are required only add parameters at the end
+        #   and don't change the arguments (or the defaults!) of the arguments
+        #   existing already.
+
+        # lexer / parser information
+        self.block_start_string = block_start_string
+        self.block_end_string = block_end_string
+        self.variable_start_string = variable_start_string
+        self.variable_end_string = variable_end_string
+        self.comment_start_string = comment_start_string
+        self.comment_end_string = comment_end_string
+        self.line_statement_prefix = line_statement_prefix
+        self.line_comment_prefix = line_comment_prefix
+        self.trim_blocks = trim_blocks
+        self.newline_sequence = newline_sequence
+
+        # runtime information
+        self.undefined = undefined
+        self.optimized = optimized
+        self.finalize = finalize
+        self.autoescape = autoescape
+
+        # defaults
+        self.filters = DEFAULT_FILTERS.copy()
+        self.tests = DEFAULT_TESTS.copy()
+        self.globals = DEFAULT_NAMESPACE.copy()
+
+        # set the loader provided
+        self.loader = loader
+        self.bytecode_cache = None
+        self.cache = create_cache(cache_size)
+        self.bytecode_cache = bytecode_cache
+        self.auto_reload = auto_reload
+
+        # load extensions
+        self.extensions = load_extensions(self, extensions)
+
+        _environment_sanity_check(self)
+
+    def add_extension(self, extension):
+        """Adds an extension after the environment was created.
+
+        .. versionadded:: 2.5
+        """
+        self.extensions.update(load_extensions(self, [extension]))
+
+    def extend(self, **attributes):
+        """Add the items to the instance of the environment if they do not exist
+        yet.  This is used by :ref:`extensions <writing-extensions>` to register
+        callbacks and configuration values without breaking inheritance.
+        """
+        for key, value in attributes.iteritems():
+            if not hasattr(self, key):
+                setattr(self, key, value)
+
+    def overlay(self, block_start_string=missing, block_end_string=missing,
+                variable_start_string=missing, variable_end_string=missing,
+                comment_start_string=missing, comment_end_string=missing,
+                line_statement_prefix=missing, line_comment_prefix=missing,
+                trim_blocks=missing, extensions=missing, optimized=missing,
+                undefined=missing, finalize=missing, autoescape=missing,
+                loader=missing, cache_size=missing, auto_reload=missing,
+                bytecode_cache=missing):
+        """Create a new overlay environment that shares all the data with the
+        current environment except of cache and the overridden attributes.
+        Extensions cannot be removed for an overlayed environment.  An overlayed
+        environment automatically gets all the extensions of the environment it
+        is linked to plus optional extra extensions.
+
+        Creating overlays should happen after the initial environment was set
+        up completely.  Not all attributes are truly linked, some are just
+        copied over so modifications on the original environment may not shine
+        through.
+        """
+        args = dict(locals())
+        del args['self'], args['cache_size'], args['extensions']
+
+        rv = object.__new__(self.__class__)
+        rv.__dict__.update(self.__dict__)
+        rv.overlayed = True
+        rv.linked_to = self
+
+        for key, value in args.iteritems():
+            if value is not missing:
+                setattr(rv, key, value)
+
+        if cache_size is not missing:
+            rv.cache = create_cache(cache_size)
+        else:
+            rv.cache = copy_cache(self.cache)
+
+        rv.extensions = {}
+        for key, value in self.extensions.iteritems():
+            rv.extensions[key] = value.bind(rv)
+        if extensions is not missing:
+            rv.extensions.update(load_extensions(rv, extensions))
+
+        return _environment_sanity_check(rv)
+
+    lexer = property(get_lexer, doc="The lexer for this environment.")
+
+    def iter_extensions(self):
+        """Iterates over the extensions by priority."""
+        return iter(sorted(self.extensions.values(),
+                           key=lambda x: x.priority))
+
+    def getitem(self, obj, argument):
+        """Get an item or attribute of an object but prefer the item."""
+        try:
+            return obj[argument]
+        except (TypeError, LookupError):
+            if isinstance(argument, basestring):
+                try:
+                    attr = str(argument)
+                except Exception:
+                    pass
+                else:
+                    try:
+                        return getattr(obj, attr)
+                    except AttributeError:
+                        pass
+            return self.undefined(obj=obj, name=argument)
+
+    def getattr(self, obj, attribute):
+        """Get an item or attribute of an object but prefer the attribute.
+        Unlike :meth:`getitem` the attribute *must* be a bytestring.
+        """
+        try:
+            return getattr(obj, attribute)
+        except AttributeError:
+            pass
+        try:
+            return obj[attribute]
+        except (TypeError, LookupError, AttributeError):
+            return self.undefined(obj=obj, name=attribute)
+
+    @internalcode
+    def parse(self, source, name=None, filename=None):
+        """Parse the sourcecode and return the abstract syntax tree.  This
+        tree of nodes is used by the compiler to convert the template into
+        executable source- or bytecode.  This is useful for debugging or to
+        extract information from templates.
+
+        If you are :ref:`developing Jinja2 extensions <writing-extensions>`
+        this gives you a good overview of the node tree generated.
+        """
+        try:
+            return self._parse(source, name, filename)
+        except TemplateSyntaxError:
+            exc_info = sys.exc_info()
+        self.handle_exception(exc_info, source_hint=source)
+
+    def _parse(self, source, name, filename):
+        """Internal parsing function used by `parse` and `compile`."""
+        return Parser(self, source, name, _encode_filename(filename)).parse()
+
+    def lex(self, source, name=None, filename=None):
+        """Lex the given sourcecode and return a generator that yields
+        tokens as tuples in the form ``(lineno, token_type, value)``.
+        This can be useful for :ref:`extension development <writing-extensions>`
+        and debugging templates.
+
+        This does not perform preprocessing.  If you want the preprocessing
+        of the extensions to be applied you have to filter source through
+        the :meth:`preprocess` method.
+        """
+        source = unicode(source)
+        try:
+            return self.lexer.tokeniter(source, name, filename)
+        except TemplateSyntaxError:
+            exc_info = sys.exc_info()
+        self.handle_exception(exc_info, source_hint=source)
+
+    def preprocess(self, source, name=None, filename=None):
+        """Preprocesses the source with all extensions.  This is automatically
+        called for all parsing and compiling methods but *not* for :meth:`lex`
+        because there you usually only want the actual source tokenized.
+        """
+        return reduce(lambda s, e: e.preprocess(s, name, filename),
+                      self.iter_extensions(), unicode(source))
+
+    def _tokenize(self, source, name, filename=None, state=None):
+        """Called by the parser to do the preprocessing and filtering
+        for all the extensions.  Returns a :class:`~jinja2.lexer.TokenStream`.
+        """
+        source = self.preprocess(source, name, filename)
+        stream = self.lexer.tokenize(source, name, filename, state)
+        for ext in self.iter_extensions():
+            stream = ext.filter_stream(stream)
+            if not isinstance(stream, TokenStream):
+                stream = TokenStream(stream, name, filename)
+        return stream
+
+    def _generate(self, source, name, filename, defer_init=False):
+        """Internal hook that can be overriden to hook a different generate
+        method in.
+
+        .. versionadded:: 2.5
+        """
+        return generate(source, self, name, filename, defer_init=defer_init)
+
+    def _compile(self, source, filename):
+        """Internal hook that can be overriden to hook a different compile
+        method in.
+
+        .. versionadded:: 2.5
+        """
+        return compile(source, filename, 'exec')
+
+    @internalcode
+    def compile(self, source, name=None, filename=None, raw=False,
+                defer_init=False):
+        """Compile a node or template source code.  The `name` parameter is
+        the load name of the template after it was joined using
+        :meth:`join_path` if necessary, not the filename on the file system.
+        the `filename` parameter is the estimated filename of the template on
+        the file system.  If the template came from a database or memory this
+        can be omitted.
+
+        The return value of this method is a python code object.  If the `raw`
+        parameter is `True` the return value will be a string with python
+        code equivalent to the bytecode returned otherwise.  This method is
+        mainly used internally.
+
+        `defer_init` is use internally to aid the module code generator.  This
+        causes the generated code to be able to import without the global
+        environment variable to be set.
+
+        .. versionadded:: 2.4
+           `defer_init` parameter added.
+        """
+        source_hint = None
+        try:
+            if isinstance(source, basestring):
+                source_hint = source
+                source = self._parse(source, name, filename)
+            if self.optimized:
+                source = optimize(source, self)
+            source = self._generate(source, name, filename,
+                                    defer_init=defer_init)
+            if raw:
+                return source
+            if filename is None:
+                filename = '<template>'
+            else:
+                filename = _encode_filename(filename)
+            return self._compile(source, filename)
+        except TemplateSyntaxError:
+            exc_info = sys.exc_info()
+        self.handle_exception(exc_info, source_hint=source)
+
+    def compile_expression(self, source, undefined_to_none=True):
+        """A handy helper method that returns a callable that accepts keyword
+        arguments that appear as variables in the expression.  If called it
+        returns the result of the expression.
+
+        This is useful if applications want to use the same rules as Jinja
+        in template "configuration files" or similar situations.
+
+        Example usage:
+
+        >>> env = Environment()
+        >>> expr = env.compile_expression('foo == 42')
+        >>> expr(foo=23)
+        False
+        >>> expr(foo=42)
+        True
+
+        Per default the return value is converted to `None` if the
+        expression returns an undefined value.  This can be changed
+        by setting `undefined_to_none` to `False`.
+
+        >>> env.compile_expression('var')() is None
+        True
+        >>> env.compile_expression('var', undefined_to_none=False)()
+        Undefined
+
+        .. versionadded:: 2.1
+        """
+        parser = Parser(self, source, state='variable')
+        exc_info = None
+        try:
+            expr = parser.parse_expression()
+            if not parser.stream.eos:
+                raise TemplateSyntaxError('chunk after expression',
+                                          parser.stream.current.lineno,
+                                          None, None)
+            expr.set_environment(self)
+        except TemplateSyntaxError:
+            exc_info = sys.exc_info()
+        if exc_info is not None:
+            self.handle_exception(exc_info, source_hint=source)
+        body = [nodes.Assign(nodes.Name('result', 'store'), expr, lineno=1)]
+        template = self.from_string(nodes.Template(body, lineno=1))
+        return TemplateExpression(template, undefined_to_none)
+
+    def compile_templates(self, target, extensions=None, filter_func=None,
+                          zip='deflated', log_function=None,
+                          ignore_errors=True, py_compile=False):
+        """Finds all the templates the loader can find, compiles them
+        and stores them in `target`.  If `zip` is `None`, instead of in a
+        zipfile, the templates will be will be stored in a directory.
+        By default a deflate zip algorithm is used, to switch to
+        the stored algorithm, `zip` can be set to ``'stored'``.
+
+        `extensions` and `filter_func` are passed to :meth:`list_templates`.
+        Each template returned will be compiled to the target folder or
+        zipfile.
+
+        By default template compilation errors are ignored.  In case a
+        log function is provided, errors are logged.  If you want template
+        syntax errors to abort the compilation you can set `ignore_errors`
+        to `False` and you will get an exception on syntax errors.
+
+        If `py_compile` is set to `True` .pyc files will be written to the
+        target instead of standard .py files.
+
+        .. versionadded:: 2.4
+        """
+        from jinja2.loaders import ModuleLoader
+
+        if log_function is None:
+            log_function = lambda x: None
+
+        if py_compile:
+            import imp, marshal
+            py_header = imp.get_magic() + \
+                u'\xff\xff\xff\xff'.encode('iso-8859-15')
+
+        def write_file(filename, data, mode):
+            if zip:
+                info = ZipInfo(filename)
+                info.external_attr = 0755 << 16L
+                zip_file.writestr(info, data)
+            else:
+                f = open(os.path.join(target, filename), mode)
+                try:
+                    f.write(data)
+                finally:
+                    f.close()
+
+        if zip is not None:
+            from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED, ZIP_STORED
+            zip_file = ZipFile(target, 'w', dict(deflated=ZIP_DEFLATED,
+                                                 stored=ZIP_STORED)[zip])
+            log_function('Compiling into Zip archive "%s"' % target)
+        else:
+            if not os.path.isdir(target):
+                os.makedirs(target)
+            log_function('Compiling into folder "%s"' % target)
+
+        try:
+            for name in self.list_templates(extensions, filter_func):
+                source, filename, _ = self.loader.get_source(self, name)
+                try:
+                    code = self.compile(source, name, filename, True, True)
+                except TemplateSyntaxError, e:
+                    if not ignore_errors:
+                        raise
+                    log_function('Could not compile "%s": %s' % (name, e))
+                    continue
+
+                filename = ModuleLoader.get_module_filename(name)
+
+                if py_compile:
+                    c = self._compile(code, _encode_filename(filename))
+                    write_file(filename + 'c', py_header +
+                               marshal.dumps(c), 'wb')
+                    log_function('Byte-compiled "%s" as %s' %
+                                 (name, filename + 'c'))
+                else:
+                    write_file(filename, code, 'w')
+                    log_function('Compiled "%s" as %s' % (name, filename))
+        finally:
+            if zip:
+                zip_file.close()
+
+        log_function('Finished compiling templates')
+
+    def list_templates(self, extensions=None, filter_func=None):
+        """Returns a list of templates for this environment.  This requires
+        that the loader supports the loader's
+        :meth:`~BaseLoader.list_templates` method.
+
+        If there are other files in the template folder besides the
+        actual templates, the returned list can be filtered.  There are two
+        ways: either `extensions` is set to a list of file extensions for
+        templates, or a `filter_func` can be provided which is a callable that
+        is passed a template name and should return `True` if it should end up
+        in the result list.
+
+        If the loader does not support that, a :exc:`TypeError` is raised.
+
+        .. versionadded:: 2.4
+        """
+        x = self.loader.list_templates()
+        if extensions is not None:
+            if filter_func is not None:
+                raise TypeError('either extensions or filter_func '
+                                'can be passed, but not both')
+            filter_func = lambda x: '.' in x and \
+                                    x.rsplit('.', 1)[1] in extensions
+        if filter_func is not None:
+            x = filter(filter_func, x)
+        return x
+
+    def handle_exception(self, exc_info=None, rendered=False, source_hint=None):
+        """Exception handling helper.  This is used internally to either raise
+        rewritten exceptions or return a rendered traceback for the template.
+        """
+        global _make_traceback
+        if exc_info is None:
+            exc_info = sys.exc_info()
+
+        # the debugging module is imported when it's used for the first time.
+        # we're doing a lot of stuff there and for applications that do not
+        # get any exceptions in template rendering there is no need to load
+        # all of that.
+        if _make_traceback is None:
+            from jinja2.debug import make_traceback as _make_traceback
+        traceback = _make_traceback(exc_info, source_hint)
+        if rendered and self.exception_formatter is not None:
+            return self.exception_formatter(traceback)
+        if self.exception_handler is not None:
+            self.exception_handler(traceback)
+        exc_type, exc_value, tb = traceback.standard_exc_info
+        raise exc_type, exc_value, tb
+
+    def join_path(self, template, parent):
+        """Join a template with the parent.  By default all the lookups are
+        relative to the loader root so this method returns the `template`
+        parameter unchanged, but if the paths should be relative to the
+        parent template, this function can be used to calculate the real
+        template name.
+
+        Subclasses may override this method and implement template path
+        joining here.
+        """
+        return template
+
+    @internalcode
+    def _load_template(self, name, globals):
+        if self.loader is None:
+            raise TypeError('no loader for this environment specified')
+        if self.cache is not None:
+            template = self.cache.get(name)
+            if template is not None and (not self.auto_reload or \
+                                         template.is_up_to_date):
+                return template
+        template = self.loader.load(self, name, globals)
+        if self.cache is not None:
+            self.cache[name] = template
+        return template
+
+    @internalcode
+    def get_template(self, name, parent=None, globals=None):
+        """Load a template from the loader.  If a loader is configured this
+        method ask the loader for the template and returns a :class:`Template`.
+        If the `parent` parameter is not `None`, :meth:`join_path` is called
+        to get the real template name before loading.
+
+        The `globals` parameter can be used to provide template wide globals.
+        These variables are available in the context at render time.
+
+        If the template does not exist a :exc:`TemplateNotFound` exception is
+        raised.
+
+        .. versionchanged:: 2.4
+           If `name` is a :class:`Template` object it is returned from the
+           function unchanged.
+        """
+        if isinstance(name, Template):
+            return name
+        if parent is not None:
+            name = self.join_path(name, parent)
+        return self._load_template(name, self.make_globals(globals))
+
+    @internalcode
+    def select_template(self, names, parent=None, globals=None):
+        """Works like :meth:`get_template` but tries a number of templates
+        before it fails.  If it cannot find any of the templates, it will
+        raise a :exc:`TemplatesNotFound` exception.
+
+        .. versionadded:: 2.3
+
+        .. versionchanged:: 2.4
+           If `names` contains a :class:`Template` object it is returned
+           from the function unchanged.
+        """
+        if not names:
+            raise TemplatesNotFound(message=u'Tried to select from an empty list '
+                                            u'of templates.')
+        globals = self.make_globals(globals)
+        for name in names:
+            if isinstance(name, Template):
+                return name
+            if parent is not None:
+                name = self.join_path(name, parent)
+            try:
+                return self._load_template(name, globals)
+            except TemplateNotFound:
+                pass
+        raise TemplatesNotFound(names)
+
+    @internalcode
+    def get_or_select_template(self, template_name_or_list,
+                               parent=None, globals=None):
+        """Does a typecheck and dispatches to :meth:`select_template`
+        if an iterable of template names is given, otherwise to
+        :meth:`get_template`.
+
+        .. versionadded:: 2.3
+        """
+        if isinstance(template_name_or_list, basestring):
+            return self.get_template(template_name_or_list, parent, globals)
+        elif isinstance(template_name_or_list, Template):
+            return template_name_or_list
+        return self.select_template(template_name_or_list, parent, globals)
+
+    def from_string(self, source, globals=None, template_class=None):
+        """Load a template from a string.  This parses the source given and
+        returns a :class:`Template` object.
+        """
+        globals = self.make_globals(globals)
+        cls = template_class or self.template_class
+        return cls.from_code(self, self.compile(source), globals, None)
+
+    def make_globals(self, d):
+        """Return a dict for the globals."""
+        if not d:
+            return self.globals
+        return dict(self.globals, **d)
+
+
+class Template(object):
+    """The central template object.  This class represents a compiled template
+    and is used to evaluate it.
+
+    Normally the template object is generated from an :class:`Environment` but
+    it also has a constructor that makes it possible to create a template
+    instance directly using the constructor.  It takes the same arguments as
+    the environment constructor but it's not possible to specify a loader.
+
+    Every template object has a few methods and members that are guaranteed
+    to exist.  However it's important that a template object should be
+    considered immutable.  Modifications on the object are not supported.
+
+    Template objects created from the constructor rather than an environment
+    do have an `environment` attribute that points to a temporary environment
+    that is probably shared with other templates created with the constructor
+    and compatible settings.
+
+    >>> template = Template('Hello {{ name }}!')
+    >>> template.render(name='John Doe')
+    u'Hello John Doe!'
+
+    >>> stream = template.stream(name='John Doe')
+    >>> stream.next()
+    u'Hello John Doe!'
+    >>> stream.next()
+    Traceback (most recent call last):
+        ...
+    StopIteration
+    """
+
+    def __new__(cls, source,
+                block_start_string=BLOCK_START_STRING,
+                block_end_string=BLOCK_END_STRING,
+                variable_start_string=VARIABLE_START_STRING,
+                variable_end_string=VARIABLE_END_STRING,
+                comment_start_string=COMMENT_START_STRING,
+                comment_end_string=COMMENT_END_STRING,
+                line_statement_prefix=LINE_STATEMENT_PREFIX,
+                line_comment_prefix=LINE_COMMENT_PREFIX,
+                trim_blocks=TRIM_BLOCKS,
+                newline_sequence=NEWLINE_SEQUENCE,
+                extensions=(),
+                optimized=True,
+                undefined=Undefined,
+                finalize=None,
+                autoescape=False):
+        env = get_spontaneous_environment(
+            block_start_string, block_end_string, variable_start_string,
+            variable_end_string, comment_start_string, comment_end_string,
+            line_statement_prefix, line_comment_prefix, trim_blocks,
+            newline_sequence, frozenset(extensions), optimized, undefined,
+            finalize, autoescape, None, 0, False, None)
+        return env.from_string(source, template_class=cls)
+
+    @classmethod
+    def from_code(cls, environment, code, globals, uptodate=None):
+        """Creates a template object from compiled code and the globals.  This
+        is used by the loaders and environment to create a template object.
+        """
+        namespace = {
+            'environment':  environment,
+            '__file__':     code.co_filename
+        }
+        exec code in namespace
+        rv = cls._from_namespace(environment, namespace, globals)
+        rv._uptodate = uptodate
+        return rv
+
+    @classmethod
+    def from_module_dict(cls, environment, module_dict, globals):
+        """Creates a template object from a module.  This is used by the
+        module loader to create a template object.
+
+        .. versionadded:: 2.4
+        """
+        return cls._from_namespace(environment, module_dict, globals)
+
+    @classmethod
+    def _from_namespace(cls, environment, namespace, globals):
+        t = object.__new__(cls)
+        t.environment = environment
+        t.globals = globals
+        t.name = namespace['name']
+        t.filename = namespace['__file__']
+        t.blocks = namespace['blocks']
+
+        # render function and module
+        t.root_render_func = namespace['root']
+        t._module = None
+
+        # debug and loader helpers
+        t._debug_info = namespace['debug_info']
+        t._uptodate = None
+
+        # store the reference
+        namespace['environment'] = environment
+        namespace['__jinja_template__'] = t
+
+        return t
+
+    def render(self, *args, **kwargs):
+        """This method accepts the same arguments as the `dict` constructor:
+        A dict, a dict subclass or some keyword arguments.  If no arguments
+        are given the context will be empty.  These two calls do the same::
+
+            template.render(knights='that say nih')
+            template.render({'knights': 'that say nih'})
+
+        This will return the rendered template as unicode string.
+        """
+        vars = dict(*args, **kwargs)
+        try:
+            return concat(self.root_render_func(self.new_context(vars)))
+        except Exception:
+            exc_info = sys.exc_info()
+        return self.environment.handle_exception(exc_info, True)
+
+    def stream(self, *args, **kwargs):
+        """Works exactly like :meth:`generate` but returns a
+        :class:`TemplateStream`.
+        """
+        return TemplateStream(self.generate(*args, **kwargs))
+
+    def generate(self, *args, **kwargs):
+        """For very large templates it can be useful to not render the whole
+        template at once but evaluate each statement after another and yield
+        piece for piece.  This method basically does exactly that and returns
+        a generator that yields one item after another as unicode strings.
+
+        It accepts the same arguments as :meth:`render`.
+        """
+        vars = dict(*args, **kwargs)
+        try:
+            for event in self.root_render_func(self.new_context(vars)):
+                yield event
+        except Exception:
+            exc_info = sys.exc_info()
+        else:
+            return
+        yield self.environment.handle_exception(exc_info, True)
+
+    def new_context(self, vars=None, shared=False, locals=None):
+        """Create a new :class:`Context` for this template.  The vars
+        provided will be passed to the template.  Per default the globals
+        are added to the context.  If shared is set to `True` the data
+        is passed as it to the context without adding the globals.
+
+        `locals` can be a dict of local variables for internal usage.
+        """
+        return new_context(self.environment, self.name, self.blocks,
+                           vars, shared, self.globals, locals)
+
+    def make_module(self, vars=None, shared=False, locals=None):
+        """This method works like the :attr:`module` attribute when called
+        without arguments but it will evaluate the template on every call
+        rather than caching it.  It's also possible to provide
+        a dict which is then used as context.  The arguments are the same
+        as for the :meth:`new_context` method.
+        """
+        return TemplateModule(self, self.new_context(vars, shared, locals))
+
+    @property
+    def module(self):
+        """The template as module.  This is used for imports in the
+        template runtime but is also useful if one wants to access
+        exported template variables from the Python layer:
+
+        >>> t = Template('{% macro foo() %}42{% endmacro %}23')
+        >>> unicode(t.module)
+        u'23'
+        >>> t.module.foo()
+        u'42'
+        """
+        if self._module is not None:
+            return self._module
+        self._module = rv = self.make_module()
+        return rv
+
+    def get_corresponding_lineno(self, lineno):
+        """Return the source line number of a line number in the
+        generated bytecode as they are not in sync.
+        """
+        for template_line, code_line in reversed(self.debug_info):
+            if code_line <= lineno:
+                return template_line
+        return 1
+
+    @property
+    def is_up_to_date(self):
+        """If this variable is `False` there is a newer version available."""
+        if self._uptodate is None:
+            return True
+        return self._uptodate()
+
+    @property
+    def debug_info(self):
+        """The debug info mapping."""
+        return [tuple(map(int, x.split('='))) for x in
+                self._debug_info.split('&')]
+
+    def __repr__(self):
+        if self.name is None:
+            name = 'memory:%x' % id(self)
+        else:
+            name = repr(self.name)
+        return '<%s %s>' % (self.__class__.__name__, name)
+
+
+class TemplateModule(object):
+    """Represents an imported template.  All the exported names of the
+    template are available as attributes on this object.  Additionally
+    converting it into an unicode- or bytestrings renders the contents.
+    """
+
+    def __init__(self, template, context):
+        self._body_stream = list(template.root_render_func(context))
+        self.__dict__.update(context.get_exported())
+        self.__name__ = template.name
+
+    def __html__(self):
+        return Markup(concat(self._body_stream))
+
+    def __str__(self):
+        return unicode(self).encode('utf-8')
+
+    # unicode goes after __str__ because we configured 2to3 to rename
+    # __unicode__ to __str__.  because the 2to3 tree is not designed to
+    # remove nodes from it, we leave the above __str__ around and let
+    # it override at runtime.
+    def __unicode__(self):
+        return concat(self._body_stream)
+
+    def __repr__(self):
+        if self.__name__ is None:
+            name = 'memory:%x' % id(self)
+        else:
+            name = repr(self.__name__)
+        return '<%s %s>' % (self.__class__.__name__, name)
+
+
+class TemplateExpression(object):
+    """The :meth:`jinja2.Environment.compile_expression` method returns an
+    instance of this object.  It encapsulates the expression-like access
+    to the template with an expression it wraps.
+    """
+
+    def __init__(self, template, undefined_to_none):
+        self._template = template
+        self._undefined_to_none = undefined_to_none
+
+    def __call__(self, *args, **kwargs):
+        context = self._template.new_context(dict(*args, **kwargs))
+        consume(self._template.root_render_func(context))
+        rv = context.vars['result']
+        if self._undefined_to_none and isinstance(rv, Undefined):
+            rv = None
+        return rv
+
+
+class TemplateStream(object):
+    """A template stream works pretty much like an ordinary python generator
+    but it can buffer multiple items to reduce the number of total iterations.
+    Per default the output is unbuffered which means that for every unbuffered
+    instruction in the template one unicode string is yielded.
+
+    If buffering is enabled with a buffer size of 5, five items are combined
+    into a new unicode string.  This is mainly useful if you are streaming
+    big templates to a client via WSGI which flushes after each iteration.
+    """
+
+    def __init__(self, gen):
+        self._gen = gen
+        self.disable_buffering()
+
+    def dump(self, fp, encoding=None, errors='strict'):
+        """Dump the complete stream into a file or file-like object.
+        Per default unicode strings are written, if you want to encode
+        before writing specifiy an `encoding`.
+
+        Example usage::
+
+            Template('Hello {{ name }}!').stream(name='foo').dump('hello.html')
+        """
+        close = False
+        if isinstance(fp, basestring):
+            fp = file(fp, 'w')
+            close = True
+        try:
+            if encoding is not None:
+                iterable = (x.encode(encoding, errors) for x in self)
+            else:
+                iterable = self
+            if hasattr(fp, 'writelines'):
+                fp.writelines(iterable)
+            else:
+                for item in iterable:
+                    fp.write(item)
+        finally:
+            if close:
+                fp.close()
+
+    def disable_buffering(self):
+        """Disable the output buffering."""
+        self._next = self._gen.next
+        self.buffered = False
+
+    def enable_buffering(self, size=5):
+        """Enable buffering.  Buffer `size` items before yielding them."""
+        if size <= 1:
+            raise ValueError('buffer size too small')
+
+        def generator(next):
+            buf = []
+            c_size = 0
+            push = buf.append
+
+            while 1:
+                try:
+                    while c_size < size:
+                        c = next()
+                        push(c)
+                        if c:
+                            c_size += 1
+                except StopIteration:
+                    if not c_size:
+                        return
+                yield concat(buf)
+                del buf[:]
+                c_size = 0
+
+        self.buffered = True
+        self._next = generator(self._gen.next).next
+
+    def __iter__(self):
+        return self
+
+    def next(self):
+        return self._next()
+
+
+# hook in default template class.  if anyone reads this comment: ignore that
+# it's possible to use custom templates ;-)
+Environment.template_class = Template
diff --git a/lib/jinja2/jinja2/exceptions.py b/lib/jinja2/jinja2/exceptions.py
new file mode 100644
index 0000000..771f6a8
--- /dev/null
+++ b/lib/jinja2/jinja2/exceptions.py
@@ -0,0 +1,143 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.exceptions
+    ~~~~~~~~~~~~~~~~~
+
+    Jinja exceptions.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+
+
+class TemplateError(Exception):
+    """Baseclass for all template errors."""
+
+    def __init__(self, message=None):
+        if message is not None:
+            message = unicode(message).encode('utf-8')
+        Exception.__init__(self, message)
+
+    @property
+    def message(self):
+        if self.args:
+            message = self.args[0]
+            if message is not None:
+                return message.decode('utf-8', 'replace')
+
+
+class TemplateNotFound(IOError, LookupError, TemplateError):
+    """Raised if a template does not exist."""
+
+    # looks weird, but removes the warning descriptor that just
+    # bogusly warns us about message being deprecated
+    message = None
+
+    def __init__(self, name, message=None):
+        IOError.__init__(self)
+        if message is None:
+            message = name
+        self.message = message
+        self.name = name
+        self.templates = [name]
+
+    def __str__(self):
+        return self.message.encode('utf-8')
+
+    # unicode goes after __str__ because we configured 2to3 to rename
+    # __unicode__ to __str__.  because the 2to3 tree is not designed to
+    # remove nodes from it, we leave the above __str__ around and let
+    # it override at runtime.
+    def __unicode__(self):
+        return self.message
+
+
+class TemplatesNotFound(TemplateNotFound):
+    """Like :class:`TemplateNotFound` but raised if multiple templates
+    are selected.  This is a subclass of :class:`TemplateNotFound`
+    exception, so just catching the base exception will catch both.
+
+    .. versionadded:: 2.2
+    """
+
+    def __init__(self, names=(), message=None):
+        if message is None:
+            message = u'non of the templates given were found: ' + \
+                      u', '.join(map(unicode, names))
+        TemplateNotFound.__init__(self, names and names[-1] or None, message)
+        self.templates = list(names)
+
+
+class TemplateSyntaxError(TemplateError):
+    """Raised to tell the user that there is a problem with the template."""
+
+    def __init__(self, message, lineno, name=None, filename=None):
+        TemplateError.__init__(self, message)
+        self.lineno = lineno
+        self.name = name
+        self.filename = filename
+        self.source = None
+
+        # this is set to True if the debug.translate_syntax_error
+        # function translated the syntax error into a new traceback
+        self.translated = False
+
+    def __str__(self):
+        return unicode(self).encode('utf-8')
+
+    # unicode goes after __str__ because we configured 2to3 to rename
+    # __unicode__ to __str__.  because the 2to3 tree is not designed to
+    # remove nodes from it, we leave the above __str__ around and let
+    # it override at runtime.
+    def __unicode__(self):
+        # for translated errors we only return the message
+        if self.translated:
+            return self.message
+
+        # otherwise attach some stuff
+        location = 'line %d' % self.lineno
+        name = self.filename or self.name
+        if name:
+            location = 'File "%s", %s' % (name, location)
+        lines = [self.message, '  ' + location]
+
+        # if the source is set, add the line to the output
+        if self.source is not None:
+            try:
+                line = self.source.splitlines()[self.lineno - 1]
+            except IndexError:
+                line = None
+            if line:
+                lines.append('    ' + line.strip())
+
+        return u'\n'.join(lines)
+
+
+class TemplateAssertionError(TemplateSyntaxError):
+    """Like a template syntax error, but covers cases where something in the
+    template caused an error at compile time that wasn't necessarily caused
+    by a syntax error.  However it's a direct subclass of
+    :exc:`TemplateSyntaxError` and has the same attributes.
+    """
+
+
+class TemplateRuntimeError(TemplateError):
+    """A generic runtime error in the template engine.  Under some situations
+    Jinja may raise this exception.
+    """
+
+
+class UndefinedError(TemplateRuntimeError):
+    """Raised if a template tries to operate on :class:`Undefined`."""
+
+
+class SecurityError(TemplateRuntimeError):
+    """Raised if a template tries to do something insecure if the
+    sandbox is enabled.
+    """
+
+
+class FilterArgumentError(TemplateRuntimeError):
+    """This error is raised if a filter was called with inappropriate
+    arguments
+    """
diff --git a/lib/jinja2/jinja2/ext.py b/lib/jinja2/jinja2/ext.py
new file mode 100644
index 0000000..5ba6efd
--- /dev/null
+++ b/lib/jinja2/jinja2/ext.py
@@ -0,0 +1,612 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.ext
+    ~~~~~~~~~~
+
+    Jinja extensions allow to add custom tags similar to the way django custom
+    tags work.  By default two example extensions exist: an i18n and a cache
+    extension.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD.
+"""
+from collections import deque
+from jinja2 import nodes
+from jinja2.defaults import *
+from jinja2.environment import Environment
+from jinja2.runtime import Undefined, concat
+from jinja2.exceptions import TemplateAssertionError, TemplateSyntaxError
+from jinja2.utils import contextfunction, import_string, Markup, next
+
+
+# the only real useful gettext functions for a Jinja template.  Note
+# that ugettext must be assigned to gettext as Jinja doesn't support
+# non unicode strings.
+GETTEXT_FUNCTIONS = ('_', 'gettext', 'ngettext')
+
+
+class ExtensionRegistry(type):
+    """Gives the extension an unique identifier."""
+
+    def __new__(cls, name, bases, d):
+        rv = type.__new__(cls, name, bases, d)
+        rv.identifier = rv.__module__ + '.' + rv.__name__
+        return rv
+
+
+class Extension(object):
+    """Extensions can be used to add extra functionality to the Jinja template
+    system at the parser level.  Custom extensions are bound to an environment
+    but may not store environment specific data on `self`.  The reason for
+    this is that an extension can be bound to another environment (for
+    overlays) by creating a copy and reassigning the `environment` attribute.
+
+    As extensions are created by the environment they cannot accept any
+    arguments for configuration.  One may want to work around that by using
+    a factory function, but that is not possible as extensions are identified
+    by their import name.  The correct way to configure the extension is
+    storing the configuration values on the environment.  Because this way the
+    environment ends up acting as central configuration storage the
+    attributes may clash which is why extensions have to ensure that the names
+    they choose for configuration are not too generic.  ``prefix`` for example
+    is a terrible name, ``fragment_cache_prefix`` on the other hand is a good
+    name as includes the name of the extension (fragment cache).
+    """
+    __metaclass__ = ExtensionRegistry
+
+    #: if this extension parses this is the list of tags it's listening to.
+    tags = set()
+
+    #: the priority of that extension.  This is especially useful for
+    #: extensions that preprocess values.  A lower value means higher
+    #: priority.
+    #:
+    #: .. versionadded:: 2.4
+    priority = 100
+
+    def __init__(self, environment):
+        self.environment = environment
+
+    def bind(self, environment):
+        """Create a copy of this extension bound to another environment."""
+        rv = object.__new__(self.__class__)
+        rv.__dict__.update(self.__dict__)
+        rv.environment = environment
+        return rv
+
+    def preprocess(self, source, name, filename=None):
+        """This method is called before the actual lexing and can be used to
+        preprocess the source.  The `filename` is optional.  The return value
+        must be the preprocessed source.
+        """
+        return source
+
+    def filter_stream(self, stream):
+        """It's passed a :class:`~jinja2.lexer.TokenStream` that can be used
+        to filter tokens returned.  This method has to return an iterable of
+        :class:`~jinja2.lexer.Token`\s, but it doesn't have to return a
+        :class:`~jinja2.lexer.TokenStream`.
+
+        In the `ext` folder of the Jinja2 source distribution there is a file
+        called `inlinegettext.py` which implements a filter that utilizes this
+        method.
+        """
+        return stream
+
+    def parse(self, parser):
+        """If any of the :attr:`tags` matched this method is called with the
+        parser as first argument.  The token the parser stream is pointing at
+        is the name token that matched.  This method has to return one or a
+        list of multiple nodes.
+        """
+        raise NotImplementedError()
+
+    def attr(self, name, lineno=None):
+        """Return an attribute node for the current extension.  This is useful
+        to pass constants on extensions to generated template code.
+
+        ::
+
+            self.attr('_my_attribute', lineno=lineno)
+        """
+        return nodes.ExtensionAttribute(self.identifier, name, lineno=lineno)
+
+    def call_method(self, name, args=None, kwargs=None, dyn_args=None,
+                    dyn_kwargs=None, lineno=None):
+        """Call a method of the extension.  This is a shortcut for
+        :meth:`attr` + :class:`jinja2.nodes.Call`.
+        """
+        if args is None:
+            args = []
+        if kwargs is None:
+            kwargs = []
+        return nodes.Call(self.attr(name, lineno=lineno), args, kwargs,
+                          dyn_args, dyn_kwargs, lineno=lineno)
+
+
+@contextfunction
+def _gettext_alias(__context, *args, **kwargs):
+    return __context.call(__context.resolve('gettext'), *args, **kwargs)
+
+
+def _make_new_gettext(func):
+    @contextfunction
+    def gettext(__context, __string, **variables):
+        rv = __context.call(func, __string)
+        if __context.eval_ctx.autoescape:
+            rv = Markup(rv)
+        return rv % variables
+    return gettext
+
+
+def _make_new_ngettext(func):
+    @contextfunction
+    def ngettext(__context, __singular, __plural, __num, **variables):
+        variables.setdefault('num', __num)
+        rv = __context.call(func, __singular, __plural, __num)
+        if __context.eval_ctx.autoescape:
+            rv = Markup(rv)
+        return rv % variables
+    return ngettext
+
+
+class InternationalizationExtension(Extension):
+    """This extension adds gettext support to Jinja2."""
+    tags = set(['trans'])
+
+    # TODO: the i18n extension is currently reevaluating values in a few
+    # situations.  Take this example:
+    #   {% trans count=something() %}{{ count }} foo{% pluralize
+    #     %}{{ count }} fooss{% endtrans %}
+    # something is called twice here.  One time for the gettext value and
+    # the other time for the n-parameter of the ngettext function.
+
+    def __init__(self, environment):
+        Extension.__init__(self, environment)
+        environment.globals['_'] = _gettext_alias
+        environment.extend(
+            install_gettext_translations=self._install,
+            install_null_translations=self._install_null,
+            install_gettext_callables=self._install_callables,
+            uninstall_gettext_translations=self._uninstall,
+            extract_translations=self._extract,
+            newstyle_gettext=False
+        )
+
+    def _install(self, translations, newstyle=None):
+        gettext = getattr(translations, 'ugettext', None)
+        if gettext is None:
+            gettext = translations.gettext
+        ngettext = getattr(translations, 'ungettext', None)
+        if ngettext is None:
+            ngettext = translations.ngettext
+        self._install_callables(gettext, ngettext, newstyle)
+
+    def _install_null(self, newstyle=None):
+        self._install_callables(
+            lambda x: x,
+            lambda s, p, n: (n != 1 and (p,) or (s,))[0],
+            newstyle
+        )
+
+    def _install_callables(self, gettext, ngettext, newstyle=None):
+        if newstyle is not None:
+            self.environment.newstyle_gettext = newstyle
+        if self.environment.newstyle_gettext:
+            gettext = _make_new_gettext(gettext)
+            ngettext = _make_new_ngettext(ngettext)
+        self.environment.globals.update(
+            gettext=gettext,
+            ngettext=ngettext
+        )
+
+    def _uninstall(self, translations):
+        for key in 'gettext', 'ngettext':
+            self.environment.globals.pop(key, None)
+
+    def _extract(self, source, gettext_functions=GETTEXT_FUNCTIONS):
+        if isinstance(source, basestring):
+            source = self.environment.parse(source)
+        return extract_from_ast(source, gettext_functions)
+
+    def parse(self, parser):
+        """Parse a translatable tag."""
+        lineno = next(parser.stream).lineno
+        num_called_num = False
+
+        # find all the variables referenced.  Additionally a variable can be
+        # defined in the body of the trans block too, but this is checked at
+        # a later state.
+        plural_expr = None
+        variables = {}
+        while parser.stream.current.type != 'block_end':
+            if variables:
+                parser.stream.expect('comma')
+
+            # skip colon for python compatibility
+            if parser.stream.skip_if('colon'):
+                break
+
+            name = parser.stream.expect('name')
+            if name.value in variables:
+                parser.fail('translatable variable %r defined twice.' %
+                            name.value, name.lineno,
+                            exc=TemplateAssertionError)
+
+            # expressions
+            if parser.stream.current.type == 'assign':
+                next(parser.stream)
+                variables[name.value] = var = parser.parse_expression()
+            else:
+                variables[name.value] = var = nodes.Name(name.value, 'load')
+
+            if plural_expr is None:
+                plural_expr = var
+                num_called_num = name.value == 'num'
+
+        parser.stream.expect('block_end')
+
+        plural = plural_names = None
+        have_plural = False
+        referenced = set()
+
+        # now parse until endtrans or pluralize
+        singular_names, singular = self._parse_block(parser, True)
+        if singular_names:
+            referenced.update(singular_names)
+            if plural_expr is None:
+                plural_expr = nodes.Name(singular_names[0], 'load')
+                num_called_num = singular_names[0] == 'num'
+
+        # if we have a pluralize block, we parse that too
+        if parser.stream.current.test('name:pluralize'):
+            have_plural = True
+            next(parser.stream)
+            if parser.stream.current.type != 'block_end':
+                name = parser.stream.expect('name')
+                if name.value not in variables:
+                    parser.fail('unknown variable %r for pluralization' %
+                                name.value, name.lineno,
+                                exc=TemplateAssertionError)
+                plural_expr = variables[name.value]
+                num_called_num = name.value == 'num'
+            parser.stream.expect('block_end')
+            plural_names, plural = self._parse_block(parser, False)
+            next(parser.stream)
+            referenced.update(plural_names)
+        else:
+            next(parser.stream)
+
+        # register free names as simple name expressions
+        for var in referenced:
+            if var not in variables:
+                variables[var] = nodes.Name(var, 'load')
+
+        if not have_plural:
+            plural_expr = None
+        elif plural_expr is None:
+            parser.fail('pluralize without variables', lineno)
+
+        node = self._make_node(singular, plural, variables, plural_expr,
+                               bool(referenced),
+                               num_called_num and have_plural)
+        node.set_lineno(lineno)
+        return node
+
+    def _parse_block(self, parser, allow_pluralize):
+        """Parse until the next block tag with a given name."""
+        referenced = []
+        buf = []
+        while 1:
+            if parser.stream.current.type == 'data':
+                buf.append(parser.stream.current.value.replace('%', '%%'))
+                next(parser.stream)
+            elif parser.stream.current.type == 'variable_begin':
+                next(parser.stream)
+                name = parser.stream.expect('name').value
+                referenced.append(name)
+                buf.append('%%(%s)s' % name)
+                parser.stream.expect('variable_end')
+            elif parser.stream.current.type == 'block_begin':
+                next(parser.stream)
+                if parser.stream.current.test('name:endtrans'):
+                    break
+                elif parser.stream.current.test('name:pluralize'):
+                    if allow_pluralize:
+                        break
+                    parser.fail('a translatable section can have only one '
+                                'pluralize section')
+                parser.fail('control structures in translatable sections are '
+                            'not allowed')
+            elif parser.stream.eos:
+                parser.fail('unclosed translation block')
+            else:
+                assert False, 'internal parser error'
+
+        return referenced, concat(buf)
+
+    def _make_node(self, singular, plural, variables, plural_expr,
+                   vars_referenced, num_called_num):
+        """Generates a useful node from the data provided."""
+        # no variables referenced?  no need to escape for old style
+        # gettext invocations only if there are vars.
+        if not vars_referenced and not self.environment.newstyle_gettext:
+            singular = singular.replace('%%', '%')
+            if plural:
+                plural = plural.replace('%%', '%')
+
+        # singular only:
+        if plural_expr is None:
+            gettext = nodes.Name('gettext', 'load')
+            node = nodes.Call(gettext, [nodes.Const(singular)],
+                              [], None, None)
+
+        # singular and plural
+        else:
+            ngettext = nodes.Name('ngettext', 'load')
+            node = nodes.Call(ngettext, [
+                nodes.Const(singular),
+                nodes.Const(plural),
+                plural_expr
+            ], [], None, None)
+
+        # in case newstyle gettext is used, the method is powerful
+        # enough to handle the variable expansion and autoescape
+        # handling itself
+        if self.environment.newstyle_gettext:
+            for key, value in variables.iteritems():
+                # the function adds that later anyways in case num was
+                # called num, so just skip it.
+                if num_called_num and key == 'num':
+                    continue
+                node.kwargs.append(nodes.Keyword(key, value))
+
+        # otherwise do that here
+        else:
+            # mark the return value as safe if we are in an
+            # environment with autoescaping turned on
+            node = nodes.MarkSafeIfAutoescape(node)
+            if variables:
+                node = nodes.Mod(node, nodes.Dict([
+                    nodes.Pair(nodes.Const(key), value)
+                    for key, value in variables.items()
+                ]))
+        return nodes.Output([node])
+
+
+class ExprStmtExtension(Extension):
+    """Adds a `do` tag to Jinja2 that works like the print statement just
+    that it doesn't print the return value.
+    """
+    tags = set(['do'])
+
+    def parse(self, parser):
+        node = nodes.ExprStmt(lineno=next(parser.stream).lineno)
+        node.node = parser.parse_tuple()
+        return node
+
+
+class LoopControlExtension(Extension):
+    """Adds break and continue to the template engine."""
+    tags = set(['break', 'continue'])
+
+    def parse(self, parser):
+        token = next(parser.stream)
+        if token.value == 'break':
+            return nodes.Break(lineno=token.lineno)
+        return nodes.Continue(lineno=token.lineno)
+
+
+class WithExtension(Extension):
+    """Adds support for a django-like with block."""
+    tags = set(['with'])
+
+    def parse(self, parser):
+        node = nodes.Scope(lineno=next(parser.stream).lineno)
+        assignments = []
+        while parser.stream.current.type != 'block_end':
+            lineno = parser.stream.current.lineno
+            if assignments:
+                parser.stream.expect('comma')
+            target = parser.parse_assign_target()
+            parser.stream.expect('assign')
+            expr = parser.parse_expression()
+            assignments.append(nodes.Assign(target, expr, lineno=lineno))
+        node.body = assignments + \
+            list(parser.parse_statements(('name:endwith',),
+                                         drop_needle=True))
+        return node
+
+
+class AutoEscapeExtension(Extension):
+    """Changes auto escape rules for a scope."""
+    tags = set(['autoescape'])
+
+    def parse(self, parser):
+        node = nodes.ScopedEvalContextModifier(lineno=next(parser.stream).lineno)
+        node.options = [
+            nodes.Keyword('autoescape', parser.parse_expression())
+        ]
+        node.body = parser.parse_statements(('name:endautoescape',),
+                                            drop_needle=True)
+        return nodes.Scope([node])
+
+
+def extract_from_ast(node, gettext_functions=GETTEXT_FUNCTIONS,
+                     babel_style=True):
+    """Extract localizable strings from the given template node.  Per
+    default this function returns matches in babel style that means non string
+    parameters as well as keyword arguments are returned as `None`.  This
+    allows Babel to figure out what you really meant if you are using
+    gettext functions that allow keyword arguments for placeholder expansion.
+    If you don't want that behavior set the `babel_style` parameter to `False`
+    which causes only strings to be returned and parameters are always stored
+    in tuples.  As a consequence invalid gettext calls (calls without a single
+    string parameter or string parameters after non-string parameters) are
+    skipped.
+
+    This example explains the behavior:
+
+    >>> from jinja2 import Environment
+    >>> env = Environment()
+    >>> node = env.parse('{{ (_("foo"), _(), ngettext("foo", "bar", 42)) }}')
+    >>> list(extract_from_ast(node))
+    [(1, '_', 'foo'), (1, '_', ()), (1, 'ngettext', ('foo', 'bar', None))]
+    >>> list(extract_from_ast(node, babel_style=False))
+    [(1, '_', ('foo',)), (1, 'ngettext', ('foo', 'bar'))]
+
+    For every string found this function yields a ``(lineno, function,
+    message)`` tuple, where:
+
+    * ``lineno`` is the number of the line on which the string was found,
+    * ``function`` is the name of the ``gettext`` function used (if the
+      string was extracted from embedded Python code), and
+    *  ``message`` is the string itself (a ``unicode`` object, or a tuple
+       of ``unicode`` objects for functions with multiple string arguments).
+
+    This extraction function operates on the AST and is because of that unable
+    to extract any comments.  For comment support you have to use the babel
+    extraction interface or extract comments yourself.
+    """
+    for node in node.find_all(nodes.Call):
+        if not isinstance(node.node, nodes.Name) or \
+           node.node.name not in gettext_functions:
+            continue
+
+        strings = []
+        for arg in node.args:
+            if isinstance(arg, nodes.Const) and \
+               isinstance(arg.value, basestring):
+                strings.append(arg.value)
+            else:
+                strings.append(None)
+
+        for arg in node.kwargs:
+            strings.append(None)
+        if node.dyn_args is not None:
+            strings.append(None)
+        if node.dyn_kwargs is not None:
+            strings.append(None)
+
+        if not babel_style:
+            strings = tuple(x for x in strings if x is not None)
+            if not strings:
+                continue
+        else:
+            if len(strings) == 1:
+                strings = strings[0]
+            else:
+                strings = tuple(strings)
+        yield node.lineno, node.node.name, strings
+
+
+class _CommentFinder(object):
+    """Helper class to find comments in a token stream.  Can only
+    find comments for gettext calls forwards.  Once the comment
+    from line 4 is found, a comment for line 1 will not return a
+    usable value.
+    """
+
+    def __init__(self, tokens, comment_tags):
+        self.tokens = tokens
+        self.comment_tags = comment_tags
+        self.offset = 0
+        self.last_lineno = 0
+
+    def find_backwards(self, offset):
+        try:
+            for _, token_type, token_value in \
+                    reversed(self.tokens[self.offset:offset]):
+                if token_type in ('comment', 'linecomment'):
+                    try:
+                        prefix, comment = token_value.split(None, 1)
+                    except ValueError:
+                        continue
+                    if prefix in self.comment_tags:
+                        return [comment.rstrip()]
+            return []
+        finally:
+            self.offset = offset
+
+    def find_comments(self, lineno):
+        if not self.comment_tags or self.last_lineno > lineno:
+            return []
+        for idx, (token_lineno, _, _) in enumerate(self.tokens[self.offset:]):
+            if token_lineno > lineno:
+                return self.find_backwards(self.offset + idx)
+        return self.find_backwards(len(self.tokens))
+
+
+def babel_extract(fileobj, keywords, comment_tags, options):
+    """Babel extraction method for Jinja templates.
+
+    .. versionchanged:: 2.3
+       Basic support for translation comments was added.  If `comment_tags`
+       is now set to a list of keywords for extraction, the extractor will
+       try to find the best preceeding comment that begins with one of the
+       keywords.  For best results, make sure to not have more than one
+       gettext call in one line of code and the matching comment in the
+       same line or the line before.
+
+    .. versionchanged:: 2.5.1
+       The `newstyle_gettext` flag can be set to `True` to enable newstyle
+       gettext calls.
+
+    :param fileobj: the file-like object the messages should be extracted from
+    :param keywords: a list of keywords (i.e. function names) that should be
+                     recognized as translation functions
+    :param comment_tags: a list of translator tags to search for and include
+                         in the results.
+    :param options: a dictionary of additional options (optional)
+    :return: an iterator over ``(lineno, funcname, message, comments)`` tuples.
+             (comments will be empty currently)
+    """
+    extensions = set()
+    for extension in options.get('extensions', '').split(','):
+        extension = extension.strip()
+        if not extension:
+            continue
+        extensions.add(import_string(extension))
+    if InternationalizationExtension not in extensions:
+        extensions.add(InternationalizationExtension)
+
+    def getbool(options, key, default=False):
+        options.get(key, str(default)).lower() in ('1', 'on', 'yes', 'true')
+
+    environment = Environment(
+        options.get('block_start_string', BLOCK_START_STRING),
+        options.get('block_end_string', BLOCK_END_STRING),
+        options.get('variable_start_string', VARIABLE_START_STRING),
+        options.get('variable_end_string', VARIABLE_END_STRING),
+        options.get('comment_start_string', COMMENT_START_STRING),
+        options.get('comment_end_string', COMMENT_END_STRING),
+        options.get('line_statement_prefix') or LINE_STATEMENT_PREFIX,
+        options.get('line_comment_prefix') or LINE_COMMENT_PREFIX,
+        getbool(options, 'trim_blocks', TRIM_BLOCKS),
+        NEWLINE_SEQUENCE, frozenset(extensions),
+        cache_size=0,
+        auto_reload=False
+    )
+
+    if getbool(options, 'newstyle_gettext'):
+        environment.newstyle_gettext = True
+
+    source = fileobj.read().decode(options.get('encoding', 'utf-8'))
+    try:
+        node = environment.parse(source)
+        tokens = list(environment.lex(environment.preprocess(source)))
+    except TemplateSyntaxError, e:
+        # skip templates with syntax errors
+        return
+
+    finder = _CommentFinder(tokens, comment_tags)
+    for lineno, func, message in extract_from_ast(node, keywords):
+        yield lineno, func, message, finder.find_comments(lineno)
+
+
+#: nicer import names
+i18n = InternationalizationExtension
+do = ExprStmtExtension
+loopcontrols = LoopControlExtension
+with_ = WithExtension
+autoescape = AutoEscapeExtension
diff --git a/lib/jinja2/jinja2/filters.py b/lib/jinja2/jinja2/filters.py
new file mode 100644
index 0000000..1ef47f9
--- /dev/null
+++ b/lib/jinja2/jinja2/filters.py
@@ -0,0 +1,801 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.filters
+    ~~~~~~~~~~~~~~
+
+    Bundled jinja filters.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import re
+import math
+from random import choice
+from operator import itemgetter
+from itertools import imap, groupby
+from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode
+from jinja2.runtime import Undefined
+from jinja2.exceptions import FilterArgumentError, SecurityError
+
+
+_word_re = re.compile(r'\w+(?u)')
+
+
+def contextfilter(f):
+    """Decorator for marking context dependent filters. The current
+    :class:`Context` will be passed as first argument.
+    """
+    f.contextfilter = True
+    return f
+
+
+def evalcontextfilter(f):
+    """Decorator for marking eval-context dependent filters.  An eval
+    context object is passed as first argument.  For more information
+    about the eval context, see :ref:`eval-context`.
+
+    .. versionadded:: 2.4
+    """
+    f.evalcontextfilter = True
+    return f
+
+
+def environmentfilter(f):
+    """Decorator for marking evironment dependent filters.  The current
+    :class:`Environment` is passed to the filter as first argument.
+    """
+    f.environmentfilter = True
+    return f
+
+
+def make_attrgetter(environment, attribute):
+    """Returns a callable that looks up the given attribute from a
+    passed object with the rules of the environment.  Dots are allowed
+    to access attributes of attributes.
+    """
+    if not isinstance(attribute, basestring) or '.' not in attribute:
+        return lambda x: environment.getitem(x, attribute)
+    attribute = attribute.split('.')
+    def attrgetter(item):
+        for part in attribute:
+            item = environment.getitem(item, part)
+        return item
+    return attrgetter
+
+
+def do_forceescape(value):
+    """Enforce HTML escaping.  This will probably double escape variables."""
+    if hasattr(value, '__html__'):
+        value = value.__html__()
+    return escape(unicode(value))
+
+
+@evalcontextfilter
+def do_replace(eval_ctx, s, old, new, count=None):
+    """Return a copy of the value with all occurrences of a substring
+    replaced with a new one. The first argument is the substring
+    that should be replaced, the second is the replacement string.
+    If the optional third argument ``count`` is given, only the first
+    ``count`` occurrences are replaced:
+
+    .. sourcecode:: jinja
+
+        {{ "Hello World"|replace("Hello", "Goodbye") }}
+            -> Goodbye World
+
+        {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
+            -> d'oh, d'oh, aaargh
+    """
+    if count is None:
+        count = -1
+    if not eval_ctx.autoescape:
+        return unicode(s).replace(unicode(old), unicode(new), count)
+    if hasattr(old, '__html__') or hasattr(new, '__html__') and \
+       not hasattr(s, '__html__'):
+        s = escape(s)
+    else:
+        s = soft_unicode(s)
+    return s.replace(soft_unicode(old), soft_unicode(new), count)
+
+
+def do_upper(s):
+    """Convert a value to uppercase."""
+    return soft_unicode(s).upper()
+
+
+def do_lower(s):
+    """Convert a value to lowercase."""
+    return soft_unicode(s).lower()
+
+
+@evalcontextfilter
+def do_xmlattr(_eval_ctx, d, autospace=True):
+    """Create an SGML/XML attribute string based on the items in a dict.
+    All values that are neither `none` nor `undefined` are automatically
+    escaped:
+
+    .. sourcecode:: html+jinja
+
+        <ul{{ {'class': 'my_list', 'missing': none,
+                'id': 'list-%d'|format(variable)}|xmlattr }}>
+        ...
+        </ul>
+
+    Results in something like this:
+
+    .. sourcecode:: html
+
+        <ul class="my_list" id="list-42">
+        ...
+        </ul>
+
+    As you can see it automatically prepends a space in front of the item
+    if the filter returned something unless the second parameter is false.
+    """
+    rv = u' '.join(
+        u'%s="%s"' % (escape(key), escape(value))
+        for key, value in d.iteritems()
+        if value is not None and not isinstance(value, Undefined)
+    )
+    if autospace and rv:
+        rv = u' ' + rv
+    if _eval_ctx.autoescape:
+        rv = Markup(rv)
+    return rv
+
+
+def do_capitalize(s):
+    """Capitalize a value. The first character will be uppercase, all others
+    lowercase.
+    """
+    return soft_unicode(s).capitalize()
+
+
+def do_title(s):
+    """Return a titlecased version of the value. I.e. words will start with
+    uppercase letters, all remaining characters are lowercase.
+    """
+    return soft_unicode(s).title()
+
+
+def do_dictsort(value, case_sensitive=False, by='key'):
+    """Sort a dict and yield (key, value) pairs. Because python dicts are
+    unsorted you may want to use this function to order them by either
+    key or value:
+
+    .. sourcecode:: jinja
+
+        {% for item in mydict|dictsort %}
+            sort the dict by key, case insensitive
+
+        {% for item in mydict|dicsort(true) %}
+            sort the dict by key, case sensitive
+
+        {% for item in mydict|dictsort(false, 'value') %}
+            sort the dict by key, case insensitive, sorted
+            normally and ordered by value.
+    """
+    if by == 'key':
+        pos = 0
+    elif by == 'value':
+        pos = 1
+    else:
+        raise FilterArgumentError('You can only sort by either '
+                                  '"key" or "value"')
+    def sort_func(item):
+        value = item[pos]
+        if isinstance(value, basestring) and not case_sensitive:
+            value = value.lower()
+        return value
+
+    return sorted(value.items(), key=sort_func)
+
+
+@environmentfilter
+def do_sort(environment, value, reverse=False, case_sensitive=False,
+            attribute=None):
+    """Sort an iterable.  Per default it sorts ascending, if you pass it
+    true as first argument it will reverse the sorting.
+
+    If the iterable is made of strings the third parameter can be used to
+    control the case sensitiveness of the comparison which is disabled by
+    default.
+
+    .. sourcecode:: jinja
+
+        {% for item in iterable|sort %}
+            ...
+        {% endfor %}
+
+    It is also possible to sort by an attribute (for example to sort
+    by the date of an object) by specifying the `attribute` parameter:
+
+    .. sourcecode:: jinja
+
+        {% for item in iterable|sort(attribute='date') %}
+            ...
+        {% endfor %}
+
+    .. versionchanged:: 2.6
+       The `attribute` parameter was added.
+    """
+    if not case_sensitive:
+        def sort_func(item):
+            if isinstance(item, basestring):
+                item = item.lower()
+            return item
+    else:
+        sort_func = None
+    if attribute is not None:
+        getter = make_attrgetter(environment, attribute)
+        def sort_func(item, processor=sort_func or (lambda x: x)):
+            return processor(getter(item))
+    return sorted(value, key=sort_func, reverse=reverse)
+
+
+def do_default(value, default_value=u'', boolean=False):
+    """If the value is undefined it will return the passed default value,
+    otherwise the value of the variable:
+
+    .. sourcecode:: jinja
+
+        {{ my_variable|default('my_variable is not defined') }}
+
+    This will output the value of ``my_variable`` if the variable was
+    defined, otherwise ``'my_variable is not defined'``. If you want
+    to use default with variables that evaluate to false you have to
+    set the second parameter to `true`:
+
+    .. sourcecode:: jinja
+
+        {{ ''|default('the string was empty', true) }}
+    """
+    if (boolean and not value) or isinstance(value, Undefined):
+        return default_value
+    return value
+
+
+@evalcontextfilter
+def do_join(eval_ctx, value, d=u'', attribute=None):
+    """Return a string which is the concatenation of the strings in the
+    sequence. The separator between elements is an empty string per
+    default, you can define it with the optional parameter:
+
+    .. sourcecode:: jinja
+
+        {{ [1, 2, 3]|join('|') }}
+            -> 1|2|3
+
+        {{ [1, 2, 3]|join }}
+            -> 123
+
+    It is also possible to join certain attributes of an object:
+
+    .. sourcecode:: jinja
+
+        {{ users|join(', ', attribute='username') }}
+
+    .. versionadded:: 2.6
+       The `attribute` parameter was added.
+    """
+    if attribute is not None:
+        value = imap(make_attrgetter(eval_ctx.environment, attribute), value)
+
+    # no automatic escaping?  joining is a lot eaiser then
+    if not eval_ctx.autoescape:
+        return unicode(d).join(imap(unicode, value))
+
+    # if the delimiter doesn't have an html representation we check
+    # if any of the items has.  If yes we do a coercion to Markup
+    if not hasattr(d, '__html__'):
+        value = list(value)
+        do_escape = False
+        for idx, item in enumerate(value):
+            if hasattr(item, '__html__'):
+                do_escape = True
+            else:
+                value[idx] = unicode(item)
+        if do_escape:
+            d = escape(d)
+        else:
+            d = unicode(d)
+        return d.join(value)
+
+    # no html involved, to normal joining
+    return soft_unicode(d).join(imap(soft_unicode, value))
+
+
+def do_center(value, width=80):
+    """Centers the value in a field of a given width."""
+    return unicode(value).center(width)
+
+
+@environmentfilter
+def do_first(environment, seq):
+    """Return the first item of a sequence."""
+    try:
+        return iter(seq).next()
+    except StopIteration:
+        return environment.undefined('No first item, sequence was empty.')
+
+
+@environmentfilter
+def do_last(environment, seq):
+    """Return the last item of a sequence."""
+    try:
+        return iter(reversed(seq)).next()
+    except StopIteration:
+        return environment.undefined('No last item, sequence was empty.')
+
+
+@environmentfilter
+def do_random(environment, seq):
+    """Return a random item from the sequence."""
+    try:
+        return choice(seq)
+    except IndexError:
+        return environment.undefined('No random item, sequence was empty.')
+
+
+def do_filesizeformat(value, binary=False):
+    """Format the value like a 'human-readable' file size (i.e. 13 kB,
+    4.1 MB, 102 Bytes, etc).  Per default decimal prefixes are used (Mega,
+    Giga, etc.), if the second parameter is set to `True` the binary
+    prefixes are used (Mebi, Gibi).
+    """
+    bytes = float(value)
+    base = binary and 1024 or 1000
+    prefixes = [
+        (binary and "KiB" or "kB"),
+        (binary and "MiB" or "MB"),
+        (binary and "GiB" or "GB"),
+        (binary and "TiB" or "TB"),
+        (binary and "PiB" or "PB"),
+        (binary and "EiB" or "EB"),
+        (binary and "ZiB" or "ZB"),
+        (binary and "YiB" or "YB")
+    ]
+    if bytes == 1:
+        return "1 Byte"
+    elif bytes < base:
+        return "%d Bytes" % bytes
+    else:
+        for i, prefix in enumerate(prefixes):
+            unit = base * base ** (i + 1)
+            if bytes < unit:
+                return "%.1f %s" % ((bytes / unit), prefix)
+        return "%.1f %s" % ((bytes / unit), prefix)
+
+
+def do_pprint(value, verbose=False):
+    """Pretty print a variable. Useful for debugging.
+
+    With Jinja 1.2 onwards you can pass it a parameter.  If this parameter
+    is truthy the output will be more verbose (this requires `pretty`)
+    """
+    return pformat(value, verbose=verbose)
+
+
+@evalcontextfilter
+def do_urlize(eval_ctx, value, trim_url_limit=None, nofollow=False):
+    """Converts URLs in plain text into clickable links.
+
+    If you pass the filter an additional integer it will shorten the urls
+    to that number. Also a third argument exists that makes the urls
+    "nofollow":
+
+    .. sourcecode:: jinja
+
+        {{ mytext|urlize(40, true) }}
+            links are shortened to 40 chars and defined with rel="nofollow"
+    """
+    rv = urlize(value, trim_url_limit, nofollow)
+    if eval_ctx.autoescape:
+        rv = Markup(rv)
+    return rv
+
+
+def do_indent(s, width=4, indentfirst=False):
+    """Return a copy of the passed string, each line indented by
+    4 spaces. The first line is not indented. If you want to
+    change the number of spaces or indent the first line too
+    you can pass additional parameters to the filter:
+
+    .. sourcecode:: jinja
+
+        {{ mytext|indent(2, true) }}
+            indent by two spaces and indent the first line too.
+    """
+    indention = u' ' * width
+    rv = (u'\n' + indention).join(s.splitlines())
+    if indentfirst:
+        rv = indention + rv
+    return rv
+
+
+def do_truncate(s, length=255, killwords=False, end='...'):
+    """Return a truncated copy of the string. The length is specified
+    with the first parameter which defaults to ``255``. If the second
+    parameter is ``true`` the filter will cut the text at length. Otherwise
+    it will try to save the last word. If the text was in fact
+    truncated it will append an ellipsis sign (``"..."``). If you want a
+    different ellipsis sign than ``"..."`` you can specify it using the
+    third parameter.
+
+    .. sourcecode jinja::
+
+        {{ mytext|truncate(300, false, '&raquo;') }}
+            truncate mytext to 300 chars, don't split up words, use a
+            right pointing double arrow as ellipsis sign.
+    """
+    if len(s) <= length:
+        return s
+    elif killwords:
+        return s[:length] + end
+    words = s.split(' ')
+    result = []
+    m = 0
+    for word in words:
+        m += len(word) + 1
+        if m > length:
+            break
+        result.append(word)
+    result.append(end)
+    return u' '.join(result)
+
+@environmentfilter
+def do_wordwrap(environment, s, width=79, break_long_words=True):
+    """
+    Return a copy of the string passed to the filter wrapped after
+    ``79`` characters.  You can override this default using the first
+    parameter.  If you set the second parameter to `false` Jinja will not
+    split words apart if they are longer than `width`.
+    """
+    import textwrap
+    return environment.newline_sequence.join(textwrap.wrap(s, width=width, expand_tabs=False,
+                                   replace_whitespace=False,
+                                   break_long_words=break_long_words))
+
+
+def do_wordcount(s):
+    """Count the words in that string."""
+    return len(_word_re.findall(s))
+
+
+def do_int(value, default=0):
+    """Convert the value into an integer. If the
+    conversion doesn't work it will return ``0``. You can
+    override this default using the first parameter.
+    """
+    try:
+        return int(value)
+    except (TypeError, ValueError):
+        # this quirk is necessary so that "42.23"|int gives 42.
+        try:
+            return int(float(value))
+        except (TypeError, ValueError):
+            return default
+
+
+def do_float(value, default=0.0):
+    """Convert the value into a floating point number. If the
+    conversion doesn't work it will return ``0.0``. You can
+    override this default using the first parameter.
+    """
+    try:
+        return float(value)
+    except (TypeError, ValueError):
+        return default
+
+
+def do_format(value, *args, **kwargs):
+    """
+    Apply python string formatting on an object:
+
+    .. sourcecode:: jinja
+
+        {{ "%s - %s"|format("Hello?", "Foo!") }}
+            -> Hello? - Foo!
+    """
+    if args and kwargs:
+        raise FilterArgumentError('can\'t handle positional and keyword '
+                                  'arguments at the same time')
+    return soft_unicode(value) % (kwargs or args)
+
+
+def do_trim(value):
+    """Strip leading and trailing whitespace."""
+    return soft_unicode(value).strip()
+
+
+def do_striptags(value):
+    """Strip SGML/XML tags and replace adjacent whitespace by one space.
+    """
+    if hasattr(value, '__html__'):
+        value = value.__html__()
+    return Markup(unicode(value)).striptags()
+
+
+def do_slice(value, slices, fill_with=None):
+    """Slice an iterator and return a list of lists containing
+    those items. Useful if you want to create a div containing
+    three ul tags that represent columns:
+
+    .. sourcecode:: html+jinja
+
+        <div class="columwrapper">
+          {%- for column in items|slice(3) %}
+            <ul class="column-{{ loop.index }}">
+            {%- for item in column %}
+              <li>{{ item }}</li>
+            {%- endfor %}
+            </ul>
+          {%- endfor %}
+        </div>
+
+    If you pass it a second argument it's used to fill missing
+    values on the last iteration.
+    """
+    seq = list(value)
+    length = len(seq)
+    items_per_slice = length // slices
+    slices_with_extra = length % slices
+    offset = 0
+    for slice_number in xrange(slices):
+        start = offset + slice_number * items_per_slice
+        if slice_number < slices_with_extra:
+            offset += 1
+        end = offset + (slice_number + 1) * items_per_slice
+        tmp = seq[start:end]
+        if fill_with is not None and slice_number >= slices_with_extra:
+            tmp.append(fill_with)
+        yield tmp
+
+
+def do_batch(value, linecount, fill_with=None):
+    """
+    A filter that batches items. It works pretty much like `slice`
+    just the other way round. It returns a list of lists with the
+    given number of items. If you provide a second parameter this
+    is used to fill missing items. See this example:
+
+    .. sourcecode:: html+jinja
+
+        <table>
+        {%- for row in items|batch(3, '&nbsp;') %}
+          <tr>
+          {%- for column in row %}
+            <td>{{ column }}</td>
+          {%- endfor %}
+          </tr>
+        {%- endfor %}
+        </table>
+    """
+    result = []
+    tmp = []
+    for item in value:
+        if len(tmp) == linecount:
+            yield tmp
+            tmp = []
+        tmp.append(item)
+    if tmp:
+        if fill_with is not None and len(tmp) < linecount:
+            tmp += [fill_with] * (linecount - len(tmp))
+        yield tmp
+
+
+def do_round(value, precision=0, method='common'):
+    """Round the number to a given precision. The first
+    parameter specifies the precision (default is ``0``), the
+    second the rounding method:
+
+    - ``'common'`` rounds either up or down
+    - ``'ceil'`` always rounds up
+    - ``'floor'`` always rounds down
+
+    If you don't specify a method ``'common'`` is used.
+
+    .. sourcecode:: jinja
+
+        {{ 42.55|round }}
+            -> 43.0
+        {{ 42.55|round(1, 'floor') }}
+            -> 42.5
+
+    Note that even if rounded to 0 precision, a float is returned.  If
+    you need a real integer, pipe it through `int`:
+
+    .. sourcecode:: jinja
+
+        {{ 42.55|round|int }}
+            -> 43
+    """
+    if not method in ('common', 'ceil', 'floor'):
+        raise FilterArgumentError('method must be common, ceil or floor')
+    if method == 'common':
+        return round(value, precision)
+    func = getattr(math, method)
+    return func(value * (10 ** precision)) / (10 ** precision)
+
+
+@environmentfilter
+def do_groupby(environment, value, attribute):
+    """Group a sequence of objects by a common attribute.
+
+    If you for example have a list of dicts or objects that represent persons
+    with `gender`, `first_name` and `last_name` attributes and you want to
+    group all users by genders you can do something like the following
+    snippet:
+
+    .. sourcecode:: html+jinja
+
+        <ul>
+        {% for group in persons|groupby('gender') %}
+            <li>{{ group.grouper }}<ul>
+            {% for person in group.list %}
+                <li>{{ person.first_name }} {{ person.last_name }}</li>
+            {% endfor %}</ul></li>
+        {% endfor %}
+        </ul>
+
+    Additionally it's possible to use tuple unpacking for the grouper and
+    list:
+
+    .. sourcecode:: html+jinja
+
+        <ul>
+        {% for grouper, list in persons|groupby('gender') %}
+            ...
+        {% endfor %}
+        </ul>
+
+    As you can see the item we're grouping by is stored in the `grouper`
+    attribute and the `list` contains all the objects that have this grouper
+    in common.
+
+    .. versionchanged:: 2.6
+       It's now possible to use dotted notation to group by the child
+       attribute of another attribute.
+    """
+    expr = make_attrgetter(environment, attribute)
+    return sorted(map(_GroupTuple, groupby(sorted(value, key=expr), expr)))
+
+
+class _GroupTuple(tuple):
+    __slots__ = ()
+    grouper = property(itemgetter(0))
+    list = property(itemgetter(1))
+
+    def __new__(cls, (key, value)):
+        return tuple.__new__(cls, (key, list(value)))
+
+
+@environmentfilter
+def do_sum(environment, iterable, attribute=None, start=0):
+    """Returns the sum of a sequence of numbers plus the value of parameter
+    'start' (which defaults to 0).  When the sequence is empty it returns
+    start.
+
+    It is also possible to sum up only certain attributes:
+
+    .. sourcecode:: jinja
+
+        Total: {{ items|sum(attribute='price') }}
+
+    .. versionchanged:: 2.6
+       The `attribute` parameter was added to allow suming up over
+       attributes.  Also the `start` parameter was moved on to the right.
+    """
+    if attribute is not None:
+        iterable = imap(make_attrgetter(environment, attribute), iterable)
+    return sum(iterable, start)
+
+
+def do_list(value):
+    """Convert the value into a list.  If it was a string the returned list
+    will be a list of characters.
+    """
+    return list(value)
+
+
+def do_mark_safe(value):
+    """Mark the value as safe which means that in an environment with automatic
+    escaping enabled this variable will not be escaped.
+    """
+    return Markup(value)
+
+
+def do_mark_unsafe(value):
+    """Mark a value as unsafe.  This is the reverse operation for :func:`safe`."""
+    return unicode(value)
+
+
+def do_reverse(value):
+    """Reverse the object or return an iterator the iterates over it the other
+    way round.
+    """
+    if isinstance(value, basestring):
+        return value[::-1]
+    try:
+        return reversed(value)
+    except TypeError:
+        try:
+            rv = list(value)
+            rv.reverse()
+            return rv
+        except TypeError:
+            raise FilterArgumentError('argument must be iterable')
+
+
+@environmentfilter
+def do_attr(environment, obj, name):
+    """Get an attribute of an object.  ``foo|attr("bar")`` works like
+    ``foo["bar"]`` just that always an attribute is returned and items are not
+    looked up.
+
+    See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details.
+    """
+    try:
+        name = str(name)
+    except UnicodeError:
+        pass
+    else:
+        try:
+            value = getattr(obj, name)
+        except AttributeError:
+            pass
+        else:
+            if environment.sandboxed and not \
+               environment.is_safe_attribute(obj, name, value):
+                return environment.unsafe_undefined(obj, name)
+            return value
+    return environment.undefined(obj=obj, name=name)
+
+
+FILTERS = {
+    'attr':                 do_attr,
+    'replace':              do_replace,
+    'upper':                do_upper,
+    'lower':                do_lower,
+    'escape':               escape,
+    'e':                    escape,
+    'forceescape':          do_forceescape,
+    'capitalize':           do_capitalize,
+    'title':                do_title,
+    'default':              do_default,
+    'd':                    do_default,
+    'join':                 do_join,
+    'count':                len,
+    'dictsort':             do_dictsort,
+    'sort':                 do_sort,
+    'length':               len,
+    'reverse':              do_reverse,
+    'center':               do_center,
+    'indent':               do_indent,
+    'title':                do_title,
+    'capitalize':           do_capitalize,
+    'first':                do_first,
+    'last':                 do_last,
+    'random':               do_random,
+    'filesizeformat':       do_filesizeformat,
+    'pprint':               do_pprint,
+    'truncate':             do_truncate,
+    'wordwrap':             do_wordwrap,
+    'wordcount':            do_wordcount,
+    'int':                  do_int,
+    'float':                do_float,
+    'string':               soft_unicode,
+    'list':                 do_list,
+    'urlize':               do_urlize,
+    'format':               do_format,
+    'trim':                 do_trim,
+    'striptags':            do_striptags,
+    'slice':                do_slice,
+    'batch':                do_batch,
+    'sum':                  do_sum,
+    'abs':                  abs,
+    'round':                do_round,
+    'groupby':              do_groupby,
+    'safe':                 do_mark_safe,
+    'xmlattr':              do_xmlattr
+}
diff --git a/lib/jinja2/jinja2/lexer.py b/lib/jinja2/jinja2/lexer.py
new file mode 100644
index 0000000..0d3f696
--- /dev/null
+++ b/lib/jinja2/jinja2/lexer.py
@@ -0,0 +1,681 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.lexer
+    ~~~~~~~~~~~~
+
+    This module implements a Jinja / Python combination lexer. The
+    `Lexer` class provided by this module is used to do some preprocessing
+    for Jinja.
+
+    On the one hand it filters out invalid operators like the bitshift
+    operators we don't allow in templates. On the other hand it separates
+    template code and python code in expressions.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import re
+from operator import itemgetter
+from collections import deque
+from jinja2.exceptions import TemplateSyntaxError
+from jinja2.utils import LRUCache, next
+
+
+# cache for the lexers. Exists in order to be able to have multiple
+# environments with the same lexer
+_lexer_cache = LRUCache(50)
+
+# static regular expressions
+whitespace_re = re.compile(r'\s+', re.U)
+string_re = re.compile(r"('([^'\\]*(?:\\.[^'\\]*)*)'"
+                       r'|"([^"\\]*(?:\\.[^"\\]*)*)")', re.S)
+integer_re = re.compile(r'\d+')
+
+# we use the unicode identifier rule if this python version is able
+# to handle unicode identifiers, otherwise the standard ASCII one.
+try:
+    compile('föö', '<unknown>', 'eval')
+except SyntaxError:
+    name_re = re.compile(r'\b[a-zA-Z_][a-zA-Z0-9_]*\b')
+else:
+    from jinja2 import _stringdefs
+    name_re = re.compile(r'[%s][%s]*' % (_stringdefs.xid_start,
+                                         _stringdefs.xid_continue))
+
+float_re = re.compile(r'(?<!\.)\d+\.\d+')
+newline_re = re.compile(r'(\r\n|\r|\n)')
+
+# internal the tokens and keep references to them
+TOKEN_ADD = intern('add')
+TOKEN_ASSIGN = intern('assign')
+TOKEN_COLON = intern('colon')
+TOKEN_COMMA = intern('comma')
+TOKEN_DIV = intern('div')
+TOKEN_DOT = intern('dot')
+TOKEN_EQ = intern('eq')
+TOKEN_FLOORDIV = intern('floordiv')
+TOKEN_GT = intern('gt')
+TOKEN_GTEQ = intern('gteq')
+TOKEN_LBRACE = intern('lbrace')
+TOKEN_LBRACKET = intern('lbracket')
+TOKEN_LPAREN = intern('lparen')
+TOKEN_LT = intern('lt')
+TOKEN_LTEQ = intern('lteq')
+TOKEN_MOD = intern('mod')
+TOKEN_MUL = intern('mul')
+TOKEN_NE = intern('ne')
+TOKEN_PIPE = intern('pipe')
+TOKEN_POW = intern('pow')
+TOKEN_RBRACE = intern('rbrace')
+TOKEN_RBRACKET = intern('rbracket')
+TOKEN_RPAREN = intern('rparen')
+TOKEN_SEMICOLON = intern('semicolon')
+TOKEN_SUB = intern('sub')
+TOKEN_TILDE = intern('tilde')
+TOKEN_WHITESPACE = intern('whitespace')
+TOKEN_FLOAT = intern('float')
+TOKEN_INTEGER = intern('integer')
+TOKEN_NAME = intern('name')
+TOKEN_STRING = intern('string')
+TOKEN_OPERATOR = intern('operator')
+TOKEN_BLOCK_BEGIN = intern('block_begin')
+TOKEN_BLOCK_END = intern('block_end')
+TOKEN_VARIABLE_BEGIN = intern('variable_begin')
+TOKEN_VARIABLE_END = intern('variable_end')
+TOKEN_RAW_BEGIN = intern('raw_begin')
+TOKEN_RAW_END = intern('raw_end')
+TOKEN_COMMENT_BEGIN = intern('comment_begin')
+TOKEN_COMMENT_END = intern('comment_end')
+TOKEN_COMMENT = intern('comment')
+TOKEN_LINESTATEMENT_BEGIN = intern('linestatement_begin')
+TOKEN_LINESTATEMENT_END = intern('linestatement_end')
+TOKEN_LINECOMMENT_BEGIN = intern('linecomment_begin')
+TOKEN_LINECOMMENT_END = intern('linecomment_end')
+TOKEN_LINECOMMENT = intern('linecomment')
+TOKEN_DATA = intern('data')
+TOKEN_INITIAL = intern('initial')
+TOKEN_EOF = intern('eof')
+
+# bind operators to token types
+operators = {
+    '+':            TOKEN_ADD,
+    '-':            TOKEN_SUB,
+    '/':            TOKEN_DIV,
+    '//':           TOKEN_FLOORDIV,
+    '*':            TOKEN_MUL,
+    '%':            TOKEN_MOD,
+    '**':           TOKEN_POW,
+    '~':            TOKEN_TILDE,
+    '[':            TOKEN_LBRACKET,
+    ']':            TOKEN_RBRACKET,
+    '(':            TOKEN_LPAREN,
+    ')':            TOKEN_RPAREN,
+    '{':            TOKEN_LBRACE,
+    '}':            TOKEN_RBRACE,
+    '==':           TOKEN_EQ,
+    '!=':           TOKEN_NE,
+    '>':            TOKEN_GT,
+    '>=':           TOKEN_GTEQ,
+    '<':            TOKEN_LT,
+    '<=':           TOKEN_LTEQ,
+    '=':            TOKEN_ASSIGN,
+    '.':            TOKEN_DOT,
+    ':':            TOKEN_COLON,
+    '|':            TOKEN_PIPE,
+    ',':            TOKEN_COMMA,
+    ';':            TOKEN_SEMICOLON
+}
+
+reverse_operators = dict([(v, k) for k, v in operators.iteritems()])
+assert len(operators) == len(reverse_operators), 'operators dropped'
+operator_re = re.compile('(%s)' % '|'.join(re.escape(x) for x in
+                         sorted(operators, key=lambda x: -len(x))))
+
+ignored_tokens = frozenset([TOKEN_COMMENT_BEGIN, TOKEN_COMMENT,
+                            TOKEN_COMMENT_END, TOKEN_WHITESPACE,
+                            TOKEN_WHITESPACE, TOKEN_LINECOMMENT_BEGIN,
+                            TOKEN_LINECOMMENT_END, TOKEN_LINECOMMENT])
+ignore_if_empty = frozenset([TOKEN_WHITESPACE, TOKEN_DATA,
+                             TOKEN_COMMENT, TOKEN_LINECOMMENT])
+
+
+def _describe_token_type(token_type):
+    if token_type in reverse_operators:
+        return reverse_operators[token_type]
+    return {
+        TOKEN_COMMENT_BEGIN:        'begin of comment',
+        TOKEN_COMMENT_END:          'end of comment',
+        TOKEN_COMMENT:              'comment',
+        TOKEN_LINECOMMENT:          'comment',
+        TOKEN_BLOCK_BEGIN:          'begin of statement block',
+        TOKEN_BLOCK_END:            'end of statement block',
+        TOKEN_VARIABLE_BEGIN:       'begin of print statement',
+        TOKEN_VARIABLE_END:         'end of print statement',
+        TOKEN_LINESTATEMENT_BEGIN:  'begin of line statement',
+        TOKEN_LINESTATEMENT_END:    'end of line statement',
+        TOKEN_DATA:                 'template data / text',
+        TOKEN_EOF:                  'end of template'
+    }.get(token_type, token_type)
+
+
+def describe_token(token):
+    """Returns a description of the token."""
+    if token.type == 'name':
+        return token.value
+    return _describe_token_type(token.type)
+
+
+def describe_token_expr(expr):
+    """Like `describe_token` but for token expressions."""
+    if ':' in expr:
+        type, value = expr.split(':', 1)
+        if type == 'name':
+            return value
+    else:
+        type = expr
+    return _describe_token_type(type)
+
+
+def count_newlines(value):
+    """Count the number of newline characters in the string.  This is
+    useful for extensions that filter a stream.
+    """
+    return len(newline_re.findall(value))
+
+
+def compile_rules(environment):
+    """Compiles all the rules from the environment into a list of rules."""
+    e = re.escape
+    rules = [
+        (len(environment.comment_start_string), 'comment',
+         e(environment.comment_start_string)),
+        (len(environment.block_start_string), 'block',
+         e(environment.block_start_string)),
+        (len(environment.variable_start_string), 'variable',
+         e(environment.variable_start_string))
+    ]
+
+    if environment.line_statement_prefix is not None:
+        rules.append((len(environment.line_statement_prefix), 'linestatement',
+                      r'^\s*' + e(environment.line_statement_prefix)))
+    if environment.line_comment_prefix is not None:
+        rules.append((len(environment.line_comment_prefix), 'linecomment',
+                      r'(?:^|(?<=\S))[^\S\r\n]*' +
+                      e(environment.line_comment_prefix)))
+
+    return [x[1:] for x in sorted(rules, reverse=True)]
+
+
+class Failure(object):
+    """Class that raises a `TemplateSyntaxError` if called.
+    Used by the `Lexer` to specify known errors.
+    """
+
+    def __init__(self, message, cls=TemplateSyntaxError):
+        self.message = message
+        self.error_class = cls
+
+    def __call__(self, lineno, filename):
+        raise self.error_class(self.message, lineno, filename)
+
+
+class Token(tuple):
+    """Token class."""
+    __slots__ = ()
+    lineno, type, value = (property(itemgetter(x)) for x in range(3))
+
+    def __new__(cls, lineno, type, value):
+        return tuple.__new__(cls, (lineno, intern(str(type)), value))
+
+    def __str__(self):
+        if self.type in reverse_operators:
+            return reverse_operators[self.type]
+        elif self.type == 'name':
+            return self.value
+        return self.type
+
+    def test(self, expr):
+        """Test a token against a token expression.  This can either be a
+        token type or ``'token_type:token_value'``.  This can only test
+        against string values and types.
+        """
+        # here we do a regular string equality check as test_any is usually
+        # passed an iterable of not interned strings.
+        if self.type == expr:
+            return True
+        elif ':' in expr:
+            return expr.split(':', 1) == [self.type, self.value]
+        return False
+
+    def test_any(self, *iterable):
+        """Test against multiple token expressions."""
+        for expr in iterable:
+            if self.test(expr):
+                return True
+        return False
+
+    def __repr__(self):
+        return 'Token(%r, %r, %r)' % (
+            self.lineno,
+            self.type,
+            self.value
+        )
+
+
+class TokenStreamIterator(object):
+    """The iterator for tokenstreams.  Iterate over the stream
+    until the eof token is reached.
+    """
+
+    def __init__(self, stream):
+        self.stream = stream
+
+    def __iter__(self):
+        return self
+
+    def next(self):
+        token = self.stream.current
+        if token.type is TOKEN_EOF:
+            self.stream.close()
+            raise StopIteration()
+        next(self.stream)
+        return token
+
+
+class TokenStream(object):
+    """A token stream is an iterable that yields :class:`Token`\s.  The
+    parser however does not iterate over it but calls :meth:`next` to go
+    one token ahead.  The current active token is stored as :attr:`current`.
+    """
+
+    def __init__(self, generator, name, filename):
+        self._next = iter(generator).next
+        self._pushed = deque()
+        self.name = name
+        self.filename = filename
+        self.closed = False
+        self.current = Token(1, TOKEN_INITIAL, '')
+        next(self)
+
+    def __iter__(self):
+        return TokenStreamIterator(self)
+
+    def __nonzero__(self):
+        return bool(self._pushed) or self.current.type is not TOKEN_EOF
+
+    eos = property(lambda x: not x, doc="Are we at the end of the stream?")
+
+    def push(self, token):
+        """Push a token back to the stream."""
+        self._pushed.append(token)
+
+    def look(self):
+        """Look at the next token."""
+        old_token = next(self)
+        result = self.current
+        self.push(result)
+        self.current = old_token
+        return result
+
+    def skip(self, n=1):
+        """Got n tokens ahead."""
+        for x in xrange(n):
+            next(self)
+
+    def next_if(self, expr):
+        """Perform the token test and return the token if it matched.
+        Otherwise the return value is `None`.
+        """
+        if self.current.test(expr):
+            return next(self)
+
+    def skip_if(self, expr):
+        """Like :meth:`next_if` but only returns `True` or `False`."""
+        return self.next_if(expr) is not None
+
+    def next(self):
+        """Go one token ahead and return the old one"""
+        rv = self.current
+        if self._pushed:
+            self.current = self._pushed.popleft()
+        elif self.current.type is not TOKEN_EOF:
+            try:
+                self.current = self._next()
+            except StopIteration:
+                self.close()
+        return rv
+
+    def close(self):
+        """Close the stream."""
+        self.current = Token(self.current.lineno, TOKEN_EOF, '')
+        self._next = None
+        self.closed = True
+
+    def expect(self, expr):
+        """Expect a given token type and return it.  This accepts the same
+        argument as :meth:`jinja2.lexer.Token.test`.
+        """
+        if not self.current.test(expr):
+            expr = describe_token_expr(expr)
+            if self.current.type is TOKEN_EOF:
+                raise TemplateSyntaxError('unexpected end of template, '
+                                          'expected %r.' % expr,
+                                          self.current.lineno,
+                                          self.name, self.filename)
+            raise TemplateSyntaxError("expected token %r, got %r" %
+                                      (expr, describe_token(self.current)),
+                                      self.current.lineno,
+                                      self.name, self.filename)
+        try:
+            return self.current
+        finally:
+            next(self)
+
+
+def get_lexer(environment):
+    """Return a lexer which is probably cached."""
+    key = (environment.block_start_string,
+           environment.block_end_string,
+           environment.variable_start_string,
+           environment.variable_end_string,
+           environment.comment_start_string,
+           environment.comment_end_string,
+           environment.line_statement_prefix,
+           environment.line_comment_prefix,
+           environment.trim_blocks,
+           environment.newline_sequence)
+    lexer = _lexer_cache.get(key)
+    if lexer is None:
+        lexer = Lexer(environment)
+        _lexer_cache[key] = lexer
+    return lexer
+
+
+class Lexer(object):
+    """Class that implements a lexer for a given environment. Automatically
+    created by the environment class, usually you don't have to do that.
+
+    Note that the lexer is not automatically bound to an environment.
+    Multiple environments can share the same lexer.
+    """
+
+    def __init__(self, environment):
+        # shortcuts
+        c = lambda x: re.compile(x, re.M | re.S)
+        e = re.escape
+
+        # lexing rules for tags
+        tag_rules = [
+            (whitespace_re, TOKEN_WHITESPACE, None),
+            (float_re, TOKEN_FLOAT, None),
+            (integer_re, TOKEN_INTEGER, None),
+            (name_re, TOKEN_NAME, None),
+            (string_re, TOKEN_STRING, None),
+            (operator_re, TOKEN_OPERATOR, None)
+        ]
+
+        # assamble the root lexing rule. because "|" is ungreedy
+        # we have to sort by length so that the lexer continues working
+        # as expected when we have parsing rules like <% for block and
+        # <%= for variables. (if someone wants asp like syntax)
+        # variables are just part of the rules if variable processing
+        # is required.
+        root_tag_rules = compile_rules(environment)
+
+        # block suffix if trimming is enabled
+        block_suffix_re = environment.trim_blocks and '\\n?' or ''
+
+        self.newline_sequence = environment.newline_sequence
+
+        # global lexing rules
+        self.rules = {
+            'root': [
+                # directives
+                (c('(.*?)(?:%s)' % '|'.join(
+                    [r'(?P<raw_begin>(?:\s*%s\-|%s)\s*raw\s*(?:\-%s\s*|%s))' % (
+                        e(environment.block_start_string),
+                        e(environment.block_start_string),
+                        e(environment.block_end_string),
+                        e(environment.block_end_string)
+                    )] + [
+                        r'(?P<%s_begin>\s*%s\-|%s)' % (n, r, r)
+                        for n, r in root_tag_rules
+                    ])), (TOKEN_DATA, '#bygroup'), '#bygroup'),
+                # data
+                (c('.+'), TOKEN_DATA, None)
+            ],
+            # comments
+            TOKEN_COMMENT_BEGIN: [
+                (c(r'(.*?)((?:\-%s\s*|%s)%s)' % (
+                    e(environment.comment_end_string),
+                    e(environment.comment_end_string),
+                    block_suffix_re
+                )), (TOKEN_COMMENT, TOKEN_COMMENT_END), '#pop'),
+                (c('(.)'), (Failure('Missing end of comment tag'),), None)
+            ],
+            # blocks
+            TOKEN_BLOCK_BEGIN: [
+                (c('(?:\-%s\s*|%s)%s' % (
+                    e(environment.block_end_string),
+                    e(environment.block_end_string),
+                    block_suffix_re
+                )), TOKEN_BLOCK_END, '#pop'),
+            ] + tag_rules,
+            # variables
+            TOKEN_VARIABLE_BEGIN: [
+                (c('\-%s\s*|%s' % (
+                    e(environment.variable_end_string),
+                    e(environment.variable_end_string)
+                )), TOKEN_VARIABLE_END, '#pop')
+            ] + tag_rules,
+            # raw block
+            TOKEN_RAW_BEGIN: [
+                (c('(.*?)((?:\s*%s\-|%s)\s*endraw\s*(?:\-%s\s*|%s%s))' % (
+                    e(environment.block_start_string),
+                    e(environment.block_start_string),
+                    e(environment.block_end_string),
+                    e(environment.block_end_string),
+                    block_suffix_re
+                )), (TOKEN_DATA, TOKEN_RAW_END), '#pop'),
+                (c('(.)'), (Failure('Missing end of raw directive'),), None)
+            ],
+            # line statements
+            TOKEN_LINESTATEMENT_BEGIN: [
+                (c(r'\s*(\n|$)'), TOKEN_LINESTATEMENT_END, '#pop')
+            ] + tag_rules,
+            # line comments
+            TOKEN_LINECOMMENT_BEGIN: [
+                (c(r'(.*?)()(?=\n|$)'), (TOKEN_LINECOMMENT,
+                 TOKEN_LINECOMMENT_END), '#pop')
+            ]
+        }
+
+    def _normalize_newlines(self, value):
+        """Called for strings and template data to normlize it to unicode."""
+        return newline_re.sub(self.newline_sequence, value)
+
+    def tokenize(self, source, name=None, filename=None, state=None):
+        """Calls tokeniter + tokenize and wraps it in a token stream.
+        """
+        stream = self.tokeniter(source, name, filename, state)
+        return TokenStream(self.wrap(stream, name, filename), name, filename)
+
+    def wrap(self, stream, name=None, filename=None):
+        """This is called with the stream as returned by `tokenize` and wraps
+        every token in a :class:`Token` and converts the value.
+        """
+        for lineno, token, value in stream:
+            if token in ignored_tokens:
+                continue
+            elif token == 'linestatement_begin':
+                token = 'block_begin'
+            elif token == 'linestatement_end':
+                token = 'block_end'
+            # we are not interested in those tokens in the parser
+            elif token in ('raw_begin', 'raw_end'):
+                continue
+            elif token == 'data':
+                value = self._normalize_newlines(value)
+            elif token == 'keyword':
+                token = value
+            elif token == 'name':
+                value = str(value)
+            elif token == 'string':
+                # try to unescape string
+                try:
+                    value = self._normalize_newlines(value[1:-1]) \
+                        .encode('ascii', 'backslashreplace') \
+                        .decode('unicode-escape')
+                except Exception, e:
+                    msg = str(e).split(':')[-1].strip()
+                    raise TemplateSyntaxError(msg, lineno, name, filename)
+                # if we can express it as bytestring (ascii only)
+                # we do that for support of semi broken APIs
+                # as datetime.datetime.strftime.  On python 3 this
+                # call becomes a noop thanks to 2to3
+                try:
+                    value = str(value)
+                except UnicodeError:
+                    pass
+            elif token == 'integer':
+                value = int(value)
+            elif token == 'float':
+                value = float(value)
+            elif token == 'operator':
+                token = operators[value]
+            yield Token(lineno, token, value)
+
+    def tokeniter(self, source, name, filename=None, state=None):
+        """This method tokenizes the text and returns the tokens in a
+        generator.  Use this method if you just want to tokenize a template.
+        """
+        source = '\n'.join(unicode(source).splitlines())
+        pos = 0
+        lineno = 1
+        stack = ['root']
+        if state is not None and state != 'root':
+            assert state in ('variable', 'block'), 'invalid state'
+            stack.append(state + '_begin')
+        else:
+            state = 'root'
+        statetokens = self.rules[stack[-1]]
+        source_length = len(source)
+
+        balancing_stack = []
+
+        while 1:
+            # tokenizer loop
+            for regex, tokens, new_state in statetokens:
+                m = regex.match(source, pos)
+                # if no match we try again with the next rule
+                if m is None:
+                    continue
+
+                # we only match blocks and variables if brances / parentheses
+                # are balanced. continue parsing with the lower rule which
+                # is the operator rule. do this only if the end tags look
+                # like operators
+                if balancing_stack and \
+                   tokens in ('variable_end', 'block_end',
+                              'linestatement_end'):
+                    continue
+
+                # tuples support more options
+                if isinstance(tokens, tuple):
+                    for idx, token in enumerate(tokens):
+                        # failure group
+                        if token.__class__ is Failure:
+                            raise token(lineno, filename)
+                        # bygroup is a bit more complex, in that case we
+                        # yield for the current token the first named
+                        # group that matched
+                        elif token == '#bygroup':
+                            for key, value in m.groupdict().iteritems():
+                                if value is not None:
+                                    yield lineno, key, value
+                                    lineno += value.count('\n')
+                                    break
+                            else:
+                                raise RuntimeError('%r wanted to resolve '
+                                                   'the token dynamically'
+                                                   ' but no group matched'
+                                                   % regex)
+                        # normal group
+                        else:
+                            data = m.group(idx + 1)
+                            if data or token not in ignore_if_empty:
+                                yield lineno, token, data
+                            lineno += data.count('\n')
+
+                # strings as token just are yielded as it.
+                else:
+                    data = m.group()
+                    # update brace/parentheses balance
+                    if tokens == 'operator':
+                        if data == '{':
+                            balancing_stack.append('}')
+                        elif data == '(':
+                            balancing_stack.append(')')
+                        elif data == '[':
+                            balancing_stack.append(']')
+                        elif data in ('}', ')', ']'):
+                            if not balancing_stack:
+                                raise TemplateSyntaxError('unexpected \'%s\'' %
+                                                          data, lineno, name,
+                                                          filename)
+                            expected_op = balancing_stack.pop()
+                            if expected_op != data:
+                                raise TemplateSyntaxError('unexpected \'%s\', '
+                                                          'expected \'%s\'' %
+                                                          (data, expected_op),
+                                                          lineno, name,
+                                                          filename)
+                    # yield items
+                    if data or tokens not in ignore_if_empty:
+                        yield lineno, tokens, data
+                    lineno += data.count('\n')
+
+                # fetch new position into new variable so that we can check
+                # if there is a internal parsing error which would result
+                # in an infinite loop
+                pos2 = m.end()
+
+                # handle state changes
+                if new_state is not None:
+                    # remove the uppermost state
+                    if new_state == '#pop':
+                        stack.pop()
+                    # resolve the new state by group checking
+                    elif new_state == '#bygroup':
+                        for key, value in m.groupdict().iteritems():
+                            if value is not None:
+                                stack.append(key)
+                                break
+                        else:
+                            raise RuntimeError('%r wanted to resolve the '
+                                               'new state dynamically but'
+                                               ' no group matched' %
+                                               regex)
+                    # direct state name given
+                    else:
+                        stack.append(new_state)
+                    statetokens = self.rules[stack[-1]]
+                # we are still at the same position and no stack change.
+                # this means a loop without break condition, avoid that and
+                # raise error
+                elif pos2 == pos:
+                    raise RuntimeError('%r yielded empty string without '
+                                       'stack change' % regex)
+                # publish new function and start again
+                pos = pos2
+                break
+            # if loop terminated without break we havn't found a single match
+            # either we are at the end of the file or we have a problem
+            else:
+                # end of text
+                if pos >= source_length:
+                    return
+                # something went wrong
+                raise TemplateSyntaxError('unexpected char %r at %d' %
+                                          (source[pos], pos), lineno,
+                                          name, filename)
diff --git a/lib/jinja2/jinja2/loaders.py b/lib/jinja2/jinja2/loaders.py
new file mode 100644
index 0000000..419a9c8
--- /dev/null
+++ b/lib/jinja2/jinja2/loaders.py
@@ -0,0 +1,450 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.loaders
+    ~~~~~~~~~~~~~~
+
+    Jinja loader classes.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import os
+import sys
+import weakref
+from types import ModuleType
+from os import path
+try:
+    from hashlib import sha1
+except ImportError:
+    from sha import new as sha1
+from jinja2.exceptions import TemplateNotFound
+from jinja2.utils import LRUCache, open_if_exists, internalcode
+
+
+def split_template_path(template):
+    """Split a path into segments and perform a sanity check.  If it detects
+    '..' in the path it will raise a `TemplateNotFound` error.
+    """
+    pieces = []
+    for piece in template.split('/'):
+        if path.sep in piece \
+           or (path.altsep and path.altsep in piece) or \
+           piece == path.pardir:
+            raise TemplateNotFound(template)
+        elif piece and piece != '.':
+            pieces.append(piece)
+    return pieces
+
+
+class BaseLoader(object):
+    """Baseclass for all loaders.  Subclass this and override `get_source` to
+    implement a custom loading mechanism.  The environment provides a
+    `get_template` method that calls the loader's `load` method to get the
+    :class:`Template` object.
+
+    A very basic example for a loader that looks up templates on the file
+    system could look like this::
+
+        from jinja2 import BaseLoader, TemplateNotFound
+        from os.path import join, exists, getmtime
+
+        class MyLoader(BaseLoader):
+
+            def __init__(self, path):
+                self.path = path
+
+            def get_source(self, environment, template):
+                path = join(self.path, template)
+                if not exists(path):
+                    raise TemplateNotFound(template)
+                mtime = getmtime(path)
+                with file(path) as f:
+                    source = f.read().decode('utf-8')
+                return source, path, lambda: mtime == getmtime(path)
+    """
+
+    #: if set to `False` it indicates that the loader cannot provide access
+    #: to the source of templates.
+    #:
+    #: .. versionadded:: 2.4
+    has_source_access = True
+
+    def get_source(self, environment, template):
+        """Get the template source, filename and reload helper for a template.
+        It's passed the environment and template name and has to return a
+        tuple in the form ``(source, filename, uptodate)`` or raise a
+        `TemplateNotFound` error if it can't locate the template.
+
+        The source part of the returned tuple must be the source of the
+        template as unicode string or a ASCII bytestring.  The filename should
+        be the name of the file on the filesystem if it was loaded from there,
+        otherwise `None`.  The filename is used by python for the tracebacks
+        if no loader extension is used.
+
+        The last item in the tuple is the `uptodate` function.  If auto
+        reloading is enabled it's always called to check if the template
+        changed.  No arguments are passed so the function must store the
+        old state somewhere (for example in a closure).  If it returns `False`
+        the template will be reloaded.
+        """
+        if not self.has_source_access:
+            raise RuntimeError('%s cannot provide access to the source' %
+                               self.__class__.__name__)
+        raise TemplateNotFound(template)
+
+    def list_templates(self):
+        """Iterates over all templates.  If the loader does not support that
+        it should raise a :exc:`TypeError` which is the default behavior.
+        """
+        raise TypeError('this loader cannot iterate over all templates')
+
+    @internalcode
+    def load(self, environment, name, globals=None):
+        """Loads a template.  This method looks up the template in the cache
+        or loads one by calling :meth:`get_source`.  Subclasses should not
+        override this method as loaders working on collections of other
+        loaders (such as :class:`PrefixLoader` or :class:`ChoiceLoader`)
+        will not call this method but `get_source` directly.
+        """
+        code = None
+        if globals is None:
+            globals = {}
+
+        # first we try to get the source for this template together
+        # with the filename and the uptodate function.
+        source, filename, uptodate = self.get_source(environment, name)
+
+        # try to load the code from the bytecode cache if there is a
+        # bytecode cache configured.
+        bcc = environment.bytecode_cache
+        if bcc is not None:
+            bucket = bcc.get_bucket(environment, name, filename, source)
+            code = bucket.code
+
+        # if we don't have code so far (not cached, no longer up to
+        # date) etc. we compile the template
+        if code is None:
+            code = environment.compile(source, name, filename)
+
+        # if the bytecode cache is available and the bucket doesn't
+        # have a code so far, we give the bucket the new code and put
+        # it back to the bytecode cache.
+        if bcc is not None and bucket.code is None:
+            bucket.code = code
+            bcc.set_bucket(bucket)
+
+        return environment.template_class.from_code(environment, code,
+                                                    globals, uptodate)
+
+
+class FileSystemLoader(BaseLoader):
+    """Loads templates from the file system.  This loader can find templates
+    in folders on the file system and is the preferred way to load them.
+
+    The loader takes the path to the templates as string, or if multiple
+    locations are wanted a list of them which is then looked up in the
+    given order:
+
+    >>> loader = FileSystemLoader('/path/to/templates')
+    >>> loader = FileSystemLoader(['/path/to/templates', '/other/path'])
+
+    Per default the template encoding is ``'utf-8'`` which can be changed
+    by setting the `encoding` parameter to something else.
+    """
+
+    def __init__(self, searchpath, encoding='utf-8'):
+        if isinstance(searchpath, basestring):
+            searchpath = [searchpath]
+        self.searchpath = list(searchpath)
+        self.encoding = encoding
+
+    def get_source(self, environment, template):
+        pieces = split_template_path(template)
+        for searchpath in self.searchpath:
+            filename = path.join(searchpath, *pieces)
+            f = open_if_exists(filename)
+            if f is None:
+                continue
+            try:
+                contents = f.read().decode(self.encoding)
+            finally:
+                f.close()
+
+            mtime = path.getmtime(filename)
+            def uptodate():
+                try:
+                    return path.getmtime(filename) == mtime
+                except OSError:
+                    return False
+            return contents, filename, uptodate
+        raise TemplateNotFound(template)
+
+    def list_templates(self):
+        found = set()
+        for searchpath in self.searchpath:
+            for dirpath, dirnames, filenames in os.walk(searchpath):
+                for filename in filenames:
+                    template = os.path.join(dirpath, filename) \
+                        [len(searchpath):].strip(os.path.sep) \
+                                          .replace(os.path.sep, '/')
+                    if template[:2] == './':
+                        template = template[2:]
+                    if template not in found:
+                        found.add(template)
+        return sorted(found)
+
+
+class PackageLoader(BaseLoader):
+    """Load templates from python eggs or packages.  It is constructed with
+    the name of the python package and the path to the templates in that
+    package::
+
+        loader = PackageLoader('mypackage', 'views')
+
+    If the package path is not given, ``'templates'`` is assumed.
+
+    Per default the template encoding is ``'utf-8'`` which can be changed
+    by setting the `encoding` parameter to something else.  Due to the nature
+    of eggs it's only possible to reload templates if the package was loaded
+    from the file system and not a zip file.
+    """
+
+    def __init__(self, package_name, package_path='templates',
+                 encoding='utf-8'):
+        from pkg_resources import DefaultProvider, ResourceManager, \
+                                  get_provider
+        provider = get_provider(package_name)
+        self.encoding = encoding
+        self.manager = ResourceManager()
+        self.filesystem_bound = isinstance(provider, DefaultProvider)
+        self.provider = provider
+        self.package_path = package_path
+
+    def get_source(self, environment, template):
+        pieces = split_template_path(template)
+        p = '/'.join((self.package_path,) + tuple(pieces))
+        if not self.provider.has_resource(p):
+            raise TemplateNotFound(template)
+
+        filename = uptodate = None
+        if self.filesystem_bound:
+            filename = self.provider.get_resource_filename(self.manager, p)
+            mtime = path.getmtime(filename)
+            def uptodate():
+                try:
+                    return path.getmtime(filename) == mtime
+                except OSError:
+                    return False
+
+        source = self.provider.get_resource_string(self.manager, p)
+        return source.decode(self.encoding), filename, uptodate
+
+    def list_templates(self):
+        path = self.package_path
+        if path[:2] == './':
+            path = path[2:]
+        elif path == '.':
+            path = ''
+        offset = len(path)
+        results = []
+        def _walk(path):
+            for filename in self.provider.resource_listdir(path):
+                fullname = path + '/' + filename
+                if self.provider.resource_isdir(fullname):
+                    _walk(fullname)
+                else:
+                    results.append(fullname[offset:].lstrip('/'))
+        _walk(path)
+        results.sort()
+        return results
+
+
+class DictLoader(BaseLoader):
+    """Loads a template from a python dict.  It's passed a dict of unicode
+    strings bound to template names.  This loader is useful for unittesting:
+
+    >>> loader = DictLoader({'index.html': 'source here'})
+
+    Because auto reloading is rarely useful this is disabled per default.
+    """
+
+    def __init__(self, mapping):
+        self.mapping = mapping
+
+    def get_source(self, environment, template):
+        if template in self.mapping:
+            source = self.mapping[template]
+            return source, None, lambda: source != self.mapping.get(template)
+        raise TemplateNotFound(template)
+
+    def list_templates(self):
+        return sorted(self.mapping)
+
+
+class FunctionLoader(BaseLoader):
+    """A loader that is passed a function which does the loading.  The
+    function becomes the name of the template passed and has to return either
+    an unicode string with the template source, a tuple in the form ``(source,
+    filename, uptodatefunc)`` or `None` if the template does not exist.
+
+    >>> def load_template(name):
+    ...     if name == 'index.html':
+    ...         return '...'
+    ...
+    >>> loader = FunctionLoader(load_template)
+
+    The `uptodatefunc` is a function that is called if autoreload is enabled
+    and has to return `True` if the template is still up to date.  For more
+    details have a look at :meth:`BaseLoader.get_source` which has the same
+    return value.
+    """
+
+    def __init__(self, load_func):
+        self.load_func = load_func
+
+    def get_source(self, environment, template):
+        rv = self.load_func(template)
+        if rv is None:
+            raise TemplateNotFound(template)
+        elif isinstance(rv, basestring):
+            return rv, None, None
+        return rv
+
+
+class PrefixLoader(BaseLoader):
+    """A loader that is passed a dict of loaders where each loader is bound
+    to a prefix.  The prefix is delimited from the template by a slash per
+    default, which can be changed by setting the `delimiter` argument to
+    something else::
+
+        loader = PrefixLoader({
+            'app1':     PackageLoader('mypackage.app1'),
+            'app2':     PackageLoader('mypackage.app2')
+        })
+
+    By loading ``'app1/index.html'`` the file from the app1 package is loaded,
+    by loading ``'app2/index.html'`` the file from the second.
+    """
+
+    def __init__(self, mapping, delimiter='/'):
+        self.mapping = mapping
+        self.delimiter = delimiter
+
+    def get_source(self, environment, template):
+        try:
+            prefix, name = template.split(self.delimiter, 1)
+            loader = self.mapping[prefix]
+        except (ValueError, KeyError):
+            raise TemplateNotFound(template)
+        try:
+            return loader.get_source(environment, name)
+        except TemplateNotFound:
+            # re-raise the exception with the correct fileame here.
+            # (the one that includes the prefix)
+            raise TemplateNotFound(template)
+
+    def list_templates(self):
+        result = []
+        for prefix, loader in self.mapping.iteritems():
+            for template in loader.list_templates():
+                result.append(prefix + self.delimiter + template)
+        return result
+
+
+class ChoiceLoader(BaseLoader):
+    """This loader works like the `PrefixLoader` just that no prefix is
+    specified.  If a template could not be found by one loader the next one
+    is tried.
+
+    >>> loader = ChoiceLoader([
+    ...     FileSystemLoader('/path/to/user/templates'),
+    ...     FileSystemLoader('/path/to/system/templates')
+    ... ])
+
+    This is useful if you want to allow users to override builtin templates
+    from a different location.
+    """
+
+    def __init__(self, loaders):
+        self.loaders = loaders
+
+    def get_source(self, environment, template):
+        for loader in self.loaders:
+            try:
+                return loader.get_source(environment, template)
+            except TemplateNotFound:
+                pass
+        raise TemplateNotFound(template)
+
+    def list_templates(self):
+        found = set()
+        for loader in self.loaders:
+            found.update(loader.list_templates())
+        return sorted(found)
+
+
+class _TemplateModule(ModuleType):
+    """Like a normal module but with support for weak references"""
+
+
+class ModuleLoader(BaseLoader):
+    """This loader loads templates from precompiled templates.
+
+    Example usage:
+
+    >>> loader = ChoiceLoader([
+    ...     ModuleLoader('/path/to/compiled/templates'),
+    ...     FileSystemLoader('/path/to/templates')
+    ... ])
+
+    Templates can be precompiled with :meth:`Environment.compile_templates`.
+    """
+
+    has_source_access = False
+
+    def __init__(self, path):
+        package_name = '_jinja2_module_templates_%x' % id(self)
+
+        # create a fake module that looks for the templates in the
+        # path given.
+        mod = _TemplateModule(package_name)
+        if isinstance(path, basestring):
+            path = [path]
+        else:
+            path = list(path)
+        mod.__path__ = path
+
+        sys.modules[package_name] = weakref.proxy(mod,
+            lambda x: sys.modules.pop(package_name, None))
+
+        # the only strong reference, the sys.modules entry is weak
+        # so that the garbage collector can remove it once the
+        # loader that created it goes out of business.
+        self.module = mod
+        self.package_name = package_name
+
+    @staticmethod
+    def get_template_key(name):
+        return 'tmpl_' + sha1(name.encode('utf-8')).hexdigest()
+
+    @staticmethod
+    def get_module_filename(name):
+        return ModuleLoader.get_template_key(name) + '.py'
+
+    @internalcode
+    def load(self, environment, name, globals=None):
+        key = self.get_template_key(name)
+        module = '%s.%s' % (self.package_name, key)
+        mod = getattr(self.module, module, None)
+        if mod is None:
+            try:
+                mod = __import__(module, None, None, ['root'])
+            except ImportError:
+                raise TemplateNotFound(name)
+
+            # remove the entry from sys.modules, we only want the attribute
+            # on the module object we have stored on the loader.
+            sys.modules.pop(module, None)
+
+        return environment.template_class.from_module_dict(
+            environment, mod.__dict__, globals)
diff --git a/lib/jinja2/jinja2/meta.py b/lib/jinja2/jinja2/meta.py
new file mode 100644
index 0000000..3a779a5
--- /dev/null
+++ b/lib/jinja2/jinja2/meta.py
@@ -0,0 +1,102 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.meta
+    ~~~~~~~~~~~
+
+    This module implements various functions that exposes information about
+    templates that might be interesting for various kinds of applications.
+
+    :copyright: (c) 2010 by the Jinja Team, see AUTHORS for more details.
+    :license: BSD, see LICENSE for more details.
+"""
+from jinja2 import nodes
+from jinja2.compiler import CodeGenerator
+
+
+class TrackingCodeGenerator(CodeGenerator):
+    """We abuse the code generator for introspection."""
+
+    def __init__(self, environment):
+        CodeGenerator.__init__(self, environment, '<introspection>',
+                               '<introspection>')
+        self.undeclared_identifiers = set()
+
+    def write(self, x):
+        """Don't write."""
+
+    def pull_locals(self, frame):
+        """Remember all undeclared identifiers."""
+        self.undeclared_identifiers.update(frame.identifiers.undeclared)
+
+
+def find_undeclared_variables(ast):
+    """Returns a set of all variables in the AST that will be looked up from
+    the context at runtime.  Because at compile time it's not known which
+    variables will be used depending on the path the execution takes at
+    runtime, all variables are returned.
+
+    >>> from jinja2 import Environment, meta
+    >>> env = Environment()
+    >>> ast = env.parse('{% set foo = 42 %}{{ bar + foo }}')
+    >>> meta.find_undeclared_variables(ast)
+    set(['bar'])
+
+    .. admonition:: Implementation
+
+       Internally the code generator is used for finding undeclared variables.
+       This is good to know because the code generator might raise a
+       :exc:`TemplateAssertionError` during compilation and as a matter of
+       fact this function can currently raise that exception as well.
+    """
+    codegen = TrackingCodeGenerator(ast.environment)
+    codegen.visit(ast)
+    return codegen.undeclared_identifiers
+
+
+def find_referenced_templates(ast):
+    """Finds all the referenced templates from the AST.  This will return an
+    iterator over all the hardcoded template extensions, inclusions and
+    imports.  If dynamic inheritance or inclusion is used, `None` will be
+    yielded.
+
+    >>> from jinja2 import Environment, meta
+    >>> env = Environment()
+    >>> ast = env.parse('{% extends "layout.html" %}{% include helper %}')
+    >>> list(meta.find_referenced_templates(ast))
+    ['layout.html', None]
+
+    This function is useful for dependency tracking.  For example if you want
+    to rebuild parts of the website after a layout template has changed.
+    """
+    for node in ast.find_all((nodes.Extends, nodes.FromImport, nodes.Import,
+                              nodes.Include)):
+        if not isinstance(node.template, nodes.Const):
+            # a tuple with some non consts in there
+            if isinstance(node.template, (nodes.Tuple, nodes.List)):
+                for template_name in node.template.items:
+                    # something const, only yield the strings and ignore
+                    # non-string consts that really just make no sense
+                    if isinstance(template_name, nodes.Const):
+                        if isinstance(template_name.value, basestring):
+                            yield template_name.value
+                    # something dynamic in there
+                    else:
+                        yield None
+            # something dynamic we don't know about here
+            else:
+                yield None
+            continue
+        # constant is a basestring, direct template name
+        if isinstance(node.template.value, basestring):
+            yield node.template.value
+        # a tuple or list (latter *should* not happen) made of consts,
+        # yield the consts that are strings.  We could warn here for
+        # non string values
+        elif isinstance(node, nodes.Include) and \
+             isinstance(node.template.value, (tuple, list)):
+            for template_name in node.template.value:
+                if isinstance(template_name, basestring):
+                    yield template_name
+        # something else we don't care about, we could warn here
+        else:
+            yield None
diff --git a/lib/jinja2/jinja2/nodes.py b/lib/jinja2/jinja2/nodes.py
new file mode 100644
index 0000000..f9da1da
--- /dev/null
+++ b/lib/jinja2/jinja2/nodes.py
@@ -0,0 +1,910 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.nodes
+    ~~~~~~~~~~~~
+
+    This module implements additional nodes derived from the ast base node.
+
+    It also provides some node tree helper functions like `in_lineno` and
+    `get_nodes` used by the parser and translator in order to normalize
+    python and jinja nodes.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import operator
+from itertools import chain, izip
+from collections import deque
+from jinja2.utils import Markup, MethodType, FunctionType
+
+
+#: the types we support for context functions
+_context_function_types = (FunctionType, MethodType)
+
+
+_binop_to_func = {
+    '*':        operator.mul,
+    '/':        operator.truediv,
+    '//':       operator.floordiv,
+    '**':       operator.pow,
+    '%':        operator.mod,
+    '+':        operator.add,
+    '-':        operator.sub
+}
+
+_uaop_to_func = {
+    'not':      operator.not_,
+    '+':        operator.pos,
+    '-':        operator.neg
+}
+
+_cmpop_to_func = {
+    'eq':       operator.eq,
+    'ne':       operator.ne,
+    'gt':       operator.gt,
+    'gteq':     operator.ge,
+    'lt':       operator.lt,
+    'lteq':     operator.le,
+    'in':       lambda a, b: a in b,
+    'notin':    lambda a, b: a not in b
+}
+
+
+class Impossible(Exception):
+    """Raised if the node could not perform a requested action."""
+
+
+class NodeType(type):
+    """A metaclass for nodes that handles the field and attribute
+    inheritance.  fields and attributes from the parent class are
+    automatically forwarded to the child."""
+
+    def __new__(cls, name, bases, d):
+        for attr in 'fields', 'attributes':
+            storage = []
+            storage.extend(getattr(bases[0], attr, ()))
+            storage.extend(d.get(attr, ()))
+            assert len(bases) == 1, 'multiple inheritance not allowed'
+            assert len(storage) == len(set(storage)), 'layout conflict'
+            d[attr] = tuple(storage)
+        d.setdefault('abstract', False)
+        return type.__new__(cls, name, bases, d)
+
+
+class EvalContext(object):
+    """Holds evaluation time information.  Custom attributes can be attached
+    to it in extensions.
+    """
+
+    def __init__(self, environment, template_name=None):
+        self.environment = environment
+        if callable(environment.autoescape):
+            self.autoescape = environment.autoescape(template_name)
+        else:
+            self.autoescape = environment.autoescape
+        self.volatile = False
+
+    def save(self):
+        return self.__dict__.copy()
+
+    def revert(self, old):
+        self.__dict__.clear()
+        self.__dict__.update(old)
+
+
+def get_eval_context(node, ctx):
+    if ctx is None:
+        if node.environment is None:
+            raise RuntimeError('if no eval context is passed, the '
+                               'node must have an attached '
+                               'environment.')
+        return EvalContext(node.environment)
+    return ctx
+
+
+class Node(object):
+    """Baseclass for all Jinja2 nodes.  There are a number of nodes available
+    of different types.  There are three major types:
+
+    -   :class:`Stmt`: statements
+    -   :class:`Expr`: expressions
+    -   :class:`Helper`: helper nodes
+    -   :class:`Template`: the outermost wrapper node
+
+    All nodes have fields and attributes.  Fields may be other nodes, lists,
+    or arbitrary values.  Fields are passed to the constructor as regular
+    positional arguments, attributes as keyword arguments.  Each node has
+    two attributes: `lineno` (the line number of the node) and `environment`.
+    The `environment` attribute is set at the end of the parsing process for
+    all nodes automatically.
+    """
+    __metaclass__ = NodeType
+    fields = ()
+    attributes = ('lineno', 'environment')
+    abstract = True
+
+    def __init__(self, *fields, **attributes):
+        if self.abstract:
+            raise TypeError('abstract nodes are not instanciable')
+        if fields:
+            if len(fields) != len(self.fields):
+                if not self.fields:
+                    raise TypeError('%r takes 0 arguments' %
+                                    self.__class__.__name__)
+                raise TypeError('%r takes 0 or %d argument%s' % (
+                    self.__class__.__name__,
+                    len(self.fields),
+                    len(self.fields) != 1 and 's' or ''
+                ))
+            for name, arg in izip(self.fields, fields):
+                setattr(self, name, arg)
+        for attr in self.attributes:
+            setattr(self, attr, attributes.pop(attr, None))
+        if attributes:
+            raise TypeError('unknown attribute %r' %
+                            iter(attributes).next())
+
+    def iter_fields(self, exclude=None, only=None):
+        """This method iterates over all fields that are defined and yields
+        ``(key, value)`` tuples.  Per default all fields are returned, but
+        it's possible to limit that to some fields by providing the `only`
+        parameter or to exclude some using the `exclude` parameter.  Both
+        should be sets or tuples of field names.
+        """
+        for name in self.fields:
+            if (exclude is only is None) or \
+               (exclude is not None and name not in exclude) or \
+               (only is not None and name in only):
+                try:
+                    yield name, getattr(self, name)
+                except AttributeError:
+                    pass
+
+    def iter_child_nodes(self, exclude=None, only=None):
+        """Iterates over all direct child nodes of the node.  This iterates
+        over all fields and yields the values of they are nodes.  If the value
+        of a field is a list all the nodes in that list are returned.
+        """
+        for field, item in self.iter_fields(exclude, only):
+            if isinstance(item, list):
+                for n in item:
+                    if isinstance(n, Node):
+                        yield n
+            elif isinstance(item, Node):
+                yield item
+
+    def find(self, node_type):
+        """Find the first node of a given type.  If no such node exists the
+        return value is `None`.
+        """
+        for result in self.find_all(node_type):
+            return result
+
+    def find_all(self, node_type):
+        """Find all the nodes of a given type.  If the type is a tuple,
+        the check is performed for any of the tuple items.
+        """
+        for child in self.iter_child_nodes():
+            if isinstance(child, node_type):
+                yield child
+            for result in child.find_all(node_type):
+                yield result
+
+    def set_ctx(self, ctx):
+        """Reset the context of a node and all child nodes.  Per default the
+        parser will all generate nodes that have a 'load' context as it's the
+        most common one.  This method is used in the parser to set assignment
+        targets and other nodes to a store context.
+        """
+        todo = deque([self])
+        while todo:
+            node = todo.popleft()
+            if 'ctx' in node.fields:
+                node.ctx = ctx
+            todo.extend(node.iter_child_nodes())
+        return self
+
+    def set_lineno(self, lineno, override=False):
+        """Set the line numbers of the node and children."""
+        todo = deque([self])
+        while todo:
+            node = todo.popleft()
+            if 'lineno' in node.attributes:
+                if node.lineno is None or override:
+                    node.lineno = lineno
+            todo.extend(node.iter_child_nodes())
+        return self
+
+    def set_environment(self, environment):
+        """Set the environment for all nodes."""
+        todo = deque([self])
+        while todo:
+            node = todo.popleft()
+            node.environment = environment
+            todo.extend(node.iter_child_nodes())
+        return self
+
+    def __eq__(self, other):
+        return type(self) is type(other) and \
+               tuple(self.iter_fields()) == tuple(other.iter_fields())
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def __repr__(self):
+        return '%s(%s)' % (
+            self.__class__.__name__,
+            ', '.join('%s=%r' % (arg, getattr(self, arg, None)) for
+                      arg in self.fields)
+        )
+
+
+class Stmt(Node):
+    """Base node for all statements."""
+    abstract = True
+
+
+class Helper(Node):
+    """Nodes that exist in a specific context only."""
+    abstract = True
+
+
+class Template(Node):
+    """Node that represents a template.  This must be the outermost node that
+    is passed to the compiler.
+    """
+    fields = ('body',)
+
+
+class Output(Stmt):
+    """A node that holds multiple expressions which are then printed out.
+    This is used both for the `print` statement and the regular template data.
+    """
+    fields = ('nodes',)
+
+
+class Extends(Stmt):
+    """Represents an extends statement."""
+    fields = ('template',)
+
+
+class For(Stmt):
+    """The for loop.  `target` is the target for the iteration (usually a
+    :class:`Name` or :class:`Tuple`), `iter` the iterable.  `body` is a list
+    of nodes that are used as loop-body, and `else_` a list of nodes for the
+    `else` block.  If no else node exists it has to be an empty list.
+
+    For filtered nodes an expression can be stored as `test`, otherwise `None`.
+    """
+    fields = ('target', 'iter', 'body', 'else_', 'test', 'recursive')
+
+
+class If(Stmt):
+    """If `test` is true, `body` is rendered, else `else_`."""
+    fields = ('test', 'body', 'else_')
+
+
+class Macro(Stmt):
+    """A macro definition.  `name` is the name of the macro, `args` a list of
+    arguments and `defaults` a list of defaults if there are any.  `body` is
+    a list of nodes for the macro body.
+    """
+    fields = ('name', 'args', 'defaults', 'body')
+
+
+class CallBlock(Stmt):
+    """Like a macro without a name but a call instead.  `call` is called with
+    the unnamed macro as `caller` argument this node holds.
+    """
+    fields = ('call', 'args', 'defaults', 'body')
+
+
+class FilterBlock(Stmt):
+    """Node for filter sections."""
+    fields = ('body', 'filter')
+
+
+class Block(Stmt):
+    """A node that represents a block."""
+    fields = ('name', 'body', 'scoped')
+
+
+class Include(Stmt):
+    """A node that represents the include tag."""
+    fields = ('template', 'with_context', 'ignore_missing')
+
+
+class Import(Stmt):
+    """A node that represents the import tag."""
+    fields = ('template', 'target', 'with_context')
+
+
+class FromImport(Stmt):
+    """A node that represents the from import tag.  It's important to not
+    pass unsafe names to the name attribute.  The compiler translates the
+    attribute lookups directly into getattr calls and does *not* use the
+    subscript callback of the interface.  As exported variables may not
+    start with double underscores (which the parser asserts) this is not a
+    problem for regular Jinja code, but if this node is used in an extension
+    extra care must be taken.
+
+    The list of names may contain tuples if aliases are wanted.
+    """
+    fields = ('template', 'names', 'with_context')
+
+
+class ExprStmt(Stmt):
+    """A statement that evaluates an expression and discards the result."""
+    fields = ('node',)
+
+
+class Assign(Stmt):
+    """Assigns an expression to a target."""
+    fields = ('target', 'node')
+
+
+class Expr(Node):
+    """Baseclass for all expressions."""
+    abstract = True
+
+    def as_const(self, eval_ctx=None):
+        """Return the value of the expression as constant or raise
+        :exc:`Impossible` if this was not possible.
+
+        An :class:`EvalContext` can be provided, if none is given
+        a default context is created which requires the nodes to have
+        an attached environment.
+
+        .. versionchanged:: 2.4
+           the `eval_ctx` parameter was added.
+        """
+        raise Impossible()
+
+    def can_assign(self):
+        """Check if it's possible to assign something to this node."""
+        return False
+
+
+class BinExpr(Expr):
+    """Baseclass for all binary expressions."""
+    fields = ('left', 'right')
+    operator = None
+    abstract = True
+
+    def as_const(self, eval_ctx=None):
+        eval_ctx = get_eval_context(self, eval_ctx)
+        # intercepted operators cannot be folded at compile time
+        if self.environment.sandboxed and \
+           self.operator in self.environment.intercepted_binops:
+            raise Impossible()
+        f = _binop_to_func[self.operator]
+        try:
+            return f(self.left.as_const(eval_ctx), self.right.as_const(eval_ctx))
+        except Exception:
+            raise Impossible()
+
+
+class UnaryExpr(Expr):
+    """Baseclass for all unary expressions."""
+    fields = ('node',)
+    operator = None
+    abstract = True
+
+    def as_const(self, eval_ctx=None):
+        eval_ctx = get_eval_context(self, eval_ctx)
+        # intercepted operators cannot be folded at compile time
+        if self.environment.sandboxed and \
+           self.operator in self.environment.intercepted_unops:
+            raise Impossible()
+        f = _uaop_to_func[self.operator]
+        try:
+            return f(self.node.as_const(eval_ctx))
+        except Exception:
+            raise Impossible()
+
+
+class Name(Expr):
+    """Looks up a name or stores a value in a name.
+    The `ctx` of the node can be one of the following values:
+
+    -   `store`: store a value in the name
+    -   `load`: load that name
+    -   `param`: like `store` but if the name was defined as function parameter.
+    """
+    fields = ('name', 'ctx')
+
+    def can_assign(self):
+        return self.name not in ('true', 'false', 'none',
+                                 'True', 'False', 'None')
+
+
+class Literal(Expr):
+    """Baseclass for literals."""
+    abstract = True
+
+
+class Const(Literal):
+    """All constant values.  The parser will return this node for simple
+    constants such as ``42`` or ``"foo"`` but it can be used to store more
+    complex values such as lists too.  Only constants with a safe
+    representation (objects where ``eval(repr(x)) == x`` is true).
+    """
+    fields = ('value',)
+
+    def as_const(self, eval_ctx=None):
+        return self.value
+
+    @classmethod
+    def from_untrusted(cls, value, lineno=None, environment=None):
+        """Return a const object if the value is representable as
+        constant value in the generated code, otherwise it will raise
+        an `Impossible` exception.
+        """
+        from compiler import has_safe_repr
+        if not has_safe_repr(value):
+            raise Impossible()
+        return cls(value, lineno=lineno, environment=environment)
+
+
+class TemplateData(Literal):
+    """A constant template string."""
+    fields = ('data',)
+
+    def as_const(self, eval_ctx=None):
+        eval_ctx = get_eval_context(self, eval_ctx)
+        if eval_ctx.volatile:
+            raise Impossible()
+        if eval_ctx.autoescape:
+            return Markup(self.data)
+        return self.data
+
+
+class Tuple(Literal):
+    """For loop unpacking and some other things like multiple arguments
+    for subscripts.  Like for :class:`Name` `ctx` specifies if the tuple
+    is used for loading the names or storing.
+    """
+    fields = ('items', 'ctx')
+
+    def as_const(self, eval_ctx=None):
+        eval_ctx = get_eval_context(self, eval_ctx)
+        return tuple(x.as_const(eval_ctx) for x in self.items)
+
+    def can_assign(self):
+        for item in self.items:
+            if not item.can_assign():
+                return False
+        return True
+
+
+class List(Literal):
+    """Any list literal such as ``[1, 2, 3]``"""
+    fields = ('items',)
+
+    def as_const(self, eval_ctx=None):
+        eval_ctx = get_eval_context(self, eval_ctx)
+        return [x.as_const(eval_ctx) for x in self.items]
+
+
+class Dict(Literal):
+    """Any dict literal such as ``{1: 2, 3: 4}``.  The items must be a list of
+    :class:`Pair` nodes.
+    """
+    fields = ('items',)
+
+    def as_const(self, eval_ctx=None):
+        eval_ctx = get_eval_context(self, eval_ctx)
+        return dict(x.as_const(eval_ctx) for x in self.items)
+
+
+class Pair(Helper):
+    """A key, value pair for dicts."""
+    fields = ('key', 'value')
+
+    def as_const(self, eval_ctx=None):
+        eval_ctx = get_eval_context(self, eval_ctx)
+        return self.key.as_const(eval_ctx), self.value.as_const(eval_ctx)
+
+
+class Keyword(Helper):
+    """A key, value pair for keyword arguments where key is a string."""
+    fields = ('key', 'value')
+
+    def as_const(self, eval_ctx=None):
+        eval_ctx = get_eval_context(self, eval_ctx)
+        return self.key, self.value.as_const(eval_ctx)
+
+
+class CondExpr(Expr):
+    """A conditional expression (inline if expression).  (``{{
+    foo if bar else baz }}``)
+    """
+    fields = ('test', 'expr1', 'expr2')
+
+    def as_const(self, eval_ctx=None):
+        eval_ctx = get_eval_context(self, eval_ctx)
+        if self.test.as_const(eval_ctx):
+            return self.expr1.as_const(eval_ctx)
+
+        # if we evaluate to an undefined object, we better do that at runtime
+        if self.expr2 is None:
+            raise Impossible()
+
+        return self.expr2.as_const(eval_ctx)
+
+
+class Filter(Expr):
+    """This node applies a filter on an expression.  `name` is the name of
+    the filter, the rest of the fields are the same as for :class:`Call`.
+
+    If the `node` of a filter is `None` the contents of the last buffer are
+    filtered.  Buffers are created by macros and filter blocks.
+    """
+    fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
+
+    def as_const(self, eval_ctx=None):
+        eval_ctx = get_eval_context(self, eval_ctx)
+        if eval_ctx.volatile or self.node is None:
+            raise Impossible()
+        # we have to be careful here because we call filter_ below.
+        # if this variable would be called filter, 2to3 would wrap the
+        # call in a list beause it is assuming we are talking about the
+        # builtin filter function here which no longer returns a list in
+        # python 3.  because of that, do not rename filter_ to filter!
+        filter_ = self.environment.filters.get(self.name)
+        if filter_ is None or getattr(filter_, 'contextfilter', False):
+            raise Impossible()
+        obj = self.node.as_const(eval_ctx)
+        args = [x.as_const(eval_ctx) for x in self.args]
+        if getattr(filter_, 'evalcontextfilter', False):
+            args.insert(0, eval_ctx)
+        elif getattr(filter_, 'environmentfilter', False):
+            args.insert(0, self.environment)
+        kwargs = dict(x.as_const(eval_ctx) for x in self.kwargs)
+        if self.dyn_args is not None:
+            try:
+                args.extend(self.dyn_args.as_const(eval_ctx))
+            except Exception:
+                raise Impossible()
+        if self.dyn_kwargs is not None:
+            try:
+                kwargs.update(self.dyn_kwargs.as_const(eval_ctx))
+            except Exception:
+                raise Impossible()
+        try:
+            return filter_(obj, *args, **kwargs)
+        except Exception:
+            raise Impossible()
+
+
+class Test(Expr):
+    """Applies a test on an expression.  `name` is the name of the test, the
+    rest of the fields are the same as for :class:`Call`.
+    """
+    fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
+
+
+class Call(Expr):
+    """Calls an expression.  `args` is a list of arguments, `kwargs` a list
+    of keyword arguments (list of :class:`Keyword` nodes), and `dyn_args`
+    and `dyn_kwargs` has to be either `None` or a node that is used as
+    node for dynamic positional (``*args``) or keyword (``**kwargs``)
+    arguments.
+    """
+    fields = ('node', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
+
+    def as_const(self, eval_ctx=None):
+        eval_ctx = get_eval_context(self, eval_ctx)
+        if eval_ctx.volatile:
+            raise Impossible()
+        obj = self.node.as_const(eval_ctx)
+
+        # don't evaluate context functions
+        args = [x.as_const(eval_ctx) for x in self.args]
+        if isinstance(obj, _context_function_types):
+            if getattr(obj, 'contextfunction', False):
+                raise Impossible()
+            elif getattr(obj, 'evalcontextfunction', False):
+                args.insert(0, eval_ctx)
+            elif getattr(obj, 'environmentfunction', False):
+                args.insert(0, self.environment)
+
+        kwargs = dict(x.as_const(eval_ctx) for x in self.kwargs)
+        if self.dyn_args is not None:
+            try:
+                args.extend(self.dyn_args.as_const(eval_ctx))
+            except Exception:
+                raise Impossible()
+        if self.dyn_kwargs is not None:
+            try:
+                kwargs.update(self.dyn_kwargs.as_const(eval_ctx))
+            except Exception:
+                raise Impossible()
+        try:
+            return obj(*args, **kwargs)
+        except Exception:
+            raise Impossible()
+
+
+class Getitem(Expr):
+    """Get an attribute or item from an expression and prefer the item."""
+    fields = ('node', 'arg', 'ctx')
+
+    def as_const(self, eval_ctx=None):
+        eval_ctx = get_eval_context(self, eval_ctx)
+        if self.ctx != 'load':
+            raise Impossible()
+        try:
+            return self.environment.getitem(self.node.as_const(eval_ctx),
+                                            self.arg.as_const(eval_ctx))
+        except Exception:
+            raise Impossible()
+
+    def can_assign(self):
+        return False
+
+
+class Getattr(Expr):
+    """Get an attribute or item from an expression that is a ascii-only
+    bytestring and prefer the attribute.
+    """
+    fields = ('node', 'attr', 'ctx')
+
+    def as_const(self, eval_ctx=None):
+        if self.ctx != 'load':
+            raise Impossible()
+        try:
+            eval_ctx = get_eval_context(self, eval_ctx)
+            return self.environment.getattr(self.node.as_const(eval_ctx),
+                                            self.attr)
+        except Exception:
+            raise Impossible()
+
+    def can_assign(self):
+        return False
+
+
+class Slice(Expr):
+    """Represents a slice object.  This must only be used as argument for
+    :class:`Subscript`.
+    """
+    fields = ('start', 'stop', 'step')
+
+    def as_const(self, eval_ctx=None):
+        eval_ctx = get_eval_context(self, eval_ctx)
+        def const(obj):
+            if obj is None:
+                return None
+            return obj.as_const(eval_ctx)
+        return slice(const(self.start), const(self.stop), const(self.step))
+
+
+class Concat(Expr):
+    """Concatenates the list of expressions provided after converting them to
+    unicode.
+    """
+    fields = ('nodes',)
+
+    def as_const(self, eval_ctx=None):
+        eval_ctx = get_eval_context(self, eval_ctx)
+        return ''.join(unicode(x.as_const(eval_ctx)) for x in self.nodes)
+
+
+class Compare(Expr):
+    """Compares an expression with some other expressions.  `ops` must be a
+    list of :class:`Operand`\s.
+    """
+    fields = ('expr', 'ops')
+
+    def as_const(self, eval_ctx=None):
+        eval_ctx = get_eval_context(self, eval_ctx)
+        result = value = self.expr.as_const(eval_ctx)
+        try:
+            for op in self.ops:
+                new_value = op.expr.as_const(eval_ctx)
+                result = _cmpop_to_func[op.op](value, new_value)
+                value = new_value
+        except Exception:
+            raise Impossible()
+        return result
+
+
+class Operand(Helper):
+    """Holds an operator and an expression."""
+    fields = ('op', 'expr')
+
+if __debug__:
+    Operand.__doc__ += '\nThe following operators are available: ' + \
+        ', '.join(sorted('``%s``' % x for x in set(_binop_to_func) |
+                  set(_uaop_to_func) | set(_cmpop_to_func)))
+
+
+class Mul(BinExpr):
+    """Multiplies the left with the right node."""
+    operator = '*'
+
+
+class Div(BinExpr):
+    """Divides the left by the right node."""
+    operator = '/'
+
+
+class FloorDiv(BinExpr):
+    """Divides the left by the right node and truncates conver the
+    result into an integer by truncating.
+    """
+    operator = '//'
+
+
+class Add(BinExpr):
+    """Add the left to the right node."""
+    operator = '+'
+
+
+class Sub(BinExpr):
+    """Substract the right from the left node."""
+    operator = '-'
+
+
+class Mod(BinExpr):
+    """Left modulo right."""
+    operator = '%'
+
+
+class Pow(BinExpr):
+    """Left to the power of right."""
+    operator = '**'
+
+
+class And(BinExpr):
+    """Short circuited AND."""
+    operator = 'and'
+
+    def as_const(self, eval_ctx=None):
+        eval_ctx = get_eval_context(self, eval_ctx)
+        return self.left.as_const(eval_ctx) and self.right.as_const(eval_ctx)
+
+
+class Or(BinExpr):
+    """Short circuited OR."""
+    operator = 'or'
+
+    def as_const(self, eval_ctx=None):
+        eval_ctx = get_eval_context(self, eval_ctx)
+        return self.left.as_const(eval_ctx) or self.right.as_const(eval_ctx)
+
+
+class Not(UnaryExpr):
+    """Negate the expression."""
+    operator = 'not'
+
+
+class Neg(UnaryExpr):
+    """Make the expression negative."""
+    operator = '-'
+
+
+class Pos(UnaryExpr):
+    """Make the expression positive (noop for most expressions)"""
+    operator = '+'
+
+
+# Helpers for extensions
+
+
+class EnvironmentAttribute(Expr):
+    """Loads an attribute from the environment object.  This is useful for
+    extensions that want to call a callback stored on the environment.
+    """
+    fields = ('name',)
+
+
+class ExtensionAttribute(Expr):
+    """Returns the attribute of an extension bound to the environment.
+    The identifier is the identifier of the :class:`Extension`.
+
+    This node is usually constructed by calling the
+    :meth:`~jinja2.ext.Extension.attr` method on an extension.
+    """
+    fields = ('identifier', 'name')
+
+
+class ImportedName(Expr):
+    """If created with an import name the import name is returned on node
+    access.  For example ``ImportedName('cgi.escape')`` returns the `escape`
+    function from the cgi module on evaluation.  Imports are optimized by the
+    compiler so there is no need to assign them to local variables.
+    """
+    fields = ('importname',)
+
+
+class InternalName(Expr):
+    """An internal name in the compiler.  You cannot create these nodes
+    yourself but the parser provides a
+    :meth:`~jinja2.parser.Parser.free_identifier` method that creates
+    a new identifier for you.  This identifier is not available from the
+    template and is not threated specially by the compiler.
+    """
+    fields = ('name',)
+
+    def __init__(self):
+        raise TypeError('Can\'t create internal names.  Use the '
+                        '`free_identifier` method on a parser.')
+
+
+class MarkSafe(Expr):
+    """Mark the wrapped expression as safe (wrap it as `Markup`)."""
+    fields = ('expr',)
+
+    def as_const(self, eval_ctx=None):
+        eval_ctx = get_eval_context(self, eval_ctx)
+        return Markup(self.expr.as_const(eval_ctx))
+
+
+class MarkSafeIfAutoescape(Expr):
+    """Mark the wrapped expression as safe (wrap it as `Markup`) but
+    only if autoescaping is active.
+
+    .. versionadded:: 2.5
+    """
+    fields = ('expr',)
+
+    def as_const(self, eval_ctx=None):
+        eval_ctx = get_eval_context(self, eval_ctx)
+        if eval_ctx.volatile:
+            raise Impossible()
+        expr = self.expr.as_const(eval_ctx)
+        if eval_ctx.autoescape:
+            return Markup(expr)
+        return expr
+
+
+class ContextReference(Expr):
+    """Returns the current template context.  It can be used like a
+    :class:`Name` node, with a ``'load'`` ctx and will return the
+    current :class:`~jinja2.runtime.Context` object.
+
+    Here an example that assigns the current template name to a
+    variable named `foo`::
+
+        Assign(Name('foo', ctx='store'),
+               Getattr(ContextReference(), 'name'))
+    """
+
+
+class Continue(Stmt):
+    """Continue a loop."""
+
+
+class Break(Stmt):
+    """Break a loop."""
+
+
+class Scope(Stmt):
+    """An artificial scope."""
+    fields = ('body',)
+
+
+class EvalContextModifier(Stmt):
+    """Modifies the eval context.  For each option that should be modified,
+    a :class:`Keyword` has to be added to the :attr:`options` list.
+
+    Example to change the `autoescape` setting::
+
+        EvalContextModifier(options=[Keyword('autoescape', Const(True))])
+    """
+    fields = ('options',)
+
+
+class ScopedEvalContextModifier(EvalContextModifier):
+    """Modifies the eval context and reverts it later.  Works exactly like
+    :class:`EvalContextModifier` but will only modify the
+    :class:`~jinja2.nodes.EvalContext` for nodes in the :attr:`body`.
+    """
+    fields = ('body',)
+
+
+# make sure nobody creates custom nodes
+def _failing_new(*args, **kwargs):
+    raise TypeError('can\'t create custom node types')
+NodeType.__new__ = staticmethod(_failing_new); del _failing_new
diff --git a/lib/jinja2/jinja2/optimizer.py b/lib/jinja2/jinja2/optimizer.py
new file mode 100644
index 0000000..00eab11
--- /dev/null
+++ b/lib/jinja2/jinja2/optimizer.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.optimizer
+    ~~~~~~~~~~~~~~~~
+
+    The jinja optimizer is currently trying to constant fold a few expressions
+    and modify the AST in place so that it should be easier to evaluate it.
+
+    Because the AST does not contain all the scoping information and the
+    compiler has to find that out, we cannot do all the optimizations we
+    want.  For example loop unrolling doesn't work because unrolled loops would
+    have a different scoping.
+
+    The solution would be a second syntax tree that has the scoping rules stored.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD.
+"""
+from jinja2 import nodes
+from jinja2.visitor import NodeTransformer
+
+
+def optimize(node, environment):
+    """The context hint can be used to perform an static optimization
+    based on the context given."""
+    optimizer = Optimizer(environment)
+    return optimizer.visit(node)
+
+
+class Optimizer(NodeTransformer):
+
+    def __init__(self, environment):
+        self.environment = environment
+
+    def visit_If(self, node):
+        """Eliminate dead code."""
+        # do not optimize ifs that have a block inside so that it doesn't
+        # break super().
+        if node.find(nodes.Block) is not None:
+            return self.generic_visit(node)
+        try:
+            val = self.visit(node.test).as_const()
+        except nodes.Impossible:
+            return self.generic_visit(node)
+        if val:
+            body = node.body
+        else:
+            body = node.else_
+        result = []
+        for node in body:
+            result.extend(self.visit_list(node))
+        return result
+
+    def fold(self, node):
+        """Do constant folding."""
+        node = self.generic_visit(node)
+        try:
+            return nodes.Const.from_untrusted(node.as_const(),
+                                              lineno=node.lineno,
+                                              environment=self.environment)
+        except nodes.Impossible:
+            return node
+
+    visit_Add = visit_Sub = visit_Mul = visit_Div = visit_FloorDiv = \
+    visit_Pow = visit_Mod = visit_And = visit_Or = visit_Pos = visit_Neg = \
+    visit_Not = visit_Compare = visit_Getitem = visit_Getattr = visit_Call = \
+    visit_Filter = visit_Test = visit_CondExpr = fold
+    del fold
diff --git a/lib/jinja2/jinja2/parser.py b/lib/jinja2/jinja2/parser.py
new file mode 100644
index 0000000..d44229a
--- /dev/null
+++ b/lib/jinja2/jinja2/parser.py
@@ -0,0 +1,896 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.parser
+    ~~~~~~~~~~~~~
+
+    Implements the template parser.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+from jinja2 import nodes
+from jinja2.exceptions import TemplateSyntaxError, TemplateAssertionError
+from jinja2.utils import next
+from jinja2.lexer import describe_token, describe_token_expr
+
+
+#: statements that callinto 
+_statement_keywords = frozenset(['for', 'if', 'block', 'extends', 'print',
+                                 'macro', 'include', 'from', 'import',
+                                 'set'])
+_compare_operators = frozenset(['eq', 'ne', 'lt', 'lteq', 'gt', 'gteq'])
+
+
+class Parser(object):
+    """This is the central parsing class Jinja2 uses.  It's passed to
+    extensions and can be used to parse expressions or statements.
+    """
+
+    def __init__(self, environment, source, name=None, filename=None,
+                 state=None):
+        self.environment = environment
+        self.stream = environment._tokenize(source, name, filename, state)
+        self.name = name
+        self.filename = filename
+        self.closed = False
+        self.extensions = {}
+        for extension in environment.iter_extensions():
+            for tag in extension.tags:
+                self.extensions[tag] = extension.parse
+        self._last_identifier = 0
+        self._tag_stack = []
+        self._end_token_stack = []
+
+    def fail(self, msg, lineno=None, exc=TemplateSyntaxError):
+        """Convenience method that raises `exc` with the message, passed
+        line number or last line number as well as the current name and
+        filename.
+        """
+        if lineno is None:
+            lineno = self.stream.current.lineno
+        raise exc(msg, lineno, self.name, self.filename)
+
+    def _fail_ut_eof(self, name, end_token_stack, lineno):
+        expected = []
+        for exprs in end_token_stack:
+            expected.extend(map(describe_token_expr, exprs))
+        if end_token_stack:
+            currently_looking = ' or '.join(
+                "'%s'" % describe_token_expr(expr)
+                for expr in end_token_stack[-1])
+        else:
+            currently_looking = None
+
+        if name is None:
+            message = ['Unexpected end of template.']
+        else:
+            message = ['Encountered unknown tag \'%s\'.' % name]
+
+        if currently_looking:
+            if name is not None and name in expected:
+                message.append('You probably made a nesting mistake. Jinja '
+                               'is expecting this tag, but currently looking '
+                               'for %s.' % currently_looking)
+            else:
+                message.append('Jinja was looking for the following tags: '
+                               '%s.' % currently_looking)
+
+        if self._tag_stack:
+            message.append('The innermost block that needs to be '
+                           'closed is \'%s\'.' % self._tag_stack[-1])
+
+        self.fail(' '.join(message), lineno)
+
+    def fail_unknown_tag(self, name, lineno=None):
+        """Called if the parser encounters an unknown tag.  Tries to fail
+        with a human readable error message that could help to identify
+        the problem.
+        """
+        return self._fail_ut_eof(name, self._end_token_stack, lineno)
+
+    def fail_eof(self, end_tokens=None, lineno=None):
+        """Like fail_unknown_tag but for end of template situations."""
+        stack = list(self._end_token_stack)
+        if end_tokens is not None:
+            stack.append(end_tokens)
+        return self._fail_ut_eof(None, stack, lineno)
+
+    def is_tuple_end(self, extra_end_rules=None):
+        """Are we at the end of a tuple?"""
+        if self.stream.current.type in ('variable_end', 'block_end', 'rparen'):
+            return True
+        elif extra_end_rules is not None:
+            return self.stream.current.test_any(extra_end_rules)
+        return False
+
+    def free_identifier(self, lineno=None):
+        """Return a new free identifier as :class:`~jinja2.nodes.InternalName`."""
+        self._last_identifier += 1
+        rv = object.__new__(nodes.InternalName)
+        nodes.Node.__init__(rv, 'fi%d' % self._last_identifier, lineno=lineno)
+        return rv
+
+    def parse_statement(self):
+        """Parse a single statement."""
+        token = self.stream.current
+        if token.type != 'name':
+            self.fail('tag name expected', token.lineno)
+        self._tag_stack.append(token.value)
+        pop_tag = True
+        try:
+            if token.value in _statement_keywords:
+                return getattr(self, 'parse_' + self.stream.current.value)()
+            if token.value == 'call':
+                return self.parse_call_block()
+            if token.value == 'filter':
+                return self.parse_filter_block()
+            ext = self.extensions.get(token.value)
+            if ext is not None:
+                return ext(self)
+
+            # did not work out, remove the token we pushed by accident
+            # from the stack so that the unknown tag fail function can
+            # produce a proper error message.
+            self._tag_stack.pop()
+            pop_tag = False
+            self.fail_unknown_tag(token.value, token.lineno)
+        finally:
+            if pop_tag:
+                self._tag_stack.pop()
+
+    def parse_statements(self, end_tokens, drop_needle=False):
+        """Parse multiple statements into a list until one of the end tokens
+        is reached.  This is used to parse the body of statements as it also
+        parses template data if appropriate.  The parser checks first if the
+        current token is a colon and skips it if there is one.  Then it checks
+        for the block end and parses until if one of the `end_tokens` is
+        reached.  Per default the active token in the stream at the end of
+        the call is the matched end token.  If this is not wanted `drop_needle`
+        can be set to `True` and the end token is removed.
+        """
+        # the first token may be a colon for python compatibility
+        self.stream.skip_if('colon')
+
+        # in the future it would be possible to add whole code sections
+        # by adding some sort of end of statement token and parsing those here.
+        self.stream.expect('block_end')
+        result = self.subparse(end_tokens)
+
+        # we reached the end of the template too early, the subparser
+        # does not check for this, so we do that now
+        if self.stream.current.type == 'eof':
+            self.fail_eof(end_tokens)
+
+        if drop_needle:
+            next(self.stream)
+        return result
+
+    def parse_set(self):
+        """Parse an assign statement."""
+        lineno = next(self.stream).lineno
+        target = self.parse_assign_target()
+        self.stream.expect('assign')
+        expr = self.parse_tuple()
+        return nodes.Assign(target, expr, lineno=lineno)
+
+    def parse_for(self):
+        """Parse a for loop."""
+        lineno = self.stream.expect('name:for').lineno
+        target = self.parse_assign_target(extra_end_rules=('name:in',))
+        self.stream.expect('name:in')
+        iter = self.parse_tuple(with_condexpr=False,
+                                extra_end_rules=('name:recursive',))
+        test = None
+        if self.stream.skip_if('name:if'):
+            test = self.parse_expression()
+        recursive = self.stream.skip_if('name:recursive')
+        body = self.parse_statements(('name:endfor', 'name:else'))
+        if next(self.stream).value == 'endfor':
+            else_ = []
+        else:
+            else_ = self.parse_statements(('name:endfor',), drop_needle=True)
+        return nodes.For(target, iter, body, else_, test,
+                         recursive, lineno=lineno)
+
+    def parse_if(self):
+        """Parse an if construct."""
+        node = result = nodes.If(lineno=self.stream.expect('name:if').lineno)
+        while 1:
+            node.test = self.parse_tuple(with_condexpr=False)
+            node.body = self.parse_statements(('name:elif', 'name:else',
+                                               'name:endif'))
+            token = next(self.stream)
+            if token.test('name:elif'):
+                new_node = nodes.If(lineno=self.stream.current.lineno)
+                node.else_ = [new_node]
+                node = new_node
+                continue
+            elif token.test('name:else'):
+                node.else_ = self.parse_statements(('name:endif',),
+                                                   drop_needle=True)
+            else:
+                node.else_ = []
+            break
+        return result
+
+    def parse_block(self):
+        node = nodes.Block(lineno=next(self.stream).lineno)
+        node.name = self.stream.expect('name').value
+        node.scoped = self.stream.skip_if('name:scoped')
+
+        # common problem people encounter when switching from django
+        # to jinja.  we do not support hyphens in block names, so let's
+        # raise a nicer error message in that case.
+        if self.stream.current.type == 'sub':
+            self.fail('Block names in Jinja have to be valid Python '
+                      'identifiers and may not contain hypens, use an '
+                      'underscore instead.')
+
+        node.body = self.parse_statements(('name:endblock',), drop_needle=True)
+        self.stream.skip_if('name:' + node.name)
+        return node
+
+    def parse_extends(self):
+        node = nodes.Extends(lineno=next(self.stream).lineno)
+        node.template = self.parse_expression()
+        return node
+
+    def parse_import_context(self, node, default):
+        if self.stream.current.test_any('name:with', 'name:without') and \
+           self.stream.look().test('name:context'):
+            node.with_context = next(self.stream).value == 'with'
+            self.stream.skip()
+        else:
+            node.with_context = default
+        return node
+
+    def parse_include(self):
+        node = nodes.Include(lineno=next(self.stream).lineno)
+        node.template = self.parse_expression()
+        if self.stream.current.test('name:ignore') and \
+           self.stream.look().test('name:missing'):
+            node.ignore_missing = True
+            self.stream.skip(2)
+        else:
+            node.ignore_missing = False
+        return self.parse_import_context(node, True)
+
+    def parse_import(self):
+        node = nodes.Import(lineno=next(self.stream).lineno)
+        node.template = self.parse_expression()
+        self.stream.expect('name:as')
+        node.target = self.parse_assign_target(name_only=True).name
+        return self.parse_import_context(node, False)
+
+    def parse_from(self):
+        node = nodes.FromImport(lineno=next(self.stream).lineno)
+        node.template = self.parse_expression()
+        self.stream.expect('name:import')
+        node.names = []
+
+        def parse_context():
+            if self.stream.current.value in ('with', 'without') and \
+               self.stream.look().test('name:context'):
+                node.with_context = next(self.stream).value == 'with'
+                self.stream.skip()
+                return True
+            return False
+
+        while 1:
+            if node.names:
+                self.stream.expect('comma')
+            if self.stream.current.type == 'name':
+                if parse_context():
+                    break
+                target = self.parse_assign_target(name_only=True)
+                if target.name.startswith('_'):
+                    self.fail('names starting with an underline can not '
+                              'be imported', target.lineno,
+                              exc=TemplateAssertionError)
+                if self.stream.skip_if('name:as'):
+                    alias = self.parse_assign_target(name_only=True)
+                    node.names.append((target.name, alias.name))
+                else:
+                    node.names.append(target.name)
+                if parse_context() or self.stream.current.type != 'comma':
+                    break
+            else:
+                break
+        if not hasattr(node, 'with_context'):
+            node.with_context = False
+            self.stream.skip_if('comma')
+        return node
+
+    def parse_signature(self, node):
+        node.args = args = []
+        node.defaults = defaults = []
+        self.stream.expect('lparen')
+        while self.stream.current.type != 'rparen':
+            if args:
+                self.stream.expect('comma')
+            arg = self.parse_assign_target(name_only=True)
+            arg.set_ctx('param')
+            if self.stream.skip_if('assign'):
+                defaults.append(self.parse_expression())
+            args.append(arg)
+        self.stream.expect('rparen')
+
+    def parse_call_block(self):
+        node = nodes.CallBlock(lineno=next(self.stream).lineno)
+        if self.stream.current.type == 'lparen':
+            self.parse_signature(node)
+        else:
+            node.args = []
+            node.defaults = []
+
+        node.call = self.parse_expression()
+        if not isinstance(node.call, nodes.Call):
+            self.fail('expected call', node.lineno)
+        node.body = self.parse_statements(('name:endcall',), drop_needle=True)
+        return node
+
+    def parse_filter_block(self):
+        node = nodes.FilterBlock(lineno=next(self.stream).lineno)
+        node.filter = self.parse_filter(None, start_inline=True)
+        node.body = self.parse_statements(('name:endfilter',),
+                                          drop_needle=True)
+        return node
+
+    def parse_macro(self):
+        node = nodes.Macro(lineno=next(self.stream).lineno)
+        node.name = self.parse_assign_target(name_only=True).name
+        self.parse_signature(node)
+        node.body = self.parse_statements(('name:endmacro',),
+                                          drop_needle=True)
+        return node
+
+    def parse_print(self):
+        node = nodes.Output(lineno=next(self.stream).lineno)
+        node.nodes = []
+        while self.stream.current.type != 'block_end':
+            if node.nodes:
+                self.stream.expect('comma')
+            node.nodes.append(self.parse_expression())
+        return node
+
+    def parse_assign_target(self, with_tuple=True, name_only=False,
+                            extra_end_rules=None):
+        """Parse an assignment target.  As Jinja2 allows assignments to
+        tuples, this function can parse all allowed assignment targets.  Per
+        default assignments to tuples are parsed, that can be disable however
+        by setting `with_tuple` to `False`.  If only assignments to names are
+        wanted `name_only` can be set to `True`.  The `extra_end_rules`
+        parameter is forwarded to the tuple parsing function.
+        """
+        if name_only:
+            token = self.stream.expect('name')
+            target = nodes.Name(token.value, 'store', lineno=token.lineno)
+        else:
+            if with_tuple:
+                target = self.parse_tuple(simplified=True,
+                                          extra_end_rules=extra_end_rules)
+            else:
+                target = self.parse_primary()
+            target.set_ctx('store')
+        if not target.can_assign():
+            self.fail('can\'t assign to %r' % target.__class__.
+                      __name__.lower(), target.lineno)
+        return target
+
+    def parse_expression(self, with_condexpr=True):
+        """Parse an expression.  Per default all expressions are parsed, if
+        the optional `with_condexpr` parameter is set to `False` conditional
+        expressions are not parsed.
+        """
+        if with_condexpr:
+            return self.parse_condexpr()
+        return self.parse_or()
+
+    def parse_condexpr(self):
+        lineno = self.stream.current.lineno
+        expr1 = self.parse_or()
+        while self.stream.skip_if('name:if'):
+            expr2 = self.parse_or()
+            if self.stream.skip_if('name:else'):
+                expr3 = self.parse_condexpr()
+            else:
+                expr3 = None
+            expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno)
+            lineno = self.stream.current.lineno
+        return expr1
+
+    def parse_or(self):
+        lineno = self.stream.current.lineno
+        left = self.parse_and()
+        while self.stream.skip_if('name:or'):
+            right = self.parse_and()
+            left = nodes.Or(left, right, lineno=lineno)
+            lineno = self.stream.current.lineno
+        return left
+
+    def parse_and(self):
+        lineno = self.stream.current.lineno
+        left = self.parse_not()
+        while self.stream.skip_if('name:and'):
+            right = self.parse_not()
+            left = nodes.And(left, right, lineno=lineno)
+            lineno = self.stream.current.lineno
+        return left
+
+    def parse_not(self):
+        if self.stream.current.test('name:not'):
+            lineno = next(self.stream).lineno
+            return nodes.Not(self.parse_not(), lineno=lineno)
+        return self.parse_compare()
+
+    def parse_compare(self):
+        lineno = self.stream.current.lineno
+        expr = self.parse_add()
+        ops = []
+        while 1:
+            token_type = self.stream.current.type
+            if token_type in _compare_operators:
+                next(self.stream)
+                ops.append(nodes.Operand(token_type, self.parse_add()))
+            elif self.stream.skip_if('name:in'):
+                ops.append(nodes.Operand('in', self.parse_add()))
+            elif self.stream.current.test('name:not') and \
+                 self.stream.look().test('name:in'):
+                self.stream.skip(2)
+                ops.append(nodes.Operand('notin', self.parse_add()))
+            else:
+                break
+            lineno = self.stream.current.lineno
+        if not ops:
+            return expr
+        return nodes.Compare(expr, ops, lineno=lineno)
+
+    def parse_add(self):
+        lineno = self.stream.current.lineno
+        left = self.parse_sub()
+        while self.stream.current.type == 'add':
+            next(self.stream)
+            right = self.parse_sub()
+            left = nodes.Add(left, right, lineno=lineno)
+            lineno = self.stream.current.lineno
+        return left
+
+    def parse_sub(self):
+        lineno = self.stream.current.lineno
+        left = self.parse_concat()
+        while self.stream.current.type == 'sub':
+            next(self.stream)
+            right = self.parse_concat()
+            left = nodes.Sub(left, right, lineno=lineno)
+            lineno = self.stream.current.lineno
+        return left
+
+    def parse_concat(self):
+        lineno = self.stream.current.lineno
+        args = [self.parse_mul()]
+        while self.stream.current.type == 'tilde':
+            next(self.stream)
+            args.append(self.parse_mul())
+        if len(args) == 1:
+            return args[0]
+        return nodes.Concat(args, lineno=lineno)
+
+    def parse_mul(self):
+        lineno = self.stream.current.lineno
+        left = self.parse_div()
+        while self.stream.current.type == 'mul':
+            next(self.stream)
+            right = self.parse_div()
+            left = nodes.Mul(left, right, lineno=lineno)
+            lineno = self.stream.current.lineno
+        return left
+
+    def parse_div(self):
+        lineno = self.stream.current.lineno
+        left = self.parse_floordiv()
+        while self.stream.current.type == 'div':
+            next(self.stream)
+            right = self.parse_floordiv()
+            left = nodes.Div(left, right, lineno=lineno)
+            lineno = self.stream.current.lineno
+        return left
+
+    def parse_floordiv(self):
+        lineno = self.stream.current.lineno
+        left = self.parse_mod()
+        while self.stream.current.type == 'floordiv':
+            next(self.stream)
+            right = self.parse_mod()
+            left = nodes.FloorDiv(left, right, lineno=lineno)
+            lineno = self.stream.current.lineno
+        return left
+
+    def parse_mod(self):
+        lineno = self.stream.current.lineno
+        left = self.parse_pow()
+        while self.stream.current.type == 'mod':
+            next(self.stream)
+            right = self.parse_pow()
+            left = nodes.Mod(left, right, lineno=lineno)
+            lineno = self.stream.current.lineno
+        return left
+
+    def parse_pow(self):
+        lineno = self.stream.current.lineno
+        left = self.parse_unary()
+        while self.stream.current.type == 'pow':
+            next(self.stream)
+            right = self.parse_unary()
+            left = nodes.Pow(left, right, lineno=lineno)
+            lineno = self.stream.current.lineno
+        return left
+
+    def parse_unary(self, with_filter=True):
+        token_type = self.stream.current.type
+        lineno = self.stream.current.lineno
+        if token_type == 'sub':
+            next(self.stream)
+            node = nodes.Neg(self.parse_unary(False), lineno=lineno)
+        elif token_type == 'add':
+            next(self.stream)
+            node = nodes.Pos(self.parse_unary(False), lineno=lineno)
+        else:
+            node = self.parse_primary()
+        node = self.parse_postfix(node)
+        if with_filter:
+            node = self.parse_filter_expr(node)
+        return node
+
+    def parse_primary(self):
+        token = self.stream.current
+        if token.type == 'name':
+            if token.value in ('true', 'false', 'True', 'False'):
+                node = nodes.Const(token.value in ('true', 'True'),
+                                   lineno=token.lineno)
+            elif token.value in ('none', 'None'):
+                node = nodes.Const(None, lineno=token.lineno)
+            else:
+                node = nodes.Name(token.value, 'load', lineno=token.lineno)
+            next(self.stream)
+        elif token.type == 'string':
+            next(self.stream)
+            buf = [token.value]
+            lineno = token.lineno
+            while self.stream.current.type == 'string':
+                buf.append(self.stream.current.value)
+                next(self.stream)
+            node = nodes.Const(''.join(buf), lineno=lineno)
+        elif token.type in ('integer', 'float'):
+            next(self.stream)
+            node = nodes.Const(token.value, lineno=token.lineno)
+        elif token.type == 'lparen':
+            next(self.stream)
+            node = self.parse_tuple(explicit_parentheses=True)
+            self.stream.expect('rparen')
+        elif token.type == 'lbracket':
+            node = self.parse_list()
+        elif token.type == 'lbrace':
+            node = self.parse_dict()
+        else:
+            self.fail("unexpected '%s'" % describe_token(token), token.lineno)
+        return node
+
+    def parse_tuple(self, simplified=False, with_condexpr=True,
+                    extra_end_rules=None, explicit_parentheses=False):
+        """Works like `parse_expression` but if multiple expressions are
+        delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
+        This method could also return a regular expression instead of a tuple
+        if no commas where found.
+
+        The default parsing mode is a full tuple.  If `simplified` is `True`
+        only names and literals are parsed.  The `no_condexpr` parameter is
+        forwarded to :meth:`parse_expression`.
+
+        Because tuples do not require delimiters and may end in a bogus comma
+        an extra hint is needed that marks the end of a tuple.  For example
+        for loops support tuples between `for` and `in`.  In that case the
+        `extra_end_rules` is set to ``['name:in']``.
+
+        `explicit_parentheses` is true if the parsing was triggered by an
+        expression in parentheses.  This is used to figure out if an empty
+        tuple is a valid expression or not.
+        """
+        lineno = self.stream.current.lineno
+        if simplified:
+            parse = self.parse_primary
+        elif with_condexpr:
+            parse = self.parse_expression
+        else:
+            parse = lambda: self.parse_expression(with_condexpr=False)
+        args = []
+        is_tuple = False
+        while 1:
+            if args:
+                self.stream.expect('comma')
+            if self.is_tuple_end(extra_end_rules):
+                break
+            args.append(parse())
+            if self.stream.current.type == 'comma':
+                is_tuple = True
+            else:
+                break
+            lineno = self.stream.current.lineno
+
+        if not is_tuple:
+            if args:
+                return args[0]
+
+            # if we don't have explicit parentheses, an empty tuple is
+            # not a valid expression.  This would mean nothing (literally
+            # nothing) in the spot of an expression would be an empty
+            # tuple.
+            if not explicit_parentheses:
+                self.fail('Expected an expression, got \'%s\'' %
+                          describe_token(self.stream.current))
+
+        return nodes.Tuple(args, 'load', lineno=lineno)
+
+    def parse_list(self):
+        token = self.stream.expect('lbracket')
+        items = []
+        while self.stream.current.type != 'rbracket':
+            if items:
+                self.stream.expect('comma')
+            if self.stream.current.type == 'rbracket':
+                break
+            items.append(self.parse_expression())
+        self.stream.expect('rbracket')
+        return nodes.List(items, lineno=token.lineno)
+
+    def parse_dict(self):
+        token = self.stream.expect('lbrace')
+        items = []
+        while self.stream.current.type != 'rbrace':
+            if items:
+                self.stream.expect('comma')
+            if self.stream.current.type == 'rbrace':
+                break
+            key = self.parse_expression()
+            self.stream.expect('colon')
+            value = self.parse_expression()
+            items.append(nodes.Pair(key, value, lineno=key.lineno))
+        self.stream.expect('rbrace')
+        return nodes.Dict(items, lineno=token.lineno)
+
+    def parse_postfix(self, node):
+        while 1:
+            token_type = self.stream.current.type
+            if token_type == 'dot' or token_type == 'lbracket':
+                node = self.parse_subscript(node)
+            # calls are valid both after postfix expressions (getattr
+            # and getitem) as well as filters and tests
+            elif token_type == 'lparen':
+                node = self.parse_call(node)
+            else:
+                break
+        return node
+
+    def parse_filter_expr(self, node):
+        while 1:
+            token_type = self.stream.current.type
+            if token_type == 'pipe':
+                node = self.parse_filter(node)
+            elif token_type == 'name' and self.stream.current.value == 'is':
+                node = self.parse_test(node)
+            # calls are valid both after postfix expressions (getattr
+            # and getitem) as well as filters and tests
+            elif token_type == 'lparen':
+                node = self.parse_call(node)
+            else:
+                break
+        return node
+
+    def parse_subscript(self, node):
+        token = next(self.stream)
+        if token.type == 'dot':
+            attr_token = self.stream.current
+            next(self.stream)
+            if attr_token.type == 'name':
+                return nodes.Getattr(node, attr_token.value, 'load',
+                                     lineno=token.lineno)
+            elif attr_token.type != 'integer':
+                self.fail('expected name or number', attr_token.lineno)
+            arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
+            return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
+        if token.type == 'lbracket':
+            priority_on_attribute = False
+            args = []
+            while self.stream.current.type != 'rbracket':
+                if args:
+                    self.stream.expect('comma')
+                args.append(self.parse_subscribed())
+            self.stream.expect('rbracket')
+            if len(args) == 1:
+                arg = args[0]
+            else:
+                arg = nodes.Tuple(args, 'load', lineno=token.lineno)
+            return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
+        self.fail('expected subscript expression', self.lineno)
+
+    def parse_subscribed(self):
+        lineno = self.stream.current.lineno
+
+        if self.stream.current.type == 'colon':
+            next(self.stream)
+            args = [None]
+        else:
+            node = self.parse_expression()
+            if self.stream.current.type != 'colon':
+                return node
+            next(self.stream)
+            args = [node]
+
+        if self.stream.current.type == 'colon':
+            args.append(None)
+        elif self.stream.current.type not in ('rbracket', 'comma'):
+            args.append(self.parse_expression())
+        else:
+            args.append(None)
+
+        if self.stream.current.type == 'colon':
+            next(self.stream)
+            if self.stream.current.type not in ('rbracket', 'comma'):
+                args.append(self.parse_expression())
+            else:
+                args.append(None)
+        else:
+            args.append(None)
+
+        return nodes.Slice(lineno=lineno, *args)
+
+    def parse_call(self, node):
+        token = self.stream.expect('lparen')
+        args = []
+        kwargs = []
+        dyn_args = dyn_kwargs = None
+        require_comma = False
+
+        def ensure(expr):
+            if not expr:
+                self.fail('invalid syntax for function call expression',
+                          token.lineno)
+
+        while self.stream.current.type != 'rparen':
+            if require_comma:
+                self.stream.expect('comma')
+                # support for trailing comma
+                if self.stream.current.type == 'rparen':
+                    break
+            if self.stream.current.type == 'mul':
+                ensure(dyn_args is None and dyn_kwargs is None)
+                next(self.stream)
+                dyn_args = self.parse_expression()
+            elif self.stream.current.type == 'pow':
+                ensure(dyn_kwargs is None)
+                next(self.stream)
+                dyn_kwargs = self.parse_expression()
+            else:
+                ensure(dyn_args is None and dyn_kwargs is None)
+                if self.stream.current.type == 'name' and \
+                    self.stream.look().type == 'assign':
+                    key = self.stream.current.value
+                    self.stream.skip(2)
+                    value = self.parse_expression()
+                    kwargs.append(nodes.Keyword(key, value,
+                                                lineno=value.lineno))
+                else:
+                    ensure(not kwargs)
+                    args.append(self.parse_expression())
+
+            require_comma = True
+        self.stream.expect('rparen')
+
+        if node is None:
+            return args, kwargs, dyn_args, dyn_kwargs
+        return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs,
+                          lineno=token.lineno)
+
+    def parse_filter(self, node, start_inline=False):
+        while self.stream.current.type == 'pipe' or start_inline:
+            if not start_inline:
+                next(self.stream)
+            token = self.stream.expect('name')
+            name = token.value
+            while self.stream.current.type == 'dot':
+                next(self.stream)
+                name += '.' + self.stream.expect('name').value
+            if self.stream.current.type == 'lparen':
+                args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
+            else:
+                args = []
+                kwargs = []
+                dyn_args = dyn_kwargs = None
+            node = nodes.Filter(node, name, args, kwargs, dyn_args,
+                                dyn_kwargs, lineno=token.lineno)
+            start_inline = False
+        return node
+
+    def parse_test(self, node):
+        token = next(self.stream)
+        if self.stream.current.test('name:not'):
+            next(self.stream)
+            negated = True
+        else:
+            negated = False
+        name = self.stream.expect('name').value
+        while self.stream.current.type == 'dot':
+            next(self.stream)
+            name += '.' + self.stream.expect('name').value
+        dyn_args = dyn_kwargs = None
+        kwargs = []
+        if self.stream.current.type == 'lparen':
+            args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
+        elif self.stream.current.type in ('name', 'string', 'integer',
+                                          'float', 'lparen', 'lbracket',
+                                          'lbrace') and not \
+             self.stream.current.test_any('name:else', 'name:or',
+                                          'name:and'):
+            if self.stream.current.test('name:is'):
+                self.fail('You cannot chain multiple tests with is')
+            args = [self.parse_expression()]
+        else:
+            args = []
+        node = nodes.Test(node, name, args, kwargs, dyn_args,
+                          dyn_kwargs, lineno=token.lineno)
+        if negated:
+            node = nodes.Not(node, lineno=token.lineno)
+        return node
+
+    def subparse(self, end_tokens=None):
+        body = []
+        data_buffer = []
+        add_data = data_buffer.append
+
+        if end_tokens is not None:
+            self._end_token_stack.append(end_tokens)
+
+        def flush_data():
+            if data_buffer:
+                lineno = data_buffer[0].lineno
+                body.append(nodes.Output(data_buffer[:], lineno=lineno))
+                del data_buffer[:]
+
+        try:
+            while self.stream:
+                token = self.stream.current
+                if token.type == 'data':
+                    if token.value:
+                        add_data(nodes.TemplateData(token.value,
+                                                    lineno=token.lineno))
+                    next(self.stream)
+                elif token.type == 'variable_begin':
+                    next(self.stream)
+                    add_data(self.parse_tuple(with_condexpr=True))
+                    self.stream.expect('variable_end')
+                elif token.type == 'block_begin':
+                    flush_data()
+                    next(self.stream)
+                    if end_tokens is not None and \
+                       self.stream.current.test_any(*end_tokens):
+                        return body
+                    rv = self.parse_statement()
+                    if isinstance(rv, list):
+                        body.extend(rv)
+                    else:
+                        body.append(rv)
+                    self.stream.expect('block_end')
+                else:
+                    raise AssertionError('internal parsing error')
+
+            flush_data()
+        finally:
+            if end_tokens is not None:
+                self._end_token_stack.pop()
+
+        return body
+
+    def parse(self):
+        """Parse the whole template into a `Template` node."""
+        result = nodes.Template(self.subparse(), lineno=1)
+        result.set_environment(self.environment)
+        return result
diff --git a/lib/jinja2/jinja2/runtime.py b/lib/jinja2/jinja2/runtime.py
new file mode 100644
index 0000000..a4a47a2
--- /dev/null
+++ b/lib/jinja2/jinja2/runtime.py
@@ -0,0 +1,548 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.runtime
+    ~~~~~~~~~~~~~~
+
+    Runtime helpers.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD.
+"""
+from itertools import chain, imap
+from jinja2.nodes import EvalContext, _context_function_types
+from jinja2.utils import Markup, partial, soft_unicode, escape, missing, \
+     concat, internalcode, next, object_type_repr
+from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \
+     TemplateNotFound
+
+
+# these variables are exported to the template runtime
+__all__ = ['LoopContext', 'TemplateReference', 'Macro', 'Markup',
+           'TemplateRuntimeError', 'missing', 'concat', 'escape',
+           'markup_join', 'unicode_join', 'to_string', 'identity',
+           'TemplateNotFound']
+
+#: the name of the function that is used to convert something into
+#: a string.  2to3 will adopt that automatically and the generated
+#: code can take advantage of it.
+to_string = unicode
+
+#: the identity function.  Useful for certain things in the environment
+identity = lambda x: x
+
+
+def markup_join(seq):
+    """Concatenation that escapes if necessary and converts to unicode."""
+    buf = []
+    iterator = imap(soft_unicode, seq)
+    for arg in iterator:
+        buf.append(arg)
+        if hasattr(arg, '__html__'):
+            return Markup(u'').join(chain(buf, iterator))
+    return concat(buf)
+
+
+def unicode_join(seq):
+    """Simple args to unicode conversion and concatenation."""
+    return concat(imap(unicode, seq))
+
+
+def new_context(environment, template_name, blocks, vars=None,
+                shared=None, globals=None, locals=None):
+    """Internal helper to for context creation."""
+    if vars is None:
+        vars = {}
+    if shared:
+        parent = vars
+    else:
+        parent = dict(globals or (), **vars)
+    if locals:
+        # if the parent is shared a copy should be created because
+        # we don't want to modify the dict passed
+        if shared:
+            parent = dict(parent)
+        for key, value in locals.iteritems():
+            if key[:2] == 'l_' and value is not missing:
+                parent[key[2:]] = value
+    return Context(environment, parent, template_name, blocks)
+
+
+class TemplateReference(object):
+    """The `self` in templates."""
+
+    def __init__(self, context):
+        self.__context = context
+
+    def __getitem__(self, name):
+        blocks = self.__context.blocks[name]
+        return BlockReference(name, self.__context, blocks, 0)
+
+    def __repr__(self):
+        return '<%s %r>' % (
+            self.__class__.__name__,
+            self.__context.name
+        )
+
+
+class Context(object):
+    """The template context holds the variables of a template.  It stores the
+    values passed to the template and also the names the template exports.
+    Creating instances is neither supported nor useful as it's created
+    automatically at various stages of the template evaluation and should not
+    be created by hand.
+
+    The context is immutable.  Modifications on :attr:`parent` **must not**
+    happen and modifications on :attr:`vars` are allowed from generated
+    template code only.  Template filters and global functions marked as
+    :func:`contextfunction`\s get the active context passed as first argument
+    and are allowed to access the context read-only.
+
+    The template context supports read only dict operations (`get`,
+    `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,
+    `__getitem__`, `__contains__`).  Additionally there is a :meth:`resolve`
+    method that doesn't fail with a `KeyError` but returns an
+    :class:`Undefined` object for missing variables.
+    """
+    __slots__ = ('parent', 'vars', 'environment', 'eval_ctx', 'exported_vars',
+                 'name', 'blocks', '__weakref__')
+
+    def __init__(self, environment, parent, name, blocks):
+        self.parent = parent
+        self.vars = {}
+        self.environment = environment
+        self.eval_ctx = EvalContext(self.environment, name)
+        self.exported_vars = set()
+        self.name = name
+
+        # create the initial mapping of blocks.  Whenever template inheritance
+        # takes place the runtime will update this mapping with the new blocks
+        # from the template.
+        self.blocks = dict((k, [v]) for k, v in blocks.iteritems())
+
+    def super(self, name, current):
+        """Render a parent block."""
+        try:
+            blocks = self.blocks[name]
+            index = blocks.index(current) + 1
+            blocks[index]
+        except LookupError:
+            return self.environment.undefined('there is no parent block '
+                                              'called %r.' % name,
+                                              name='super')
+        return BlockReference(name, self, blocks, index)
+
+    def get(self, key, default=None):
+        """Returns an item from the template context, if it doesn't exist
+        `default` is returned.
+        """
+        try:
+            return self[key]
+        except KeyError:
+            return default
+
+    def resolve(self, key):
+        """Looks up a variable like `__getitem__` or `get` but returns an
+        :class:`Undefined` object with the name of the name looked up.
+        """
+        if key in self.vars:
+            return self.vars[key]
+        if key in self.parent:
+            return self.parent[key]
+        return self.environment.undefined(name=key)
+
+    def get_exported(self):
+        """Get a new dict with the exported variables."""
+        return dict((k, self.vars[k]) for k in self.exported_vars)
+
+    def get_all(self):
+        """Return a copy of the complete context as dict including the
+        exported variables.
+        """
+        return dict(self.parent, **self.vars)
+
+    @internalcode
+    def call(__self, __obj, *args, **kwargs):
+        """Call the callable with the arguments and keyword arguments
+        provided but inject the active context or environment as first
+        argument if the callable is a :func:`contextfunction` or
+        :func:`environmentfunction`.
+        """
+        if __debug__:
+            __traceback_hide__ = True
+        if isinstance(__obj, _context_function_types):
+            if getattr(__obj, 'contextfunction', 0):
+                args = (__self,) + args
+            elif getattr(__obj, 'evalcontextfunction', 0):
+                args = (__self.eval_ctx,) + args
+            elif getattr(__obj, 'environmentfunction', 0):
+                args = (__self.environment,) + args
+        try:
+            return __obj(*args, **kwargs)
+        except StopIteration:
+            return __self.environment.undefined('value was undefined because '
+                                                'a callable raised a '
+                                                'StopIteration exception')
+
+    def derived(self, locals=None):
+        """Internal helper function to create a derived context."""
+        context = new_context(self.environment, self.name, {},
+                              self.parent, True, None, locals)
+        context.vars.update(self.vars)
+        context.eval_ctx = self.eval_ctx
+        context.blocks.update((k, list(v)) for k, v in self.blocks.iteritems())
+        return context
+
+    def _all(meth):
+        proxy = lambda self: getattr(self.get_all(), meth)()
+        proxy.__doc__ = getattr(dict, meth).__doc__
+        proxy.__name__ = meth
+        return proxy
+
+    keys = _all('keys')
+    values = _all('values')
+    items = _all('items')
+
+    # not available on python 3
+    if hasattr(dict, 'iterkeys'):
+        iterkeys = _all('iterkeys')
+        itervalues = _all('itervalues')
+        iteritems = _all('iteritems')
+    del _all
+
+    def __contains__(self, name):
+        return name in self.vars or name in self.parent
+
+    def __getitem__(self, key):
+        """Lookup a variable or raise `KeyError` if the variable is
+        undefined.
+        """
+        item = self.resolve(key)
+        if isinstance(item, Undefined):
+            raise KeyError(key)
+        return item
+
+    def __repr__(self):
+        return '<%s %s of %r>' % (
+            self.__class__.__name__,
+            repr(self.get_all()),
+            self.name
+        )
+
+
+# register the context as mapping if possible
+try:
+    from collections import Mapping
+    Mapping.register(Context)
+except ImportError:
+    pass
+
+
+class BlockReference(object):
+    """One block on a template reference."""
+
+    def __init__(self, name, context, stack, depth):
+        self.name = name
+        self._context = context
+        self._stack = stack
+        self._depth = depth
+
+    @property
+    def super(self):
+        """Super the block."""
+        if self._depth + 1 >= len(self._stack):
+            return self._context.environment. \
+                undefined('there is no parent block called %r.' %
+                          self.name, name='super')
+        return BlockReference(self.name, self._context, self._stack,
+                              self._depth + 1)
+
+    @internalcode
+    def __call__(self):
+        rv = concat(self._stack[self._depth](self._context))
+        if self._context.eval_ctx.autoescape:
+            rv = Markup(rv)
+        return rv
+
+
+class LoopContext(object):
+    """A loop context for dynamic iteration."""
+
+    def __init__(self, iterable, recurse=None):
+        self._iterator = iter(iterable)
+        self._recurse = recurse
+        self.index0 = -1
+
+        # try to get the length of the iterable early.  This must be done
+        # here because there are some broken iterators around where there
+        # __len__ is the number of iterations left (i'm looking at your
+        # listreverseiterator!).
+        try:
+            self._length = len(iterable)
+        except (TypeError, AttributeError):
+            self._length = None
+
+    def cycle(self, *args):
+        """Cycles among the arguments with the current loop index."""
+        if not args:
+            raise TypeError('no items for cycling given')
+        return args[self.index0 % len(args)]
+
+    first = property(lambda x: x.index0 == 0)
+    last = property(lambda x: x.index0 + 1 == x.length)
+    index = property(lambda x: x.index0 + 1)
+    revindex = property(lambda x: x.length - x.index0)
+    revindex0 = property(lambda x: x.length - x.index)
+
+    def __len__(self):
+        return self.length
+
+    def __iter__(self):
+        return LoopContextIterator(self)
+
+    @internalcode
+    def loop(self, iterable):
+        if self._recurse is None:
+            raise TypeError('Tried to call non recursive loop.  Maybe you '
+                            "forgot the 'recursive' modifier.")
+        return self._recurse(iterable, self._recurse)
+
+    # a nifty trick to enhance the error message if someone tried to call
+    # the the loop without or with too many arguments.
+    __call__ = loop
+    del loop
+
+    @property
+    def length(self):
+        if self._length is None:
+            # if was not possible to get the length of the iterator when
+            # the loop context was created (ie: iterating over a generator)
+            # we have to convert the iterable into a sequence and use the
+            # length of that.
+            iterable = tuple(self._iterator)
+            self._iterator = iter(iterable)
+            self._length = len(iterable) + self.index0 + 1
+        return self._length
+
+    def __repr__(self):
+        return '<%s %r/%r>' % (
+            self.__class__.__name__,
+            self.index,
+            self.length
+        )
+
+
+class LoopContextIterator(object):
+    """The iterator for a loop context."""
+    __slots__ = ('context',)
+
+    def __init__(self, context):
+        self.context = context
+
+    def __iter__(self):
+        return self
+
+    def next(self):
+        ctx = self.context
+        ctx.index0 += 1
+        return next(ctx._iterator), ctx
+
+
+class Macro(object):
+    """Wraps a macro function."""
+
+    def __init__(self, environment, func, name, arguments, defaults,
+                 catch_kwargs, catch_varargs, caller):
+        self._environment = environment
+        self._func = func
+        self._argument_count = len(arguments)
+        self.name = name
+        self.arguments = arguments
+        self.defaults = defaults
+        self.catch_kwargs = catch_kwargs
+        self.catch_varargs = catch_varargs
+        self.caller = caller
+
+    @internalcode
+    def __call__(self, *args, **kwargs):
+        # try to consume the positional arguments
+        arguments = list(args[:self._argument_count])
+        off = len(arguments)
+
+        # if the number of arguments consumed is not the number of
+        # arguments expected we start filling in keyword arguments
+        # and defaults.
+        if off != self._argument_count:
+            for idx, name in enumerate(self.arguments[len(arguments):]):
+                try:
+                    value = kwargs.pop(name)
+                except KeyError:
+                    try:
+                        value = self.defaults[idx - self._argument_count + off]
+                    except IndexError:
+                        value = self._environment.undefined(
+                            'parameter %r was not provided' % name, name=name)
+                arguments.append(value)
+
+        # it's important that the order of these arguments does not change
+        # if not also changed in the compiler's `function_scoping` method.
+        # the order is caller, keyword arguments, positional arguments!
+        if self.caller:
+            caller = kwargs.pop('caller', None)
+            if caller is None:
+                caller = self._environment.undefined('No caller defined',
+                                                     name='caller')
+            arguments.append(caller)
+        if self.catch_kwargs:
+            arguments.append(kwargs)
+        elif kwargs:
+            raise TypeError('macro %r takes no keyword argument %r' %
+                            (self.name, next(iter(kwargs))))
+        if self.catch_varargs:
+            arguments.append(args[self._argument_count:])
+        elif len(args) > self._argument_count:
+            raise TypeError('macro %r takes not more than %d argument(s)' %
+                            (self.name, len(self.arguments)))
+        return self._func(*arguments)
+
+    def __repr__(self):
+        return '<%s %s>' % (
+            self.__class__.__name__,
+            self.name is None and 'anonymous' or repr(self.name)
+        )
+
+
+class Undefined(object):
+    """The default undefined type.  This undefined type can be printed and
+    iterated over, but every other access will raise an :exc:`UndefinedError`:
+
+    >>> foo = Undefined(name='foo')
+    >>> str(foo)
+    ''
+    >>> not foo
+    True
+    >>> foo + 42
+    Traceback (most recent call last):
+      ...
+    UndefinedError: 'foo' is undefined
+    """
+    __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name',
+                 '_undefined_exception')
+
+    def __init__(self, hint=None, obj=missing, name=None, exc=UndefinedError):
+        self._undefined_hint = hint
+        self._undefined_obj = obj
+        self._undefined_name = name
+        self._undefined_exception = exc
+
+    @internalcode
+    def _fail_with_undefined_error(self, *args, **kwargs):
+        """Regular callback function for undefined objects that raises an
+        `UndefinedError` on call.
+        """
+        if self._undefined_hint is None:
+            if self._undefined_obj is missing:
+                hint = '%r is undefined' % self._undefined_name
+            elif not isinstance(self._undefined_name, basestring):
+                hint = '%s has no element %r' % (
+                    object_type_repr(self._undefined_obj),
+                    self._undefined_name
+                )
+            else:
+                hint = '%r has no attribute %r' % (
+                    object_type_repr(self._undefined_obj),
+                    self._undefined_name
+                )
+        else:
+            hint = self._undefined_hint
+        raise self._undefined_exception(hint)
+
+    @internalcode
+    def __getattr__(self, name):
+        if name[:2] == '__':
+            raise AttributeError(name)
+        return self._fail_with_undefined_error()
+
+    __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
+    __truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \
+    __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
+    __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = __int__ = \
+    __float__ = __complex__ = __pow__ = __rpow__ = \
+        _fail_with_undefined_error
+
+    def __str__(self):
+        return unicode(self).encode('utf-8')
+
+    # unicode goes after __str__ because we configured 2to3 to rename
+    # __unicode__ to __str__.  because the 2to3 tree is not designed to
+    # remove nodes from it, we leave the above __str__ around and let
+    # it override at runtime.
+    def __unicode__(self):
+        return u''
+
+    def __len__(self):
+        return 0
+
+    def __iter__(self):
+        if 0:
+            yield None
+
+    def __nonzero__(self):
+        return False
+
+    def __repr__(self):
+        return 'Undefined'
+
+
+class DebugUndefined(Undefined):
+    """An undefined that returns the debug info when printed.
+
+    >>> foo = DebugUndefined(name='foo')
+    >>> str(foo)
+    '{{ foo }}'
+    >>> not foo
+    True
+    >>> foo + 42
+    Traceback (most recent call last):
+      ...
+    UndefinedError: 'foo' is undefined
+    """
+    __slots__ = ()
+
+    def __unicode__(self):
+        if self._undefined_hint is None:
+            if self._undefined_obj is missing:
+                return u'{{ %s }}' % self._undefined_name
+            return '{{ no such element: %s[%r] }}' % (
+                object_type_repr(self._undefined_obj),
+                self._undefined_name
+            )
+        return u'{{ undefined value printed: %s }}' % self._undefined_hint
+
+
+class StrictUndefined(Undefined):
+    """An undefined that barks on print and iteration as well as boolean
+    tests and all kinds of comparisons.  In other words: you can do nothing
+    with it except checking if it's defined using the `defined` test.
+
+    >>> foo = StrictUndefined(name='foo')
+    >>> str(foo)
+    Traceback (most recent call last):
+      ...
+    UndefinedError: 'foo' is undefined
+    >>> not foo
+    Traceback (most recent call last):
+      ...
+    UndefinedError: 'foo' is undefined
+    >>> foo + 42
+    Traceback (most recent call last):
+      ...
+    UndefinedError: 'foo' is undefined
+    """
+    __slots__ = ()
+    __iter__ = __unicode__ = __str__ = __len__ = __nonzero__ = __eq__ = \
+        __ne__ = __bool__ = Undefined._fail_with_undefined_error
+
+
+# remove remaining slots attributes, after the metaclass did the magic they
+# are unneeded and irritating as they contain wrong data for the subclasses.
+del Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__
diff --git a/lib/jinja2/jinja2/sandbox.py b/lib/jinja2/jinja2/sandbox.py
new file mode 100644
index 0000000..a1cbb29
--- /dev/null
+++ b/lib/jinja2/jinja2/sandbox.py
@@ -0,0 +1,361 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.sandbox
+    ~~~~~~~~~~~~~~
+
+    Adds a sandbox layer to Jinja as it was the default behavior in the old
+    Jinja 1 releases.  This sandbox is slightly different from Jinja 1 as the
+    default behavior is easier to use.
+
+    The behavior can be changed by subclassing the environment.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD.
+"""
+import operator
+from jinja2.environment import Environment
+from jinja2.exceptions import SecurityError
+from jinja2.utils import FunctionType, MethodType, TracebackType, CodeType, \
+     FrameType, GeneratorType
+
+
+#: maximum number of items a range may produce
+MAX_RANGE = 100000
+
+#: attributes of function objects that are considered unsafe.
+UNSAFE_FUNCTION_ATTRIBUTES = set(['func_closure', 'func_code', 'func_dict',
+                                  'func_defaults', 'func_globals'])
+
+#: unsafe method attributes.  function attributes are unsafe for methods too
+UNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self'])
+
+
+import warnings
+
+# make sure we don't warn in python 2.6 about stuff we don't care about
+warnings.filterwarnings('ignore', 'the sets module', DeprecationWarning,
+                        module='jinja2.sandbox')
+
+from collections import deque
+
+_mutable_set_types = (set,)
+_mutable_mapping_types = (dict,)
+_mutable_sequence_types = (list,)
+
+
+# on python 2.x we can register the user collection types
+try:
+    from UserDict import UserDict, DictMixin
+    from UserList import UserList
+    _mutable_mapping_types += (UserDict, DictMixin)
+    _mutable_set_types += (UserList,)
+except ImportError:
+    pass
+
+# if sets is still available, register the mutable set from there as well
+try:
+    from sets import Set
+    _mutable_set_types += (Set,)
+except ImportError:
+    pass
+
+#: register Python 2.6 abstract base classes
+try:
+    from collections import MutableSet, MutableMapping, MutableSequence
+    _mutable_set_types += (MutableSet,)
+    _mutable_mapping_types += (MutableMapping,)
+    _mutable_sequence_types += (MutableSequence,)
+except ImportError:
+    pass
+
+_mutable_spec = (
+    (_mutable_set_types, frozenset([
+        'add', 'clear', 'difference_update', 'discard', 'pop', 'remove',
+        'symmetric_difference_update', 'update'
+    ])),
+    (_mutable_mapping_types, frozenset([
+        'clear', 'pop', 'popitem', 'setdefault', 'update'
+    ])),
+    (_mutable_sequence_types, frozenset([
+        'append', 'reverse', 'insert', 'sort', 'extend', 'remove'
+    ])),
+    (deque, frozenset([
+        'append', 'appendleft', 'clear', 'extend', 'extendleft', 'pop',
+        'popleft', 'remove', 'rotate'
+    ]))
+)
+
+
+def safe_range(*args):
+    """A range that can't generate ranges with a length of more than
+    MAX_RANGE items.
+    """
+    rng = xrange(*args)
+    if len(rng) > MAX_RANGE:
+        raise OverflowError('range too big, maximum size for range is %d' %
+                            MAX_RANGE)
+    return rng
+
+
+def unsafe(f):
+    """Marks a function or method as unsafe.
+
+    ::
+
+        @unsafe
+        def delete(self):
+            pass
+    """
+    f.unsafe_callable = True
+    return f
+
+
+def is_internal_attribute(obj, attr):
+    """Test if the attribute given is an internal python attribute.  For
+    example this function returns `True` for the `func_code` attribute of
+    python objects.  This is useful if the environment method
+    :meth:`~SandboxedEnvironment.is_safe_attribute` is overriden.
+
+    >>> from jinja2.sandbox import is_internal_attribute
+    >>> is_internal_attribute(lambda: None, "func_code")
+    True
+    >>> is_internal_attribute((lambda x:x).func_code, 'co_code')
+    True
+    >>> is_internal_attribute(str, "upper")
+    False
+    """
+    if isinstance(obj, FunctionType):
+        if attr in UNSAFE_FUNCTION_ATTRIBUTES:
+            return True
+    elif isinstance(obj, MethodType):
+        if attr in UNSAFE_FUNCTION_ATTRIBUTES or \
+           attr in UNSAFE_METHOD_ATTRIBUTES:
+            return True
+    elif isinstance(obj, type):
+        if attr == 'mro':
+            return True
+    elif isinstance(obj, (CodeType, TracebackType, FrameType)):
+        return True
+    elif isinstance(obj, GeneratorType):
+        if attr == 'gi_frame':
+            return True
+    return attr.startswith('__')
+
+
+def modifies_known_mutable(obj, attr):
+    """This function checks if an attribute on a builtin mutable object
+    (list, dict, set or deque) would modify it if called.  It also supports
+    the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and
+    with Python 2.6 onwards the abstract base classes `MutableSet`,
+    `MutableMapping`, and `MutableSequence`.
+
+    >>> modifies_known_mutable({}, "clear")
+    True
+    >>> modifies_known_mutable({}, "keys")
+    False
+    >>> modifies_known_mutable([], "append")
+    True
+    >>> modifies_known_mutable([], "index")
+    False
+
+    If called with an unsupported object (such as unicode) `False` is
+    returned.
+
+    >>> modifies_known_mutable("foo", "upper")
+    False
+    """
+    for typespec, unsafe in _mutable_spec:
+        if isinstance(obj, typespec):
+            return attr in unsafe
+    return False
+
+
+class SandboxedEnvironment(Environment):
+    """The sandboxed environment.  It works like the regular environment but
+    tells the compiler to generate sandboxed code.  Additionally subclasses of
+    this environment may override the methods that tell the runtime what
+    attributes or functions are safe to access.
+
+    If the template tries to access insecure code a :exc:`SecurityError` is
+    raised.  However also other exceptions may occour during the rendering so
+    the caller has to ensure that all exceptions are catched.
+    """
+    sandboxed = True
+
+    #: default callback table for the binary operators.  A copy of this is
+    #: available on each instance of a sandboxed environment as
+    #: :attr:`binop_table`
+    default_binop_table = {
+        '+':        operator.add,
+        '-':        operator.sub,
+        '*':        operator.mul,
+        '/':        operator.truediv,
+        '//':       operator.floordiv,
+        '**':       operator.pow,
+        '%':        operator.mod
+    }
+
+    #: default callback table for the unary operators.  A copy of this is
+    #: available on each instance of a sandboxed environment as
+    #: :attr:`unop_table`
+    default_unop_table = {
+        '+':        operator.pos,
+        '-':        operator.neg
+    }
+
+    #: a set of binary operators that should be intercepted.  Each operator
+    #: that is added to this set (empty by default) is delegated to the
+    #: :meth:`call_binop` method that will perform the operator.  The default
+    #: operator callback is specified by :attr:`binop_table`.
+    #:
+    #: The following binary operators are interceptable:
+    #: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**``
+    #:
+    #: The default operation form the operator table corresponds to the
+    #: builtin function.  Intercepted calls are always slower than the native
+    #: operator call, so make sure only to intercept the ones you are
+    #: interested in.
+    #:
+    #: .. versionadded:: 2.6
+    intercepted_binops = frozenset()
+
+    #: a set of unary operators that should be intercepted.  Each operator
+    #: that is added to this set (empty by default) is delegated to the
+    #: :meth:`call_unop` method that will perform the operator.  The default
+    #: operator callback is specified by :attr:`unop_table`.
+    #:
+    #: The following unary operators are interceptable: ``+``, ``-``
+    #:
+    #: The default operation form the operator table corresponds to the
+    #: builtin function.  Intercepted calls are always slower than the native
+    #: operator call, so make sure only to intercept the ones you are
+    #: interested in.
+    #:
+    #: .. versionadded:: 2.6
+    intercepted_unops = frozenset()
+
+    def intercept_unop(self, operator):
+        """Called during template compilation with the name of a unary
+        operator to check if it should be intercepted at runtime.  If this
+        method returns `True`, :meth:`call_unop` is excuted for this unary
+        operator.  The default implementation of :meth:`call_unop` will use
+        the :attr:`unop_table` dictionary to perform the operator with the
+        same logic as the builtin one.
+
+        The following unary operators are interceptable: ``+`` and ``-``
+
+        Intercepted calls are always slower than the native operator call,
+        so make sure only to intercept the ones you are interested in.
+
+        .. versionadded:: 2.6
+        """
+        return False
+
+
+    def __init__(self, *args, **kwargs):
+        Environment.__init__(self, *args, **kwargs)
+        self.globals['range'] = safe_range
+        self.binop_table = self.default_binop_table.copy()
+        self.unop_table = self.default_unop_table.copy()
+
+    def is_safe_attribute(self, obj, attr, value):
+        """The sandboxed environment will call this method to check if the
+        attribute of an object is safe to access.  Per default all attributes
+        starting with an underscore are considered private as well as the
+        special attributes of internal python objects as returned by the
+        :func:`is_internal_attribute` function.
+        """
+        return not (attr.startswith('_') or is_internal_attribute(obj, attr))
+
+    def is_safe_callable(self, obj):
+        """Check if an object is safely callable.  Per default a function is
+        considered safe unless the `unsafe_callable` attribute exists and is
+        True.  Override this method to alter the behavior, but this won't
+        affect the `unsafe` decorator from this module.
+        """
+        return not (getattr(obj, 'unsafe_callable', False) or
+                    getattr(obj, 'alters_data', False))
+
+    def call_binop(self, context, operator, left, right):
+        """For intercepted binary operator calls (:meth:`intercepted_binops`)
+        this function is executed instead of the builtin operator.  This can
+        be used to fine tune the behavior of certain operators.
+
+        .. versionadded:: 2.6
+        """
+        return self.binop_table[operator](left, right)
+
+    def call_unop(self, context, operator, arg):
+        """For intercepted unary operator calls (:meth:`intercepted_unops`)
+        this function is executed instead of the builtin operator.  This can
+        be used to fine tune the behavior of certain operators.
+
+        .. versionadded:: 2.6
+        """
+        return self.unop_table[operator](arg)
+
+    def getitem(self, obj, argument):
+        """Subscribe an object from sandboxed code."""
+        try:
+            return obj[argument]
+        except (TypeError, LookupError):
+            if isinstance(argument, basestring):
+                try:
+                    attr = str(argument)
+                except Exception:
+                    pass
+                else:
+                    try:
+                        value = getattr(obj, attr)
+                    except AttributeError:
+                        pass
+                    else:
+                        if self.is_safe_attribute(obj, argument, value):
+                            return value
+                        return self.unsafe_undefined(obj, argument)
+        return self.undefined(obj=obj, name=argument)
+
+    def getattr(self, obj, attribute):
+        """Subscribe an object from sandboxed code and prefer the
+        attribute.  The attribute passed *must* be a bytestring.
+        """
+        try:
+            value = getattr(obj, attribute)
+        except AttributeError:
+            try:
+                return obj[attribute]
+            except (TypeError, LookupError):
+                pass
+        else:
+            if self.is_safe_attribute(obj, attribute, value):
+                return value
+            return self.unsafe_undefined(obj, attribute)
+        return self.undefined(obj=obj, name=attribute)
+
+    def unsafe_undefined(self, obj, attribute):
+        """Return an undefined object for unsafe attributes."""
+        return self.undefined('access to attribute %r of %r '
+                              'object is unsafe.' % (
+            attribute,
+            obj.__class__.__name__
+        ), name=attribute, obj=obj, exc=SecurityError)
+
+    def call(__self, __context, __obj, *args, **kwargs):
+        """Call an object from sandboxed code."""
+        # the double prefixes are to avoid double keyword argument
+        # errors when proxying the call.
+        if not __self.is_safe_callable(__obj):
+            raise SecurityError('%r is not safely callable' % (__obj,))
+        return __context.call(__obj, *args, **kwargs)
+
+
+class ImmutableSandboxedEnvironment(SandboxedEnvironment):
+    """Works exactly like the regular `SandboxedEnvironment` but does not
+    permit modifications on the builtin mutable objects `list`, `set`, and
+    `dict` by using the :func:`modifies_known_mutable` function.
+    """
+
+    def is_safe_attribute(self, obj, attr, value):
+        if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value):
+            return False
+        return not modifies_known_mutable(obj, attr)
diff --git a/lib/jinja2/jinja2/tests.py b/lib/jinja2/jinja2/tests.py
new file mode 100644
index 0000000..50510b0
--- /dev/null
+++ b/lib/jinja2/jinja2/tests.py
@@ -0,0 +1,161 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.tests
+    ~~~~~~~~~~~~
+
+    Jinja test functions. Used with the "is" operator.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import re
+from jinja2.runtime import Undefined
+
+try:
+    from collections import Mapping as MappingType
+except ImportError:
+    import UserDict
+    MappingType = (UserDict.UserDict, UserDict.DictMixin, dict)
+
+# nose, nothing here to test
+__test__ = False
+
+
+number_re = re.compile(r'^-?\d+(\.\d+)?$')
+regex_type = type(number_re)
+
+
+try:
+    test_callable = callable
+except NameError:
+    def test_callable(x):
+        return hasattr(x, '__call__')
+
+
+def test_odd(value):
+    """Return true if the variable is odd."""
+    return value % 2 == 1
+
+
+def test_even(value):
+    """Return true if the variable is even."""
+    return value % 2 == 0
+
+
+def test_divisibleby(value, num):
+    """Check if a variable is divisible by a number."""
+    return value % num == 0
+
+
+def test_defined(value):
+    """Return true if the variable is defined:
+
+    .. sourcecode:: jinja
+
+        {% if variable is defined %}
+            value of variable: {{ variable }}
+        {% else %}
+            variable is not defined
+        {% endif %}
+
+    See the :func:`default` filter for a simple way to set undefined
+    variables.
+    """
+    return not isinstance(value, Undefined)
+
+
+def test_undefined(value):
+    """Like :func:`defined` but the other way round."""
+    return isinstance(value, Undefined)
+
+
+def test_none(value):
+    """Return true if the variable is none."""
+    return value is None
+
+
+def test_lower(value):
+    """Return true if the variable is lowercased."""
+    return unicode(value).islower()
+
+
+def test_upper(value):
+    """Return true if the variable is uppercased."""
+    return unicode(value).isupper()
+
+
+def test_string(value):
+    """Return true if the object is a string."""
+    return isinstance(value, basestring)
+
+
+def test_mapping(value):
+    """Return true if the object is a mapping (dict etc.).
+
+    .. versionadded:: 2.6
+    """
+    return isinstance(value, MappingType)
+
+
+def test_number(value):
+    """Return true if the variable is a number."""
+    return isinstance(value, (int, long, float, complex))
+
+
+def test_sequence(value):
+    """Return true if the variable is a sequence. Sequences are variables
+    that are iterable.
+    """
+    try:
+        len(value)
+        value.__getitem__
+    except:
+        return False
+    return True
+
+
+def test_sameas(value, other):
+    """Check if an object points to the same memory address than another
+    object:
+
+    .. sourcecode:: jinja
+
+        {% if foo.attribute is sameas false %}
+            the foo attribute really is the `False` singleton
+        {% endif %}
+    """
+    return value is other
+
+
+def test_iterable(value):
+    """Check if it's possible to iterate over an object."""
+    try:
+        iter(value)
+    except TypeError:
+        return False
+    return True
+
+
+def test_escaped(value):
+    """Check if the value is escaped."""
+    return hasattr(value, '__html__')
+
+
+TESTS = {
+    'odd':              test_odd,
+    'even':             test_even,
+    'divisibleby':      test_divisibleby,
+    'defined':          test_defined,
+    'undefined':        test_undefined,
+    'none':             test_none,
+    'lower':            test_lower,
+    'upper':            test_upper,
+    'string':           test_string,
+    'mapping':          test_mapping,
+    'number':           test_number,
+    'sequence':         test_sequence,
+    'iterable':         test_iterable,
+    'callable':         test_callable,
+    'sameas':           test_sameas,
+    'escaped':          test_escaped
+}
diff --git a/lib/jinja2/jinja2/testsuite/__init__.py b/lib/jinja2/jinja2/testsuite/__init__.py
new file mode 100644
index 0000000..1f10ef6
--- /dev/null
+++ b/lib/jinja2/jinja2/testsuite/__init__.py
@@ -0,0 +1,95 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.testsuite
+    ~~~~~~~~~~~~~~~~
+
+    All the unittests of Jinja2.  These tests can be executed by
+    either running run-tests.py using multiple Python versions at
+    the same time.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import os
+import re
+import sys
+import unittest
+from traceback import format_exception
+from jinja2 import loaders
+
+
+here = os.path.dirname(os.path.abspath(__file__))
+
+dict_loader = loaders.DictLoader({
+    'justdict.html':        'FOO'
+})
+package_loader = loaders.PackageLoader('jinja2.testsuite.res', 'templates')
+filesystem_loader = loaders.FileSystemLoader(here + '/res/templates')
+function_loader = loaders.FunctionLoader({'justfunction.html': 'FOO'}.get)
+choice_loader = loaders.ChoiceLoader([dict_loader, package_loader])
+prefix_loader = loaders.PrefixLoader({
+    'a':        filesystem_loader,
+    'b':        dict_loader
+})
+
+
+class JinjaTestCase(unittest.TestCase):
+
+    ### use only these methods for testing.  If you need standard
+    ### unittest method, wrap them!
+
+    def setup(self):
+        pass
+
+    def teardown(self):
+        pass
+
+    def setUp(self):
+        self.setup()
+
+    def tearDown(self):
+        self.teardown()
+
+    def assert_equal(self, a, b):
+        return self.assertEqual(a, b)
+
+    def assert_raises(self, *args, **kwargs):
+        return self.assertRaises(*args, **kwargs)
+
+    def assert_traceback_matches(self, callback, expected_tb):
+        try:
+            callback()
+        except Exception, e:
+            tb = format_exception(*sys.exc_info())
+            if re.search(expected_tb.strip(), ''.join(tb)) is None:
+                raise self.fail('Traceback did not match:\n\n%s\nexpected:\n%s'
+                    % (''.join(tb), expected_tb))
+        else:
+            self.fail('Expected exception')
+
+
+def suite():
+    from jinja2.testsuite import ext, filters, tests, core_tags, \
+         loader, inheritance, imports, lexnparse, security, api, \
+         regression, debug, utils, doctests
+    suite = unittest.TestSuite()
+    suite.addTest(ext.suite())
+    suite.addTest(filters.suite())
+    suite.addTest(tests.suite())
+    suite.addTest(core_tags.suite())
+    suite.addTest(loader.suite())
+    suite.addTest(inheritance.suite())
+    suite.addTest(imports.suite())
+    suite.addTest(lexnparse.suite())
+    suite.addTest(security.suite())
+    suite.addTest(api.suite())
+    suite.addTest(regression.suite())
+    suite.addTest(debug.suite())
+    suite.addTest(utils.suite())
+
+    # doctests will not run on python 3 currently.  Too many issues
+    # with that, do not test that on that platform.
+    if sys.version_info < (3, 0):
+        suite.addTest(doctests.suite())
+
+    return suite
diff --git a/lib/jinja2/jinja2/testsuite/api.py b/lib/jinja2/jinja2/testsuite/api.py
new file mode 100644
index 0000000..c8f9634
--- /dev/null
+++ b/lib/jinja2/jinja2/testsuite/api.py
@@ -0,0 +1,245 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.testsuite.api
+    ~~~~~~~~~~~~~~~~~~~~
+
+    Tests the public API and related stuff.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import unittest
+
+from jinja2.testsuite import JinjaTestCase
+
+from jinja2 import Environment, Undefined, DebugUndefined, \
+     StrictUndefined, UndefinedError, meta, \
+     is_undefined, Template, DictLoader
+from jinja2.utils import Cycler
+
+env = Environment()
+
+
+class ExtendedAPITestCase(JinjaTestCase):
+
+    def test_item_and_attribute(self):
+        from jinja2.sandbox import SandboxedEnvironment
+
+        for env in Environment(), SandboxedEnvironment():
+            # the |list is necessary for python3
+            tmpl = env.from_string('{{ foo.items()|list }}')
+            assert tmpl.render(foo={'items': 42}) == "[('items', 42)]"
+            tmpl = env.from_string('{{ foo|attr("items")()|list }}')
+            assert tmpl.render(foo={'items': 42}) == "[('items', 42)]"
+            tmpl = env.from_string('{{ foo["items"] }}')
+            assert tmpl.render(foo={'items': 42}) == '42'
+
+    def test_finalizer(self):
+        def finalize_none_empty(value):
+            if value is None:
+                value = u''
+            return value
+        env = Environment(finalize=finalize_none_empty)
+        tmpl = env.from_string('{% for item in seq %}|{{ item }}{% endfor %}')
+        assert tmpl.render(seq=(None, 1, "foo")) == '||1|foo'
+        tmpl = env.from_string('<{{ none }}>')
+        assert tmpl.render() == '<>'
+
+    def test_cycler(self):
+        items = 1, 2, 3
+        c = Cycler(*items)
+        for item in items + items:
+            assert c.current == item
+            assert c.next() == item
+        c.next()
+        assert c.current == 2
+        c.reset()
+        assert c.current == 1
+
+    def test_expressions(self):
+        expr = env.compile_expression("foo")
+        assert expr() is None
+        assert expr(foo=42) == 42
+        expr2 = env.compile_expression("foo", undefined_to_none=False)
+        assert is_undefined(expr2())
+
+        expr = env.compile_expression("42 + foo")
+        assert expr(foo=42) == 84
+
+    def test_template_passthrough(self):
+        t = Template('Content')
+        assert env.get_template(t) is t
+        assert env.select_template([t]) is t
+        assert env.get_or_select_template([t]) is t
+        assert env.get_or_select_template(t) is t
+
+    def test_autoescape_autoselect(self):
+        def select_autoescape(name):
+            if name is None or '.' not in name:
+                return False
+            return name.endswith('.html')
+        env = Environment(autoescape=select_autoescape,
+                          loader=DictLoader({
+            'test.txt':     '{{ foo }}',
+            'test.html':    '{{ foo }}'
+        }))
+        t = env.get_template('test.txt')
+        assert t.render(foo='<foo>') == '<foo>'
+        t = env.get_template('test.html')
+        assert t.render(foo='<foo>') == '&lt;foo&gt;'
+        t = env.from_string('{{ foo }}')
+        assert t.render(foo='<foo>') == '<foo>'
+
+
+class MetaTestCase(JinjaTestCase):
+
+    def test_find_undeclared_variables(self):
+        ast = env.parse('{% set foo = 42 %}{{ bar + foo }}')
+        x = meta.find_undeclared_variables(ast)
+        assert x == set(['bar'])
+
+        ast = env.parse('{% set foo = 42 %}{{ bar + foo }}'
+                        '{% macro meh(x) %}{{ x }}{% endmacro %}'
+                        '{% for item in seq %}{{ muh(item) + meh(seq) }}{% endfor %}')
+        x = meta.find_undeclared_variables(ast)
+        assert x == set(['bar', 'seq', 'muh'])
+
+    def test_find_refererenced_templates(self):
+        ast = env.parse('{% extends "layout.html" %}{% include helper %}')
+        i = meta.find_referenced_templates(ast)
+        assert i.next() == 'layout.html'
+        assert i.next() is None
+        assert list(i) == []
+
+        ast = env.parse('{% extends "layout.html" %}'
+                        '{% from "test.html" import a, b as c %}'
+                        '{% import "meh.html" as meh %}'
+                        '{% include "muh.html" %}')
+        i = meta.find_referenced_templates(ast)
+        assert list(i) == ['layout.html', 'test.html', 'meh.html', 'muh.html']
+
+    def test_find_included_templates(self):
+        ast = env.parse('{% include ["foo.html", "bar.html"] %}')
+        i = meta.find_referenced_templates(ast)
+        assert list(i) == ['foo.html', 'bar.html']
+
+        ast = env.parse('{% include ("foo.html", "bar.html") %}')
+        i = meta.find_referenced_templates(ast)
+        assert list(i) == ['foo.html', 'bar.html']
+
+        ast = env.parse('{% include ["foo.html", "bar.html", foo] %}')
+        i = meta.find_referenced_templates(ast)
+        assert list(i) == ['foo.html', 'bar.html', None]
+
+        ast = env.parse('{% include ("foo.html", "bar.html", foo) %}')
+        i = meta.find_referenced_templates(ast)
+        assert list(i) == ['foo.html', 'bar.html', None]
+
+
+class StreamingTestCase(JinjaTestCase):
+
+    def test_basic_streaming(self):
+        tmpl = env.from_string("<ul>{% for item in seq %}<li>{{ loop.index "
+                               "}} - {{ item }}</li>{%- endfor %}</ul>")
+        stream = tmpl.stream(seq=range(4))
+        self.assert_equal(stream.next(), '<ul>')
+        self.assert_equal(stream.next(), '<li>1 - 0</li>')
+        self.assert_equal(stream.next(), '<li>2 - 1</li>')
+        self.assert_equal(stream.next(), '<li>3 - 2</li>')
+        self.assert_equal(stream.next(), '<li>4 - 3</li>')
+        self.assert_equal(stream.next(), '</ul>')
+
+    def test_buffered_streaming(self):
+        tmpl = env.from_string("<ul>{% for item in seq %}<li>{{ loop.index "
+                               "}} - {{ item }}</li>{%- endfor %}</ul>")
+        stream = tmpl.stream(seq=range(4))
+        stream.enable_buffering(size=3)
+        self.assert_equal(stream.next(), u'<ul><li>1 - 0</li><li>2 - 1</li>')
+        self.assert_equal(stream.next(), u'<li>3 - 2</li><li>4 - 3</li></ul>')
+
+    def test_streaming_behavior(self):
+        tmpl = env.from_string("")
+        stream = tmpl.stream()
+        assert not stream.buffered
+        stream.enable_buffering(20)
+        assert stream.buffered
+        stream.disable_buffering()
+        assert not stream.buffered
+
+
+class UndefinedTestCase(JinjaTestCase):
+
+    def test_stopiteration_is_undefined(self):
+        def test():
+            raise StopIteration()
+        t = Template('A{{ test() }}B')
+        assert t.render(test=test) == 'AB'
+        t = Template('A{{ test().missingattribute }}B')
+        self.assert_raises(UndefinedError, t.render, test=test)
+
+    def test_undefined_and_special_attributes(self):
+        try:
+            Undefined('Foo').__dict__
+        except AttributeError:
+            pass
+        else:
+            assert False, "Expected actual attribute error"
+
+    def test_default_undefined(self):
+        env = Environment(undefined=Undefined)
+        self.assert_equal(env.from_string('{{ missing }}').render(), u'')
+        self.assert_raises(UndefinedError,
+                           env.from_string('{{ missing.attribute }}').render)
+        self.assert_equal(env.from_string('{{ missing|list }}').render(), '[]')
+        self.assert_equal(env.from_string('{{ missing is not defined }}').render(), 'True')
+        self.assert_equal(env.from_string('{{ foo.missing }}').render(foo=42), '')
+        self.assert_equal(env.from_string('{{ not missing }}').render(), 'True')
+
+    def test_debug_undefined(self):
+        env = Environment(undefined=DebugUndefined)
+        self.assert_equal(env.from_string('{{ missing }}').render(), '{{ missing }}')
+        self.assert_raises(UndefinedError,
+                           env.from_string('{{ missing.attribute }}').render)
+        self.assert_equal(env.from_string('{{ missing|list }}').render(), '[]')
+        self.assert_equal(env.from_string('{{ missing is not defined }}').render(), 'True')
+        self.assert_equal(env.from_string('{{ foo.missing }}').render(foo=42),
+                          u"{{ no such element: int object['missing'] }}")
+        self.assert_equal(env.from_string('{{ not missing }}').render(), 'True')
+
+    def test_strict_undefined(self):
+        env = Environment(undefined=StrictUndefined)
+        self.assert_raises(UndefinedError, env.from_string('{{ missing }}').render)
+        self.assert_raises(UndefinedError, env.from_string('{{ missing.attribute }}').render)
+        self.assert_raises(UndefinedError, env.from_string('{{ missing|list }}').render)
+        self.assert_equal(env.from_string('{{ missing is not defined }}').render(), 'True')
+        self.assert_raises(UndefinedError, env.from_string('{{ foo.missing }}').render, foo=42)
+        self.assert_raises(UndefinedError, env.from_string('{{ not missing }}').render)
+
+    def test_indexing_gives_undefined(self):
+        t = Template("{{ var[42].foo }}")
+        self.assert_raises(UndefinedError, t.render, var=0)
+
+    def test_none_gives_proper_error(self):
+        try:
+            Environment().getattr(None, 'split')()
+        except UndefinedError, e:
+            assert e.message == "'None' has no attribute 'split'"
+        else:
+            assert False, 'expected exception'
+
+    def test_object_repr(self):
+        try:
+            Undefined(obj=42, name='upper')()
+        except UndefinedError, e:
+            assert e.message == "'int object' has no attribute 'upper'"
+        else:
+            assert False, 'expected exception'
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(ExtendedAPITestCase))
+    suite.addTest(unittest.makeSuite(MetaTestCase))
+    suite.addTest(unittest.makeSuite(StreamingTestCase))
+    suite.addTest(unittest.makeSuite(UndefinedTestCase))
+    return suite
diff --git a/lib/jinja2/jinja2/testsuite/core_tags.py b/lib/jinja2/jinja2/testsuite/core_tags.py
new file mode 100644
index 0000000..2b5f580
--- /dev/null
+++ b/lib/jinja2/jinja2/testsuite/core_tags.py
@@ -0,0 +1,285 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.testsuite.core_tags
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Test the core tags like for and if.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import unittest
+
+from jinja2.testsuite import JinjaTestCase
+
+from jinja2 import Environment, TemplateSyntaxError, UndefinedError, \
+     DictLoader
+
+env = Environment()
+
+
+class ForLoopTestCase(JinjaTestCase):
+
+    def test_simple(self):
+        tmpl = env.from_string('{% for item in seq %}{{ item }}{% endfor %}')
+        assert tmpl.render(seq=range(10)) == '0123456789'
+
+    def test_else(self):
+        tmpl = env.from_string('{% for item in seq %}XXX{% else %}...{% endfor %}')
+        assert tmpl.render() == '...'
+
+    def test_empty_blocks(self):
+        tmpl = env.from_string('<{% for item in seq %}{% else %}{% endfor %}>')
+        assert tmpl.render() == '<>'
+
+    def test_context_vars(self):
+        tmpl = env.from_string('''{% for item in seq -%}
+        {{ loop.index }}|{{ loop.index0 }}|{{ loop.revindex }}|{{
+            loop.revindex0 }}|{{ loop.first }}|{{ loop.last }}|{{
+           loop.length }}###{% endfor %}''')
+        one, two, _ = tmpl.render(seq=[0, 1]).split('###')
+        (one_index, one_index0, one_revindex, one_revindex0, one_first,
+         one_last, one_length) = one.split('|')
+        (two_index, two_index0, two_revindex, two_revindex0, two_first,
+         two_last, two_length) = two.split('|')
+
+        assert int(one_index) == 1 and int(two_index) == 2
+        assert int(one_index0) == 0 and int(two_index0) == 1
+        assert int(one_revindex) == 2 and int(two_revindex) == 1
+        assert int(one_revindex0) == 1 and int(two_revindex0) == 0
+        assert one_first == 'True' and two_first == 'False'
+        assert one_last == 'False' and two_last == 'True'
+        assert one_length == two_length == '2'
+
+    def test_cycling(self):
+        tmpl = env.from_string('''{% for item in seq %}{{
+            loop.cycle('<1>', '<2>') }}{% endfor %}{%
+            for item in seq %}{{ loop.cycle(*through) }}{% endfor %}''')
+        output = tmpl.render(seq=range(4), through=('<1>', '<2>'))
+        assert output == '<1><2>' * 4
+
+    def test_scope(self):
+        tmpl = env.from_string('{% for item in seq %}{% endfor %}{{ item }}')
+        output = tmpl.render(seq=range(10))
+        assert not output
+
+    def test_varlen(self):
+        def inner():
+            for item in range(5):
+                yield item
+        tmpl = env.from_string('{% for item in iter %}{{ item }}{% endfor %}')
+        output = tmpl.render(iter=inner())
+        assert output == '01234'
+
+    def test_noniter(self):
+        tmpl = env.from_string('{% for item in none %}...{% endfor %}')
+        self.assert_raises(TypeError, tmpl.render)
+
+    def test_recursive(self):
+        tmpl = env.from_string('''{% for item in seq recursive -%}
+            [{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
+        {%- endfor %}''')
+        assert tmpl.render(seq=[
+            dict(a=1, b=[dict(a=1), dict(a=2)]),
+            dict(a=2, b=[dict(a=1), dict(a=2)]),
+            dict(a=3, b=[dict(a='a')])
+        ]) == '[1<[1][2]>][2<[1][2]>][3<[a]>]'
+
+    def test_looploop(self):
+        tmpl = env.from_string('''{% for row in table %}
+            {%- set rowloop = loop -%}
+            {% for cell in row -%}
+                [{{ rowloop.index }}|{{ loop.index }}]
+            {%- endfor %}
+        {%- endfor %}''')
+        assert tmpl.render(table=['ab', 'cd']) == '[1|1][1|2][2|1][2|2]'
+
+    def test_reversed_bug(self):
+        tmpl = env.from_string('{% for i in items %}{{ i }}'
+                               '{% if not loop.last %}'
+                               ',{% endif %}{% endfor %}')
+        assert tmpl.render(items=reversed([3, 2, 1])) == '1,2,3'
+
+    def test_loop_errors(self):
+        tmpl = env.from_string('''{% for item in [1] if loop.index
+                                      == 0 %}...{% endfor %}''')
+        self.assert_raises(UndefinedError, tmpl.render)
+        tmpl = env.from_string('''{% for item in [] %}...{% else
+            %}{{ loop }}{% endfor %}''')
+        assert tmpl.render() == ''
+
+    def test_loop_filter(self):
+        tmpl = env.from_string('{% for item in range(10) if item '
+                               'is even %}[{{ item }}]{% endfor %}')
+        assert tmpl.render() == '[0][2][4][6][8]'
+        tmpl = env.from_string('''
+            {%- for item in range(10) if item is even %}[{{
+                loop.index }}:{{ item }}]{% endfor %}''')
+        assert tmpl.render() == '[1:0][2:2][3:4][4:6][5:8]'
+
+    def test_loop_unassignable(self):
+        self.assert_raises(TemplateSyntaxError, env.from_string,
+                           '{% for loop in seq %}...{% endfor %}')
+
+    def test_scoped_special_var(self):
+        t = env.from_string('{% for s in seq %}[{{ loop.first }}{% for c in s %}'
+                            '|{{ loop.first }}{% endfor %}]{% endfor %}')
+        assert t.render(seq=('ab', 'cd')) == '[True|True|False][False|True|False]'
+
+    def test_scoped_loop_var(self):
+        t = env.from_string('{% for x in seq %}{{ loop.first }}'
+                            '{% for y in seq %}{% endfor %}{% endfor %}')
+        assert t.render(seq='ab') == 'TrueFalse'
+        t = env.from_string('{% for x in seq %}{% for y in seq %}'
+                            '{{ loop.first }}{% endfor %}{% endfor %}')
+        assert t.render(seq='ab') == 'TrueFalseTrueFalse'
+
+    def test_recursive_empty_loop_iter(self):
+        t = env.from_string('''
+        {%- for item in foo recursive -%}{%- endfor -%}
+        ''')
+        assert t.render(dict(foo=[])) == ''
+
+    def test_call_in_loop(self):
+        t = env.from_string('''
+        {%- macro do_something() -%}
+            [{{ caller() }}]
+        {%- endmacro %}
+
+        {%- for i in [1, 2, 3] %}
+            {%- call do_something() -%}
+                {{ i }}
+            {%- endcall %}
+        {%- endfor -%}
+        ''')
+        assert t.render() == '[1][2][3]'
+
+    def test_scoping_bug(self):
+        t = env.from_string('''
+        {%- for item in foo %}...{{ item }}...{% endfor %}
+        {%- macro item(a) %}...{{ a }}...{% endmacro %}
+        {{- item(2) -}}
+        ''')
+        assert t.render(foo=(1,)) == '...1......2...'
+
+    def test_unpacking(self):
+        tmpl = env.from_string('{% for a, b, c in [[1, 2, 3]] %}'
+            '{{ a }}|{{ b }}|{{ c }}{% endfor %}')
+        assert tmpl.render() == '1|2|3'
+
+
+class IfConditionTestCase(JinjaTestCase):
+
+    def test_simple(self):
+        tmpl = env.from_string('''{% if true %}...{% endif %}''')
+        assert tmpl.render() == '...'
+
+    def test_elif(self):
+        tmpl = env.from_string('''{% if false %}XXX{% elif true
+            %}...{% else %}XXX{% endif %}''')
+        assert tmpl.render() == '...'
+
+    def test_else(self):
+        tmpl = env.from_string('{% if false %}XXX{% else %}...{% endif %}')
+        assert tmpl.render() == '...'
+
+    def test_empty(self):
+        tmpl = env.from_string('[{% if true %}{% else %}{% endif %}]')
+        assert tmpl.render() == '[]'
+
+    def test_complete(self):
+        tmpl = env.from_string('{% if a %}A{% elif b %}B{% elif c == d %}'
+                               'C{% else %}D{% endif %}')
+        assert tmpl.render(a=0, b=False, c=42, d=42.0) == 'C'
+
+    def test_no_scope(self):
+        tmpl = env.from_string('{% if a %}{% set foo = 1 %}{% endif %}{{ foo }}')
+        assert tmpl.render(a=True) == '1'
+        tmpl = env.from_string('{% if true %}{% set foo = 1 %}{% endif %}{{ foo }}')
+        assert tmpl.render() == '1'
+
+
+class MacrosTestCase(JinjaTestCase):
+    env = Environment(trim_blocks=True)
+
+    def test_simple(self):
+        tmpl = self.env.from_string('''\
+{% macro say_hello(name) %}Hello {{ name }}!{% endmacro %}
+{{ say_hello('Peter') }}''')
+        assert tmpl.render() == 'Hello Peter!'
+
+    def test_scoping(self):
+        tmpl = self.env.from_string('''\
+{% macro level1(data1) %}
+{% macro level2(data2) %}{{ data1 }}|{{ data2 }}{% endmacro %}
+{{ level2('bar') }}{% endmacro %}
+{{ level1('foo') }}''')
+        assert tmpl.render() == 'foo|bar'
+
+    def test_arguments(self):
+        tmpl = self.env.from_string('''\
+{% macro m(a, b, c='c', d='d') %}{{ a }}|{{ b }}|{{ c }}|{{ d }}{% endmacro %}
+{{ m() }}|{{ m('a') }}|{{ m('a', 'b') }}|{{ m(1, 2, 3) }}''')
+        assert tmpl.render() == '||c|d|a||c|d|a|b|c|d|1|2|3|d'
+
+    def test_varargs(self):
+        tmpl = self.env.from_string('''\
+{% macro test() %}{{ varargs|join('|') }}{% endmacro %}\
+{{ test(1, 2, 3) }}''')
+        assert tmpl.render() == '1|2|3'
+
+    def test_simple_call(self):
+        tmpl = self.env.from_string('''\
+{% macro test() %}[[{{ caller() }}]]{% endmacro %}\
+{% call test() %}data{% endcall %}''')
+        assert tmpl.render() == '[[data]]'
+
+    def test_complex_call(self):
+        tmpl = self.env.from_string('''\
+{% macro test() %}[[{{ caller('data') }}]]{% endmacro %}\
+{% call(data) test() %}{{ data }}{% endcall %}''')
+        assert tmpl.render() == '[[data]]'
+
+    def test_caller_undefined(self):
+        tmpl = self.env.from_string('''\
+{% set caller = 42 %}\
+{% macro test() %}{{ caller is not defined }}{% endmacro %}\
+{{ test() }}''')
+        assert tmpl.render() == 'True'
+
+    def test_include(self):
+        self.env = Environment(loader=DictLoader({'include':
+            '{% macro test(foo) %}[{{ foo }}]{% endmacro %}'}))
+        tmpl = self.env.from_string('{% from "include" import test %}{{ test("foo") }}')
+        assert tmpl.render() == '[foo]'
+
+    def test_macro_api(self):
+        tmpl = self.env.from_string('{% macro foo(a, b) %}{% endmacro %}'
+                               '{% macro bar() %}{{ varargs }}{{ kwargs }}{% endmacro %}'
+                               '{% macro baz() %}{{ caller() }}{% endmacro %}')
+        assert tmpl.module.foo.arguments == ('a', 'b')
+        assert tmpl.module.foo.defaults == ()
+        assert tmpl.module.foo.name == 'foo'
+        assert not tmpl.module.foo.caller
+        assert not tmpl.module.foo.catch_kwargs
+        assert not tmpl.module.foo.catch_varargs
+        assert tmpl.module.bar.arguments == ()
+        assert tmpl.module.bar.defaults == ()
+        assert not tmpl.module.bar.caller
+        assert tmpl.module.bar.catch_kwargs
+        assert tmpl.module.bar.catch_varargs
+        assert tmpl.module.baz.caller
+
+    def test_callself(self):
+        tmpl = self.env.from_string('{% macro foo(x) %}{{ x }}{% if x > 1 %}|'
+                                    '{{ foo(x - 1) }}{% endif %}{% endmacro %}'
+                                    '{{ foo(5) }}')
+        assert tmpl.render() == '5|4|3|2|1'
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(ForLoopTestCase))
+    suite.addTest(unittest.makeSuite(IfConditionTestCase))
+    suite.addTest(unittest.makeSuite(MacrosTestCase))
+    return suite
diff --git a/lib/jinja2/jinja2/testsuite/debug.py b/lib/jinja2/jinja2/testsuite/debug.py
new file mode 100644
index 0000000..7552dec
--- /dev/null
+++ b/lib/jinja2/jinja2/testsuite/debug.py
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.testsuite.debug
+    ~~~~~~~~~~~~~~~~~~~~~~
+
+    Tests the debug system.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import sys
+import unittest
+
+from jinja2.testsuite import JinjaTestCase, filesystem_loader
+
+from jinja2 import Environment, TemplateSyntaxError
+
+env = Environment(loader=filesystem_loader)
+
+
+class DebugTestCase(JinjaTestCase):
+
+    if sys.version_info[:2] != (2, 4):
+        def test_runtime_error(self):
+            def test():
+                tmpl.render(fail=lambda: 1 / 0)
+            tmpl = env.get_template('broken.html')
+            self.assert_traceback_matches(test, r'''
+  File ".*?broken.html", line 2, in (top-level template code|<module>)
+    \{\{ fail\(\) \}\}
+  File ".*?debug.pyc?", line \d+, in <lambda>
+    tmpl\.render\(fail=lambda: 1 / 0\)
+ZeroDivisionError: (int(eger)? )?division (or modulo )?by zero
+''')
+
+    def test_syntax_error(self):
+        # XXX: the .*? is necessary for python3 which does not hide
+        # some of the stack frames we don't want to show.  Not sure
+        # what's up with that, but that is not that critical.  Should
+        # be fixed though.
+        self.assert_traceback_matches(lambda: env.get_template('syntaxerror.html'), r'''(?sm)
+  File ".*?syntaxerror.html", line 4, in (template|<module>)
+    \{% endif %\}.*?
+(jinja2\.exceptions\.)?TemplateSyntaxError: Encountered unknown tag 'endif'. Jinja was looking for the following tags: 'endfor' or 'else'. The innermost block that needs to be closed is 'for'.
+    ''')
+
+    def test_regular_syntax_error(self):
+        def test():
+            raise TemplateSyntaxError('wtf', 42)
+        self.assert_traceback_matches(test, r'''
+  File ".*debug.pyc?", line \d+, in test
+    raise TemplateSyntaxError\('wtf', 42\)
+(jinja2\.exceptions\.)?TemplateSyntaxError: wtf
+  line 42''')
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(DebugTestCase))
+    return suite
diff --git a/lib/jinja2/jinja2/testsuite/doctests.py b/lib/jinja2/jinja2/testsuite/doctests.py
new file mode 100644
index 0000000..616d3b6
--- /dev/null
+++ b/lib/jinja2/jinja2/testsuite/doctests.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.testsuite.doctests
+    ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    The doctests.  Collects all tests we want to test from
+    the Jinja modules.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import unittest
+import doctest
+
+
+def suite():
+    from jinja2 import utils, sandbox, runtime, meta, loaders, \
+        ext, environment, bccache, nodes
+    suite = unittest.TestSuite()
+    suite.addTest(doctest.DocTestSuite(utils))
+    suite.addTest(doctest.DocTestSuite(sandbox))
+    suite.addTest(doctest.DocTestSuite(runtime))
+    suite.addTest(doctest.DocTestSuite(meta))
+    suite.addTest(doctest.DocTestSuite(loaders))
+    suite.addTest(doctest.DocTestSuite(ext))
+    suite.addTest(doctest.DocTestSuite(environment))
+    suite.addTest(doctest.DocTestSuite(bccache))
+    suite.addTest(doctest.DocTestSuite(nodes))
+    return suite
diff --git a/lib/jinja2/jinja2/testsuite/ext.py b/lib/jinja2/jinja2/testsuite/ext.py
new file mode 100644
index 0000000..6ca6c22
--- /dev/null
+++ b/lib/jinja2/jinja2/testsuite/ext.py
@@ -0,0 +1,455 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.testsuite.ext
+    ~~~~~~~~~~~~~~~~~~~~
+
+    Tests for the extensions.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import re
+import unittest
+
+from jinja2.testsuite import JinjaTestCase
+
+from jinja2 import Environment, DictLoader, contextfunction, nodes
+from jinja2.exceptions import TemplateAssertionError
+from jinja2.ext import Extension
+from jinja2.lexer import Token, count_newlines
+from jinja2.utils import next
+
+# 2.x / 3.x
+try:
+    from io import BytesIO
+except ImportError:
+    from StringIO import StringIO as BytesIO
+
+
+importable_object = 23
+
+_gettext_re = re.compile(r'_\((.*?)\)(?s)')
+
+
+i18n_templates = {
+    'master.html': '<title>{{ page_title|default(_("missing")) }}</title>'
+                   '{% block body %}{% endblock %}',
+    'child.html': '{% extends "master.html" %}{% block body %}'
+                  '{% trans %}watch out{% endtrans %}{% endblock %}',
+    'plural.html': '{% trans user_count %}One user online{% pluralize %}'
+                   '{{ user_count }} users online{% endtrans %}',
+    'stringformat.html': '{{ _("User: %(num)s")|format(num=user_count) }}'
+}
+
+newstyle_i18n_templates = {
+    'master.html': '<title>{{ page_title|default(_("missing")) }}</title>'
+                   '{% block body %}{% endblock %}',
+    'child.html': '{% extends "master.html" %}{% block body %}'
+                  '{% trans %}watch out{% endtrans %}{% endblock %}',
+    'plural.html': '{% trans user_count %}One user online{% pluralize %}'
+                   '{{ user_count }} users online{% endtrans %}',
+    'stringformat.html': '{{ _("User: %(num)s", num=user_count) }}',
+    'ngettext.html': '{{ ngettext("%(num)s apple", "%(num)s apples", apples) }}',
+    'ngettext_long.html': '{% trans num=apples %}{{ num }} apple{% pluralize %}'
+                          '{{ num }} apples{% endtrans %}',
+    'transvars1.html': '{% trans %}User: {{ num }}{% endtrans %}',
+    'transvars2.html': '{% trans num=count %}User: {{ num }}{% endtrans %}',
+    'transvars3.html': '{% trans count=num %}User: {{ count }}{% endtrans %}',
+    'novars.html': '{% trans %}%(hello)s{% endtrans %}',
+    'vars.html': '{% trans %}{{ foo }}%(foo)s{% endtrans %}',
+    'explicitvars.html': '{% trans foo="42" %}%(foo)s{% endtrans %}'
+}
+
+
+languages = {
+    'de': {
+        'missing':                      u'fehlend',
+        'watch out':                    u'pass auf',
+        'One user online':              u'Ein Benutzer online',
+        '%(user_count)s users online':  u'%(user_count)s Benutzer online',
+        'User: %(num)s':                u'Benutzer: %(num)s',
+        'User: %(count)s':              u'Benutzer: %(count)s',
+        '%(num)s apple':                u'%(num)s Apfel',
+        '%(num)s apples':               u'%(num)s Äpfel'
+    }
+}
+
+
+@contextfunction
+def gettext(context, string):
+    language = context.get('LANGUAGE', 'en')
+    return languages.get(language, {}).get(string, string)
+
+
+@contextfunction
+def ngettext(context, s, p, n):
+    language = context.get('LANGUAGE', 'en')
+    if n != 1:
+        return languages.get(language, {}).get(p, p)
+    return languages.get(language, {}).get(s, s)
+
+
+i18n_env = Environment(
+    loader=DictLoader(i18n_templates),
+    extensions=['jinja2.ext.i18n']
+)
+i18n_env.globals.update({
+    '_':            gettext,
+    'gettext':      gettext,
+    'ngettext':     ngettext
+})
+
+newstyle_i18n_env = Environment(
+    loader=DictLoader(newstyle_i18n_templates),
+    extensions=['jinja2.ext.i18n']
+)
+newstyle_i18n_env.install_gettext_callables(gettext, ngettext, newstyle=True)
+
+class TestExtension(Extension):
+    tags = set(['test'])
+    ext_attr = 42
+
+    def parse(self, parser):
+        return nodes.Output([self.call_method('_dump', [
+            nodes.EnvironmentAttribute('sandboxed'),
+            self.attr('ext_attr'),
+            nodes.ImportedName(__name__ + '.importable_object'),
+            nodes.ContextReference()
+        ])]).set_lineno(next(parser.stream).lineno)
+
+    def _dump(self, sandboxed, ext_attr, imported_object, context):
+        return '%s|%s|%s|%s' % (
+            sandboxed,
+            ext_attr,
+            imported_object,
+            context.blocks
+        )
+
+
+class PreprocessorExtension(Extension):
+
+    def preprocess(self, source, name, filename=None):
+        return source.replace('[[TEST]]', '({{ foo }})')
+
+
+class StreamFilterExtension(Extension):
+
+    def filter_stream(self, stream):
+        for token in stream:
+            if token.type == 'data':
+                for t in self.interpolate(token):
+                    yield t
+            else:
+                yield token
+
+    def interpolate(self, token):
+        pos = 0
+        end = len(token.value)
+        lineno = token.lineno
+        while 1:
+            match = _gettext_re.search(token.value, pos)
+            if match is None:
+                break
+            value = token.value[pos:match.start()]
+            if value:
+                yield Token(lineno, 'data', value)
+            lineno += count_newlines(token.value)
+            yield Token(lineno, 'variable_begin', None)
+            yield Token(lineno, 'name', 'gettext')
+            yield Token(lineno, 'lparen', None)
+            yield Token(lineno, 'string', match.group(1))
+            yield Token(lineno, 'rparen', None)
+            yield Token(lineno, 'variable_end', None)
+            pos = match.end()
+        if pos < end:
+            yield Token(lineno, 'data', token.value[pos:])
+
+
+class ExtensionsTestCase(JinjaTestCase):
+
+    def test_extend_late(self):
+        env = Environment()
+        env.add_extension('jinja2.ext.autoescape')
+        t = env.from_string('{% autoescape true %}{{ "<test>" }}{% endautoescape %}')
+        assert t.render() == '&lt;test&gt;'
+
+    def test_loop_controls(self):
+        env = Environment(extensions=['jinja2.ext.loopcontrols'])
+
+        tmpl = env.from_string('''
+            {%- for item in [1, 2, 3, 4] %}
+                {%- if item % 2 == 0 %}{% continue %}{% endif -%}
+                {{ item }}
+            {%- endfor %}''')
+        assert tmpl.render() == '13'
+
+        tmpl = env.from_string('''
+            {%- for item in [1, 2, 3, 4] %}
+                {%- if item > 2 %}{% break %}{% endif -%}
+                {{ item }}
+            {%- endfor %}''')
+        assert tmpl.render() == '12'
+
+    def test_do(self):
+        env = Environment(extensions=['jinja2.ext.do'])
+        tmpl = env.from_string('''
+            {%- set items = [] %}
+            {%- for char in "foo" %}
+                {%- do items.append(loop.index0 ~ char) %}
+            {%- endfor %}{{ items|join(', ') }}''')
+        assert tmpl.render() == '0f, 1o, 2o'
+
+    def test_with(self):
+        env = Environment(extensions=['jinja2.ext.with_'])
+        tmpl = env.from_string('''\
+        {% with a=42, b=23 -%}
+            {{ a }} = {{ b }}
+        {% endwith -%}
+            {{ a }} = {{ b }}\
+        ''')
+        assert [x.strip() for x in tmpl.render(a=1, b=2).splitlines()] \
+            == ['42 = 23', '1 = 2']
+
+    def test_extension_nodes(self):
+        env = Environment(extensions=[TestExtension])
+        tmpl = env.from_string('{% test %}')
+        assert tmpl.render() == 'False|42|23|{}'
+
+    def test_identifier(self):
+        assert TestExtension.identifier == __name__ + '.TestExtension'
+
+    def test_rebinding(self):
+        original = Environment(extensions=[TestExtension])
+        overlay = original.overlay()
+        for env in original, overlay:
+            for ext in env.extensions.itervalues():
+                assert ext.environment is env
+
+    def test_preprocessor_extension(self):
+        env = Environment(extensions=[PreprocessorExtension])
+        tmpl = env.from_string('{[[TEST]]}')
+        assert tmpl.render(foo=42) == '{(42)}'
+
+    def test_streamfilter_extension(self):
+        env = Environment(extensions=[StreamFilterExtension])
+        env.globals['gettext'] = lambda x: x.upper()
+        tmpl = env.from_string('Foo _(bar) Baz')
+        out = tmpl.render()
+        assert out == 'Foo BAR Baz'
+
+    def test_extension_ordering(self):
+        class T1(Extension):
+            priority = 1
+        class T2(Extension):
+            priority = 2
+        env = Environment(extensions=[T1, T2])
+        ext = list(env.iter_extensions())
+        assert ext[0].__class__ is T1
+        assert ext[1].__class__ is T2
+
+
+class InternationalizationTestCase(JinjaTestCase):
+
+    def test_trans(self):
+        tmpl = i18n_env.get_template('child.html')
+        assert tmpl.render(LANGUAGE='de') == '<title>fehlend</title>pass auf'
+
+    def test_trans_plural(self):
+        tmpl = i18n_env.get_template('plural.html')
+        assert tmpl.render(LANGUAGE='de', user_count=1) == 'Ein Benutzer online'
+        assert tmpl.render(LANGUAGE='de', user_count=2) == '2 Benutzer online'
+
+    def test_complex_plural(self):
+        tmpl = i18n_env.from_string('{% trans foo=42, count=2 %}{{ count }} item{% '
+                                    'pluralize count %}{{ count }} items{% endtrans %}')
+        assert tmpl.render() == '2 items'
+        self.assert_raises(TemplateAssertionError, i18n_env.from_string,
+                           '{% trans foo %}...{% pluralize bar %}...{% endtrans %}')
+
+    def test_trans_stringformatting(self):
+        tmpl = i18n_env.get_template('stringformat.html')
+        assert tmpl.render(LANGUAGE='de', user_count=5) == 'Benutzer: 5'
+
+    def test_extract(self):
+        from jinja2.ext import babel_extract
+        source = BytesIO('''
+        {{ gettext('Hello World') }}
+        {% trans %}Hello World{% endtrans %}
+        {% trans %}{{ users }} user{% pluralize %}{{ users }} users{% endtrans %}
+        '''.encode('ascii')) # make python 3 happy
+        assert list(babel_extract(source, ('gettext', 'ngettext', '_'), [], {})) == [
+            (2, 'gettext', u'Hello World', []),
+            (3, 'gettext', u'Hello World', []),
+            (4, 'ngettext', (u'%(users)s user', u'%(users)s users', None), [])
+        ]
+
+    def test_comment_extract(self):
+        from jinja2.ext import babel_extract
+        source = BytesIO('''
+        {# trans first #}
+        {{ gettext('Hello World') }}
+        {% trans %}Hello World{% endtrans %}{# trans second #}
+        {#: third #}
+        {% trans %}{{ users }} user{% pluralize %}{{ users }} users{% endtrans %}
+        '''.encode('utf-8')) # make python 3 happy
+        assert list(babel_extract(source, ('gettext', 'ngettext', '_'), ['trans', ':'], {})) == [
+            (3, 'gettext', u'Hello World', ['first']),
+            (4, 'gettext', u'Hello World', ['second']),
+            (6, 'ngettext', (u'%(users)s user', u'%(users)s users', None), ['third'])
+        ]
+
+
+class NewstyleInternationalizationTestCase(JinjaTestCase):
+
+    def test_trans(self):
+        tmpl = newstyle_i18n_env.get_template('child.html')
+        assert tmpl.render(LANGUAGE='de') == '<title>fehlend</title>pass auf'
+
+    def test_trans_plural(self):
+        tmpl = newstyle_i18n_env.get_template('plural.html')
+        assert tmpl.render(LANGUAGE='de', user_count=1) == 'Ein Benutzer online'
+        assert tmpl.render(LANGUAGE='de', user_count=2) == '2 Benutzer online'
+
+    def test_complex_plural(self):
+        tmpl = newstyle_i18n_env.from_string('{% trans foo=42, count=2 %}{{ count }} item{% '
+                                    'pluralize count %}{{ count }} items{% endtrans %}')
+        assert tmpl.render() == '2 items'
+        self.assert_raises(TemplateAssertionError, i18n_env.from_string,
+                           '{% trans foo %}...{% pluralize bar %}...{% endtrans %}')
+
+    def test_trans_stringformatting(self):
+        tmpl = newstyle_i18n_env.get_template('stringformat.html')
+        assert tmpl.render(LANGUAGE='de', user_count=5) == 'Benutzer: 5'
+
+    def test_newstyle_plural(self):
+        tmpl = newstyle_i18n_env.get_template('ngettext.html')
+        assert tmpl.render(LANGUAGE='de', apples=1) == '1 Apfel'
+        assert tmpl.render(LANGUAGE='de', apples=5) == u'5 Äpfel'
+
+    def test_autoescape_support(self):
+        env = Environment(extensions=['jinja2.ext.autoescape',
+                                      'jinja2.ext.i18n'])
+        env.install_gettext_callables(lambda x: u'<strong>Wert: %(name)s</strong>',
+                                      lambda s, p, n: s, newstyle=True)
+        t = env.from_string('{% autoescape ae %}{{ gettext("foo", name='
+                            '"<test>") }}{% endautoescape %}')
+        assert t.render(ae=True) == '<strong>Wert: &lt;test&gt;</strong>'
+        assert t.render(ae=False) == '<strong>Wert: <test></strong>'
+
+    def test_num_used_twice(self):
+        tmpl = newstyle_i18n_env.get_template('ngettext_long.html')
+        assert tmpl.render(apples=5, LANGUAGE='de') == u'5 Äpfel'
+
+    def test_num_called_num(self):
+        source = newstyle_i18n_env.compile('''
+            {% trans num=3 %}{{ num }} apple{% pluralize
+            %}{{ num }} apples{% endtrans %}
+        ''', raw=True)
+        # quite hacky, but the only way to properly test that.  The idea is
+        # that the generated code does not pass num twice (although that
+        # would work) for better performance.  This only works on the
+        # newstyle gettext of course
+        assert re.search(r"l_ngettext, u?'\%\(num\)s apple', u?'\%\(num\)s "
+                         r"apples', 3", source) is not None
+
+    def test_trans_vars(self):
+        t1 = newstyle_i18n_env.get_template('transvars1.html')
+        t2 = newstyle_i18n_env.get_template('transvars2.html')
+        t3 = newstyle_i18n_env.get_template('transvars3.html')
+        assert t1.render(num=1, LANGUAGE='de') == 'Benutzer: 1'
+        assert t2.render(count=23, LANGUAGE='de') == 'Benutzer: 23'
+        assert t3.render(num=42, LANGUAGE='de') == 'Benutzer: 42'
+
+    def test_novars_vars_escaping(self):
+        t = newstyle_i18n_env.get_template('novars.html')
+        assert t.render() == '%(hello)s'
+        t = newstyle_i18n_env.get_template('vars.html')
+        assert t.render(foo='42') == '42%(foo)s'
+        t = newstyle_i18n_env.get_template('explicitvars.html')
+        assert t.render() == '%(foo)s'
+
+
+class AutoEscapeTestCase(JinjaTestCase):
+
+    def test_scoped_setting(self):
+        env = Environment(extensions=['jinja2.ext.autoescape'],
+                          autoescape=True)
+        tmpl = env.from_string('''
+            {{ "<HelloWorld>" }}
+            {% autoescape false %}
+                {{ "<HelloWorld>" }}
+            {% endautoescape %}
+            {{ "<HelloWorld>" }}
+        ''')
+        assert tmpl.render().split() == \
+            [u'&lt;HelloWorld&gt;', u'<HelloWorld>', u'&lt;HelloWorld&gt;']
+
+        env = Environment(extensions=['jinja2.ext.autoescape'],
+                          autoescape=False)
+        tmpl = env.from_string('''
+            {{ "<HelloWorld>" }}
+            {% autoescape true %}
+                {{ "<HelloWorld>" }}
+            {% endautoescape %}
+            {{ "<HelloWorld>" }}
+        ''')
+        assert tmpl.render().split() == \
+            [u'<HelloWorld>', u'&lt;HelloWorld&gt;', u'<HelloWorld>']
+
+    def test_nonvolatile(self):
+        env = Environment(extensions=['jinja2.ext.autoescape'],
+                          autoescape=True)
+        tmpl = env.from_string('{{ {"foo": "<test>"}|xmlattr|escape }}')
+        assert tmpl.render() == ' foo="&lt;test&gt;"'
+        tmpl = env.from_string('{% autoescape false %}{{ {"foo": "<test>"}'
+                               '|xmlattr|escape }}{% endautoescape %}')
+        assert tmpl.render() == ' foo=&#34;&amp;lt;test&amp;gt;&#34;'
+
+    def test_volatile(self):
+        env = Environment(extensions=['jinja2.ext.autoescape'],
+                          autoescape=True)
+        tmpl = env.from_string('{% autoescape foo %}{{ {"foo": "<test>"}'
+                               '|xmlattr|escape }}{% endautoescape %}')
+        assert tmpl.render(foo=False) == ' foo=&#34;&amp;lt;test&amp;gt;&#34;'
+        assert tmpl.render(foo=True) == ' foo="&lt;test&gt;"'
+
+    def test_scoping(self):
+        env = Environment(extensions=['jinja2.ext.autoescape'])
+        tmpl = env.from_string('{% autoescape true %}{% set x = "<x>" %}{{ x }}'
+                               '{% endautoescape %}{{ x }}{{ "<y>" }}')
+        assert tmpl.render(x=1) == '&lt;x&gt;1<y>'
+
+    def test_volatile_scoping(self):
+        env = Environment(extensions=['jinja2.ext.autoescape'])
+        tmplsource = '''
+        {% autoescape val %}
+            {% macro foo(x) %}
+                [{{ x }}]
+            {% endmacro %}
+            {{ foo().__class__.__name__ }}
+        {% endautoescape %}
+        {{ '<testing>' }}
+        '''
+        tmpl = env.from_string(tmplsource)
+        assert tmpl.render(val=True).split()[0] == 'Markup'
+        assert tmpl.render(val=False).split()[0] == unicode.__name__
+
+        # looking at the source we should see <testing> there in raw
+        # (and then escaped as well)
+        env = Environment(extensions=['jinja2.ext.autoescape'])
+        pysource = env.compile(tmplsource, raw=True)
+        assert '<testing>\\n' in pysource
+
+        env = Environment(extensions=['jinja2.ext.autoescape'],
+                          autoescape=True)
+        pysource = env.compile(tmplsource, raw=True)
+        assert '&lt;testing&gt;\\n' in pysource
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(ExtensionsTestCase))
+    suite.addTest(unittest.makeSuite(InternationalizationTestCase))
+    suite.addTest(unittest.makeSuite(NewstyleInternationalizationTestCase))
+    suite.addTest(unittest.makeSuite(AutoEscapeTestCase))
+    return suite
diff --git a/lib/jinja2/jinja2/testsuite/filters.py b/lib/jinja2/jinja2/testsuite/filters.py
new file mode 100644
index 0000000..aefe768
--- /dev/null
+++ b/lib/jinja2/jinja2/testsuite/filters.py
@@ -0,0 +1,356 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.testsuite.filters
+    ~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Tests for the jinja filters.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import unittest
+from jinja2.testsuite import JinjaTestCase
+
+from jinja2 import Markup, Environment
+
+env = Environment()
+
+
+class FilterTestCase(JinjaTestCase):
+
+    def test_capitalize(self):
+        tmpl = env.from_string('{{ "foo bar"|capitalize }}')
+        assert tmpl.render() == 'Foo bar'
+
+    def test_center(self):
+        tmpl = env.from_string('{{ "foo"|center(9) }}')
+        assert tmpl.render() == '   foo   '
+
+    def test_default(self):
+        tmpl = env.from_string(
+            "{{ missing|default('no') }}|{{ false|default('no') }}|"
+            "{{ false|default('no', true) }}|{{ given|default('no') }}"
+        )
+        assert tmpl.render(given='yes') == 'no|False|no|yes'
+
+    def test_dictsort(self):
+        tmpl = env.from_string(
+            '{{ foo|dictsort }}|'
+            '{{ foo|dictsort(true) }}|'
+            '{{ foo|dictsort(false, "value") }}'
+        )
+        out = tmpl.render(foo={"aa": 0, "b": 1, "c": 2, "AB": 3})
+        assert out == ("[('aa', 0), ('AB', 3), ('b', 1), ('c', 2)]|"
+                       "[('AB', 3), ('aa', 0), ('b', 1), ('c', 2)]|"
+                       "[('aa', 0), ('b', 1), ('c', 2), ('AB', 3)]")
+
+    def test_batch(self):
+        tmpl = env.from_string("{{ foo|batch(3)|list }}|"
+                               "{{ foo|batch(3, 'X')|list }}")
+        out = tmpl.render(foo=range(10))
+        assert out == ("[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]|"
+                       "[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 'X', 'X']]")
+
+    def test_slice(self):
+        tmpl = env.from_string('{{ foo|slice(3)|list }}|'
+                               '{{ foo|slice(3, "X")|list }}')
+        out = tmpl.render(foo=range(10))
+        assert out == ("[[0, 1, 2, 3], [4, 5, 6], [7, 8, 9]]|"
+                       "[[0, 1, 2, 3], [4, 5, 6, 'X'], [7, 8, 9, 'X']]")
+
+    def test_escape(self):
+        tmpl = env.from_string('''{{ '<">&'|escape }}''')
+        out = tmpl.render()
+        assert out == '&lt;&#34;&gt;&amp;'
+
+    def test_striptags(self):
+        tmpl = env.from_string('''{{ foo|striptags }}''')
+        out = tmpl.render(foo='  <p>just a small   \n <a href="#">'
+                          'example</a> link</p>\n<p>to a webpage</p> '
+                          '<!-- <p>and some commented stuff</p> -->')
+        assert out == 'just a small example link to a webpage'
+
+    def test_filesizeformat(self):
+        tmpl = env.from_string(
+            '{{ 100|filesizeformat }}|'
+            '{{ 1000|filesizeformat }}|'
+            '{{ 1000000|filesizeformat }}|'
+            '{{ 1000000000|filesizeformat }}|'
+            '{{ 1000000000000|filesizeformat }}|'
+            '{{ 100|filesizeformat(true) }}|'
+            '{{ 1000|filesizeformat(true) }}|'
+            '{{ 1000000|filesizeformat(true) }}|'
+            '{{ 1000000000|filesizeformat(true) }}|'
+            '{{ 1000000000000|filesizeformat(true) }}'
+        )
+        out = tmpl.render()
+        assert out == (
+            '100 Bytes|0.0 kB|0.0 MB|0.0 GB|0.0 TB|100 Bytes|'
+            '1000 Bytes|1.0 KiB|0.9 MiB|0.9 GiB'
+        )
+
+    def test_first(self):
+        tmpl = env.from_string('{{ foo|first }}')
+        out = tmpl.render(foo=range(10))
+        assert out == '0'
+
+    def test_float(self):
+        tmpl = env.from_string('{{ "42"|float }}|'
+                               '{{ "ajsghasjgd"|float }}|'
+                               '{{ "32.32"|float }}')
+        out = tmpl.render()
+        assert out == '42.0|0.0|32.32'
+
+    def test_format(self):
+        tmpl = env.from_string('''{{ "%s|%s"|format("a", "b") }}''')
+        out = tmpl.render()
+        assert out == 'a|b'
+
+    def test_indent(self):
+        tmpl = env.from_string('{{ foo|indent(2) }}|{{ foo|indent(2, true) }}')
+        text = '\n'.join([' '.join(['foo', 'bar'] * 2)] * 2)
+        out = tmpl.render(foo=text)
+        assert out == ('foo bar foo bar\n  foo bar foo bar|  '
+                       'foo bar foo bar\n  foo bar foo bar')
+
+    def test_int(self):
+        tmpl = env.from_string('{{ "42"|int }}|{{ "ajsghasjgd"|int }}|'
+                               '{{ "32.32"|int }}')
+        out = tmpl.render()
+        assert out == '42|0|32'
+
+    def test_join(self):
+        tmpl = env.from_string('{{ [1, 2, 3]|join("|") }}')
+        out = tmpl.render()
+        assert out == '1|2|3'
+
+        env2 = Environment(autoescape=True)
+        tmpl = env2.from_string('{{ ["<foo>", "<span>foo</span>"|safe]|join }}')
+        assert tmpl.render() == '&lt;foo&gt;<span>foo</span>'
+
+    def test_join_attribute(self):
+        class User(object):
+            def __init__(self, username):
+                self.username = username
+        tmpl = env.from_string('''{{ users|join(', ', 'username') }}''')
+        assert tmpl.render(users=map(User, ['foo', 'bar'])) == 'foo, bar'
+
+    def test_last(self):
+        tmpl = env.from_string('''{{ foo|last }}''')
+        out = tmpl.render(foo=range(10))
+        assert out == '9'
+
+    def test_length(self):
+        tmpl = env.from_string('''{{ "hello world"|length }}''')
+        out = tmpl.render()
+        assert out == '11'
+
+    def test_lower(self):
+        tmpl = env.from_string('''{{ "FOO"|lower }}''')
+        out = tmpl.render()
+        assert out == 'foo'
+
+    def test_pprint(self):
+        from pprint import pformat
+        tmpl = env.from_string('''{{ data|pprint }}''')
+        data = range(1000)
+        assert tmpl.render(data=data) == pformat(data)
+
+    def test_random(self):
+        tmpl = env.from_string('''{{ seq|random }}''')
+        seq = range(100)
+        for _ in range(10):
+            assert int(tmpl.render(seq=seq)) in seq
+
+    def test_reverse(self):
+        tmpl = env.from_string('{{ "foobar"|reverse|join }}|'
+                               '{{ [1, 2, 3]|reverse|list }}')
+        assert tmpl.render() == 'raboof|[3, 2, 1]'
+
+    def test_string(self):
+        x = [1, 2, 3, 4, 5]
+        tmpl = env.from_string('''{{ obj|string }}''')
+        assert tmpl.render(obj=x) == unicode(x)
+
+    def test_title(self):
+        tmpl = env.from_string('''{{ "foo bar"|title }}''')
+        assert tmpl.render() == "Foo Bar"
+
+    def test_truncate(self):
+        tmpl = env.from_string(
+            '{{ data|truncate(15, true, ">>>") }}|'
+            '{{ data|truncate(15, false, ">>>") }}|'
+            '{{ smalldata|truncate(15) }}'
+        )
+        out = tmpl.render(data='foobar baz bar' * 1000,
+                          smalldata='foobar baz bar')
+        assert out == 'foobar baz barf>>>|foobar baz >>>|foobar baz bar'
+
+    def test_upper(self):
+        tmpl = env.from_string('{{ "foo"|upper }}')
+        assert tmpl.render() == 'FOO'
+
+    def test_urlize(self):
+        tmpl = env.from_string('{{ "foo http://www.example.com/ bar"|urlize }}')
+        assert tmpl.render() == 'foo <a href="http://www.example.com/">'\
+                                'http://www.example.com/</a> bar'
+
+    def test_wordcount(self):
+        tmpl = env.from_string('{{ "foo bar baz"|wordcount }}')
+        assert tmpl.render() == '3'
+
+    def test_block(self):
+        tmpl = env.from_string('{% filter lower|escape %}<HEHE>{% endfilter %}')
+        assert tmpl.render() == '&lt;hehe&gt;'
+
+    def test_chaining(self):
+        tmpl = env.from_string('''{{ ['<foo>', '<bar>']|first|upper|escape }}''')
+        assert tmpl.render() == '&lt;FOO&gt;'
+
+    def test_sum(self):
+        tmpl = env.from_string('''{{ [1, 2, 3, 4, 5, 6]|sum }}''')
+        assert tmpl.render() == '21'
+
+    def test_sum_attributes(self):
+        tmpl = env.from_string('''{{ values|sum('value') }}''')
+        assert tmpl.render(values=[
+            {'value': 23},
+            {'value': 1},
+            {'value': 18},
+        ]) == '42'
+
+    def test_sum_attributes_nested(self):
+        tmpl = env.from_string('''{{ values|sum('real.value') }}''')
+        assert tmpl.render(values=[
+            {'real': {'value': 23}},
+            {'real': {'value': 1}},
+            {'real': {'value': 18}},
+        ]) == '42'
+
+    def test_abs(self):
+        tmpl = env.from_string('''{{ -1|abs }}|{{ 1|abs }}''')
+        assert tmpl.render() == '1|1', tmpl.render()
+
+    def test_round_positive(self):
+        tmpl = env.from_string('{{ 2.7|round }}|{{ 2.1|round }}|'
+                               "{{ 2.1234|round(3, 'floor') }}|"
+                               "{{ 2.1|round(0, 'ceil') }}")
+        assert tmpl.render() == '3.0|2.0|2.123|3.0', tmpl.render()
+
+    def test_round_negative(self):
+        tmpl = env.from_string('{{ 21.3|round(-1)}}|'
+                               "{{ 21.3|round(-1, 'ceil')}}|"
+                               "{{ 21.3|round(-1, 'floor')}}")
+        assert tmpl.render() == '20.0|30.0|20.0',tmpl.render()
+
+    def test_xmlattr(self):
+        tmpl = env.from_string("{{ {'foo': 42, 'bar': 23, 'fish': none, "
+                               "'spam': missing, 'blub:blub': '<?>'}|xmlattr }}")
+        out = tmpl.render().split()
+        assert len(out) == 3
+        assert 'foo="42"' in out
+        assert 'bar="23"' in out
+        assert 'blub:blub="&lt;?&gt;"' in out
+
+    def test_sort1(self):
+        tmpl = env.from_string('{{ [2, 3, 1]|sort }}|{{ [2, 3, 1]|sort(true) }}')
+        assert tmpl.render() == '[1, 2, 3]|[3, 2, 1]'
+
+    def test_sort2(self):
+        tmpl = env.from_string('{{ "".join(["c", "A", "b", "D"]|sort) }}')
+        assert tmpl.render() == 'AbcD'
+
+    def test_sort3(self):
+        tmpl = env.from_string('''{{ ['foo', 'Bar', 'blah']|sort }}''')
+        assert tmpl.render() == "['Bar', 'blah', 'foo']"
+
+    def test_sort4(self):
+        class Magic(object):
+            def __init__(self, value):
+                self.value = value
+            def __unicode__(self):
+                return unicode(self.value)
+        tmpl = env.from_string('''{{ items|sort(attribute='value')|join }}''')
+        assert tmpl.render(items=map(Magic, [3, 2, 4, 1])) == '1234'
+
+    def test_groupby(self):
+        tmpl = env.from_string('''
+        {%- for grouper, list in [{'foo': 1, 'bar': 2},
+                                  {'foo': 2, 'bar': 3},
+                                  {'foo': 1, 'bar': 1},
+                                  {'foo': 3, 'bar': 4}]|groupby('foo') -%}
+            {{ grouper }}{% for x in list %}: {{ x.foo }}, {{ x.bar }}{% endfor %}|
+        {%- endfor %}''')
+        assert tmpl.render().split('|') == [
+            "1: 1, 2: 1, 1",
+            "2: 2, 3",
+            "3: 3, 4",
+            ""
+        ]
+
+    def test_groupby_tuple_index(self):
+        tmpl = env.from_string('''
+        {%- for grouper, list in [('a', 1), ('a', 2), ('b', 1)]|groupby(0) -%}
+            {{ grouper }}{% for x in list %}:{{ x.1 }}{% endfor %}|
+        {%- endfor %}''')
+        assert tmpl.render() == 'a:1:2|b:1|'
+
+    def test_groupby_multidot(self):
+        class Date(object):
+            def __init__(self, day, month, year):
+                self.day = day
+                self.month = month
+                self.year = year
+        class Article(object):
+            def __init__(self, title, *date):
+                self.date = Date(*date)
+                self.title = title
+        articles = [
+            Article('aha', 1, 1, 1970),
+            Article('interesting', 2, 1, 1970),
+            Article('really?', 3, 1, 1970),
+            Article('totally not', 1, 1, 1971)
+        ]
+        tmpl = env.from_string('''
+        {%- for year, list in articles|groupby('date.year') -%}
+            {{ year }}{% for x in list %}[{{ x.title }}]{% endfor %}|
+        {%- endfor %}''')
+        assert tmpl.render(articles=articles).split('|') == [
+            '1970[aha][interesting][really?]',
+            '1971[totally not]',
+            ''
+        ]
+
+    def test_filtertag(self):
+        tmpl = env.from_string("{% filter upper|replace('FOO', 'foo') %}"
+                               "foobar{% endfilter %}")
+        assert tmpl.render() == 'fooBAR'
+
+    def test_replace(self):
+        env = Environment()
+        tmpl = env.from_string('{{ string|replace("o", 42) }}')
+        assert tmpl.render(string='<foo>') == '<f4242>'
+        env = Environment(autoescape=True)
+        tmpl = env.from_string('{{ string|replace("o", 42) }}')
+        assert tmpl.render(string='<foo>') == '&lt;f4242&gt;'
+        tmpl = env.from_string('{{ string|replace("<", 42) }}')
+        assert tmpl.render(string='<foo>') == '42foo&gt;'
+        tmpl = env.from_string('{{ string|replace("o", ">x<") }}')
+        assert tmpl.render(string=Markup('foo')) == 'f&gt;x&lt;&gt;x&lt;'
+
+    def test_forceescape(self):
+        tmpl = env.from_string('{{ x|forceescape }}')
+        assert tmpl.render(x=Markup('<div />')) == u'&lt;div /&gt;'
+
+    def test_safe(self):
+        env = Environment(autoescape=True)
+        tmpl = env.from_string('{{ "<div>foo</div>"|safe }}')
+        assert tmpl.render() == '<div>foo</div>'
+        tmpl = env.from_string('{{ "<div>foo</div>" }}')
+        assert tmpl.render() == '&lt;div&gt;foo&lt;/div&gt;'
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(FilterTestCase))
+    return suite
diff --git a/lib/jinja2/jinja2/testsuite/imports.py b/lib/jinja2/jinja2/testsuite/imports.py
new file mode 100644
index 0000000..1cb12cb
--- /dev/null
+++ b/lib/jinja2/jinja2/testsuite/imports.py
@@ -0,0 +1,141 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.testsuite.imports
+    ~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Tests the import features (with includes).
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import unittest
+
+from jinja2.testsuite import JinjaTestCase
+
+from jinja2 import Environment, DictLoader
+from jinja2.exceptions import TemplateNotFound, TemplatesNotFound
+
+
+test_env = Environment(loader=DictLoader(dict(
+    module='{% macro test() %}[{{ foo }}|{{ bar }}]{% endmacro %}',
+    header='[{{ foo }}|{{ 23 }}]',
+    o_printer='({{ o }})'
+)))
+test_env.globals['bar'] = 23
+
+
+class ImportsTestCase(JinjaTestCase):
+
+    def test_context_imports(self):
+        t = test_env.from_string('{% import "module" as m %}{{ m.test() }}')
+        assert t.render(foo=42) == '[|23]'
+        t = test_env.from_string('{% import "module" as m without context %}{{ m.test() }}')
+        assert t.render(foo=42) == '[|23]'
+        t = test_env.from_string('{% import "module" as m with context %}{{ m.test() }}')
+        assert t.render(foo=42) == '[42|23]'
+        t = test_env.from_string('{% from "module" import test %}{{ test() }}')
+        assert t.render(foo=42) == '[|23]'
+        t = test_env.from_string('{% from "module" import test without context %}{{ test() }}')
+        assert t.render(foo=42) == '[|23]'
+        t = test_env.from_string('{% from "module" import test with context %}{{ test() }}')
+        assert t.render(foo=42) == '[42|23]'
+
+    def test_trailing_comma(self):
+        test_env.from_string('{% from "foo" import bar, baz with context %}')
+        test_env.from_string('{% from "foo" import bar, baz, with context %}')
+        test_env.from_string('{% from "foo" import bar, with context %}')
+        test_env.from_string('{% from "foo" import bar, with, context %}')
+        test_env.from_string('{% from "foo" import bar, with with context %}')
+
+    def test_exports(self):
+        m = test_env.from_string('''
+            {% macro toplevel() %}...{% endmacro %}
+            {% macro __private() %}...{% endmacro %}
+            {% set variable = 42 %}
+            {% for item in [1] %}
+                {% macro notthere() %}{% endmacro %}
+            {% endfor %}
+        ''').module
+        assert m.toplevel() == '...'
+        assert not hasattr(m, '__missing')
+        assert m.variable == 42
+        assert not hasattr(m, 'notthere')
+
+
+class IncludesTestCase(JinjaTestCase):
+
+    def test_context_include(self):
+        t = test_env.from_string('{% include "header" %}')
+        assert t.render(foo=42) == '[42|23]'
+        t = test_env.from_string('{% include "header" with context %}')
+        assert t.render(foo=42) == '[42|23]'
+        t = test_env.from_string('{% include "header" without context %}')
+        assert t.render(foo=42) == '[|23]'
+
+    def test_choice_includes(self):
+        t = test_env.from_string('{% include ["missing", "header"] %}')
+        assert t.render(foo=42) == '[42|23]'
+
+        t = test_env.from_string('{% include ["missing", "missing2"] ignore missing %}')
+        assert t.render(foo=42) == ''
+
+        t = test_env.from_string('{% include ["missing", "missing2"] %}')
+        self.assert_raises(TemplateNotFound, t.render)
+        try:
+            t.render()
+        except TemplatesNotFound, e:
+            assert e.templates == ['missing', 'missing2']
+            assert e.name == 'missing2'
+        else:
+            assert False, 'thou shalt raise'
+
+        def test_includes(t, **ctx):
+            ctx['foo'] = 42
+            assert t.render(ctx) == '[42|23]'
+
+        t = test_env.from_string('{% include ["missing", "header"] %}')
+        test_includes(t)
+        t = test_env.from_string('{% include x %}')
+        test_includes(t, x=['missing', 'header'])
+        t = test_env.from_string('{% include [x, "header"] %}')
+        test_includes(t, x='missing')
+        t = test_env.from_string('{% include x %}')
+        test_includes(t, x='header')
+        t = test_env.from_string('{% include x %}')
+        test_includes(t, x='header')
+        t = test_env.from_string('{% include [x] %}')
+        test_includes(t, x='header')
+
+    def test_include_ignoring_missing(self):
+        t = test_env.from_string('{% include "missing" %}')
+        self.assert_raises(TemplateNotFound, t.render)
+        for extra in '', 'with context', 'without context':
+            t = test_env.from_string('{% include "missing" ignore missing ' +
+                                     extra + ' %}')
+            assert t.render() == ''
+
+    def test_context_include_with_overrides(self):
+        env = Environment(loader=DictLoader(dict(
+            main="{% for item in [1, 2, 3] %}{% include 'item' %}{% endfor %}",
+            item="{{ item }}"
+        )))
+        assert env.get_template("main").render() == "123"
+
+    def test_unoptimized_scopes(self):
+        t = test_env.from_string("""
+            {% macro outer(o) %}
+            {% macro inner() %}
+            {% include "o_printer" %}
+            {% endmacro %}
+            {{ inner() }}
+            {% endmacro %}
+            {{ outer("FOO") }}
+        """)
+        assert t.render().strip() == '(FOO)'
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(ImportsTestCase))
+    suite.addTest(unittest.makeSuite(IncludesTestCase))
+    return suite
diff --git a/lib/jinja2/jinja2/testsuite/inheritance.py b/lib/jinja2/jinja2/testsuite/inheritance.py
new file mode 100644
index 0000000..355aa0c
--- /dev/null
+++ b/lib/jinja2/jinja2/testsuite/inheritance.py
@@ -0,0 +1,227 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.testsuite.inheritance
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Tests the template inheritance feature.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import unittest
+
+from jinja2.testsuite import JinjaTestCase
+
+from jinja2 import Environment, DictLoader
+
+
+LAYOUTTEMPLATE = '''\
+|{% block block1 %}block 1 from layout{% endblock %}
+|{% block block2 %}block 2 from layout{% endblock %}
+|{% block block3 %}
+{% block block4 %}nested block 4 from layout{% endblock %}
+{% endblock %}|'''
+
+LEVEL1TEMPLATE = '''\
+{% extends "layout" %}
+{% block block1 %}block 1 from level1{% endblock %}'''
+
+LEVEL2TEMPLATE = '''\
+{% extends "level1" %}
+{% block block2 %}{% block block5 %}nested block 5 from level2{%
+endblock %}{% endblock %}'''
+
+LEVEL3TEMPLATE = '''\
+{% extends "level2" %}
+{% block block5 %}block 5 from level3{% endblock %}
+{% block block4 %}block 4 from level3{% endblock %}
+'''
+
+LEVEL4TEMPLATE = '''\
+{% extends "level3" %}
+{% block block3 %}block 3 from level4{% endblock %}
+'''
+
+WORKINGTEMPLATE = '''\
+{% extends "layout" %}
+{% block block1 %}
+  {% if false %}
+    {% block block2 %}
+      this should workd
+    {% endblock %}
+  {% endif %}
+{% endblock %}
+'''
+
+env = Environment(loader=DictLoader({
+    'layout':       LAYOUTTEMPLATE,
+    'level1':       LEVEL1TEMPLATE,
+    'level2':       LEVEL2TEMPLATE,
+    'level3':       LEVEL3TEMPLATE,
+    'level4':       LEVEL4TEMPLATE,
+    'working':      WORKINGTEMPLATE
+}), trim_blocks=True)
+
+
+class InheritanceTestCase(JinjaTestCase):
+
+    def test_layout(self):
+        tmpl = env.get_template('layout')
+        assert tmpl.render() == ('|block 1 from layout|block 2 from '
+                                 'layout|nested block 4 from layout|')
+
+    def test_level1(self):
+        tmpl = env.get_template('level1')
+        assert tmpl.render() == ('|block 1 from level1|block 2 from '
+                                 'layout|nested block 4 from layout|')
+
+    def test_level2(self):
+        tmpl = env.get_template('level2')
+        assert tmpl.render() == ('|block 1 from level1|nested block 5 from '
+                                 'level2|nested block 4 from layout|')
+
+    def test_level3(self):
+        tmpl = env.get_template('level3')
+        assert tmpl.render() == ('|block 1 from level1|block 5 from level3|'
+                                 'block 4 from level3|')
+
+    def test_level4(sel):
+        tmpl = env.get_template('level4')
+        assert tmpl.render() == ('|block 1 from level1|block 5 from '
+                                 'level3|block 3 from level4|')
+
+    def test_super(self):
+        env = Environment(loader=DictLoader({
+            'a': '{% block intro %}INTRO{% endblock %}|'
+                 'BEFORE|{% block data %}INNER{% endblock %}|AFTER',
+            'b': '{% extends "a" %}{% block data %}({{ '
+                 'super() }}){% endblock %}',
+            'c': '{% extends "b" %}{% block intro %}--{{ '
+                 'super() }}--{% endblock %}\n{% block data '
+                 '%}[{{ super() }}]{% endblock %}'
+        }))
+        tmpl = env.get_template('c')
+        assert tmpl.render() == '--INTRO--|BEFORE|[(INNER)]|AFTER'
+
+    def test_working(self):
+        tmpl = env.get_template('working')
+
+    def test_reuse_blocks(self):
+        tmpl = env.from_string('{{ self.foo() }}|{% block foo %}42'
+                               '{% endblock %}|{{ self.foo() }}')
+        assert tmpl.render() == '42|42|42'
+
+    def test_preserve_blocks(self):
+        env = Environment(loader=DictLoader({
+            'a': '{% if false %}{% block x %}A{% endblock %}{% endif %}{{ self.x() }}',
+            'b': '{% extends "a" %}{% block x %}B{{ super() }}{% endblock %}'
+        }))
+        tmpl = env.get_template('b')
+        assert tmpl.render() == 'BA'
+
+    def test_dynamic_inheritance(self):
+        env = Environment(loader=DictLoader({
+            'master1': 'MASTER1{% block x %}{% endblock %}',
+            'master2': 'MASTER2{% block x %}{% endblock %}',
+            'child': '{% extends master %}{% block x %}CHILD{% endblock %}'
+        }))
+        tmpl = env.get_template('child')
+        for m in range(1, 3):
+            assert tmpl.render(master='master%d' % m) == 'MASTER%dCHILD' % m
+
+    def test_multi_inheritance(self):
+        env = Environment(loader=DictLoader({
+            'master1': 'MASTER1{% block x %}{% endblock %}',
+            'master2': 'MASTER2{% block x %}{% endblock %}',
+            'child': '''{% if master %}{% extends master %}{% else %}{% extends
+                        'master1' %}{% endif %}{% block x %}CHILD{% endblock %}'''
+        }))
+        tmpl = env.get_template('child')
+        assert tmpl.render(master='master2') == 'MASTER2CHILD'
+        assert tmpl.render(master='master1') == 'MASTER1CHILD'
+        assert tmpl.render() == 'MASTER1CHILD'
+
+    def test_scoped_block(self):
+        env = Environment(loader=DictLoader({
+            'master.html': '{% for item in seq %}[{% block item scoped %}'
+                           '{% endblock %}]{% endfor %}'
+        }))
+        t = env.from_string('{% extends "master.html" %}{% block item %}'
+                            '{{ item }}{% endblock %}')
+        assert t.render(seq=range(5)) == '[0][1][2][3][4]'
+
+    def test_super_in_scoped_block(self):
+        env = Environment(loader=DictLoader({
+            'master.html': '{% for item in seq %}[{% block item scoped %}'
+                           '{{ item }}{% endblock %}]{% endfor %}'
+        }))
+        t = env.from_string('{% extends "master.html" %}{% block item %}'
+                            '{{ super() }}|{{ item * 2 }}{% endblock %}')
+        assert t.render(seq=range(5)) == '[0|0][1|2][2|4][3|6][4|8]'
+
+    def test_scoped_block_after_inheritance(self):
+        env = Environment(loader=DictLoader({
+            'layout.html': '''
+            {% block useless %}{% endblock %}
+            ''',
+            'index.html': '''
+            {%- extends 'layout.html' %}
+            {% from 'helpers.html' import foo with context %}
+            {% block useless %}
+                {% for x in [1, 2, 3] %}
+                    {% block testing scoped %}
+                        {{ foo(x) }}
+                    {% endblock %}
+                {% endfor %}
+            {% endblock %}
+            ''',
+            'helpers.html': '''
+            {% macro foo(x) %}{{ the_foo + x }}{% endmacro %}
+            '''
+        }))
+        rv = env.get_template('index.html').render(the_foo=42).split()
+        assert rv == ['43', '44', '45']
+
+
+class BugFixTestCase(JinjaTestCase):
+
+    def test_fixed_macro_scoping_bug(self):
+        assert Environment(loader=DictLoader({
+            'test.html': '''\
+        {% extends 'details.html' %}
+
+        {% macro my_macro() %}
+        my_macro
+        {% endmacro %}
+
+        {% block inner_box %}
+            {{ my_macro() }}
+        {% endblock %}
+            ''',
+            'details.html': '''\
+        {% extends 'standard.html' %}
+
+        {% macro my_macro() %}
+        my_macro
+        {% endmacro %}
+
+        {% block content %}
+            {% block outer_box %}
+                outer_box
+                {% block inner_box %}
+                    inner_box
+                {% endblock %}
+            {% endblock %}
+        {% endblock %}
+        ''',
+            'standard.html': '''
+        {% block content %}&nbsp;{% endblock %}
+        '''
+        })).get_template("test.html").render().split() == [u'outer_box', u'my_macro']
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(InheritanceTestCase))
+    suite.addTest(unittest.makeSuite(BugFixTestCase))
+    return suite
diff --git a/lib/jinja2/jinja2/testsuite/lexnparse.py b/lib/jinja2/jinja2/testsuite/lexnparse.py
new file mode 100644
index 0000000..562df62
--- /dev/null
+++ b/lib/jinja2/jinja2/testsuite/lexnparse.py
@@ -0,0 +1,387 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.testsuite.lexnparse
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    All the unittests regarding lexing, parsing and syntax.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import sys
+import unittest
+
+from jinja2.testsuite import JinjaTestCase
+
+from jinja2 import Environment, Template, TemplateSyntaxError, \
+     UndefinedError, nodes
+
+env = Environment()
+
+
+# how does a string look like in jinja syntax?
+if sys.version_info < (3, 0):
+    def jinja_string_repr(string):
+        return repr(string)[1:]
+else:
+    jinja_string_repr = repr
+
+
+class LexerTestCase(JinjaTestCase):
+
+    def test_raw1(self):
+        tmpl = env.from_string('{% raw %}foo{% endraw %}|'
+                               '{%raw%}{{ bar }}|{% baz %}{%       endraw    %}')
+        assert tmpl.render() == 'foo|{{ bar }}|{% baz %}'
+
+    def test_raw2(self):
+        tmpl = env.from_string('1  {%- raw -%}   2   {%- endraw -%}   3')
+        assert tmpl.render() == '123'
+
+    def test_balancing(self):
+        env = Environment('{%', '%}', '${', '}')
+        tmpl = env.from_string('''{% for item in seq
+            %}${{'foo': item}|upper}{% endfor %}''')
+        assert tmpl.render(seq=range(3)) == "{'FOO': 0}{'FOO': 1}{'FOO': 2}"
+
+    def test_comments(self):
+        env = Environment('<!--', '-->', '{', '}')
+        tmpl = env.from_string('''\
+<ul>
+<!--- for item in seq -->
+  <li>{item}</li>
+<!--- endfor -->
+</ul>''')
+        assert tmpl.render(seq=range(3)) == ("<ul>\n  <li>0</li>\n  "
+                                             "<li>1</li>\n  <li>2</li>\n</ul>")
+
+    def test_string_escapes(self):
+        for char in u'\0', u'\u2668', u'\xe4', u'\t', u'\r', u'\n':
+            tmpl = env.from_string('{{ %s }}' % jinja_string_repr(char))
+            assert tmpl.render() == char
+        assert env.from_string('{{ "\N{HOT SPRINGS}" }}').render() == u'\u2668'
+
+    def test_bytefallback(self):
+        from pprint import pformat
+        tmpl = env.from_string(u'''{{ 'foo'|pprint }}|{{ 'bär'|pprint }}''')
+        assert tmpl.render() == pformat('foo') + '|' + pformat(u'bär')
+
+    def test_operators(self):
+        from jinja2.lexer import operators
+        for test, expect in operators.iteritems():
+            if test in '([{}])':
+                continue
+            stream = env.lexer.tokenize('{{ %s }}' % test)
+            stream.next()
+            assert stream.current.type == expect
+
+    def test_normalizing(self):
+        for seq in '\r', '\r\n', '\n':
+            env = Environment(newline_sequence=seq)
+            tmpl = env.from_string('1\n2\r\n3\n4\n')
+            result = tmpl.render()
+            assert result.replace(seq, 'X') == '1X2X3X4'
+
+
+class ParserTestCase(JinjaTestCase):
+
+    def test_php_syntax(self):
+        env = Environment('<?', '?>', '<?=', '?>', '<!--', '-->')
+        tmpl = env.from_string('''\
+<!-- I'm a comment, I'm not interesting -->\
+<? for item in seq -?>
+    <?= item ?>
+<?- endfor ?>''')
+        assert tmpl.render(seq=range(5)) == '01234'
+
+    def test_erb_syntax(self):
+        env = Environment('<%', '%>', '<%=', '%>', '<%#', '%>')
+        tmpl = env.from_string('''\
+<%# I'm a comment, I'm not interesting %>\
+<% for item in seq -%>
+    <%= item %>
+<%- endfor %>''')
+        assert tmpl.render(seq=range(5)) == '01234'
+
+    def test_comment_syntax(self):
+        env = Environment('<!--', '-->', '${', '}', '<!--#', '-->')
+        tmpl = env.from_string('''\
+<!--# I'm a comment, I'm not interesting -->\
+<!-- for item in seq --->
+    ${item}
+<!--- endfor -->''')
+        assert tmpl.render(seq=range(5)) == '01234'
+
+    def test_balancing(self):
+        tmpl = env.from_string('''{{{'foo':'bar'}.foo}}''')
+        assert tmpl.render() == 'bar'
+
+    def test_start_comment(self):
+        tmpl = env.from_string('''{# foo comment
+and bar comment #}
+{% macro blub() %}foo{% endmacro %}
+{{ blub() }}''')
+        assert tmpl.render().strip() == 'foo'
+
+    def test_line_syntax(self):
+        env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%')
+        tmpl = env.from_string('''\
+<%# regular comment %>
+% for item in seq:
+    ${item}
+% endfor''')
+        assert [int(x.strip()) for x in tmpl.render(seq=range(5)).split()] == \
+               range(5)
+
+        env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%', '##')
+        tmpl = env.from_string('''\
+<%# regular comment %>
+% for item in seq:
+    ${item} ## the rest of the stuff
+% endfor''')
+        assert [int(x.strip()) for x in tmpl.render(seq=range(5)).split()] == \
+                range(5)
+
+    def test_line_syntax_priority(self):
+        # XXX: why is the whitespace there in front of the newline?
+        env = Environment('{%', '%}', '${', '}', '/*', '*/', '##', '#')
+        tmpl = env.from_string('''\
+/* ignore me.
+   I'm a multiline comment */
+## for item in seq:
+* ${item}          # this is just extra stuff
+## endfor''')
+        assert tmpl.render(seq=[1, 2]).strip() == '* 1\n* 2'
+        env = Environment('{%', '%}', '${', '}', '/*', '*/', '#', '##')
+        tmpl = env.from_string('''\
+/* ignore me.
+   I'm a multiline comment */
+# for item in seq:
+* ${item}          ## this is just extra stuff
+    ## extra stuff i just want to ignore
+# endfor''')
+        assert tmpl.render(seq=[1, 2]).strip() == '* 1\n\n* 2'
+
+    def test_error_messages(self):
+        def assert_error(code, expected):
+            try:
+                Template(code)
+            except TemplateSyntaxError, e:
+                assert str(e) == expected, 'unexpected error message'
+            else:
+                assert False, 'that was suposed to be an error'
+
+        assert_error('{% for item in seq %}...{% endif %}',
+                     "Encountered unknown tag 'endif'. Jinja was looking "
+                     "for the following tags: 'endfor' or 'else'. The "
+                     "innermost block that needs to be closed is 'for'.")
+        assert_error('{% if foo %}{% for item in seq %}...{% endfor %}{% endfor %}',
+                     "Encountered unknown tag 'endfor'. Jinja was looking for "
+                     "the following tags: 'elif' or 'else' or 'endif'. The "
+                     "innermost block that needs to be closed is 'if'.")
+        assert_error('{% if foo %}',
+                     "Unexpected end of template. Jinja was looking for the "
+                     "following tags: 'elif' or 'else' or 'endif'. The "
+                     "innermost block that needs to be closed is 'if'.")
+        assert_error('{% for item in seq %}',
+                     "Unexpected end of template. Jinja was looking for the "
+                     "following tags: 'endfor' or 'else'. The innermost block "
+                     "that needs to be closed is 'for'.")
+        assert_error('{% block foo-bar-baz %}',
+                     "Block names in Jinja have to be valid Python identifiers "
+                     "and may not contain hypens, use an underscore instead.")
+        assert_error('{% unknown_tag %}',
+                     "Encountered unknown tag 'unknown_tag'.")
+
+
+class SyntaxTestCase(JinjaTestCase):
+
+    def test_call(self):
+        env = Environment()
+        env.globals['foo'] = lambda a, b, c, e, g: a + b + c + e + g
+        tmpl = env.from_string("{{ foo('a', c='d', e='f', *['b'], **{'g': 'h'}) }}")
+        assert tmpl.render() == 'abdfh'
+
+    def test_slicing(self):
+        tmpl = env.from_string('{{ [1, 2, 3][:] }}|{{ [1, 2, 3][::-1] }}')
+        assert tmpl.render() == '[1, 2, 3]|[3, 2, 1]'
+
+    def test_attr(self):
+        tmpl = env.from_string("{{ foo.bar }}|{{ foo['bar'] }}")
+        assert tmpl.render(foo={'bar': 42}) == '42|42'
+
+    def test_subscript(self):
+        tmpl = env.from_string("{{ foo[0] }}|{{ foo[-1] }}")
+        assert tmpl.render(foo=[0, 1, 2]) == '0|2'
+
+    def test_tuple(self):
+        tmpl = env.from_string('{{ () }}|{{ (1,) }}|{{ (1, 2) }}')
+        assert tmpl.render() == '()|(1,)|(1, 2)'
+
+    def test_math(self):
+        tmpl = env.from_string('{{ (1 + 1 * 2) - 3 / 2 }}|{{ 2**3 }}')
+        assert tmpl.render() == '1.5|8'
+
+    def test_div(self):
+        tmpl = env.from_string('{{ 3 // 2 }}|{{ 3 / 2 }}|{{ 3 % 2 }}')
+        assert tmpl.render() == '1|1.5|1'
+
+    def test_unary(self):
+        tmpl = env.from_string('{{ +3 }}|{{ -3 }}')
+        assert tmpl.render() == '3|-3'
+
+    def test_concat(self):
+        tmpl = env.from_string("{{ [1, 2] ~ 'foo' }}")
+        assert tmpl.render() == '[1, 2]foo'
+
+    def test_compare(self):
+        tmpl = env.from_string('{{ 1 > 0 }}|{{ 1 >= 1 }}|{{ 2 < 3 }}|'
+                               '{{ 2 == 2 }}|{{ 1 <= 1 }}')
+        assert tmpl.render() == 'True|True|True|True|True'
+
+    def test_inop(self):
+        tmpl = env.from_string('{{ 1 in [1, 2, 3] }}|{{ 1 not in [1, 2, 3] }}')
+        assert tmpl.render() == 'True|False'
+
+    def test_literals(self):
+        tmpl = env.from_string('{{ [] }}|{{ {} }}|{{ () }}')
+        assert tmpl.render().lower() == '[]|{}|()'
+
+    def test_bool(self):
+        tmpl = env.from_string('{{ true and false }}|{{ false '
+                               'or true }}|{{ not false }}')
+        assert tmpl.render() == 'False|True|True'
+
+    def test_grouping(self):
+        tmpl = env.from_string('{{ (true and false) or (false and true) and not false }}')
+        assert tmpl.render() == 'False'
+
+    def test_django_attr(self):
+        tmpl = env.from_string('{{ [1, 2, 3].0 }}|{{ [[1]].0.0 }}')
+        assert tmpl.render() == '1|1'
+
+    def test_conditional_expression(self):
+        tmpl = env.from_string('''{{ 0 if true else 1 }}''')
+        assert tmpl.render() == '0'
+
+    def test_short_conditional_expression(self):
+        tmpl = env.from_string('<{{ 1 if false }}>')
+        assert tmpl.render() == '<>'
+
+        tmpl = env.from_string('<{{ (1 if false).bar }}>')
+        self.assert_raises(UndefinedError, tmpl.render)
+
+    def test_filter_priority(self):
+        tmpl = env.from_string('{{ "foo"|upper + "bar"|upper }}')
+        assert tmpl.render() == 'FOOBAR'
+
+    def test_function_calls(self):
+        tests = [
+            (True, '*foo, bar'),
+            (True, '*foo, *bar'),
+            (True, '*foo, bar=42'),
+            (True, '**foo, *bar'),
+            (True, '**foo, bar'),
+            (False, 'foo, bar'),
+            (False, 'foo, bar=42'),
+            (False, 'foo, bar=23, *args'),
+            (False, 'a, b=c, *d, **e'),
+            (False, '*foo, **bar')
+        ]
+        for should_fail, sig in tests:
+            if should_fail:
+                self.assert_raises(TemplateSyntaxError,
+                    env.from_string, '{{ foo(%s) }}' % sig)
+            else:
+                env.from_string('foo(%s)' % sig)
+
+    def test_tuple_expr(self):
+        for tmpl in [
+            '{{ () }}',
+            '{{ (1, 2) }}',
+            '{{ (1, 2,) }}',
+            '{{ 1, }}',
+            '{{ 1, 2 }}',
+            '{% for foo, bar in seq %}...{% endfor %}',
+            '{% for x in foo, bar %}...{% endfor %}',
+            '{% for x in foo, %}...{% endfor %}'
+        ]:
+            assert env.from_string(tmpl)
+
+    def test_trailing_comma(self):
+        tmpl = env.from_string('{{ (1, 2,) }}|{{ [1, 2,] }}|{{ {1: 2,} }}')
+        assert tmpl.render().lower() == '(1, 2)|[1, 2]|{1: 2}'
+
+    def test_block_end_name(self):
+        env.from_string('{% block foo %}...{% endblock foo %}')
+        self.assert_raises(TemplateSyntaxError, env.from_string,
+                           '{% block x %}{% endblock y %}')
+
+    def test_contant_casing(self):
+        for const in True, False, None:
+            tmpl = env.from_string('{{ %s }}|{{ %s }}|{{ %s }}' % (
+                str(const), str(const).lower(), str(const).upper()
+            ))
+            assert tmpl.render() == '%s|%s|' % (const, const)
+
+    def test_test_chaining(self):
+        self.assert_raises(TemplateSyntaxError, env.from_string,
+                           '{{ foo is string is sequence }}')
+        env.from_string('{{ 42 is string or 42 is number }}'
+            ).render() == 'True'
+
+    def test_string_concatenation(self):
+        tmpl = env.from_string('{{ "foo" "bar" "baz" }}')
+        assert tmpl.render() == 'foobarbaz'
+
+    def test_notin(self):
+        bar = xrange(100)
+        tmpl = env.from_string('''{{ not 42 in bar }}''')
+        assert tmpl.render(bar=bar) == unicode(not 42 in bar)
+
+    def test_implicit_subscribed_tuple(self):
+        class Foo(object):
+            def __getitem__(self, x):
+                return x
+        t = env.from_string('{{ foo[1, 2] }}')
+        assert t.render(foo=Foo()) == u'(1, 2)'
+
+    def test_raw2(self):
+        tmpl = env.from_string('{% raw %}{{ FOO }} and {% BAR %}{% endraw %}')
+        assert tmpl.render() == '{{ FOO }} and {% BAR %}'
+
+    def test_const(self):
+        tmpl = env.from_string('{{ true }}|{{ false }}|{{ none }}|'
+                               '{{ none is defined }}|{{ missing is defined }}')
+        assert tmpl.render() == 'True|False|None|True|False'
+
+    def test_neg_filter_priority(self):
+        node = env.parse('{{ -1|foo }}')
+        assert isinstance(node.body[0].nodes[0], nodes.Filter)
+        assert isinstance(node.body[0].nodes[0].node, nodes.Neg)
+
+    def test_const_assign(self):
+        constass1 = '''{% set true = 42 %}'''
+        constass2 = '''{% for none in seq %}{% endfor %}'''
+        for tmpl in constass1, constass2:
+            self.assert_raises(TemplateSyntaxError, env.from_string, tmpl)
+
+    def test_localset(self):
+        tmpl = env.from_string('''{% set foo = 0 %}\
+{% for item in [1, 2] %}{% set foo = 1 %}{% endfor %}\
+{{ foo }}''')
+        assert tmpl.render() == '0'
+
+    def test_parse_unary(self):
+        tmpl = env.from_string('{{ -foo["bar"] }}')
+        assert tmpl.render(foo={'bar': 42}) == '-42'
+        tmpl = env.from_string('{{ -foo["bar"]|abs }}')
+        assert tmpl.render(foo={'bar': 42}) == '42'
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(LexerTestCase))
+    suite.addTest(unittest.makeSuite(ParserTestCase))
+    suite.addTest(unittest.makeSuite(SyntaxTestCase))
+    return suite
diff --git a/lib/jinja2/jinja2/testsuite/loader.py b/lib/jinja2/jinja2/testsuite/loader.py
new file mode 100644
index 0000000..fb1e53d
--- /dev/null
+++ b/lib/jinja2/jinja2/testsuite/loader.py
@@ -0,0 +1,190 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.testsuite.loader
+    ~~~~~~~~~~~~~~~~~~~~~~~
+
+    Test the loaders.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import os
+import sys
+import tempfile
+import shutil
+import unittest
+
+from jinja2.testsuite import JinjaTestCase, dict_loader, \
+     package_loader, filesystem_loader, function_loader, \
+     choice_loader, prefix_loader
+
+from jinja2 import Environment, loaders
+from jinja2.loaders import split_template_path
+from jinja2.exceptions import TemplateNotFound
+
+
+class LoaderTestCase(JinjaTestCase):
+
+    def test_dict_loader(self):
+        env = Environment(loader=dict_loader)
+        tmpl = env.get_template('justdict.html')
+        assert tmpl.render().strip() == 'FOO'
+        self.assert_raises(TemplateNotFound, env.get_template, 'missing.html')
+
+    def test_package_loader(self):
+        env = Environment(loader=package_loader)
+        tmpl = env.get_template('test.html')
+        assert tmpl.render().strip() == 'BAR'
+        self.assert_raises(TemplateNotFound, env.get_template, 'missing.html')
+
+    def test_filesystem_loader(self):
+        env = Environment(loader=filesystem_loader)
+        tmpl = env.get_template('test.html')
+        assert tmpl.render().strip() == 'BAR'
+        tmpl = env.get_template('foo/test.html')
+        assert tmpl.render().strip() == 'FOO'
+        self.assert_raises(TemplateNotFound, env.get_template, 'missing.html')
+
+    def test_choice_loader(self):
+        env = Environment(loader=choice_loader)
+        tmpl = env.get_template('justdict.html')
+        assert tmpl.render().strip() == 'FOO'
+        tmpl = env.get_template('test.html')
+        assert tmpl.render().strip() == 'BAR'
+        self.assert_raises(TemplateNotFound, env.get_template, 'missing.html')
+
+    def test_function_loader(self):
+        env = Environment(loader=function_loader)
+        tmpl = env.get_template('justfunction.html')
+        assert tmpl.render().strip() == 'FOO'
+        self.assert_raises(TemplateNotFound, env.get_template, 'missing.html')
+
+    def test_prefix_loader(self):
+        env = Environment(loader=prefix_loader)
+        tmpl = env.get_template('a/test.html')
+        assert tmpl.render().strip() == 'BAR'
+        tmpl = env.get_template('b/justdict.html')
+        assert tmpl.render().strip() == 'FOO'
+        self.assert_raises(TemplateNotFound, env.get_template, 'missing')
+
+    def test_caching(self):
+        changed = False
+        class TestLoader(loaders.BaseLoader):
+            def get_source(self, environment, template):
+                return u'foo', None, lambda: not changed
+        env = Environment(loader=TestLoader(), cache_size=-1)
+        tmpl = env.get_template('template')
+        assert tmpl is env.get_template('template')
+        changed = True
+        assert tmpl is not env.get_template('template')
+        changed = False
+
+        env = Environment(loader=TestLoader(), cache_size=0)
+        assert env.get_template('template') \
+               is not env.get_template('template')
+
+        env = Environment(loader=TestLoader(), cache_size=2)
+        t1 = env.get_template('one')
+        t2 = env.get_template('two')
+        assert t2 is env.get_template('two')
+        assert t1 is env.get_template('one')
+        t3 = env.get_template('three')
+        assert 'one' in env.cache
+        assert 'two' not in env.cache
+        assert 'three' in env.cache
+
+    def test_split_template_path(self):
+        assert split_template_path('foo/bar') == ['foo', 'bar']
+        assert split_template_path('./foo/bar') == ['foo', 'bar']
+        self.assert_raises(TemplateNotFound, split_template_path, '../foo')
+
+
+class ModuleLoaderTestCase(JinjaTestCase):
+    archive = None
+
+    def compile_down(self, zip='deflated', py_compile=False):
+        super(ModuleLoaderTestCase, self).setup()
+        log = []
+        self.reg_env = Environment(loader=prefix_loader)
+        if zip is not None:
+            self.archive = tempfile.mkstemp(suffix='.zip')[1]
+        else:
+            self.archive = tempfile.mkdtemp()
+        self.reg_env.compile_templates(self.archive, zip=zip,
+                                       log_function=log.append,
+                                       py_compile=py_compile)
+        self.mod_env = Environment(loader=loaders.ModuleLoader(self.archive))
+        return ''.join(log)
+
+    def teardown(self):
+        super(ModuleLoaderTestCase, self).teardown()
+        if hasattr(self, 'mod_env'):
+            if os.path.isfile(self.archive):
+                os.remove(self.archive)
+            else:
+                shutil.rmtree(self.archive)
+            self.archive = None
+
+    def test_log(self):
+        log = self.compile_down()
+        assert 'Compiled "a/foo/test.html" as ' \
+               'tmpl_a790caf9d669e39ea4d280d597ec891c4ef0404a' in log
+        assert 'Finished compiling templates' in log
+        assert 'Could not compile "a/syntaxerror.html": ' \
+               'Encountered unknown tag \'endif\'' in log
+
+    def _test_common(self):
+        tmpl1 = self.reg_env.get_template('a/test.html')
+        tmpl2 = self.mod_env.get_template('a/test.html')
+        assert tmpl1.render() == tmpl2.render()
+
+        tmpl1 = self.reg_env.get_template('b/justdict.html')
+        tmpl2 = self.mod_env.get_template('b/justdict.html')
+        assert tmpl1.render() == tmpl2.render()
+
+    def test_deflated_zip_compile(self):
+        self.compile_down(zip='deflated')
+        self._test_common()
+
+    def test_stored_zip_compile(self):
+        self.compile_down(zip='stored')
+        self._test_common()
+
+    def test_filesystem_compile(self):
+        self.compile_down(zip=None)
+        self._test_common()
+
+    def test_weak_references(self):
+        self.compile_down()
+        tmpl = self.mod_env.get_template('a/test.html')
+        key = loaders.ModuleLoader.get_template_key('a/test.html')
+        name = self.mod_env.loader.module.__name__
+
+        assert hasattr(self.mod_env.loader.module, key)
+        assert name in sys.modules
+
+        # unset all, ensure the module is gone from sys.modules
+        self.mod_env = tmpl = None
+
+        try:
+            import gc
+            gc.collect()
+        except:
+            pass
+
+        assert name not in sys.modules
+
+    def test_byte_compilation(self):
+        log = self.compile_down(py_compile=True)
+        assert 'Byte-compiled "a/test.html"' in log
+        tmpl1 = self.mod_env.get_template('a/test.html')
+        mod = self.mod_env.loader.module. \
+            tmpl_3c4ddf650c1a73df961a6d3d2ce2752f1b8fd490
+        assert mod.__file__.endswith('.pyc')
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(LoaderTestCase))
+    suite.addTest(unittest.makeSuite(ModuleLoaderTestCase))
+    return suite
diff --git a/lib/jinja2/jinja2/testsuite/regression.py b/lib/jinja2/jinja2/testsuite/regression.py
new file mode 100644
index 0000000..4db9076
--- /dev/null
+++ b/lib/jinja2/jinja2/testsuite/regression.py
@@ -0,0 +1,255 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.testsuite.regression
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Tests corner cases and bugs.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import unittest
+
+from jinja2.testsuite import JinjaTestCase
+
+from jinja2 import Template, Environment, DictLoader, TemplateSyntaxError, \
+     TemplateNotFound, PrefixLoader
+
+env = Environment()
+
+
+class CornerTestCase(JinjaTestCase):
+
+    def test_assigned_scoping(self):
+        t = env.from_string('''
+        {%- for item in (1, 2, 3, 4) -%}
+            [{{ item }}]
+        {%- endfor %}
+        {{- item -}}
+        ''')
+        assert t.render(item=42) == '[1][2][3][4]42'
+
+        t = env.from_string('''
+        {%- for item in (1, 2, 3, 4) -%}
+            [{{ item }}]
+        {%- endfor %}
+        {%- set item = 42 %}
+        {{- item -}}
+        ''')
+        assert t.render() == '[1][2][3][4]42'
+
+        t = env.from_string('''
+        {%- set item = 42 %}
+        {%- for item in (1, 2, 3, 4) -%}
+            [{{ item }}]
+        {%- endfor %}
+        {{- item -}}
+        ''')
+        assert t.render() == '[1][2][3][4]42'
+
+    def test_closure_scoping(self):
+        t = env.from_string('''
+        {%- set wrapper = "<FOO>" %}
+        {%- for item in (1, 2, 3, 4) %}
+            {%- macro wrapper() %}[{{ item }}]{% endmacro %}
+            {{- wrapper() }}
+        {%- endfor %}
+        {{- wrapper -}}
+        ''')
+        assert t.render() == '[1][2][3][4]<FOO>'
+
+        t = env.from_string('''
+        {%- for item in (1, 2, 3, 4) %}
+            {%- macro wrapper() %}[{{ item }}]{% endmacro %}
+            {{- wrapper() }}
+        {%- endfor %}
+        {%- set wrapper = "<FOO>" %}
+        {{- wrapper -}}
+        ''')
+        assert t.render() == '[1][2][3][4]<FOO>'
+
+        t = env.from_string('''
+        {%- for item in (1, 2, 3, 4) %}
+            {%- macro wrapper() %}[{{ item }}]{% endmacro %}
+            {{- wrapper() }}
+        {%- endfor %}
+        {{- wrapper -}}
+        ''')
+        assert t.render(wrapper=23) == '[1][2][3][4]23'
+
+
+class BugTestCase(JinjaTestCase):
+
+    def test_keyword_folding(self):
+        env = Environment()
+        env.filters['testing'] = lambda value, some: value + some
+        assert env.from_string("{{ 'test'|testing(some='stuff') }}") \
+               .render() == 'teststuff'
+
+    def test_extends_output_bugs(self):
+        env = Environment(loader=DictLoader({
+            'parent.html': '(({% block title %}{% endblock %}))'
+        }))
+
+        t = env.from_string('{% if expr %}{% extends "parent.html" %}{% endif %}'
+                            '[[{% block title %}title{% endblock %}]]'
+                            '{% for item in [1, 2, 3] %}({{ item }}){% endfor %}')
+        assert t.render(expr=False) == '[[title]](1)(2)(3)'
+        assert t.render(expr=True) == '((title))'
+
+    def test_urlize_filter_escaping(self):
+        tmpl = env.from_string('{{ "http://www.example.org/<foo"|urlize }}')
+        assert tmpl.render() == '<a href="http://www.example.org/&lt;foo">http://www.example.org/&lt;foo</a>'
+
+    def test_loop_call_loop(self):
+        tmpl = env.from_string('''
+
+        {% macro test() %}
+            {{ caller() }}
+        {% endmacro %}
+
+        {% for num1 in range(5) %}
+            {% call test() %}
+                {% for num2 in range(10) %}
+                    {{ loop.index }}
+                {% endfor %}
+            {% endcall %}
+        {% endfor %}
+
+        ''')
+
+        assert tmpl.render().split() == map(unicode, range(1, 11)) * 5
+
+    def test_weird_inline_comment(self):
+        env = Environment(line_statement_prefix='%')
+        self.assert_raises(TemplateSyntaxError, env.from_string,
+                           '% for item in seq {# missing #}\n...% endfor')
+
+    def test_old_macro_loop_scoping_bug(self):
+        tmpl = env.from_string('{% for i in (1, 2) %}{{ i }}{% endfor %}'
+                               '{% macro i() %}3{% endmacro %}{{ i() }}')
+        assert tmpl.render() == '123'
+
+    def test_partial_conditional_assignments(self):
+        tmpl = env.from_string('{% if b %}{% set a = 42 %}{% endif %}{{ a }}')
+        assert tmpl.render(a=23) == '23'
+        assert tmpl.render(b=True) == '42'
+
+    def test_stacked_locals_scoping_bug(self):
+        env = Environment(line_statement_prefix='#')
+        t = env.from_string('''\
+# for j in [1, 2]:
+#   set x = 1
+#   for i in [1, 2]:
+#     print x
+#     if i % 2 == 0:
+#       set x = x + 1
+#     endif
+#   endfor
+# endfor
+# if a
+#   print 'A'
+# elif b
+#   print 'B'
+# elif c == d
+#   print 'C'
+# else
+#   print 'D'
+# endif
+    ''')
+        assert t.render(a=0, b=False, c=42, d=42.0) == '1111C'
+
+    def test_stacked_locals_scoping_bug_twoframe(self):
+        t = Template('''
+            {% set x = 1 %}
+            {% for item in foo %}
+                {% if item == 1 %}
+                    {% set x = 2 %}
+                {% endif %}
+            {% endfor %}
+            {{ x }}
+        ''')
+        rv = t.render(foo=[1]).strip()
+        assert rv == u'1'
+
+    def test_call_with_args(self):
+        t = Template("""{% macro dump_users(users) -%}
+        <ul>
+          {%- for user in users -%}
+            <li><p>{{ user.username|e }}</p>{{ caller(user) }}</li>
+          {%- endfor -%}
+          </ul>
+        {%- endmacro -%}
+
+        {% call(user) dump_users(list_of_user) -%}
+          <dl>
+            <dl>Realname</dl>
+            <dd>{{ user.realname|e }}</dd>
+            <dl>Description</dl>
+            <dd>{{ user.description }}</dd>
+          </dl>
+        {% endcall %}""")
+
+        assert [x.strip() for x in t.render(list_of_user=[{
+            'username':'apo',
+            'realname':'something else',
+            'description':'test'
+        }]).splitlines()] == [
+            u'<ul><li><p>apo</p><dl>',
+            u'<dl>Realname</dl>',
+            u'<dd>something else</dd>',
+            u'<dl>Description</dl>',
+            u'<dd>test</dd>',
+            u'</dl>',
+            u'</li></ul>'
+        ]
+
+    def test_empty_if_condition_fails(self):
+        self.assert_raises(TemplateSyntaxError, Template, '{% if %}....{% endif %}')
+        self.assert_raises(TemplateSyntaxError, Template, '{% if foo %}...{% elif %}...{% endif %}')
+        self.assert_raises(TemplateSyntaxError, Template, '{% for x in %}..{% endfor %}')
+
+    def test_recursive_loop_bug(self):
+        tpl1 = Template("""
+        {% for p in foo recursive%}
+            {{p.bar}}
+            {% for f in p.fields recursive%}
+                {{f.baz}}
+                {{p.bar}}
+                {% if f.rec %}
+                    {{ loop(f.sub) }}
+                {% endif %}
+            {% endfor %}
+        {% endfor %}
+        """)
+
+        tpl2 = Template("""
+        {% for p in foo%}
+            {{p.bar}}
+            {% for f in p.fields recursive%}
+                {{f.baz}}
+                {{p.bar}}
+                {% if f.rec %}
+                    {{ loop(f.sub) }}
+                {% endif %}
+            {% endfor %}
+        {% endfor %}
+        """)
+
+    def test_correct_prefix_loader_name(self):
+        env = Environment(loader=PrefixLoader({
+            'foo':  DictLoader({})
+        }))
+        try:
+            env.get_template('foo/bar.html')
+        except TemplateNotFound, e:
+            assert e.name == 'foo/bar.html'
+        else:
+            assert False, 'expected error here'
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(CornerTestCase))
+    suite.addTest(unittest.makeSuite(BugTestCase))
+    return suite
diff --git a/lib/google-api-python-client/functional_tests/__init__.py b/lib/jinja2/jinja2/testsuite/res/__init__.py
similarity index 100%
rename from lib/google-api-python-client/functional_tests/__init__.py
rename to lib/jinja2/jinja2/testsuite/res/__init__.py
diff --git a/lib/jinja2/jinja2/testsuite/res/templates/broken.html b/lib/jinja2/jinja2/testsuite/res/templates/broken.html
new file mode 100644
index 0000000..77669fa
--- /dev/null
+++ b/lib/jinja2/jinja2/testsuite/res/templates/broken.html
@@ -0,0 +1,3 @@
+Before
+{{ fail() }}
+After
diff --git a/lib/jinja2/jinja2/testsuite/res/templates/foo/test.html b/lib/jinja2/jinja2/testsuite/res/templates/foo/test.html
new file mode 100644
index 0000000..b7d6715
--- /dev/null
+++ b/lib/jinja2/jinja2/testsuite/res/templates/foo/test.html
@@ -0,0 +1 @@
+FOO
diff --git a/lib/jinja2/jinja2/testsuite/res/templates/syntaxerror.html b/lib/jinja2/jinja2/testsuite/res/templates/syntaxerror.html
new file mode 100644
index 0000000..f21b817
--- /dev/null
+++ b/lib/jinja2/jinja2/testsuite/res/templates/syntaxerror.html
@@ -0,0 +1,4 @@
+Foo
+{% for item in broken %}
+  ...
+{% endif %}
diff --git a/lib/jinja2/jinja2/testsuite/res/templates/test.html b/lib/jinja2/jinja2/testsuite/res/templates/test.html
new file mode 100644
index 0000000..ba578e4
--- /dev/null
+++ b/lib/jinja2/jinja2/testsuite/res/templates/test.html
@@ -0,0 +1 @@
+BAR
diff --git a/lib/jinja2/jinja2/testsuite/security.py b/lib/jinja2/jinja2/testsuite/security.py
new file mode 100644
index 0000000..4518eac
--- /dev/null
+++ b/lib/jinja2/jinja2/testsuite/security.py
@@ -0,0 +1,165 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.testsuite.security
+    ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Checks the sandbox and other security features.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import unittest
+
+from jinja2.testsuite import JinjaTestCase
+
+from jinja2 import Environment
+from jinja2.sandbox import SandboxedEnvironment, \
+     ImmutableSandboxedEnvironment, unsafe
+from jinja2 import Markup, escape
+from jinja2.exceptions import SecurityError, TemplateSyntaxError, \
+     TemplateRuntimeError
+
+
+class PrivateStuff(object):
+
+    def bar(self):
+        return 23
+
+    @unsafe
+    def foo(self):
+        return 42
+
+    def __repr__(self):
+        return 'PrivateStuff'
+
+
+class PublicStuff(object):
+    bar = lambda self: 23
+    _foo = lambda self: 42
+
+    def __repr__(self):
+        return 'PublicStuff'
+
+
+class SandboxTestCase(JinjaTestCase):
+
+    def test_unsafe(self):
+        env = SandboxedEnvironment()
+        self.assert_raises(SecurityError, env.from_string("{{ foo.foo() }}").render,
+                           foo=PrivateStuff())
+        self.assert_equal(env.from_string("{{ foo.bar() }}").render(foo=PrivateStuff()), '23')
+
+        self.assert_raises(SecurityError, env.from_string("{{ foo._foo() }}").render,
+                           foo=PublicStuff())
+        self.assert_equal(env.from_string("{{ foo.bar() }}").render(foo=PublicStuff()), '23')
+        self.assert_equal(env.from_string("{{ foo.__class__ }}").render(foo=42), '')
+        self.assert_equal(env.from_string("{{ foo.func_code }}").render(foo=lambda:None), '')
+        # security error comes from __class__ already.
+        self.assert_raises(SecurityError, env.from_string(
+            "{{ foo.__class__.__subclasses__() }}").render, foo=42)
+
+    def test_immutable_environment(self):
+        env = ImmutableSandboxedEnvironment()
+        self.assert_raises(SecurityError, env.from_string(
+            '{{ [].append(23) }}').render)
+        self.assert_raises(SecurityError, env.from_string(
+            '{{ {1:2}.clear() }}').render)
+
+    def test_restricted(self):
+        env = SandboxedEnvironment()
+        self.assert_raises(TemplateSyntaxError, env.from_string,
+                      "{% for item.attribute in seq %}...{% endfor %}")
+        self.assert_raises(TemplateSyntaxError, env.from_string,
+                      "{% for foo, bar.baz in seq %}...{% endfor %}")
+
+    def test_markup_operations(self):
+        # adding two strings should escape the unsafe one
+        unsafe = '<script type="application/x-some-script">alert("foo");</script>'
+        safe = Markup('<em>username</em>')
+        assert unsafe + safe == unicode(escape(unsafe)) + unicode(safe)
+
+        # string interpolations are safe to use too
+        assert Markup('<em>%s</em>') % '<bad user>' == \
+               '<em>&lt;bad user&gt;</em>'
+        assert Markup('<em>%(username)s</em>') % {
+            'username': '<bad user>'
+        } == '<em>&lt;bad user&gt;</em>'
+
+        # an escaped object is markup too
+        assert type(Markup('foo') + 'bar') is Markup
+
+        # and it implements __html__ by returning itself
+        x = Markup("foo")
+        assert x.__html__() is x
+
+        # it also knows how to treat __html__ objects
+        class Foo(object):
+            def __html__(self):
+                return '<em>awesome</em>'
+            def __unicode__(self):
+                return 'awesome'
+        assert Markup(Foo()) == '<em>awesome</em>'
+        assert Markup('<strong>%s</strong>') % Foo() == \
+               '<strong><em>awesome</em></strong>'
+
+        # escaping and unescaping
+        assert escape('"<>&\'') == '&#34;&lt;&gt;&amp;&#39;'
+        assert Markup("<em>Foo &amp; Bar</em>").striptags() == "Foo & Bar"
+        assert Markup("&lt;test&gt;").unescape() == "<test>"
+
+    def test_template_data(self):
+        env = Environment(autoescape=True)
+        t = env.from_string('{% macro say_hello(name) %}'
+                            '<p>Hello {{ name }}!</p>{% endmacro %}'
+                            '{{ say_hello("<blink>foo</blink>") }}')
+        escaped_out = '<p>Hello &lt;blink&gt;foo&lt;/blink&gt;!</p>'
+        assert t.render() == escaped_out
+        assert unicode(t.module) == escaped_out
+        assert escape(t.module) == escaped_out
+        assert t.module.say_hello('<blink>foo</blink>') == escaped_out
+        assert escape(t.module.say_hello('<blink>foo</blink>')) == escaped_out
+
+    def test_attr_filter(self):
+        env = SandboxedEnvironment()
+        tmpl = env.from_string('{{ cls|attr("__subclasses__")() }}')
+        self.assert_raises(SecurityError, tmpl.render, cls=int)
+
+    def test_binary_operator_intercepting(self):
+        def disable_op(left, right):
+            raise TemplateRuntimeError('that operator so does not work')
+        for expr, ctx, rv in ('1 + 2', {}, '3'), ('a + 2', {'a': 2}, '4'):
+            env = SandboxedEnvironment()
+            env.binop_table['+'] = disable_op
+            t = env.from_string('{{ %s }}' % expr)
+            assert t.render(ctx) == rv
+            env.intercepted_binops = frozenset(['+'])
+            t = env.from_string('{{ %s }}' % expr)
+            try:
+                t.render(ctx)
+            except TemplateRuntimeError, e:
+                pass
+            else:
+                self.fail('expected runtime error')
+
+    def test_unary_operator_intercepting(self):
+        def disable_op(arg):
+            raise TemplateRuntimeError('that operator so does not work')
+        for expr, ctx, rv in ('-1', {}, '-1'), ('-a', {'a': 2}, '-2'):
+            env = SandboxedEnvironment()
+            env.unop_table['-'] = disable_op
+            t = env.from_string('{{ %s }}' % expr)
+            assert t.render(ctx) == rv
+            env.intercepted_unops = frozenset(['-'])
+            t = env.from_string('{{ %s }}' % expr)
+            try:
+                t.render(ctx)
+            except TemplateRuntimeError, e:
+                pass
+            else:
+                self.fail('expected runtime error')
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(SandboxTestCase))
+    return suite
diff --git a/lib/jinja2/jinja2/testsuite/tests.py b/lib/jinja2/jinja2/testsuite/tests.py
new file mode 100644
index 0000000..3ece7a8
--- /dev/null
+++ b/lib/jinja2/jinja2/testsuite/tests.py
@@ -0,0 +1,93 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.testsuite.tests
+    ~~~~~~~~~~~~~~~~~~~~~~
+
+    Who tests the tests?
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import unittest
+from jinja2.testsuite import JinjaTestCase
+
+from jinja2 import Markup, Environment
+
+env = Environment()
+
+
+class TestsTestCase(JinjaTestCase):
+
+    def test_defined(self):
+        tmpl = env.from_string('{{ missing is defined }}|{{ true is defined }}')
+        assert tmpl.render() == 'False|True'
+
+    def test_even(self):
+        tmpl = env.from_string('''{{ 1 is even }}|{{ 2 is even }}''')
+        assert tmpl.render() == 'False|True'
+
+    def test_odd(self):
+        tmpl = env.from_string('''{{ 1 is odd }}|{{ 2 is odd }}''')
+        assert tmpl.render() == 'True|False'
+
+    def test_lower(self):
+        tmpl = env.from_string('''{{ "foo" is lower }}|{{ "FOO" is lower }}''')
+        assert tmpl.render() == 'True|False'
+
+    def test_typechecks(self):
+        tmpl = env.from_string('''
+            {{ 42 is undefined }}
+            {{ 42 is defined }}
+            {{ 42 is none }}
+            {{ none is none }}
+            {{ 42 is number }}
+            {{ 42 is string }}
+            {{ "foo" is string }}
+            {{ "foo" is sequence }}
+            {{ [1] is sequence }}
+            {{ range is callable }}
+            {{ 42 is callable }}
+            {{ range(5) is iterable }}
+            {{ {} is mapping }}
+            {{ mydict is mapping }}
+            {{ [] is mapping }}
+        ''')
+        class MyDict(dict):
+            pass
+        assert tmpl.render(mydict=MyDict()).split() == [
+            'False', 'True', 'False', 'True', 'True', 'False',
+            'True', 'True', 'True', 'True', 'False', 'True',
+            'True', 'True', 'False'
+        ]
+
+    def test_sequence(self):
+        tmpl = env.from_string(
+            '{{ [1, 2, 3] is sequence }}|'
+            '{{ "foo" is sequence }}|'
+            '{{ 42 is sequence }}'
+        )
+        assert tmpl.render() == 'True|True|False'
+
+    def test_upper(self):
+        tmpl = env.from_string('{{ "FOO" is upper }}|{{ "foo" is upper }}')
+        assert tmpl.render() == 'True|False'
+
+    def test_sameas(self):
+        tmpl = env.from_string('{{ foo is sameas false }}|'
+                               '{{ 0 is sameas false }}')
+        assert tmpl.render(foo=False) == 'True|False'
+
+    def test_no_paren_for_arg1(self):
+        tmpl = env.from_string('{{ foo is sameas none }}')
+        assert tmpl.render(foo=None) == 'True'
+
+    def test_escaped(self):
+        env = Environment(autoescape=True)
+        tmpl = env.from_string('{{ x is escaped }}|{{ y is escaped }}')
+        assert tmpl.render(x='foo', y=Markup('foo')) == 'False|True'
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestsTestCase))
+    return suite
diff --git a/lib/jinja2/jinja2/testsuite/utils.py b/lib/jinja2/jinja2/testsuite/utils.py
new file mode 100644
index 0000000..be2e902
--- /dev/null
+++ b/lib/jinja2/jinja2/testsuite/utils.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.testsuite.utils
+    ~~~~~~~~~~~~~~~~~~~~~~
+
+    Tests utilities jinja uses.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import gc
+import unittest
+
+import pickle
+
+from jinja2.testsuite import JinjaTestCase
+
+from jinja2.utils import LRUCache, escape, object_type_repr
+
+
+class LRUCacheTestCase(JinjaTestCase):
+
+    def test_simple(self):
+        d = LRUCache(3)
+        d["a"] = 1
+        d["b"] = 2
+        d["c"] = 3
+        d["a"]
+        d["d"] = 4
+        assert len(d) == 3
+        assert 'a' in d and 'c' in d and 'd' in d and 'b' not in d
+
+    def test_pickleable(self):
+        cache = LRUCache(2)
+        cache["foo"] = 42
+        cache["bar"] = 23
+        cache["foo"]
+
+        for protocol in range(3):
+            copy = pickle.loads(pickle.dumps(cache, protocol))
+            assert copy.capacity == cache.capacity
+            assert copy._mapping == cache._mapping
+            assert copy._queue == cache._queue
+
+
+class HelpersTestCase(JinjaTestCase):
+
+    def test_object_type_repr(self):
+        class X(object):
+            pass
+        self.assert_equal(object_type_repr(42), 'int object')
+        self.assert_equal(object_type_repr([]), 'list object')
+        self.assert_equal(object_type_repr(X()),
+                         'jinja2.testsuite.utils.X object')
+        self.assert_equal(object_type_repr(None), 'None')
+        self.assert_equal(object_type_repr(Ellipsis), 'Ellipsis')
+
+
+class MarkupLeakTestCase(JinjaTestCase):
+
+    def test_markup_leaks(self):
+        counts = set()
+        for count in xrange(20):
+            for item in xrange(1000):
+                escape("foo")
+                escape("<foo>")
+                escape(u"foo")
+                escape(u"<foo>")
+            counts.add(len(gc.get_objects()))
+        assert len(counts) == 1, 'ouch, c extension seems to leak objects'
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(LRUCacheTestCase))
+    suite.addTest(unittest.makeSuite(HelpersTestCase))
+
+    # this test only tests the c extension
+    if not hasattr(escape, 'func_code'):
+        suite.addTest(unittest.makeSuite(MarkupLeakTestCase))
+
+    return suite
diff --git a/lib/jinja2/jinja2/utils.py b/lib/jinja2/jinja2/utils.py
new file mode 100644
index 0000000..49e9e9a
--- /dev/null
+++ b/lib/jinja2/jinja2/utils.py
@@ -0,0 +1,601 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.utils
+    ~~~~~~~~~~~~
+
+    Utility functions.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import re
+import sys
+import errno
+try:
+    from thread import allocate_lock
+except ImportError:
+    from dummy_thread import allocate_lock
+from collections import deque
+from itertools import imap
+
+
+_word_split_re = re.compile(r'(\s+)')
+_punctuation_re = re.compile(
+    '^(?P<lead>(?:%s)*)(?P<middle>.*?)(?P<trail>(?:%s)*)$' % (
+        '|'.join(imap(re.escape, ('(', '<', '&lt;'))),
+        '|'.join(imap(re.escape, ('.', ',', ')', '>', '\n', '&gt;')))
+    )
+)
+_simple_email_re = re.compile(r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$')
+_striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
+_entity_re = re.compile(r'&([^;]+);')
+_letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
+_digits = '0123456789'
+
+# special singleton representing missing values for the runtime
+missing = type('MissingType', (), {'__repr__': lambda x: 'missing'})()
+
+# internal code
+internal_code = set()
+
+
+# concatenate a list of strings and convert them to unicode.
+# unfortunately there is a bug in python 2.4 and lower that causes
+# unicode.join trash the traceback.
+_concat = u''.join
+try:
+    def _test_gen_bug():
+        raise TypeError(_test_gen_bug)
+        yield None
+    _concat(_test_gen_bug())
+except TypeError, _error:
+    if not _error.args or _error.args[0] is not _test_gen_bug:
+        def concat(gen):
+            try:
+                return _concat(list(gen))
+            except Exception:
+                # this hack is needed so that the current frame
+                # does not show up in the traceback.
+                exc_type, exc_value, tb = sys.exc_info()
+                raise exc_type, exc_value, tb.tb_next
+    else:
+        concat = _concat
+    del _test_gen_bug, _error
+
+
+# for python 2.x we create outselves a next() function that does the
+# basics without exception catching.
+try:
+    next = next
+except NameError:
+    def next(x):
+        return x.next()
+
+
+# if this python version is unable to deal with unicode filenames
+# when passed to encode we let this function encode it properly.
+# This is used in a couple of places.  As far as Jinja is concerned
+# filenames are unicode *or* bytestrings in 2.x and unicode only in
+# 3.x because compile cannot handle bytes
+if sys.version_info < (3, 0):
+    def _encode_filename(filename):
+        if isinstance(filename, unicode):
+            return filename.encode('utf-8')
+        return filename
+else:
+    def _encode_filename(filename):
+        assert filename is None or isinstance(filename, str), \
+            'filenames must be strings'
+        return filename
+
+from keyword import iskeyword as is_python_keyword
+
+
+# common types.  These do exist in the special types module too which however
+# does not exist in IronPython out of the box.  Also that way we don't have
+# to deal with implementation specific stuff here
+class _C(object):
+    def method(self): pass
+def _func():
+    yield None
+FunctionType = type(_func)
+GeneratorType = type(_func())
+MethodType = type(_C.method)
+CodeType = type(_C.method.func_code)
+try:
+    raise TypeError()
+except TypeError:
+    _tb = sys.exc_info()[2]
+    TracebackType = type(_tb)
+    FrameType = type(_tb.tb_frame)
+del _C, _tb, _func
+
+
+def contextfunction(f):
+    """This decorator can be used to mark a function or method context callable.
+    A context callable is passed the active :class:`Context` as first argument when
+    called from the template.  This is useful if a function wants to get access
+    to the context or functions provided on the context object.  For example
+    a function that returns a sorted list of template variables the current
+    template exports could look like this::
+
+        @contextfunction
+        def get_exported_names(context):
+            return sorted(context.exported_vars)
+    """
+    f.contextfunction = True
+    return f
+
+
+def evalcontextfunction(f):
+    """This decoraotr can be used to mark a function or method as an eval
+    context callable.  This is similar to the :func:`contextfunction`
+    but instead of passing the context, an evaluation context object is
+    passed.  For more information about the eval context, see
+    :ref:`eval-context`.
+
+    .. versionadded:: 2.4
+    """
+    f.evalcontextfunction = True
+    return f
+
+
+def environmentfunction(f):
+    """This decorator can be used to mark a function or method as environment
+    callable.  This decorator works exactly like the :func:`contextfunction`
+    decorator just that the first argument is the active :class:`Environment`
+    and not context.
+    """
+    f.environmentfunction = True
+    return f
+
+
+def internalcode(f):
+    """Marks the function as internally used"""
+    internal_code.add(f.func_code)
+    return f
+
+
+def is_undefined(obj):
+    """Check if the object passed is undefined.  This does nothing more than
+    performing an instance check against :class:`Undefined` but looks nicer.
+    This can be used for custom filters or tests that want to react to
+    undefined variables.  For example a custom default filter can look like
+    this::
+
+        def default(var, default=''):
+            if is_undefined(var):
+                return default
+            return var
+    """
+    from jinja2.runtime import Undefined
+    return isinstance(obj, Undefined)
+
+
+def consume(iterable):
+    """Consumes an iterable without doing anything with it."""
+    for event in iterable:
+        pass
+
+
+def clear_caches():
+    """Jinja2 keeps internal caches for environments and lexers.  These are
+    used so that Jinja2 doesn't have to recreate environments and lexers all
+    the time.  Normally you don't have to care about that but if you are
+    messuring memory consumption you may want to clean the caches.
+    """
+    from jinja2.environment import _spontaneous_environments
+    from jinja2.lexer import _lexer_cache
+    _spontaneous_environments.clear()
+    _lexer_cache.clear()
+
+
+def import_string(import_name, silent=False):
+    """Imports an object based on a string.  This use useful if you want to
+    use import paths as endpoints or something similar.  An import path can
+    be specified either in dotted notation (``xml.sax.saxutils.escape``)
+    or with a colon as object delimiter (``xml.sax.saxutils:escape``).
+
+    If the `silent` is True the return value will be `None` if the import
+    fails.
+
+    :return: imported object
+    """
+    try:
+        if ':' in import_name:
+            module, obj = import_name.split(':', 1)
+        elif '.' in import_name:
+            items = import_name.split('.')
+            module = '.'.join(items[:-1])
+            obj = items[-1]
+        else:
+            return __import__(import_name)
+        return getattr(__import__(module, None, None, [obj]), obj)
+    except (ImportError, AttributeError):
+        if not silent:
+            raise
+
+
+def open_if_exists(filename, mode='rb'):
+    """Returns a file descriptor for the filename if that file exists,
+    otherwise `None`.
+    """
+    try:
+        return open(filename, mode)
+    except IOError, e:
+        if e.errno not in (errno.ENOENT, errno.EISDIR):
+            raise
+
+
+def object_type_repr(obj):
+    """Returns the name of the object's type.  For some recognized
+    singletons the name of the object is returned instead. (For
+    example for `None` and `Ellipsis`).
+    """
+    if obj is None:
+        return 'None'
+    elif obj is Ellipsis:
+        return 'Ellipsis'
+    # __builtin__ in 2.x, builtins in 3.x
+    if obj.__class__.__module__ in ('__builtin__', 'builtins'):
+        name = obj.__class__.__name__
+    else:
+        name = obj.__class__.__module__ + '.' + obj.__class__.__name__
+    return '%s object' % name
+
+
+def pformat(obj, verbose=False):
+    """Prettyprint an object.  Either use the `pretty` library or the
+    builtin `pprint`.
+    """
+    try:
+        from pretty import pretty
+        return pretty(obj, verbose=verbose)
+    except ImportError:
+        from pprint import pformat
+        return pformat(obj)
+
+
+def urlize(text, trim_url_limit=None, nofollow=False):
+    """Converts any URLs in text into clickable links. Works on http://,
+    https:// and www. links. Links can have trailing punctuation (periods,
+    commas, close-parens) and leading punctuation (opening parens) and
+    it'll still do the right thing.
+
+    If trim_url_limit is not None, the URLs in link text will be limited
+    to trim_url_limit characters.
+
+    If nofollow is True, the URLs in link text will get a rel="nofollow"
+    attribute.
+    """
+    trim_url = lambda x, limit=trim_url_limit: limit is not None \
+                         and (x[:limit] + (len(x) >=limit and '...'
+                         or '')) or x
+    words = _word_split_re.split(unicode(escape(text)))
+    nofollow_attr = nofollow and ' rel="nofollow"' or ''
+    for i, word in enumerate(words):
+        match = _punctuation_re.match(word)
+        if match:
+            lead, middle, trail = match.groups()
+            if middle.startswith('www.') or (
+                '@' not in middle and
+                not middle.startswith('http://') and
+                len(middle) > 0 and
+                middle[0] in _letters + _digits and (
+                    middle.endswith('.org') or
+                    middle.endswith('.net') or
+                    middle.endswith('.com')
+                )):
+                middle = '<a href="http://%s"%s>%s</a>' % (middle,
+                    nofollow_attr, trim_url(middle))
+            if middle.startswith('http://') or \
+               middle.startswith('https://'):
+                middle = '<a href="%s"%s>%s</a>' % (middle,
+                    nofollow_attr, trim_url(middle))
+            if '@' in middle and not middle.startswith('www.') and \
+               not ':' in middle and _simple_email_re.match(middle):
+                middle = '<a href="mailto:%s">%s</a>' % (middle, middle)
+            if lead + middle + trail != word:
+                words[i] = lead + middle + trail
+    return u''.join(words)
+
+
+def generate_lorem_ipsum(n=5, html=True, min=20, max=100):
+    """Generate some lorem impsum for the template."""
+    from jinja2.constants import LOREM_IPSUM_WORDS
+    from random import choice, randrange
+    words = LOREM_IPSUM_WORDS.split()
+    result = []
+
+    for _ in xrange(n):
+        next_capitalized = True
+        last_comma = last_fullstop = 0
+        word = None
+        last = None
+        p = []
+
+        # each paragraph contains out of 20 to 100 words.
+        for idx, _ in enumerate(xrange(randrange(min, max))):
+            while True:
+                word = choice(words)
+                if word != last:
+                    last = word
+                    break
+            if next_capitalized:
+                word = word.capitalize()
+                next_capitalized = False
+            # add commas
+            if idx - randrange(3, 8) > last_comma:
+                last_comma = idx
+                last_fullstop += 2
+                word += ','
+            # add end of sentences
+            if idx - randrange(10, 20) > last_fullstop:
+                last_comma = last_fullstop = idx
+                word += '.'
+                next_capitalized = True
+            p.append(word)
+
+        # ensure that the paragraph ends with a dot.
+        p = u' '.join(p)
+        if p.endswith(','):
+            p = p[:-1] + '.'
+        elif not p.endswith('.'):
+            p += '.'
+        result.append(p)
+
+    if not html:
+        return u'\n\n'.join(result)
+    return Markup(u'\n'.join(u'<p>%s</p>' % escape(x) for x in result))
+
+
+class LRUCache(object):
+    """A simple LRU Cache implementation."""
+
+    # this is fast for small capacities (something below 1000) but doesn't
+    # scale.  But as long as it's only used as storage for templates this
+    # won't do any harm.
+
+    def __init__(self, capacity):
+        self.capacity = capacity
+        self._mapping = {}
+        self._queue = deque()
+        self._postinit()
+
+    def _postinit(self):
+        # alias all queue methods for faster lookup
+        self._popleft = self._queue.popleft
+        self._pop = self._queue.pop
+        if hasattr(self._queue, 'remove'):
+            self._remove = self._queue.remove
+        self._wlock = allocate_lock()
+        self._append = self._queue.append
+
+    def _remove(self, obj):
+        """Python 2.4 compatibility."""
+        for idx, item in enumerate(self._queue):
+            if item == obj:
+                del self._queue[idx]
+                break
+
+    def __getstate__(self):
+        return {
+            'capacity':     self.capacity,
+            '_mapping':     self._mapping,
+            '_queue':       self._queue
+        }
+
+    def __setstate__(self, d):
+        self.__dict__.update(d)
+        self._postinit()
+
+    def __getnewargs__(self):
+        return (self.capacity,)
+
+    def copy(self):
+        """Return an shallow copy of the instance."""
+        rv = self.__class__(self.capacity)
+        rv._mapping.update(self._mapping)
+        rv._queue = deque(self._queue)
+        return rv
+
+    def get(self, key, default=None):
+        """Return an item from the cache dict or `default`"""
+        try:
+            return self[key]
+        except KeyError:
+            return default
+
+    def setdefault(self, key, default=None):
+        """Set `default` if the key is not in the cache otherwise
+        leave unchanged. Return the value of this key.
+        """
+        try:
+            return self[key]
+        except KeyError:
+            self[key] = default
+            return default
+
+    def clear(self):
+        """Clear the cache."""
+        self._wlock.acquire()
+        try:
+            self._mapping.clear()
+            self._queue.clear()
+        finally:
+            self._wlock.release()
+
+    def __contains__(self, key):
+        """Check if a key exists in this cache."""
+        return key in self._mapping
+
+    def __len__(self):
+        """Return the current size of the cache."""
+        return len(self._mapping)
+
+    def __repr__(self):
+        return '<%s %r>' % (
+            self.__class__.__name__,
+            self._mapping
+        )
+
+    def __getitem__(self, key):
+        """Get an item from the cache. Moves the item up so that it has the
+        highest priority then.
+
+        Raise an `KeyError` if it does not exist.
+        """
+        rv = self._mapping[key]
+        if self._queue[-1] != key:
+            try:
+                self._remove(key)
+            except ValueError:
+                # if something removed the key from the container
+                # when we read, ignore the ValueError that we would
+                # get otherwise.
+                pass
+            self._append(key)
+        return rv
+
+    def __setitem__(self, key, value):
+        """Sets the value for an item. Moves the item up so that it
+        has the highest priority then.
+        """
+        self._wlock.acquire()
+        try:
+            if key in self._mapping:
+                try:
+                    self._remove(key)
+                except ValueError:
+                    # __getitem__ is not locked, it might happen
+                    pass
+            elif len(self._mapping) == self.capacity:
+                del self._mapping[self._popleft()]
+            self._append(key)
+            self._mapping[key] = value
+        finally:
+            self._wlock.release()
+
+    def __delitem__(self, key):
+        """Remove an item from the cache dict.
+        Raise an `KeyError` if it does not exist.
+        """
+        self._wlock.acquire()
+        try:
+            del self._mapping[key]
+            try:
+                self._remove(key)
+            except ValueError:
+                # __getitem__ is not locked, it might happen
+                pass
+        finally:
+            self._wlock.release()
+
+    def items(self):
+        """Return a list of items."""
+        result = [(key, self._mapping[key]) for key in list(self._queue)]
+        result.reverse()
+        return result
+
+    def iteritems(self):
+        """Iterate over all items."""
+        return iter(self.items())
+
+    def values(self):
+        """Return a list of all values."""
+        return [x[1] for x in self.items()]
+
+    def itervalue(self):
+        """Iterate over all values."""
+        return iter(self.values())
+
+    def keys(self):
+        """Return a list of all keys ordered by most recent usage."""
+        return list(self)
+
+    def iterkeys(self):
+        """Iterate over all keys in the cache dict, ordered by
+        the most recent usage.
+        """
+        return reversed(tuple(self._queue))
+
+    __iter__ = iterkeys
+
+    def __reversed__(self):
+        """Iterate over the values in the cache dict, oldest items
+        coming first.
+        """
+        return iter(tuple(self._queue))
+
+    __copy__ = copy
+
+
+# register the LRU cache as mutable mapping if possible
+try:
+    from collections import MutableMapping
+    MutableMapping.register(LRUCache)
+except ImportError:
+    pass
+
+
+class Cycler(object):
+    """A cycle helper for templates."""
+
+    def __init__(self, *items):
+        if not items:
+            raise RuntimeError('at least one item has to be provided')
+        self.items = items
+        self.reset()
+
+    def reset(self):
+        """Resets the cycle."""
+        self.pos = 0
+
+    @property
+    def current(self):
+        """Returns the current item."""
+        return self.items[self.pos]
+
+    def next(self):
+        """Goes one item ahead and returns it."""
+        rv = self.current
+        self.pos = (self.pos + 1) % len(self.items)
+        return rv
+
+
+class Joiner(object):
+    """A joining helper for templates."""
+
+    def __init__(self, sep=u', '):
+        self.sep = sep
+        self.used = False
+
+    def __call__(self):
+        if not self.used:
+            self.used = True
+            return u''
+        return self.sep
+
+
+# try markupsafe first, if that fails go with Jinja2's bundled version
+# of markupsafe.  Markupsafe was previously Jinja2's implementation of
+# the Markup object but was moved into a separate package in a patchleve
+# release
+try:
+    from markupsafe import Markup, escape, soft_unicode
+except ImportError:
+    from jinja2._markupsafe import Markup, escape, soft_unicode
+
+
+# partials
+try:
+    from functools import partial
+except ImportError:
+    class partial(object):
+        def __init__(self, _func, *args, **kwargs):
+            self._func = _func
+            self._args = args
+            self._kwargs = kwargs
+        def __call__(self, *args, **kwargs):
+            kwargs.update(self._kwargs)
+            return self._func(*(self._args + args), **kwargs)
diff --git a/lib/jinja2/jinja2/visitor.py b/lib/jinja2/jinja2/visitor.py
new file mode 100644
index 0000000..413e7c3
--- /dev/null
+++ b/lib/jinja2/jinja2/visitor.py
@@ -0,0 +1,87 @@
+# -*- coding: utf-8 -*-
+"""
+    jinja2.visitor
+    ~~~~~~~~~~~~~~
+
+    This module implements a visitor for the nodes.
+
+    :copyright: (c) 2010 by the Jinja Team.
+    :license: BSD.
+"""
+from jinja2.nodes import Node
+
+
+class NodeVisitor(object):
+    """Walks the abstract syntax tree and call visitor functions for every
+    node found.  The visitor functions may return values which will be
+    forwarded by the `visit` method.
+
+    Per default the visitor functions for the nodes are ``'visit_'`` +
+    class name of the node.  So a `TryFinally` node visit function would
+    be `visit_TryFinally`.  This behavior can be changed by overriding
+    the `get_visitor` function.  If no visitor function exists for a node
+    (return value `None`) the `generic_visit` visitor is used instead.
+    """
+
+    def get_visitor(self, node):
+        """Return the visitor function for this node or `None` if no visitor
+        exists for this node.  In that case the generic visit function is
+        used instead.
+        """
+        method = 'visit_' + node.__class__.__name__
+        return getattr(self, method, None)
+
+    def visit(self, node, *args, **kwargs):
+        """Visit a node."""
+        f = self.get_visitor(node)
+        if f is not None:
+            return f(node, *args, **kwargs)
+        return self.generic_visit(node, *args, **kwargs)
+
+    def generic_visit(self, node, *args, **kwargs):
+        """Called if no explicit visitor function exists for a node."""
+        for node in node.iter_child_nodes():
+            self.visit(node, *args, **kwargs)
+
+
+class NodeTransformer(NodeVisitor):
+    """Walks the abstract syntax tree and allows modifications of nodes.
+
+    The `NodeTransformer` will walk the AST and use the return value of the
+    visitor functions to replace or remove the old node.  If the return
+    value of the visitor function is `None` the node will be removed
+    from the previous location otherwise it's replaced with the return
+    value.  The return value may be the original node in which case no
+    replacement takes place.
+    """
+
+    def generic_visit(self, node, *args, **kwargs):
+        for field, old_value in node.iter_fields():
+            if isinstance(old_value, list):
+                new_values = []
+                for value in old_value:
+                    if isinstance(value, Node):
+                        value = self.visit(value, *args, **kwargs)
+                        if value is None:
+                            continue
+                        elif not isinstance(value, Node):
+                            new_values.extend(value)
+                            continue
+                    new_values.append(value)
+                old_value[:] = new_values
+            elif isinstance(old_value, Node):
+                new_node = self.visit(old_value, *args, **kwargs)
+                if new_node is None:
+                    delattr(node, field)
+                else:
+                    setattr(node, field, new_node)
+        return node
+
+    def visit_list(self, node, *args, **kwargs):
+        """As transformers may return lists in some places this method
+        can be used to enforce a list as return value.
+        """
+        rv = self.visit(node, *args, **kwargs)
+        if not isinstance(rv, list):
+            rv = [rv]
+        return rv
diff --git a/lib/jinja2/setup.cfg b/lib/jinja2/setup.cfg
new file mode 100644
index 0000000..3581741
--- /dev/null
+++ b/lib/jinja2/setup.cfg
@@ -0,0 +1,8 @@
+[egg_info]
+tag_build = 
+tag_date = 0
+tag_svn_revision = 0
+
+[aliases]
+release = egg_info -RDb ''
+
diff --git a/lib/jinja2/setup.py b/lib/jinja2/setup.py
new file mode 100644
index 0000000..856ec5b
--- /dev/null
+++ b/lib/jinja2/setup.py
@@ -0,0 +1,110 @@
+# -*- coding: utf-8 -*-
+"""
+Jinja2
+~~~~~~
+
+Jinja2 is a template engine written in pure Python.  It provides a
+`Django`_ inspired non-XML syntax but supports inline expressions and
+an optional `sandboxed`_ environment.
+
+Nutshell
+--------
+
+Here a small example of a Jinja template::
+
+    {% extends 'base.html' %}
+    {% block title %}Memberlist{% endblock %}
+    {% block content %}
+      <ul>
+      {% for user in users %}
+        <li><a href="{{ user.url }}">{{ user.username }}</a></li>
+      {% endfor %}
+      </ul>
+    {% endblock %}
+
+Philosophy
+----------
+
+Application logic is for the controller but don't try to make the life
+for the template designer too hard by giving him too few functionality.
+
+For more informations visit the new `Jinja2 webpage`_ and `documentation`_.
+
+.. _sandboxed: http://en.wikipedia.org/wiki/Sandbox_(computer_security)
+.. _Django: http://www.djangoproject.com/
+.. _Jinja2 webpage: http://jinja.pocoo.org/
+.. _documentation: http://jinja.pocoo.org/2/documentation/
+"""
+import sys
+
+from setuptools import setup, Extension, Feature
+
+debugsupport = Feature(
+    'optional C debug support',
+    standard=False,
+    ext_modules = [
+        Extension('jinja2._debugsupport', ['jinja2/_debugsupport.c']),
+    ],
+)
+
+
+# tell distribute to use 2to3 with our own fixers.
+extra = {}
+if sys.version_info >= (3, 0):
+    extra.update(
+        use_2to3=True,
+        use_2to3_fixers=['custom_fixers']
+    )
+
+# ignore the old '--with-speedups' flag
+try:
+    speedups_pos = sys.argv.index('--with-speedups')
+except ValueError:
+    pass
+else:
+    sys.argv[speedups_pos] = '--with-debugsupport'
+    sys.stderr.write('*' * 74 + '\n')
+    sys.stderr.write('WARNING:\n')
+    sys.stderr.write('  the --with-speedups flag is deprecated, assuming '
+                     '--with-debugsupport\n')
+    sys.stderr.write('  For the actual speedups install the MarkupSafe '
+                     'package.\n')
+    sys.stderr.write('*' * 74 + '\n')
+
+
+setup(
+    name='Jinja2',
+    version='2.6',
+    url='http://jinja.pocoo.org/',
+    license='BSD',
+    author='Armin Ronacher',
+    author_email='armin.ronacher@active-4.com',
+    description='A small but fast and easy to use stand-alone template '
+                'engine written in pure python.',
+    long_description=__doc__,
+    # jinja is egg safe. But we hate eggs
+    zip_safe=False,
+    classifiers=[
+        'Development Status :: 5 - Production/Stable',
+        'Environment :: Web Environment',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: BSD License',
+        'Operating System :: OS Independent',
+        'Programming Language :: Python',
+        'Programming Language :: Python :: 3',
+        'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
+        'Topic :: Software Development :: Libraries :: Python Modules',
+        'Topic :: Text Processing :: Markup :: HTML'
+    ],
+    packages=['jinja2', 'jinja2.testsuite', 'jinja2.testsuite.res',
+              'jinja2._markupsafe'],
+    extras_require={'i18n': ['Babel>=0.8']},
+    test_suite='jinja2.testsuite.suite',
+    include_package_data=True,
+    entry_points="""
+    [babel.extractors]
+    jinja2 = jinja2.ext:babel_extract[i18n]
+    """,
+    features={'debugsupport': debugsupport},
+    **extra
+)
diff --git a/lib/protorpc/protorpc/messages.py b/lib/protorpc/protorpc/messages.py
index d1b37ae..048494e 100644
--- a/lib/protorpc/protorpc/messages.py
+++ b/lib/protorpc/protorpc/messages.py
@@ -138,7 +138,7 @@
     except AttributeError:
       return message
     else:
-      return 'Field %s: %s' % (field_name, message)
+      return message
 
 
 # Attributes that are reserved by a class definition that
@@ -1086,8 +1086,15 @@
       try:
         self.validate_default(default)
       except ValidationError, err:
-        raise InvalidDefaultError('Invalid default value for field: %s: %s' %
-                                  (default, err))
+        try:
+          name = self.name
+        except AttributeError:         
+          # For when raising error before name initialization.
+          raise InvalidDefaultError('Invalid default value for %s: %s: %s' %
+                                    (self.__class__.__name__, default, err))
+        else:
+          raise InvalidDefaultError('Invalid default value for field %s: '
+                                    '%s: %s' % (name, default, err))
 
     self.__default = default
     self.__initialized = True
@@ -1159,8 +1166,17 @@
         if self.required:
           raise ValidationError('Required field is missing')
       else:
-        raise ValidationError('Expected type %s, found %s (type %s)' %
-                              (self.type, value, type(value)))
+        try:
+          name = self.name
+        except AttributeError:
+          raise ValidationError('Expected type %s for %s, '
+                                'found %s (type %s)' %
+                                (self.type, self.__class__.__name__,
+                                 value, type(value)))
+        else:
+          raise ValidationError('Expected type %s for field %s, '
+                                'found %s (type %s)' %
+                                (self.type, name, value, type(value)))
 
   def __validate(self, value, validate_element):
     """Internal validation function.
@@ -1181,10 +1197,24 @@
       if isinstance(value, (list, tuple)):
         for element in value:
           if element is None:
-            raise ValidationError('Repeated values may not be None')
+            try:
+              name = self.name
+            except AttributeError:
+              raise ValidationError('Repeated values for %s '
+                                    'may not be None' % self.__class__.__name__)
+            else:
+              raise ValidationError('Repeated values for field %s '
+                                    'may not be None' % name)
           validate_element(element)
       elif value is not None:
-        raise ValidationError('Field is repeated. Found: %s' % value)
+        try:
+          name = self.name
+        except AttributeError:
+          raise ValidationError('%s is repeated. Found: %s' % (
+            self.__class__.__name__, value))
+        else:
+          raise ValidationError('Field %s is repeated. Found: %s' % (name,
+                                                                     value))
 
   def validate(self, value):
     """Validate value assigned to field.
@@ -1314,9 +1344,18 @@
       try:
         unicode(value)
       except UnicodeDecodeError, err:
-        validation_error = ValidationError(
-          'Encountered non-ASCII string %s: %s' % (value, err))
-        validation_error.field_name = self.name
+        try:
+          name = self.name
+        except AttributeError:
+          validation_error = ValidationError(
+            'Field encountered non-ASCII string %s: %s' % (value,
+                                                           err))
+        else:
+          validation_error = ValidationError(
+            'Field %s encountered non-ASCII string %s: %s' % (self.name,
+                                                              value,
+                                                              err))
+          validation_error.field_name = self.name
         raise validation_error
     else:
       super(StringField, self).validate_element(value)
diff --git a/lib/protorpc/protorpc/protojson.py b/lib/protorpc/protorpc/protojson.py
index e363507..a3da283 100644
--- a/lib/protorpc/protorpc/protojson.py
+++ b/lib/protorpc/protorpc/protojson.py
@@ -191,8 +191,17 @@
         elif isinstance(field, messages.MessageField):
           item = decode_dictionary(field.type, item)
         elif (isinstance(field, messages.FloatField) and
-              isinstance(item, (int, long))):
-          item = float(item)
+              isinstance(item, (int, long, basestring))):
+          try:
+            item = float(item)
+          except:
+            pass
+        elif (isinstance(field, messages.IntegerField) and
+              isinstance(item, basestring)):
+          try:
+            item = int(item)
+          except:
+            pass
         valid_value.append(item)
 
       if field.repeated:
diff --git a/lib/protorpc/protorpc/remote.py b/lib/protorpc/protorpc/remote.py
index d41bebc..db2d138 100644
--- a/lib/protorpc/protorpc/remote.py
+++ b/lib/protorpc/protorpc/remote.py
@@ -51,7 +51,7 @@
 service.  It also has convenience methods for creating factory functions that
 can pass persistent global state to a new service instance.
 
-The 'remote' decorator is used to declare which methods of a class are
+The 'method' decorator is used to declare which methods of a class are
 meant to service RPCs.  While this decorator is not responsible for handling
 actual remote method invocations, such as handling sockets, handling various
 RPC protocols and checking messages for correctness, it does attach information
@@ -638,7 +638,7 @@
 
           if get_remote_method_info(value):
             raise ServiceDefinitionError(
-              'Do not use remote decorator when overloading remote method %s '
+              'Do not use method decorator when overloading remote method %s '
               'on service %s.' %
               (attribute, name))
 
diff --git a/lib/protorpc/protorpc/transport.py b/lib/protorpc/protorpc/transport.py
index 8a6ab6b..21e855c 100644
--- a/lib/protorpc/protorpc/transport.py
+++ b/lib/protorpc/protorpc/transport.py
@@ -35,8 +35,9 @@
 
 try:
   from google.appengine.api import urlfetch
+  from google.appengine.api import apiproxy_stub_map
 except ImportError:
-  urlfetch = None
+  pass
 
 __all__ = [
   'RpcStateError',
@@ -281,7 +282,6 @@
 
     def _start_request(self, encoded_request):
       """Initiate async call."""
-
       self.__urlfetch_rpc = urlfetch.create_rpc()
 
       headers = {
@@ -382,7 +382,12 @@
     super(HttpTransport, self).__init__(protocol=protocol)
     self.__service_url = service_url
 
-    if urlfetch:
+    try:
+      has_urlfetch = urlfetch
+    except NameError:
+      has_urlfetch = False
+
+    if has_urlfetch and apiproxy_stub_map.apiproxy.GetStub('urlfetch'):
       self.__request_type = self.__UrlfetchRequest
     else:
       self.__request_type = self.__UrllibRequest
diff --git a/lib/protorpc/protorpc/wsgi/service.py b/lib/protorpc/protorpc/wsgi/service.py
index 3be5f81..867edc0 100644
--- a/lib/protorpc/protorpc/wsgi/service.py
+++ b/lib/protorpc/protorpc/wsgi/service.py
@@ -27,6 +27,7 @@
 __author__ = 'rafek@google.com (Rafe Kaplan)'
 
 import cgi
+import cStringIO
 import httplib
 import logging
 import re
@@ -36,11 +37,13 @@
 from .. import protobuf
 from .. import protojson
 from .. import messages
+from .. import registry
 from .. import remote
 from .. import util
 from . import util as wsgi_util
 
 __all__ = [
+  'DEFAULT_REGISTRY_PATH',
   'service_app',
 ]
 
@@ -51,6 +54,8 @@
 _HTTP_NOT_FOUND = wsgi_util.error(httplib.NOT_FOUND)
 _HTTP_UNSUPPORTED_MEDIA_TYPE = wsgi_util.error(httplib.UNSUPPORTED_MEDIA_TYPE)
 
+DEFAULT_REGISTRY_PATH = '/protorpc'
+
 
 @util.positional(2)
 def service_mapping(service_factory, service_path=r'.*', protocols=None):
@@ -70,7 +75,7 @@
 
   service_class = getattr(service_factory, 'service_class', service_factory)
   remote_methods = service_class.all_remote_methods()
-  path_matcher = re.compile(_REQUEST_PATH_PATTERN % service_path)  
+  path_matcher = re.compile(_REQUEST_PATH_PATTERN % service_path)
 
   def protorpc_service_app(environ, start_response):
     """Actual WSGI application function."""
@@ -202,3 +207,68 @@
 
   # Return WSGI application.
   return protorpc_service_app
+
+
+@util.positional(1)
+def service_mappings(services, registry_path=DEFAULT_REGISTRY_PATH):
+  """Create multiple service mappings with optional RegistryService.
+
+  Use this function to create single WSGI application that maps to
+  multiple ProtoRPC services plus an optional RegistryService.
+
+  Example:
+    services = service.service_mappings(
+        [(r'/time', TimeService),
+         (r'/weather', WeatherService)
+        ])
+
+    In this example, the services WSGI application will map to two services,
+    TimeService and WeatherService to the '/time' and '/weather' paths
+    respectively.  In addition, it will also add a ProtoRPC RegistryService
+    configured to serve information about both services at the (default) path
+    '/protorpc'.
+
+  Args:
+    services: If a dictionary is provided instead of a list of tuples, the
+      dictionary item pairs are used as the mappings instead.
+      Otherwise, a list of tuples (service_path, service_factory):
+      service_path: The path to mount service on.
+      service_factory: A service class or service instance factory.
+    registry_path: A string to change where the registry is mapped (the default
+      location is '/protorpc').  When None, no registry is created or mounted.
+
+  Returns:
+    WSGI application that serves ProtoRPC services on their respective URLs
+    plus optional RegistryService.
+  """
+  if isinstance(services, dict):
+    services = services.iteritems()
+
+  final_mapping = []
+  paths = set()
+  registry_map = {} if registry_path else None
+
+  for service_path, service_factory in services:
+    try:
+      service_class = service_factory.service_class
+    except AttributeError:
+      service_class = service_factory
+
+    if service_path not in paths:
+      paths.add(service_path)
+    else:
+      raise remote.ServiceConfigurationError(
+        'Path %r is already defined in service mapping' %
+        service_path.encode('utf-8'))
+
+    if registry_map is not None:
+      registry_map[service_path] = service_class
+
+    final_mapping.append(service_mapping(service_factory, service_path))
+
+  if registry_map is not None:
+    final_mapping.append(service_mapping(
+      registry.RegistryService.new_factory(registry_map), registry_path))
+
+  return wsgi_util.first_found(final_mapping)
+
diff --git a/lib/protorpc/protorpc/wsgi/util.py b/lib/protorpc/protorpc/wsgi/util.py
index dbf6cd5..3a94b36 100644
--- a/lib/protorpc/protorpc/wsgi/util.py
+++ b/lib/protorpc/protorpc/wsgi/util.py
@@ -22,10 +22,19 @@
 
 __author__ = 'rafek@google.com (Rafe Kaplan)'
 
+import cStringIO
 import httplib
+import re
 
 from .. import util
 
+__all__ = ['static_page',
+           'error',
+           'first_found',
+]
+
+_STATUS_PATTERN = re.compile('^(\d{3})\s')
+
 
 @util.positional(1)
 def static_page(content='',
@@ -107,3 +116,52 @@
                      content_type=content_type,
                      headers=headers)
 
+
+def first_found(apps):
+  """Serve the first application that does not response with 404 Not Found.
+
+  If no application serves content, will respond with generic 404 Not Found.
+
+  Args:
+    apps: List of WSGI applications to search through.  Will serve the content
+      of the first of these that does not return a 404 Not Found.  Applications
+      in this list must not modify the environment or any objects in it if they
+      do not match.  Applications that do not obey this restriction can create
+      unpredictable results.
+
+  Returns:
+    Compound application that serves the contents of the first application that
+    does not response with 404 Not Found.
+  """
+  apps = tuple(apps)
+  not_found = error(httplib.NOT_FOUND)
+
+  def first_found_app(environ, start_response):
+    """Compound application returned from the first_found function."""
+    final_result = {}  # Used in absence of Python local scoping.
+
+    def first_found_start_response(status, response_headers):
+      """Replacement for start_response as passed in to first_found_app.
+
+      Called by each application in apps instead of the real start response.
+      Checks the response status, and if anything other than 404, sets 'status'
+      and 'response_headers' in final_result.
+      """
+      status_match = _STATUS_PATTERN.match(status)
+      assert status_match, ('Status must be a string beginning '
+                            'with 3 digit number. Found: %s' % status)
+      status_code = status_match.group(0)
+      if int(status_code) == httplib.NOT_FOUND:
+        return
+
+      final_result['status'] = status
+      final_result['response_headers'] = response_headers
+
+    for app in apps:
+      response = app(environ, first_found_start_response)
+      if final_result:
+        start_response(final_result['status'], final_result['response_headers'])
+        return response
+
+    return not_found(environ, start_response)
+  return first_found_app
diff --git a/lib/webapp2/CHANGES b/lib/webapp2/CHANGES
index 6fde84e..0b03c9f 100644
--- a/lib/webapp2/CHANGES
+++ b/lib/webapp2/CHANGES
@@ -1,85 +1,101 @@
+Version 2.5.1 - February 07, 2012
+---------------------------------
+- Bug fix release related to request charset in old versions of
+	WebOb.
+
+Version 2.5 - February 01, 2012
+-------------------------------
+
+Version 2.4 - January 23, 2012
+------------------------------
+- Maintenance release. Fixed outstanding bugs related to App Engine.
+- Removed webapp2_extras/protorpc, broken since webapp2 was added
+	to App Engine.
+
+
 Version 2.3 - August 24, 2011
 -----------------------------
 - webapp2.Response.out creates a reference loop that impedes garbage
-  collection. Changing it to a property fixed this (Issue #15).
+	collection. Changing it to a property fixed this (Issue #15).
 - webapp2_extras.i18n:
-  - When in debug mode, translations are not cached, so compiling new
-    translations make them readily available (Issue #13).
+	- When in debug mode, translations are not cached, so compiling new
+		translations make them readily available (Issue #13).
 - webapp2_extras.auth:
-  - ATTENTION: auth_id is no longer converted to lower case to retrieve
-    a key or save a new user in webapp2_extras.appengine.auth.models.User.
-    This is a more general approach, as not all systems use case-insensitive
-    user ids. If you want case-insensitive auth ids, convert them to lower
-    case before passing auth ids to the auth module (Issue #14).
-  - If user data is missing attributes, don't raise AssertionError.
-    Simply don't save or return a valid session, instead.
-  - call user_model.get_id() instead of the ndb-specific user.key.id().
-  - removed set_password_validator() and set_token_validator().
-    They add complexity to the API without a use case to justify.
-    Extend AuthStore to achieve the same thing.
+	- ATTENTION: auth_id is no longer converted to lower case to retrieve
+		a key or save a new user in webapp2_extras.appengine.auth.models.User.
+		This is a more general approach, as not all systems use case-insensitive
+		user ids. If you want case-insensitive auth ids, convert them to lower
+		case before passing auth ids to the auth module (Issue #14).
+	- If user data is missing attributes, don't raise AssertionError.
+		Simply don't save or return a valid session, instead.
+	- call user_model.get_id() instead of the ndb-specific user.key.id().
+	- removed set_password_validator() and set_token_validator().
+		They add complexity to the API without a use case to justify.
+		Extend AuthStore to achieve the same thing.
+
 
 Version 2.2.3 - August 6, 2011
 ------------------------------
 - Version 2.2.2 missed the webapp2_extras.appengine package.
 
 - get_app() and get_request() now test that app and request are set, to avoid
-  hard to debug stack traces when they are not and the local proxy is used.
+	hard to debug stack traces when they are not and the local proxy is used.
 
 
 Version 2.2.2 - August 5, 2011 (more 2's than ever!)
 ----------------------------------------------------
 - A default charset is always set in the Request object: if it is not defined
-  in the constructor, environ['CONTENT_TYPE'] is checked; and if it is still
-  not defined 'utf-8' is used.
+	in the constructor, environ['CONTENT_TYPE'] is checked; and if it is still
+	not defined 'utf-8' is used.
 
 - Added token_model as an attribute of the User model; it is used instead of
-  the hardcoded class.
+	the hardcoded class.
 
 
 Version 2.2.1 - August 1st, 2011
 --------------------------------
 - Fixed a bug in WSGIApplication.run() when running outside of App Engine:
-  CGIHandler().run(app) -> CGIHandler().run(self). (issue 9)
+	CGIHandler().run(app) -> CGIHandler().run(self). (issue 9)
 
 
 Version 2.2 - July 30, 2011
 ===========================
 - Revised webapp2_extras.auth and simplified User model, by Kyle Finley.
-  Thanks!
+	Thanks!
 
 
 Version 2.1 - July 29, 2011
 ===========================
 - Added webapp2_extras.auth: high-level utilities for authentication and
-  authorization.
+	authorization.
 
 - Added webapp2_extras.appengine.auth.models: default model implementations
-  for webapp2_extras.auth (can be overridden).
+	for webapp2_extras.auth (can be overridden).
 
 - Added webapp2_extras.appengine.ndb.unique_model: a model to store unique
-  values. This was added mainly so that the default user model can have
-  multiple unique properties.
+	values. This was added mainly so that the default user model can have
+	multiple unique properties.
 
 - import_string() now displays useful debug information when it fails.
 
 - To make things clearly separated specially for those using webapp2
-  outside of App Engine, from now on all App Engine-specific modules will
-  be placed in webapp2_extras.appengine. Also three modules were moved to
-  the new package:
+	outside of App Engine, from now on all App Engine-specific modules will
+	be placed in webapp2_extras.appengine. Also three modules were moved to
+	the new package:
 
-  - webapp2_extras.sessions_memcache
-  - webapp2_extras.sessions_ndb
-  - webapp2_extras.users
+	- webapp2_extras.sessions_memcache
+	- webapp2_extras.sessions_ndb
+	- webapp2_extras.users
 
-  The original modules were not removed, though: they will be kept in the same
-  place for compatibility purposes, just importing their stuff from the new
-  locations.
+	The original modules were not removed, though: they will be kept in the same
+	place for compatibility purposes, just importing their stuff from the new
+	locations.
 
 - Config.load_config() now makes a copy of the configuration when user_values
-  are passed. That keyword is meant to override app configuration, so the
-  previous behavior was actually wrong. This is a side feature not used inside
-  webapp2 or even well documented so the change should not affect existing
-  apps.
+	are passed. That keyword is meant to override app configuration, so the
+	previous behavior was actually wrong. This is a side feature not used inside
+	webapp2 or even well documented so the change should not affect existing
+	apps.
 
 
 Version 2.0.2 - July 18, 2011
@@ -97,95 +113,95 @@
 - Added support for the (not yet released) App Engine Python 2.7 SDK.
 
 - Deprecated webapp2_extras.local_app. WSGIApplication is now thread-safe
-  by default when webapp2_extras.local is available.
-  webapp2_extras.local_app.WSGIApplication can still be imported, but it is
-  just an alias to webapp2.WSGIApplication (and a deprecation warning is
-  emitted when it is imported).
+	by default when webapp2_extras.local is available.
+	webapp2_extras.local_app.WSGIApplication can still be imported, but it is
+	just an alias to webapp2.WSGIApplication (and a deprecation warning is
+	emitted when it is imported).
 
 - Like DomainRoute, PathPrefixRoute now only tests the nested routes if the
-  prefix matches. So now it is not only convenient but matches smartly and
-  faster. ;)
+	prefix matches. So now it is not only convenient but matches smartly and
+	faster. ;)
 
 - Added webapp2_extras.security, with security related helpers such as secure
-  password hashing tools.
+	password hashing tools.
 
 - webapp2_extras.sessions:
-  - Now uses webapp2_extras.security.create_token() to generate session IDs
-    instead of uuid.
-  - Added 'backends' configuration: get_session() can now be called passing
-    a more convenient 'backend' key. Default ones are 'securecookie',
-    'datastore' and 'memcache'.
+	- Now uses webapp2_extras.security.create_token() to generate session IDs
+		instead of uuid.
+	- Added 'backends' configuration: get_session() can now be called passing
+		a more convenient 'backend' key. Default ones are 'securecookie',
+		'datastore' and 'memcache'.
 
 - get_build_routes() now yields (name, route) instead of simply route. This
-  will allow routes with nested routes to act as a proxy to build URIs.
+	will allow routes with nested routes to act as a proxy to build URIs.
 
 - webapp2.urlunsplit() was removed from the public API.
 
 - Variables names in routes must now look like python identifiers -
-  this means that they can no longer start with a number, like before.
+	this means that they can no longer start with a number, like before.
 
 - Removed support for _anchor in uri_for() -- the documented keyword is
-  _fragment.
+	_fragment.
 
 - Removed support for handler functions receiving (request, response). The
-  correct arguments for function handlers are (request, *args, **kwargs).
+	correct arguments for function handlers are (request, *args, **kwargs).
 
 - webapp2_extras.json:
-  - Fixed an issue with importing json on non-GAE environments (missing
-    absolute import).
-  - Now imports simplejson directly instead of using the one from Django,
-    since it is now included in the App Engine SDK (since version 1.4.2).
+	- Fixed an issue with importing json on non-GAE environments (missing
+		absolute import).
+	- Now imports simplejson directly instead of using the one from Django,
+		since it is now included in the App Engine SDK (since version 1.4.2).
 
 - Added WSGIApplication.clear_globals(). Instead of
-  app.set_globals(app=None, request=None), use app.clear_globals().
+	app.set_globals(app=None, request=None), use app.clear_globals().
 
 
 Version 1.8.1 - June 29, 2011
 =============================
 - Implemented an adapter mechanism to dispatch different kind of handlers:
-  webapp.RequestHandler, webapp2.RequestHandler and "view functions".
-  Instead of monkeypatching handlers (adding a 'factory' attribute),
-  handlers are wrapped by adapters that do the appropriate dispatch.
-  How handlers are adapted can be overridden using the convenience method
-  ``set_adapter()`` from the Router class, but the common cases are covered.
+	webapp.RequestHandler, webapp2.RequestHandler and "view functions".
+	Instead of monkeypatching handlers (adding a 'factory' attribute),
+	handlers are wrapped by adapters that do the appropriate dispatch.
+	How handlers are adapted can be overridden using the convenience method
+	``set_adapter()`` from the Router class, but the common cases are covered.
 
 - Function views now conveniently receive (request, *args, **kwargs), like
-  in Django. The previous arguments will work, but they are now deprecated
-  and will not be supported in the future. This is a major incompatibility
-  with previous versions but it feels a lot better than the previous
-  (request, response) behavior, as adapters make it easy to have custom
-  dispatch arguments using a unified API.
-  The webapp2.RequestHandler class remain unchanged and is instantiated with
-  (request, response).
+	in Django. The previous arguments will work, but they are now deprecated
+	and will not be supported in the future. This is a major incompatibility
+	with previous versions but it feels a lot better than the previous
+	(request, response) behavior, as adapters make it easy to have custom
+	dispatch arguments using a unified API.
+	The webapp2.RequestHandler class remain unchanged and is instantiated with
+	(request, response).
 
 
 Version 1.8 - June 26, 2011
 ===========================
 - webap2_extras.i18n: the functions passed to I18nStore.set_locale_selector()
-  and I18nStore.set_timezone_selector() now receive (store, request) instead of
-  (request, store), for consistency with the router custom callables.
+	and I18nStore.set_timezone_selector() now receive (store, request) instead of
+	(request, store), for consistency with the router custom callables.
 
 - webap2_extras.json:
-  - json is imported first trying direct simplejson, then built-in json
-    (for Python >= 2.6), then the one from django.utils (for App Engine).
-  - All convenience functions now receive *args, **kwargs to be passed to
-    encode()/decode().
+	- json is imported first trying direct simplejson, then built-in json
+		(for Python >= 2.6), then the one from django.utils (for App Engine).
+	- All convenience functions now receive *args, **kwargs to be passed to
+		encode()/decode().
 
 - Added webapp2_extras.mako.
 
 - Added webapp2.redirect_to.
 
 - Added Request.blank() parameters compatible with WebOb >= 1.0: POST and
-  **kwargs.
+	**kwargs.
 
 - Increased compatibility with wsgiref.headers.Headers, used by
-  webapp.Response.
+	webapp.Response.
 
 
 Version 1.7.5 - June 20, 2011
 =============================
 - Implemented methods from ``wsgiref.headers.Headers``, used by
-  webapp.Response.headers.
+	webapp.Response.headers.
 
 
 Version 1.7.4 - June 19, 2011
@@ -205,22 +221,22 @@
 - Response is now compatible with latest WebOb.
 
 - Increased Response compatibility with webapp, implementing wsgi_write() and
-  has_error().
+	has_error().
 
 - Changed some status messages to be the same as webapp:
-  - 203: 'Non-Authoritative Information'
-  - 302: 'Moved Temporarily'
-  - 306: 'Unused'
-  - 408: 'Request Time-out'
-  - 414: 'Request-URI Too Large'
-  - 504: 'Gateway Time-out'
-  - 505: 'HTTP Version not supported'
+	- 203: 'Non-Authoritative Information'
+	- 302: 'Moved Temporarily'
+	- 306: 'Unused'
+	- 408: 'Request Time-out'
+	- 414: 'Request-URI Too Large'
+	- 504: 'Gateway Time-out'
+	- 505: 'HTTP Version not supported'
 
 - Copied Request from webapp, so that when using webapp2 outside of the SDK
-  they are the same.
+	they are the same.
 
 - Routes now match the Request path unquoted. See App Engine issue #2636
-  for an explanation.
+	for an explanation.
 
 
 Version 1.7.1 - June 14, 2011
@@ -230,7 +246,7 @@
 - RequestHandler.redirect and redirect_to now return a response object.
 
 - Fixed: multiple routes that define methods are tried before MethodNotAllowed
-  is raised.
+	is raised.
 
 - Updated webapp2_extras.protorpc to work with latest ProtoRPC.
 
@@ -238,18 +254,18 @@
 Version 1.7 - June 4, 2011
 ==========================
 - Added a simple configuration object for WSGIapplication, available in the
-  config attribute. Extras modules that use configuration (i18n, jinja2,
-  sessions) don't require app.config to be set manually anymore. Still, the
-  `secret_key` key config for sessions, if not defined, will result in an
-  exception.
+	config attribute. Extras modules that use configuration (i18n, jinja2,
+	sessions) don't require app.config to be set manually anymore. Still, the
+	`secret_key` key config for sessions, if not defined, will result in an
+	exception.
 
 - Deprecated webapp2_extras.config, replaced by the simpler app dict.
 
 - Router no longer receives app on construction, for consistency with the
-  config object. App is set as global before router is initialized.
+	config object. App is set as global before router is initialized.
 
 - Fixed a bug in webapp2_extras.sessions that made it not save the session
-  when it was empty (like when flashes are popped).
+	when it was empty (like when flashes are popped).
 
 - Added standalone uri_for function, to be used in templates.
 
@@ -257,11 +273,11 @@
 Version 1.6.3 - June 3, 2011
 ============================
 - Added webap2_extras.local_app, with the WSGIApplication previously in
-  webap2_extras.local. This allows using LocalProxy on App Engine, without
-  actually monkeypatching the WSGI app for threaded environments.
+	webap2_extras.local. This allows using LocalProxy on App Engine, without
+	actually monkeypatching the WSGI app for threaded environments.
 
 - Route now raises exc.HTTPMethodNotAllowed if methods are set and the request
-  method doesn't match.
+	method doesn't match.
 
 - Router.default_matcher() now raises exc.HTTPNotFound if no route matches.
 
@@ -269,11 +285,11 @@
 Version 1.6.2 - May 30, 2011
 ============================
 - WSGIApplication.__call__ checks if the dispatcher didn't return None to
-  accept the returned value as a response. Previously it checked if it was an
-  instance of Response.
+	accept the returned value as a response. Previously it checked if it was an
+	instance of Response.
 
 - To support returned response, RequestHandler.dispatch() returns the result of
-  the dispatched method.
+	the dispatched method.
 
 Version 1.6.1 - May 30, 2011
 ============================
@@ -287,65 +303,65 @@
 Version 1.6 - May 29, 2011
 ==========================
 - Handlers registered in WSGIApplication.error_handlers can now also be a
-  string to be lazily imported.
+	string to be lazily imported.
 
 - The request object now has the active response available as an attribute:
-  request.response.
+	request.response.
 
 - Added a factory method to RequestHandler, to better deal with libraries that
-  use a custom webapp.RequestHandler constructors (like ProtoRPC).
+	use a custom webapp.RequestHandler constructors (like ProtoRPC).
 
 - Added set_dispatcher() to Router, to set extended dispatching.
 
 - Handlers and error handlers can now return a response object, which will be
-  used instead of the default response created by the WSGI app. This allows
-  webapp2 to be used following the common pattern of handlers that return a
-  response, instead of the webapp way of a handler that writes to an existing
-  response.
+	used instead of the default response created by the WSGI app. This allows
+	webapp2 to be used following the common pattern of handlers that return a
+	response, instead of the webapp way of a handler that writes to an existing
+	response.
 
 - Request.Handler.redirect() now can receive a `code` parameter, to set the
-  status code. This is preferable than the `permanent` parameter, kept for
-  compatibility with webapp.
+	status code. This is preferable than the `permanent` parameter, kept for
+	compatibility with webapp.
 
 - webapp2 is now a file webapp2.py, instead of a package with a __init__.py
-  file.
+	file.
 
 - API cleanup:
-  - Removed WSGIApplication.url_for(), to_unicode(), to_utf8().
-  - RequestHandler.url_for was renamed to uri_for, with url_for kept
-    as an alias.
-  - Renamed webapp2_extras.routes.ImprovedRoute to RedirectRoute, as it
-    basically adds redirect conveniences.
-  - For consistency with uri building parameters, RedirectHandler parameters
-    are now prefixed with a underscore: `url` becomes `_uri` and `permanent`
-    becomes `_permanent`. A parameter `_code` was added to set status code.
-  - Router.do_match and do_build renamed to default_matcher and
-    default_dispatcher.
-  - URI building accepts a _fragment argument, with _anchor as fallback.
+	- Removed WSGIApplication.url_for(), to_unicode(), to_utf8().
+	- RequestHandler.url_for was renamed to uri_for, with url_for kept
+		as an alias.
+	- Renamed webapp2_extras.routes.ImprovedRoute to RedirectRoute, as it
+		basically adds redirect conveniences.
+	- For consistency with uri building parameters, RedirectHandler parameters
+		are now prefixed with a underscore: `url` becomes `_uri` and `permanent`
+		becomes `_permanent`. A parameter `_code` was added to set status code.
+	- Router.do_match and do_build renamed to default_matcher and
+		default_dispatcher.
+	- URI building accepts a _fragment argument, with _anchor as fallback.
 
 
 Version 1.5 - May 16, 2011
 ==========================
 - Added webapp2_extras.local, with an extended WSGIApplication that uses
-  thread-local for globals and so can be used outside of App Engine.
+	thread-local for globals and so can be used outside of App Engine.
 
 - Added webapp2_extras.protorpc, with support for Google ProtoRPC.
 
 - Added set_matcher() and set_builder() to Router, to set extended matcher and
-  builder.
+	builder.
 
 - Routes now return the route on match() or routes with nested routes cannot
-  work. So instead of returning (args, kwargs) they return
-  (route, args, kwargs).
+	work. So instead of returning (args, kwargs) they return
+	(route, args, kwargs).
 
 - Now handlers only receive **args if no named variables are set. Otherwise,
-  they only receive **kwargs. This allows users to use regexes that are not
-  intended to be captured, mixing named and unnamed variables.
+	they only receive **kwargs. This allows users to use regexes that are not
+	intended to be captured, mixing named and unnamed variables.
 
 - DomainRoute now uses the same syntax used by webapp2.Route, instead of a
-  regex. The resulting keywords are added to the mathed route **kwargs.
-  This gives control of what is passed to the handler if a domain/subdomain
-  matches, and allows to not pass anything if no regex groups are defined.
+	regex. The resulting keywords are added to the mathed route **kwargs.
+	This gives control of what is passed to the handler if a domain/subdomain
+	matches, and allows to not pass anything if no regex groups are defined.
 
 - Several small bugs fixed and increased test coverage in webapp2_extras.
 
@@ -353,24 +369,24 @@
 Version 1.3 - May 9, 2011
 =========================
 - Added webapp2_extras modules:
-  - webapp2_extras.i18n: internationalization support.
-  - webapp2_extras.sessions_memcache: memcache based sessions.
-  - webapp2_extras.sessions_ndb: datastore based sessions.
+	- webapp2_extras.i18n: internationalization support.
+	- webapp2_extras.sessions_memcache: memcache based sessions.
+	- webapp2_extras.sessions_ndb: datastore based sessions.
 - Several api improvements in webapp2_extras.
 
 
 Version 1.2 - May 6, 2011
 =========================
 - Removed Config from webapp2 core. It is now part of the new "webapp2_extras"
-  package.
+	package.
 - Added the package webapp2_extras. These are all optional modules that
-  complement webapp2 with common functionalities. Currently they include:
-  - webapp2_extras.config: Configuration object.
-  - webapp2_extras.jinja2: Support for Jinja2 templating.
-  - webapp2_extras.json: JSON utilities.
-  - webapp2_extras.routes: Extended route classes.
-  - webapp2_extras.securecookie: Signed cookie serializer.
-  - webapp2_extras.sessions: Sessions support.
+	complement webapp2 with common functionalities. Currently they include:
+	- webapp2_extras.config: Configuration object.
+	- webapp2_extras.jinja2: Support for Jinja2 templating.
+	- webapp2_extras.json: JSON utilities.
+	- webapp2_extras.routes: Extended route classes.
+	- webapp2_extras.securecookie: Signed cookie serializer.
+	- webapp2_extras.sessions: Sessions support.
 
 
 Version 1.1 - May 5, 2011
@@ -384,17 +400,17 @@
 stuff that won't be noticed in common usage.
 
 - Changed signature of RequestHandler's constructor: it now receives only
-  (request, response) instead of (app, request, response).
+	(request, response) instead of (app, request, response).
 
 - Added RequestContext class, which should help testing.
 
 - Added .app attribute to Request, a reference to the active app.
 
 - Refactored routing scheme:
-  - Now also supports function views besides classes.
-  - Now also supports normal functions as exception handlers, and exception
-    handlers don't need to be a subclass RequestHandler (but still can).
-  - Now also supports custom handler methods besides using the request method.
+	- Now also supports function views besides classes.
+	- Now also supports normal functions as exception handlers, and exception
+		handlers don't need to be a subclass RequestHandler (but still can).
+	- Now also supports custom handler methods besides using the request method.
 
 - Removed Request.context: was redundant with Request.registry.
 
@@ -408,196 +424,196 @@
 Version 0.7 - September 26, 2010
 ================================
 - Added WSGIApplication.app and WSGIApplication.request, class attributes set
-  on each request to reference currently active app and request.
-  WSGIApplication.app is an alias to WSGIApplication.active_instance.
+	on each request to reference currently active app and request.
+	WSGIApplication.app is an alias to WSGIApplication.active_instance.
 
 - Fixed double escaping of + in urlunsplit(). Thanks, alkis.
 
 - IMPROVED: configuration now behaves exactly like a dictionary, still
-  auto-loading configuration values when needed and honoring required configs.
-  For example, we always used this::
+	auto-loading configuration values when needed and honoring required configs.
+	For example, we always used this::
 
-      bar = self.app.get_config('foo', 'bar')
+			bar = self.app.get_config('foo', 'bar')
 
-  Now it is also possible to use direct access and dict methods::
+	Now it is also possible to use direct access and dict methods::
 
-      bar = self.app.config['foo']['bar']
-      # or...
-      bar = self.app.config['foo'].get('bar')
-      # or...
-      bar = self.app.config.get('foo').get('bar')
+			bar = self.app.config['foo']['bar']
+			# or...
+			bar = self.app.config['foo'].get('bar')
+			# or...
+			bar = self.app.config.get('foo').get('bar')
 
-  The previous get_config() method works as always.
+	The previous get_config() method works as always.
 
 
 Version 0.6 - August 31, 2010
 =============================
 - Fix: Anchors in generated URLs are quoted using urlib.quote, instead of
-  urlib.quote_plus.
+	urlib.quote_plus.
 
 - In Router.dispatch(), if an exception occurs while handling an exception,
-  raise it instead of trying to handle it again.
+	raise it instead of trying to handle it again.
 
 - Fixed bug when writing a unicode string to Response and charset is not set.
-  Thanks to martinc for the patch.
+	Thanks to martinc for the patch.
 
 - Changed: the app won't fallback anymore to the exception handler set for
-  status 500 if handlers for other status are not set.
+	status 500 if handlers for other status are not set.
 
 - Changed: exceptions are only logged when unhandled. It is up to exception
-  handlers to log them when appropriate.
+	handlers to log them when appropriate.
 
 
 Version 0.5.1 - August 17, 2010
 ===============================
 - When a URL matches, some attributes are set in the request object:
-  - request.route: the matched route
-  - request.route_args: the matched positional arguments, a tuple
-  - request.route_kwargs: the matched keyword arguments, a dict
+	- request.route: the matched route
+	- request.route_args: the matched positional arguments, a tuple
+	- request.route_kwargs: the matched keyword arguments, a dict
 
 - WSGIApplication.handle_exception() doesn't automatically raises the exception
-  when in debug mode: it is up to the error handler to raise it if in dev; it
-  will be raised if no error handler is defined to handle it anyway.
+	when in debug mode: it is up to the error handler to raise it if in dev; it
+	will be raised if no error handler is defined to handle it anyway.
 
 - Added attributes, WSGIApplication.registry, Request.registry and
-  Request.context, dictionaries for objects in use during the app or request
-  lifetimes.
+	Request.context, dictionaries for objects in use during the app or request
+	lifetimes.
 
 - Before passing the request method to the RequestHandler, '-' is replaced
-  by '_', so that a method like WebDav's 'VERSION-CONTROL' can be supported.
+	by '_', so that a method like WebDav's 'VERSION-CONTROL' can be supported.
 
 - Config.get() now only returns the passed default value when key is defined.
-  This is the intended, more predictable behavior: default is a default for
-  the key, not the module. For example::
+	This is the intended, more predictable behavior: default is a default for
+	the key, not the module. For example::
 
-      # If config['foo']['bar'] is not set, return 'baz'.
-      config.get('foo', 'bar', default='baz')
+			# If config['foo']['bar'] is not set, return 'baz'.
+			config.get('foo', 'bar', default='baz')
 
-      # If config['foo'] is not set, return None. Default is ignored here.
-      config.get('foo', default='baz')
+			# If config['foo'] is not set, return None. Default is ignored here.
+			config.get('foo', default='baz')
 
 - Router initialization now receives the app as parameter, so that extended
-  routes can access app's config.
+	routes can access app's config.
 
 
 Version 0.5 - August 13, 2010
 =============================
 - Better compatibility with webapp:
-  - webapp2.WSGIapplication can be used with webapp.RequestHandler.
-  - webapp.WSGIapplication can be used with webapp2.RequestHandler.
+	- webapp2.WSGIapplication can be used with webapp.RequestHandler.
+	- webapp.WSGIapplication can be used with webapp2.RequestHandler.
 
-  Although the functionality becomes limited in both cases, this should help
-  migration.
+	Although the functionality becomes limited in both cases, this should help
+	migration.
 
 - Review of Response based on observations from
-  http://pythonpaste.org/webob/differences.html#webapp-response:
+	http://pythonpaste.org/webob/differences.html#webapp-response:
 
-  - Response.out is now a reference to self, to use webob.Response's neat
-    .write() method which can handle both string and unicode.
-  - Response.clear() now sets .body = '' instead of .app_iter = [].
+	- Response.out is now a reference to self, to use webob.Response's neat
+		.write() method which can handle both string and unicode.
+	- Response.clear() now sets .body = '' instead of .app_iter = [].
 
 - Added Response.write(), for compatibility with StringIO behavior in webapp
-  when calling write() passing non-basestring values (issue 2).
+	when calling write() passing non-basestring values (issue 2).
 
 - Removed url_escape() and url_unescape(). Unused or almost unused.
 
 - ErrorHandlers can now be defined as strings to be lazily loaded, as they
-  now use the same dispatch mechanism of other handlers.
+	now use the same dispatch mechanism of other handlers.
 
 Backwards compatibility warning
 -------------------------------
 - The method handle_exception() is called from app-wide error handlers.
-  Previously, get() was called.
+	Previously, get() was called.
 
 
 Version 0.4.1 - August 08, 2010
 ===============================
 - Removed router parameter from get_routes(), get_match_routes(),
-  get_build_routes(). This simplifies multi-routes quite a bit.
+	get_build_routes(). This simplifies multi-routes quite a bit.
 
 
 Version 0.4 - August 07, 2010
 =============================
 - redirect() and redirect_to() now accept a keyword argument 'abort' to raise
-  an exception to do the redirect.
+	an exception to do the redirect.
 
 - '_netloc' can be passed to url_for() build URLs for a given domain or
-  subdomain.
+	subdomain.
 
 - Added BaseRoute, an interface for custom routes. Several improvements make
-  the routing system more extensible, while the default Route class sticks to
-  the basics.
+	the routing system more extensible, while the default Route class sticks to
+	the basics.
 
 - Nested routes are now possible. As an example, `extras/routes.py` has several
-  classes that accept nested routes or extend routing in other ways:
+	classes that accept nested routes or extend routing in other ways:
 
-  - PathPrefixRoute: the idea of this route is to set a base path for other
-    routes::
+	- PathPrefixRoute: the idea of this route is to set a base path for other
+		routes::
 
-        app = WSGIApplication([
-            PathPrefixRoute('/users/<user:\w+>', [
-                Route('/', UserOverviewHandler, 'user-overview'),
-                Route('/profile', UserProfileHandler, 'user-profile'),
-                Route('/projects', UserProjectsHandler, 'user-projects'),
-            ]),
-        ])
+				app = WSGIApplication([
+						PathPrefixRoute('/users/<user:\w+>', [
+								Route('/', UserOverviewHandler, 'user-overview'),
+								Route('/profile', UserProfileHandler, 'user-profile'),
+								Route('/projects', UserProjectsHandler, 'user-projects'),
+						]),
+				])
 
-    The example above is the same as setting the following routes, just more
-    convenient as you can reuse the path prefix::
+		The example above is the same as setting the following routes, just more
+		convenient as you can reuse the path prefix::
 
-        app = WSGIApplication([
-            Route('/users/<user:\w+>/', UserOverviewHandler, 'user-overview'),
-            Route('/users/<user:\w+>/profile', UserProfileHandler, 'user-profile'),
-            Route('/users/<user:\w+>/projects', UserProjectsHandler, 'user-projects'),
-        ])
+				app = WSGIApplication([
+						Route('/users/<user:\w+>/', UserOverviewHandler, 'user-overview'),
+						Route('/users/<user:\w+>/profile', UserProfileHandler, 'user-profile'),
+						Route('/users/<user:\w+>/projects', UserProjectsHandler, 'user-projects'),
+				])
 
-  - NamePrefixRoute: Same as PathPrefixRoute, but prefixes the names of routes.
+	- NamePrefixRoute: Same as PathPrefixRoute, but prefixes the names of routes.
 
-  - HandlerPrefixRoute: Same as PathPrefixRoute, but prefixes the handlers of
-    routes.
+	- HandlerPrefixRoute: Same as PathPrefixRoute, but prefixes the handlers of
+		routes.
 
-  - DomainRoute: a route used to restrict route matches to a given domain or
-    subdomain.
+	- DomainRoute: a route used to restrict route matches to a given domain or
+		subdomain.
 
-    For example, to restrict routes to a subdomain of the appspot domain::
+		For example, to restrict routes to a subdomain of the appspot domain::
 
-        SUBDOMAIN_RE = '^([^.]+)\.app-id\.appspot\.com$'
+				SUBDOMAIN_RE = '^([^.]+)\.app-id\.appspot\.com$'
 
-        app = WSGIApplication([
-            DomainRoute(SUBDOMAIN_RE, [
-                Route('/foo', 'FooHandler', 'subdomain-thing'),
-            ]),
-            Route('/bar', 'BarHandler', 'normal-thing'),
-        ])
+				app = WSGIApplication([
+						DomainRoute(SUBDOMAIN_RE, [
+								Route('/foo', 'FooHandler', 'subdomain-thing'),
+						]),
+						Route('/bar', 'BarHandler', 'normal-thing'),
+				])
 
-  - ImprovedRoute: a route with redirect_to and strict_slash.
+	- ImprovedRoute: a route with redirect_to and strict_slash.
 
-    - `redirect_to`: if set, the route is used to redirect to a URL. The value
-       can be a URL string or a callable that returns a URL. These two are
-       equivalent::
+		- `redirect_to`: if set, the route is used to redirect to a URL. The value
+			 can be a URL string or a callable that returns a URL. These two are
+			 equivalent::
 
-          route = Route('/foo', RedirectHandler, defaults={'url': '/bar'})
-          route = Route('/foo', redirect_to='/bar')
+					route = Route('/foo', RedirectHandler, defaults={'url': '/bar'})
+					route = Route('/foo', redirect_to='/bar')
 
-    - `strict_slash`: if True, redirects access to the same URL with different
-      trailing slash to the strict path defined in the rule. For example, take
-      these rules::
+		- `strict_slash`: if True, redirects access to the same URL with different
+			trailing slash to the strict path defined in the rule. For example, take
+			these rules::
 
-          route = Route('/foo', FooHandler, strict_slash=True)
-          route = Route('/bar/', BarHandler, strict_slash=True)
+					route = Route('/foo', FooHandler, strict_slash=True)
+					route = Route('/bar/', BarHandler, strict_slash=True)
 
-      Because **strict_slash** is True, this is what will happen:
+			Because **strict_slash** is True, this is what will happen:
 
-      - Access to ``/foo`` will execute ``FooHandler`` normally.
-      - Access to ``/bar/`` will execute ``BarHandler`` normally.
-      - Access to ``/foo/`` will redirect to ``/foo``.
-      - Access to ``/bar`` will redirect to ``/bar/``.
+			- Access to ``/foo`` will execute ``FooHandler`` normally.
+			- Access to ``/bar/`` will execute ``BarHandler`` normally.
+			- Access to ``/foo/`` will redirect to ``/foo``.
+			- Access to ``/bar`` will redirect to ``/bar/``.
 
 
 Version 0.3 - August 05, 2010
 =============================
 - Routes store the handler, as we had in 0.1. This allows custom routes to
-  have nested routes.
+	have nested routes.
 - Much improved URL building, now delegated to routes.
 - added urlunsplit() helper.
 
@@ -605,9 +621,9 @@
 Version 0.2 - August 04, 2010
 =============================
 - Fixed a bug in Route.match() that would make it return positional arguments
-  with wrong order. Dictionary is correctly sorted now.
+	with wrong order. Dictionary is correctly sorted now.
 - Added build_only option for routes: routes that are only used for url_for()
-  and never match.
+	and never match.
 
 
 Version 0.1 - August 03, 2010
diff --git a/lib/webapp2/LICENSE b/lib/webapp2/LICENSE
index 6a3a262..b4aabd7 100644
--- a/lib/webapp2/LICENSE
+++ b/lib/webapp2/LICENSE
@@ -15,6 +15,184 @@
 See the License for the specific language governing permissions and
 limitations under the License.
 
+                            Apache License
+                       Version 2.0, January 2004
+                    http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+  "License" shall mean the terms and conditions for use, reproduction,
+  and distribution as defined by Sections 1 through 9 of this document.
+
+  "Licensor" shall mean the copyright owner or entity authorized by
+  the copyright owner that is granting the License.
+
+  "Legal Entity" shall mean the union of the acting entity and all
+  other entities that control, are controlled by, or are under common
+  control with that entity. For the purposes of this definition,
+  "control" means (i) the power, direct or indirect, to cause the
+  direction or management of such entity, whether by contract or
+  otherwise, or (ii) ownership of fifty percent (50%) or more of the
+  outstanding shares, or (iii) beneficial ownership of such entity.
+
+  "You" (or "Your") shall mean an individual or Legal Entity
+  exercising permissions granted by this License.
+
+  "Source" form shall mean the preferred form for making modifications,
+  including but not limited to software source code, documentation
+  source, and configuration files.
+
+  "Object" form shall mean any form resulting from mechanical
+  transformation or translation of a Source form, including but
+  not limited to compiled object code, generated documentation,
+  and conversions to other media types.
+
+  "Work" shall mean the work of authorship, whether in Source or
+  Object form, made available under the License, as indicated by a
+  copyright notice that is included in or attached to the work
+  (an example is provided in the Appendix below).
+
+  "Derivative Works" shall mean any work, whether in Source or Object
+  form, that is based on (or derived from) the Work and for which the
+  editorial revisions, annotations, elaborations, or other modifications
+  represent, as a whole, an original work of authorship. For the purposes
+  of this License, Derivative Works shall not include works that remain
+  separable from, or merely link (or bind by name) to the interfaces of,
+  the Work and Derivative Works thereof.
+
+  "Contribution" shall mean any work of authorship, including
+  the original version of the Work and any modifications or additions
+  to that Work or Derivative Works thereof, that is intentionally
+  submitted to Licensor for inclusion in the Work by the copyright owner
+  or by an individual or Legal Entity authorized to submit on behalf of
+  the copyright owner. For the purposes of this definition, "submitted"
+  means any form of electronic, verbal, or written communication sent
+  to the Licensor or its representatives, including but not limited to
+  communication on electronic mailing lists, source code control systems,
+  and issue tracking systems that are managed by, or on behalf of, the
+  Licensor for the purpose of discussing and improving the Work, but
+  excluding communication that is conspicuously marked or otherwise
+  designated in writing by the copyright owner as "Not a Contribution."
+
+  "Contributor" shall mean Licensor and any individual or Legal Entity
+  on behalf of whom a Contribution has been received by Licensor and
+  subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  copyright license to reproduce, prepare Derivative Works of,
+  publicly display, publicly perform, sublicense, and distribute the
+  Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  (except as stated in this section) patent license to make, have made,
+  use, offer to sell, sell, import, and otherwise transfer the Work,
+  where such license applies only to those patent claims licensable
+  by such Contributor that are necessarily infringed by their
+  Contribution(s) alone or by combination of their Contribution(s)
+  with the Work to which such Contribution(s) was submitted. If You
+  institute patent litigation against any entity (including a
+  cross-claim or counterclaim in a lawsuit) alleging that the Work
+  or a Contribution incorporated within the Work constitutes direct
+  or contributory patent infringement, then any patent licenses
+  granted to You under this License for that Work shall terminate
+  as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+  Work or Derivative Works thereof in any medium, with or without
+  modifications, and in Source or Object form, provided that You
+  meet the following conditions:
+
+  (a) You must give any other recipients of the Work or
+      Derivative Works a copy of this License; and
+
+  (b) You must cause any modified files to carry prominent notices
+      stating that You changed the files; and
+
+  (c) You must retain, in the Source form of any Derivative Works
+      that You distribute, all copyright, patent, trademark, and
+      attribution notices from the Source form of the Work,
+      excluding those notices that do not pertain to any part of
+      the Derivative Works; and
+
+  (d) If the Work includes a "NOTICE" text file as part of its
+      distribution, then any Derivative Works that You distribute must
+      include a readable copy of the attribution notices contained
+      within such NOTICE file, excluding those notices that do not
+      pertain to any part of the Derivative Works, in at least one
+      of the following places: within a NOTICE text file distributed
+      as part of the Derivative Works; within the Source form or
+      documentation, if provided along with the Derivative Works; or,
+      within a display generated by the Derivative Works, if and
+      wherever such third-party notices normally appear. The contents
+      of the NOTICE file are for informational purposes only and
+      do not modify the License. You may add Your own attribution
+      notices within Derivative Works that You distribute, alongside
+      or as an addendum to the NOTICE text from the Work, provided
+      that such additional attribution notices cannot be construed
+      as modifying the License.
+
+  You may add Your own copyright statement to Your modifications and
+  may provide additional or different license terms and conditions
+  for use, reproduction, or distribution of Your modifications, or
+  for any such Derivative Works as a whole, provided Your use,
+  reproduction, and distribution of the Work otherwise complies with
+  the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+  any Contribution intentionally submitted for inclusion in the Work
+  by You to the Licensor shall be under the terms and conditions of
+  this License, without any additional terms or conditions.
+  Notwithstanding the above, nothing herein shall supersede or modify
+  the terms of any separate license agreement you may have executed
+  with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+  names, trademarks, service marks, or product names of the Licensor,
+  except as required for reasonable and customary use in describing the
+  origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+  agreed to in writing, Licensor provides the Work (and each
+  Contributor provides its Contributions) on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+  implied, including, without limitation, any warranties or conditions
+  of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+  PARTICULAR PURPOSE. You are solely responsible for determining the
+  appropriateness of using or redistributing the Work and assume any
+  risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+  whether in tort (including negligence), contract, or otherwise,
+  unless required by applicable law (such as deliberate and grossly
+  negligent acts) or agreed to in writing, shall any Contributor be
+  liable to You for damages, including any direct, indirect, special,
+  incidental, or consequential damages of any character arising as a
+  result of this License or out of the use or inability to use the
+  Work (including but not limited to damages for loss of goodwill,
+  work stoppage, computer failure or malfunction, or any and all
+  other commercial damages or losses), even if such Contributor
+  has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+  the Work or Derivative Works thereof, You may choose to offer,
+  and charge a fee for, acceptance of support, warranty, indemnity,
+  or other liability obligations and/or rights consistent with this
+  License. However, in accepting such obligations, You may act only
+  on Your own behalf and on Your sole responsibility, not on behalf
+  of any other Contributor, and only if You agree to indemnify,
+  defend, and hold each Contributor harmless for any liability
+  incurred by, or claims asserted against, such Contributor by reason
+  of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+-------------------------------------------------------------------------------
 
 GOOGLE APP ENGINE SDK
 =====================
@@ -33,6 +211,184 @@
 See the License for the specific language governing permissions and
 limitations under the License.
 
+                            Apache License
+                       Version 2.0, January 2004
+                    http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+  "License" shall mean the terms and conditions for use, reproduction,
+  and distribution as defined by Sections 1 through 9 of this document.
+
+  "Licensor" shall mean the copyright owner or entity authorized by
+  the copyright owner that is granting the License.
+
+  "Legal Entity" shall mean the union of the acting entity and all
+  other entities that control, are controlled by, or are under common
+  control with that entity. For the purposes of this definition,
+  "control" means (i) the power, direct or indirect, to cause the
+  direction or management of such entity, whether by contract or
+  otherwise, or (ii) ownership of fifty percent (50%) or more of the
+  outstanding shares, or (iii) beneficial ownership of such entity.
+
+  "You" (or "Your") shall mean an individual or Legal Entity
+  exercising permissions granted by this License.
+
+  "Source" form shall mean the preferred form for making modifications,
+  including but not limited to software source code, documentation
+  source, and configuration files.
+
+  "Object" form shall mean any form resulting from mechanical
+  transformation or translation of a Source form, including but
+  not limited to compiled object code, generated documentation,
+  and conversions to other media types.
+
+  "Work" shall mean the work of authorship, whether in Source or
+  Object form, made available under the License, as indicated by a
+  copyright notice that is included in or attached to the work
+  (an example is provided in the Appendix below).
+
+  "Derivative Works" shall mean any work, whether in Source or Object
+  form, that is based on (or derived from) the Work and for which the
+  editorial revisions, annotations, elaborations, or other modifications
+  represent, as a whole, an original work of authorship. For the purposes
+  of this License, Derivative Works shall not include works that remain
+  separable from, or merely link (or bind by name) to the interfaces of,
+  the Work and Derivative Works thereof.
+
+  "Contribution" shall mean any work of authorship, including
+  the original version of the Work and any modifications or additions
+  to that Work or Derivative Works thereof, that is intentionally
+  submitted to Licensor for inclusion in the Work by the copyright owner
+  or by an individual or Legal Entity authorized to submit on behalf of
+  the copyright owner. For the purposes of this definition, "submitted"
+  means any form of electronic, verbal, or written communication sent
+  to the Licensor or its representatives, including but not limited to
+  communication on electronic mailing lists, source code control systems,
+  and issue tracking systems that are managed by, or on behalf of, the
+  Licensor for the purpose of discussing and improving the Work, but
+  excluding communication that is conspicuously marked or otherwise
+  designated in writing by the copyright owner as "Not a Contribution."
+
+  "Contributor" shall mean Licensor and any individual or Legal Entity
+  on behalf of whom a Contribution has been received by Licensor and
+  subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  copyright license to reproduce, prepare Derivative Works of,
+  publicly display, publicly perform, sublicense, and distribute the
+  Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  (except as stated in this section) patent license to make, have made,
+  use, offer to sell, sell, import, and otherwise transfer the Work,
+  where such license applies only to those patent claims licensable
+  by such Contributor that are necessarily infringed by their
+  Contribution(s) alone or by combination of their Contribution(s)
+  with the Work to which such Contribution(s) was submitted. If You
+  institute patent litigation against any entity (including a
+  cross-claim or counterclaim in a lawsuit) alleging that the Work
+  or a Contribution incorporated within the Work constitutes direct
+  or contributory patent infringement, then any patent licenses
+  granted to You under this License for that Work shall terminate
+  as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+  Work or Derivative Works thereof in any medium, with or without
+  modifications, and in Source or Object form, provided that You
+  meet the following conditions:
+
+  (a) You must give any other recipients of the Work or
+      Derivative Works a copy of this License; and
+
+  (b) You must cause any modified files to carry prominent notices
+      stating that You changed the files; and
+
+  (c) You must retain, in the Source form of any Derivative Works
+      that You distribute, all copyright, patent, trademark, and
+      attribution notices from the Source form of the Work,
+      excluding those notices that do not pertain to any part of
+      the Derivative Works; and
+
+  (d) If the Work includes a "NOTICE" text file as part of its
+      distribution, then any Derivative Works that You distribute must
+      include a readable copy of the attribution notices contained
+      within such NOTICE file, excluding those notices that do not
+      pertain to any part of the Derivative Works, in at least one
+      of the following places: within a NOTICE text file distributed
+      as part of the Derivative Works; within the Source form or
+      documentation, if provided along with the Derivative Works; or,
+      within a display generated by the Derivative Works, if and
+      wherever such third-party notices normally appear. The contents
+      of the NOTICE file are for informational purposes only and
+      do not modify the License. You may add Your own attribution
+      notices within Derivative Works that You distribute, alongside
+      or as an addendum to the NOTICE text from the Work, provided
+      that such additional attribution notices cannot be construed
+      as modifying the License.
+
+  You may add Your own copyright statement to Your modifications and
+  may provide additional or different license terms and conditions
+  for use, reproduction, or distribution of Your modifications, or
+  for any such Derivative Works as a whole, provided Your use,
+  reproduction, and distribution of the Work otherwise complies with
+  the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+  any Contribution intentionally submitted for inclusion in the Work
+  by You to the Licensor shall be under the terms and conditions of
+  this License, without any additional terms or conditions.
+  Notwithstanding the above, nothing herein shall supersede or modify
+  the terms of any separate license agreement you may have executed
+  with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+  names, trademarks, service marks, or product names of the Licensor,
+  except as required for reasonable and customary use in describing the
+  origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+  agreed to in writing, Licensor provides the Work (and each
+  Contributor provides its Contributions) on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+  implied, including, without limitation, any warranties or conditions
+  of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+  PARTICULAR PURPOSE. You are solely responsible for determining the
+  appropriateness of using or redistributing the Work and assume any
+  risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+  whether in tort (including negligence), contract, or otherwise,
+  unless required by applicable law (such as deliberate and grossly
+  negligent acts) or agreed to in writing, shall any Contributor be
+  liable to You for damages, including any direct, indirect, special,
+  incidental, or consequential damages of any character arising as a
+  result of this License or out of the use or inability to use the
+  Work (including but not limited to damages for loss of goodwill,
+  work stoppage, computer failure or malfunction, or any and all
+  other commercial damages or losses), even if such Contributor
+  has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+  the Work or Derivative Works thereof, You may choose to offer,
+  and charge a fee for, acceptance of support, warranty, indemnity,
+  or other liability obligations and/or rights consistent with this
+  License. However, in accepting such obligations, You may act only
+  on Your own behalf and on Your sole responsibility, not on behalf
+  of any other Contributor, and only if You agree to indemnify,
+  defend, and hold each Contributor harmless for any liability
+  incurred by, or claims asserted against, such Contributor by reason
+  of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+-------------------------------------------------------------------------------
 
 WebOb
 =====
@@ -56,6 +412,7 @@
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 
+-------------------------------------------------------------------------------
 
 Werkzeug
 ========
@@ -89,6 +446,7 @@
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+-------------------------------------------------------------------------------
 
 Tornado
 =======
@@ -106,6 +464,184 @@
 License for the specific language governing permissions and limitations
 under the License.
 
+                            Apache License
+                       Version 2.0, January 2004
+                    http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+  "License" shall mean the terms and conditions for use, reproduction,
+  and distribution as defined by Sections 1 through 9 of this document.
+
+  "Licensor" shall mean the copyright owner or entity authorized by
+  the copyright owner that is granting the License.
+
+  "Legal Entity" shall mean the union of the acting entity and all
+  other entities that control, are controlled by, or are under common
+  control with that entity. For the purposes of this definition,
+  "control" means (i) the power, direct or indirect, to cause the
+  direction or management of such entity, whether by contract or
+  otherwise, or (ii) ownership of fifty percent (50%) or more of the
+  outstanding shares, or (iii) beneficial ownership of such entity.
+
+  "You" (or "Your") shall mean an individual or Legal Entity
+  exercising permissions granted by this License.
+
+  "Source" form shall mean the preferred form for making modifications,
+  including but not limited to software source code, documentation
+  source, and configuration files.
+
+  "Object" form shall mean any form resulting from mechanical
+  transformation or translation of a Source form, including but
+  not limited to compiled object code, generated documentation,
+  and conversions to other media types.
+
+  "Work" shall mean the work of authorship, whether in Source or
+  Object form, made available under the License, as indicated by a
+  copyright notice that is included in or attached to the work
+  (an example is provided in the Appendix below).
+
+  "Derivative Works" shall mean any work, whether in Source or Object
+  form, that is based on (or derived from) the Work and for which the
+  editorial revisions, annotations, elaborations, or other modifications
+  represent, as a whole, an original work of authorship. For the purposes
+  of this License, Derivative Works shall not include works that remain
+  separable from, or merely link (or bind by name) to the interfaces of,
+  the Work and Derivative Works thereof.
+
+  "Contribution" shall mean any work of authorship, including
+  the original version of the Work and any modifications or additions
+  to that Work or Derivative Works thereof, that is intentionally
+  submitted to Licensor for inclusion in the Work by the copyright owner
+  or by an individual or Legal Entity authorized to submit on behalf of
+  the copyright owner. For the purposes of this definition, "submitted"
+  means any form of electronic, verbal, or written communication sent
+  to the Licensor or its representatives, including but not limited to
+  communication on electronic mailing lists, source code control systems,
+  and issue tracking systems that are managed by, or on behalf of, the
+  Licensor for the purpose of discussing and improving the Work, but
+  excluding communication that is conspicuously marked or otherwise
+  designated in writing by the copyright owner as "Not a Contribution."
+
+  "Contributor" shall mean Licensor and any individual or Legal Entity
+  on behalf of whom a Contribution has been received by Licensor and
+  subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  copyright license to reproduce, prepare Derivative Works of,
+  publicly display, publicly perform, sublicense, and distribute the
+  Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  (except as stated in this section) patent license to make, have made,
+  use, offer to sell, sell, import, and otherwise transfer the Work,
+  where such license applies only to those patent claims licensable
+  by such Contributor that are necessarily infringed by their
+  Contribution(s) alone or by combination of their Contribution(s)
+  with the Work to which such Contribution(s) was submitted. If You
+  institute patent litigation against any entity (including a
+  cross-claim or counterclaim in a lawsuit) alleging that the Work
+  or a Contribution incorporated within the Work constitutes direct
+  or contributory patent infringement, then any patent licenses
+  granted to You under this License for that Work shall terminate
+  as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+  Work or Derivative Works thereof in any medium, with or without
+  modifications, and in Source or Object form, provided that You
+  meet the following conditions:
+
+  (a) You must give any other recipients of the Work or
+      Derivative Works a copy of this License; and
+
+  (b) You must cause any modified files to carry prominent notices
+      stating that You changed the files; and
+
+  (c) You must retain, in the Source form of any Derivative Works
+      that You distribute, all copyright, patent, trademark, and
+      attribution notices from the Source form of the Work,
+      excluding those notices that do not pertain to any part of
+      the Derivative Works; and
+
+  (d) If the Work includes a "NOTICE" text file as part of its
+      distribution, then any Derivative Works that You distribute must
+      include a readable copy of the attribution notices contained
+      within such NOTICE file, excluding those notices that do not
+      pertain to any part of the Derivative Works, in at least one
+      of the following places: within a NOTICE text file distributed
+      as part of the Derivative Works; within the Source form or
+      documentation, if provided along with the Derivative Works; or,
+      within a display generated by the Derivative Works, if and
+      wherever such third-party notices normally appear. The contents
+      of the NOTICE file are for informational purposes only and
+      do not modify the License. You may add Your own attribution
+      notices within Derivative Works that You distribute, alongside
+      or as an addendum to the NOTICE text from the Work, provided
+      that such additional attribution notices cannot be construed
+      as modifying the License.
+
+  You may add Your own copyright statement to Your modifications and
+  may provide additional or different license terms and conditions
+  for use, reproduction, or distribution of Your modifications, or
+  for any such Derivative Works as a whole, provided Your use,
+  reproduction, and distribution of the Work otherwise complies with
+  the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+  any Contribution intentionally submitted for inclusion in the Work
+  by You to the Licensor shall be under the terms and conditions of
+  this License, without any additional terms or conditions.
+  Notwithstanding the above, nothing herein shall supersede or modify
+  the terms of any separate license agreement you may have executed
+  with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+  names, trademarks, service marks, or product names of the Licensor,
+  except as required for reasonable and customary use in describing the
+  origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+  agreed to in writing, Licensor provides the Work (and each
+  Contributor provides its Contributions) on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+  implied, including, without limitation, any warranties or conditions
+  of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+  PARTICULAR PURPOSE. You are solely responsible for determining the
+  appropriateness of using or redistributing the Work and assume any
+  risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+  whether in tort (including negligence), contract, or otherwise,
+  unless required by applicable law (such as deliberate and grossly
+  negligent acts) or agreed to in writing, shall any Contributor be
+  liable to You for damages, including any direct, indirect, special,
+  incidental, or consequential damages of any character arising as a
+  result of this License or out of the use or inability to use the
+  Work (including but not limited to damages for loss of goodwill,
+  work stoppage, computer failure or malfunction, or any and all
+  other commercial damages or losses), even if such Contributor
+  has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+  the Work or Derivative Works thereof, You may choose to offer,
+  and charge a fee for, acceptance of support, warranty, indemnity,
+  or other liability obligations and/or rights consistent with this
+  License. However, in accepting such obligations, You may act only
+  on Your own behalf and on Your sole responsibility, not on behalf
+  of any other Contributor, and only if You agree to indemnify,
+  defend, and hold each Contributor harmless for any liability
+  incurred by, or claims asserted against, such Contributor by reason
+  of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+-------------------------------------------------------------------------------
 
 Flask
 =====
@@ -142,180 +678,3 @@
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 DAMAGE.
-
-                                Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
diff --git a/lib/webapp2/PKG-INFO b/lib/webapp2/PKG-INFO
index 223dcdc..310c240 100644
--- a/lib/webapp2/PKG-INFO
+++ b/lib/webapp2/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: webapp2
-Version: 2.3
+Version: 2.5.1
 Summary: Taking Google App Engine's webapp to the next level!
 Home-page: http://webapp-improved.appspot.com
 Author: Rodrigo Moraes
@@ -12,7 +12,7 @@
         `webapp2`_ is a lightweight Python web framework compatible with Google App
         Engine's `webapp`_.
         
-        webapp2 is a `single file`_ that follows the simplicity of webapp, but
+        webapp2 is `simple`_. it follows the simplicity of webapp, but
         improves it in some ways: it adds better URI routing and exception handling,
         a full featured response object and a more flexible dispatching mechanism.
         
@@ -36,7 +36,7 @@
         
         .. _webapp: http://code.google.com/appengine/docs/python/tools/webapp/
         .. _webapp2: http://code.google.com/p/webapp-improved/
-        .. _single file: http://code.google.com/p/webapp-improved/source/browse/webapp2.py
+        .. _simple: http://code.google.com/p/webapp-improved/source/browse/webapp2.py
         .. _webapp2_extras: http://webapp-improved.appspot.com/#api-reference-webapp2-extras
         .. _webapp2 features: http://webapp-improved.appspot.com/features.html
         
diff --git a/lib/webapp2/docs/api/extras.protorpc.rst b/lib/webapp2/docs/api/extras.protorpc.rst
deleted file mode 100644
index c3a30d3..0000000
--- a/lib/webapp2/docs/api/extras.protorpc.rst
+++ /dev/null
@@ -1,3 +0,0 @@
-ProtoRPC
-========
-This page moved to :ref:`api.webapp2_extras.protorpc`.
diff --git a/lib/webapp2/docs/api/webapp2_extras/appengine/auth/models.rst b/lib/webapp2/docs/api/webapp2_extras/appengine/auth/models.rst
index 6be04a3..2fb3f46 100644
--- a/lib/webapp2/docs/api/webapp2_extras/appengine/auth/models.rst
+++ b/lib/webapp2/docs/api/webapp2_extras/appengine/auth/models.rst
@@ -6,8 +6,6 @@
 
 A collection of user related models for :ref:`api.webapp2_extras.auth`.
 
-This module requires you to add the ``ndb`` package to your app. See `NDB`_.
-
 .. warning::
    This is an experimental module. The API is subject to changes.
 
diff --git a/lib/webapp2/docs/api/webapp2_extras/protorpc.rst b/lib/webapp2/docs/api/webapp2_extras/protorpc.rst
deleted file mode 100644
index 52bd65b..0000000
--- a/lib/webapp2/docs/api/webapp2_extras/protorpc.rst
+++ /dev/null
@@ -1,25 +0,0 @@
-.. _api.webapp2_extras.protorpc:
-
-ProtoRPC
-========
-.. module:: webapp2_extras.protorpc
-
-``webapp2_extras.protorpc`` makes webapp2 compatible with ProtoRPC services.
-You can register service mappings in a normal webapp2 WSGI application, and it
-will be fully compatible with the ProtoRPC library.
-
-Check the `ProtoRPC documentation`_ or the `ProtoRPC project page`_ for usage
-details.
-
-.. warning::
-   This is an experimental package, as the ProtoRPC API is not stable yet.
-   ``webapp2_extras.protorpc`` is compatible with the ProtoRPC version shipped
-   with the App Engine SDK (since version 1.5.1).
-
-.. autofunction:: service_mapping
-.. autofunction:: get_app
-.. autofunction:: run_services
-
-
-.. _ProtoRPC documentation: http://code.google.com/appengine/docs/python/tools/protorpc/overview.html
-.. _ProtoRPC project page: http://code.google.com/p/google-protorpc/
diff --git a/lib/webapp2/docs/conf.py b/lib/webapp2/docs/conf.py
index d315ff0..e231b05 100644
--- a/lib/webapp2/docs/conf.py
+++ b/lib/webapp2/docs/conf.py
@@ -28,7 +28,6 @@
     theme_path,
     gae_path,
     # All libs used by webapp2 and extras.
-    os.path.join(path, 'lib', 'appengine-ndb-experiment'),
     os.path.join(path, 'lib', 'babel'),
     os.path.join(path, 'lib', 'Jinja2-2.6'),
     os.path.join(path, 'lib', 'Mako-0.4.1'),
@@ -36,9 +35,7 @@
     os.path.join(path, 'lib', 'WebOb-1.0.8'),
     # SDK libs.
     os.path.join(gae_path, 'lib', 'django_0_96'),
-    #os.path.join(gae_path, 'lib', 'webob'),
     os.path.join(gae_path, 'lib', 'yaml', 'lib'),
-    os.path.join(gae_path, 'lib', 'protorpc'),
     os.path.join(gae_path, 'lib', 'simplejson'),
     path,
 ]
@@ -79,9 +76,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = '2.3'
+version = '2.5.1'
 # The full version, including alpha/beta/rc tags.
-release = '2.3'
+release = '2.5.1'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/lib/webapp2/docs/features.rst b/lib/webapp2/docs/features.rst
index 6715e69..76fe15f 100644
--- a/lib/webapp2/docs/features.rst
+++ b/lib/webapp2/docs/features.rst
@@ -240,11 +240,11 @@
     ])
 
 
-Single file, well-tested and documented
----------------------------------------
-webapp2 is an extensively documented `single file <http://code.google.com/p/webapp-improved/source/browse/webapp2.py>`_
-and has almost 100% test coverage. The source code is explicit, magic-free
-and made to be extended. We like less.
+Simple, well-tested and documented
+----------------------------------
+webapp2 is `simple <http://code.google.com/p/webapp-improved/source/browse/webapp2.py>`_,
+extensively documented and has almost 100% test coverage. The source code is
+explicit, magic-free and made to be extended. We like less.
 
 
 Independent of the App Engine SDK
@@ -284,6 +284,6 @@
 - Localization and internationalization support
 - Sessions using secure cookies, memcache or datastore
 - Extra route classes -- to match subdomains and other conveniences
-- Support for third party libraries: Jinja2, Mako and Google's ProtoRPC
+- Support for third party libraries: Jinja2 and Mako
 - Support for threaded environments, so that you can use webapp2 outside of
   App Engine or in the upcoming App Engine Python 2.7 runtime
diff --git a/lib/webapp2/docs/guide/extras.rst b/lib/webapp2/docs/guide/extras.rst
index 1340a74..ba9b98a 100644
--- a/lib/webapp2/docs/guide/extras.rst
+++ b/lib/webapp2/docs/guide/extras.rst
@@ -6,7 +6,7 @@
 - Localization and internationalization support
 - Sessions using secure cookies, memcache or datastore
 - Extra route classes -- to match subdomains and other conveniences
-- Support for third party libraries: Jinja2, Mako and Google's ProtoRPC
+- Support for third party libraries: Jinja2 and Mako
 - Support for threaded environments, so that you can use webapp2 outside of
   App Engine or in the upcoming App Engine Python 2.7 runtime
 
diff --git a/lib/webapp2/docs/guide/response.rst b/lib/webapp2/docs/guide/response.rst
index 83b835d..326426a 100644
--- a/lib/webapp2/docs/guide/response.rst
+++ b/lib/webapp2/docs/guide/response.rst
@@ -39,7 +39,7 @@
 ---------------
 Cookies are set in the response object. The methods to handle cookies are:
 
-set_cookie(key, value='', max_age=None, path='/', domain=None, secure=None, httponly=False, version=None, comment=None)
+set_cookie(key, value='', max_age=None, path='/', domain=None, secure=None, httponly=False, comment=None, expires=None, overwrite=False)
   Sets a cookie.
 
 delete_cookie(key, path='/', domain=None)
@@ -67,6 +67,9 @@
   Cookie name.
 value
   Cookie value.
+expires
+  An expiration date. Must be a :py:mod:`datetime`.datetime object. Use this
+  instead of max_age since the former is not supported by Internet Explorer.
 max_age
   Cookie max age in seconds.
 path
@@ -77,10 +80,11 @@
   If True, the cookie is only available via HTTPS.
 httponly
   Disallow JavaScript to access the cookie.
-version
-  Defines a cookie version number.
 comment
   Defines a cookie comment.
+overwrite
+  If true, overwrites previously set (and not yet sent to the client) cookies
+  with the same name.
 
 .. seealso::
    :ref:`How to read cookies from the request object <guide.request.cookies>`
diff --git a/lib/webapp2/docs/guide/routing.rst b/lib/webapp2/docs/guide/routing.rst
index 7ef5e0b..48919fd 100644
--- a/lib/webapp2/docs/guide/routing.rst
+++ b/lib/webapp2/docs/guide/routing.rst
@@ -95,7 +95,7 @@
     ])
 
 The first argument in the routes above is a
-:ref:`regex template <guide.routing.the-regex-template>`, the `handler`
+:ref:`URL template <guide.routing.the-url-template>`, the `handler`
 argument is the :ref:`request handler <guide.handlers>` to be used, and the
 `name` argument third is a name used to
 :ref:`build a URI <guide.routing.building-uris>` for that route.
@@ -104,12 +104,14 @@
 accepted by the ``Route`` constructor. We will explain some of them in details
 below.
 
-.. _guide.routing.the-regex-template:
+.. _guide.routing.the-url-template:
 
-The regex template
-~~~~~~~~~~~~~~~~~~
-The regex template can have variables enclosed by ``<>`` that define a name, a
-regular expression or both. Examples:
+The URL template
+~~~~~~~~~~~~~~~~
+The URL template defines the URL path to be matched. It can have regular
+expressions for variables using the syntax ``<name:regex>``; everything
+outside of ``<>`` is not interpreted as a regular expression to be matched.
+Both name and regex are optional, like in the examples below:
 
 =================  ==================================
 Format             Example
@@ -121,8 +123,9 @@
 
 The same template can mix parts with name, regular expression or both.
 
-If the name is set, the value of the matched regular expression is passed as
-keyword argument to the handler. Otherwise it is passed as positional argument.
+The name, if defined, is used to build URLs for the route. When it is set,
+the value of the matched regular expression is passed as keyword argument to
+the handler. Otherwise it is passed as positional argument.
 
 If only the name is set, it will match anything except a slash. So these
 routes are equivalent::
diff --git a/lib/webapp2/docs/index.rst b/lib/webapp2/docs/index.rst
index eb17cc7..f293e99 100644
--- a/lib/webapp2/docs/index.rst
+++ b/lib/webapp2/docs/index.rst
@@ -10,7 +10,7 @@
 `webapp2`_ is a lightweight Python web framework compatible with Google App
 Engine's `webapp`_.
 
-webapp2 is a `single file`_ that follows the simplicity of webapp, but improves
+webapp2 is a `simple`_. it follows the simplicity of webapp, but improves
 it in some ways: it adds better URI routing and exception handling, a full
 featured response object and a more flexible dispatching mechanism.
 
@@ -23,6 +23,11 @@
 
 For a complete description of how webapp2 improves webapp, see :ref:`features`.
 
+.. note::
+   webapp2 is part of the Python 2.7 runtime since App Engine SDK 1.6.0.
+   To include it in your app see
+   `Configuring Libraries <http://code.google.com/appengine/docs/python/python27/using27.html#Configuring_Libraries>`_.
+
 
 Quick links
 -----------
@@ -83,7 +88,6 @@
    api/webapp2_extras/json.rst
    api/webapp2_extras/local.rst
    api/webapp2_extras/mako.rst
-   api/webapp2_extras/protorpc.rst
    api/webapp2_extras/routes.rst
    api/webapp2_extras/securecookie.rst
    api/webapp2_extras/security.rst
@@ -132,7 +136,6 @@
    api/extras.local.rst
    api/extras.local_app.rst
    api/extras.mako.rst
-   api/extras.protorpc.rst
    api/extras.routes.rst
    api/extras.securecookie.rst
    api/extras.security.rst
@@ -195,7 +198,7 @@
 
 .. _webapp: http://code.google.com/appengine/docs/python/tools/webapp/
 .. _webapp2: http://code.google.com/p/webapp-improved/
-.. _single file: http://code.google.com/p/webapp-improved/source/browse/webapp2.py
+.. _simple: http://code.google.com/p/webapp-improved/source/browse/webapp2.py
 .. _WebOb: http://docs.webob.org/
 .. _Werkzeug: http://werkzeug.pocoo.org/
 .. _Tipfy: http://www.tipfy.org/
diff --git a/lib/webapp2/docs/tutorials/gettingstarted/helloworld.rst b/lib/webapp2/docs/tutorials/gettingstarted/helloworld.rst
index 9381139..9657d31 100644
--- a/lib/webapp2/docs/tutorials/gettingstarted/helloworld.rst
+++ b/lib/webapp2/docs/tutorials/gettingstarted/helloworld.rst
@@ -41,8 +41,9 @@
 
    application: helloworld
    version: 1
-   runtime: python
+   runtime: python27
    api_version: 1
+   threadsafe: true
 
    handlers:
    - url: /.*
diff --git a/lib/webapp2/docs/tutorials/gettingstarted/staticfiles.rst b/lib/webapp2/docs/tutorials/gettingstarted/staticfiles.rst
index 3512943..7d499a3 100644
--- a/lib/webapp2/docs/tutorials/gettingstarted/staticfiles.rst
+++ b/lib/webapp2/docs/tutorials/gettingstarted/staticfiles.rst
@@ -22,15 +22,16 @@
 
    application: helloworld
    version: 1
-   runtime: python
+   runtime: python27
    api_version: 1
+   threadsafe: true
 
    handlers:
    - url: /stylesheets
      static_dir: stylesheets
 
    - url: /.*
-     script: helloworld.py
+     script: helloworld.app
 
 The new ``handlers`` section defines two handlers for URLs. When App Engine
 receives a request with a URL beginning with ``/stylesheets``, it maps the
diff --git a/lib/webapp2/docs/tutorials/gettingstarted/usingwebapp2.rst b/lib/webapp2/docs/tutorials/gettingstarted/usingwebapp2.rst
index aac3614..fec3118 100644
--- a/lib/webapp2/docs/tutorials/gettingstarted/usingwebapp2.rst
+++ b/lib/webapp2/docs/tutorials/gettingstarted/usingwebapp2.rst
@@ -49,11 +49,19 @@
         ('/', MainPage)
     ], debug=True)
 
-    def main():
-        application.run()
+Also edit ``app.yaml`` and replace its contents with the following:
 
-    if __name__ == "__main__":
-        main()
+.. code-block:: yaml
+
+   application: helloworld
+   version: 1
+   runtime: python27
+   api_version: 1
+   threadsafe: true
+
+   handlers:
+   - url: /.*
+     script: helloworld.app
 
 Reload `http://localhost:8080/ <http://localhost:8080/>`_ in your browser to
 see the new version in action (if you stopped your web server, restart it by
diff --git a/lib/webapp2/docs/tutorials/quickstart.rst b/lib/webapp2/docs/tutorials/quickstart.rst
index e94e23c..08d19f5 100644
--- a/lib/webapp2/docs/tutorials/quickstart.rst
+++ b/lib/webapp2/docs/tutorials/quickstart.rst
@@ -23,6 +23,11 @@
 features such as sessions, extra routes, localization, internationalization
 and more, also add the ``webapp2_extras`` directory to your app.
 
+.. note::
+   webapp2 is part of the Python 2.7 runtime since App Engine SDK 1.6.0,
+   so you don't need to upload it with your app anymore. To include it in
+   your app see
+   `Configuring Libraries <http://code.google.com/appengine/docs/python/python27/using27.html#Configuring_Libraries>`_.
 
 Hello, webapp2!
 ---------------
@@ -30,14 +35,15 @@
 
 .. code-block:: yaml
 
-   application: hellowebapp2
+   application: helloworld
    version: 1
-   runtime: python
+   runtime: python27
    api_version: 1
+   threadsafe: true
 
    handlers:
    - url: /.*
-     script: main.py
+     script: main.app
 
 Then create a file ``main.py`` and define a handler to display a
 'Hello, webapp2!' message::
@@ -52,12 +58,6 @@
         ('/', HelloWebapp2),
     ], debug=True)
 
-    def main():
-        app.run()
-
-    if __name__ == '__main__':
-        main()
-
 
 Test your app
 -------------
diff --git a/lib/webapp2/run_tests.py b/lib/webapp2/run_tests.py
index 8358d92..e9ee49a 100644
--- a/lib/webapp2/run_tests.py
+++ b/lib/webapp2/run_tests.py
@@ -11,7 +11,6 @@
     tests_path,
     gae_path,
     # All libs used by webapp2 and extras.
-    os.path.join(current_path, 'lib', 'appengine-ndb-experiment'),
     os.path.join(current_path, 'lib', 'babel'),
     os.path.join(current_path, 'lib', 'Jinja2-2.6'),
     os.path.join(current_path, 'lib', 'Mako-0.4.1'),
diff --git a/lib/webapp2/setup.py b/lib/webapp2/setup.py
index 58ac98f..c1d06eb 100644
--- a/lib/webapp2/setup.py
+++ b/lib/webapp2/setup.py
@@ -5,7 +5,7 @@
 `webapp2`_ is a lightweight Python web framework compatible with Google App
 Engine's `webapp`_.
 
-webapp2 is a `single file`_ that follows the simplicity of webapp, but
+webapp2 is `simple`_. it follows the simplicity of webapp, but
 improves it in some ways: it adds better URI routing and exception handling,
 a full featured response object and a more flexible dispatching mechanism.
 
@@ -29,7 +29,7 @@
 
 .. _webapp: http://code.google.com/appengine/docs/python/tools/webapp/
 .. _webapp2: http://code.google.com/p/webapp-improved/
-.. _single file: http://code.google.com/p/webapp-improved/source/browse/webapp2.py
+.. _simple: http://code.google.com/p/webapp-improved/source/browse/webapp2.py
 .. _webapp2_extras: http://webapp-improved.appspot.com/#api-reference-webapp2-extras
 .. _webapp2 features: http://webapp-improved.appspot.com/features.html
 """
@@ -37,7 +37,7 @@
 
 setup(
     name = 'webapp2',
-    version = '2.3',
+    version = '2.5.1',
     license = 'Apache Software License',
     url = 'http://webapp-improved.appspot.com',
     description = "Taking Google App Engine's webapp to the next level!",
diff --git a/lib/webapp2/tests/extras_appengine_auth_models_test.py b/lib/webapp2/tests/extras_appengine_auth_models_test.py
index 92a5201..4d43c9f 100644
--- a/lib/webapp2/tests/extras_appengine_auth_models_test.py
+++ b/lib/webapp2/tests/extras_appengine_auth_models_test.py
@@ -1,7 +1,7 @@
 from webapp2_extras import auth
 from webapp2_extras.appengine.auth import models
 
-from ndb import model
+from google.appengine.ext.ndb import model
 
 import test_base
 
@@ -80,6 +80,26 @@
         self.assertEqual(success, False)
         self.assertEqual(info, extras)
 
+    def test_add_auth_ids(self):
+        m = models.User
+        success, new_user = m.create_user(auth_id='auth_id_1', password_raw='foo')
+        self.assertEqual(success, True)
+        self.assertTrue(new_user is not None)
+        self.assertTrue(new_user.password is not None)
+
+        success, new_user_2 = m.create_user(auth_id='auth_id_2', password_raw='foo')
+        self.assertEqual(success, True)
+        self.assertTrue(new_user is not None)
+        self.assertTrue(new_user.password is not None)
+
+        success, info = new_user.add_auth_id('auth_id_3')
+        self.assertEqual(success, True)
+        self.assertEqual(info.auth_ids, ['auth_id_1', 'auth_id_3'])
+
+        success, info = new_user.add_auth_id('auth_id_2')
+        self.assertEqual(success, False)
+        self.assertEqual(info, ['auth_id'])
+
     def test_token(self):
         m = models.UserToken
 
diff --git a/lib/webapp2/tests/extras_appengine_sessions_ndb_test.py b/lib/webapp2/tests/extras_appengine_sessions_ndb_test.py
index 711cb6a..3fc5963 100644
--- a/lib/webapp2/tests/extras_appengine_sessions_ndb_test.py
+++ b/lib/webapp2/tests/extras_appengine_sessions_ndb_test.py
@@ -158,9 +158,6 @@
 
     def test_misc(self):
 
-        p = sessions_ndb.PickledProperty(dict)
-        self.assertRaises(datastore_errors.BadValueError, p._validate, ['foo'])
-
         s = sessions_ndb.Session(id='foo')
         key = s.put()
 
diff --git a/lib/webapp2/tests/extras_auth_test.py b/lib/webapp2/tests/extras_auth_test.py
index 48f57af..29ea63f 100644
--- a/lib/webapp2/tests/extras_auth_test.py
+++ b/lib/webapp2/tests/extras_auth_test.py
@@ -4,7 +4,7 @@
 from webapp2_extras import auth
 from webapp2_extras.appengine.auth import models
 
-from ndb import model
+from google.appengine.ext.ndb import model
 
 import test_base
 
diff --git a/lib/webapp2/tests/extras_protorpc_test.py b/lib/webapp2/tests/extras_protorpc_test.py
deleted file mode 100644
index fbd90b0..0000000
--- a/lib/webapp2/tests/extras_protorpc_test.py
+++ /dev/null
@@ -1,196 +0,0 @@
-# -*- coding: utf-8 -*-
-import webapp2
-
-import test_base
-
-from protorpc import messages
-from protorpc import remote
-from protorpc.webapp import service_handlers
-
-from webapp2_extras import protorpc
-
-# Hello service ---------------------------------------------------------------
-
-class HelloRequest(messages.Message):
-    my_name = messages.StringField(1, required=True)
-
-class HelloResponse(messages.Message):
-    hello = messages.StringField(1, required=True)
-
-class HelloService(remote.Service):
-    @remote.method(HelloRequest, HelloResponse)
-    def hello(self, request):
-        return HelloResponse(hello='Hello, %s!' %
-                             request.my_name)
-
-    @remote.method(HelloRequest, HelloResponse)
-    def hello_error(self, request):
-        raise ValueError()
-
-class AhoyService(remote.Service):
-    @remote.method(HelloRequest, HelloResponse)
-    def ahoy(self, request):
-        return HelloResponse(hello='Ahoy, %s!' %
-                             request.my_name)
-
-class HolaService(remote.Service):
-    @remote.method(HelloRequest, HelloResponse)
-    def hola(self, request):
-        return HelloResponse(hello='Hola, %s!' %
-                             request.my_name)
-
-service_mappings = protorpc.service_mapping([
-    ('/hello', HelloService),
-    AhoyService,
-])
-app = webapp2.WSGIApplication(service_mappings)
-
-service_mappings2 = protorpc.service_mapping({
-    '/hola': HolaService,
-})
-app2 = webapp2.WSGIApplication(service_mappings2)
-
-# Tests -----------------------------------------------------------------------
-
-class TestProtoRPC(test_base.BaseTestCase):
-
-    def test_example(self):
-        req = webapp2.Request.blank('/hello.hello')
-        req.method = 'POST'
-        req.headers['Content-Type'] = 'application/json'
-        req.body = '{"my_name": "bob"}'
-
-        rsp = req.get_response(app)
-        self.assertEqual(rsp.status_int, 200)
-        self.assertEqual(rsp.body, '{"hello": "Hello, bob!"}')
-
-    def test_run_services(self):
-        import os
-        os.environ['REQUEST_METHOD'] = 'POST'
-        os.environ['PATH_INFO'] = '/hello.hello'
-        protorpc.run_services([('/hello', HelloService)])
-
-    def test_ahoy(self):
-        req = webapp2.Request.blank('/extras_protorpc_test/AhoyService.ahoy')
-        req.method = 'POST'
-        req.headers['Content-Type'] = 'application/json'
-        req.body = '{"my_name": "bob"}'
-
-        rsp = req.get_response(app)
-        self.assertEqual(rsp.status_int, 200)
-        self.assertEqual(rsp.body, '{"hello": "Ahoy, bob!"}')
-
-    def test_hola(self):
-        req = webapp2.Request.blank('/hola.hola')
-        req.method = 'POST'
-        req.headers['Content-Type'] = 'application/json'
-        req.body = '{"my_name": "bob"}'
-
-        rsp = req.get_response(app2)
-        self.assertEqual(rsp.status_int, 200)
-        self.assertEqual(rsp.body, '{"hello": "Hola, bob!"}')
-
-    def test_unrecognized_rpc_format(self):
-        # No content type
-        req = webapp2.Request.blank('/hello.hello')
-        req.method = 'POST'
-        req.body = '{"my_name": "bob"}'
-
-        rsp = req.get_response(app)
-        self.assertEqual(rsp.status_int, 400)
-
-        # Invalid content type
-        req = webapp2.Request.blank('/hello.hello')
-        req.method = 'POST'
-        req.headers['Content-Type'] = 'text/xml'
-        req.body = '{"my_name": "bob"}'
-
-        rsp = req.get_response(app)
-        self.assertEqual(rsp.status_int, 415)
-
-        # Bad request method
-        req = webapp2.Request.blank('/hello.hello')
-        req.method = 'PUT'
-        req.headers['Content-Type'] = 'application/json'
-        req.body = '{"my_name": "bob"}'
-
-        rsp = req.get_response(app)
-        self.assertEqual(rsp.status_int, 405)
-
-    def test_invalid_method(self):
-        # Bad request method
-        req = webapp2.Request.blank('/hello.ahoy')
-        req.method = 'POST'
-        req.headers['Content-Type'] = 'application/json'
-        req.body = '{"my_name": "bob"}'
-
-        rsp = req.get_response(app)
-        self.assertEqual(rsp.status_int, 400)
-
-    def test_invalid_json(self):
-        # Bad request method
-        req = webapp2.Request.blank('/hello.hello')
-        req.method = 'POST'
-        req.headers['Content-Type'] = 'application/json'
-        req.body = '"my_name": "bob"'
-
-        rsp = req.get_response(app)
-        self.assertEqual(rsp.status_int, 500)
-
-    def test_response_error(self):
-        # Bad request method
-        req = webapp2.Request.blank('/hello.hello_error')
-        req.method = 'POST'
-        req.headers['Content-Type'] = 'application/json'
-        req.body = '{"my_name": "bob"}'
-
-        rsp = req.get_response(app)
-        self.assertEqual(rsp.status_int, 500)
-
-    def test_invalid_paths(self):
-        # Not starting with slash.
-        #self.assertRaises(ValueError, protorpc.service_mapping, [
-        #    ('hello', HelloService),
-        #])
-        # Trailing slash.
-        self.assertRaises(ValueError, protorpc.service_mapping, [
-            ('/hello/', HelloService),
-        ])
-        # Double paths.
-        self.assertRaises(protorpc.service_handlers.ServiceConfigurationError,
-            protorpc.service_mapping, [
-                ('/hello', HelloService),
-                ('/hello', HelloService),
-            ]
-        )
-
-    def test_lazy_services(self):
-        service_mappings = protorpc.service_mapping([
-            ('/bonjour', 'resources.protorpc_services.BonjourService'),
-            'resources.protorpc_services.CiaoService',
-        ])
-        app = webapp2.WSGIApplication(service_mappings)
-
-        # Bonjour
-        req = webapp2.Request.blank('/bonjour.bonjour')
-        req.method = 'POST'
-        req.headers['Content-Type'] = 'application/json'
-        req.body = '{"my_name": "bob"}'
-
-        rsp = req.get_response(app)
-        self.assertEqual(rsp.status_int, 200)
-        self.assertEqual(rsp.body, '{"hello": "Bonjour, bob!"}')
-
-        # Ciao
-        req = webapp2.Request.blank('/resources/protorpc_services/CiaoService.ciao')
-        req.method = 'POST'
-        req.headers['Content-Type'] = 'application/json'
-        req.body = '{"my_name": "bob"}'
-
-        rsp = req.get_response(app)
-        self.assertEqual(rsp.status_int, 200)
-        self.assertEqual(rsp.body, '{"hello": "Ciao, bob!"}')
-
-
-if __name__ == '__main__':
-    test_base.main()
diff --git a/lib/webapp2/tests/handler_test.py b/lib/webapp2/tests/handler_test.py
index 99203e3..52b9fa2 100644
--- a/lib/webapp2/tests/handler_test.py
+++ b/lib/webapp2/tests/handler_test.py
@@ -133,7 +133,7 @@
     webapp2.Route('/methods', MethodsHandler, name='methods'),
     webapp2.Route('/broken', BrokenHandler),
     webapp2.Route('/broken-but-fixed', BrokenButFixedHandler),
-    webapp2.Route('/<year:\d{4}>/<month:\d\d>/<name>', None, name='route-test'),
+    webapp2.Route('/<year:\d{4}>/<month:\d{1,2}>/<name>', None, name='route-test'),
     webapp2.Route('/<:\d\d>/<:\d{2}>/<:\w+>', PositionalHandler, name='positional'),
     webapp2.Route('/redirect-me', webapp2.RedirectHandler, defaults={'_uri': '/broken'}),
     webapp2.Route('/redirect-me2', webapp2.RedirectHandler, defaults={'_uri': get_redirect_url}),
@@ -215,9 +215,9 @@
         app = webapp2.WSGIApplication([
             webapp2.Route('/broken', BrokenHandler),
         ], debug=True)
-
         req = webapp2.Request.blank('/broken')
-        self.assertRaises(ValueError, req.get_response, app)
+        rsp = req.get_response(app)
+        self.assertEqual(rsp.status_int, 500)
 
     def test_custom_error_handlers(self):
         app.error_handlers = {
@@ -420,6 +420,7 @@
             self.assertEqual(func('methods', _scheme='https', _full=False), 'https://localhost:80/methods')
             self.assertEqual(func('methods', _scheme='https', _fragment='my-anchor'), 'https://localhost:80/methods#my-anchor')
 
+            self.assertEqual(func('route-test', year='2010', month='0', name='test'), '/2010/0/test')
             self.assertEqual(func('route-test', year='2010', month='07', name='test'), '/2010/07/test')
             self.assertEqual(func('route-test', year='2010', month='07', name='test', foo='bar'), '/2010/07/test?foo=bar')
             self.assertEqual(func('route-test', _fragment='my-anchor', year='2010', month='07', name='test', foo='bar'), '/2010/07/test?foo=bar#my-anchor')
@@ -518,7 +519,8 @@
         app.error_handlers[500] = handle_exception
 
         req = webapp2.Request.blank('/')
-        self.assertRaises(ValueError, req.get_response, app)
+        rsp = req.get_response(app)
+        self.assertEqual(rsp.status_int, 500)
 
     def test_function_handler(self):
         def my_view(request, *args, **kwargs):
diff --git a/lib/webapp2/tests/request_test.py b/lib/webapp2/tests/request_test.py
index 0b0f8e0..dac45b8 100644
--- a/lib/webapp2/tests/request_test.py
+++ b/lib/webapp2/tests/request_test.py
@@ -54,6 +54,12 @@
         self.assertEqual(req.content_type, 'application/json')
         self.assertEqual(req.charset, 'iso-8859-1')
 
+        req = webapp2.Request.blank('/', environ={
+            'CONTENT_TYPE': 'application/json',
+        })
+        self.assertEqual(req.content_type, 'application/json')
+        self.assertEqual(req.charset.lower(), 'utf-8')
+
         match = webapp2._charset_re.search('text/html')
         if match:
             charset = match.group(1).lower().strip().strip('"').strip()
diff --git a/lib/webapp2/webapp2.egg-info/PKG-INFO b/lib/webapp2/webapp2.egg-info/PKG-INFO
index 223dcdc..310c240 100644
--- a/lib/webapp2/webapp2.egg-info/PKG-INFO
+++ b/lib/webapp2/webapp2.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: webapp2
-Version: 2.3
+Version: 2.5.1
 Summary: Taking Google App Engine's webapp to the next level!
 Home-page: http://webapp-improved.appspot.com
 Author: Rodrigo Moraes
@@ -12,7 +12,7 @@
         `webapp2`_ is a lightweight Python web framework compatible with Google App
         Engine's `webapp`_.
         
-        webapp2 is a `single file`_ that follows the simplicity of webapp, but
+        webapp2 is `simple`_. it follows the simplicity of webapp, but
         improves it in some ways: it adds better URI routing and exception handling,
         a full featured response object and a more flexible dispatching mechanism.
         
@@ -36,7 +36,7 @@
         
         .. _webapp: http://code.google.com/appengine/docs/python/tools/webapp/
         .. _webapp2: http://code.google.com/p/webapp-improved/
-        .. _single file: http://code.google.com/p/webapp-improved/source/browse/webapp2.py
+        .. _simple: http://code.google.com/p/webapp-improved/source/browse/webapp2.py
         .. _webapp2_extras: http://webapp-improved.appspot.com/#api-reference-webapp2-extras
         .. _webapp2 features: http://webapp-improved.appspot.com/features.html
         
diff --git a/lib/webapp2/webapp2.egg-info/SOURCES.txt b/lib/webapp2/webapp2.egg-info/SOURCES.txt
index 826790e..1d40ccf 100644
--- a/lib/webapp2/webapp2.egg-info/SOURCES.txt
+++ b/lib/webapp2/webapp2.egg-info/SOURCES.txt
@@ -31,7 +31,6 @@
 docs/api/extras.local.rst
 docs/api/extras.local_app.rst
 docs/api/extras.mako.rst
-docs/api/extras.protorpc.rst
 docs/api/extras.routes.rst
 docs/api/extras.securecookie.rst
 docs/api/extras.security.rst
@@ -49,7 +48,6 @@
 docs/api/webapp2_extras/local.rst
 docs/api/webapp2_extras/local_app.rst
 docs/api/webapp2_extras/mako.rst
-docs/api/webapp2_extras/protorpc.rst
 docs/api/webapp2_extras/routes.rst
 docs/api/webapp2_extras/securecookie.rst
 docs/api/webapp2_extras/security.rst
@@ -97,7 +95,6 @@
 tests/extras_json_test.py
 tests/extras_local_app_test.py
 tests/extras_mako_test.py
-tests/extras_protorpc_test.py
 tests/extras_routes_test.py
 tests/extras_securecookie_test.py
 tests/extras_security_test.py
@@ -134,7 +131,6 @@
 webapp2_extras/local.py
 webapp2_extras/local_app.py
 webapp2_extras/mako.py
-webapp2_extras/protorpc.py
 webapp2_extras/routes.py
 webapp2_extras/securecookie.py
 webapp2_extras/security.py
diff --git a/lib/webapp2/webapp2.py b/lib/webapp2/webapp2.py
index 04c05cb..6bbdb64 100644
--- a/lib/webapp2/webapp2.py
+++ b/lib/webapp2/webapp2.py
@@ -17,6 +17,7 @@
 import re
 import sys
 import threading
+import traceback
 import urllib
 import urlparse
 from wsgiref import handlers
@@ -26,34 +27,34 @@
 
 _webapp = _webapp_util = _local = None
 
-try:  # pragma: no cover
+try: # pragma: no cover
     # WebOb < 1.0 (App Engine Python 2.5).
     from webob.statusreasons import status_reasons
     from webob.headerdict import HeaderDict as BaseResponseHeaders
-except ImportError:  # pragma: no cover
+except ImportError: # pragma: no cover
     # WebOb >= 1.0.
     from webob.util import status_reasons
     from webob.headers import ResponseHeaders as BaseResponseHeaders
 
 # google.appengine.ext.webapp imports webapp2 in the
 # App Engine Python 2.7 runtime.
-if os.environ.get('APPENGINE_RUNTIME') != 'python27':  # pragma: no cover
+if os.environ.get('APPENGINE_RUNTIME') != 'python27': # pragma: no cover
     try:
         from google.appengine.ext import webapp as _webapp
-    except ImportError:  # pragma: no cover
+    except ImportError: # pragma: no cover
         # Running webapp2 outside of GAE.
         pass
 
-try:  # pragma: no cover
+try: # pragma: no cover
     # Thread-local variables container.
     from webapp2_extras import local
     _local = local.Local()
-except ImportError:  # pragma: no cover
+except ImportError: # pragma: no cover
     logging.warning("webapp2_extras.local is not available "
                     "so webapp2 won't be thread-safe!")
 
 
-__version_info__ = (2, 3)
+__version_info__ = (2, 5, 1)
 __version__ = '.'.join(str(n) for n in __version_info__)
 
 #: Base HTTP exception, set here as public interface.
@@ -69,6 +70,30 @@
 #: Regex extract charset from environ.
 _charset_re = re.compile(r';\s*charset=([^;]*)', re.I)
 
+#: To show exceptions in debug mode.
+_debug_template = """<html>
+  <head>
+    <title>Internal Server Error</title>
+    <style>
+      body {
+        padding: 20px;
+        font-family: arial, sans-serif;
+        font-size: 14px;
+      }
+      pre {
+        background: #F2F2F2;
+        padding: 10px;
+      }
+    </style>
+  </head>
+  <body>
+    <h1>Internal Server Error</h1>
+    <p>The server has either erred or is incapable of performing
+    the requested operation.</p>
+    <pre>%s</pre>
+  </body>
+</html>"""
+
 # Set same default messages from webapp plus missing ones.
 _webapp_status_reasons = {
     203: 'Non-Authoritative Information',
@@ -116,17 +141,17 @@
         :param environ:
             A WSGI-compliant environment dictionary.
         """
-        if kwargs.get('charset') is None:
+        if kwargs.get('charset') is None and not hasattr(webob, '__version__'):
+            # webob 0.9 didn't have a __version__ attribute and also defaulted
+            # to None rather than UTF-8 if no charset was provided. Providing a
+            # default charset is required for backwards compatibility.
             match = _charset_re.search(environ.get('CONTENT_TYPE', ''))
             if match:
                 charset = match.group(1).lower().strip().strip('"').strip()
             else:
                 charset = 'utf-8'
-
             kwargs['charset'] = charset
 
-        kwargs.setdefault('unicode_errors', 'ignore')
-        kwargs.setdefault('decode_param_names', True)
         super(Request, self).__init__(environ, *args, **kwargs)
         self.registry = {}
 
@@ -235,7 +260,7 @@
 
     @classmethod
     def blank(cls, path, environ=None, base_url=None,
-              headers=None, **kwargs):  # pragma: no cover
+              headers=None, **kwargs): # pragma: no cover
         """Adds parameters compatible with WebOb >= 1.0: POST and **kwargs."""
         try:
             return super(Request, cls).blank(path, environ=environ,
@@ -997,7 +1022,7 @@
         values = {}
         for name, regex in variables.iteritems():
             value = kwargs.pop(name, self.defaults.get(name))
-            if not value:
+            if value is None:
                 raise KeyError('Missing argument "%s" to build URI.' % \
                     name.strip('_'))
 
@@ -1470,18 +1495,18 @@
         :param request:
             A :class:`Request` instance.
         """
-        if _local is not None:  # pragma: no cover
+        if _local is not None: # pragma: no cover
             _local.app = app
             _local.request = request
-        else:  # pragma: no cover
+        else: # pragma: no cover
             WSGIApplication.app = WSGIApplication.active_instance = app
             WSGIApplication.request = request
 
     def clear_globals(self):
         """Clears global variables. See :meth:`set_globals`."""
-        if _local is not None:  # pragma: no cover
+        if _local is not None: # pragma: no cover
             _local.__release_local__()
-        else:  # pragma: no cover
+        else: # pragma: no cover
             WSGIApplication.app = WSGIApplication.active_instance = None
             WSGIApplication.request = None
 
@@ -1527,7 +1552,9 @@
         """Last resource error for :meth:`__call__`."""
         logging.exception(exception)
         if self.debug:
-            raise
+            lines = ''.join(traceback.format_exception(*sys.exc_info()))
+            html = _debug_template % (cgi.escape(lines, quote=True))
+            return Response(body=html, status=500)
 
         return exc.HTTPInternalServerError()
 
@@ -1549,7 +1576,7 @@
 
         :param request:
             A :class:`Request` instance.
-        :param request:
+        :param response:
             A :class:`Response` instance.
         :param e:
             The uncaught exception.
@@ -1588,7 +1615,7 @@
                 _webapp_util.run_bare_wsgi_app(self)
             else:
                 _webapp_util.run_wsgi_app(self)
-        else:  # pragma: no cover
+        else: # pragma: no cover
             handlers.CGIHandler().run(self)
 
     def get_response(self, *args, **kwargs):
@@ -1939,7 +1966,7 @@
 
 def _set_thread_safe_app():
     """Assigns WSGIApplication globals to a proxy pointing to thread-local."""
-    if _local is not None:  # pragma: no cover
+    if _local is not None: # pragma: no cover
         WSGIApplication.app = WSGIApplication.active_instance = _local('app')
         WSGIApplication.request = _local('request')
 
@@ -1956,5 +1983,5 @@
 # runtime imports this module to provide its public interface.
 try:
     from google.appengine.ext.webapp import util as _webapp_util
-except ImportError:  # pragma: no cover
+except ImportError: # pragma: no cover
     pass
diff --git a/lib/webapp2/webapp2_extras/appengine/auth/models.py b/lib/webapp2/webapp2_extras/appengine/auth/models.py
index a9be319..ec815a6 100644
--- a/lib/webapp2/webapp2_extras/appengine/auth/models.py
+++ b/lib/webapp2/webapp2_extras/appengine/auth/models.py
@@ -10,7 +10,10 @@
 """
 import time
 
-from ndb import model
+try:
+    from ndb import model
+except ImportError: # pragma: no cover
+    from google.appengine.ext.ndb import model
 
 from webapp2_extras import auth
 from webapp2_extras import security
@@ -218,6 +221,29 @@
         """Returns this user's unique ID, which can be an integer or string."""
         return self._key.id()
 
+    def add_auth_id(self, auth_id):
+        """A helper method to add additional auth ids to a User
+
+        :param auth_id:
+            String representing a unique id for the user. Examples:
+
+            - own:username
+            - google:username
+        :returns:
+            A tuple (boolean, info). The boolean indicates if the user
+            was saved. If creation succeeds, ``info`` is the user entity;
+            otherwise it is a list of duplicated unique properties that
+            caused creation to fail.
+        """
+        self.auth_ids.append(auth_id)
+        unique = '%s.auth_id:%s' % (self.__class__.__name__, auth_id)
+        ok = self.unique_model.create(unique)
+        if ok:
+            self.put()
+            return True, self
+        else:
+            return False, ['auth_id']
+
     @classmethod
     def get_by_auth_id(cls, auth_id):
         """Returns a user object based on a auth_id.
diff --git a/lib/webapp2/webapp2_extras/appengine/sessions_ndb.py b/lib/webapp2/webapp2_extras/appengine/sessions_ndb.py
index 03d62a0..c871f5b 100644
--- a/lib/webapp2/webapp2_extras/appengine/sessions_ndb.py
+++ b/lib/webapp2/webapp2_extras/appengine/sessions_ndb.py
@@ -10,61 +10,48 @@
 """
 from __future__ import absolute_import
 
-import pickle
-
-from google.appengine.api import datastore_errors
 from google.appengine.api import memcache
 
-from ndb import model
+try:
+    from ndb import model
+except ImportError: # pragma: no cover
+    from google.appengine.ext.ndb import model
+
+try:
+    from ndb.model import PickleProperty
+except ImportError: # pragma: no cover
+    try:
+        from google.appengine.ext.ndb.model import PickleProperty
+    except ImportError: # pragma: no cover
+        # ndb in SDK 1.6.1 doesn't have PickleProperty.
+        import pickle
+
+        class PickleProperty(model.BlobProperty):
+            """A Property whose value is any picklable Python object."""
+
+            def _validate(self, value):
+                return value
+
+            def _db_set_value(self, v, p, value):
+                super(PickleProperty, self)._db_set_value(v, p,
+                    pickle.dumps(value))
+
+            def _db_get_value(self, v, p):
+                if not v.has_stringvalue():
+                    return None
+
+                return pickle.loads(v.stringvalue())
+
 
 from webapp2_extras import sessions
 
-
-class PickledProperty(model.BlobProperty):
-    _type = None
-    _indexed = False
-
-    def __init__(self, _type, *args, **kwargs):
-        super(PickledProperty, self).__init__(*args, **kwargs)
-        self._type = _type
-
-    def _validate_type(self, value):
-        if not isinstance(value, self._type):
-            raise datastore_errors.BadValueError(
-                'Expected %r, got %r' % (self._type, value))
-        return value
-
-    def _validate(self, value):
-        return self._validate_type(value)
-
-    def _db_set_value(self, v, p, value):
-        value = self._validate_type(value)
-        super(PickledProperty, self)._db_set_value(v, p, pickle.dumps(value))
-
-    def _db_get_value(self, v, p):
-        if not v.has_stringvalue():
-            return None
-
-        return pickle.loads(v.stringvalue())
-
-
 class Session(model.Model):
     """A model to store session data."""
 
     #: Save time.
     updated = model.DateTimeProperty(auto_now=True)
     #: Session data, pickled.
-    try:
-        # If model.PickleProperty exists, we must use it, since the
-        # above PickledProperty is broken in NDB 0.9.4 and later.
-        # This still leaves NDB 0.9.4 broken, since it doesn't have
-        # model.PickleProperty.  Fortunately no SDK contains NDB
-        # 0.9.4, we went straight from 0.9.3 (in SDK 1.6.1) to 0.9.6
-        # (in SDK 1.6.2).
-        data = model.PickleProperty()
-    except AttributeError:
-        # In NDB 0.9.3 or before, the above PickledProperty works.
-        data = PickledProperty(dict)
+    data = PickleProperty()
 
     @classmethod
     def get_by_sid(cls, sid):
diff --git a/lib/webapp2/webapp2_extras/i18n.py b/lib/webapp2/webapp2_extras/i18n.py
index 99b5d2e..058e07e 100644
--- a/lib/webapp2/webapp2_extras/i18n.py
+++ b/lib/webapp2/webapp2_extras/i18n.py
@@ -21,7 +21,7 @@
 try:
     # Monkeypatches pytz for gae.
     import pytz.gae
-except ImportError:  # pragma: no cover
+except ImportError: # pragma: no cover
     pass
 
 import pytz
diff --git a/lib/webapp2/webapp2_extras/json.py b/lib/webapp2/webapp2_extras/json.py
index 18f4883..ac2e1e9 100644
--- a/lib/webapp2/webapp2_extras/json.py
+++ b/lib/webapp2/webapp2_extras/json.py
@@ -17,11 +17,11 @@
     # Preference for installed library with updated fixes.
     # Also available in Google App Engine SDK >= 1.4.2.
     import simplejson as json
-except ImportError:  # pragma: no cover
+except ImportError: # pragma: no cover
     try:
         # Standard library module in Python >= 2.6.
         import json
-    except ImportError:  # pragma: no cover
+    except ImportError: # pragma: no cover
         raise RuntimeError(
             'A JSON parser is required, e.g., simplejson at '
             'http://pypi.python.org/pypi/simplejson/')
diff --git a/lib/webapp2/webapp2_extras/local.py b/lib/webapp2/webapp2_extras/local.py
index b0fbe2a..011e927 100644
--- a/lib/webapp2/webapp2_extras/local.py
+++ b/lib/webapp2/webapp2_extras/local.py
@@ -12,7 +12,7 @@
 """
 try:
     from greenlet import getcurrent as get_current_greenlet
-except ImportError:  # pragma: no cover
+except ImportError: # pragma: no cover
     try:
         from py.magic import greenlet
         get_current_greenlet = greenlet.getcurrent
@@ -22,14 +22,14 @@
         get_current_greenlet = int
 try:
     from thread import get_ident as get_current_thread, allocate_lock
-except ImportError:  # pragma: no cover
+except ImportError: # pragma: no cover
     from dummy_thread import get_ident as get_current_thread, allocate_lock
 
 
 # get the best ident function.  if greenlets are not installed we can
 # safely just use the builtin thread function and save a python methodcall
 # and the cost of calculating a hash.
-if get_current_greenlet is int:  # pragma: no cover
+if get_current_greenlet is int: # pragma: no cover
     get_ident = get_current_thread
 else:
     get_ident = lambda: (get_current_thread(), get_current_greenlet())
diff --git a/lib/webapp2/webapp2_extras/protorpc.py b/lib/webapp2/webapp2_extras/protorpc.py
deleted file mode 100644
index 1462335..0000000
--- a/lib/webapp2/webapp2_extras/protorpc.py
+++ /dev/null
@@ -1,215 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-    webapp2_extras.protorpc
-    =======================
-
-    Support for Google ProtoRPC library in webapp2.
-
-    Ported from protorpc.service_handlers.
-
-    See: http://code.google.com/p/google-protorpc/
-
-    .. warning::
-       This is an experimental package, as the ProtoRPC API is not stable yet.
-
-    :copyright: 2010 Google Inc.
-    :copyright: 2011 tipfy.org.
-    :license: Apache Sotware License, see LICENSE for details.
-"""
-from __future__ import absolute_import
-
-import logging
-
-from protorpc import registry
-from protorpc.webapp import service_handlers
-from protorpc.webapp import forms
-
-import webapp2
-
-
-class ServiceHandler(webapp2.RequestHandler, service_handlers.ServiceHandler):
-    def dispatch(self, factory, service):
-        # Unfortunately we need to access the protected attributes.
-        self._ServiceHandler__factory = factory
-        self._ServiceHandler__service = service
-
-        request = self.request
-        request_method = request.method
-        method = getattr(self, request_method.lower(), None)
-        service_path, remote_method = request.route_args
-        if method:
-            self.handle(request_method, service_path, remote_method)
-        else:
-            message = 'Unsupported HTTP method: %s' % request_method
-            logging.error(message)
-            self.response.status = '405 %s' % message
-
-        if request_method == 'GET':
-            status = self.response.status_int
-            if status in (405, 415) or not request.content_type:
-                # Again, now a protected method.
-                self._ServiceHandler__show_info(service_path, remote_method)
-
-
-class ServiceHandlerFactory(service_handlers.ServiceHandlerFactory):
-    def __call__(self, request, *args, **kwargs):
-        """Construct a new service handler instance."""
-        handler = ServiceHandler(request, request.response)
-        handler.dispatch(self, self.service_factory())
-
-
-def _normalize_services(mixed_services):
-    if isinstance(mixed_services, dict):
-        mixed_services = mixed_services.iteritems()
-
-    services = []
-    for service_item in mixed_services:
-        if isinstance(service_item, (list, tuple)):
-            path, service = service_item
-        else:
-            path = None
-            service = service_item
-
-        if isinstance(service, basestring):
-            # Lazily import the service class.
-            service = webapp2.import_string(service)
-
-        services.append((path, service))
-
-    return services
-
-
-def service_mapping(services, registry_path=forms.DEFAULT_REGISTRY_PATH):
-    """Create a services mapping for use with webapp2.
-
-    Creates basic default configuration and registration for ProtoRPC services.
-    Each service listed in the service mapping has a standard service handler
-    factory created for it.
-
-    The list of mappings can either be an explicit path to service mapping or
-    just services.  If mappings are just services, they will automatically
-    be mapped to their default name.  For example::
-
-        from protorpc import messages
-        from protorpc import remote
-
-        import webapp2
-        from webapp2_extras import protorpc
-
-        class HelloRequest(messages.Message):
-            my_name = messages.StringField(1, required=True)
-
-        class HelloResponse(messages.Message):
-            hello = messages.StringField(1, required=True)
-
-        class HelloService(remote.Service):
-            @remote.method(HelloRequest, HelloResponse)
-            def hello(self, request):
-                return HelloResponse(hello='Hello there, %s!' %
-                                     request.my_name)
-
-        service_mappings = protorpc.service_mapping([
-            ('/hello', HelloService),
-        ])
-
-        app = webapp2.WSGIApplication(routes=service_mappings)
-
-        def main():
-            app.run()
-
-        if __name__ == '__main__':
-            main()
-
-    Specifying a service mapping:
-
-    Normally services are mapped to URL paths by specifying a tuple
-    (path, service):
-
-    - path: The path the service resides on.
-    - service: The service class or service factory for creating new instances
-      of the service.  For more information about service factories, please
-      see remote.Service.new_factory.
-
-    If no tuple is provided, and therefore no path specified, a default path
-    is calculated by using the fully qualified service name using a URL path
-    separator for each of its components instead of a '.'.
-
-    :param services:
-        Can be service type, service factory or string definition name of
-        service being mapped or list of tuples (path, service):
-
-        - path: Path on server to map service to.
-        - service: Service type, service factory or string definition name of
-          service being mapped.
-
-      Can also be a dict.  If so, the keys are treated as the path and values
-      as the service.
-    :param registry_path:
-        Path to give to registry service. Use None to disable registry service.
-    :returns:
-        List of tuples defining a mapping of request handlers compatible with a
-        webapp2 application.
-    :raises:
-        ServiceConfigurationError when duplicate paths are provided.
-    """
-    # TODO: clean the convoluted API? Accept services as tuples only, or
-    # make different functions to accept different things.
-    # For now we are just following the same API from protorpc.
-    services = _normalize_services(services)
-    mapping = []
-    registry_map = {}
-
-    if registry_path is not None:
-        registry_service = registry.RegistryService.new_factory(registry_map)
-        services = list(services) + [(registry_path, registry_service)]
-        forms_handler = forms.FormsHandler(registry_path=registry_path)
-        mapping.append((registry_path + r'/form(?:/)?', forms_handler))
-        mapping.append((registry_path + r'/form/(.+)', forms.ResourceHandler))
-
-    paths = set()
-    for path, service in services:
-        service_class = getattr(service, 'service_class', service)
-        if not path:
-            path = '/' + service_class.definition_name().replace('.', '/')
-
-        if path in paths:
-            raise service_handlers.ServiceConfigurationError(
-                'Path %r is already defined in service mapping'
-                % path.encode('utf-8'))
-        else:
-            paths.add(path)
-
-        # Create service mapping for webapp2.
-        new_mapping = ServiceHandlerFactory.default(service).mapping(path)
-        mapping.append(new_mapping)
-
-        # Update registry with service class.
-        registry_map[path] = service_class
-
-    return mapping
-
-
-def get_app(services, registry_path=forms.DEFAULT_REGISTRY_PATH,
-            debug=False, config=None):
-    """Returns a WSGI application configured for the given services.
-
-    Parameters are the same as :func:`service_mapping`, plus:
-
-    :param debug:
-        WSGI application debug flag: True to enable debug mode.
-    :param config:
-        WSGI application configuration dictionary.
-    """
-    mappings = service_mapping(services, registry_path=registry_path)
-    return webapp2.WSGIApplication(routes=mappings, debug=debug, config=config)
-
-
-def run_services(services, registry_path=forms.DEFAULT_REGISTRY_PATH,
-                 debug=False, config=None):
-    """Handle CGI request using service mapping.
-
-    Parameters are the same as :func:`get_app`.
-    """
-    app = get_app(services, registry_path=registry_path, debug=debug,
-                  config=config)
-    app.run()
diff --git a/lib/webapp2/webapp2_extras/securecookie.py b/lib/webapp2/webapp2_extras/securecookie.py
index 97e6a1e..7fde385 100644
--- a/lib/webapp2/webapp2_extras/securecookie.py
+++ b/lib/webapp2/webapp2_extras/securecookie.py
@@ -8,6 +8,7 @@
     :copyright: 2011 by tipfy.org.
     :license: Apache Sotware License, see LICENSE for details.
 """
+import Cookie
 import hashlib
 import hmac
 import logging
@@ -63,6 +64,9 @@
         if not value:
             return None
 
+        # Unquote for old WebOb.
+        value = Cookie._unquote(value)
+
         parts = value.split('|')
         if len(parts) != 3:
             return None
diff --git a/remote_api_shell.py b/remote_api_shell.py
index 88994d1..0276d25 100755
--- a/remote_api_shell.py
+++ b/remote_api_shell.py
@@ -21,6 +21,7 @@
 
 
 import os
+import re
 import sys
 
 
@@ -57,18 +58,32 @@
   os.path.join(DIR_PATH, 'lib', 'google.appengine._internal.graphy'),
 ]
 
+API_SERVER_EXTRA_PATHS = [
+  os.path.join(DIR_PATH, 'lib', 'argparse'),
+]
+API_SERVER_EXTRA_PATH_SCRIPTS = 'api_server'
 
-GOOGLE_SQL_EXTRA_PATHS = [
-  os.path.join(DIR_PATH, 'lib', 'enum'),
+
+OAUTH_CLIENT_EXTRA_PATHS = [
   os.path.join(DIR_PATH, 'lib', 'google-api-python-client'),
-  os.path.join(DIR_PATH, 'lib', 'grizzled'),
   os.path.join(DIR_PATH, 'lib', 'httplib2'),
+  os.path.join(DIR_PATH, 'lib', 'python-gflags'),
+]
+
+OAUTH_CLIENT_EXTRA_PATH_SCRIPTS = '(appcfg|bulkloader)'
+
+
+GOOGLE_SQL_EXTRA_PATHS = OAUTH_CLIENT_EXTRA_PATHS + [
+  os.path.join(DIR_PATH, 'lib', 'enum'),
+  os.path.join(DIR_PATH, 'lib', 'grizzled'),
   os.path.join(DIR_PATH, 'lib', 'oauth2'),
   os.path.join(DIR_PATH, 'lib', 'prettytable'),
-  os.path.join(DIR_PATH, 'lib', 'python-gflags'),
   os.path.join(DIR_PATH, 'lib', 'sqlcmd'),
 ]
 
+GOOGLE_SQL_EXTRA_PATH_SCRIPTS = 'google_sql'
+
+
 
 SCRIPT_EXCEPTIONS = {
   "dev_appserver.py" : "dev_appserver_main.py"
@@ -79,18 +94,27 @@
 }
 
 
-def fix_sys_path(include_google_sql_libs=False):
+def fix_sys_path(extra_extra_paths=()):
   """Fix the sys.path to include our extra paths."""
   extra_paths = EXTRA_PATHS[:]
-  if include_google_sql_libs:
-    extra_paths.extend(GOOGLE_SQL_EXTRA_PATHS)
+  extra_paths.extend(extra_extra_paths)
   sys.path = extra_paths + sys.path
 
 
 def run_file(file_path, globals_, script_dir=SCRIPT_DIR):
   """Execute the file at the specified path with the passed-in globals."""
   script_name = os.path.basename(file_path)
-  fix_sys_path('google_sql' in script_name)
+
+  if re.match(OAUTH_CLIENT_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = OAUTH_CLIENT_EXTRA_PATHS
+  elif re.match(GOOGLE_SQL_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = GOOGLE_SQL_EXTRA_PATHS
+  elif re.match(API_SERVER_EXTRA_PATH_SCRIPTS, script_name):
+    extra_extra_paths = API_SERVER_EXTRA_PATHS
+  else:
+    extra_extra_paths = []
+  fix_sys_path(extra_extra_paths)
+
   script_name = SCRIPT_EXCEPTIONS.get(script_name, script_name)
   script_dir = SCRIPT_DIR_EXCEPTIONS.get(script_name, script_dir)
   script_path = os.path.join(script_dir, script_name)