App Engine Python SDK version 1.9.10

git-svn-id: http://googleappengine.googlecode.com/svn/trunk/python@461 80f5ef21-4148-0410-bacc-cfb02402ada8
diff --git a/RELEASE_NOTES b/RELEASE_NOTES
index f189833..3a13b65 100644
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -3,6 +3,18 @@
 
 App Engine SDK - Release Notes
 
+Version 1.9.10
+
+Python
+==============================
+- Asynchronous calls are now supported in the Search API.
+
+PHP
+==============================
+- Fixed an issue that causes script routing errors in the dev_appserver when
+  the url regular expression uses subgroups that include a leading slash.
+    https://code.google.com/p/googleappengine/issues/detail?id=11134
+
 Version 1.9.9
 
 All
diff --git a/VERSION b/VERSION
index dc3d71b..114b85e 100644
--- a/VERSION
+++ b/VERSION
@@ -1,5 +1,5 @@
-release: "1.9.9"
-timestamp: 1406573704
+release: "1.9.10"
+timestamp: 1407785464
 api_versions: ['1']
 supported_api_versions:
   python:
diff --git a/google/appengine/api/appinfo.py b/google/appengine/api/appinfo.py
index 523ea74..a950596 100644
--- a/google/appengine/api/appinfo.py
+++ b/google/appengine/api/appinfo.py
@@ -1868,7 +1868,8 @@
       The effective runtime: the value of vm_settings.vm_runtime if runtime is
       "vm", or runtime otherwise.
     """
-    if self.runtime == 'vm' and hasattr(self, 'vm_settings'):
+    if (self.runtime == 'vm' and hasattr(self, 'vm_settings')
+        and self.vm_settings is not None):
       return self.vm_settings.get('vm_runtime')
     return self.runtime
 
diff --git a/google/appengine/api/backends/__init__.py b/google/appengine/api/backends/__init__.py
index b804a62..0755653 100644
--- a/google/appengine/api/backends/__init__.py
+++ b/google/appengine/api/backends/__init__.py
@@ -18,7 +18,14 @@
 
 
 
-"""Backends API module."""
+"""Backends API.
+
+.. deprecated:: 1.9.1
+   Use Modules library instead.
+
+Although Google will continue to support the Backend API in accordance with our
+terms of service, it is strongly recommended that all new applications use the
+Modules API instead."""
 
 
 from backends import *
diff --git a/google/appengine/api/backends/backends.py b/google/appengine/api/backends/backends.py
index 9926f00..a76b5a0 100644
--- a/google/appengine/api/backends/backends.py
+++ b/google/appengine/api/backends/backends.py
@@ -17,7 +17,10 @@
 
 
 
-"""DEPRECATED: Backends API.
+"""Backends API.
+
+.. deprecated:: 1.9.1
+   Use Modules library instead.
 
 This API provides utility methods for working with backends.
 """
diff --git a/google/appengine/api/background_thread/__init__.py b/google/appengine/api/background_thread/__init__.py
index 3667b09..369aa72 100644
--- a/google/appengine/api/background_thread/__init__.py
+++ b/google/appengine/api/background_thread/__init__.py
@@ -16,7 +16,14 @@
 #
 
 
-"""Background thread API module."""
+"""Background Threads API.
+
+.. deprecated:: 1.9.1
+   Use Modules library instead.
+
+Although Google will continue to support the Background Threads API in accordance with our
+terms of service, it is strongly recommended that all new applications use the
+Modules API instead."""
 
 
 from background_thread import *
diff --git a/google/appengine/api/background_thread/background_thread.py b/google/appengine/api/background_thread/background_thread.py
index cbe6abb..b188775 100644
--- a/google/appengine/api/background_thread/background_thread.py
+++ b/google/appengine/api/background_thread/background_thread.py
@@ -16,7 +16,12 @@
 #
 
 
-"""An API for creating background threads.
+"""Background Threads API.
+
+.. deprecated:: 1.9.1
+   Use Modules library instead.
+
+An API for creating background threads.
 
 Background threads created using this API do not inherit the context of their
 creator and do not need to end before the creator request completes.
diff --git a/google/appengine/api/files/__init__.py b/google/appengine/api/files/__init__.py
index 68d12a2..acd0c9d 100644
--- a/google/appengine/api/files/__init__.py
+++ b/google/appengine/api/files/__init__.py
@@ -18,10 +18,10 @@
 
 
 
-"""Appengine Files API.
+"""Appengine Files API
 
 .. deprecated:: 1.8.1
-   Use GCS client library instead.
+   Use Google Cloud Storage Client library instead.
 """
 
 
diff --git a/google/appengine/api/files/blobstore.py b/google/appengine/api/files/blobstore.py
index eb2a4d3..65d5ea1 100644
--- a/google/appengine/api/files/blobstore.py
+++ b/google/appengine/api/files/blobstore.py
@@ -18,7 +18,12 @@
 
 
 
-"""Blobstore-specific Files API calls."""
+"""Files API.
+
+.. deprecated:: 1.8.1
+   Use Google Cloud Storage Client library instead.
+
+Blobstore-specific Files API calls."""
 
 from __future__ import with_statement
 
diff --git a/google/appengine/api/files/file.py b/google/appengine/api/files/file.py
index 3ec16c2..1646d8d 100644
--- a/google/appengine/api/files/file.py
+++ b/google/appengine/api/files/file.py
@@ -18,7 +18,10 @@
 
 
 
-"""App Engine Files API."""
+"""Files API.
+
+.. deprecated:: 1.8.1
+   Use Google Cloud Storage Client library instead."""
 
 from __future__ import with_statement
 
diff --git a/google/appengine/api/files/gs.py b/google/appengine/api/files/gs.py
index 7dd78b3..9eb40a4 100644
--- a/google/appengine/api/files/gs.py
+++ b/google/appengine/api/files/gs.py
@@ -18,7 +18,12 @@
 
 
 
-"""Google Storage specific Files API calls."""
+"""Files API.
+
+.. deprecated:: 1.8.1
+   Use Google Cloud Storage Client library instead.
+
+Google Storage specific Files API calls."""
 
 
 
diff --git a/google/appengine/api/files/records.py b/google/appengine/api/files/records.py
index 4b07c05..0808931 100644
--- a/google/appengine/api/files/records.py
+++ b/google/appengine/api/files/records.py
@@ -18,7 +18,12 @@
 
 
 
-"""Lightweight record format.
+"""Files API.
+
+.. deprecated:: 1.8.1
+   Use Google Cloud Storage Client library instead.
+
+Lightweight record format.
 
 This format implements log file format from leveldb:
 http://leveldb.googlecode.com/svn/trunk/doc/log_format.txt
diff --git a/google/appengine/api/files/shuffler.py b/google/appengine/api/files/shuffler.py
index cc56996..5f9a86d 100644
--- a/google/appengine/api/files/shuffler.py
+++ b/google/appengine/api/files/shuffler.py
@@ -18,7 +18,12 @@
 
 
 
-"""Files API Shuffler interface"""
+"""Files API.
+
+.. deprecated:: 1.8.1
+   Use Google Cloud Storage Client library instead.
+
+Files API Shuffler interface"""
 
 
 import logging
diff --git a/google/appengine/api/files/testutil.py b/google/appengine/api/files/testutil.py
index 538d18e..696999c 100644
--- a/google/appengine/api/files/testutil.py
+++ b/google/appengine/api/files/testutil.py
@@ -18,7 +18,12 @@
 
 
 
-"""Testing utils for writing tests involving Files API."""
+"""Files API.
+
+.. deprecated:: 1.8.1
+   Use Google Cloud Storage Client library instead.
+
+Testing utils for writing tests involving Files API."""
 
 
 __all__ = ['TestFileServiceStub']
diff --git a/google/appengine/api/runtime/__init__.py b/google/appengine/api/runtime/__init__.py
index 4646472..7e0f9b5 100644
--- a/google/appengine/api/runtime/__init__.py
+++ b/google/appengine/api/runtime/__init__.py
@@ -18,7 +18,11 @@
 
 
 
-"""Runtime API module."""
+"""Runtime Utilities API.
+
+.. deprecated:: 1.8.1
+
+"""
 
 
 from runtime import *
diff --git a/google/appengine/api/runtime/runtime.py b/google/appengine/api/runtime/runtime.py
index b6559a0..a3599e5 100644
--- a/google/appengine/api/runtime/runtime.py
+++ b/google/appengine/api/runtime/runtime.py
@@ -19,7 +19,11 @@
 
 
 
-"""Utilities for interacting with the Python Runtime."""
+"""Runtime Utilities API.
+
+.. deprecated:: 1.8.1
+
+Utilities for interacting with the Python Runtime."""
 
 
 
diff --git a/google/appengine/api/search/search.py b/google/appengine/api/search/search.py
index 57bff9a..fff115e 100644
--- a/google/appengine/api/search/search.py
+++ b/google/appengine/api/search/search.py
@@ -16,8 +16,6 @@
 #
 
 
-
-
 """A Python Search API used by app developers.
 
 Contains methods used to interface with Search API.
@@ -29,8 +27,8 @@
 
 
 
-
 import datetime
+import logging
 import re
 import string
 import sys
@@ -65,6 +63,7 @@
     'GeoField',
     'GeoPoint',
     'get_indexes',
+    'get_indexes_async',
     'GetResponse',
     'Index',
     'InternalError',
@@ -215,6 +214,55 @@
   return prefix
 
 
+class _RpcOperationFuture(object):
+  """Represents the future result a search RPC sent to a backend."""
+
+  def __init__(self, call, request, response, deadline, get_result_hook):
+    """Initializer.
+
+    Args:
+      call: Method name to call, as a string
+      request: The request object
+      response: The response object
+      deadline: Deadline for RPC call in seconds; if None use the default.
+      get_result_hook: Required result hook. Must be a function that takes
+        no arguments. Its return value is returned by get_result().
+    """
+    _ValidateDeadline(deadline)
+    self._get_result_hook = get_result_hook
+    self._rpc = apiproxy_stub_map.UserRPC('search', deadline=deadline)
+    self._rpc.make_call(call, request, response)
+
+  def get_result(self):
+    self._rpc.wait();
+    try:
+      self._rpc.check_success();
+    except apiproxy_errors.ApplicationError, e:
+      raise _ToSearchError(e)
+    return self._get_result_hook()
+
+
+class _SimpleOperationFuture(object):
+  """Adapts a late-binding function to a future."""
+
+  def __init__(self, future, function):
+    self._future = future
+    self._function = function
+
+  def get_result(self):
+    return self._function(self._future.get_result())
+
+
+class _WrappedValueFuture(object):
+  """Adapts an immediately-known result to a future."""
+
+  def __init__(self, result):
+    self._result = result
+
+  def get_result(self):
+    return self._result
+
+
 class OperationResult(object):
   """Represents result of individual operation of a batch index or removal.
 
@@ -669,6 +717,7 @@
       results=[_NewIndexFromPb(index)
                for index in response.index_metadata_list()])
 
+
 @datastore_rpc._positional(7)
 def get_indexes(namespace='', offset=None, limit=20,
                 start_index_name=None, include_start_index=True,
@@ -699,26 +748,26 @@
     ValueError: If any of the parameters have invalid values (e.g., a
       negative deadline).
   """
+  return get_indexes_async(
+      namespace, offset, limit, start_index_name, include_start_index,
+      index_name_prefix, fetch_schema, deadline=deadline, **kwargs).get_result()
+
+
+@datastore_rpc._positional(7)
+def get_indexes_async(namespace='', offset=None, limit=20,
+                      start_index_name=None, include_start_index=True,
+                      index_name_prefix=None, fetch_schema=False, deadline=None,
+                      **kwargs):
+  """Asynchronously returns a list of available indexes.
+
+  Identical to get_indexes() except that it returns a future. Call
+  get_result() on the return value to block on the call and get its result.
+  """
 
   app_id = kwargs.pop('app_id', None)
   if kwargs:
     raise TypeError('Invalid arguments: %s' % ', '.join(kwargs))
 
-  response = _GetIndexes(
-      namespace=namespace, offset=offset, limit=limit,
-      start_index_name=start_index_name,
-      include_start_index=include_start_index,
-      index_name_prefix=index_name_prefix,
-      fetch_schema=fetch_schema, deadline=deadline, app_id=app_id)
-  return _ListIndexesResponsePbToGetResponse(response)
-
-
-def _GetIndexes(namespace='', offset=None, limit=20,
-                start_index_name=None, include_start_index=True,
-                index_name_prefix=None, fetch_schema=False, deadline=None,
-                app_id=None):
-  """Returns a ListIndexesResponse."""
-
   request = search_service_pb.ListIndexesRequest()
   params = request.mutable_params()
 
@@ -752,10 +801,12 @@
   if app_id:
     request.set_app_id(app_id)
 
-  _MakeSyncSearchServiceCall('ListIndexes', request, response, deadline)
+  def hook():
+    _CheckStatus(response.status())
+    return _ListIndexesResponsePbToGetResponse(response)
+  return _RpcOperationFuture(
+      'ListIndexes', request, response, deadline, hook)
 
-  _CheckStatus(response.status())
-  return response
 
 class Field(object):
   """An abstract base class which represents a field of a document.
@@ -2498,7 +2549,15 @@
         or number of the documents is larger than
         MAXIMUM_DOCUMENTS_PER_PUT_REQUEST or deadline is a negative number.
     """
+    return self.put_async(documents, deadline=deadline).get_result()
 
+  @datastore_rpc._positional(2)
+  def put_async(self, documents, deadline=None):
+    """Asynchronously indexes the collection of documents.
+
+    Identical to put() except that it returns a future. Call
+    get_result() on the return value to block on the call and get its result.
+    """
     if isinstance(documents, basestring):
       raise TypeError('documents must be a Document or sequence of '
                       'Documents, got %s' % documents.__class__.__name__)
@@ -2508,7 +2567,7 @@
       docs = [documents]
 
     if not docs:
-      return []
+      return _WrappedValueFuture([])
 
     if len(docs) > MAXIMUM_DOCUMENTS_PER_PUT_REQUEST:
       raise ValueError('too many documents to index')
@@ -2535,19 +2594,20 @@
       doc_pb = params.add_document()
       _CopyDocumentToProtocolBuffer(document, doc_pb)
 
-    _MakeSyncSearchServiceCall('IndexDocument', request, response, deadline)
+    def hook():
+      results = self._NewPutResultList(response)
 
-    results = self._NewPutResultList(response)
+      if response.status_size() != len(params.document_list()):
+        raise PutError('did not index requested number of documents', results)
 
-    if response.status_size() != len(params.document_list()):
-      raise PutError('did not index requested number of documents', results)
-
-    for status in response.status_list():
-      if status.code() != search_service_pb.SearchServiceError.OK:
-        raise PutError(
-            _ConcatenateErrorMessages(
-                'one or more put document operations failed', status), results)
-    return results
+      for status in response.status_list():
+        if status.code() != search_service_pb.SearchServiceError.OK:
+          raise PutError(
+              _ConcatenateErrorMessages(
+                  'one or more put document operations failed', status), results)
+      return results
+    return _RpcOperationFuture(
+        'IndexDocument', request, response, deadline, hook)
 
   def _NewDeleteResultFromPb(self, status_pb, doc_id):
     """Constructs DeleteResult from RequestStatus pb and doc_id."""
@@ -2584,9 +2644,18 @@
         identifiers or number of document ids is larger than
         MAXIMUM_DOCUMENTS_PER_PUT_REQUEST or deadline is a negative number.
     """
+    return self.delete_async(document_ids, deadline=deadline).get_result()
+
+  @datastore_rpc._positional(2)
+  def delete_async(self, document_ids, deadline=None):
+    """Asynchronously deletes the documents with the corresponding document ids.
+
+    Identical to delete() except that it returns a future. Call
+    get_result() on the return value to block on the call and get its result.
+    """
     doc_ids = _ConvertToList(document_ids)
     if not doc_ids:
-      return
+      return _WrappedValueFuture([])
 
     if len(doc_ids) > MAXIMUM_DOCUMENTS_PER_PUT_REQUEST:
       raise ValueError('too many documents to delete')
@@ -2599,21 +2668,22 @@
       _CheckDocumentId(document_id)
       params.add_doc_id(document_id)
 
-    _MakeSyncSearchServiceCall('DeleteDocument', request, response,
-                               deadline)
+    def hook():
+      results = self._NewDeleteResultList(doc_ids, response)
 
-    results = self._NewDeleteResultList(doc_ids, response)
-
-    if response.status_size() != len(doc_ids):
-      raise DeleteError(
-          'did not delete requested number of documents', results)
-
-    for status in response.status_list():
-      if status.code() != search_service_pb.SearchServiceError.OK:
+      if response.status_size() != len(doc_ids):
         raise DeleteError(
-            _ConcatenateErrorMessages(
-                'one or more delete document operations failed', status),
-            results)
+            'did not delete requested number of documents', results)
+
+      for status in response.status_list():
+        if status.code() != search_service_pb.SearchServiceError.OK:
+          raise DeleteError(
+              _ConcatenateErrorMessages(
+                  'one or more delete document operations failed', status),
+              results)
+      return results
+    return _RpcOperationFuture(
+        'DeleteDocument', request, response, deadline, hook)
 
   def delete_schema(self):
     """Deprecated in 1.7.4. Delete the schema from the index.
@@ -2636,18 +2706,20 @@
     params = request.mutable_params()
     _CopyMetadataToProtocolBuffer(self, params.add_index_spec())
 
-    _MakeSyncSearchServiceCall('DeleteSchema', request, response, None)
+    def hook():
 
-    results = self._NewDeleteResultList([self.name], response)
+      results = self._NewDeleteResultList([self.name], response)
 
-    if response.status_size() != 1:
-      raise DeleteError('did not delete exactly one schema', results)
+      if response.status_size() != 1:
+        raise DeleteError('did not delete exactly one schema', results)
 
-    status = response.status_list()[0]
-    if status.code() != search_service_pb.SearchServiceError.OK:
-      raise DeleteError(
-          _ConcatenateErrorMessages('delete schema operation failed', status),
-          results)
+      status = response.status_list()[0]
+      if status.code() != search_service_pb.SearchServiceError.OK:
+        raise DeleteError(
+            _ConcatenateErrorMessages('delete schema operation failed', status),
+            results)
+    return _RpcOperationFuture(
+        'DeleteSchema', request, response, None, hook).get_result()
 
   def _NewScoredDocumentFromPb(self, doc_pb, sort_scores, expressions, cursor):
     """Constructs a Document from a document_pb.Document protocol buffer."""
@@ -2704,10 +2776,21 @@
       ValueError: If any of the parameters have invalid values (e.g., a
         negative deadline).
     """
-    response = self.get_range(start_id=doc_id, limit=1, deadline=deadline)
-    if response.results and response.results[0].doc_id == doc_id:
-      return response.results[0]
-    return None
+    return self.get_async(doc_id, deadline=deadline).get_result()
+
+  @datastore_rpc._positional(2)
+  def get_async(self, doc_id, deadline=None):
+    """Asynchronously retrieve a document by document ID.
+
+    Identical to get() except that it returns a future. Call
+    get_result() on the return value to block on the call and get its result.
+    """
+    future = self.get_range_async(start_id=doc_id, limit=1, deadline=deadline)
+    def hook(response):
+      if response.results and response.results[0].doc_id == doc_id:
+        return response.results[0]
+      return None
+    return _SimpleOperationFuture(future, hook)
 
   @datastore_rpc._positional(2)
   def search(self, query, deadline=None, **kwargs):
@@ -2754,6 +2837,9 @@
       results = index.search(
           Query('subject:first good', options=QueryOptions(cursor=cursor)))
 
+    See http://developers.google.com/appengine/docs/python/search/query_strings
+    for more information about query syntax.
+
     Args:
       query: The Query to match against documents in the index.
 
@@ -2770,10 +2856,28 @@
       ValueError: If any of the parameters have invalid values (e.g., a
         negative deadline).
     """
+    return self.search_async(query, deadline=deadline, **kwargs).get_result()
 
+  @datastore_rpc._positional(2)
+  def search_async(self, query, deadline=None, **kwargs):
+    """Asynchronously searches the index for documents matching the query.
 
+    Identical to search() except that it returns a future. Call
+    get_result() on the return value to block on the call and get its result.
+    """
+    if isinstance(query, basestring):
+      query = Query(query_string=query)
+    request = self._NewSearchRequest(query, deadline, **kwargs)
+    response = search_service_pb.SearchResponse()
+    def hook():
+      _CheckStatus(response.status())
+      cursor = None
+      if query.options:
+        cursor = query.options.cursor
+      return self._NewSearchResults(response, cursor)
+    return _RpcOperationFuture('Search', request, response, deadline, hook)
 
-
+  def _NewSearchRequest(self, query, deadline, **kwargs):
 
     app_id = kwargs.pop('app_id', None)
     if kwargs:
@@ -2788,16 +2892,7 @@
       query = Query(query_string=query)
     _CopyMetadataToProtocolBuffer(self, params.mutable_index_spec())
     _CopyQueryObjectToProtocolBuffer(query, params)
-
-    response = search_service_pb.SearchResponse()
-
-    _MakeSyncSearchServiceCall('Search', request, response, deadline)
-
-    _CheckStatus(response.status())
-    cursor = None
-    if query.options:
-      cursor = query.options.cursor
-    return self._NewSearchResults(response, cursor)
+    return request
 
   def _NewGetResponse(self, response):
     """Returns a GetResponse from the list_documents response pb."""
@@ -2807,31 +2902,6 @@
 
     return GetResponse(results=documents)
 
-  def _GetRange(self, start_id=None, include_start_object=True,
-                limit=100, ids_only=False, deadline=None, app_id=None):
-    """Get a range of objects in the index, in id order in a response."""
-    request = search_service_pb.ListDocumentsRequest()
-    if app_id:
-      request.set_app_id(app_id)
-
-    params = request.mutable_params()
-    _CopyMetadataToProtocolBuffer(self, params.mutable_index_spec())
-
-    if start_id:
-      params.set_start_doc_id(start_id)
-    params.set_include_start_doc(include_start_object)
-
-    params.set_limit(_CheckInteger(
-        limit, 'limit', zero_ok=False,
-        upper_bound=MAXIMUM_DOCUMENTS_RETURNED_PER_SEARCH))
-    params.set_keys_only(ids_only)
-
-    response = search_service_pb.ListDocumentsResponse()
-    _MakeSyncSearchServiceCall('ListDocuments', request, response, deadline)
-
-    _CheckStatus(response.status())
-    return response
-
   @datastore_rpc._positional(5)
   def get_range(self, start_id=None, include_start_object=True,
                 limit=100, ids_only=False, deadline=None, **kwargs):
@@ -2859,14 +2929,44 @@
       ValueError: If any of the parameters have invalid values (e.g., a
         negative deadline).
     """
+    return self.get_range_async(
+        start_id, include_start_object, limit, ids_only, deadline=deadline,
+        **kwargs).get_result()
+
+  @datastore_rpc._positional(5)
+  def get_range_async(self, start_id=None, include_start_object=True,
+                      limit=100, ids_only=False, deadline=None, **kwargs):
+    """Asynchronously gets a range of Documents in the index, in id order.
+
+    Identical to get_range() except that it returns a future. Call
+    get_result() on the return value to block on the call and get its result.
+    """
 
     app_id = kwargs.pop('app_id', None)
     if kwargs:
       raise TypeError('Invalid arguments: %s' % ', '.join(kwargs))
-    response = self._GetRange(
-        start_id=start_id, include_start_object=include_start_object,
-        limit=limit, ids_only=ids_only, deadline=deadline, app_id=app_id)
-    return self._NewGetResponse(response)
+    request = search_service_pb.ListDocumentsRequest()
+    if app_id:
+      request.set_app_id(app_id)
+
+    params = request.mutable_params()
+    _CopyMetadataToProtocolBuffer(self, params.mutable_index_spec())
+
+    if start_id:
+      params.set_start_doc_id(start_id)
+    params.set_include_start_doc(include_start_object)
+
+    params.set_limit(_CheckInteger(
+        limit, 'limit', zero_ok=False,
+        upper_bound=MAXIMUM_DOCUMENTS_RETURNED_PER_SEARCH))
+    params.set_keys_only(ids_only)
+
+    response = search_service_pb.ListDocumentsResponse()
+    def hook():
+      _CheckStatus(response.status())
+      return self._NewGetResponse(response)
+    return _RpcOperationFuture(
+        'ListDocuments', request, response, deadline, hook)
 
 
 _CURSOR_TYPE_PB_MAP = {
@@ -2949,7 +3049,7 @@
 
 
 def _MakeSyncSearchServiceCall(call, request, response, deadline):
-  """Make a synchronous call to search service.
+  """Deprecated: Make a synchronous call to search service.
 
   If the deadline is not None, waits only until the deadline expires.
 
@@ -2965,21 +3065,27 @@
     TypeError: if the deadline is not a number and is not None.
     ValueError: If the deadline is less than zero.
   """
+  _ValidateDeadline(deadline)
+  logging.warning("_MakeSyncSearchServiceCall is deprecated; please use API.")
   try:
     if deadline is None:
       apiproxy_stub_map.MakeSyncCall('search', call, request, response)
     else:
 
 
-      if (not isinstance(deadline, (int, long, float))
-          or isinstance(deadline, (bool,))):
-        raise TypeError('deadline argument should be int/long/float (%r)'
-                        % (deadline,))
-      if deadline <= 0:
-        raise ValueError('deadline argument must be > 0 (%s)' % (deadline,))
       rpc = apiproxy_stub_map.UserRPC('search', deadline=deadline)
       rpc.make_call(call, request, response)
       rpc.wait()
       rpc.check_success()
   except apiproxy_errors.ApplicationError, e:
     raise _ToSearchError(e)
+
+def _ValidateDeadline(deadline):
+  if deadline is None:
+    return
+  if (not isinstance(deadline, (int, long, float))
+      or isinstance(deadline, (bool,))):
+    raise TypeError('deadline argument should be int/long/float (%r)'
+                    % (deadline,))
+  if deadline <= 0:
+    raise ValueError('deadline argument must be > 0 (%s)' % (deadline,))
diff --git a/google/appengine/api/taskqueue/taskqueue_stub.py b/google/appengine/api/taskqueue/taskqueue_stub.py
index 12c4fe6..69a9fb9 100644
--- a/google/appengine/api/taskqueue/taskqueue_stub.py
+++ b/google/appengine/api/taskqueue/taskqueue_stub.py
@@ -2105,7 +2105,9 @@
 
     if self._root_path is None:
       return None
-    for queueyaml in ('queue.yaml', 'queue.yml'):
+    for queueyaml in (
+        'queue.yaml', 'queue.yml',
+        os.path.join('WEB-INF', 'appengine-generated', 'queue.yaml')):
       try:
         path = os.path.join(self._root_path, queueyaml)
         modified = os.stat(path).st_mtime
diff --git a/google/appengine/api/urlfetch.py b/google/appengine/api/urlfetch.py
index f1a6144..df362a2 100644
--- a/google/appengine/api/urlfetch.py
+++ b/google/appengine/api/urlfetch.py
@@ -421,7 +421,11 @@
     if (err.application_error ==
         urlfetch_service_pb.URLFetchServiceError.SSL_CERTIFICATE_ERROR):
       raise SSLCertificateError(
-        'Invalid and/or missing SSL certificate for URL: ' + url)
+          'Invalid and/or missing SSL certificate for URL: ' + url)
+    if (err.application_error ==
+        urlfetch_service_pb.URLFetchServiceError.CONNECTION_ERROR):
+      raise DownloadError('Unable to connect to server at URL: ' + url)
+
     raise err
 
   response = rpc.response
diff --git a/google/appengine/datastore/datastore_query.py b/google/appengine/datastore/datastore_query.py
index 0c81568..178e519 100644
--- a/google/appengine/datastore/datastore_query.py
+++ b/google/appengine/datastore/datastore_query.py
@@ -931,6 +931,72 @@
     return self._lat_lng - lat_lng <= self._radius_meters
 
 
+class _BoundingBoxFilter(_SinglePropertyFilter):
+  """An immutable bounding box filter for geo locations.
+
+  An immutable filter predicate that constrains a geo location property to a
+  bounding box region. The filter is inclusive at the border. The property
+  has to be of type V3 PointValue. V4 GeoPoints converts to this type.
+  """
+
+
+
+  def __init__(self, property_name, southwest, northeast):
+    """Initializes a _BoundingBoxFilter.
+
+    Args:
+      property_name: the name of the property to filter on.
+      southwest: The south-west corner of the bounding box. The type is
+          datastore_types.GeoPt.
+      northeast: The north-east corner of the bounding box. The type is
+          datastore_types.GeoPt.
+
+    Raises:
+      datastore_errors.BadArgumentError if the south-west coordinate is on top
+      of the north-east coordinate.
+    """
+
+
+    if southwest.lat > northeast.lat:
+      raise datastore_errors.BadArgumentError(
+          'the south-west coordinate is on top of the north-east coordinate')
+
+    self._property_name = property_name
+    self._southwest = southwest
+    self._northeast = northeast
+
+  @classmethod
+  def _from_v4_pb(cls, bounding_box_v4_pb):
+    sw = datastore_types.GeoPt(bounding_box_v4_pb.southwest().latitude(),
+                               bounding_box_v4_pb.southwest().longitude())
+    ne = datastore_types.GeoPt(bounding_box_v4_pb.northeast().latitude(),
+                               bounding_box_v4_pb.northeast().longitude())
+    return _BoundingBoxFilter(bounding_box_v4_pb.property().name(), sw, ne)
+
+  def _get_prop_name(self):
+    return self._property_name
+
+  def _apply_to_value(self, value):
+
+
+    if value[0] != entity_pb.PropertyValue.kPointValueGroup:
+      return False
+
+    _, latitude, longitude = value
+
+
+
+    if not self._southwest.lat <= latitude <= self._northeast.lat:
+      return False
+
+
+    if self._southwest.lon > self._northeast.lon:
+      return (longitude <= self._northeast.lon
+              or longitude >= self._southwest.lon)
+    else:
+      return self._southwest.lon <= longitude <= self._northeast.lon
+
+
 class Order(_PropertyComponent):
   """A base class that represents a sort order on a query.
 
diff --git a/google/appengine/datastore/datastore_v4_stub.py b/google/appengine/datastore/datastore_v4_stub.py
index 7297d29..52cdb64 100644
--- a/google/appengine/datastore/datastore_v4_stub.py
+++ b/google/appengine/datastore/datastore_v4_stub.py
@@ -160,6 +160,9 @@
     if filter_pb.has_bounding_circle_filter():
       return (datastore_query._BoundingCircleFilter._from_v4_pb(
           filter_pb.bounding_circle_filter()))
+    elif filter_pb.has_bounding_box_filter():
+      return (datastore_query._BoundingBoxFilter._from_v4_pb(
+          filter_pb.bounding_box_filter()))
     else:
       return None
 
diff --git a/google/appengine/datastore/document_pb.py b/google/appengine/datastore/document_pb.py
index 7d7149e..b2bd3bb 100644
--- a/google/appengine/datastore/document_pb.py
+++ b/google/appengine/datastore/document_pb.py
@@ -669,6 +669,244 @@
   _STYLE = """"""
   _STYLE_CONTENT_TYPE = """"""
   _PROTO_DESCRIPTOR_NAME = 'storage_onestore_v3.FieldTypes'
+class FieldMetadata(ProtocolBuffer.ProtocolMessage):
+  has_name_ = 0
+  name_ = ""
+
+  def __init__(self, contents=None):
+    self.type_ = []
+    if contents is not None: self.MergeFromString(contents)
+
+  def name(self): return self.name_
+
+  def set_name(self, x):
+    self.has_name_ = 1
+    self.name_ = x
+
+  def clear_name(self):
+    if self.has_name_:
+      self.has_name_ = 0
+      self.name_ = ""
+
+  def has_name(self): return self.has_name_
+
+  def type_size(self): return len(self.type_)
+  def type_list(self): return self.type_
+
+  def type(self, i):
+    return self.type_[i]
+
+  def set_type(self, i, x):
+    self.type_[i] = x
+
+  def add_type(self, x):
+    self.type_.append(x)
+
+  def clear_type(self):
+    self.type_ = []
+
+
+  def MergeFrom(self, x):
+    assert x is not self
+    if (x.has_name()): self.set_name(x.name())
+    for i in xrange(x.type_size()): self.add_type(x.type(i))
+
+  def Equals(self, x):
+    if x is self: return 1
+    if self.has_name_ != x.has_name_: return 0
+    if self.has_name_ and self.name_ != x.name_: return 0
+    if len(self.type_) != len(x.type_): return 0
+    for e1, e2 in zip(self.type_, x.type_):
+      if e1 != e2: return 0
+    return 1
+
+  def IsInitialized(self, debug_strs=None):
+    initialized = 1
+    if (not self.has_name_):
+      initialized = 0
+      if debug_strs is not None:
+        debug_strs.append('Required field: name not set.')
+    return initialized
+
+  def ByteSize(self):
+    n = 0
+    n += self.lengthString(len(self.name_))
+    n += 1 * len(self.type_)
+    for i in xrange(len(self.type_)): n += self.lengthVarInt64(self.type_[i])
+    return n + 1
+
+  def ByteSizePartial(self):
+    n = 0
+    if (self.has_name_):
+      n += 1
+      n += self.lengthString(len(self.name_))
+    n += 1 * len(self.type_)
+    for i in xrange(len(self.type_)): n += self.lengthVarInt64(self.type_[i])
+    return n
+
+  def Clear(self):
+    self.clear_name()
+    self.clear_type()
+
+  def OutputUnchecked(self, out):
+    out.putVarInt32(10)
+    out.putPrefixedString(self.name_)
+    for i in xrange(len(self.type_)):
+      out.putVarInt32(16)
+      out.putVarInt32(self.type_[i])
+
+  def OutputPartial(self, out):
+    if (self.has_name_):
+      out.putVarInt32(10)
+      out.putPrefixedString(self.name_)
+    for i in xrange(len(self.type_)):
+      out.putVarInt32(16)
+      out.putVarInt32(self.type_[i])
+
+  def TryMerge(self, d):
+    while d.avail() > 0:
+      tt = d.getVarInt32()
+      if tt == 10:
+        self.set_name(d.getPrefixedString())
+        continue
+      if tt == 16:
+        self.add_type(d.getVarInt32())
+        continue
+
+
+      if (tt == 0): raise ProtocolBuffer.ProtocolBufferDecodeError
+      d.skipData(tt)
+
+
+  def __str__(self, prefix="", printElemNumber=0):
+    res=""
+    if self.has_name_: res+=prefix+("name: %s\n" % self.DebugFormatString(self.name_))
+    cnt=0
+    for e in self.type_:
+      elm=""
+      if printElemNumber: elm="(%d)" % cnt
+      res+=prefix+("type%s: %s\n" % (elm, self.DebugFormatInt32(e)))
+      cnt+=1
+    return res
+
+
+  def _BuildTagLookupTable(sparse, maxtag, default=None):
+    return tuple([sparse.get(i, default) for i in xrange(0, 1+maxtag)])
+
+  kname = 1
+  ktype = 2
+
+  _TEXT = _BuildTagLookupTable({
+    0: "ErrorCode",
+    1: "name",
+    2: "type",
+  }, 2)
+
+  _TYPES = _BuildTagLookupTable({
+    0: ProtocolBuffer.Encoder.NUMERIC,
+    1: ProtocolBuffer.Encoder.STRING,
+    2: ProtocolBuffer.Encoder.NUMERIC,
+  }, 2, ProtocolBuffer.Encoder.MAX_TYPE)
+
+
+  _STYLE = """"""
+  _STYLE_CONTENT_TYPE = """"""
+  _PROTO_DESCRIPTOR_NAME = 'storage_onestore_v3.FieldMetadata'
+class IndexMetadata(ProtocolBuffer.ProtocolMessage):
+  has_is_over_field_number_threshold_ = 0
+  is_over_field_number_threshold_ = 0
+
+  def __init__(self, contents=None):
+    if contents is not None: self.MergeFromString(contents)
+
+  def is_over_field_number_threshold(self): return self.is_over_field_number_threshold_
+
+  def set_is_over_field_number_threshold(self, x):
+    self.has_is_over_field_number_threshold_ = 1
+    self.is_over_field_number_threshold_ = x
+
+  def clear_is_over_field_number_threshold(self):
+    if self.has_is_over_field_number_threshold_:
+      self.has_is_over_field_number_threshold_ = 0
+      self.is_over_field_number_threshold_ = 0
+
+  def has_is_over_field_number_threshold(self): return self.has_is_over_field_number_threshold_
+
+
+  def MergeFrom(self, x):
+    assert x is not self
+    if (x.has_is_over_field_number_threshold()): self.set_is_over_field_number_threshold(x.is_over_field_number_threshold())
+
+  def Equals(self, x):
+    if x is self: return 1
+    if self.has_is_over_field_number_threshold_ != x.has_is_over_field_number_threshold_: return 0
+    if self.has_is_over_field_number_threshold_ and self.is_over_field_number_threshold_ != x.is_over_field_number_threshold_: return 0
+    return 1
+
+  def IsInitialized(self, debug_strs=None):
+    initialized = 1
+    return initialized
+
+  def ByteSize(self):
+    n = 0
+    if (self.has_is_over_field_number_threshold_): n += 2
+    return n
+
+  def ByteSizePartial(self):
+    n = 0
+    if (self.has_is_over_field_number_threshold_): n += 2
+    return n
+
+  def Clear(self):
+    self.clear_is_over_field_number_threshold()
+
+  def OutputUnchecked(self, out):
+    if (self.has_is_over_field_number_threshold_):
+      out.putVarInt32(8)
+      out.putBoolean(self.is_over_field_number_threshold_)
+
+  def OutputPartial(self, out):
+    if (self.has_is_over_field_number_threshold_):
+      out.putVarInt32(8)
+      out.putBoolean(self.is_over_field_number_threshold_)
+
+  def TryMerge(self, d):
+    while d.avail() > 0:
+      tt = d.getVarInt32()
+      if tt == 8:
+        self.set_is_over_field_number_threshold(d.getBoolean())
+        continue
+
+
+      if (tt == 0): raise ProtocolBuffer.ProtocolBufferDecodeError
+      d.skipData(tt)
+
+
+  def __str__(self, prefix="", printElemNumber=0):
+    res=""
+    if self.has_is_over_field_number_threshold_: res+=prefix+("is_over_field_number_threshold: %s\n" % self.DebugFormatBool(self.is_over_field_number_threshold_))
+    return res
+
+
+  def _BuildTagLookupTable(sparse, maxtag, default=None):
+    return tuple([sparse.get(i, default) for i in xrange(0, 1+maxtag)])
+
+  kis_over_field_number_threshold = 1
+
+  _TEXT = _BuildTagLookupTable({
+    0: "ErrorCode",
+    1: "is_over_field_number_threshold",
+  }, 1)
+
+  _TYPES = _BuildTagLookupTable({
+    0: ProtocolBuffer.Encoder.NUMERIC,
+    1: ProtocolBuffer.Encoder.NUMERIC,
+  }, 1, ProtocolBuffer.Encoder.MAX_TYPE)
+
+
+  _STYLE = """"""
+  _STYLE_CONTENT_TYPE = """"""
+  _PROTO_DESCRIPTOR_NAME = 'storage_onestore_v3.IndexMetadata'
 class FacetValue(ProtocolBuffer.ProtocolMessage):
 
 
@@ -1416,4 +1654,4 @@
 if _extension_runtime:
   pass
 
-__all__ = ['FieldValue','FieldValue_Geo','Field','FieldTypes','FacetValue','Facet','DocumentMetadata','Document']
+__all__ = ['FieldValue','FieldValue_Geo','Field','FieldTypes','FieldMetadata','IndexMetadata','FacetValue','Facet','DocumentMetadata','Document']
diff --git a/google/appengine/datastore/entity_pb.py b/google/appengine/datastore/entity_pb.py
index 2e3d908..370c8a3 100644
--- a/google/appengine/datastore/entity_pb.py
+++ b/google/appengine/datastore/entity_pb.py
@@ -3227,6 +3227,8 @@
   state_ = 0
   has_only_use_if_required_ = 0
   only_use_if_required_ = 0
+  has_disabled_index_ = 0
+  disabled_index_ = 0
   has_write_division_family_ = 0
   write_division_family_ = ""
 
@@ -3295,6 +3297,19 @@
 
   def has_only_use_if_required(self): return self.has_only_use_if_required_
 
+  def disabled_index(self): return self.disabled_index_
+
+  def set_disabled_index(self, x):
+    self.has_disabled_index_ = 1
+    self.disabled_index_ = x
+
+  def clear_disabled_index(self):
+    if self.has_disabled_index_:
+      self.has_disabled_index_ = 0
+      self.disabled_index_ = 0
+
+  def has_disabled_index(self): return self.has_disabled_index_
+
   def read_division_family_size(self): return len(self.read_division_family_)
   def read_division_family_list(self): return self.read_division_family_
 
@@ -3331,6 +3346,7 @@
     if (x.has_definition()): self.mutable_definition().MergeFrom(x.definition())
     if (x.has_state()): self.set_state(x.state())
     if (x.has_only_use_if_required()): self.set_only_use_if_required(x.only_use_if_required())
+    if (x.has_disabled_index()): self.set_disabled_index(x.disabled_index())
     for i in xrange(x.read_division_family_size()): self.add_read_division_family(x.read_division_family(i))
     if (x.has_write_division_family()): self.set_write_division_family(x.write_division_family())
 
@@ -3346,6 +3362,8 @@
     if self.has_state_ and self.state_ != x.state_: return 0
     if self.has_only_use_if_required_ != x.has_only_use_if_required_: return 0
     if self.has_only_use_if_required_ and self.only_use_if_required_ != x.only_use_if_required_: return 0
+    if self.has_disabled_index_ != x.has_disabled_index_: return 0
+    if self.has_disabled_index_ and self.disabled_index_ != x.disabled_index_: return 0
     if len(self.read_division_family_) != len(x.read_division_family_): return 0
     for e1, e2 in zip(self.read_division_family_, x.read_division_family_):
       if e1 != e2: return 0
@@ -3381,6 +3399,7 @@
     n += self.lengthString(self.definition_.ByteSize())
     n += self.lengthVarInt64(self.state_)
     if (self.has_only_use_if_required_): n += 2
+    if (self.has_disabled_index_): n += 2
     n += 1 * len(self.read_division_family_)
     for i in xrange(len(self.read_division_family_)): n += self.lengthString(len(self.read_division_family_[i]))
     if (self.has_write_division_family_): n += 1 + self.lengthString(len(self.write_division_family_))
@@ -3401,6 +3420,7 @@
       n += 1
       n += self.lengthVarInt64(self.state_)
     if (self.has_only_use_if_required_): n += 2
+    if (self.has_disabled_index_): n += 2
     n += 1 * len(self.read_division_family_)
     for i in xrange(len(self.read_division_family_)): n += self.lengthString(len(self.read_division_family_[i]))
     if (self.has_write_division_family_): n += 1 + self.lengthString(len(self.write_division_family_))
@@ -3412,6 +3432,7 @@
     self.clear_definition()
     self.clear_state()
     self.clear_only_use_if_required()
+    self.clear_disabled_index()
     self.clear_read_division_family()
     self.clear_write_division_family()
 
@@ -3434,6 +3455,9 @@
     if (self.has_write_division_family_):
       out.putVarInt32(66)
       out.putPrefixedString(self.write_division_family_)
+    if (self.has_disabled_index_):
+      out.putVarInt32(72)
+      out.putBoolean(self.disabled_index_)
 
   def OutputPartial(self, out):
     if (self.has_app_id_):
@@ -3458,6 +3482,9 @@
     if (self.has_write_division_family_):
       out.putVarInt32(66)
       out.putPrefixedString(self.write_division_family_)
+    if (self.has_disabled_index_):
+      out.putVarInt32(72)
+      out.putBoolean(self.disabled_index_)
 
   def TryMerge(self, d):
     while d.avail() > 0:
@@ -3486,6 +3513,9 @@
       if tt == 66:
         self.set_write_division_family(d.getPrefixedString())
         continue
+      if tt == 72:
+        self.set_disabled_index(d.getBoolean())
+        continue
 
 
       if (tt == 0): raise ProtocolBuffer.ProtocolBufferDecodeError
@@ -3502,6 +3532,7 @@
       res+=prefix+">\n"
     if self.has_state_: res+=prefix+("state: %s\n" % self.DebugFormatInt32(self.state_))
     if self.has_only_use_if_required_: res+=prefix+("only_use_if_required: %s\n" % self.DebugFormatBool(self.only_use_if_required_))
+    if self.has_disabled_index_: res+=prefix+("disabled_index: %s\n" % self.DebugFormatBool(self.disabled_index_))
     cnt=0
     for e in self.read_division_family_:
       elm=""
@@ -3520,6 +3551,7 @@
   kdefinition = 3
   kstate = 4
   konly_use_if_required = 6
+  kdisabled_index = 9
   kread_division_family = 7
   kwrite_division_family = 8
 
@@ -3532,7 +3564,8 @@
     6: "only_use_if_required",
     7: "read_division_family",
     8: "write_division_family",
-  }, 8)
+    9: "disabled_index",
+  }, 9)
 
   _TYPES = _BuildTagLookupTable({
     0: ProtocolBuffer.Encoder.NUMERIC,
@@ -3543,7 +3576,8 @@
     6: ProtocolBuffer.Encoder.NUMERIC,
     7: ProtocolBuffer.Encoder.STRING,
     8: ProtocolBuffer.Encoder.STRING,
-  }, 8, ProtocolBuffer.Encoder.MAX_TYPE)
+    9: ProtocolBuffer.Encoder.NUMERIC,
+  }, 9, ProtocolBuffer.Encoder.MAX_TYPE)
 
 
   _STYLE = """"""
@@ -4283,6 +4317,8 @@
   key_ = ""
   has_before_ = 0
   before_ = 1
+  has_before_ascending_ = 0
+  before_ascending_ = 0
 
   def __init__(self, contents=None):
     if contents is not None: self.MergeFromString(contents)
@@ -4313,11 +4349,25 @@
 
   def has_before(self): return self.has_before_
 
+  def before_ascending(self): return self.before_ascending_
+
+  def set_before_ascending(self, x):
+    self.has_before_ascending_ = 1
+    self.before_ascending_ = x
+
+  def clear_before_ascending(self):
+    if self.has_before_ascending_:
+      self.has_before_ascending_ = 0
+      self.before_ascending_ = 0
+
+  def has_before_ascending(self): return self.has_before_ascending_
+
 
   def MergeFrom(self, x):
     assert x is not self
     if (x.has_key()): self.set_key(x.key())
     if (x.has_before()): self.set_before(x.before())
+    if (x.has_before_ascending()): self.set_before_ascending(x.before_ascending())
 
   def Equals(self, x):
     if x is self: return 1
@@ -4325,6 +4375,8 @@
     if self.has_key_ and self.key_ != x.key_: return 0
     if self.has_before_ != x.has_before_: return 0
     if self.has_before_ and self.before_ != x.before_: return 0
+    if self.has_before_ascending_ != x.has_before_ascending_: return 0
+    if self.has_before_ascending_ and self.before_ascending_ != x.before_ascending_: return 0
     return 1
 
   def IsInitialized(self, debug_strs=None):
@@ -4335,17 +4387,20 @@
     n = 0
     if (self.has_key_): n += 1 + self.lengthString(len(self.key_))
     if (self.has_before_): n += 2
+    if (self.has_before_ascending_): n += 2
     return n
 
   def ByteSizePartial(self):
     n = 0
     if (self.has_key_): n += 1 + self.lengthString(len(self.key_))
     if (self.has_before_): n += 2
+    if (self.has_before_ascending_): n += 2
     return n
 
   def Clear(self):
     self.clear_key()
     self.clear_before()
+    self.clear_before_ascending()
 
   def OutputUnchecked(self, out):
     if (self.has_key_):
@@ -4354,6 +4409,9 @@
     if (self.has_before_):
       out.putVarInt32(16)
       out.putBoolean(self.before_)
+    if (self.has_before_ascending_):
+      out.putVarInt32(24)
+      out.putBoolean(self.before_ascending_)
 
   def OutputPartial(self, out):
     if (self.has_key_):
@@ -4362,6 +4420,9 @@
     if (self.has_before_):
       out.putVarInt32(16)
       out.putBoolean(self.before_)
+    if (self.has_before_ascending_):
+      out.putVarInt32(24)
+      out.putBoolean(self.before_ascending_)
 
   def TryMerge(self, d):
     while d.avail() > 0:
@@ -4372,6 +4433,9 @@
       if tt == 16:
         self.set_before(d.getBoolean())
         continue
+      if tt == 24:
+        self.set_before_ascending(d.getBoolean())
+        continue
 
 
       if (tt == 0): raise ProtocolBuffer.ProtocolBufferDecodeError
@@ -4382,6 +4446,7 @@
     res=""
     if self.has_key_: res+=prefix+("key: %s\n" % self.DebugFormatString(self.key_))
     if self.has_before_: res+=prefix+("before: %s\n" % self.DebugFormatBool(self.before_))
+    if self.has_before_ascending_: res+=prefix+("before_ascending: %s\n" % self.DebugFormatBool(self.before_ascending_))
     return res
 
 
@@ -4390,18 +4455,21 @@
 
   kkey = 1
   kbefore = 2
+  kbefore_ascending = 3
 
   _TEXT = _BuildTagLookupTable({
     0: "ErrorCode",
     1: "key",
     2: "before",
-  }, 2)
+    3: "before_ascending",
+  }, 3)
 
   _TYPES = _BuildTagLookupTable({
     0: ProtocolBuffer.Encoder.NUMERIC,
     1: ProtocolBuffer.Encoder.STRING,
     2: ProtocolBuffer.Encoder.NUMERIC,
-  }, 2, ProtocolBuffer.Encoder.MAX_TYPE)
+    3: ProtocolBuffer.Encoder.NUMERIC,
+  }, 3, ProtocolBuffer.Encoder.MAX_TYPE)
 
 
   _STYLE = """"""
diff --git a/google/appengine/ext/appstats/static/appstats_js.js b/google/appengine/ext/appstats/static/appstats_js.js
index 6eba6a9..e3d16d8 100644
--- a/google/appengine/ext/appstats/static/appstats_js.js
+++ b/google/appengine/ext/appstats/static/appstats_js.js
@@ -35,7 +35,7 @@
 var jc=function(a){if(null==a.Ca){var b=a.f?a.d:a.A.Q.body,c;t:{c=eb(b);if(c.defaultView&&c.defaultView.getComputedStyle&&(c=c.defaultView.getComputedStyle(b,null))){c=c.direction||c.getPropertyValue("direction")||"";break t}c=""}a.Ca="rtl"==(c||(b.currentStyle?b.currentStyle.direction:null)||b.style&&b.style.direction)}return a.Ca};L.prototype.ra=function(a){if(this.f)throw Error("Component already rendered");this.Ca=a};
 var ic=function(a){return a.q?a.q.length:0},fc=function(a,b){var c;a.F&&b?(c=a.F,c=(b in c?c[b]:void 0)||null):c=null;return c},M=function(a,b){return a.q?a.q[b]||null:null},hc=function(a,b,c){a.q&&s(a.q,b,c)},kc=function(a,b){return a.q&&b?Ba(a.q,b):-1};
 L.prototype.removeChild=function(a,b){if(a){var c=m(a)?a:cc(a);a=fc(this,c);if(c&&a){var d=this.F;c in d&&delete d[c];Ea(this.q,a);b&&(a.ba(),a.d&&(c=a.d)&&c.parentNode&&c.parentNode.removeChild(c));gc(a,null)}}if(!a)throw Error("Child is not in parent component");return a};var lc,mc={nc:"activedescendant",sc:"atomic",tc:"autocomplete",vc:"busy",yc:"checked",Dc:"controls",Fc:"describedby",Ic:"disabled",Kc:"dropeffect",Lc:"expanded",Mc:"flowto",Oc:"grabbed",Sc:"haspopup",Uc:"hidden",Wc:"invalid",Xc:"label",Yc:"labelledby",Zc:"level",dd:"live",od:"multiline",pd:"multiselectable",td:"orientation",ud:"owns",vd:"posinset",xd:"pressed",Bd:"readonly",Dd:"relevant",Ed:"required",Kd:"selected",Md:"setsize",Od:"sort",ae:"valuemax",be:"valuemin",ce:"valuenow",de:"valuetext"};var nc={oc:"alert",pc:"alertdialog",qc:"application",rc:"article",uc:"banner",wc:"button",xc:"checkbox",zc:"columnheader",Ac:"combobox",Bc:"complementary",Cc:"contentinfo",Ec:"definition",Gc:"dialog",Hc:"directory",Jc:"document",Nc:"form",Pc:"grid",Qc:"gridcell",Rc:"group",Tc:"heading",Vc:"img",$c:"link",ad:"list",bd:"listbox",cd:"listitem",ed:"log",fd:"main",gd:"marquee",hd:"math",jd:"menu",kd:"menubar",ld:"menuitem",md:"menuitemcheckbox",nd:"menuitemradio",qd:"navigation",rd:"note",sd:"option",
-wd:"presentation",yd:"progressbar",zd:"radio",Ad:"radiogroup",Cd:"region",Fd:"row",Gd:"rowgroup",Hd:"rowheader",Id:"scrollbar",Jd:"search",Ld:"separator",Nd:"slider",Pd:"spinbutton",Qd:"status",Rd:"tab",Sd:"tablist",Td:"tabpanel",Ud:"textbox",Vd:"timer",Wd:"toolbar",Xd:"tooltip",Yd:"tree",Zd:"treegrid",$d:"treeitem"};var oc=function(a,b){b?(q(Na(nc,b),"No such ARIA role "+b),a.setAttribute("role",b)):a.removeAttribute("role")},qc=function(a,b,c){ea(c)&&(c=c.join(" "));var d=pc(b);""===c||void 0==c?(lc||(lc={atomic:!1,autocomplete:"none",dropeffect:"none",haspopup:!1,live:"off",multiline:!1,multiselectable:!1,orientation:"vertical",readonly:!1,relevant:"additions text",required:!1,sort:"none",busy:!1,disabled:!1,hidden:!1,invalid:"false"}),c=lc,b in c?a.setAttribute(d,c[b]):a.removeAttribute(d)):a.setAttribute(d,
+wd:"presentation",yd:"progressbar",zd:"radio",Ad:"radiogroup",Cd:"region",Fd:"row",Gd:"rowgroup",Hd:"rowheader",Id:"scrollbar",Jd:"search",Ld:"separator",Nd:"slider",Pd:"spinbutton",Qd:"status",Rd:"tab",Sd:"tablist",Td:"tabpanel",Ud:"textbox",Vd:"timer",Wd:"toolbar",Xd:"tooltip",Yd:"tree",Zd:"treegrid",$d:"treeitem"};var oc=function(a,b){b?(q(Na(nc,b),"No such ARIA role "+b),a.setAttribute("role",b)):a.removeAttribute("role")},qc=function(a,b,c){da(c)&&(c=c.join(" "));var d=pc(b);""===c||void 0==c?(lc||(lc={atomic:!1,autocomplete:"none",dropeffect:"none",haspopup:!1,live:"off",multiline:!1,multiselectable:!1,orientation:"vertical",readonly:!1,relevant:"additions text",required:!1,sort:"none",busy:!1,disabled:!1,hidden:!1,invalid:"false"}),c=lc,b in c?a.setAttribute(d,c[b]):a.removeAttribute(d)):a.setAttribute(d,
 c)},pc=function(a){q(a,"ARIA attribute cannot be empty.");q(Na(mc,a),"No such ARIA attribute "+a);return"aria-"+a};var tc=function(a,b,c,d,e){if(!(v||x&&A("525")))return!0;if(y&&e)return rc(a);if(e&&!d)return!1;"number"==typeof b&&(b=sc(b));if(!c&&(17==b||18==b||y&&91==b))return!1;if(x&&d&&c)switch(a){case 220:case 219:case 221:case 192:case 186:case 189:case 187:case 188:case 190:case 191:case 192:case 222:return!1}if(v&&d&&b==a)return!1;switch(a){case 13:return!0;case 27:return!x}return rc(a)},rc=function(a){if(48<=a&&57>=a||96<=a&&106>=a||65<=a&&90>=a||x&&0==a)return!0;switch(a){case 32:case 63:case 107:case 109:case 110:case 111:case 186:case 59:case 189:case 187:case 61:case 188:case 190:case 191:case 192:case 222:case 219:case 220:case 221:return!0;
 default:return!1}},sc=function(a){if(w)a=uc(a);else if(y&&x)t:switch(a){case 93:a=91;break t}return a},uc=function(a){switch(a){case 61:return 187;case 59:return 186;case 173:return 189;case 224:return 91;case 0:return 224;default:return a}};var N=function(a,b){H.call(this);a&&vc(this,a,b)};p(N,H);f=N.prototype;f.d=null;f.Ia=null;f.Ya=null;f.Ja=null;f.r=-1;f.N=-1;f.kb=!1;
 var wc={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},xc={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},yc=v||x&&A("525"),zc=y&&w;
@@ -68,8 +68,8 @@
 f.Hb=function(a){var b;t:{b=a.target;if(this.M)for(var c=this.a();b&&b!==c;){var d=b.id;if(d in this.M){b=this.M[d];break t}b=b.parentNode}b=null}if(b)switch(a.type){case "mousedown":b.la(a);break;case "mouseup":b.Ta(a);break;case "mouseover":b.Sa(a);break;case "mouseout":b.Ra(a);break;case "contextmenu":b.qa(a)}};f.na=function(){};f.ma=function(){dd(this,-1);this.aa=!1;this.i&&Yc(this.i,!1)};
 f.J=function(a){return this.isEnabled()&&this.s()&&(0!=ic(this)||this.ub)&&this.nb(a)?(a.preventDefault(),a.stopPropagation(),!0):!1};
 f.nb=function(a){var b=M(this,this.h);if(b&&"function"==typeof b.J&&b.J(a)||this.i&&this.i!=b&&"function"==typeof this.i.J&&this.i.J(a))return!0;if(a.shiftKey||a.ctrlKey||a.metaKey||a.altKey)return!1;switch(a.keyCode){case 27:if(this.I())this.j().blur();else return!1;break;case 36:ed(this);break;case 35:fd(this);break;case 38:if("vertical"==this.L)gd(this);else return!1;break;case 37:if("horizontal"==this.L)jc(this)?hd(this):gd(this);else return!1;break;case 40:if("vertical"==this.L)hd(this);else return!1;
-break;case 39:if("horizontal"==this.L)jc(this)?gd(this):hd(this);else return!1;break;default:return!1}return!0};var bd=function(a,b){var c=b.a(),c=c.id||(c.id=cc(b));a.M||(a.M={});a.M[c]=b};V.prototype.Da=function(a,b){Aa(a,S,"The child of a container must be a control");V.e.Da.call(this,a,b)};V.prototype.Va=function(a,b,c){a.T|=2;a.T|=64;!this.I()&&this.Rb||Zc(a,32,!1);a.Pa(!1);V.e.Va.call(this,a,b,c);a.f&&this.f&&bd(this,a);b<=this.h&&this.h++};
-V.prototype.removeChild=function(a,b){if(a=m(a)?fc(this,a):a){var c=kc(this,a);-1!=c&&(c==this.h?(a.B(!1),this.h=-1):c<this.h&&this.h--);var d=a.a();d&&d.id&&this.M&&(c=this.M,d=d.id,d in c&&delete c[d])}a=V.e.removeChild.call(this,a,b);a.Pa(!0);return a};var Lc=function(a,b){if(a.a())throw Error("Component already rendered");a.L=b};f=V.prototype;f.s=function(){return this.n};
+break;case 39:if("horizontal"==this.L)jc(this)?gd(this):hd(this);else return!1;break;default:return!1}return!0};var bd=function(a,b){var c=b.a(),c=c.id||(c.id=cc(b));a.M||(a.M={});a.M[c]=b};V.prototype.Da=function(a,b){Aa(a,S,"The child of a container must be a control");V.e.Da.call(this,a,b)};V.prototype.Va=function(a,b,c){Aa(a,S);a.T|=2;a.T|=64;!this.I()&&this.Rb||Zc(a,32,!1);a.Pa(!1);V.e.Va.call(this,a,b,c);a.f&&this.f&&bd(this,a);b<=this.h&&this.h++};
+V.prototype.removeChild=function(a,b){a=m(a)?fc(this,a):a;Aa(a,S);if(a){var c=kc(this,a);-1!=c&&(c==this.h?(a.B(!1),this.h=-1):c<this.h&&this.h--);var d=a.a();d&&d.id&&this.M&&(c=this.M,d=d.id,d in c&&delete c[d])}a=V.e.removeChild.call(this,a,b);a.Pa(!0);return a};var Lc=function(a,b){if(a.a())throw Error("Component already rendered");a.L=b};f=V.prototype;f.s=function(){return this.n};
 f.ka=function(a,b){if(b||this.n!=a&&this.dispatchEvent(a?"show":"hide")){this.n=a;var c=this.a();c&&(J(c,a),this.I()&&Jc(this.j(),this.U&&this.n),b||this.dispatchEvent(this.n?"aftershow":"afterhide"));return!0}return!1};f.isEnabled=function(){return this.U};f.ca=function(a){this.U!=a&&this.dispatchEvent(a?"enable":"disable")&&(a?(this.U=!0,hc(this,function(a){a.wb?delete a.wb:a.ca(!0)})):(hc(this,function(a){a.isEnabled()?a.ca(!1):a.wb=!0}),this.aa=this.U=!1),this.I()&&Jc(this.j(),a&&this.n))};
 f.I=function(){return this.$a};f.oa=function(a){a!=this.$a&&this.f&&cd(this,a);this.$a=a;this.U&&this.n&&Jc(this.j(),a)};var dd=function(a,b){var c=M(a,b);c?c.B(!0):-1<a.h&&M(a,a.h).B(!1)};V.prototype.B=function(a){dd(this,kc(this,a))};
 var ed=function(a){id(a,function(a,c){return(a+1)%c},ic(a)-1)},fd=function(a){id(a,function(a,c){a--;return 0>a?c-1:a},0)},hd=function(a){id(a,function(a,c){return(a+1)%c},a.h)},gd=function(a){id(a,function(a,c){a--;return 0>a?c-1:a},a.h)},id=function(a,b,c){c=0>c?kc(a,a.i):c;var d=ic(a);c=b.call(a,c,d);for(var e=0;e<=d;){var g=M(a,c);if(g&&g.s()&&g.isEnabled()&&g.l&2){a.Wa(c);break}e++;c=b.call(a,c,d)}};V.prototype.Wa=function(a){dd(this,a)};var jd=function(){};p(jd,R);ba(jd);f=jd.prototype;f.v=function(){return"goog-tab"};f.fa=function(){return"tab"};f.o=function(a){var b=jd.e.o.call(this,a);(a=a.Ua())&&this.Xa(b,a);return b};f.K=function(a,b){b=jd.e.K.call(this,a,b);var c=this.Ua(b);c&&(a.sb=c);a.g&8&&(c=a.getParent())&&n(c.V)&&(a.t(8,!1),c.V(a));return b};f.Ua=function(a){return a.title||""};f.Xa=function(a,b){a&&(a.title=b||"")};var kd=function(a,b,c){S.call(this,a,b||jd.ia(),c);Zc(this,8,!0);this.T|=9};p(kd,S);kd.prototype.Ua=function(){return this.sb};kd.prototype.Xa=function(a){this.zb().Xa(this.a(),a);this.sb=a};Hc("goog-tab",function(){return new kd(null)});var W=function(){this.Gb="tablist"};p(W,Q);ba(W);W.prototype.v=function(){return"goog-tab-bar"};W.prototype.bb=function(a,b,c){this.Ab||(this.Ka||ld(this),this.Ab=Pa(this.Ka));var d=this.Ab[b];d?(Lc(a,md(d)),a.xb=d):W.e.bb.call(this,a,b,c)};W.prototype.ta=function(a){var b=W.e.ta.call(this,a);this.Ka||ld(this);b.push(this.Ka[a.xb]);return b};var ld=function(a){var b=a.v();a.Ka={top:b+"-top",bottom:b+"-bottom",start:b+"-start",end:b+"-end"}};var X=function(a,b,c){a=a||"top";Lc(this,md(a));this.xb=a;V.call(this,this.L,b||W.ia(),c);nd(this)};p(X,V);f=X.prototype;f.ac=!0;f.H=null;f.D=function(){X.e.D.call(this);nd(this)};f.removeChild=function(a,b){od(this,a);return X.e.removeChild.call(this,a,b)};f.Wa=function(a){X.e.Wa.call(this,a);this.ac&&this.V(M(this,a))};f.V=function(a){a?Xc(a,!0):this.H&&Xc(this.H,!1)};
diff --git a/google/appengine/tools/app_engine_web_xml_parser.py b/google/appengine/tools/app_engine_web_xml_parser.py
index 288ef5a..f83463c 100644
--- a/google/appengine/tools/app_engine_web_xml_parser.py
+++ b/google/appengine/tools/app_engine_web_xml_parser.py
@@ -77,8 +77,8 @@
 
         raise AppEngineConfigException('\n'.join(self.errors))
       return self.app_engine_web_xml
-    except ElementTree.ParseError:
-      raise AppEngineConfigException('Bad input -- not valid XML')
+    except ElementTree.ParseError as e:
+      raise AppEngineConfigException('Bad input -- not valid XML: %s' % e)
 
   def ProcessChildNode(self, child_node):
     """Processes second-level nodes one by one.
diff --git a/google/appengine/tools/appcfg.py b/google/appengine/tools/appcfg.py
index d77e83c..730c858 100644
--- a/google/appengine/tools/appcfg.py
+++ b/google/appengine/tools/appcfg.py
@@ -3139,6 +3139,9 @@
                       dest='auth_local_webserver', default=True,
                       help='Do not run a local web server to handle redirects '
                       'during OAuth authorization.')
+    parser.add_option('--called_by_gcloud',
+                      action='store_true', default=False,
+                      help=optparse.SUPPRESS_HELP)
     return parser
 
   def _MakeSpecificParser(self, action):
@@ -3614,14 +3617,31 @@
       paths to absolute paths, its stderr is raised.
     """
 
-    if (not self.options.precompilation and
-        appyaml.GetEffectiveRuntime() == 'go'):
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    runtime = appyaml.GetEffectiveRuntime()
+    if appyaml.vm and (self.options.called_by_gcloud or runtime != 'go'):
+      self.options.precompilation = False
+    elif runtime == 'dart':
+      self.options.precompilation = False
+    elif runtime == 'go' and not self.options.precompilation:
       logging.warning('Precompilation is required for Go apps; '
                       'ignoring --no_precompilation')
       self.options.precompilation = True
-
-    if (appyaml.runtime.startswith('java') or
-        appyaml.GetEffectiveRuntime() == 'dart'):
+    elif (runtime.startswith('java') and
+          appinfo.JAVA_PRECOMPILED not in (appyaml.derived_file_type or [])):
       self.options.precompilation = False
 
     if self.options.precompilation:
diff --git a/google/appengine/tools/appcfg_java.py b/google/appengine/tools/appcfg_java.py
index 6529a9f..2b7cf5b 100644
--- a/google/appengine/tools/appcfg_java.py
+++ b/google/appengine/tools/appcfg_java.py
@@ -20,6 +20,7 @@
 import os.path
 import re
 import shutil
+import stat
 import subprocess
 import sys
 import tempfile
@@ -341,7 +342,11 @@
       os.makedirs(destdir)
     if self._ShouldSplitJar(source):
       self._SplitJar(source, destdir)
-    elif source.endswith('web.xml') or self.options.no_symlinks:
+    elif source.endswith('web.xml'):
+      shutil.copy(source, dest)
+      os.chmod(dest, os.stat(dest).st_mode | stat.S_IWRITE)
+
+    elif self.options.no_symlinks:
       shutil.copy(source, dest)
     else:
       os.symlink(source, dest)
diff --git a/google/appengine/tools/dev-channel-js.js b/google/appengine/tools/dev-channel-js.js
index 727d347..d18d596 100644
--- a/google/appengine/tools/dev-channel-js.js
+++ b/google/appengine/tools/dev-channel-js.js
@@ -700,12 +700,6 @@
   }
   return goog.string.jsEscapeCache_[c] = rv;
 };
-goog.string.toMap = function(s) {
-  for (var rv = {}, i = 0;i < s.length;i++) {
-    rv[s.charAt(i)] = !0;
-  }
-  return rv;
-};
 goog.string.contains = function(str, subString) {
   return-1 != str.indexOf(subString);
 };
@@ -1278,108 +1272,6 @@
     arr[j] = tmp;
   }
 };
-goog.functions = {};
-goog.functions.constant = function(retValue) {
-  return function() {
-    return retValue;
-  };
-};
-goog.functions.FALSE = goog.functions.constant(!1);
-goog.functions.TRUE = goog.functions.constant(!0);
-goog.functions.NULL = goog.functions.constant(null);
-goog.functions.identity = function(opt_returnValue) {
-  return opt_returnValue;
-};
-goog.functions.error = function(message) {
-  return function() {
-    throw Error(message);
-  };
-};
-goog.functions.fail = function(err) {
-  return function() {
-    throw err;
-  };
-};
-goog.functions.lock = function(f, opt_numArgs) {
-  opt_numArgs = opt_numArgs || 0;
-  return function() {
-    return f.apply(this, Array.prototype.slice.call(arguments, 0, opt_numArgs));
-  };
-};
-goog.functions.nth = function(n) {
-  return function() {
-    return arguments[n];
-  };
-};
-goog.functions.withReturnValue = function(f, retValue) {
-  return goog.functions.sequence(f, goog.functions.constant(retValue));
-};
-goog.functions.compose = function(fn, var_args) {
-  var functions = arguments, length = functions.length;
-  return function() {
-    var result;
-    length && (result = functions[length - 1].apply(this, arguments));
-    for (var i = length - 2;0 <= i;i--) {
-      result = functions[i].call(this, result);
-    }
-    return result;
-  };
-};
-goog.functions.sequence = function(var_args) {
-  var functions = arguments, length = functions.length;
-  return function() {
-    for (var result, i = 0;i < length;i++) {
-      result = functions[i].apply(this, arguments);
-    }
-    return result;
-  };
-};
-goog.functions.and = function(var_args) {
-  var functions = arguments, length = functions.length;
-  return function() {
-    for (var i = 0;i < length;i++) {
-      if (!functions[i].apply(this, arguments)) {
-        return!1;
-      }
-    }
-    return!0;
-  };
-};
-goog.functions.or = function(var_args) {
-  var functions = arguments, length = functions.length;
-  return function() {
-    for (var i = 0;i < length;i++) {
-      if (functions[i].apply(this, arguments)) {
-        return!0;
-      }
-    }
-    return!1;
-  };
-};
-goog.functions.not = function(f) {
-  return function() {
-    return!f.apply(this, arguments);
-  };
-};
-goog.functions.create = function(constructor, var_args) {
-  var temp = function() {
-  };
-  temp.prototype = constructor.prototype;
-  var obj = new temp;
-  constructor.apply(obj, Array.prototype.slice.call(arguments, 1));
-  return obj;
-};
-goog.functions.CACHE_RETURN_VALUE = !0;
-goog.functions.cacheReturnValue = function(fn) {
-  var called = !1, value;
-  return function() {
-    if (!goog.functions.CACHE_RETURN_VALUE) {
-      return fn();
-    }
-    called || (value = fn(), called = !0);
-    return value;
-  };
-};
 goog.math = {};
 goog.math.randomInt = function(a) {
   return Math.floor(Math.random() * a);
@@ -1854,7 +1746,7 @@
   return goog.labs.userAgent.util.matchUserAgent("Chrome") || goog.labs.userAgent.util.matchUserAgent("CriOS");
 };
 goog.labs.userAgent.browser.matchAndroidBrowser_ = function() {
-  return goog.labs.userAgent.util.matchUserAgent("Android") && !goog.labs.userAgent.util.matchUserAgent("Chrome") && !goog.labs.userAgent.util.matchUserAgent("CriOS");
+  return!goog.labs.userAgent.browser.isChrome() && goog.labs.userAgent.util.matchUserAgent("Android");
 };
 goog.labs.userAgent.browser.isOpera = goog.labs.userAgent.browser.matchOpera_;
 goog.labs.userAgent.browser.isIE = goog.labs.userAgent.browser.matchIE_;
@@ -1866,15 +1758,28 @@
   return goog.labs.userAgent.util.matchUserAgent("Silk");
 };
 goog.labs.userAgent.browser.getVersion = function() {
+  function lookUpValueWithKeys(keys) {
+    var key = goog.array.find(keys, versionMapHasKey);
+    return versionMap[key] || "";
+  }
   var userAgentString = goog.labs.userAgent.util.getUserAgent();
   if (goog.labs.userAgent.browser.isIE()) {
     return goog.labs.userAgent.browser.getIEVersion_(userAgentString);
   }
+  var versionTuples = goog.labs.userAgent.util.extractVersionTuples(userAgentString), versionMap = {};
+  goog.array.forEach(versionTuples, function(tuple) {
+    var key = tuple[0], value = tuple[1];
+    versionMap[key] = value;
+  });
+  var versionMapHasKey = goog.partial(goog.object.containsKey, versionMap);
   if (goog.labs.userAgent.browser.isOpera()) {
-    return goog.labs.userAgent.browser.getOperaVersion_(userAgentString);
+    return lookUpValueWithKeys(["Version", "Opera", "OPR"]);
   }
-  var versionTuples = goog.labs.userAgent.util.extractVersionTuples(userAgentString);
-  return goog.labs.userAgent.browser.getVersionFromTuples_(versionTuples);
+  if (goog.labs.userAgent.browser.isChrome()) {
+    return lookUpValueWithKeys(["Chrome", "CriOS"]);
+  }
+  var tuple = versionTuples[2];
+  return tuple && tuple[1] || "";
 };
 goog.labs.userAgent.browser.isVersionOrHigher = function(version) {
   return 0 <= goog.string.compareVersions(goog.labs.userAgent.browser.getVersion(), version);
@@ -1911,14 +1816,6 @@
   }
   return version;
 };
-goog.labs.userAgent.browser.getOperaVersion_ = function(userAgent) {
-  var versionTuples = goog.labs.userAgent.util.extractVersionTuples(userAgent), lastTuple = goog.array.peek(versionTuples);
-  return "OPR" == lastTuple[0] && lastTuple[1] ? lastTuple[1] : goog.labs.userAgent.browser.getVersionFromTuples_(versionTuples);
-};
-goog.labs.userAgent.browser.getVersionFromTuples_ = function(versionTuples) {
-  goog.asserts.assert(2 < versionTuples.length, "Couldn't extract version tuple from user agent string");
-  return versionTuples[2] && versionTuples[2][1] ? versionTuples[2][1] : "";
-};
 goog.labs.userAgent.engine = {};
 goog.labs.userAgent.engine.isPresto = function() {
   return goog.labs.userAgent.util.matchUserAgent("Presto");
@@ -2713,10 +2610,10 @@
   }
   return null;
 };
-goog.dom.getPixelRatio = goog.functions.cacheReturnValue(function() {
+goog.dom.getPixelRatio = function() {
   var win = goog.dom.getWindow(), isFirefoxMobile = goog.userAgent.GECKO && goog.userAgent.MOBILE;
   return goog.isDef(win.devicePixelRatio) && !isFirefoxMobile ? win.devicePixelRatio : win.matchMedia ? goog.dom.matchesPixelRatio_(.75) || goog.dom.matchesPixelRatio_(1.5) || goog.dom.matchesPixelRatio_(2) || goog.dom.matchesPixelRatio_(3) || 1 : 1;
-});
+};
 goog.dom.matchesPixelRatio_ = function(pixelRatio) {
   var win = goog.dom.getWindow(), query = "(-webkit-min-device-pixel-ratio: " + pixelRatio + "),(min--moz-device-pixel-ratio: " + pixelRatio + "),(min-resolution: " + pixelRatio + "dppx)";
   return win.matchMedia(query).matches ? pixelRatio : 0;
@@ -3626,6 +3523,108 @@
 goog.structs = {};
 goog.structs.Collection = function() {
 };
+goog.functions = {};
+goog.functions.constant = function(retValue) {
+  return function() {
+    return retValue;
+  };
+};
+goog.functions.FALSE = goog.functions.constant(!1);
+goog.functions.TRUE = goog.functions.constant(!0);
+goog.functions.NULL = goog.functions.constant(null);
+goog.functions.identity = function(opt_returnValue) {
+  return opt_returnValue;
+};
+goog.functions.error = function(message) {
+  return function() {
+    throw Error(message);
+  };
+};
+goog.functions.fail = function(err) {
+  return function() {
+    throw err;
+  };
+};
+goog.functions.lock = function(f, opt_numArgs) {
+  opt_numArgs = opt_numArgs || 0;
+  return function() {
+    return f.apply(this, Array.prototype.slice.call(arguments, 0, opt_numArgs));
+  };
+};
+goog.functions.nth = function(n) {
+  return function() {
+    return arguments[n];
+  };
+};
+goog.functions.withReturnValue = function(f, retValue) {
+  return goog.functions.sequence(f, goog.functions.constant(retValue));
+};
+goog.functions.compose = function(fn, var_args) {
+  var functions = arguments, length = functions.length;
+  return function() {
+    var result;
+    length && (result = functions[length - 1].apply(this, arguments));
+    for (var i = length - 2;0 <= i;i--) {
+      result = functions[i].call(this, result);
+    }
+    return result;
+  };
+};
+goog.functions.sequence = function(var_args) {
+  var functions = arguments, length = functions.length;
+  return function() {
+    for (var result, i = 0;i < length;i++) {
+      result = functions[i].apply(this, arguments);
+    }
+    return result;
+  };
+};
+goog.functions.and = function(var_args) {
+  var functions = arguments, length = functions.length;
+  return function() {
+    for (var i = 0;i < length;i++) {
+      if (!functions[i].apply(this, arguments)) {
+        return!1;
+      }
+    }
+    return!0;
+  };
+};
+goog.functions.or = function(var_args) {
+  var functions = arguments, length = functions.length;
+  return function() {
+    for (var i = 0;i < length;i++) {
+      if (functions[i].apply(this, arguments)) {
+        return!0;
+      }
+    }
+    return!1;
+  };
+};
+goog.functions.not = function(f) {
+  return function() {
+    return!f.apply(this, arguments);
+  };
+};
+goog.functions.create = function(constructor, var_args) {
+  var temp = function() {
+  };
+  temp.prototype = constructor.prototype;
+  var obj = new temp;
+  constructor.apply(obj, Array.prototype.slice.call(arguments, 1));
+  return obj;
+};
+goog.functions.CACHE_RETURN_VALUE = !0;
+goog.functions.cacheReturnValue = function(fn) {
+  var called = !1, value;
+  return function() {
+    if (!goog.functions.CACHE_RETURN_VALUE) {
+      return fn();
+    }
+    called || (value = fn(), called = !0);
+    return value;
+  };
+};
 goog.iter = {};
 goog.iter.StopIteration = "StopIteration" in goog.global ? goog.global.StopIteration : Error("StopIteration");
 goog.iter.Iterator = function() {
@@ -5001,8 +5000,8 @@
     }
   }
 };
-goog.uri.utils.decodeIfPossible_ = function(uri) {
-  return uri && decodeURIComponent(uri);
+goog.uri.utils.decodeIfPossible_ = function(uri, opt_preserveReserved) {
+  return uri ? opt_preserveReserved ? decodeURI(uri) : decodeURIComponent(uri) : uri;
 };
 goog.uri.utils.getComponentByIndex_ = function(componentIndex, uri) {
   return goog.uri.utils.split(uri)[componentIndex] || null;
@@ -5027,7 +5026,7 @@
   return goog.uri.utils.getComponentByIndex_(goog.uri.utils.ComponentIndex.DOMAIN, uri);
 };
 goog.uri.utils.getDomain = function(uri) {
-  return goog.uri.utils.decodeIfPossible_(goog.uri.utils.getDomainEncoded(uri));
+  return goog.uri.utils.decodeIfPossible_(goog.uri.utils.getDomainEncoded(uri), !0);
 };
 goog.uri.utils.getPort = function(uri) {
   return Number(goog.uri.utils.getComponentByIndex_(goog.uri.utils.ComponentIndex.PORT, uri)) || null;
@@ -5036,7 +5035,7 @@
   return goog.uri.utils.getComponentByIndex_(goog.uri.utils.ComponentIndex.PATH, uri);
 };
 goog.uri.utils.getPath = function(uri) {
-  return goog.uri.utils.decodeIfPossible_(goog.uri.utils.getPathEncoded(uri));
+  return goog.uri.utils.decodeIfPossible_(goog.uri.utils.getPathEncoded(uri), !0);
 };
 goog.uri.utils.getQueryData = function(uri) {
   return goog.uri.utils.getComponentByIndex_(goog.uri.utils.ComponentIndex.QUERY_DATA, uri);
diff --git a/google/appengine/tools/devappserver2/admin/templates/modules.html b/google/appengine/tools/devappserver2/admin/templates/modules.html
index 1df35b6..ee72953 100644
--- a/google/appengine/tools/devappserver2/admin/templates/modules.html
+++ b/google/appengine/tools/devappserver2/admin/templates/modules.html
@@ -15,6 +15,7 @@
         <th>Latency (ms)</th>
         <th>QPS</th>
         <th>Total Requests</th>
+        <th>Runtime</th>
       </tr>
     </thead>
     <tbody>
@@ -24,6 +25,12 @@
           <a href="//{{ module.balanced_address }}" target="_blank">
             {{ module.name }}</a>
         </th>
+        <td>
+          {% if module.runtime == "vm" %}
+            vm:
+          {% endif %}
+          {{ module.effective_runtime }}
+        </td>
       </tr>
       {% for instance in module.instances|sort(attribute='instance_id') %}
       <tr class="instance">
diff --git a/google/appengine/tools/devappserver2/application_configuration.py b/google/appengine/tools/devappserver2/application_configuration.py
index b02317a..d276f3d 100644
--- a/google/appengine/tools/devappserver2/application_configuration.py
+++ b/google/appengine/tools/devappserver2/application_configuration.py
@@ -14,7 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-"""Stores application configuration taken from e.g. app.yaml, queues.yaml."""
+"""Stores application configuration taken from e.g. app.yaml, index.yaml."""
 
 # TODO: Support more than just app.yaml.
 
@@ -32,6 +32,7 @@
 from google.appengine.api import appinfo_includes
 from google.appengine.api import backendinfo
 from google.appengine.api import dispatchinfo
+from google.appengine.tools import queue_xml_parser
 from google.appengine.tools import yaml_translator
 from google.appengine.tools.devappserver2 import errors
 
@@ -119,6 +120,8 @@
     self._minor_version_id = ''.join(random.choice(string.digits) for _ in
                                      range(18))
 
+    self._translate_configuration_files()
+
   @property
   def application_root(self):
     """The directory containing the application e.g. "/home/user/myapp"."""
@@ -355,6 +358,27 @@
     config = appinfo.LoadSingleAppInfo(app_yaml_str)
     return config, [app_engine_web_xml_path, web_xml_path]
 
+  def _translate_configuration_files(self):
+    """Writes YAML equivalents of certain XML configuration files."""
+    # For the most part we translate files in memory rather than writing out
+    # translations. But since the task queue stub (taskqueue_stub.py)
+    # reads queue.yaml directly rather than being configured with it, we need
+    # to write a translation for the stub to find.
+    # This means that we won't detect a change to the queue.xml, but we don't
+    # currently have logic to react to changes to queue.yaml either.
+    web_inf = os.path.join(self._application_root, 'WEB-INF')
+    queue_xml_file = os.path.join(web_inf, 'queue.xml')
+    if os.path.exists(queue_xml_file):
+      appengine_generated = os.path.join(web_inf, 'appengine-generated')
+      if not os.path.exists(appengine_generated):
+        os.mkdir(appengine_generated)
+      queue_yaml_file = os.path.join(appengine_generated, 'queue.yaml')
+      with open(queue_xml_file) as f:
+        queue_xml = f.read()
+      queue_yaml = queue_xml_parser.GetQueueYaml(None, queue_xml)
+      with open(queue_yaml_file, 'w') as f:
+        f.write(queue_yaml)
+
 
 class BackendsConfiguration(object):
   """Stores configuration information for a backends.yaml file."""
diff --git a/google/appengine/tools/devappserver2/go_application.py b/google/appengine/tools/devappserver2/go_application.py
index fa65b48..c3e20c8 100644
--- a/google/appengine/tools/devappserver2/go_application.py
+++ b/google/appengine/tools/devappserver2/go_application.py
@@ -59,26 +59,25 @@
   return ','.join([f.replace('\\', r'\\').replace(',', r'\,') for f in flags])
 
 
-def _get_base_gab_args(module_config, arch):
+def _get_base_gab_args(application_root, nobuild_files, arch):
   """Returns the base arguments for invoking go-app-builder.
 
   Args:
-    module_config: An application_configuration.ModuleConfiguration
-        instance storing the configuration data for a module.
+    application_root: string path to the root dir of the application.
+    nobuild_files: regexp identifying which files to not build.
     arch: The one-character architecture designator (5, 6, or 8).
 
   Returns:
     List of strings of arguments for invoking go-app-builder.
   """
   # Go's regexp package does not implicitly anchor to the start.
-  nobuild_files = '^' + str(module_config.nobuild_files)
   gab_args = [
       _GAB_PATH,
-      '-app_base', module_config.application_root,
+      '-app_base', application_root,
       '-arch', arch,
       '-dynamic',
       '-goroot', GOROOT,
-      '-nobuild_files', nobuild_files,
+      '-nobuild_files', '^' + str(nobuild_files),
       '-unsafe',
   ]
   if 'GOPATH' in os.environ:
@@ -86,41 +85,43 @@
   return gab_args
 
 
-def list_go_files(module_config):
+def list_go_files(application_root, nobuild_files, skip_files):
   """Returns a list of all Go files under the application root.
 
   Args:
-    module_config: An application_configuration.ModuleConfiguration
-        instance storing the configuration data for a module.
+    application_root: string path to the root dir of the application.
+    nobuild_files: regexp identifying which files to not build.
+    skip_files: regexp identifying which files to omit from app.
 
   Returns:
     A list of every .go file under the application root, relative to
     that root.
   """
   go_files = []
-  for root, _, file_names in os.walk(module_config.application_root):
+  for root, _, file_names in os.walk(application_root):
     for file_name in file_names:
       if not file_name.endswith('.go'):
         continue
       full_path = os.path.join(root, file_name)
-      rel_path = os.path.relpath(full_path, module_config.application_root)
-      if module_config.skip_files.match(rel_path):
+      rel_path = os.path.relpath(full_path, application_root)
+      if skip_files.match(rel_path):
         continue
-      if module_config.nobuild_files.match(rel_path):
+      if nobuild_files.match(rel_path):
         continue
 
       go_files.append(rel_path)
   return go_files
 
 
-def get_app_extras_for_vm(module_config):
+def get_app_extras_for_vm(application_root, nobuild_files, skip_files):
   """Returns an iterable describing extra Go files needed to build VM apps.
 
   The Go files are decided based on the production environment linux/amd64.
 
   Args:
-    module_config: An application_configuration.ModuleConfiguration
-        instance storing the configuration data for a module.
+    application_root: string path to the root dir of the application.
+    nobuild_files: regexp identifying which files to not build.
+    skip_files: regexp identifying which files to omit from app.
 
   Returns:
     An iterable of pairs, one per extra Go file. The first pair element
@@ -130,9 +131,9 @@
   Raises:
     BuildError: if the go application builder fails.
   """
-  gab_args = _get_base_gab_args(module_config, '6')
+  gab_args = _get_base_gab_args(application_root, nobuild_files, '6')
   gab_args.extend(['-print_extras', '-vm'])
-  gab_args.extend(list_go_files(module_config))
+  gab_args.extend(list_go_files(application_root, nobuild_files, skip_files))
   env = {
       'GOOS': 'linux',
       'GOARCH': 'amd64',
@@ -223,7 +224,9 @@
     """
     app_root = self._module_configuration.application_root
     go_file_to_mtime = {}
-    for rel_path in list_go_files(self._module_configuration):
+    for rel_path in list_go_files(
+        app_root, self._module_configuration.nobuild_files,
+        self._module_configuration.skip_files):
       full_path = os.path.join(app_root, rel_path)
       try:
         go_file_to_mtime[rel_path] = os.path.getmtime(full_path)
@@ -242,7 +245,9 @@
     Raises:
       BuildError: if the go application builder fails.
     """
-    gab_args = _get_base_gab_args(self._module_configuration, self._arch)
+    gab_args = _get_base_gab_args(
+        self._module_configuration.application_root,
+        self._module_configuration.nobuild_files, self._arch)
     gab_args.append('-print_extras_hash')
     gab_args.extend(self._go_file_to_mtime)
 
@@ -262,7 +267,9 @@
     assert self._go_file_to_mtime, 'no .go files'
     logging.debug('Building Go application')
 
-    gab_args = _get_base_gab_args(self._module_configuration, self._arch)
+    gab_args = _get_base_gab_args(
+        self._module_configuration.application_root,
+        self._module_configuration.nobuild_files, self._arch)
     gab_args.extend([
         '-binary_name', '_go_app',
         '-extra_imports', 'appengine_internal/init',
diff --git a/google/appengine/tools/devappserver2/http_proxy.py b/google/appengine/tools/devappserver2/http_proxy.py
index 651600d..3dcb0c5 100644
--- a/google/appengine/tools/devappserver2/http_proxy.py
+++ b/google/appengine/tools/devappserver2/http_proxy.py
@@ -95,7 +95,7 @@
       with contextlib.closing(connection):
         try:
           connection.connect()
-        except socket.error, httplib.HTTPException:
+        except (socket.error, httplib.HTTPException):
           return False
         else:
           return True
diff --git a/google/appengine/tools/devappserver2/http_runtime.py b/google/appengine/tools/devappserver2/http_runtime.py
index 8e2f9e8..3960374 100644
--- a/google/appengine/tools/devappserver2/http_runtime.py
+++ b/google/appengine/tools/devappserver2/http_runtime.py
@@ -116,7 +116,21 @@
   # TODO: Determine if we can always use SIGTERM.
   # Set this to True to quit with SIGTERM rather than SIGKILL
 
-  quit_with_sigterm = False
+  _quit_with_sigterm = False
+
+  @classmethod
+  def stop_runtimes_with_sigterm(cls, quit_with_sigterm):
+    """Configures the http_runtime module to kill the runtimes with SIGTERM.
+
+    Args:
+      quit_with_sigterm: True to enable stopping runtimes with SIGTERM.
+
+    Returns:
+      The previous value.
+    """
+    previous_quit_with_sigterm = cls._quit_with_sigterm
+    cls._quit_with_sigterm = quit_with_sigterm
+    return previous_quit_with_sigterm
 
   def __init__(self, args, runtime_config_getter, module_configuration,
                env=None, start_process_flavor=START_PROCESS):
@@ -280,7 +294,7 @@
     with self._process_lock:
       assert self._process, 'module was not running'
       try:
-        if HttpRuntimeProxy.quit_with_sigterm:
+        if HttpRuntimeProxy._quit_with_sigterm:
           logging.debug('Calling process.terminate on child runtime.')
           self._process.terminate()
         else:
diff --git a/google/appengine/tools/devappserver2/http_runtime_test.py b/google/appengine/tools/devappserver2/http_runtime_test.py
index f9ecc06..3d9ce09 100644
--- a/google/appengine/tools/devappserver2/http_runtime_test.py
+++ b/google/appengine/tools/devappserver2/http_runtime_test.py
@@ -129,19 +129,22 @@
 
     self.mox.StubOutWithMock(http_proxy.HttpProxy, 'wait_for_connection')
     http_proxy.HttpProxy.wait_for_connection()
-    self._saved_quit_with_sigterm = (
-        http_runtime.HttpRuntimeProxy.quit_with_sigterm)
+    self._saved_quit_with_sigterm = None
+
 
   def tearDown(self):
     shutil.rmtree(self.tmpdir)
     self.mox.UnsetStubs()
-    http_runtime.HttpRuntimeProxy.quit_with_sigterm = (
-        self._saved_quit_with_sigterm)
+    if self._saved_quit_with_sigterm is not None:
+      http_runtime.HttpRuntimeProxy.stop_runtimes_with_sigterm(
+          self._saved_quit_with_sigterm)
 
   def _test_start_and_quit(self, quit_with_sigterm):
     ## Test start()
     # start()
-    http_runtime.HttpRuntimeProxy.quit_with_sigterm = quit_with_sigterm
+    self._saved_quit_with_sigterm = (
+        http_runtime.HttpRuntimeProxy.stop_runtimes_with_sigterm(
+            quit_with_sigterm))
     safe_subprocess.start_process(
         ['/runtime'],
         base64.b64encode(self.runtime_config.SerializeToString()),
@@ -203,6 +206,7 @@
 
 
 class HttpRuntimeProxyFileFlavorTest(wsgi_test_utils.WSGITestCase):
+
   def setUp(self):
     self.mox = mox.Mox()
     self.tmpdir = tempfile.mkdtemp()
diff --git a/google/appengine/tools/devappserver2/module.py b/google/appengine/tools/devappserver2/module.py
index cc45c7a..1733e38 100644
--- a/google/appengine/tools/devappserver2/module.py
+++ b/google/appengine/tools/devappserver2/module.py
@@ -521,6 +521,16 @@
     return self._module_configuration
 
   @property
+  def runtime(self):
+    """Runtime property for this module."""
+    return self._module_configuration.runtime
+
+  @property
+  def effective_runtime(self):
+    """Effective_runtime property for this module."""
+    return self._module_configuration.effective_runtime
+
+  @property
   def supports_interactive_commands(self):
     """True if the module can evaluate arbitrary code and return the result."""
     return self._instance_factory.SUPPORTS_INTERACTIVE_REQUESTS
diff --git a/google/appengine/tools/devappserver2/module_test.py b/google/appengine/tools/devappserver2/module_test.py
index a4e0977..f7fee54 100644
--- a/google/appengine/tools/devappserver2/module_test.py
+++ b/google/appengine/tools/devappserver2/module_test.py
@@ -512,6 +512,91 @@
     self.mox.VerifyAll()
 
 
+class TestModuleRuntime(unittest.TestCase):
+  """Tests for module.Module.runtime."""
+
+  def setUp(self):
+    api_server.test_setup_stubs()
+    self.mox = mox.Mox()
+    self.mox.StubOutWithMock(application_configuration.ModuleConfiguration,
+                             '_parse_configuration')
+    self.mox.StubOutWithMock(os.path, 'getmtime')
+
+  def tearDown(self):
+    self.mox.UnsetStubs()
+
+  class ModuleStubRuntime(module.Module):
+
+    def __init__(self, module_configuration):
+      self._module_configuration = module_configuration
+
+  def test_vm_false(self):
+    automatic_scaling = appinfo.AutomaticScaling(min_pending_latency='1.0s',
+                                                 max_pending_latency='2.0s',
+                                                 min_idle_instances=1,
+                                                 max_idle_instances=2)
+    error_handlers = [appinfo.ErrorHandlers(file='error.html')]
+    handlers = [appinfo.URLMap(url=r'/python-(.*)',
+                               script=r'\1.py')]
+    info = appinfo.AppInfoExternal(
+        application='app',
+        module='module1',
+        version='1',
+        runtime='python27',
+        threadsafe=False,
+        automatic_scaling=automatic_scaling,
+        skip_files=r'\*.gif',
+        error_handlers=error_handlers,
+        handlers=handlers,
+        inbound_services=['warmup'],
+        env_variables=appinfo.EnvironmentVariables(),
+        )
+    config_path = '/appdir/app.yaml'
+    application_configuration.ModuleConfiguration._parse_configuration(
+        config_path).AndReturn((info, [config_path]))
+    os.path.getmtime(config_path).AndReturn(10)
+
+    self.mox.ReplayAll()
+    config = application_configuration.ModuleConfiguration(
+        '/appdir/app.yaml')
+    servr = TestModuleRuntime.ModuleStubRuntime(
+        module_configuration=config)
+    self.assertEqual(servr.runtime, 'python27')
+    self.assertEqual(servr.effective_runtime, 'python27')
+    self.mox.VerifyAll()
+
+  def test_vm_true(self):
+    manual_scaling = appinfo.ManualScaling()
+    vm_settings = appinfo.VmSettings()
+    vm_settings['vm_runtime'] = 'python27'
+    handlers = [appinfo.URLMap(url=r'/*', script=r'\1.py')]
+    info = appinfo.AppInfoExternal(
+        application='app',
+        module='module1',
+        version='1',
+        runtime='vm',
+        vm_settings=vm_settings,
+        threadsafe=False,
+        manual_scaling=manual_scaling,
+        handlers=handlers,
+        )
+    config_path = '/appdir/app.yaml'
+    application_configuration.ModuleConfiguration._parse_configuration(
+        config_path).AndReturn((info, [config_path]))
+    os.path.getmtime(config_path).AndReturn(10)
+
+    self.mox.ReplayAll()
+
+    module_configuration = application_configuration.ModuleConfiguration(
+        config_path)
+    servr = TestModuleRuntime.ModuleStubRuntime(
+        module_configuration=module_configuration)
+    self.assertEqual(servr.runtime, 'vm')
+    self.assertEqual(servr.effective_runtime, 'python27')
+
+    self.mox.VerifyAll()
+
+
 class TestAutoScalingModuleWarmup(unittest.TestCase):
   """Tests for module.AutoScalingModule._warmup."""
 
diff --git a/google/appengine/tools/devappserver2/php/runtime.py b/google/appengine/tools/devappserver2/php/runtime.py
index 4d7bda1..bd5d039 100644
--- a/google/appengine/tools/devappserver2/php/runtime.py
+++ b/google/appengine/tools/devappserver2/php/runtime.py
@@ -109,7 +109,7 @@
     # PHP environment. Put the user script in REAL_SCRIPT_FILENAME.
     user_environ['REAL_SCRIPT_FILENAME'] = os.path.normpath(
         os.path.join(self.config.application_root,
-                     environ[http_runtime_constants.SCRIPT_HEADER]))
+                     environ[http_runtime_constants.SCRIPT_HEADER].lstrip('/')))
     user_environ['SCRIPT_FILENAME'] = SETUP_PHP_PATH
     user_environ['REMOTE_REQUEST_ID'] = environ[
         http_runtime_constants.REQUEST_ID_ENVIRON]
diff --git a/google/appengine/tools/devappserver2/python/sandbox.py b/google/appengine/tools/devappserver2/python/sandbox.py
index 3064966..7a17f19 100644
--- a/google/appengine/tools/devappserver2/python/sandbox.py
+++ b/google/appengine/tools/devappserver2/python/sandbox.py
@@ -65,6 +65,31 @@
 # Store all the modules removed from sys.modules so they don't get cleaned up.
 _removed_modules = []
 
+_open_hooks = []
+
+
+def add_open_hook(install_open_hook):
+  """Hook the open chain to allow files to be opened from FS-like containers.
+
+  In order to allow files to be opened from FS-like containers such as zip
+  files, provide a sandbox compatible way to hook into the open chain. To
+  correctly work with our sandbox, these hooks must be called before FakeFile.
+  Due to code flow, the easiest way to allow that is for code to provide an
+  install function that the sandbox calls at the appropriate time.
+
+  Hook functions are expected to only handle paths that cannot be handled by
+  the standard filesystem open and are expected to forward all other paths
+  to the next hook. Hook functions are responsible for saving the next hook
+  function by getting the value of __builtin__.open when the install function
+  is called (very key point here, make sure to evaluate __builtin__.open when
+  your install function is called and not at import time).
+
+  Args:
+    install_open_hook: a method of no parameters that will install an open
+      hook.
+  """
+  _open_hooks.append(install_open_hook)
+
 
 def _make_request_id_aware_start_new_thread(base_start_new_thread):
   """Returns a replacement for start_new_thread that inherits request id.
@@ -140,6 +165,15 @@
   __builtin__.file = stubs.FakeFile
   __builtin__.open = stubs.FakeFile
   types.FileType = stubs.FakeFile
+  if _open_hooks:
+    for install_open_hook in _open_hooks:
+      install_open_hook()
+    # Assume installed open hooks don't enforce the sandbox path restrictions
+    # and install a final hook to do that (the goal of hooks is to allow
+    # alternate open techniques, not to circumvent the sandbox). It does mean
+    # that open requests that make it to FakeFile have their path checked
+    # twice but that doesn't break anything.
+    __builtin__.open = stubs.RestrictedPathFunction(__builtin__.open, IOError)
   sys.platform = 'linux3'
   enabled_library_regexes = [
       NAME_TO_CMODULE_WHITELIST_REGEX[lib.name] for lib in config.libraries
diff --git a/google/appengine/tools/devappserver2/python/stubs.py b/google/appengine/tools/devappserver2/python/stubs.py
index 2bc9bc1..aa426a3 100644
--- a/google/appengine/tools/devappserver2/python/stubs.py
+++ b/google/appengine/tools/devappserver2/python/stubs.py
@@ -55,12 +55,13 @@
   return ''.join(chr(random.randint(0, 255)) for _ in xrange(n))
 
 
-def fake_access(path, mode):
+def fake_access(path, mode, _os_access=os.access):
   """Fake version of os.access where only reads are supported."""
   if mode & (os.W_OK | os.X_OK):
     return False
-  else:
-    return FakeFile.is_file_accessible(path)
+  elif not FakeFile.is_file_accessible(path):
+    return False
+  return _os_access(path, mode)
 
 
 def fake_open(filename, flags, mode=0777, _os_open=os.open):
@@ -253,20 +254,23 @@
 class RestrictedPathFunction(object):
   """Enforces restrictions for functions with a path as their first argument."""
 
-  def __init__(self, original_func):
+  def __init__(self, original_func, error_class=OSError):
     """Initializer.
 
     Args:
       original_func: Callable that takes as its first argument the path to a
         file or directory on disk; all subsequent arguments may be variable.
+      error_class: The class of the error to raise when the file is not
+        accessible.
     """
     self._original_func = original_func
     functools.update_wrapper(self, original_func)
+    self._error_class = error_class
 
   def __call__(self, path, *args, **kwargs):
     """Enforces access permissions for the wrapped function."""
     if not FakeFile.is_file_accessible(path):
-      raise OSError(errno.EACCES, 'path not accessible', path)
+      raise self._error_class(errno.EACCES, 'path not accessible', path)
 
     return self._original_func(path, *args, **kwargs)
 
diff --git a/google/appengine/tools/devappserver2/vm_runtime_factory.py b/google/appengine/tools/devappserver2/vm_runtime_factory.py
index 8c7fa91..45abb5a 100644
--- a/google/appengine/tools/devappserver2/vm_runtime_factory.py
+++ b/google/appengine/tools/devappserver2/vm_runtime_factory.py
@@ -22,6 +22,7 @@
 import docker
 import requests
 
+from google.appengine.api import appinfo
 from google.appengine.tools.devappserver2 import instance
 from google.appengine.tools.devappserver2 import vm_runtime_proxy
 from google.appengine.tools.devappserver2 import vm_runtime_proxy_dart
@@ -39,6 +40,15 @@
 class VMRuntimeInstanceFactory(instance.InstanceFactory):
   """A factory that creates new VM runtime Instances."""
 
+  START_URL_MAP = appinfo.URLMap(
+      url='/_ah/start',
+      script='/dev/null',
+      login='admin')
+  WARMUP_URL_MAP = appinfo.URLMap(
+      url='/_ah/warmup',
+      script='/dev/null',
+      login='admin')
+
   RUNTIME_SPECIFIC_PROXY = {
       'dart': vm_runtime_proxy_dart.DartVMRuntimeProxy,
       'go': vm_runtime_proxy_go.GoVMRuntimeProxy,
diff --git a/google/appengine/tools/devappserver2/vm_runtime_proxy_go.py b/google/appengine/tools/devappserver2/vm_runtime_proxy_go.py
index 7942f6c..1819d8b 100644
--- a/google/appengine/tools/devappserver2/vm_runtime_proxy_go.py
+++ b/google/appengine/tools/devappserver2/vm_runtime_proxy_go.py
@@ -114,8 +114,9 @@
 
       with TempDir('go_deployment_dir') as dst_deployment_dir:
         build_go_docker_image_source(
-            application_dir, dst_deployment_dir,
-            _GO_APP_BUILDER, self._module_configuration)
+            application_dir, dst_deployment_dir, _GO_APP_BUILDER,
+            self._module_configuration.nobuild_files,
+            self._module_configuration.skip_files)
 
         self._vm_runtime_proxy.start(dockerfile_dir=dst_deployment_dir)
 
@@ -186,7 +187,8 @@
 
 
 def build_go_docker_image_source(
-    application_dir, dst_deployment_dir, go_app_builder, module_configuration):
+    application_dir, dst_deployment_dir, go_app_builder,
+    nobuild_files, skip_files):
   """Builds the Docker image source in preparation for building.
 
   Steps:
@@ -198,13 +200,11 @@
     application_dir: string pathname of application directory.
     dst_deployment_dir: string pathname of temporary deployment directory.
     go_app_builder: string pathname of docker-gab executable.
-    module_configuration: An application_configuration.ModuleConfiguration
-        instance respresenting the configuration of the module that owns the
-        runtime.
+    nobuild_files: regexp identifying which files to not build.
+    skip_files: regexp identifying which files to omit from app.
   """
   try:
-    _copytree(application_dir, dst_deployment_dir,
-              module_configuration.skip_files)
+    _copytree(application_dir, dst_deployment_dir, skip_files)
   except shutil.Error as e:
     logging.error('Error copying tree: %s', e)
     for src, unused_dst, unused_error in e.args[0]:
@@ -218,7 +218,8 @@
     logging.error('Failed to copy dir: %s', e.strerror)
     raise
 
-  extras = go_application.get_app_extras_for_vm(module_configuration)
+  extras = go_application.get_app_extras_for_vm(
+      application_dir, nobuild_files, skip_files)
   for dest, src in extras:
     try:
       dest = os.path.join(dst_deployment_dir, dest)
@@ -247,20 +248,20 @@
     raise
 
   # Write build script.
-  nobuild_files = '^' + str(module_configuration.nobuild_files)
   gab_args = [
       '/app/_ah/gab',
       '-app_base', '/app',
       '-arch', '6',
       '-dynamic',
       '-goroot', '/goroot',
-      '-nobuild_files', nobuild_files,
+      '-nobuild_files', '^' + str(nobuild_files),
       '-unsafe',
       '-binary_name', '_ah_exe',
       '-work_dir', '/tmp/work',
       '-vm',
   ]
-  gab_args.extend(go_application.list_go_files(module_configuration))
+  gab_args.extend(go_application.list_go_files(
+      application_dir, nobuild_files, skip_files))
   gab_args.extend([x[0] for x in extras])
   dst_build = os.path.join(ah_dir, 'build.sh')
   lines = [
diff --git a/google/appengine/tools/docker/containers.py b/google/appengine/tools/docker/containers.py
index e9514f2..e2b8fb5 100644
--- a/google/appengine/tools/docker/containers.py
+++ b/google/appengine/tools/docker/containers.py
@@ -414,7 +414,7 @@
   def Stop(self):
     """Stops a running container, removes it and underlying image if needed."""
     if self._id:
-      self._docker_client.stop(self.id)
+      self._docker_client.kill(self.id)
       self._docker_client.remove_container(self.id, v=False,
                                            link=False)
       self._id = None
diff --git a/google/appengine/tools/queue_xml_parser.py b/google/appengine/tools/queue_xml_parser.py
index 70b69fc..fa0b562 100644
--- a/google/appengine/tools/queue_xml_parser.py
+++ b/google/appengine/tools/queue_xml_parser.py
@@ -84,8 +84,8 @@
 
       return self.queue_xml
 
-    except ElementTree.ParseError:
-      raise AppEngineConfigException('Bad input -- not valid XML')
+    except ElementTree.ParseError as e:
+      raise AppEngineConfigException('Bad input -- not valid XML: %s' % e)
 
   def ProcessQueueNode(self, node):
     """Processes XML <queue> nodes into Queue objects.
diff --git a/google/net/proto2/proto/descriptor_pb2.py b/google/net/proto2/proto/descriptor_pb2.py
index 0741b69..7f7bde4 100644
--- a/google/net/proto2/proto/descriptor_pb2.py
+++ b/google/net/proto2/proto/descriptor_pb2.py
@@ -33,7 +33,7 @@
 DESCRIPTOR = _descriptor.FileDescriptor(
   name='net/proto2/proto/descriptor.proto',
   package='proto2',
-  serialized_pb=_b('\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\"\xa5\x03\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\x30\n\noneof_decl\x18\x08 \x03(\x0b\x32\x1c.proto2.OneofDescriptorProto\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\"\x8e\x05\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\x13\n\x0boneof_index\x18\t \x01(\x05\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\"$\n\x14OneofDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\"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\"\xa5\n\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\'\n\x19\x63\x63_proto_array_compatible\x18\x16 \x01(\x08:\x04true\x12\"\n\x14\x63\x63_utf8_verification\x18\x18 \x01(\x08:\x04true\x12$\n\x15\x63\x63_proto1_text_format\x18\x19 \x01(\x08:\x05\x66\x61lse\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\x34\n%java_enable_dual_generate_mutable_api\x18\x1a \x01(\x08:\x05\x66\x61lse\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\x16java_string_check_utf8\x18\x1b \x01(\x08:\x05\x66\x61lse\x12\x1f\n\x10java_mutable_api\x18\x1c \x01(\x08:\x05\x66\x61lse\x12+\n#java_multiple_files_mutable_package\x18\x1d \x01(\t\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\x19\n\ndeprecated\x18\x17 \x01(\x08:\x05\x66\x61lse\x12\x1a\n\x12\x65xperimental_style\x18\x1e \x01(\t\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\"\xe4\x02\n\x0eMessageOptions\x12+\n#experimental_java_message_interface\x18\x04 \x03(\t\x12+\n#experimental_java_builder_interface\x18\x05 \x03(\t\x12+\n#experimental_java_interface_extends\x18\x06 \x03(\t\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\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x11\n\tmap_entry\x18\x07 \x01(\x08\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xa0\x05\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\x0fupgraded_option\x18\x0b \x03(\x0b\x32#.proto2.FieldOptions.UpgradedOption\x12%\n\x16\x64\x65precated_raw_message\x18\x0c \x01(\x08:\x05\x66\x61lse\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption\x1a-\n\x0eUpgradedOption\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"/\n\x05\x43Type\x12\n\n\x06STRING\x10\x00\x12\x08\n\x04\x43ORD\x10\x01\x12\x10\n\x0cSTRING_PIECE\x10\x02\"<\n\x05JType\x12\n\n\x06NORMAL\x10\x00\x12\t\n\x05\x42YTES\x10\x01\x12\x1c\n\x18\x45XPERIMENTAL_BYTE_BUFFER\x10\x02\"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\"\x99\x01\n\x0b\x45numOptions\x12\x13\n\x0bproto1_name\x18\x01 \x01(\t\x12\x13\n\x0b\x61llow_alias\x18\x02 \x01(\x08\x12\x19\n\ndeprecated\x18\x03 \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\"t\n\x10\x45numValueOptions\x12\x19\n\ndeprecated\x18\x01 \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\"\xb6\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\x19\n\ndeprecated\x18! \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\"\xd3\t\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\'\n\x18\x65nd_user_creds_requested\x18\x1a \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\x18\n\x10\x63lient_streaming\x18\x14 \x01(\x08\x12\x18\n\x10server_streaming\x18\x15 \x01(\x08\x12\x1a\n\x12legacy_stream_type\x18\x16 \x01(\t\x12\x1a\n\x12legacy_result_type\x18\x17 \x01(\t\x12(\n\x1clegacy_client_initial_tokens\x18\x18 \x01(\x03:\x02-1\x12(\n\x1clegacy_server_initial_tokens\x18\x19 \x01(\x03:\x02-1\x12^\n\tlog_level\x18\x1b \x01(\x0e\x32\x1e.proto2.MethodOptions.LogLevel:+LOG_HEADER_AND_NON_PRIVATE_PAYLOAD_INTERNAL\x12\x19\n\ndeprecated\x18! \x01(\x08:\x05\x66\x61lse\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\"\x9f\x01\n\x08LogLevel\x12\x0c\n\x08LOG_NONE\x10\x00\x12\x13\n\x0fLOG_HEADER_ONLY\x10\x01\x12/\n+LOG_HEADER_AND_NON_PRIVATE_PAYLOAD_INTERNAL\x10\x02\x12#\n\x1fLOG_HEADER_AND_FILTERED_PAYLOAD\x10\x03\x12\x1a\n\x16LOG_HEADER_AND_PAYLOAD\x10\x04*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xe7\x04\n\rStreamOptions\x12!\n\x15\x63lient_initial_tokens\x18\x01 \x01(\x03:\x02-1\x12!\n\x15server_initial_tokens\x18\x02 \x01(\x03:\x02-1\x12<\n\ntoken_unit\x18\x03 \x01(\x0e\x32\x1f.proto2.StreamOptions.TokenUnit:\x07MESSAGE\x12\x41\n\x0esecurity_level\x18\x04 \x01(\x0e\x32#.proto2.MethodOptions.SecurityLevel:\x04NONE\x12\x16\n\x0esecurity_label\x18\x05 \x01(\t\x12\x1b\n\x0e\x63lient_logging\x18\x06 \x01(\x05:\x03\x32\x35\x36\x12\x1b\n\x0eserver_logging\x18\x07 \x01(\x05:\x03\x32\x35\x36\x12\x14\n\x08\x64\x65\x61\x64line\x18\x08 \x01(\x01:\x02-1\x12\x18\n\tfail_fast\x18\t \x01(\x08:\x05\x66\x61lse\x12\'\n\x18\x65nd_user_creds_requested\x18\n \x01(\x08:\x05\x66\x61lse\x12^\n\tlog_level\x18\x0b \x01(\x0e\x32\x1e.proto2.MethodOptions.LogLevel:+LOG_HEADER_AND_NON_PRIVATE_PAYLOAD_INTERNAL\x12\x19\n\ndeprecated\x18! \x01(\x08:\x05\x66\x61lse\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption\"\"\n\tTokenUnit\x12\x0b\n\x07MESSAGE\x10\x00\x12\x08\n\x04\x42YTE\x10\x01*\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\"\xa8\x01\n\x0eSourceCodeInfo\x12\x31\n\x08location\x18\x01 \x03(\x0b\x32\x1f.proto2.SourceCodeInfo.Location\x1a\x63\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\x12\x18\n\x10leading_comments\x18\x03 \x01(\t\x12\x19\n\x11trailing_comments\x18\x04 \x01(\tB,\n\x13\x63om.google.protobufB\x10\x44\x65scriptorProtosH\x01\xe0\x01\x01')
+  serialized_pb=_b('\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\"\xa5\x03\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\x30\n\noneof_decl\x18\x08 \x03(\x0b\x32\x1c.proto2.OneofDescriptorProto\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\"\x8e\x05\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\x13\n\x0boneof_index\x18\t \x01(\x05\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\"$\n\x14OneofDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\"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\"\xa5\n\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\'\n\x19\x63\x63_proto_array_compatible\x18\x16 \x01(\x08:\x04true\x12\"\n\x14\x63\x63_utf8_verification\x18\x18 \x01(\x08:\x04true\x12$\n\x15\x63\x63_proto1_text_format\x18\x19 \x01(\x08:\x05\x66\x61lse\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\x34\n%java_enable_dual_generate_mutable_api\x18\x1a \x01(\x08:\x05\x66\x61lse\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\x16java_string_check_utf8\x18\x1b \x01(\x08:\x05\x66\x61lse\x12\x1f\n\x10java_mutable_api\x18\x1c \x01(\x08:\x05\x66\x61lse\x12+\n#java_multiple_files_mutable_package\x18\x1d \x01(\t\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\x19\n\ndeprecated\x18\x17 \x01(\x08:\x05\x66\x61lse\x12\x1a\n\x12\x65xperimental_style\x18\x1e \x01(\t\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\"\xe4\x02\n\x0eMessageOptions\x12+\n#experimental_java_message_interface\x18\x04 \x03(\t\x12+\n#experimental_java_builder_interface\x18\x05 \x03(\t\x12+\n#experimental_java_interface_extends\x18\x06 \x03(\t\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\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x11\n\tmap_entry\x18\x07 \x01(\x08\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x82\x05\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\x13\n\x04weak\x18\n \x01(\x08:\x05\x66\x61lse\x12<\n\x0fupgraded_option\x18\x0b \x03(\x0b\x32#.proto2.FieldOptions.UpgradedOption\x12%\n\x16\x64\x65precated_raw_message\x18\x0c \x01(\x08:\x05\x66\x61lse\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption\x1a-\n\x0eUpgradedOption\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"/\n\x05\x43Type\x12\n\n\x06STRING\x10\x00\x12\x08\n\x04\x43ORD\x10\x01\x12\x10\n\x0cSTRING_PIECE\x10\x02\"<\n\x05JType\x12\n\n\x06NORMAL\x10\x00\x12\t\n\x05\x42YTES\x10\x01\x12\x1c\n\x18\x45XPERIMENTAL_BYTE_BUFFER\x10\x02\"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\"\x99\x01\n\x0b\x45numOptions\x12\x13\n\x0bproto1_name\x18\x01 \x01(\t\x12\x13\n\x0b\x61llow_alias\x18\x02 \x01(\x08\x12\x19\n\ndeprecated\x18\x03 \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\"t\n\x10\x45numValueOptions\x12\x19\n\ndeprecated\x18\x01 \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\"\xb6\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\x19\n\ndeprecated\x18! \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\"\xd3\t\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\'\n\x18\x65nd_user_creds_requested\x18\x1a \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\x18\n\x10\x63lient_streaming\x18\x14 \x01(\x08\x12\x18\n\x10server_streaming\x18\x15 \x01(\x08\x12\x1a\n\x12legacy_stream_type\x18\x16 \x01(\t\x12\x1a\n\x12legacy_result_type\x18\x17 \x01(\t\x12(\n\x1clegacy_client_initial_tokens\x18\x18 \x01(\x03:\x02-1\x12(\n\x1clegacy_server_initial_tokens\x18\x19 \x01(\x03:\x02-1\x12^\n\tlog_level\x18\x1b \x01(\x0e\x32\x1e.proto2.MethodOptions.LogLevel:+LOG_HEADER_AND_NON_PRIVATE_PAYLOAD_INTERNAL\x12\x19\n\ndeprecated\x18! \x01(\x08:\x05\x66\x61lse\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\"\x9f\x01\n\x08LogLevel\x12\x0c\n\x08LOG_NONE\x10\x00\x12\x13\n\x0fLOG_HEADER_ONLY\x10\x01\x12/\n+LOG_HEADER_AND_NON_PRIVATE_PAYLOAD_INTERNAL\x10\x02\x12#\n\x1fLOG_HEADER_AND_FILTERED_PAYLOAD\x10\x03\x12\x1a\n\x16LOG_HEADER_AND_PAYLOAD\x10\x04*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xe7\x04\n\rStreamOptions\x12!\n\x15\x63lient_initial_tokens\x18\x01 \x01(\x03:\x02-1\x12!\n\x15server_initial_tokens\x18\x02 \x01(\x03:\x02-1\x12<\n\ntoken_unit\x18\x03 \x01(\x0e\x32\x1f.proto2.StreamOptions.TokenUnit:\x07MESSAGE\x12\x41\n\x0esecurity_level\x18\x04 \x01(\x0e\x32#.proto2.MethodOptions.SecurityLevel:\x04NONE\x12\x16\n\x0esecurity_label\x18\x05 \x01(\t\x12\x1b\n\x0e\x63lient_logging\x18\x06 \x01(\x05:\x03\x32\x35\x36\x12\x1b\n\x0eserver_logging\x18\x07 \x01(\x05:\x03\x32\x35\x36\x12\x14\n\x08\x64\x65\x61\x64line\x18\x08 \x01(\x01:\x02-1\x12\x18\n\tfail_fast\x18\t \x01(\x08:\x05\x66\x61lse\x12\'\n\x18\x65nd_user_creds_requested\x18\n \x01(\x08:\x05\x66\x61lse\x12^\n\tlog_level\x18\x0b \x01(\x0e\x32\x1e.proto2.MethodOptions.LogLevel:+LOG_HEADER_AND_NON_PRIVATE_PAYLOAD_INTERNAL\x12\x19\n\ndeprecated\x18! \x01(\x08:\x05\x66\x61lse\x12:\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32\x1b.proto2.UninterpretedOption\"\"\n\tTokenUnit\x12\x0b\n\x07MESSAGE\x10\x00\x12\x08\n\x04\x42YTE\x10\x01*\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\"\xa8\x01\n\x0eSourceCodeInfo\x12\x31\n\x08location\x18\x01 \x03(\x0b\x32\x1f.proto2.SourceCodeInfo.Location\x1a\x63\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\x12\x18\n\x10leading_comments\x18\x03 \x01(\t\x12\x19\n\x11trailing_comments\x18\x04 \x01(\tB,\n\x13\x63om.google.protobufB\x10\x44\x65scriptorProtosH\x01\xe0\x01\x01')
 )
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
@@ -224,8 +224,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=4472,
-  serialized_end=4519,
+  serialized_start=4442,
+  serialized_end=4489,
 )
 _sym_db.RegisterEnumDescriptor(_FIELDOPTIONS_CTYPE)
 
@@ -250,8 +250,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=4521,
-  serialized_end=4581,
+  serialized_start=4491,
+  serialized_end=4551,
 )
 _sym_db.RegisterEnumDescriptor(_FIELDOPTIONS_JTYPE)
 
@@ -276,8 +276,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=4583,
-  serialized_end=4636,
+  serialized_start=4553,
+  serialized_end=4606,
 )
 _sym_db.RegisterEnumDescriptor(_FIELDOPTIONS_JSTYPE)
 
@@ -298,8 +298,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=5990,
-  serialized_end=6018,
+  serialized_start=5960,
+  serialized_end=5988,
 )
 _sym_db.RegisterEnumDescriptor(_METHODOPTIONS_PROTOCOL)
 
@@ -328,8 +328,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=6020,
-  serialized_end=6121,
+  serialized_start=5990,
+  serialized_end=6091,
 )
 _sym_db.RegisterEnumDescriptor(_METHODOPTIONS_SECURITYLEVEL)
 
@@ -350,8 +350,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=6123,
-  serialized_end=6171,
+  serialized_start=6093,
+  serialized_end=6141,
 )
 _sym_db.RegisterEnumDescriptor(_METHODOPTIONS_FORMAT)
 
@@ -384,8 +384,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=6174,
-  serialized_end=6333,
+  serialized_start=6144,
+  serialized_end=6303,
 )
 _sym_db.RegisterEnumDescriptor(_METHODOPTIONS_LOGLEVEL)
 
@@ -406,8 +406,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=6917,
-  serialized_end=6951,
+  serialized_start=6887,
+  serialized_end=6921,
 )
 _sym_db.RegisterEnumDescriptor(_STREAMOPTIONS_TOKENUNIT)
 
@@ -1362,8 +1362,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4425,
-  serialized_end=4470,
+  serialized_start=4395,
+  serialized_end=4440,
 )
 
 _FIELDOPTIONS = _descriptor.Descriptor(
@@ -1416,35 +1416,28 @@
       is_extension=False, extension_scope=None,
       options=None),
     _descriptor.FieldDescriptor(
-      name='experimental_map_key', full_name='proto2.FieldOptions.experimental_map_key', index=6,
-      number=9, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='weak', full_name='proto2.FieldOptions.weak', index=7,
+      name='weak', full_name='proto2.FieldOptions.weak', index=6,
       number=10, type=8, cpp_type=7, label=1,
       has_default_value=True, default_value=False,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       options=None),
     _descriptor.FieldDescriptor(
-      name='upgraded_option', full_name='proto2.FieldOptions.upgraded_option', index=8,
+      name='upgraded_option', full_name='proto2.FieldOptions.upgraded_option', index=7,
       number=11, 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='deprecated_raw_message', full_name='proto2.FieldOptions.deprecated_raw_message', index=9,
+      name='deprecated_raw_message', full_name='proto2.FieldOptions.deprecated_raw_message', index=8,
       number=12, type=8, cpp_type=7, label=1,
       has_default_value=True, default_value=False,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       options=None),
     _descriptor.FieldDescriptor(
-      name='uninterpreted_option', full_name='proto2.FieldOptions.uninterpreted_option', index=10,
+      name='uninterpreted_option', full_name='proto2.FieldOptions.uninterpreted_option', index=9,
       number=999, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
@@ -1465,7 +1458,7 @@
   oneofs=[
   ],
   serialized_start=3975,
-  serialized_end=4647,
+  serialized_end=4617,
 )
 
 
@@ -1515,8 +1508,8 @@
   extension_ranges=[(1000, 536870912), ],
   oneofs=[
   ],
-  serialized_start=4650,
-  serialized_end=4803,
+  serialized_start=4620,
+  serialized_end=4773,
 )
 
 
@@ -1552,8 +1545,8 @@
   extension_ranges=[(1000, 536870912), ],
   oneofs=[
   ],
-  serialized_start=4805,
-  serialized_end=4921,
+  serialized_start=4775,
+  serialized_end=4891,
 )
 
 
@@ -1603,8 +1596,8 @@
   extension_ranges=[(1000, 536870912), ],
   oneofs=[
   ],
-  serialized_start=4924,
-  serialized_end=5106,
+  serialized_start=4894,
+  serialized_end=5076,
 )
 
 
@@ -1777,8 +1770,8 @@
   extension_ranges=[(1000, 536870912), ],
   oneofs=[
   ],
-  serialized_start=5109,
-  serialized_end=6344,
+  serialized_start=5079,
+  serialized_end=6314,
 )
 
 
@@ -1892,8 +1885,8 @@
   extension_ranges=[(1000, 536870912), ],
   oneofs=[
   ],
-  serialized_start=6347,
-  serialized_end=6962,
+  serialized_start=6317,
+  serialized_end=6932,
 )
 
 
@@ -1929,8 +1922,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7191,
-  serialized_end=7242,
+  serialized_start=7161,
+  serialized_end=7212,
 )
 
 _UNINTERPRETEDOPTION = _descriptor.Descriptor(
@@ -2000,8 +1993,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6965,
-  serialized_end=7242,
+  serialized_start=6935,
+  serialized_end=7212,
 )
 
 
@@ -2051,8 +2044,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7314,
-  serialized_end=7413,
+  serialized_start=7284,
+  serialized_end=7383,
 )
 
 _SOURCECODEINFO = _descriptor.Descriptor(
@@ -2080,8 +2073,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7245,
-  serialized_end=7413,
+  serialized_start=7215,
+  serialized_end=7383,
 )
 
 _FILEDESCRIPTORSET.fields_by_name['file'].message_type = _FILEDESCRIPTORPROTO
diff --git a/google/net/proto2/python/internal/python_message.py b/google/net/proto2/python/internal/python_message.py
index 45f0110..b6915e0 100644
--- a/google/net/proto2/python/internal/python_message.py
+++ b/google/net/proto2/python/internal/python_message.py
@@ -92,7 +92,7 @@
   _AddPropertiesForExtensions(descriptor, cls)
   _AddStaticMethods(cls)
   _AddMessageMethods(descriptor, cls)
-  _AddPrivateHelperMethods(cls)
+  _AddPrivateHelperMethods(descriptor, cls)
   copyreg.pickle(cls, lambda obj: (cls, (), obj.__getstate__()))
 
 
@@ -170,7 +170,8 @@
                              '_is_present_in_parent',
                              '_listener',
                              '_listener_for_children',
-                             '__weakref__']
+                             '__weakref__',
+                             '_oneofs']
 
 
 def _IsMessageSetExtension(field):
@@ -297,6 +298,10 @@
     self._fields = {}
 
 
+    self._oneofs = {}
+
+
+
     self._unknown_fields = ()
     self._is_present_in_parent = False
     self._listener = message_listener_mod.NullMessageListener()
@@ -444,7 +449,7 @@
     return self._fields.get(field, default_value)
   getter.__module__ = None
   getter.__doc__ = 'Getter for %s.' % proto_field_name
-  def setter(self, new_value):
+  def field_setter(self, new_value):
 
     self._fields[field] = type_checker.CheckValue(new_value)
 
@@ -452,6 +457,13 @@
     if not self._cached_byte_size_dirty:
       self._Modified()
 
+  if field.containing_oneof is not None:
+    def setter(self, new_value):
+      field_setter(self, new_value)
+      self._UpdateOneofState(field)
+  else:
+    setter = field_setter
+
   setter.__module__ = None
   setter.__doc__ = 'Setter for %s.' % proto_field_name
 
@@ -487,7 +499,10 @@
     if field_value is None:
 
       field_value = message_type._concrete_class()
-      field_value._SetListener(self._listener_for_children)
+      field_value._SetListener(
+          _OneofListener(self, field)
+          if field.containing_oneof is not None
+          else self._listener_for_children)
 
 
 
@@ -584,6 +599,9 @@
     if field.label != _FieldDescriptor.LABEL_REPEATED:
       singular_fields[field.name] = field
 
+  for field in message_descriptor.oneofs:
+    singular_fields[field.name] = field
+
   def HasField(self, field_name):
     try:
       field = singular_fields[field_name]
@@ -591,11 +609,18 @@
       raise ValueError(
           'Protocol message has no singular "%s" field.' % field_name)
 
-    if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
-      value = self._fields.get(field)
-      return value is not None and value._is_present_in_parent
+    if isinstance(field, descriptor_mod.OneofDescriptor):
+      try:
+        return HasField(self, self._oneofs[field].name)
+      except KeyError:
+        return False
     else:
-      return field in self._fields
+      if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
+        value = self._fields.get(field)
+        return value is not None and value._is_present_in_parent
+      else:
+        return field in self._fields
+
   cls.HasField = HasField
 
 
@@ -605,7 +630,14 @@
     try:
       field = message_descriptor.fields_by_name[field_name]
     except KeyError:
-      raise ValueError('Protocol message has no "%s" field.' % field_name)
+      try:
+        field = message_descriptor.oneofs_by_name[field_name]
+        if field in self._oneofs:
+          field = self._oneofs[field]
+        else:
+          return
+      except KeyError:
+        raise ValueError('Protocol message has no "%s" field.' % field_name)
 
     if field in self._fields:
 
@@ -613,6 +645,9 @@
 
       del self._fields[field]
 
+      if self._oneofs.get(field.containing_oneof, None) is field:
+        del self._oneofs[field.containing_oneof]
+
 
 
 
@@ -948,6 +983,24 @@
   cls.MergeFrom = MergeFrom
 
 
+def _AddWhichOneofMethod(message_descriptor, cls):
+  def WhichOneof(self, oneof_name):
+    """Returns the name of the currently set field inside a oneof, or None."""
+    try:
+      field = message_descriptor.oneofs_by_name[oneof_name]
+    except KeyError:
+      raise ValueError(
+          'Protocol message has no oneof "%s" field.' % oneof_name)
+
+    nested_field = self._oneofs.get(field, None)
+    if nested_field is not None and self.HasField(nested_field.name):
+      return nested_field.name
+    else:
+      return None
+
+  cls.WhichOneof = WhichOneof
+
+
 def _AddMessageMethods(message_descriptor, cls):
   """Adds implementations of all Message methods to cls."""
   _AddListFieldsMethod(message_descriptor, cls)
@@ -967,9 +1020,9 @@
   _AddMergeFromStringMethod(message_descriptor, cls)
   _AddIsInitializedMethod(message_descriptor, cls)
   _AddMergeFromMethod(cls)
+  _AddWhichOneofMethod(message_descriptor, cls)
 
-
-def _AddPrivateHelperMethods(cls):
+def _AddPrivateHelperMethods(message_descriptor, cls):
   """Adds implementation of private helper methods to cls."""
 
   def Modified(self):
@@ -987,8 +1040,20 @@
       self._is_present_in_parent = True
       self._listener.Modified()
 
+  def _UpdateOneofState(self, field):
+    """Sets field as the active field in its containing oneof.
+
+    Will also delete currently active field in the oneof, if it is different
+    from the argument. Does not mark the message as modified.
+    """
+    other_field = self._oneofs.setdefault(field.containing_oneof, field)
+    if other_field is not field:
+      del self._fields[other_field]
+      self._oneofs[field.containing_oneof] = field
+
   cls._Modified = Modified
   cls.SetInParent = Modified
+  cls._UpdateOneofState = _UpdateOneofState
 
 
 class _Listener(object):
@@ -1037,6 +1102,27 @@
       pass
 
 
+class _OneofListener(_Listener):
+  """Special listener implementation for setting composite oneof fields."""
+
+  def __init__(self, parent_message, field):
+    """Args:
+      parent_message: The message whose _Modified() method we should call when
+        we receive Modified() messages.
+      field: The descriptor of the field being set in the parent message.
+    """
+    super(_OneofListener, self).__init__(parent_message)
+    self._field = field
+
+  def Modified(self):
+    """Also updates the state of the containing oneof in the parent message."""
+    try:
+      self._parent_message_weakref._UpdateOneofState(self._field)
+      super(_OneofListener, self).Modified()
+    except ReferenceError:
+      pass
+
+
 
 
 
diff --git a/google/net/proto2/python/public/descriptor_pool.py b/google/net/proto2/python/public/descriptor_pool.py
index 78e0962..2cd7028 100644
--- a/google/net/proto2/python/public/descriptor_pool.py
+++ b/google/net/proto2/python/public/descriptor_pool.py
@@ -346,6 +346,10 @@
     extensions = [
         self.MakeFieldDescriptor(extension, desc_name, index, is_extension=True)
         for index, extension in enumerate(desc_proto.extension)]
+    oneofs = [
+        descriptor.OneofDescriptor(desc.name, '.'.join((desc_name, desc.name)),
+                                   index, None, [])
+        for index, desc in enumerate(desc_proto.oneof_decl)]
     extension_ranges = [(r.start, r.end) for r in desc_proto.extension_range]
     if extension_ranges:
       is_extendable = True
@@ -357,6 +361,7 @@
         filename=file_name,
         containing_type=None,
         fields=fields,
+        oneofs=oneofs,
         nested_types=nested,
         enum_types=enums,
         extensions=extensions,
@@ -370,6 +375,12 @@
       nested.containing_type = desc
     for enum in desc.enum_types:
       enum.containing_type = desc
+    for field_index, field_desc in enumerate(desc_proto.field):
+      if field_desc.HasField('oneof_index'):
+        oneof_index = field_desc.oneof_index
+        oneofs[oneof_index].fields.append(fields[field_index])
+        fields[field_index].containing_oneof = oneofs[oneof_index]
+
     scope[_PrefixWithDot(desc_name)] = desc
     self._descriptors[desc_name] = desc
     return desc
diff --git a/lib/cacerts/urlfetch_cacerts.txt b/lib/cacerts/urlfetch_cacerts.txt
index 44eab70..172db1d 100644
--- a/lib/cacerts/urlfetch_cacerts.txt
+++ b/lib/cacerts/urlfetch_cacerts.txt
@@ -5618,33 +5618,6 @@
 OFm9oAww5XJiDz+dG0mEsnqRIawxKq0Lg0ZrHQ==
 -----END CERTIFICATE-----
 
-subject= /C=DK/O=TDC/OU=TDC SSL Server CA
-serial=3C1A2772
------BEGIN CERTIFICATE-----
-MIIECjCCAvKgAwIBAgIEPBoncjANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJE
-SzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQg
-Um9vdCBDQTAeFw0xMDAzMjUwODUxMjlaFw0xNDA4MjUwOTIxMjlaMDcxCzAJBgNV
-BAYTAkRLMQwwCgYDVQQKEwNUREMxGjAYBgNVBAsTEVREQyBTU0wgU2VydmVyIENB
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2ccg54uj7AKBZCwhFQbn
-0ovjkDjjFw2pi1eMHlWqlHLm6dUMtfuL77fIkNUAFSurGfMFL1xoaXVaq5z4c7gC
-G2pEkHdg3F4RHAOv6JvpbMDBRFLyNUgC6x9tk4YG9qGsGtDTljAT+ATKorFPszho
-CP5SAKOGgnMY/MGoxYhOFjjc5+PfpqZNO5nG/FbzzB+lwrgEuwi6odMA92/2Zgi1
-xRr0AxfnhkZPfKU9XHrLEsaPnk3DH2gXf1q++h4YMSwWX7Kqp+ffKA2wIIeKOZ33
-bXNyMXjgi6EYQyALjCpZCdZX4ok9DSUEx1WXOy2AOrKMcMTF1vvJOxAQOJthyq0E
-ewIDAQABo4IBEDCCAQwwgZMGA1UdHwSBizCBiDBaoFigVqRUMFIxCzAJBgNVBAYT
-AkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRlcm5l
-dCBSb290IENBMQ0wCwYDVQQDEwRDUkwxMCqgKKAmhiRodHRwOi8vY3JsLmNlcnRp
-ZmlrYXQuZGsvUm9vdF9DQS5jcmwwCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGxk
-Acf9hW2syNqeUAiFCLU8VqhQMB0GA1UdDgQWBBT9HsKzCDqV0dSlh87NQYRz7zN0
-DTAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY2LjADAgSQMA0GCSqG
-SIb3DQEBBQUAA4IBAQAU8G3+r8x8msjQ6xj6io0p7Jmr2mGXC/ORhZf4QdluWaWQ
-aNIjvuKOdXae6jlTc/BfmXv2PzjME3040loxdvs4SkiH9YO3wU4+YCxtoe2ngvt7
-XkEDKb9Z6SJqOL/TDNsLM6SWcIkGtiEWfevwVwBh0tZHN7s5pqUtNhvoyXeijKN3
-LDDKC07vwKllqS0zW9fkeZ0LxyxqVmcXAkH+/Yyd333bEQM2CtgxVZekkX1xFdjF
-bRCsImNsMAyHOu258nPNJ1rvbB69F3r2pNGxznven3INy9bbsvHihDwYGJVDshyu
-50FxBsiYOB6e1zFqDr0OPLoSjOHq1gwXwFI8Z5jZ
------END CERTIFICATE-----
-
 subject= /OU=Alpha CA/O=Alpha/CN=Alpha CA
 serial=0400000000011E44A5F365
 -----BEGIN CERTIFICATE-----
@@ -28773,46 +28746,6 @@
 T2TqAPQSMWGbI8Xv2tncNegK0TNiNe+DI6cSDsI0+aM=
 -----END CERTIFICATE-----
 
-subject= /C=US/O=Digital Signature Trust Co./OU=TrustID Server/CN=TrustID Server CA A5
-serial=B0AAA890F860B50424BCBBE8865CBDFF
------BEGIN CERTIFICATE-----
-MIIGiTCCBXGgAwIBAgIRALCqqJD4YLUEJLy76IZcvf8wDQYJKoZIhvcNAQEFBQAw
-PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
-Ew5EU1QgUm9vdCBDQSBYMzAeFw0wNzA4MjQxNzU0MTlaFw0xNDA4MjQxNDEzMzVa
-MGsxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVz
-dCBDby4xFzAVBgNVBAsTDlRydXN0SUQgU2VydmVyMR0wGwYDVQQDExRUcnVzdElE
-IFNlcnZlciBDQSBBNTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOae
-jyufM+mrKgTCpPm9ha5UBAORNLhAv3PFlmzA8n6lnEvBTJfeG5vUZYQrlZMMKmZl
-F1D3mYRFAhT/qFbBsTMlF9XsDNF40NB21ABTquuEB3Ji8mmC1Z2cZjwa4VeKxGIq
-kTdBypQgWekopNVvoOGLPbRXgYKW4UCc6pt7Q+We+eUuonp2XIRIOvmJQtXb/rNz
-4B1ahu3QB4HnystmQ9dW8BySSGDhZ/kzIcSU8GuHcL58SHsei07gjFzXRhMkkbJH
-MT8zS/hrjNsB8Z5kamI4QL7nLVNuCF1Sg9zgB1POdMPLEnm4uDx+BRLwVMGZMwza
-MNfEATnWTvLazzIDarMCAwEAAaOCA1IwggNOMA8GA1UdEwEB/wQFMAMBAf8wDgYD
-VR0PAQH/BAQDAgHGMEcGA1UdJQRAMD4GCCsGAQUFBwMBBggrBgEFBQcDAwYIKwYB
-BQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYKKwYBBAGCNwoDATCCATIGA1UdIASC
-ASkwggElMIIBIQYKYIZIAYb5LwAGAzCCAREwSgYIKwYBBQUHAgEWPmh0dHBzOi8v
-c2VjdXJlLmlkZW50cnVzdC5jb20vY2VydGlmaWNhdGVzL3BvbGljeS90cy9pbmRl
-eC5odG1sMIHCBggrBgEFBQcCAjCBtRqBslRoaXMgVHJ1c3RJRCBTZXJ2ZXIgQ2Vy
-dGlmaWNhdGUgaGFzIGJlZW4gaXNzdWVkIGluIGFjY29yZGFuY2Ugd2l0aCBJZGVu
-VHJ1c3QncyBUcnVzdElEIENlcnRpZmljYXRlIFBvbGljeSBmb3VuZCBhdCBodHRw
-czovL3NlY3VyZS5pZGVudHJ1c3QuY29tLyBjZXJ0aWZpY2F0ZXMvcG9saWN5L3Rz
-L2luZGV4Lmh0bWwwgbkGA1UdHwSBsTCBrjAuoCygKoYoaHR0cDovL2NybC5pZGVu
-dHJ1c3QuY29tL0RTVFJPT1RDQVgzLmNybDB8oHqgeIZ2bGRhcDovL2xkYXAuaWRl
-bnRydXN0LmNvbS9jbj1EU1QlMjBSb290JTIwQ0ElMjBYMyxvPURpZ2l0YWwlMjBT
-aWduYXR1cmUlMjBUcnVzdCUyMENvLj9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0
-O2JpbmFyeTCBrwYIKwYBBQUHAQEEgaIwgZ8wJQYIKwYBBQUHMAGGGWh0dHA6Ly9v
-Y3NwLmlkZW50cnVzdC5jb20wdgYIKwYBBQUHMAKGamxkYXA6Ly9sZGFwLmlkZW50
-cnVzdC5jb20vY249RFNUJTIwUm9vdCUyMENBJTIwWDMsbz1EaWdpdGFsJTIwU2ln
-bmF0dXJlJTIwVHJ1c3QlMjBDby4/Y0FDZXJ0aWZpY2F0ZTtiaW5hcnkwHwYDVR0j
-BBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAwHQYDVR0OBBYEFLeoy2iu3EVD0tyJ
-EamBZhn5+3XpMA0GCSqGSIb3DQEBBQUAA4IBAQAtreoVqLQx+G35L8byM/IvGqNa
-MzbWYzGIidH3+hT8B2e0duWfZCDazgu272ErWL/T4HL5psUEOIHfzNxEWHA24XhY
-zBFsYR64vaTRV7T+iYKv5Nxptidk26zOZ2/F+TKZvOfhPg5IqnH3FyXHEcRDWm1/
-QJsZ4mqgUFx38pc50i1ed6XUdvBObMnGJc1fGdfVqcNqbvHACNrw+WJE9PIeMKJQ
-HC/NkE87xFP/Q1OW7hPmqQvmIIbm6BLZ7U0kxqNL3HmegxkJ2yJQntsX+5BooJqj
-/uVpwzAEei7IjKsdtomxkHCDPFGEJYBldDLBH0ScSlngQZ6V5HNM473l8bWs
------END CERTIFICATE-----
-
 subject= /postalCode=46980/emailAddress=acedicom@edicomgroup.com/CN=ACEDICOM 01/serialNumber=B96490867/OU=PKI/O=EDICOM/L=Ronda de Auguste y Louis Lumiere 12 Paterna/ST=Valencia/C=ES
 serial=5D726090D98DF33B
 -----BEGIN CERTIFICATE-----
diff --git a/lib/distutils/distutils/sysconfig.py b/lib/distutils/distutils/sysconfig.py
index 4aa9334..18f6294 100644
--- a/lib/distutils/distutils/sysconfig.py
+++ b/lib/distutils/distutils/sysconfig.py
@@ -394,7 +394,12 @@
 def _init_posix():
     """Initialize the module as appropriate for POSIX systems."""
     # _sysconfigdata is generated at build time, see the sysconfig module
-    from _sysconfigdata import build_time_vars
+    # work with both the current GRTE v3 Python 2.7.3, and the upcoming GRTE v4
+    # Python 2.7.6
+    try:
+        from _sysconfigdata import build_time_vars
+    except ImportError:
+        from _sysconfig_data import build_time_vars
     global _config_vars
     _config_vars = {}
     _config_vars.update(build_time_vars)
diff --git a/php/sdk/google/appengine/datastore/entity_pb.php b/php/sdk/google/appengine/datastore/entity_pb.php
index 1fd6566..eb5997b 100644
--- a/php/sdk/google/appengine/datastore/entity_pb.php
+++ b/php/sdk/google/appengine/datastore/entity_pb.php
@@ -3261,6 +3261,23 @@
     public function hasWriteDivisionFamily() {
       return isset($this->write_division_family);
     }
+    public function getDisabledIndex() {
+      if (!isset($this->disabled_index)) {
+        return false;
+      }
+      return $this->disabled_index;
+    }
+    public function setDisabledIndex($val) {
+      $this->disabled_index = $val;
+      return $this;
+    }
+    public function clearDisabledIndex() {
+      unset($this->disabled_index);
+      return $this;
+    }
+    public function hasDisabledIndex() {
+      return isset($this->disabled_index);
+    }
     public function clear() {
       $this->clearAppId();
       $this->clearId();
@@ -3269,6 +3286,7 @@
       $this->clearOnlyUseIfRequired();
       $this->clearReadDivisionFamily();
       $this->clearWriteDivisionFamily();
+      $this->clearDisabledIndex();
     }
     public function byteSizePartial() {
       $res = 0;
@@ -3300,6 +3318,9 @@
         $res += 1;
         $res += $this->lengthString(strlen($this->write_division_family));
       }
+      if (isset($this->disabled_index)) {
+        $res += 2;
+      }
       return $res;
     }
     public function outputPartial($out) {
@@ -3333,6 +3354,10 @@
         $out->putVarInt32(66);
         $out->putPrefixedString($this->write_division_family);
       }
+      if (isset($this->disabled_index)) {
+        $out->putVarInt32(72);
+        $out->putBoolean($this->disabled_index);
+      }
     }
     public function tryMerge($d) {
       while($d->avail() > 0) {
@@ -3368,6 +3393,9 @@
             $this->setWriteDivisionFamily(substr($d->buffer(), $d->pos(), $length));
             $d->skip($length);
             break;
+          case 72:
+            $this->setDisabledIndex($d->getBoolean());
+            break;
           case 0:
             throw new \google\net\ProtocolBufferDecodeError();
             break;
@@ -3406,6 +3434,9 @@
       if ($x->hasWriteDivisionFamily()) {
         $this->setWriteDivisionFamily($x->getWriteDivisionFamily());
       }
+      if ($x->hasDisabledIndex()) {
+        $this->setDisabledIndex($x->getDisabledIndex());
+      }
     }
     public function equals($x) {
       if ($x === $this) { return true; }
@@ -3425,6 +3456,8 @@
       }
       if (isset($this->write_division_family) !== isset($x->write_division_family)) return false;
       if (isset($this->write_division_family) && $this->write_division_family !== $x->write_division_family) return false;
+      if (isset($this->disabled_index) !== isset($x->disabled_index)) return false;
+      if (isset($this->disabled_index) && $this->disabled_index !== $x->disabled_index) return false;
       return true;
     }
     public function shortDebugString($prefix = "") {
@@ -3450,6 +3483,9 @@
       if (isset($this->write_division_family)) {
         $res .= $prefix . "write_division_family: " . $this->debugFormatString($this->write_division_family) . "\n";
       }
+      if (isset($this->disabled_index)) {
+        $res .= $prefix . "disabled_index: " . $this->debugFormatBool($this->disabled_index) . "\n";
+      }
       return $res;
     }
   }
@@ -4169,9 +4205,27 @@
     public function hasBefore() {
       return isset($this->before);
     }
+    public function getBeforeAscending() {
+      if (!isset($this->before_ascending)) {
+        return false;
+      }
+      return $this->before_ascending;
+    }
+    public function setBeforeAscending($val) {
+      $this->before_ascending = $val;
+      return $this;
+    }
+    public function clearBeforeAscending() {
+      unset($this->before_ascending);
+      return $this;
+    }
+    public function hasBeforeAscending() {
+      return isset($this->before_ascending);
+    }
     public function clear() {
       $this->clearKey();
       $this->clearBefore();
+      $this->clearBeforeAscending();
     }
     public function byteSizePartial() {
       $res = 0;
@@ -4182,6 +4236,9 @@
       if (isset($this->before)) {
         $res += 2;
       }
+      if (isset($this->before_ascending)) {
+        $res += 2;
+      }
       return $res;
     }
     public function outputPartial($out) {
@@ -4193,6 +4250,10 @@
         $out->putVarInt32(16);
         $out->putBoolean($this->before);
       }
+      if (isset($this->before_ascending)) {
+        $out->putVarInt32(24);
+        $out->putBoolean($this->before_ascending);
+      }
     }
     public function tryMerge($d) {
       while($d->avail() > 0) {
@@ -4206,6 +4267,9 @@
           case 16:
             $this->setBefore($d->getBoolean());
             break;
+          case 24:
+            $this->setBeforeAscending($d->getBoolean());
+            break;
           case 0:
             throw new \google\net\ProtocolBufferDecodeError();
             break;
@@ -4225,6 +4289,9 @@
       if ($x->hasBefore()) {
         $this->setBefore($x->getBefore());
       }
+      if ($x->hasBeforeAscending()) {
+        $this->setBeforeAscending($x->getBeforeAscending());
+      }
     }
     public function equals($x) {
       if ($x === $this) { return true; }
@@ -4232,6 +4299,8 @@
       if (isset($this->key) && $this->key !== $x->key) return false;
       if (isset($this->before) !== isset($x->before)) return false;
       if (isset($this->before) && $this->before !== $x->before) return false;
+      if (isset($this->before_ascending) !== isset($x->before_ascending)) return false;
+      if (isset($this->before_ascending) && $this->before_ascending !== $x->before_ascending) return false;
       return true;
     }
     public function shortDebugString($prefix = "") {
@@ -4242,6 +4311,9 @@
       if (isset($this->before)) {
         $res .= $prefix . "before: " . $this->debugFormatBool($this->before) . "\n";
       }
+      if (isset($this->before_ascending)) {
+        $res .= $prefix . "before_ascending: " . $this->debugFormatBool($this->before_ascending) . "\n";
+      }
       return $res;
     }
   }