Remove apiclient package

BUG=

Review URL: https://codereview.chromium.org/1091163002

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@294877 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/third_party/google_api_python_client/.gitignore b/third_party/google_api_python_client/.gitignore
deleted file mode 100644
index ddb969d..0000000
--- a/third_party/google_api_python_client/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-# Build artifacts
-*.py[cod]
-google_api_python_client.egg-info/
-build/
-dist/
-
-# Test files
-.tox/
diff --git a/third_party/google_api_python_client/.gitmodules b/third_party/google_api_python_client/.gitmodules
deleted file mode 100644
index e69de29..0000000
--- a/third_party/google_api_python_client/.gitmodules
+++ /dev/null
diff --git a/third_party/google_api_python_client/.hgignore b/third_party/google_api_python_client/.hgignore
deleted file mode 100644
index dc9cf78..0000000
--- a/third_party/google_api_python_client/.hgignore
+++ /dev/null
@@ -1,24 +0,0 @@
-syntax: glob
-
-*.pyc
-*.pyc-2.4
-*.dat
-.*.swp
-*/.git/*
-*/.cache/*
-.gitignore
-.tox
-samples/buzz/*.dat
-samples/moderator/*.dat
-htmlcov/*
-.coverage
-database.sqlite3
-build/*
-googlecode_upload.py
-google_api_python_client.egg-info/*
-dist/*
-snapshot/*
-MANIFEST
-.project
-.pydevproject
-.settings/*
diff --git a/third_party/google_api_python_client/CHANGELOG b/third_party/google_api_python_client/CHANGELOG
deleted file mode 100644
index af6d669..0000000
--- a/third_party/google_api_python_client/CHANGELOG
+++ /dev/null
@@ -1,167 +0,0 @@
-v1.3.1
-  Version 1.3.1
-
-  Quick release for a fix around aliasing in v1.3.
-	
-v1.3
-  Version 1.3
-
-  Add support for the Google Application Default Credentials.
-  Require python 2.6 as a minimum version.
-  Update several API samples.
-  Finish splitting out oauth2client repo and update tests.
-  Various doc cleanup and bugfixes.
-
-  Two important notes:
-    * We've added `googleapiclient` as the primary suggested import
-      name, and kept `apiclient` as an alias, in order to have a more
-      appropriate import name. At some point, we will remove `apiclient`
-      as an alias.
-    * Due to an issue around in-place upgrades for Python packages,
-      it's not possible to do an upgrade from version 1.2 to 1.3. Instead,
-      setup.py attempts to detect this and prevents it. Simply remove
-      the previous version and reinstall to fix this.
-
-v1.2
-  Version 1.2
-
-  The use of the gflags library is now deprecated, and is no longer a
-    dependency. If you are still using the oauth2client.tools.run() function
-    then include gflags as a dependency of your application or switch to
-    oauth2client.tools.run_flow.
-  Samples have been updated to use the new apiclient.sample_tools, and no
-    longer use gflags.
-  Added support for the experimental Object Change Notification, as found in
-    the Cloud Storage API.
-  The oauth2client App Engine decorators are now threadsafe.
-
-  - Use the following redirects feature of httplib2 where it returns the
-    ultimate URL after a series of redirects to avoid multiple hops for every
-    resumable media upload request.
-  - Updated AdSense Management API samples to V1.3
-  - Add option to automatically retry requests.
-  - Ability to list registered keys in multistore_file.
-  - User-agent must contain (gzip).
-  - The 'method' parameter for httplib2 is not positional. This would cause
-    spurious warnings in the logging.
-  - Making OAuth2Decorator more extensible. Fixes Issue 256.
-  - Update AdExchange Buyer API examples to version v1.2.
-
-
-v1.1
-  Version 1.1
-
-  Add PEM support to SignedJWTAssertionCredentials (used to only support
-  PKCS12 formatted keys). Note that if you use PEM formatted keys you can use
-  PyCrypto 2.6 or later instead of OpenSSL.
-
-  Allow deserialized discovery docs to be passed to build_from_document().
-
-  - Make ResumableUploadError derive from HttpError.
-  - Many changes to move all the closures in apiclient.discovery into real
-  -  classes and objects.
-  - Make from_json behavior inheritable.
-  - Expose the full token response in OAuth2Client and OAuth2Decorator.
-  - Handle reasons that are None.
-  - Added support for NDB based storing of oauth2client objects.
-  - Update grant_type for AssertionCredentials.
-  - Adding a .revoke() to Credentials. Closes issue 98.
-  - Modify oauth2client.multistore_file to store and retrieve credentials
-    using an arbitrary key.
-  - Don't accept 403 challenges by default for auth challenges.
-  - Set httplib2.RETRIES to 1.
-  - Consolidate handling of scopes.
-  - Upgrade to httplib2 version 0.8.
-  - Allow setting the response_type in OAuth2WebServerFlow.
-  - Ensure that dataWrapper feature is checked before using the 'data' value.
-  - HMAC verification does not use a constant time algorithm.
-
-v1.0
- Version 1.0
-
-  - Changes to the code for running tests and building releases.
-
-v1.0c3
- Version 1.0 Release Candidate 3
-
-  - In samples and oauth2 decorator, escape untrusted content before displaying it.
-  - Do not allow credentials files to be symlinks.
-  - Add XSRF protection to oauth2decorator callback 'state'.
-  - Handle uploading chunked media by stream.
-  - Handle passing streams directly to httplib2.
-  - Add support for Google Compute Engine service accounts.
-  - Flows no longer need to be saved between uses.
-  - Change GET to POST if URI is too long. Fixes issue #96.
-  - Add a keyring based Storage.
-  - More robust picking up JSON error responses.
-  - Make batch errors align with normal errors.
-  - Add a Google Compute sample.
-  - Token refresh to work with 'old' GData API
-  - Loading of client_secrets JSON file backed by a cache.
-  - Switch to new discovery path parameters.
-  - Add support for additionalProperties when printing schema'd objects.
-  - Fix media upload parameter names. Reviewed in http://codereview.appspot.com/6374062/
-  - oauth2client support for URL-encoded format of exchange token response (e.g.  Facebook)
-  - Build cleaner and easier to read docs for dynamic surfaces.
-
-v1.0c2
- Version 1.0 Release Candidate 2
-
-  - Parameter values of None should be treated as missing. Fixes issue #144.
-  - Distribute the samples separately from the library source. Fixes issue #155.
-  - Move all remaining samples over to client_secrets.json. Fixes issue #156.
-  - Make locked_file.py understand win32file primitives for better awesomeness.
-
-v1.0c1
- Version 1.0 Release Candidate 1
-
- - Documentation for the library has switched to epydoc:
-     http://google-api-python-client.googlecode.com/hg/docs/epy/index.html
- - Many improvements for media support:
-   * Added media download support, including resumable downloads.
-   * Better handling of streams that report their size as 0.
-   * Update Media Upload to include io.Base and also fix some bugs.
- - OAuth bug fixes and improvements.
-   * Remove OAuth 1.0 support.
-   * Added credentials_from_code and credentials_from_clientsecrets_and_code.
-   * Make oauth2client support Windows-friendly locking.
-   * Fix bug in StorageByKeyName.
-   * Fix None handling in Django fields. Reviewed in http://codereview.appspot.com/6298084/. Fixes issue #128.
- - Add epydoc generated docs. Reviewed in http://codereview.appspot.com/6305043/
- - Move to PEP386 compliant version numbers.
- - New and updated samples
-   * Ad Exchange Buyer API v1 code samples.
-   * Automatically generate Samples wiki page from README files.
-   * Update Google Prediction samples.
-   * Add a Tasks sample that demonstrates Service accounts.
-   * new analytics api samples. Reviewed here: http://codereview.appspot.com/5494058/
- - Convert all inline samples to the Farm API for consistency.
-
-v1.0beta8
- - Updated meda upload support.
- - Many fixes for batch requests.
- - Better handling for requests that don't require a body.
- - Fix issues with Google App Engine Python 2.7 runtime.
- - Better support for proxies.
- - All Storages now have a .delete() method.
- - Important changes which might break your code:
-    * apiclient.anyjson has moved to oauth2client.anyjson.
-    * Some calls, for example, taskqueue().lease() used to require a parameter
-      named body. In this new release only methods that really need to send a body
-      require a body parameter, and so you may get errors about an unknown
-      'body' parameter in your call. The solution is to remove the unneeded
-      body={} parameter.
-
-v1.0beta7
- - Support for batch requests.  http://code.google.com/p/google-api-python-client/wiki/Batch
- - Support for media upload.  http://code.google.com/p/google-api-python-client/wiki/MediaUpload
- - Better handling for APIs that return something other than JSON.
- - Major cleanup and consolidation of the samples.
- - Bug fixes and other enhancements:
-   72  Defect  Appengine OAuth2Decorator: Convert redirect address to string
-   22  Defect  Better error handling for unknown service name or version
-   48  Defect  StorageByKeyName().get() has side effects
-   50  Defect  Need sample client code for Admin Audit API
-   28  Defect  better comments for app engine sample   Nov 9
-   63  Enhancement Let OAuth2Decorator take a list of scope
-
diff --git a/third_party/google_api_python_client/LICENSE b/third_party/google_api_python_client/LICENSE
deleted file mode 100644
index 2987b3b..0000000
--- a/third_party/google_api_python_client/LICENSE
+++ /dev/null
@@ -1,22 +0,0 @@
- Copyright 2014 Google Inc. All Rights Reserved.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
-Dependent Modules
-=================
-
-This code has the following dependencies
-above and beyond the Python standard library:
-
-uritemplates - Apache License 2.0
-httplib2 - MIT License
diff --git a/third_party/google_api_python_client/MANIFEST.in b/third_party/google_api_python_client/MANIFEST.in
deleted file mode 100644
index cc692b3..0000000
--- a/third_party/google_api_python_client/MANIFEST.in
+++ /dev/null
@@ -1,6 +0,0 @@
-recursive-include apiclient *.json *.py
-include CHANGELOG
-include LICENSE
-include README
-include FAQ
-include setpath.sh
diff --git a/third_party/google_api_python_client/Makefile b/third_party/google_api_python_client/Makefile
deleted file mode 100644
index 6366e77..0000000
--- a/third_party/google_api_python_client/Makefile
+++ /dev/null
@@ -1,47 +0,0 @@
-pep8:
-	find googleapiclient samples -name "*.py" | xargs pep8 --ignore=E111,E202
-
-APP_ENGINE_PATH=../google_appengine
-
-test:
-	tox
-
-.PHONY: coverage
-coverage:
-	coverage erase
-	find tests -name "test_*.py" | xargs --max-args=1 coverage run -a runtests.py
-	coverage report
-	coverage html
-
-.PHONY: docs
-docs:
-	cd docs; ./build
-	mkdir -p docs/dyn
-	python describe.py
-
-.PHONY: wiki
-wiki:
-	python samples-index.py > ../google-api-python-client.wiki/SampleApps.wiki
-
-.PHONY: prerelease
-prerelease:
-	-rm -rf dist/
-	-sudo rm -rf dist/
-	-rm -rf snapshot/
-	-sudo rm -rf snapshot/
-	# ./tools/gae-zip-creator.sh
-	python expandsymlinks.py
-	cd snapshot; python setup.py clean
-	cd snapshot; python setup.py sdist --formats=gztar,zip
-	cd snapshot; tar czf google-api-python-client-samples-$(shell python setup.py --version).tar.gz samples
-	cd snapshot; zip -r google-api-python-client-samples-$(shell python setup.py --version).zip samples
-
-
-.PHONY: release
-release: prerelease
-	@echo "This target will upload a new release to PyPi and code.google.com hosting."
-	@echo "Are you sure you want to proceed? (yes/no)"
-	@read yn; if [ yes -ne $(yn) ]; then exit 1; fi
-	@echo "Here we go..."
-	cd snapshot; python setup.py sdist --formats=gztar,zip register upload
-	
\ No newline at end of file
diff --git a/third_party/google_api_python_client/README.chromium b/third_party/google_api_python_client/README.chromium
deleted file mode 100644
index eb7a00d..0000000
--- a/third_party/google_api_python_client/README.chromium
+++ /dev/null
@@ -1,6 +0,0 @@
-URL: https://github.com/google/google-api-python-client
-Version: v1.3.1
-Revision: 49d45a6c3318b75e551c3022020f46c78655f365
-License: Apache License, Version 2.0 (the "License")
-
-No local changes
diff --git a/third_party/google_api_python_client/README.md b/third_party/google_api_python_client/README.md
deleted file mode 100644
index c22221c..0000000
--- a/third_party/google_api_python_client/README.md
+++ /dev/null
@@ -1,32 +0,0 @@
-# About
-This is the Python client library for Google's discovery based APIs. To get started, please see the [full documentation for this library](http://google.github.io/google-api-python-client). Additionally, [dynamically generated documentation](http://api-python-client-doc.appspot.com/) is available for all of the APIs supported by this library.
-
-
-# Installation
-To install, simply use `pip` or `easy_install`:
-
-```bash
-$ pip install --upgrade google-api-python-client
-```
-or
-```bash
-$ easy_install --upgrade google-api-python-client
-```
-
-See the [Developers Guide](https://developers.google.com/api-client-library/python/start/get_started) for more detailed instructions and additional documentation.
-
-# Python Version
-Python 2.6 or 2.7 is required. Python 3.x is not yet supported.
-
-# Third Party Libraries and Dependencies
-The following libraries will be installed when you install the client library:
-* [httplib2](https://github.com/jcgregorio/httplib2)
-* [uri-templates](https://github.com/uri-templates/uritemplate-py)
-
-For development you will also need the following libraries:
-* [WebTest](http://pythonpaste.org/webtest/)
-* [pycrypto](https://pypi.python.org/pypi/pycrypto)
-* [pyopenssl](https://pypi.python.org/pypi/pyOpenSSL)
-
-# Contributing
-Please see the [contributing page](http://google.github.io/google-api-python-client/contributing.html) for more information. In particular, we love pull requests - but please make sure to sign the contributor license agreement.
diff --git a/third_party/google_api_python_client/__init__.py b/third_party/google_api_python_client/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/third_party/google_api_python_client/__init__.py
+++ /dev/null
diff --git a/third_party/google_api_python_client/apiclient/__init__.py b/third_party/google_api_python_client/apiclient/__init__.py
deleted file mode 100644
index 5efb142..0000000
--- a/third_party/google_api_python_client/apiclient/__init__.py
+++ /dev/null
@@ -1,40 +0,0 @@
-"""Retain apiclient as an alias for googleapiclient."""
-
-import googleapiclient
-
-try:
-  import oauth2client
-except ImportError:
-  raise RuntimeError(
-      'Previous version of google-api-python-client detected; due to a '
-      'packaging issue, we cannot perform an in-place upgrade. To repair, '
-      'remove and reinstall this package, along with oauth2client and '
-      'uritemplate. One can do this with pip via\n'
-      '  pip install -I google-api-python-client'
-  )
-
-from googleapiclient import channel
-from googleapiclient import discovery
-from googleapiclient import errors
-from googleapiclient import http
-from googleapiclient import mimeparse
-from googleapiclient import model
-from googleapiclient import sample_tools
-from googleapiclient import schema
-
-__version__ = googleapiclient.__version__
-
-_SUBMODULES = {
-    'channel': channel,
-    'discovery': discovery,
-    'errors': errors,
-    'http': http,
-    'mimeparse': mimeparse,
-    'model': model,
-    'sample_tools': sample_tools,
-    'schema': schema,
-}
-
-import sys
-for module_name, module in _SUBMODULES.iteritems():
-  sys.modules['apiclient.%s' % module_name] = module
diff --git a/third_party/google_api_python_client/describe.py b/third_party/google_api_python_client/describe.py
deleted file mode 100755
index 5dcac90..0000000
--- a/third_party/google_api_python_client/describe.py
+++ /dev/null
@@ -1,390 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2014 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Create documentation for generate API surfaces.
-
-Command-line tool that creates documentation for all APIs listed in discovery.
-The documentation is generated from a combination of the discovery document and
-the generated API surface itself.
-"""
-
-__author__ = 'jcgregorio@google.com (Joe Gregorio)'
-
-import argparse
-import json
-import os
-import re
-import string
-import sys
-
-from googleapiclient.discovery import DISCOVERY_URI
-from googleapiclient.discovery import build
-from googleapiclient.discovery import build_from_document
-import httplib2
-import uritemplate
-
-CSS = """<style>
-
-body, h1, h2, h3, div, span, p, pre, a {
-  margin: 0;
-  padding: 0;
-  border: 0;
-  font-weight: inherit;
-  font-style: inherit;
-  font-size: 100%;
-  font-family: inherit;
-  vertical-align: baseline;
-}
-
-body {
-  font-size: 13px;
-  padding: 1em;
-}
-
-h1 {
-  font-size: 26px;
-  margin-bottom: 1em;
-}
-
-h2 {
-  font-size: 24px;
-  margin-bottom: 1em;
-}
-
-h3 {
-  font-size: 20px;
-  margin-bottom: 1em;
-  margin-top: 1em;
-}
-
-pre, code {
-  line-height: 1.5;
-  font-family: Monaco, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Lucida Console', monospace;
-}
-
-pre {
-  margin-top: 0.5em;
-}
-
-h1, h2, h3, p {
-  font-family: Arial, sans serif;
-}
-
-h1, h2, h3 {
-  border-bottom: solid #CCC 1px;
-}
-
-.toc_element {
-  margin-top: 0.5em;
-}
-
-.firstline {
-  margin-left: 2 em;
-}
-
-.method  {
-  margin-top: 1em;
-  border: solid 1px #CCC;
-  padding: 1em;
-  background: #EEE;
-}
-
-.details {
-  font-weight: bold;
-  font-size: 14px;
-}
-
-</style>
-"""
-
-METHOD_TEMPLATE = """<div class="method">
-    <code class="details" id="$name">$name($params)</code>
-  <pre>$doc</pre>
-</div>
-"""
-
-COLLECTION_LINK = """<p class="toc_element">
-  <code><a href="$href">$name()</a></code>
-</p>
-<p class="firstline">Returns the $name Resource.</p>
-"""
-
-METHOD_LINK = """<p class="toc_element">
-  <code><a href="#$name">$name($params)</a></code></p>
-<p class="firstline">$firstline</p>"""
-
-BASE = 'docs/dyn'
-
-DIRECTORY_URI = 'https://www.googleapis.com/discovery/v1/apis?preferred=true'
-
-parser = argparse.ArgumentParser(description=__doc__)
-
-parser.add_argument('--discovery_uri_template', default=DISCOVERY_URI,
-                    help='URI Template for discovery.')
-
-parser.add_argument('--discovery_uri', default='',
-                    help=('URI of discovery document. If supplied then only '
-                          'this API will be documented.'))
-
-parser.add_argument('--directory_uri', default=DIRECTORY_URI,
-                    help=('URI of directory document. Unused if --discovery_uri'
-                          ' is supplied.'))
-
-parser.add_argument('--dest', default=BASE,
-                    help='Directory name to write documents into.')
-
-
-
-def safe_version(version):
-  """Create a safe version of the verion string.
-
-  Needed so that we can distinguish between versions
-  and sub-collections in URIs. I.e. we don't want
-  adsense_v1.1 to refer to the '1' collection in the v1
-  version of the adsense api.
-
-  Args:
-    version: string, The version string.
-  Returns:
-    The string with '.' replaced with '_'.
-  """
-
-  return version.replace('.', '_')
-
-
-def unsafe_version(version):
-  """Undoes what safe_version() does.
-
-  See safe_version() for the details.
-
-
-  Args:
-    version: string, The safe version string.
-  Returns:
-    The string with '_' replaced with '.'.
-  """
-
-  return version.replace('_', '.')
-
-
-def method_params(doc):
-  """Document the parameters of a method.
-
-  Args:
-    doc: string, The method's docstring.
-
-  Returns:
-    The method signature as a string.
-  """
-  doclines = doc.splitlines()
-  if 'Args:' in doclines:
-    begin = doclines.index('Args:')
-    if 'Returns:' in doclines[begin+1:]:
-      end = doclines.index('Returns:', begin)
-      args = doclines[begin+1: end]
-    else:
-      args = doclines[begin+1:]
-
-    parameters = []
-    for line in args:
-      m = re.search('^\s+([a-zA-Z0-9_]+): (.*)', line)
-      if m is None:
-        continue
-      pname = m.group(1)
-      desc = m.group(2)
-      if '(required)' not in desc:
-        pname = pname + '=None'
-      parameters.append(pname)
-    parameters = ', '.join(parameters)
-  else:
-    parameters = ''
-  return parameters
-
-
-def method(name, doc):
-  """Documents an individual method.
-
-  Args:
-    name: string, Name of the method.
-    doc: string, The methods docstring.
-  """
-
-  params = method_params(doc)
-  return string.Template(METHOD_TEMPLATE).substitute(
-      name=name, params=params, doc=doc)
-
-
-def breadcrumbs(path, root_discovery):
-  """Create the breadcrumb trail to this page of documentation.
-
-  Args:
-    path: string, Dot separated name of the resource.
-    root_discovery: Deserialized discovery document.
-
-  Returns:
-    HTML with links to each of the parent resources of this resource.
-  """
-  parts = path.split('.')
-
-  crumbs = []
-  accumulated = []
-
-  for i, p in enumerate(parts):
-    prefix = '.'.join(accumulated)
-    # The first time through prefix will be [], so we avoid adding in a
-    # superfluous '.' to prefix.
-    if prefix:
-      prefix += '.'
-    display = p
-    if i == 0:
-      display = root_discovery.get('title', display)
-    crumbs.append('<a href="%s.html">%s</a>' % (prefix + p, display))
-    accumulated.append(p)
-
-  return ' . '.join(crumbs)
-
-
-def document_collection(resource, path, root_discovery, discovery, css=CSS):
-  """Document a single collection in an API.
-
-  Args:
-    resource: Collection or service being documented.
-    path: string, Dot separated name of the resource.
-    root_discovery: Deserialized discovery document.
-    discovery: Deserialized discovery document, but just the portion that
-      describes the resource.
-    css: string, The CSS to include in the generated file.
-  """
-  collections = []
-  methods = []
-  resource_name = path.split('.')[-2]
-  html = [
-      '<html><body>',
-      css,
-      '<h1>%s</h1>' % breadcrumbs(path[:-1], root_discovery),
-      '<h2>Instance Methods</h2>'
-      ]
-
-  # Which methods are for collections.
-  for name in dir(resource):
-    if not name.startswith('_') and callable(getattr(resource, name)):
-      if hasattr(getattr(resource, name), '__is_resource__'):
-        collections.append(name)
-      else:
-        methods.append(name)
-
-
-  # TOC
-  if collections:
-    for name in collections:
-      if not name.startswith('_') and callable(getattr(resource, name)):
-        href = path + name + '.html'
-        html.append(string.Template(COLLECTION_LINK).substitute(
-            href=href, name=name))
-
-  if methods:
-    for name in methods:
-      if not name.startswith('_') and callable(getattr(resource, name)):
-        doc = getattr(resource, name).__doc__
-        params = method_params(doc)
-        firstline = doc.splitlines()[0]
-        html.append(string.Template(METHOD_LINK).substitute(
-            name=name, params=params, firstline=firstline))
-
-  if methods:
-    html.append('<h3>Method Details</h3>')
-    for name in methods:
-      dname = name.rsplit('_')[0]
-      html.append(method(name, getattr(resource, name).__doc__))
-
-  html.append('</body></html>')
-
-  return '\n'.join(html)
-
-
-def document_collection_recursive(resource, path, root_discovery, discovery):
-
-  html = document_collection(resource, path, root_discovery, discovery)
-
-  f = open(os.path.join(FLAGS.dest, path + 'html'), 'w')
-  f.write(html.encode('utf-8'))
-  f.close()
-
-  for name in dir(resource):
-    if (not name.startswith('_')
-        and callable(getattr(resource, name))
-        and hasattr(getattr(resource, name), '__is_resource__')):
-      dname = name.rsplit('_')[0]
-      collection = getattr(resource, name)()
-      document_collection_recursive(collection, path + name + '.', root_discovery,
-               discovery['resources'].get(dname, {}))
-
-def document_api(name, version):
-  """Document the given API.
-
-  Args:
-    name: string, Name of the API.
-    version: string, Version of the API.
-  """
-  service = build(name, version)
-  response, content = http.request(
-      uritemplate.expand(
-          FLAGS.discovery_uri_template, {
-              'api': name,
-              'apiVersion': version})
-          )
-  discovery = json.loads(content)
-
-  version = safe_version(version)
-
-  document_collection_recursive(
-      service, '%s_%s.' % (name, version), discovery, discovery)
-
-
-def document_api_from_discovery_document(uri):
-  """Document the given API.
-
-  Args:
-    uri: string, URI of discovery document.
-  """
-  http = httplib2.Http()
-  response, content = http.request(FLAGS.discovery_uri)
-  discovery = json.loads(content)
-
-  service = build_from_document(discovery)
-
-  name = discovery['version']
-  version = safe_version(discovery['version'])
-
-  document_collection_recursive(
-      service, '%s_%s.' % (name, version), discovery, discovery)
-
-
-if __name__ == '__main__':
-  FLAGS = parser.parse_args(sys.argv[1:])
-  if FLAGS.discovery_uri:
-    document_api_from_discovery_document(FLAGS.discovery_uri)
-  else:
-    http = httplib2.Http()
-    resp, content = http.request(
-        FLAGS.directory_uri,
-        headers={'X-User-IP': '0.0.0.0'})
-    if resp.status == 200:
-      directory = json.loads(content)['items']
-      for api in directory:
-        document_api(api['name'], api['version'])
-    else:
-      sys.exit("Failed to load the discovery document.")
diff --git a/third_party/google_api_python_client/expandsymlinks.py b/third_party/google_api_python_client/expandsymlinks.py
deleted file mode 100644
index 8213622..0000000
--- a/third_party/google_api_python_client/expandsymlinks.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/python2.4
-# -*- coding: utf-8 -*-
-#
-# Copyright 2014 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Copy files from source to dest expanding symlinks along the way.
-"""
-
-from shutil import copytree
-
-import argparse
-import sys
-
-
-# Ignore these files and directories when copying over files into the snapshot.
-IGNORE = set(['.hg', 'httplib2', 'oauth2', 'simplejson', 'static'])
-
-# In addition to the above files also ignore these files and directories when
-# copying over samples into the snapshot.
-IGNORE_IN_SAMPLES = set(['googleapiclient', 'oauth2client', 'uritemplate'])
-
-parser = argparse.ArgumentParser(description=__doc__)
-
-parser.add_argument('--source', default='.',
-                    help='Directory name to copy from.')
-
-parser.add_argument('--dest', default='snapshot',
-                    help='Directory name to copy to.')
-
-
-def _ignore(path, names):
-  retval = set()
-  if path != '.':
-    retval = retval.union(IGNORE_IN_SAMPLES.intersection(names))
-  retval = retval.union(IGNORE.intersection(names))
-  return retval
-
-
-def main():
-  copytree(FLAGS.source, FLAGS.dest, symlinks=True,
-            ignore=_ignore)
-
-
-if __name__ == '__main__':
-  FLAGS = parser.parse_args(sys.argv[1:])
-  main()
diff --git a/third_party/google_api_python_client/googleapiclient/__init__.py b/third_party/google_api_python_client/googleapiclient/__init__.py
deleted file mode 100644
index 1e1a6cf..0000000
--- a/third_party/google_api_python_client/googleapiclient/__init__.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2014 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-__version__ = "1.3.1"
diff --git a/third_party/google_api_python_client/googleapiclient/channel.py b/third_party/google_api_python_client/googleapiclient/channel.py
deleted file mode 100644
index 68a3b89..0000000
--- a/third_party/google_api_python_client/googleapiclient/channel.py
+++ /dev/null
@@ -1,285 +0,0 @@
-"""Channel notifications support.
-
-Classes and functions to support channel subscriptions and notifications
-on those channels.
-
-Notes:
-  - This code is based on experimental APIs and is subject to change.
-  - Notification does not do deduplication of notification ids, that's up to
-    the receiver.
-  - Storing the Channel between calls is up to the caller.
-
-
-Example setting up a channel:
-
-  # Create a new channel that gets notifications via webhook.
-  channel = new_webhook_channel("https://example.com/my_web_hook")
-
-  # Store the channel, keyed by 'channel.id'. Store it before calling the
-  # watch method because notifications may start arriving before the watch
-  # method returns.
-  ...
-
-  resp = service.objects().watchAll(
-    bucket="some_bucket_id", body=channel.body()).execute()
-  channel.update(resp)
-
-  # Store the channel, keyed by 'channel.id'. Store it after being updated
-  # since the resource_id value will now be correct, and that's needed to
-  # stop a subscription.
-  ...
-
-
-An example Webhook implementation using webapp2. Note that webapp2 puts
-headers in a case insensitive dictionary, as headers aren't guaranteed to
-always be upper case.
-
-  id = self.request.headers[X_GOOG_CHANNEL_ID]
-
-  # Retrieve the channel by id.
-  channel = ...
-
-  # Parse notification from the headers, including validating the id.
-  n = notification_from_headers(channel, self.request.headers)
-
-  # Do app specific stuff with the notification here.
-  if n.resource_state == 'sync':
-    # Code to handle sync state.
-  elif n.resource_state == 'exists':
-    # Code to handle the exists state.
-  elif n.resource_state == 'not_exists':
-    # Code to handle the not exists state.
-
-
-Example of unsubscribing.
-
-  service.channels().stop(channel.body())
-"""
-
-import datetime
-import uuid
-
-from googleapiclient import errors
-from ...oauth2client import util
-
-
-# The unix time epoch starts at midnight 1970.
-EPOCH = datetime.datetime.utcfromtimestamp(0)
-
-# Map the names of the parameters in the JSON channel description to
-# the parameter names we use in the Channel class.
-CHANNEL_PARAMS = {
-    'address': 'address',
-    'id': 'id',
-    'expiration': 'expiration',
-    'params': 'params',
-    'resourceId': 'resource_id',
-    'resourceUri': 'resource_uri',
-    'type': 'type',
-    'token': 'token',
-    }
-
-X_GOOG_CHANNEL_ID     = 'X-GOOG-CHANNEL-ID'
-X_GOOG_MESSAGE_NUMBER = 'X-GOOG-MESSAGE-NUMBER'
-X_GOOG_RESOURCE_STATE = 'X-GOOG-RESOURCE-STATE'
-X_GOOG_RESOURCE_URI   = 'X-GOOG-RESOURCE-URI'
-X_GOOG_RESOURCE_ID    = 'X-GOOG-RESOURCE-ID'
-
-
-def _upper_header_keys(headers):
-  new_headers = {}
-  for k, v in headers.iteritems():
-    new_headers[k.upper()] = v
-  return new_headers
-
-
-class Notification(object):
-  """A Notification from a Channel.
-
-  Notifications are not usually constructed directly, but are returned
-  from functions like notification_from_headers().
-
-  Attributes:
-    message_number: int, The unique id number of this notification.
-    state: str, The state of the resource being monitored.
-    uri: str, The address of the resource being monitored.
-    resource_id: str, The unique identifier of the version of the resource at
-      this event.
-  """
-  @util.positional(5)
-  def __init__(self, message_number, state, resource_uri, resource_id):
-    """Notification constructor.
-
-    Args:
-      message_number: int, The unique id number of this notification.
-      state: str, The state of the resource being monitored. Can be one
-        of "exists", "not_exists", or "sync".
-      resource_uri: str, The address of the resource being monitored.
-      resource_id: str, The identifier of the watched resource.
-    """
-    self.message_number = message_number
-    self.state = state
-    self.resource_uri = resource_uri
-    self.resource_id = resource_id
-
-
-class Channel(object):
-  """A Channel for notifications.
-
-  Usually not constructed directly, instead it is returned from helper
-  functions like new_webhook_channel().
-
-  Attributes:
-    type: str, The type of delivery mechanism used by this channel. For
-      example, 'web_hook'.
-    id: str, A UUID for the channel.
-    token: str, An arbitrary string associated with the channel that
-      is delivered to the target address with each event delivered
-      over this channel.
-    address: str, The address of the receiving entity where events are
-      delivered. Specific to the channel type.
-    expiration: int, The time, in milliseconds from the epoch, when this
-      channel will expire.
-    params: dict, A dictionary of string to string, with additional parameters
-      controlling delivery channel behavior.
-    resource_id: str, An opaque id that identifies the resource that is
-      being watched. Stable across different API versions.
-    resource_uri: str, The canonicalized ID of the watched resource.
-  """
-
-  @util.positional(5)
-  def __init__(self, type, id, token, address, expiration=None,
-               params=None, resource_id="", resource_uri=""):
-    """Create a new Channel.
-
-    In user code, this Channel constructor will not typically be called
-    manually since there are functions for creating channels for each specific
-    type with a more customized set of arguments to pass.
-
-    Args:
-      type: str, The type of delivery mechanism used by this channel. For
-        example, 'web_hook'.
-      id: str, A UUID for the channel.
-      token: str, An arbitrary string associated with the channel that
-        is delivered to the target address with each event delivered
-        over this channel.
-      address: str,  The address of the receiving entity where events are
-        delivered. Specific to the channel type.
-      expiration: int, The time, in milliseconds from the epoch, when this
-        channel will expire.
-      params: dict, A dictionary of string to string, with additional parameters
-        controlling delivery channel behavior.
-      resource_id: str, An opaque id that identifies the resource that is
-        being watched. Stable across different API versions.
-      resource_uri: str, The canonicalized ID of the watched resource.
-    """
-    self.type = type
-    self.id = id
-    self.token = token
-    self.address = address
-    self.expiration = expiration
-    self.params = params
-    self.resource_id = resource_id
-    self.resource_uri = resource_uri
-
-  def body(self):
-    """Build a body from the Channel.
-
-    Constructs a dictionary that's appropriate for passing into watch()
-    methods as the value of body argument.
-
-    Returns:
-      A dictionary representation of the channel.
-    """
-    result = {
-        'id': self.id,
-        'token': self.token,
-        'type': self.type,
-        'address': self.address
-        }
-    if self.params:
-      result['params'] = self.params
-    if self.resource_id:
-      result['resourceId'] = self.resource_id
-    if self.resource_uri:
-      result['resourceUri'] = self.resource_uri
-    if self.expiration:
-      result['expiration'] = self.expiration
-
-    return result
-
-  def update(self, resp):
-    """Update a channel with information from the response of watch().
-
-    When a request is sent to watch() a resource, the response returned
-    from the watch() request is a dictionary with updated channel information,
-    such as the resource_id, which is needed when stopping a subscription.
-
-    Args:
-      resp: dict, The response from a watch() method.
-    """
-    for json_name, param_name in CHANNEL_PARAMS.iteritems():
-      value = resp.get(json_name)
-      if value is not None:
-        setattr(self, param_name, value)
-
-
-def notification_from_headers(channel, headers):
-  """Parse a notification from the webhook request headers, validate
-    the notification, and return a Notification object.
-
-  Args:
-    channel: Channel, The channel that the notification is associated with.
-    headers: dict, A dictionary like object that contains the request headers
-      from the webhook HTTP request.
-
-  Returns:
-    A Notification object.
-
-  Raises:
-    errors.InvalidNotificationError if the notification is invalid.
-    ValueError if the X-GOOG-MESSAGE-NUMBER can't be converted to an int.
-  """
-  headers = _upper_header_keys(headers)
-  channel_id = headers[X_GOOG_CHANNEL_ID]
-  if channel.id != channel_id:
-    raise errors.InvalidNotificationError(
-        'Channel id mismatch: %s != %s' % (channel.id, channel_id))
-  else:
-    message_number = int(headers[X_GOOG_MESSAGE_NUMBER])
-    state = headers[X_GOOG_RESOURCE_STATE]
-    resource_uri = headers[X_GOOG_RESOURCE_URI]
-    resource_id = headers[X_GOOG_RESOURCE_ID]
-    return Notification(message_number, state, resource_uri, resource_id)
-
-
-@util.positional(2)
-def new_webhook_channel(url, token=None, expiration=None, params=None):
-    """Create a new webhook Channel.
-
-    Args:
-      url: str, URL to post notifications to.
-      token: str, An arbitrary string associated with the channel that
-        is delivered to the target address with each notification delivered
-        over this channel.
-      expiration: datetime.datetime, A time in the future when the channel
-        should expire. Can also be None if the subscription should use the
-        default expiration. Note that different services may have different
-        limits on how long a subscription lasts. Check the response from the
-        watch() method to see the value the service has set for an expiration
-        time.
-      params: dict, Extra parameters to pass on channel creation. Currently
-        not used for webhook channels.
-    """
-    expiration_ms = 0
-    if expiration:
-      delta = expiration - EPOCH
-      expiration_ms = delta.microseconds/1000 + (
-          delta.seconds + delta.days*24*3600)*1000
-      if expiration_ms < 0:
-        expiration_ms = 0
-
-    return Channel('web_hook', str(uuid.uuid4()),
-                   token, url, expiration=expiration_ms,
-                   params=params)
-
diff --git a/third_party/google_api_python_client/googleapiclient/discovery.py b/third_party/google_api_python_client/googleapiclient/discovery.py
deleted file mode 100644
index 3ddac57..0000000
--- a/third_party/google_api_python_client/googleapiclient/discovery.py
+++ /dev/null
@@ -1,995 +0,0 @@
-# Copyright 2014 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Client for discovery based APIs.
-
-A client library for Google's discovery based APIs.
-"""
-
-__author__ = 'jcgregorio@google.com (Joe Gregorio)'
-__all__ = [
-    'build',
-    'build_from_document',
-    'fix_method_name',
-    'key2param',
-    ]
-
-
-# Standard library imports
-import StringIO
-import copy
-from email.generator import Generator
-from email.mime.multipart import MIMEMultipart
-from email.mime.nonmultipart import MIMENonMultipart
-import json
-import keyword
-import logging
-import mimetypes
-import os
-import re
-import urllib
-import urlparse
-
-try:
-  from urlparse import parse_qsl
-except ImportError:
-  from cgi import parse_qsl
-
-# Third-party imports
-from ... import httplib2
-import mimeparse
-from ... import uritemplate
-
-# Local imports
-from googleapiclient.errors import HttpError
-from googleapiclient.errors import InvalidJsonError
-from googleapiclient.errors import MediaUploadSizeError
-from googleapiclient.errors import UnacceptableMimeTypeError
-from googleapiclient.errors import UnknownApiNameOrVersion
-from googleapiclient.errors import UnknownFileType
-from googleapiclient.http import HttpRequest
-from googleapiclient.http import MediaFileUpload
-from googleapiclient.http import MediaUpload
-from googleapiclient.model import JsonModel
-from googleapiclient.model import MediaModel
-from googleapiclient.model import RawModel
-from googleapiclient.schema import Schemas
-from oauth2client.client import GoogleCredentials
-from oauth2client.util import _add_query_parameter
-from oauth2client.util import positional
-
-
-# The client library requires a version of httplib2 that supports RETRIES.
-httplib2.RETRIES = 1
-
-logger = logging.getLogger(__name__)
-
-URITEMPLATE = re.compile('{[^}]*}')
-VARNAME = re.compile('[a-zA-Z0-9_-]+')
-DISCOVERY_URI = ('https://www.googleapis.com/discovery/v1/apis/'
-                 '{api}/{apiVersion}/rest')
-DEFAULT_METHOD_DOC = 'A description of how to use this function'
-HTTP_PAYLOAD_METHODS = frozenset(['PUT', 'POST', 'PATCH'])
-_MEDIA_SIZE_BIT_SHIFTS = {'KB': 10, 'MB': 20, 'GB': 30, 'TB': 40}
-BODY_PARAMETER_DEFAULT_VALUE = {
-    'description': 'The request body.',
-    'type': 'object',
-    'required': True,
-}
-MEDIA_BODY_PARAMETER_DEFAULT_VALUE = {
-    'description': ('The filename of the media request body, or an instance '
-                    'of a MediaUpload object.'),
-    'type': 'string',
-    'required': False,
-}
-
-# Parameters accepted by the stack, but not visible via discovery.
-# TODO(dhermes): Remove 'userip' in 'v2'.
-STACK_QUERY_PARAMETERS = frozenset(['trace', 'pp', 'userip', 'strict'])
-STACK_QUERY_PARAMETER_DEFAULT_VALUE = {'type': 'string', 'location': 'query'}
-
-# Library-specific reserved words beyond Python keywords.
-RESERVED_WORDS = frozenset(['body'])
-
-
-def fix_method_name(name):
-  """Fix method names to avoid reserved word conflicts.
-
-  Args:
-    name: string, method name.
-
-  Returns:
-    The name with a '_' prefixed if the name is a reserved word.
-  """
-  if keyword.iskeyword(name) or name in RESERVED_WORDS:
-    return name + '_'
-  else:
-    return name
-
-
-def key2param(key):
-  """Converts key names into parameter names.
-
-  For example, converting "max-results" -> "max_results"
-
-  Args:
-    key: string, the method key name.
-
-  Returns:
-    A safe method name based on the key name.
-  """
-  result = []
-  key = list(key)
-  if not key[0].isalpha():
-    result.append('x')
-  for c in key:
-    if c.isalnum():
-      result.append(c)
-    else:
-      result.append('_')
-
-  return ''.join(result)
-
-
-@positional(2)
-def build(serviceName,
-          version,
-          http=None,
-          discoveryServiceUrl=DISCOVERY_URI,
-          developerKey=None,
-          model=None,
-          requestBuilder=HttpRequest,
-          credentials=None):
-  """Construct a Resource for interacting with an API.
-
-  Construct a Resource object for interacting with an API. The serviceName and
-  version are the names from the Discovery service.
-
-  Args:
-    serviceName: string, name of the service.
-    version: string, the version of the service.
-    http: httplib2.Http, An instance of httplib2.Http or something that acts
-      like it that HTTP requests will be made through.
-    discoveryServiceUrl: string, a URI Template that points to the location of
-      the discovery service. It should have two parameters {api} and
-      {apiVersion} that when filled in produce an absolute URI to the discovery
-      document for that service.
-    developerKey: string, key obtained from
-      https://code.google.com/apis/console.
-    model: googleapiclient.Model, converts to and from the wire format.
-    requestBuilder: googleapiclient.http.HttpRequest, encapsulator for an HTTP
-      request.
-    credentials: oauth2client.Credentials, credentials to be used for
-      authentication.
-
-  Returns:
-    A Resource object with methods for interacting with the service.
-  """
-  params = {
-      'api': serviceName,
-      'apiVersion': version
-      }
-
-  if http is None:
-    http = httplib2.Http()
-
-  requested_url = uritemplate.expand(discoveryServiceUrl, params)
-
-  # REMOTE_ADDR is defined by the CGI spec [RFC3875] as the environment
-  # variable that contains the network address of the client sending the
-  # request. If it exists then add that to the request for the discovery
-  # document to avoid exceeding the quota on discovery requests.
-  if 'REMOTE_ADDR' in os.environ:
-    requested_url = _add_query_parameter(requested_url, 'userIp',
-                                         os.environ['REMOTE_ADDR'])
-  logger.info('URL being requested: GET %s' % requested_url)
-
-  resp, content = http.request(requested_url)
-
-  if resp.status == 404:
-    raise UnknownApiNameOrVersion("name: %s  version: %s" % (serviceName,
-                                                            version))
-  if resp.status >= 400:
-    raise HttpError(resp, content, uri=requested_url)
-
-  try:
-    service = json.loads(content)
-  except ValueError, e:
-    logger.error('Failed to parse as JSON: ' + content)
-    raise InvalidJsonError()
-
-  return build_from_document(content, base=discoveryServiceUrl, http=http,
-      developerKey=developerKey, model=model, requestBuilder=requestBuilder,
-      credentials=credentials)
-
-
-@positional(1)
-def build_from_document(
-    service,
-    base=None,
-    future=None,
-    http=None,
-    developerKey=None,
-    model=None,
-    requestBuilder=HttpRequest,
-    credentials=None):
-  """Create a Resource for interacting with an API.
-
-  Same as `build()`, but constructs the Resource object from a discovery
-  document that is it given, as opposed to retrieving one over HTTP.
-
-  Args:
-    service: string or object, the JSON discovery document describing the API.
-      The value passed in may either be the JSON string or the deserialized
-      JSON.
-    base: string, base URI for all HTTP requests, usually the discovery URI.
-      This parameter is no longer used as rootUrl and servicePath are included
-      within the discovery document. (deprecated)
-    future: string, discovery document with future capabilities (deprecated).
-    http: httplib2.Http, An instance of httplib2.Http or something that acts
-      like it that HTTP requests will be made through.
-    developerKey: string, Key for controlling API usage, generated
-      from the API Console.
-    model: Model class instance that serializes and de-serializes requests and
-      responses.
-    requestBuilder: Takes an http request and packages it up to be executed.
-    credentials: object, credentials to be used for authentication.
-
-  Returns:
-    A Resource object with methods for interacting with the service.
-  """
-
-  # future is no longer used.
-  future = {}
-
-  if isinstance(service, basestring):
-    service = json.loads(service)
-  base = urlparse.urljoin(service['rootUrl'], service['servicePath'])
-  schema = Schemas(service)
-
-  if credentials:
-    # If credentials were passed in, we could have two cases:
-    # 1. the scopes were specified, in which case the given credentials
-    #    are used for authorizing the http;
-    # 2. the scopes were not provided (meaning the Application Default
-    #    Credentials are to be used). In this case, the Application Default
-    #    Credentials are built and used instead of the original credentials.
-    #    If there are no scopes found (meaning the given service requires no
-    #    authentication), there is no authorization of the http.
-    if (isinstance(credentials, GoogleCredentials) and
-        credentials.create_scoped_required()):
-      scopes = service.get('auth', {}).get('oauth2', {}).get('scopes', {})
-      if scopes:
-        credentials = credentials.create_scoped(scopes.keys())
-      else:
-        # No need to authorize the http object
-        # if the service does not require authentication.
-        credentials = None
-
-    if credentials:
-      http = credentials.authorize(http)
-
-  if model is None:
-    features = service.get('features', [])
-    model = JsonModel('dataWrapper' in features)
-  return Resource(http=http, baseUrl=base, model=model,
-                  developerKey=developerKey, requestBuilder=requestBuilder,
-                  resourceDesc=service, rootDesc=service, schema=schema)
-
-
-def _cast(value, schema_type):
-  """Convert value to a string based on JSON Schema type.
-
-  See http://tools.ietf.org/html/draft-zyp-json-schema-03 for more details on
-  JSON Schema.
-
-  Args:
-    value: any, the value to convert
-    schema_type: string, the type that value should be interpreted as
-
-  Returns:
-    A string representation of 'value' based on the schema_type.
-  """
-  if schema_type == 'string':
-    if type(value) == type('') or type(value) == type(u''):
-      return value
-    else:
-      return str(value)
-  elif schema_type == 'integer':
-    return str(int(value))
-  elif schema_type == 'number':
-    return str(float(value))
-  elif schema_type == 'boolean':
-    return str(bool(value)).lower()
-  else:
-    if type(value) == type('') or type(value) == type(u''):
-      return value
-    else:
-      return str(value)
-
-
-def _media_size_to_long(maxSize):
-  """Convert a string media size, such as 10GB or 3TB into an integer.
-
-  Args:
-    maxSize: string, size as a string, such as 2MB or 7GB.
-
-  Returns:
-    The size as an integer value.
-  """
-  if len(maxSize) < 2:
-    return 0L
-  units = maxSize[-2:].upper()
-  bit_shift = _MEDIA_SIZE_BIT_SHIFTS.get(units)
-  if bit_shift is not None:
-    return long(maxSize[:-2]) << bit_shift
-  else:
-    return long(maxSize)
-
-
-def _media_path_url_from_info(root_desc, path_url):
-  """Creates an absolute media path URL.
-
-  Constructed using the API root URI and service path from the discovery
-  document and the relative path for the API method.
-
-  Args:
-    root_desc: Dictionary; the entire original deserialized discovery document.
-    path_url: String; the relative URL for the API method. Relative to the API
-        root, which is specified in the discovery document.
-
-  Returns:
-    String; the absolute URI for media upload for the API method.
-  """
-  return '%(root)supload/%(service_path)s%(path)s' % {
-      'root': root_desc['rootUrl'],
-      'service_path': root_desc['servicePath'],
-      'path': path_url,
-  }
-
-
-def _fix_up_parameters(method_desc, root_desc, http_method):
-  """Updates parameters of an API method with values specific to this library.
-
-  Specifically, adds whatever global parameters are specified by the API to the
-  parameters for the individual method. Also adds parameters which don't
-  appear in the discovery document, but are available to all discovery based
-  APIs (these are listed in STACK_QUERY_PARAMETERS).
-
-  SIDE EFFECTS: This updates the parameters dictionary object in the method
-  description.
-
-  Args:
-    method_desc: Dictionary with metadata describing an API method. Value comes
-        from the dictionary of methods stored in the 'methods' key in the
-        deserialized discovery document.
-    root_desc: Dictionary; the entire original deserialized discovery document.
-    http_method: String; the HTTP method used to call the API method described
-        in method_desc.
-
-  Returns:
-    The updated Dictionary stored in the 'parameters' key of the method
-        description dictionary.
-  """
-  parameters = method_desc.setdefault('parameters', {})
-
-  # Add in the parameters common to all methods.
-  for name, description in root_desc.get('parameters', {}).iteritems():
-    parameters[name] = description
-
-  # Add in undocumented query parameters.
-  for name in STACK_QUERY_PARAMETERS:
-    parameters[name] = STACK_QUERY_PARAMETER_DEFAULT_VALUE.copy()
-
-  # Add 'body' (our own reserved word) to parameters if the method supports
-  # a request payload.
-  if http_method in HTTP_PAYLOAD_METHODS and 'request' in method_desc:
-    body = BODY_PARAMETER_DEFAULT_VALUE.copy()
-    body.update(method_desc['request'])
-    parameters['body'] = body
-
-  return parameters
-
-
-def _fix_up_media_upload(method_desc, root_desc, path_url, parameters):
-  """Updates parameters of API by adding 'media_body' if supported by method.
-
-  SIDE EFFECTS: If the method supports media upload and has a required body,
-  sets body to be optional (required=False) instead. Also, if there is a
-  'mediaUpload' in the method description, adds 'media_upload' key to
-  parameters.
-
-  Args:
-    method_desc: Dictionary with metadata describing an API method. Value comes
-        from the dictionary of methods stored in the 'methods' key in the
-        deserialized discovery document.
-    root_desc: Dictionary; the entire original deserialized discovery document.
-    path_url: String; the relative URL for the API method. Relative to the API
-        root, which is specified in the discovery document.
-    parameters: A dictionary describing method parameters for method described
-        in method_desc.
-
-  Returns:
-    Triple (accept, max_size, media_path_url) where:
-      - accept is a list of strings representing what content types are
-        accepted for media upload. Defaults to empty list if not in the
-        discovery document.
-      - max_size is a long representing the max size in bytes allowed for a
-        media upload. Defaults to 0L if not in the discovery document.
-      - media_path_url is a String; the absolute URI for media upload for the
-        API method. Constructed using the API root URI and service path from
-        the discovery document and the relative path for the API method. If
-        media upload is not supported, this is None.
-  """
-  media_upload = method_desc.get('mediaUpload', {})
-  accept = media_upload.get('accept', [])
-  max_size = _media_size_to_long(media_upload.get('maxSize', ''))
-  media_path_url = None
-
-  if media_upload:
-    media_path_url = _media_path_url_from_info(root_desc, path_url)
-    parameters['media_body'] = MEDIA_BODY_PARAMETER_DEFAULT_VALUE.copy()
-    if 'body' in parameters:
-      parameters['body']['required'] = False
-
-  return accept, max_size, media_path_url
-
-
-def _fix_up_method_description(method_desc, root_desc):
-  """Updates a method description in a discovery document.
-
-  SIDE EFFECTS: Changes the parameters dictionary in the method description with
-  extra parameters which are used locally.
-
-  Args:
-    method_desc: Dictionary with metadata describing an API method. Value comes
-        from the dictionary of methods stored in the 'methods' key in the
-        deserialized discovery document.
-    root_desc: Dictionary; the entire original deserialized discovery document.
-
-  Returns:
-    Tuple (path_url, http_method, method_id, accept, max_size, media_path_url)
-    where:
-      - path_url is a String; the relative URL for the API method. Relative to
-        the API root, which is specified in the discovery document.
-      - http_method is a String; the HTTP method used to call the API method
-        described in the method description.
-      - method_id is a String; the name of the RPC method associated with the
-        API method, and is in the method description in the 'id' key.
-      - accept is a list of strings representing what content types are
-        accepted for media upload. Defaults to empty list if not in the
-        discovery document.
-      - max_size is a long representing the max size in bytes allowed for a
-        media upload. Defaults to 0L if not in the discovery document.
-      - media_path_url is a String; the absolute URI for media upload for the
-        API method. Constructed using the API root URI and service path from
-        the discovery document and the relative path for the API method. If
-        media upload is not supported, this is None.
-  """
-  path_url = method_desc['path']
-  http_method = method_desc['httpMethod']
-  method_id = method_desc['id']
-
-  parameters = _fix_up_parameters(method_desc, root_desc, http_method)
-  # Order is important. `_fix_up_media_upload` needs `method_desc` to have a
-  # 'parameters' key and needs to know if there is a 'body' parameter because it
-  # also sets a 'media_body' parameter.
-  accept, max_size, media_path_url = _fix_up_media_upload(
-      method_desc, root_desc, path_url, parameters)
-
-  return path_url, http_method, method_id, accept, max_size, media_path_url
-
-
-# TODO(dhermes): Convert this class to ResourceMethod and make it callable
-class ResourceMethodParameters(object):
-  """Represents the parameters associated with a method.
-
-  Attributes:
-    argmap: Map from method parameter name (string) to query parameter name
-        (string).
-    required_params: List of required parameters (represented by parameter
-        name as string).
-    repeated_params: List of repeated parameters (represented by parameter
-        name as string).
-    pattern_params: Map from method parameter name (string) to regular
-        expression (as a string). If the pattern is set for a parameter, the
-        value for that parameter must match the regular expression.
-    query_params: List of parameters (represented by parameter name as string)
-        that will be used in the query string.
-    path_params: Set of parameters (represented by parameter name as string)
-        that will be used in the base URL path.
-    param_types: Map from method parameter name (string) to parameter type. Type
-        can be any valid JSON schema type; valid values are 'any', 'array',
-        'boolean', 'integer', 'number', 'object', or 'string'. Reference:
-        http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.1
-    enum_params: Map from method parameter name (string) to list of strings,
-       where each list of strings is the list of acceptable enum values.
-  """
-
-  def __init__(self, method_desc):
-    """Constructor for ResourceMethodParameters.
-
-    Sets default values and defers to set_parameters to populate.
-
-    Args:
-      method_desc: Dictionary with metadata describing an API method. Value
-          comes from the dictionary of methods stored in the 'methods' key in
-          the deserialized discovery document.
-    """
-    self.argmap = {}
-    self.required_params = []
-    self.repeated_params = []
-    self.pattern_params = {}
-    self.query_params = []
-    # TODO(dhermes): Change path_params to a list if the extra URITEMPLATE
-    #                parsing is gotten rid of.
-    self.path_params = set()
-    self.param_types = {}
-    self.enum_params = {}
-
-    self.set_parameters(method_desc)
-
-  def set_parameters(self, method_desc):
-    """Populates maps and lists based on method description.
-
-    Iterates through each parameter for the method and parses the values from
-    the parameter dictionary.
-
-    Args:
-      method_desc: Dictionary with metadata describing an API method. Value
-          comes from the dictionary of methods stored in the 'methods' key in
-          the deserialized discovery document.
-    """
-    for arg, desc in method_desc.get('parameters', {}).iteritems():
-      param = key2param(arg)
-      self.argmap[param] = arg
-
-      if desc.get('pattern'):
-        self.pattern_params[param] = desc['pattern']
-      if desc.get('enum'):
-        self.enum_params[param] = desc['enum']
-      if desc.get('required'):
-        self.required_params.append(param)
-      if desc.get('repeated'):
-        self.repeated_params.append(param)
-      if desc.get('location') == 'query':
-        self.query_params.append(param)
-      if desc.get('location') == 'path':
-        self.path_params.add(param)
-      self.param_types[param] = desc.get('type', 'string')
-
-    # TODO(dhermes): Determine if this is still necessary. Discovery based APIs
-    #                should have all path parameters already marked with
-    #                'location: path'.
-    for match in URITEMPLATE.finditer(method_desc['path']):
-      for namematch in VARNAME.finditer(match.group(0)):
-        name = key2param(namematch.group(0))
-        self.path_params.add(name)
-        if name in self.query_params:
-          self.query_params.remove(name)
-
-
-def createMethod(methodName, methodDesc, rootDesc, schema):
-  """Creates a method for attaching to a Resource.
-
-  Args:
-    methodName: string, name of the method to use.
-    methodDesc: object, fragment of deserialized discovery document that
-      describes the method.
-    rootDesc: object, the entire deserialized discovery document.
-    schema: object, mapping of schema names to schema descriptions.
-  """
-  methodName = fix_method_name(methodName)
-  (pathUrl, httpMethod, methodId, accept,
-   maxSize, mediaPathUrl) = _fix_up_method_description(methodDesc, rootDesc)
-
-  parameters = ResourceMethodParameters(methodDesc)
-
-  def method(self, **kwargs):
-    # Don't bother with doc string, it will be over-written by createMethod.
-
-    for name in kwargs.iterkeys():
-      if name not in parameters.argmap:
-        raise TypeError('Got an unexpected keyword argument "%s"' % name)
-
-    # Remove args that have a value of None.
-    keys = kwargs.keys()
-    for name in keys:
-      if kwargs[name] is None:
-        del kwargs[name]
-
-    for name in parameters.required_params:
-      if name not in kwargs:
-        raise TypeError('Missing required parameter "%s"' % name)
-
-    for name, regex in parameters.pattern_params.iteritems():
-      if name in kwargs:
-        if isinstance(kwargs[name], basestring):
-          pvalues = [kwargs[name]]
-        else:
-          pvalues = kwargs[name]
-        for pvalue in pvalues:
-          if re.match(regex, pvalue) is None:
-            raise TypeError(
-                'Parameter "%s" value "%s" does not match the pattern "%s"' %
-                (name, pvalue, regex))
-
-    for name, enums in parameters.enum_params.iteritems():
-      if name in kwargs:
-        # We need to handle the case of a repeated enum
-        # name differently, since we want to handle both
-        # arg='value' and arg=['value1', 'value2']
-        if (name in parameters.repeated_params and
-            not isinstance(kwargs[name], basestring)):
-          values = kwargs[name]
-        else:
-          values = [kwargs[name]]
-        for value in values:
-          if value not in enums:
-            raise TypeError(
-                'Parameter "%s" value "%s" is not an allowed value in "%s"' %
-                (name, value, str(enums)))
-
-    actual_query_params = {}
-    actual_path_params = {}
-    for key, value in kwargs.iteritems():
-      to_type = parameters.param_types.get(key, 'string')
-      # For repeated parameters we cast each member of the list.
-      if key in parameters.repeated_params and type(value) == type([]):
-        cast_value = [_cast(x, to_type) for x in value]
-      else:
-        cast_value = _cast(value, to_type)
-      if key in parameters.query_params:
-        actual_query_params[parameters.argmap[key]] = cast_value
-      if key in parameters.path_params:
-        actual_path_params[parameters.argmap[key]] = cast_value
-    body_value = kwargs.get('body', None)
-    media_filename = kwargs.get('media_body', None)
-
-    if self._developerKey:
-      actual_query_params['key'] = self._developerKey
-
-    model = self._model
-    if methodName.endswith('_media'):
-      model = MediaModel()
-    elif 'response' not in methodDesc:
-      model = RawModel()
-
-    headers = {}
-    headers, params, query, body = model.request(headers,
-        actual_path_params, actual_query_params, body_value)
-
-    expanded_url = uritemplate.expand(pathUrl, params)
-    url = urlparse.urljoin(self._baseUrl, expanded_url + query)
-
-    resumable = None
-    multipart_boundary = ''
-
-    if media_filename:
-      # Ensure we end up with a valid MediaUpload object.
-      if isinstance(media_filename, basestring):
-        (media_mime_type, encoding) = mimetypes.guess_type(media_filename)
-        if media_mime_type is None:
-          raise UnknownFileType(media_filename)
-        if not mimeparse.best_match([media_mime_type], ','.join(accept)):
-          raise UnacceptableMimeTypeError(media_mime_type)
-        media_upload = MediaFileUpload(media_filename,
-                                       mimetype=media_mime_type)
-      elif isinstance(media_filename, MediaUpload):
-        media_upload = media_filename
-      else:
-        raise TypeError('media_filename must be str or MediaUpload.')
-
-      # Check the maxSize
-      if maxSize > 0 and media_upload.size() > maxSize:
-        raise MediaUploadSizeError("Media larger than: %s" % maxSize)
-
-      # Use the media path uri for media uploads
-      expanded_url = uritemplate.expand(mediaPathUrl, params)
-      url = urlparse.urljoin(self._baseUrl, expanded_url + query)
-      if media_upload.resumable():
-        url = _add_query_parameter(url, 'uploadType', 'resumable')
-
-      if media_upload.resumable():
-        # This is all we need to do for resumable, if the body exists it gets
-        # sent in the first request, otherwise an empty body is sent.
-        resumable = media_upload
-      else:
-        # A non-resumable upload
-        if body is None:
-          # This is a simple media upload
-          headers['content-type'] = media_upload.mimetype()
-          body = media_upload.getbytes(0, media_upload.size())
-          url = _add_query_parameter(url, 'uploadType', 'media')
-        else:
-          # This is a multipart/related upload.
-          msgRoot = MIMEMultipart('related')
-          # msgRoot should not write out it's own headers
-          setattr(msgRoot, '_write_headers', lambda self: None)
-
-          # attach the body as one part
-          msg = MIMENonMultipart(*headers['content-type'].split('/'))
-          msg.set_payload(body)
-          msgRoot.attach(msg)
-
-          # attach the media as the second part
-          msg = MIMENonMultipart(*media_upload.mimetype().split('/'))
-          msg['Content-Transfer-Encoding'] = 'binary'
-
-          payload = media_upload.getbytes(0, media_upload.size())
-          msg.set_payload(payload)
-          msgRoot.attach(msg)
-          # encode the body: note that we can't use `as_string`, because
-          # it plays games with `From ` lines.
-          fp = StringIO.StringIO()
-          g = Generator(fp, mangle_from_=False)
-          g.flatten(msgRoot, unixfrom=False)
-          body = fp.getvalue()
-
-          multipart_boundary = msgRoot.get_boundary()
-          headers['content-type'] = ('multipart/related; '
-                                     'boundary="%s"') % multipart_boundary
-          url = _add_query_parameter(url, 'uploadType', 'multipart')
-
-    logger.info('URL being requested: %s %s' % (httpMethod,url))
-    return self._requestBuilder(self._http,
-                                model.response,
-                                url,
-                                method=httpMethod,
-                                body=body,
-                                headers=headers,
-                                methodId=methodId,
-                                resumable=resumable)
-
-  docs = [methodDesc.get('description', DEFAULT_METHOD_DOC), '\n\n']
-  if len(parameters.argmap) > 0:
-    docs.append('Args:\n')
-
-  # Skip undocumented params and params common to all methods.
-  skip_parameters = rootDesc.get('parameters', {}).keys()
-  skip_parameters.extend(STACK_QUERY_PARAMETERS)
-
-  all_args = parameters.argmap.keys()
-  args_ordered = [key2param(s) for s in methodDesc.get('parameterOrder', [])]
-
-  # Move body to the front of the line.
-  if 'body' in all_args:
-    args_ordered.append('body')
-
-  for name in all_args:
-    if name not in args_ordered:
-      args_ordered.append(name)
-
-  for arg in args_ordered:
-    if arg in skip_parameters:
-      continue
-
-    repeated = ''
-    if arg in parameters.repeated_params:
-      repeated = ' (repeated)'
-    required = ''
-    if arg in parameters.required_params:
-      required = ' (required)'
-    paramdesc = methodDesc['parameters'][parameters.argmap[arg]]
-    paramdoc = paramdesc.get('description', 'A parameter')
-    if '$ref' in paramdesc:
-      docs.append(
-          ('  %s: object, %s%s%s\n    The object takes the'
-          ' form of:\n\n%s\n\n') % (arg, paramdoc, required, repeated,
-            schema.prettyPrintByName(paramdesc['$ref'])))
-    else:
-      paramtype = paramdesc.get('type', 'string')
-      docs.append('  %s: %s, %s%s%s\n' % (arg, paramtype, paramdoc, required,
-                                          repeated))
-    enum = paramdesc.get('enum', [])
-    enumDesc = paramdesc.get('enumDescriptions', [])
-    if enum and enumDesc:
-      docs.append('    Allowed values\n')
-      for (name, desc) in zip(enum, enumDesc):
-        docs.append('      %s - %s\n' % (name, desc))
-  if 'response' in methodDesc:
-    if methodName.endswith('_media'):
-      docs.append('\nReturns:\n  The media object as a string.\n\n    ')
-    else:
-      docs.append('\nReturns:\n  An object of the form:\n\n    ')
-      docs.append(schema.prettyPrintSchema(methodDesc['response']))
-
-  setattr(method, '__doc__', ''.join(docs))
-  return (methodName, method)
-
-
-def createNextMethod(methodName):
-  """Creates any _next methods for attaching to a Resource.
-
-  The _next methods allow for easy iteration through list() responses.
-
-  Args:
-    methodName: string, name of the method to use.
-  """
-  methodName = fix_method_name(methodName)
-
-  def methodNext(self, previous_request, previous_response):
-    """Retrieves the next page of results.
-
-Args:
-  previous_request: The request for the previous page. (required)
-  previous_response: The response from the request for the previous page. (required)
-
-Returns:
-  A request object that you can call 'execute()' on to request the next
-  page. Returns None if there are no more items in the collection.
-    """
-    # Retrieve nextPageToken from previous_response
-    # Use as pageToken in previous_request to create new request.
-
-    if 'nextPageToken' not in previous_response:
-      return None
-
-    request = copy.copy(previous_request)
-
-    pageToken = previous_response['nextPageToken']
-    parsed = list(urlparse.urlparse(request.uri))
-    q = parse_qsl(parsed[4])
-
-    # Find and remove old 'pageToken' value from URI
-    newq = [(key, value) for (key, value) in q if key != 'pageToken']
-    newq.append(('pageToken', pageToken))
-    parsed[4] = urllib.urlencode(newq)
-    uri = urlparse.urlunparse(parsed)
-
-    request.uri = uri
-
-    logger.info('URL being requested: %s %s' % (methodName,uri))
-
-    return request
-
-  return (methodName, methodNext)
-
-
-class Resource(object):
-  """A class for interacting with a resource."""
-
-  def __init__(self, http, baseUrl, model, requestBuilder, developerKey,
-               resourceDesc, rootDesc, schema):
-    """Build a Resource from the API description.
-
-    Args:
-      http: httplib2.Http, Object to make http requests with.
-      baseUrl: string, base URL for the API. All requests are relative to this
-          URI.
-      model: googleapiclient.Model, converts to and from the wire format.
-      requestBuilder: class or callable that instantiates an
-          googleapiclient.HttpRequest object.
-      developerKey: string, key obtained from
-          https://code.google.com/apis/console
-      resourceDesc: object, section of deserialized discovery document that
-          describes a resource. Note that the top level discovery document
-          is considered a resource.
-      rootDesc: object, the entire deserialized discovery document.
-      schema: object, mapping of schema names to schema descriptions.
-    """
-    self._dynamic_attrs = []
-
-    self._http = http
-    self._baseUrl = baseUrl
-    self._model = model
-    self._developerKey = developerKey
-    self._requestBuilder = requestBuilder
-    self._resourceDesc = resourceDesc
-    self._rootDesc = rootDesc
-    self._schema = schema
-
-    self._set_service_methods()
-
-  def _set_dynamic_attr(self, attr_name, value):
-    """Sets an instance attribute and tracks it in a list of dynamic attributes.
-
-    Args:
-      attr_name: string; The name of the attribute to be set
-      value: The value being set on the object and tracked in the dynamic cache.
-    """
-    self._dynamic_attrs.append(attr_name)
-    self.__dict__[attr_name] = value
-
-  def __getstate__(self):
-    """Trim the state down to something that can be pickled.
-
-    Uses the fact that the instance variable _dynamic_attrs holds attrs that
-    will be wiped and restored on pickle serialization.
-    """
-    state_dict = copy.copy(self.__dict__)
-    for dynamic_attr in self._dynamic_attrs:
-      del state_dict[dynamic_attr]
-    del state_dict['_dynamic_attrs']
-    return state_dict
-
-  def __setstate__(self, state):
-    """Reconstitute the state of the object from being pickled.
-
-    Uses the fact that the instance variable _dynamic_attrs holds attrs that
-    will be wiped and restored on pickle serialization.
-    """
-    self.__dict__.update(state)
-    self._dynamic_attrs = []
-    self._set_service_methods()
-
-  def _set_service_methods(self):
-    self._add_basic_methods(self._resourceDesc, self._rootDesc, self._schema)
-    self._add_nested_resources(self._resourceDesc, self._rootDesc, self._schema)
-    self._add_next_methods(self._resourceDesc, self._schema)
-
-  def _add_basic_methods(self, resourceDesc, rootDesc, schema):
-    # Add basic methods to Resource
-    if 'methods' in resourceDesc:
-      for methodName, methodDesc in resourceDesc['methods'].iteritems():
-        fixedMethodName, method = createMethod(
-            methodName, methodDesc, rootDesc, schema)
-        self._set_dynamic_attr(fixedMethodName,
-                               method.__get__(self, self.__class__))
-        # Add in _media methods. The functionality of the attached method will
-        # change when it sees that the method name ends in _media.
-        if methodDesc.get('supportsMediaDownload', False):
-          fixedMethodName, method = createMethod(
-              methodName + '_media', methodDesc, rootDesc, schema)
-          self._set_dynamic_attr(fixedMethodName,
-                                 method.__get__(self, self.__class__))
-
-  def _add_nested_resources(self, resourceDesc, rootDesc, schema):
-    # Add in nested resources
-    if 'resources' in resourceDesc:
-
-      def createResourceMethod(methodName, methodDesc):
-        """Create a method on the Resource to access a nested Resource.
-
-        Args:
-          methodName: string, name of the method to use.
-          methodDesc: object, fragment of deserialized discovery document that
-            describes the method.
-        """
-        methodName = fix_method_name(methodName)
-
-        def methodResource(self):
-          return Resource(http=self._http, baseUrl=self._baseUrl,
-                          model=self._model, developerKey=self._developerKey,
-                          requestBuilder=self._requestBuilder,
-                          resourceDesc=methodDesc, rootDesc=rootDesc,
-                          schema=schema)
-
-        setattr(methodResource, '__doc__', 'A collection resource.')
-        setattr(methodResource, '__is_resource__', True)
-
-        return (methodName, methodResource)
-
-      for methodName, methodDesc in resourceDesc['resources'].iteritems():
-        fixedMethodName, method = createResourceMethod(methodName, methodDesc)
-        self._set_dynamic_attr(fixedMethodName,
-                               method.__get__(self, self.__class__))
-
-  def _add_next_methods(self, resourceDesc, schema):
-    # Add _next() methods
-    # Look for response bodies in schema that contain nextPageToken, and methods
-    # that take a pageToken parameter.
-    if 'methods' in resourceDesc:
-      for methodName, methodDesc in resourceDesc['methods'].iteritems():
-        if 'response' in methodDesc:
-          responseSchema = methodDesc['response']
-          if '$ref' in responseSchema:
-            responseSchema = schema.get(responseSchema['$ref'])
-          hasNextPageToken = 'nextPageToken' in responseSchema.get('properties',
-                                                                   {})
-          hasPageToken = 'pageToken' in methodDesc.get('parameters', {})
-          if hasNextPageToken and hasPageToken:
-            fixedMethodName, method = createNextMethod(methodName + '_next')
-            self._set_dynamic_attr(fixedMethodName,
-                                   method.__get__(self, self.__class__))
diff --git a/third_party/google_api_python_client/googleapiclient/errors.py b/third_party/google_api_python_client/googleapiclient/errors.py
deleted file mode 100644
index a1999fd..0000000
--- a/third_party/google_api_python_client/googleapiclient/errors.py
+++ /dev/null
@@ -1,140 +0,0 @@
-#!/usr/bin/python2.4
-#
-# Copyright 2014 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Errors for the library.
-
-All exceptions defined by the library
-should be defined in this file.
-"""
-
-__author__ = 'jcgregorio@google.com (Joe Gregorio)'
-
-import json
-
-from ...oauth2client import util
-
-
-class Error(Exception):
-  """Base error for this module."""
-  pass
-
-
-class HttpError(Error):
-  """HTTP data was invalid or unexpected."""
-
-  @util.positional(3)
-  def __init__(self, resp, content, uri=None):
-    self.resp = resp
-    self.content = content
-    self.uri = uri
-
-  def _get_reason(self):
-    """Calculate the reason for the error from the response content."""
-    reason = self.resp.reason
-    try:
-      data = json.loads(self.content)
-      reason = data['error']['message']
-    except (ValueError, KeyError):
-      pass
-    if reason is None:
-      reason = ''
-    return reason
-
-  def __repr__(self):
-    if self.uri:
-      return '<HttpError %s when requesting %s returned "%s">' % (
-          self.resp.status, self.uri, self._get_reason().strip())
-    else:
-      return '<HttpError %s "%s">' % (self.resp.status, self._get_reason())
-
-  __str__ = __repr__
-
-
-class InvalidJsonError(Error):
-  """The JSON returned could not be parsed."""
-  pass
-
-
-class UnknownFileType(Error):
-  """File type unknown or unexpected."""
-  pass
-
-
-class UnknownLinkType(Error):
-  """Link type unknown or unexpected."""
-  pass
-
-
-class UnknownApiNameOrVersion(Error):
-  """No API with that name and version exists."""
-  pass
-
-
-class UnacceptableMimeTypeError(Error):
-  """That is an unacceptable mimetype for this operation."""
-  pass
-
-
-class MediaUploadSizeError(Error):
-  """Media is larger than the method can accept."""
-  pass
-
-
-class ResumableUploadError(HttpError):
-  """Error occured during resumable upload."""
-  pass
-
-
-class InvalidChunkSizeError(Error):
-  """The given chunksize is not valid."""
-  pass
-
-class InvalidNotificationError(Error):
-  """The channel Notification is invalid."""
-  pass
-
-class BatchError(HttpError):
-  """Error occured during batch operations."""
-
-  @util.positional(2)
-  def __init__(self, reason, resp=None, content=None):
-    self.resp = resp
-    self.content = content
-    self.reason = reason
-
-  def __repr__(self):
-      return '<BatchError %s "%s">' % (self.resp.status, self.reason)
-
-  __str__ = __repr__
-
-
-class UnexpectedMethodError(Error):
-  """Exception raised by RequestMockBuilder on unexpected calls."""
-
-  @util.positional(1)
-  def __init__(self, methodId=None):
-    """Constructor for an UnexpectedMethodError."""
-    super(UnexpectedMethodError, self).__init__(
-        'Received unexpected call %s' % methodId)
-
-
-class UnexpectedBodyError(Error):
-  """Exception raised by RequestMockBuilder on unexpected bodies."""
-
-  def __init__(self, expected, provided):
-    """Constructor for an UnexpectedMethodError."""
-    super(UnexpectedBodyError, self).__init__(
-        'Expected: [%s] - Provided: [%s]' % (expected, provided))
diff --git a/third_party/google_api_python_client/googleapiclient/http.py b/third_party/google_api_python_client/googleapiclient/http.py
deleted file mode 100644
index 8638279..0000000
--- a/third_party/google_api_python_client/googleapiclient/http.py
+++ /dev/null
@@ -1,1614 +0,0 @@
-# Copyright 2014 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Classes to encapsulate a single HTTP request.
-
-The classes implement a command pattern, with every
-object supporting an execute() method that does the
-actuall HTTP request.
-"""
-
-__author__ = 'jcgregorio@google.com (Joe Gregorio)'
-
-import StringIO
-import base64
-import copy
-import gzip
-import httplib2
-import json
-import logging
-import mimeparse
-import mimetypes
-import os
-import random
-import sys
-import time
-import urllib
-import urlparse
-import uuid
-
-from email.generator import Generator
-from email.mime.multipart import MIMEMultipart
-from email.mime.nonmultipart import MIMENonMultipart
-from email.parser import FeedParser
-from errors import BatchError
-from errors import HttpError
-from errors import InvalidChunkSizeError
-from errors import ResumableUploadError
-from errors import UnexpectedBodyError
-from errors import UnexpectedMethodError
-from model import JsonModel
-from ...oauth2client import util
-
-
-DEFAULT_CHUNK_SIZE = 512*1024
-
-MAX_URI_LENGTH = 2048
-
-
-class MediaUploadProgress(object):
-  """Status of a resumable upload."""
-
-  def __init__(self, resumable_progress, total_size):
-    """Constructor.
-
-    Args:
-      resumable_progress: int, bytes sent so far.
-      total_size: int, total bytes in complete upload, or None if the total
-        upload size isn't known ahead of time.
-    """
-    self.resumable_progress = resumable_progress
-    self.total_size = total_size
-
-  def progress(self):
-    """Percent of upload completed, as a float.
-
-    Returns:
-      the percentage complete as a float, returning 0.0 if the total size of
-      the upload is unknown.
-    """
-    if self.total_size is not None:
-      return float(self.resumable_progress) / float(self.total_size)
-    else:
-      return 0.0
-
-
-class MediaDownloadProgress(object):
-  """Status of a resumable download."""
-
-  def __init__(self, resumable_progress, total_size):
-    """Constructor.
-
-    Args:
-      resumable_progress: int, bytes received so far.
-      total_size: int, total bytes in complete download.
-    """
-    self.resumable_progress = resumable_progress
-    self.total_size = total_size
-
-  def progress(self):
-    """Percent of download completed, as a float.
-
-    Returns:
-      the percentage complete as a float, returning 0.0 if the total size of
-      the download is unknown.
-    """
-    if self.total_size is not None:
-      return float(self.resumable_progress) / float(self.total_size)
-    else:
-      return 0.0
-
-
-class MediaUpload(object):
-  """Describes a media object to upload.
-
-  Base class that defines the interface of MediaUpload subclasses.
-
-  Note that subclasses of MediaUpload may allow you to control the chunksize
-  when uploading a media object. It is important to keep the size of the chunk
-  as large as possible to keep the upload efficient. Other factors may influence
-  the size of the chunk you use, particularly if you are working in an
-  environment where individual HTTP requests may have a hardcoded time limit,
-  such as under certain classes of requests under Google App Engine.
-
-  Streams are io.Base compatible objects that support seek(). Some MediaUpload
-  subclasses support using streams directly to upload data. Support for
-  streaming may be indicated by a MediaUpload sub-class and if appropriate for a
-  platform that stream will be used for uploading the media object. The support
-  for streaming is indicated by has_stream() returning True. The stream() method
-  should return an io.Base object that supports seek(). On platforms where the
-  underlying httplib module supports streaming, for example Python 2.6 and
-  later, the stream will be passed into the http library which will result in
-  less memory being used and possibly faster uploads.
-
-  If you need to upload media that can't be uploaded using any of the existing
-  MediaUpload sub-class then you can sub-class MediaUpload for your particular
-  needs.
-  """
-
-  def chunksize(self):
-    """Chunk size for resumable uploads.
-
-    Returns:
-      Chunk size in bytes.
-    """
-    raise NotImplementedError()
-
-  def mimetype(self):
-    """Mime type of the body.
-
-    Returns:
-      Mime type.
-    """
-    return 'application/octet-stream'
-
-  def size(self):
-    """Size of upload.
-
-    Returns:
-      Size of the body, or None of the size is unknown.
-    """
-    return None
-
-  def resumable(self):
-    """Whether this upload is resumable.
-
-    Returns:
-      True if resumable upload or False.
-    """
-    return False
-
-  def getbytes(self, begin, end):
-    """Get bytes from the media.
-
-    Args:
-      begin: int, offset from beginning of file.
-      length: int, number of bytes to read, starting at begin.
-
-    Returns:
-      A string of bytes read. May be shorter than length if EOF was reached
-      first.
-    """
-    raise NotImplementedError()
-
-  def has_stream(self):
-    """Does the underlying upload support a streaming interface.
-
-    Streaming means it is an io.IOBase subclass that supports seek, i.e.
-    seekable() returns True.
-
-    Returns:
-      True if the call to stream() will return an instance of a seekable io.Base
-      subclass.
-    """
-    return False
-
-  def stream(self):
-    """A stream interface to the data being uploaded.
-
-    Returns:
-      The returned value is an io.IOBase subclass that supports seek, i.e.
-      seekable() returns True.
-    """
-    raise NotImplementedError()
-
-  @util.positional(1)
-  def _to_json(self, strip=None):
-    """Utility function for creating a JSON representation of a MediaUpload.
-
-    Args:
-      strip: array, An array of names of members to not include in the JSON.
-
-    Returns:
-       string, a JSON representation of this instance, suitable to pass to
-       from_json().
-    """
-    t = type(self)
-    d = copy.copy(self.__dict__)
-    if strip is not None:
-      for member in strip:
-        del d[member]
-    d['_class'] = t.__name__
-    d['_module'] = t.__module__
-    return json.dumps(d)
-
-  def to_json(self):
-    """Create a JSON representation of an instance of MediaUpload.
-
-    Returns:
-       string, a JSON representation of this instance, suitable to pass to
-       from_json().
-    """
-    return self._to_json()
-
-  @classmethod
-  def new_from_json(cls, s):
-    """Utility class method to instantiate a MediaUpload subclass from a JSON
-    representation produced by to_json().
-
-    Args:
-      s: string, JSON from to_json().
-
-    Returns:
-      An instance of the subclass of MediaUpload that was serialized with
-      to_json().
-    """
-    data = json.loads(s)
-    # Find and call the right classmethod from_json() to restore the object.
-    module = data['_module']
-    m = __import__(module, fromlist=module.split('.')[:-1])
-    kls = getattr(m, data['_class'])
-    from_json = getattr(kls, 'from_json')
-    return from_json(s)
-
-
-class MediaIoBaseUpload(MediaUpload):
-  """A MediaUpload for a io.Base objects.
-
-  Note that the Python file object is compatible with io.Base and can be used
-  with this class also.
-
-    fh = io.BytesIO('...Some data to upload...')
-    media = MediaIoBaseUpload(fh, mimetype='image/png',
-      chunksize=1024*1024, resumable=True)
-    farm.animals().insert(
-        id='cow',
-        name='cow.png',
-        media_body=media).execute()
-
-  Depending on the platform you are working on, you may pass -1 as the
-  chunksize, which indicates that the entire file should be uploaded in a single
-  request. If the underlying platform supports streams, such as Python 2.6 or
-  later, then this can be very efficient as it avoids multiple connections, and
-  also avoids loading the entire file into memory before sending it. Note that
-  Google App Engine has a 5MB limit on request size, so you should never set
-  your chunksize larger than 5MB, or to -1.
-  """
-
-  @util.positional(3)
-  def __init__(self, fd, mimetype, chunksize=DEFAULT_CHUNK_SIZE,
-      resumable=False):
-    """Constructor.
-
-    Args:
-      fd: io.Base or file object, The source of the bytes to upload. MUST be
-        opened in blocking mode, do not use streams opened in non-blocking mode.
-        The given stream must be seekable, that is, it must be able to call
-        seek() on fd.
-      mimetype: string, Mime-type of the file.
-      chunksize: int, File will be uploaded in chunks of this many bytes. Only
-        used if resumable=True. Pass in a value of -1 if the file is to be
-        uploaded as a single chunk. Note that Google App Engine has a 5MB limit
-        on request size, so you should never set your chunksize larger than 5MB,
-        or to -1.
-      resumable: bool, True if this is a resumable upload. False means upload
-        in a single request.
-    """
-    super(MediaIoBaseUpload, self).__init__()
-    self._fd = fd
-    self._mimetype = mimetype
-    if not (chunksize == -1 or chunksize > 0):
-      raise InvalidChunkSizeError()
-    self._chunksize = chunksize
-    self._resumable = resumable
-
-    self._fd.seek(0, os.SEEK_END)
-    self._size = self._fd.tell()
-
-  def chunksize(self):
-    """Chunk size for resumable uploads.
-
-    Returns:
-      Chunk size in bytes.
-    """
-    return self._chunksize
-
-  def mimetype(self):
-    """Mime type of the body.
-
-    Returns:
-      Mime type.
-    """
-    return self._mimetype
-
-  def size(self):
-    """Size of upload.
-
-    Returns:
-      Size of the body, or None of the size is unknown.
-    """
-    return self._size
-
-  def resumable(self):
-    """Whether this upload is resumable.
-
-    Returns:
-      True if resumable upload or False.
-    """
-    return self._resumable
-
-  def getbytes(self, begin, length):
-    """Get bytes from the media.
-
-    Args:
-      begin: int, offset from beginning of file.
-      length: int, number of bytes to read, starting at begin.
-
-    Returns:
-      A string of bytes read. May be shorted than length if EOF was reached
-      first.
-    """
-    self._fd.seek(begin)
-    return self._fd.read(length)
-
-  def has_stream(self):
-    """Does the underlying upload support a streaming interface.
-
-    Streaming means it is an io.IOBase subclass that supports seek, i.e.
-    seekable() returns True.
-
-    Returns:
-      True if the call to stream() will return an instance of a seekable io.Base
-      subclass.
-    """
-    return True
-
-  def stream(self):
-    """A stream interface to the data being uploaded.
-
-    Returns:
-      The returned value is an io.IOBase subclass that supports seek, i.e.
-      seekable() returns True.
-    """
-    return self._fd
-
-  def to_json(self):
-    """This upload type is not serializable."""
-    raise NotImplementedError('MediaIoBaseUpload is not serializable.')
-
-
-class MediaFileUpload(MediaIoBaseUpload):
-  """A MediaUpload for a file.
-
-  Construct a MediaFileUpload and pass as the media_body parameter of the
-  method. For example, if we had a service that allowed uploading images:
-
-
-    media = MediaFileUpload('cow.png', mimetype='image/png',
-      chunksize=1024*1024, resumable=True)
-    farm.animals().insert(
-        id='cow',
-        name='cow.png',
-        media_body=media).execute()
-
-  Depending on the platform you are working on, you may pass -1 as the
-  chunksize, which indicates that the entire file should be uploaded in a single
-  request. If the underlying platform supports streams, such as Python 2.6 or
-  later, then this can be very efficient as it avoids multiple connections, and
-  also avoids loading the entire file into memory before sending it. Note that
-  Google App Engine has a 5MB limit on request size, so you should never set
-  your chunksize larger than 5MB, or to -1.
-  """
-
-  @util.positional(2)
-  def __init__(self, filename, mimetype=None, chunksize=DEFAULT_CHUNK_SIZE,
-               resumable=False):
-    """Constructor.
-
-    Args:
-      filename: string, Name of the file.
-      mimetype: string, Mime-type of the file. If None then a mime-type will be
-        guessed from the file extension.
-      chunksize: int, File will be uploaded in chunks of this many bytes. Only
-        used if resumable=True. Pass in a value of -1 if the file is to be
-        uploaded in a single chunk. Note that Google App Engine has a 5MB limit
-        on request size, so you should never set your chunksize larger than 5MB,
-        or to -1.
-      resumable: bool, True if this is a resumable upload. False means upload
-        in a single request.
-    """
-    self._filename = filename
-    fd = open(self._filename, 'rb')
-    if mimetype is None:
-      (mimetype, encoding) = mimetypes.guess_type(filename)
-    super(MediaFileUpload, self).__init__(fd, mimetype, chunksize=chunksize,
-                                          resumable=resumable)
-
-  def to_json(self):
-    """Creating a JSON representation of an instance of MediaFileUpload.
-
-    Returns:
-       string, a JSON representation of this instance, suitable to pass to
-       from_json().
-    """
-    return self._to_json(strip=['_fd'])
-
-  @staticmethod
-  def from_json(s):
-    d = json.loads(s)
-    return MediaFileUpload(d['_filename'], mimetype=d['_mimetype'],
-                           chunksize=d['_chunksize'], resumable=d['_resumable'])
-
-
-class MediaInMemoryUpload(MediaIoBaseUpload):
-  """MediaUpload for a chunk of bytes.
-
-  DEPRECATED: Use MediaIoBaseUpload with either io.TextIOBase or StringIO for
-  the stream.
-  """
-
-  @util.positional(2)
-  def __init__(self, body, mimetype='application/octet-stream',
-               chunksize=DEFAULT_CHUNK_SIZE, resumable=False):
-    """Create a new MediaInMemoryUpload.
-
-  DEPRECATED: Use MediaIoBaseUpload with either io.TextIOBase or StringIO for
-  the stream.
-
-  Args:
-    body: string, Bytes of body content.
-    mimetype: string, Mime-type of the file or default of
-      'application/octet-stream'.
-    chunksize: int, File will be uploaded in chunks of this many bytes. Only
-      used if resumable=True.
-    resumable: bool, True if this is a resumable upload. False means upload
-      in a single request.
-    """
-    fd = StringIO.StringIO(body)
-    super(MediaInMemoryUpload, self).__init__(fd, mimetype, chunksize=chunksize,
-                                              resumable=resumable)
-
-
-class MediaIoBaseDownload(object):
-  """"Download media resources.
-
-  Note that the Python file object is compatible with io.Base and can be used
-  with this class also.
-
-
-  Example:
-    request = farms.animals().get_media(id='cow')
-    fh = io.FileIO('cow.png', mode='wb')
-    downloader = MediaIoBaseDownload(fh, request, chunksize=1024*1024)
-
-    done = False
-    while done is False:
-      status, done = downloader.next_chunk()
-      if status:
-        print "Download %d%%." % int(status.progress() * 100)
-    print "Download Complete!"
-  """
-
-  @util.positional(3)
-  def __init__(self, fd, request, chunksize=DEFAULT_CHUNK_SIZE):
-    """Constructor.
-
-    Args:
-      fd: io.Base or file object, The stream in which to write the downloaded
-        bytes.
-      request: googleapiclient.http.HttpRequest, the media request to perform in
-        chunks.
-      chunksize: int, File will be downloaded in chunks of this many bytes.
-    """
-    self._fd = fd
-    self._request = request
-    self._uri = request.uri
-    self._chunksize = chunksize
-    self._progress = 0
-    self._total_size = None
-    self._done = False
-
-    # Stubs for testing.
-    self._sleep = time.sleep
-    self._rand = random.random
-
-  @util.positional(1)
-  def next_chunk(self, num_retries=0):
-    """Get the next chunk of the download.
-
-    Args:
-      num_retries: Integer, number of times to retry 500's with randomized
-            exponential backoff. If all retries fail, the raised HttpError
-            represents the last request. If zero (default), we attempt the
-            request only once.
-
-    Returns:
-      (status, done): (MediaDownloadStatus, boolean)
-         The value of 'done' will be True when the media has been fully
-         downloaded.
-
-    Raises:
-      googleapiclient.errors.HttpError if the response was not a 2xx.
-      httplib2.HttpLib2Error if a transport error has occured.
-    """
-    headers = {
-        'range': 'bytes=%d-%d' % (
-            self._progress, self._progress + self._chunksize)
-        }
-    http = self._request.http
-
-    for retry_num in xrange(num_retries + 1):
-      if retry_num > 0:
-        self._sleep(self._rand() * 2**retry_num)
-        logging.warning(
-            'Retry #%d for media download: GET %s, following status: %d'
-            % (retry_num, self._uri, resp.status))
-
-      resp, content = http.request(self._uri, headers=headers)
-      if resp.status < 500:
-        break
-
-    if resp.status in [200, 206]:
-      if 'content-location' in resp and resp['content-location'] != self._uri:
-        self._uri = resp['content-location']
-      self._progress += len(content)
-      self._fd.write(content)
-
-      if 'content-range' in resp:
-        content_range = resp['content-range']
-        length = content_range.rsplit('/', 1)[1]
-        self._total_size = int(length)
-
-      if self._progress == self._total_size:
-        self._done = True
-      return MediaDownloadProgress(self._progress, self._total_size), self._done
-    else:
-      raise HttpError(resp, content, uri=self._uri)
-
-
-class _StreamSlice(object):
-  """Truncated stream.
-
-  Takes a stream and presents a stream that is a slice of the original stream.
-  This is used when uploading media in chunks. In later versions of Python a
-  stream can be passed to httplib in place of the string of data to send. The
-  problem is that httplib just blindly reads to the end of the stream. This
-  wrapper presents a virtual stream that only reads to the end of the chunk.
-  """
-
-  def __init__(self, stream, begin, chunksize):
-    """Constructor.
-
-    Args:
-      stream: (io.Base, file object), the stream to wrap.
-      begin: int, the seek position the chunk begins at.
-      chunksize: int, the size of the chunk.
-    """
-    self._stream = stream
-    self._begin = begin
-    self._chunksize = chunksize
-    self._stream.seek(begin)
-
-  def read(self, n=-1):
-    """Read n bytes.
-
-    Args:
-      n, int, the number of bytes to read.
-
-    Returns:
-      A string of length 'n', or less if EOF is reached.
-    """
-    # The data left available to read sits in [cur, end)
-    cur = self._stream.tell()
-    end = self._begin + self._chunksize
-    if n == -1 or cur + n > end:
-      n = end - cur
-    return self._stream.read(n)
-
-
-class HttpRequest(object):
-  """Encapsulates a single HTTP request."""
-
-  @util.positional(4)
-  def __init__(self, http, postproc, uri,
-               method='GET',
-               body=None,
-               headers=None,
-               methodId=None,
-               resumable=None):
-    """Constructor for an HttpRequest.
-
-    Args:
-      http: httplib2.Http, the transport object to use to make a request
-      postproc: callable, called on the HTTP response and content to transform
-                it into a data object before returning, or raising an exception
-                on an error.
-      uri: string, the absolute URI to send the request to
-      method: string, the HTTP method to use
-      body: string, the request body of the HTTP request,
-      headers: dict, the HTTP request headers
-      methodId: string, a unique identifier for the API method being called.
-      resumable: MediaUpload, None if this is not a resumbale request.
-    """
-    self.uri = uri
-    self.method = method
-    self.body = body
-    self.headers = headers or {}
-    self.methodId = methodId
-    self.http = http
-    self.postproc = postproc
-    self.resumable = resumable
-    self.response_callbacks = []
-    self._in_error_state = False
-
-    # Pull the multipart boundary out of the content-type header.
-    major, minor, params = mimeparse.parse_mime_type(
-        headers.get('content-type', 'application/json'))
-
-    # The size of the non-media part of the request.
-    self.body_size = len(self.body or '')
-
-    # The resumable URI to send chunks to.
-    self.resumable_uri = None
-
-    # The bytes that have been uploaded.
-    self.resumable_progress = 0
-
-    # Stubs for testing.
-    self._rand = random.random
-    self._sleep = time.sleep
-
-  @util.positional(1)
-  def execute(self, http=None, num_retries=0):
-    """Execute the request.
-
-    Args:
-      http: httplib2.Http, an http object to be used in place of the
-            one the HttpRequest request object was constructed with.
-      num_retries: Integer, number of times to retry 500's with randomized
-            exponential backoff. If all retries fail, the raised HttpError
-            represents the last request. If zero (default), we attempt the
-            request only once.
-
-    Returns:
-      A deserialized object model of the response body as determined
-      by the postproc.
-
-    Raises:
-      googleapiclient.errors.HttpError if the response was not a 2xx.
-      httplib2.HttpLib2Error if a transport error has occured.
-    """
-    if http is None:
-      http = self.http
-
-    if self.resumable:
-      body = None
-      while body is None:
-        _, body = self.next_chunk(http=http, num_retries=num_retries)
-      return body
-
-    # Non-resumable case.
-
-    if 'content-length' not in self.headers:
-      self.headers['content-length'] = str(self.body_size)
-    # If the request URI is too long then turn it into a POST request.
-    if len(self.uri) > MAX_URI_LENGTH and self.method == 'GET':
-      self.method = 'POST'
-      self.headers['x-http-method-override'] = 'GET'
-      self.headers['content-type'] = 'application/x-www-form-urlencoded'
-      parsed = urlparse.urlparse(self.uri)
-      self.uri = urlparse.urlunparse(
-          (parsed.scheme, parsed.netloc, parsed.path, parsed.params, None,
-           None)
-          )
-      self.body = parsed.query
-      self.headers['content-length'] = str(len(self.body))
-
-    # Handle retries for server-side errors.
-    for retry_num in xrange(num_retries + 1):
-      if retry_num > 0:
-        self._sleep(self._rand() * 2**retry_num)
-        logging.warning('Retry #%d for request: %s %s, following status: %d'
-                        % (retry_num, self.method, self.uri, resp.status))
-
-      resp, content = http.request(str(self.uri), method=str(self.method),
-                                   body=self.body, headers=self.headers)
-      if resp.status < 500:
-        break
-
-    for callback in self.response_callbacks:
-      callback(resp)
-    if resp.status >= 300:
-      raise HttpError(resp, content, uri=self.uri)
-    return self.postproc(resp, content)
-
-  @util.positional(2)
-  def add_response_callback(self, cb):
-    """add_response_headers_callback
-
-    Args:
-      cb: Callback to be called on receiving the response headers, of signature:
-
-      def cb(resp):
-        # Where resp is an instance of httplib2.Response
-    """
-    self.response_callbacks.append(cb)
-
-  @util.positional(1)
-  def next_chunk(self, http=None, num_retries=0):
-    """Execute the next step of a resumable upload.
-
-    Can only be used if the method being executed supports media uploads and
-    the MediaUpload object passed in was flagged as using resumable upload.
-
-    Example:
-
-      media = MediaFileUpload('cow.png', mimetype='image/png',
-                              chunksize=1000, resumable=True)
-      request = farm.animals().insert(
-          id='cow',
-          name='cow.png',
-          media_body=media)
-
-      response = None
-      while response is None:
-        status, response = request.next_chunk()
-        if status:
-          print "Upload %d%% complete." % int(status.progress() * 100)
-
-
-    Args:
-      http: httplib2.Http, an http object to be used in place of the
-            one the HttpRequest request object was constructed with.
-      num_retries: Integer, number of times to retry 500's with randomized
-            exponential backoff. If all retries fail, the raised HttpError
-            represents the last request. If zero (default), we attempt the
-            request only once.
-
-    Returns:
-      (status, body): (ResumableMediaStatus, object)
-         The body will be None until the resumable media is fully uploaded.
-
-    Raises:
-      googleapiclient.errors.HttpError if the response was not a 2xx.
-      httplib2.HttpLib2Error if a transport error has occured.
-    """
-    if http is None:
-      http = self.http
-
-    if self.resumable.size() is None:
-      size = '*'
-    else:
-      size = str(self.resumable.size())
-
-    if self.resumable_uri is None:
-      start_headers = copy.copy(self.headers)
-      start_headers['X-Upload-Content-Type'] = self.resumable.mimetype()
-      if size != '*':
-        start_headers['X-Upload-Content-Length'] = size
-      start_headers['content-length'] = str(self.body_size)
-
-      for retry_num in xrange(num_retries + 1):
-        if retry_num > 0:
-          self._sleep(self._rand() * 2**retry_num)
-          logging.warning(
-              'Retry #%d for resumable URI request: %s %s, following status: %d'
-              % (retry_num, self.method, self.uri, resp.status))
-
-        resp, content = http.request(self.uri, method=self.method,
-                                     body=self.body,
-                                     headers=start_headers)
-        if resp.status < 500:
-          break
-
-      if resp.status == 200 and 'location' in resp:
-        self.resumable_uri = resp['location']
-      else:
-        raise ResumableUploadError(resp, content)
-    elif self._in_error_state:
-      # If we are in an error state then query the server for current state of
-      # the upload by sending an empty PUT and reading the 'range' header in
-      # the response.
-      headers = {
-          'Content-Range': 'bytes */%s' % size,
-          'content-length': '0'
-          }
-      resp, content = http.request(self.resumable_uri, 'PUT',
-                                   headers=headers)
-      status, body = self._process_response(resp, content)
-      if body:
-        # The upload was complete.
-        return (status, body)
-
-    # The httplib.request method can take streams for the body parameter, but
-    # only in Python 2.6 or later. If a stream is available under those
-    # conditions then use it as the body argument.
-    if self.resumable.has_stream() and sys.version_info[1] >= 6:
-      data = self.resumable.stream()
-      if self.resumable.chunksize() == -1:
-        data.seek(self.resumable_progress)
-        chunk_end = self.resumable.size() - self.resumable_progress - 1
-      else:
-        # Doing chunking with a stream, so wrap a slice of the stream.
-        data = _StreamSlice(data, self.resumable_progress,
-                            self.resumable.chunksize())
-        chunk_end = min(
-            self.resumable_progress + self.resumable.chunksize() - 1,
-            self.resumable.size() - 1)
-    else:
-      data = self.resumable.getbytes(
-          self.resumable_progress, self.resumable.chunksize())
-
-      # A short read implies that we are at EOF, so finish the upload.
-      if len(data) < self.resumable.chunksize():
-        size = str(self.resumable_progress + len(data))
-
-      chunk_end = self.resumable_progress + len(data) - 1
-
-    headers = {
-        'Content-Range': 'bytes %d-%d/%s' % (
-            self.resumable_progress, chunk_end, size),
-        # Must set the content-length header here because httplib can't
-        # calculate the size when working with _StreamSlice.
-        'Content-Length': str(chunk_end - self.resumable_progress + 1)
-        }
-
-    for retry_num in xrange(num_retries + 1):
-      if retry_num > 0:
-        self._sleep(self._rand() * 2**retry_num)
-        logging.warning(
-            'Retry #%d for media upload: %s %s, following status: %d'
-            % (retry_num, self.method, self.uri, resp.status))
-
-      try:
-        resp, content = http.request(self.resumable_uri, method='PUT',
-                                     body=data,
-                                     headers=headers)
-      except:
-        self._in_error_state = True
-        raise
-      if resp.status < 500:
-        break
-
-    return self._process_response(resp, content)
-
-  def _process_response(self, resp, content):
-    """Process the response from a single chunk upload.
-
-    Args:
-      resp: httplib2.Response, the response object.
-      content: string, the content of the response.
-
-    Returns:
-      (status, body): (ResumableMediaStatus, object)
-         The body will be None until the resumable media is fully uploaded.
-
-    Raises:
-      googleapiclient.errors.HttpError if the response was not a 2xx or a 308.
-    """
-    if resp.status in [200, 201]:
-      self._in_error_state = False
-      return None, self.postproc(resp, content)
-    elif resp.status == 308:
-      self._in_error_state = False
-      # A "308 Resume Incomplete" indicates we are not done.
-      self.resumable_progress = int(resp['range'].split('-')[1]) + 1
-      if 'location' in resp:
-        self.resumable_uri = resp['location']
-    else:
-      self._in_error_state = True
-      raise HttpError(resp, content, uri=self.uri)
-
-    return (MediaUploadProgress(self.resumable_progress, self.resumable.size()),
-            None)
-
-  def to_json(self):
-    """Returns a JSON representation of the HttpRequest."""
-    d = copy.copy(self.__dict__)
-    if d['resumable'] is not None:
-      d['resumable'] = self.resumable.to_json()
-    del d['http']
-    del d['postproc']
-    del d['_sleep']
-    del d['_rand']
-
-    return json.dumps(d)
-
-  @staticmethod
-  def from_json(s, http, postproc):
-    """Returns an HttpRequest populated with info from a JSON object."""
-    d = json.loads(s)
-    if d['resumable'] is not None:
-      d['resumable'] = MediaUpload.new_from_json(d['resumable'])
-    return HttpRequest(
-        http,
-        postproc,
-        uri=d['uri'],
-        method=d['method'],
-        body=d['body'],
-        headers=d['headers'],
-        methodId=d['methodId'],
-        resumable=d['resumable'])
-
-
-class BatchHttpRequest(object):
-  """Batches multiple HttpRequest objects into a single HTTP request.
-
-  Example:
-    from googleapiclient.http import BatchHttpRequest
-
-    def list_animals(request_id, response, exception):
-      \"\"\"Do something with the animals list response.\"\"\"
-      if exception is not None:
-        # Do something with the exception.
-        pass
-      else:
-        # Do something with the response.
-        pass
-
-    def list_farmers(request_id, response, exception):
-      \"\"\"Do something with the farmers list response.\"\"\"
-      if exception is not None:
-        # Do something with the exception.
-        pass
-      else:
-        # Do something with the response.
-        pass
-
-    service = build('farm', 'v2')
-
-    batch = BatchHttpRequest()
-
-    batch.add(service.animals().list(), list_animals)
-    batch.add(service.farmers().list(), list_farmers)
-    batch.execute(http=http)
-  """
-
-  @util.positional(1)
-  def __init__(self, callback=None, batch_uri=None):
-    """Constructor for a BatchHttpRequest.
-
-    Args:
-      callback: callable, A callback to be called for each response, of the
-        form callback(id, response, exception). The first parameter is the
-        request id, and the second is the deserialized response object. The
-        third is an googleapiclient.errors.HttpError exception object if an HTTP error
-        occurred while processing the request, or None if no error occurred.
-      batch_uri: string, URI to send batch requests to.
-    """
-    if batch_uri is None:
-      batch_uri = 'https://www.googleapis.com/batch'
-    self._batch_uri = batch_uri
-
-    # Global callback to be called for each individual response in the batch.
-    self._callback = callback
-
-    # A map from id to request.
-    self._requests = {}
-
-    # A map from id to callback.
-    self._callbacks = {}
-
-    # List of request ids, in the order in which they were added.
-    self._order = []
-
-    # The last auto generated id.
-    self._last_auto_id = 0
-
-    # Unique ID on which to base the Content-ID headers.
-    self._base_id = None
-
-    # A map from request id to (httplib2.Response, content) response pairs
-    self._responses = {}
-
-    # A map of id(Credentials) that have been refreshed.
-    self._refreshed_credentials = {}
-
-  def _refresh_and_apply_credentials(self, request, http):
-    """Refresh the credentials and apply to the request.
-
-    Args:
-      request: HttpRequest, the request.
-      http: httplib2.Http, the global http object for the batch.
-    """
-    # For the credentials to refresh, but only once per refresh_token
-    # If there is no http per the request then refresh the http passed in
-    # via execute()
-    creds = None
-    if request.http is not None and hasattr(request.http.request,
-        'credentials'):
-      creds = request.http.request.credentials
-    elif http is not None and hasattr(http.request, 'credentials'):
-      creds = http.request.credentials
-    if creds is not None:
-      if id(creds) not in self._refreshed_credentials:
-        creds.refresh(http)
-        self._refreshed_credentials[id(creds)] = 1
-
-    # Only apply the credentials if we are using the http object passed in,
-    # otherwise apply() will get called during _serialize_request().
-    if request.http is None or not hasattr(request.http.request,
-        'credentials'):
-      creds.apply(request.headers)
-
-  def _id_to_header(self, id_):
-    """Convert an id to a Content-ID header value.
-
-    Args:
-      id_: string, identifier of individual request.
-
-    Returns:
-      A Content-ID header with the id_ encoded into it. A UUID is prepended to
-      the value because Content-ID headers are supposed to be universally
-      unique.
-    """
-    if self._base_id is None:
-      self._base_id = uuid.uuid4()
-
-    return '<%s+%s>' % (self._base_id, urllib.quote(id_))
-
-  def _header_to_id(self, header):
-    """Convert a Content-ID header value to an id.
-
-    Presumes the Content-ID header conforms to the format that _id_to_header()
-    returns.
-
-    Args:
-      header: string, Content-ID header value.
-
-    Returns:
-      The extracted id value.
-
-    Raises:
-      BatchError if the header is not in the expected format.
-    """
-    if header[0] != '<' or header[-1] != '>':
-      raise BatchError("Invalid value for Content-ID: %s" % header)
-    if '+' not in header:
-      raise BatchError("Invalid value for Content-ID: %s" % header)
-    base, id_ = header[1:-1].rsplit('+', 1)
-
-    return urllib.unquote(id_)
-
-  def _serialize_request(self, request):
-    """Convert an HttpRequest object into a string.
-
-    Args:
-      request: HttpRequest, the request to serialize.
-
-    Returns:
-      The request as a string in application/http format.
-    """
-    # Construct status line
-    parsed = urlparse.urlparse(request.uri)
-    request_line = urlparse.urlunparse(
-        (None, None, parsed.path, parsed.params, parsed.query, None)
-        )
-    status_line = request.method + ' ' + request_line + ' HTTP/1.1\n'
-    major, minor = request.headers.get('content-type', 'application/json').split('/')
-    msg = MIMENonMultipart(major, minor)
-    headers = request.headers.copy()
-
-    if request.http is not None and hasattr(request.http.request,
-        'credentials'):
-      request.http.request.credentials.apply(headers)
-
-    # MIMENonMultipart adds its own Content-Type header.
-    if 'content-type' in headers:
-      del headers['content-type']
-
-    for key, value in headers.iteritems():
-      msg[key] = value
-    msg['Host'] = parsed.netloc
-    msg.set_unixfrom(None)
-
-    if request.body is not None:
-      msg.set_payload(request.body)
-      msg['content-length'] = str(len(request.body))
-
-    # Serialize the mime message.
-    fp = StringIO.StringIO()
-    # maxheaderlen=0 means don't line wrap headers.
-    g = Generator(fp, maxheaderlen=0)
-    g.flatten(msg, unixfrom=False)
-    body = fp.getvalue()
-
-    # Strip off the \n\n that the MIME lib tacks onto the end of the payload.
-    if request.body is None:
-      body = body[:-2]
-
-    return status_line.encode('utf-8') + body
-
-  def _deserialize_response(self, payload):
-    """Convert string into httplib2 response and content.
-
-    Args:
-      payload: string, headers and body as a string.
-
-    Returns:
-      A pair (resp, content), such as would be returned from httplib2.request.
-    """
-    # Strip off the status line
-    status_line, payload = payload.split('\n', 1)
-    protocol, status, reason = status_line.split(' ', 2)
-
-    # Parse the rest of the response
-    parser = FeedParser()
-    parser.feed(payload)
-    msg = parser.close()
-    msg['status'] = status
-
-    # Create httplib2.Response from the parsed headers.
-    resp = httplib2.Response(msg)
-    resp.reason = reason
-    resp.version = int(protocol.split('/', 1)[1].replace('.', ''))
-
-    content = payload.split('\r\n\r\n', 1)[1]
-
-    return resp, content
-
-  def _new_id(self):
-    """Create a new id.
-
-    Auto incrementing number that avoids conflicts with ids already used.
-
-    Returns:
-       string, a new unique id.
-    """
-    self._last_auto_id += 1
-    while str(self._last_auto_id) in self._requests:
-      self._last_auto_id += 1
-    return str(self._last_auto_id)
-
-  @util.positional(2)
-  def add(self, request, callback=None, request_id=None):
-    """Add a new request.
-
-    Every callback added will be paired with a unique id, the request_id. That
-    unique id will be passed back to the callback when the response comes back
-    from the server. The default behavior is to have the library generate it's
-    own unique id. If the caller passes in a request_id then they must ensure
-    uniqueness for each request_id, and if they are not an exception is
-    raised. Callers should either supply all request_ids or nevery supply a
-    request id, to avoid such an error.
-
-    Args:
-      request: HttpRequest, Request to add to the batch.
-      callback: callable, A callback to be called for this response, of the
-        form callback(id, response, exception). The first parameter is the
-        request id, and the second is the deserialized response object. The
-        third is an googleapiclient.errors.HttpError exception object if an HTTP error
-        occurred while processing the request, or None if no errors occurred.
-      request_id: string, A unique id for the request. The id will be passed to
-        the callback with the response.
-
-    Returns:
-      None
-
-    Raises:
-      BatchError if a media request is added to a batch.
-      KeyError is the request_id is not unique.
-    """
-    if request_id is None:
-      request_id = self._new_id()
-    if request.resumable is not None:
-      raise BatchError("Media requests cannot be used in a batch request.")
-    if request_id in self._requests:
-      raise KeyError("A request with this ID already exists: %s" % request_id)
-    self._requests[request_id] = request
-    self._callbacks[request_id] = callback
-    self._order.append(request_id)
-
-  def _execute(self, http, order, requests):
-    """Serialize batch request, send to server, process response.
-
-    Args:
-      http: httplib2.Http, an http object to be used to make the request with.
-      order: list, list of request ids in the order they were added to the
-        batch.
-      request: list, list of request objects to send.
-
-    Raises:
-      httplib2.HttpLib2Error if a transport error has occured.
-      googleapiclient.errors.BatchError if the response is the wrong format.
-    """
-    message = MIMEMultipart('mixed')
-    # Message should not write out it's own headers.
-    setattr(message, '_write_headers', lambda self: None)
-
-    # Add all the individual requests.
-    for request_id in order:
-      request = requests[request_id]
-
-      msg = MIMENonMultipart('application', 'http')
-      msg['Content-Transfer-Encoding'] = 'binary'
-      msg['Content-ID'] = self._id_to_header(request_id)
-
-      body = self._serialize_request(request)
-      msg.set_payload(body)
-      message.attach(msg)
-
-    # encode the body: note that we can't use `as_string`, because
-    # it plays games with `From ` lines.
-    fp = StringIO.StringIO()
-    g = Generator(fp, mangle_from_=False)
-    g.flatten(message, unixfrom=False)
-    body = fp.getvalue()
-
-    headers = {}
-    headers['content-type'] = ('multipart/mixed; '
-                               'boundary="%s"') % message.get_boundary()
-
-    resp, content = http.request(self._batch_uri, method='POST', body=body,
-                                 headers=headers)
-
-    if resp.status >= 300:
-      raise HttpError(resp, content, uri=self._batch_uri)
-
-    # Now break out the individual responses and store each one.
-    boundary, _ = content.split(None, 1)
-
-    # Prepend with a content-type header so FeedParser can handle it.
-    header = 'content-type: %s\r\n\r\n' % resp['content-type']
-    for_parser = header + content
-
-    parser = FeedParser()
-    parser.feed(for_parser)
-    mime_response = parser.close()
-
-    if not mime_response.is_multipart():
-      raise BatchError("Response not in multipart/mixed format.", resp=resp,
-                       content=content)
-
-    for part in mime_response.get_payload():
-      request_id = self._header_to_id(part['Content-ID'])
-      response, content = self._deserialize_response(part.get_payload())
-      self._responses[request_id] = (response, content)
-
-  @util.positional(1)
-  def execute(self, http=None):
-    """Execute all the requests as a single batched HTTP request.
-
-    Args:
-      http: httplib2.Http, an http object to be used in place of the one the
-        HttpRequest request object was constructed with. If one isn't supplied
-        then use a http object from the requests in this batch.
-
-    Returns:
-      None
-
-    Raises:
-      httplib2.HttpLib2Error if a transport error has occured.
-      googleapiclient.errors.BatchError if the response is the wrong format.
-    """
-
-    # If http is not supplied use the first valid one given in the requests.
-    if http is None:
-      for request_id in self._order:
-        request = self._requests[request_id]
-        if request is not None:
-          http = request.http
-          break
-
-    if http is None:
-      raise ValueError("Missing a valid http object.")
-
-    self._execute(http, self._order, self._requests)
-
-    # Loop over all the requests and check for 401s. For each 401 request the
-    # credentials should be refreshed and then sent again in a separate batch.
-    redo_requests = {}
-    redo_order = []
-
-    for request_id in self._order:
-      resp, content = self._responses[request_id]
-      if resp['status'] == '401':
-        redo_order.append(request_id)
-        request = self._requests[request_id]
-        self._refresh_and_apply_credentials(request, http)
-        redo_requests[request_id] = request
-
-    if redo_requests:
-      self._execute(http, redo_order, redo_requests)
-
-    # Now process all callbacks that are erroring, and raise an exception for
-    # ones that return a non-2xx response? Or add extra parameter to callback
-    # that contains an HttpError?
-
-    for request_id in self._order:
-      resp, content = self._responses[request_id]
-
-      request = self._requests[request_id]
-      callback = self._callbacks[request_id]
-
-      response = None
-      exception = None
-      try:
-        if resp.status >= 300:
-          raise HttpError(resp, content, uri=request.uri)
-        response = request.postproc(resp, content)
-      except HttpError, e:
-        exception = e
-
-      if callback is not None:
-        callback(request_id, response, exception)
-      if self._callback is not None:
-        self._callback(request_id, response, exception)
-
-
-class HttpRequestMock(object):
-  """Mock of HttpRequest.
-
-  Do not construct directly, instead use RequestMockBuilder.
-  """
-
-  def __init__(self, resp, content, postproc):
-    """Constructor for HttpRequestMock
-
-    Args:
-      resp: httplib2.Response, the response to emulate coming from the request
-      content: string, the response body
-      postproc: callable, the post processing function usually supplied by
-                the model class. See model.JsonModel.response() as an example.
-    """
-    self.resp = resp
-    self.content = content
-    self.postproc = postproc
-    if resp is None:
-      self.resp = httplib2.Response({'status': 200, 'reason': 'OK'})
-    if 'reason' in self.resp:
-      self.resp.reason = self.resp['reason']
-
-  def execute(self, http=None):
-    """Execute the request.
-
-    Same behavior as HttpRequest.execute(), but the response is
-    mocked and not really from an HTTP request/response.
-    """
-    return self.postproc(self.resp, self.content)
-
-
-class RequestMockBuilder(object):
-  """A simple mock of HttpRequest
-
-    Pass in a dictionary to the constructor that maps request methodIds to
-    tuples of (httplib2.Response, content, opt_expected_body) that should be
-    returned when that method is called. None may also be passed in for the
-    httplib2.Response, in which case a 200 OK response will be generated.
-    If an opt_expected_body (str or dict) is provided, it will be compared to
-    the body and UnexpectedBodyError will be raised on inequality.
-
-    Example:
-      response = '{"data": {"id": "tag:google.c...'
-      requestBuilder = RequestMockBuilder(
-        {
-          'plus.activities.get': (None, response),
-        }
-      )
-      googleapiclient.discovery.build("plus", "v1", requestBuilder=requestBuilder)
-
-    Methods that you do not supply a response for will return a
-    200 OK with an empty string as the response content or raise an excpetion
-    if check_unexpected is set to True. The methodId is taken from the rpcName
-    in the discovery document.
-
-    For more details see the project wiki.
-  """
-
-  def __init__(self, responses, check_unexpected=False):
-    """Constructor for RequestMockBuilder
-
-    The constructed object should be a callable object
-    that can replace the class HttpResponse.
-
-    responses - A dictionary that maps methodIds into tuples
-                of (httplib2.Response, content). The methodId
-                comes from the 'rpcName' field in the discovery
-                document.
-    check_unexpected - A boolean setting whether or not UnexpectedMethodError
-                       should be raised on unsupplied method.
-    """
-    self.responses = responses
-    self.check_unexpected = check_unexpected
-
-  def __call__(self, http, postproc, uri, method='GET', body=None,
-               headers=None, methodId=None, resumable=None):
-    """Implements the callable interface that discovery.build() expects
-    of requestBuilder, which is to build an object compatible with
-    HttpRequest.execute(). See that method for the description of the
-    parameters and the expected response.
-    """
-    if methodId in self.responses:
-      response = self.responses[methodId]
-      resp, content = response[:2]
-      if len(response) > 2:
-        # Test the body against the supplied expected_body.
-        expected_body = response[2]
-        if bool(expected_body) != bool(body):
-          # Not expecting a body and provided one
-          # or expecting a body and not provided one.
-          raise UnexpectedBodyError(expected_body, body)
-        if isinstance(expected_body, str):
-          expected_body = json.loads(expected_body)
-        body = json.loads(body)
-        if body != expected_body:
-          raise UnexpectedBodyError(expected_body, body)
-      return HttpRequestMock(resp, content, postproc)
-    elif self.check_unexpected:
-      raise UnexpectedMethodError(methodId=methodId)
-    else:
-      model = JsonModel(False)
-      return HttpRequestMock(None, '{}', model.response)
-
-
-class HttpMock(object):
-  """Mock of httplib2.Http"""
-
-  def __init__(self, filename=None, headers=None):
-    """
-    Args:
-      filename: string, absolute filename to read response from
-      headers: dict, header to return with response
-    """
-    if headers is None:
-      headers = {'status': '200 OK'}
-    if filename:
-      f = file(filename, 'r')
-      self.data = f.read()
-      f.close()
-    else:
-      self.data = None
-    self.response_headers = headers
-    self.headers = None
-    self.uri = None
-    self.method = None
-    self.body = None
-    self.headers = None
-
-
-  def request(self, uri,
-              method='GET',
-              body=None,
-              headers=None,
-              redirections=1,
-              connection_type=None):
-    self.uri = uri
-    self.method = method
-    self.body = body
-    self.headers = headers
-    return httplib2.Response(self.response_headers), self.data
-
-
-class HttpMockSequence(object):
-  """Mock of httplib2.Http
-
-  Mocks a sequence of calls to request returning different responses for each
-  call. Create an instance initialized with the desired response headers
-  and content and then use as if an httplib2.Http instance.
-
-    http = HttpMockSequence([
-      ({'status': '401'}, ''),
-      ({'status': '200'}, '{"access_token":"1/3w","expires_in":3600}'),
-      ({'status': '200'}, 'echo_request_headers'),
-      ])
-    resp, content = http.request("http://examples.com")
-
-  There are special values you can pass in for content to trigger
-  behavours that are helpful in testing.
-
-  'echo_request_headers' means return the request headers in the response body
-  'echo_request_headers_as_json' means return the request headers in
-     the response body
-  'echo_request_body' means return the request body in the response body
-  'echo_request_uri' means return the request uri in the response body
-  """
-
-  def __init__(self, iterable):
-    """
-    Args:
-      iterable: iterable, a sequence of pairs of (headers, body)
-    """
-    self._iterable = iterable
-    self.follow_redirects = True
-
-  def request(self, uri,
-              method='GET',
-              body=None,
-              headers=None,
-              redirections=1,
-              connection_type=None):
-    resp, content = self._iterable.pop(0)
-    if content == 'echo_request_headers':
-      content = headers
-    elif content == 'echo_request_headers_as_json':
-      content = json.dumps(headers)
-    elif content == 'echo_request_body':
-      if hasattr(body, 'read'):
-        content = body.read()
-      else:
-        content = body
-    elif content == 'echo_request_uri':
-      content = uri
-    return httplib2.Response(resp), content
-
-
-def set_user_agent(http, user_agent):
-  """Set the user-agent on every request.
-
-  Args:
-     http - An instance of httplib2.Http
-         or something that acts like it.
-     user_agent: string, the value for the user-agent header.
-
-  Returns:
-     A modified instance of http that was passed in.
-
-  Example:
-
-    h = httplib2.Http()
-    h = set_user_agent(h, "my-app-name/6.0")
-
-  Most of the time the user-agent will be set doing auth, this is for the rare
-  cases where you are accessing an unauthenticated endpoint.
-  """
-  request_orig = http.request
-
-  # The closure that will replace 'httplib2.Http.request'.
-  def new_request(uri, method='GET', body=None, headers=None,
-                  redirections=httplib2.DEFAULT_MAX_REDIRECTS,
-                  connection_type=None):
-    """Modify the request headers to add the user-agent."""
-    if headers is None:
-      headers = {}
-    if 'user-agent' in headers:
-      headers['user-agent'] = user_agent + ' ' + headers['user-agent']
-    else:
-      headers['user-agent'] = user_agent
-    resp, content = request_orig(uri, method, body, headers,
-                        redirections, connection_type)
-    return resp, content
-
-  http.request = new_request
-  return http
-
-
-def tunnel_patch(http):
-  """Tunnel PATCH requests over POST.
-  Args:
-     http - An instance of httplib2.Http
-         or something that acts like it.
-
-  Returns:
-     A modified instance of http that was passed in.
-
-  Example:
-
-    h = httplib2.Http()
-    h = tunnel_patch(h, "my-app-name/6.0")
-
-  Useful if you are running on a platform that doesn't support PATCH.
-  Apply this last if you are using OAuth 1.0, as changing the method
-  will result in a different signature.
-  """
-  request_orig = http.request
-
-  # The closure that will replace 'httplib2.Http.request'.
-  def new_request(uri, method='GET', body=None, headers=None,
-                  redirections=httplib2.DEFAULT_MAX_REDIRECTS,
-                  connection_type=None):
-    """Modify the request headers to add the user-agent."""
-    if headers is None:
-      headers = {}
-    if method == 'PATCH':
-      if 'oauth_token' in headers.get('authorization', ''):
-        logging.warning(
-            'OAuth 1.0 request made with Credentials after tunnel_patch.')
-      headers['x-http-method-override'] = "PATCH"
-      method = 'POST'
-    resp, content = request_orig(uri, method, body, headers,
-                        redirections, connection_type)
-    return resp, content
-
-  http.request = new_request
-  return http
diff --git a/third_party/google_api_python_client/googleapiclient/mimeparse.py b/third_party/google_api_python_client/googleapiclient/mimeparse.py
deleted file mode 100644
index 8038af1..0000000
--- a/third_party/google_api_python_client/googleapiclient/mimeparse.py
+++ /dev/null
@@ -1,172 +0,0 @@
-# Copyright 2014 Joe Gregorio
-#
-# Licensed under the MIT License
-
-"""MIME-Type Parser
-
-This module provides basic functions for handling mime-types. It can handle
-matching mime-types against a list of media-ranges. See section 14.1 of the
-HTTP specification [RFC 2616] for a complete explanation.
-
-   http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
-
-Contents:
- - parse_mime_type():   Parses a mime-type into its component parts.
- - parse_media_range(): Media-ranges are mime-types with wild-cards and a 'q'
-                          quality parameter.
- - quality():           Determines the quality ('q') of a mime-type when
-                          compared against a list of media-ranges.
- - quality_parsed():    Just like quality() except the second parameter must be
-                          pre-parsed.
- - best_match():        Choose the mime-type with the highest quality ('q')
-                          from a list of candidates.
-"""
-
-__version__ = '0.1.3'
-__author__ = 'Joe Gregorio'
-__email__ = 'joe@bitworking.org'
-__license__ = 'MIT License'
-__credits__ = ''
-
-
-def parse_mime_type(mime_type):
-    """Parses a mime-type into its component parts.
-
-    Carves up a mime-type and returns a tuple of the (type, subtype, params)
-    where 'params' is a dictionary of all the parameters for the media range.
-    For example, the media range 'application/xhtml;q=0.5' would get parsed
-    into:
-
-       ('application', 'xhtml', {'q', '0.5'})
-       """
-    parts = mime_type.split(';')
-    params = dict([tuple([s.strip() for s in param.split('=', 1)])\
-            for param in parts[1:]
-                  ])
-    full_type = parts[0].strip()
-    # Java URLConnection class sends an Accept header that includes a
-    # single '*'. Turn it into a legal wildcard.
-    if full_type == '*':
-        full_type = '*/*'
-    (type, subtype) = full_type.split('/')
-
-    return (type.strip(), subtype.strip(), params)
-
-
-def parse_media_range(range):
-    """Parse a media-range into its component parts.
-
-    Carves up a media range and returns a tuple of the (type, subtype,
-    params) where 'params' is a dictionary of all the parameters for the media
-    range.  For example, the media range 'application/*;q=0.5' would get parsed
-    into:
-
-       ('application', '*', {'q', '0.5'})
-
-    In addition this function also guarantees that there is a value for 'q'
-    in the params dictionary, filling it in with a proper default if
-    necessary.
-    """
-    (type, subtype, params) = parse_mime_type(range)
-    if not params.has_key('q') or not params['q'] or \
-            not float(params['q']) or float(params['q']) > 1\
-            or float(params['q']) < 0:
-        params['q'] = '1'
-
-    return (type, subtype, params)
-
-
-def fitness_and_quality_parsed(mime_type, parsed_ranges):
-    """Find the best match for a mime-type amongst parsed media-ranges.
-
-    Find the best match for a given mime-type against a list of media_ranges
-    that have already been parsed by parse_media_range(). Returns a tuple of
-    the fitness value and the value of the 'q' quality parameter of the best
-    match, or (-1, 0) if no match was found. Just as for quality_parsed(),
-    'parsed_ranges' must be a list of parsed media ranges.
-    """
-    best_fitness = -1
-    best_fit_q = 0
-    (target_type, target_subtype, target_params) =\
-            parse_media_range(mime_type)
-    for (type, subtype, params) in parsed_ranges:
-        type_match = (type == target_type or\
-                      type == '*' or\
-                      target_type == '*')
-        subtype_match = (subtype == target_subtype or\
-                         subtype == '*' or\
-                         target_subtype == '*')
-        if type_match and subtype_match:
-            param_matches = reduce(lambda x, y: x + y, [1 for (key, value) in \
-                    target_params.iteritems() if key != 'q' and \
-                    params.has_key(key) and value == params[key]], 0)
-            fitness = (type == target_type) and 100 or 0
-            fitness += (subtype == target_subtype) and 10 or 0
-            fitness += param_matches
-            if fitness > best_fitness:
-                best_fitness = fitness
-                best_fit_q = params['q']
-
-    return best_fitness, float(best_fit_q)
-
-
-def quality_parsed(mime_type, parsed_ranges):
-    """Find the best match for a mime-type amongst parsed media-ranges.
-
-    Find the best match for a given mime-type against a list of media_ranges
-    that have already been parsed by parse_media_range(). Returns the 'q'
-    quality parameter of the best match, 0 if no match was found. This function
-    bahaves the same as quality() except that 'parsed_ranges' must be a list of
-    parsed media ranges.
-    """
-
-    return fitness_and_quality_parsed(mime_type, parsed_ranges)[1]
-
-
-def quality(mime_type, ranges):
-    """Return the quality ('q') of a mime-type against a list of media-ranges.
-
-    Returns the quality 'q' of a mime-type when compared against the
-    media-ranges in ranges. For example:
-
-    >>> quality('text/html','text/*;q=0.3, text/html;q=0.7,
-                  text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5')
-    0.7
-
-    """
-    parsed_ranges = [parse_media_range(r) for r in ranges.split(',')]
-
-    return quality_parsed(mime_type, parsed_ranges)
-
-
-def best_match(supported, header):
-    """Return mime-type with the highest quality ('q') from list of candidates.
-
-    Takes a list of supported mime-types and finds the best match for all the
-    media-ranges listed in header. The value of header must be a string that
-    conforms to the format of the HTTP Accept: header. The value of 'supported'
-    is a list of mime-types. The list of supported mime-types should be sorted
-    in order of increasing desirability, in case of a situation where there is
-    a tie.
-
-    >>> best_match(['application/xbel+xml', 'text/xml'],
-                   'text/*;q=0.5,*/*; q=0.1')
-    'text/xml'
-    """
-    split_header = _filter_blank(header.split(','))
-    parsed_header = [parse_media_range(r) for r in split_header]
-    weighted_matches = []
-    pos = 0
-    for mime_type in supported:
-        weighted_matches.append((fitness_and_quality_parsed(mime_type,
-                                 parsed_header), pos, mime_type))
-        pos += 1
-    weighted_matches.sort()
-
-    return weighted_matches[-1][0][1] and weighted_matches[-1][2] or ''
-
-
-def _filter_blank(i):
-    for s in i:
-        if s.strip():
-            yield s
diff --git a/third_party/google_api_python_client/googleapiclient/model.py b/third_party/google_api_python_client/googleapiclient/model.py
deleted file mode 100644
index 0f0172c..0000000
--- a/third_party/google_api_python_client/googleapiclient/model.py
+++ /dev/null
@@ -1,383 +0,0 @@
-#!/usr/bin/python2.4
-#
-# Copyright 2014 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Model objects for requests and responses.
-
-Each API may support one or more serializations, such
-as JSON, Atom, etc. The model classes are responsible
-for converting between the wire format and the Python
-object representation.
-"""
-
-__author__ = 'jcgregorio@google.com (Joe Gregorio)'
-
-import json
-import logging
-import urllib
-
-from googleapiclient import __version__
-from errors import HttpError
-
-
-dump_request_response = False
-
-
-def _abstract():
-  raise NotImplementedError('You need to override this function')
-
-
-class Model(object):
-  """Model base class.
-
-  All Model classes should implement this interface.
-  The Model serializes and de-serializes between a wire
-  format such as JSON and a Python object representation.
-  """
-
-  def request(self, headers, path_params, query_params, body_value):
-    """Updates outgoing requests with a serialized body.
-
-    Args:
-      headers: dict, request headers
-      path_params: dict, parameters that appear in the request path
-      query_params: dict, parameters that appear in the query
-      body_value: object, the request body as a Python object, which must be
-                  serializable.
-    Returns:
-      A tuple of (headers, path_params, query, body)
-
-      headers: dict, request headers
-      path_params: dict, parameters that appear in the request path
-      query: string, query part of the request URI
-      body: string, the body serialized in the desired wire format.
-    """
-    _abstract()
-
-  def response(self, resp, content):
-    """Convert the response wire format into a Python object.
-
-    Args:
-      resp: httplib2.Response, the HTTP response headers and status
-      content: string, the body of the HTTP response
-
-    Returns:
-      The body de-serialized as a Python object.
-
-    Raises:
-      googleapiclient.errors.HttpError if a non 2xx response is received.
-    """
-    _abstract()
-
-
-class BaseModel(Model):
-  """Base model class.
-
-  Subclasses should provide implementations for the "serialize" and
-  "deserialize" methods, as well as values for the following class attributes.
-
-  Attributes:
-    accept: The value to use for the HTTP Accept header.
-    content_type: The value to use for the HTTP Content-type header.
-    no_content_response: The value to return when deserializing a 204 "No
-        Content" response.
-    alt_param: The value to supply as the "alt" query parameter for requests.
-  """
-
-  accept = None
-  content_type = None
-  no_content_response = None
-  alt_param = None
-
-  def _log_request(self, headers, path_params, query, body):
-    """Logs debugging information about the request if requested."""
-    if dump_request_response:
-      logging.info('--request-start--')
-      logging.info('-headers-start-')
-      for h, v in headers.iteritems():
-        logging.info('%s: %s', h, v)
-      logging.info('-headers-end-')
-      logging.info('-path-parameters-start-')
-      for h, v in path_params.iteritems():
-        logging.info('%s: %s', h, v)
-      logging.info('-path-parameters-end-')
-      logging.info('body: %s', body)
-      logging.info('query: %s', query)
-      logging.info('--request-end--')
-
-  def request(self, headers, path_params, query_params, body_value):
-    """Updates outgoing requests with a serialized body.
-
-    Args:
-      headers: dict, request headers
-      path_params: dict, parameters that appear in the request path
-      query_params: dict, parameters that appear in the query
-      body_value: object, the request body as a Python object, which must be
-                  serializable by json.
-    Returns:
-      A tuple of (headers, path_params, query, body)
-
-      headers: dict, request headers
-      path_params: dict, parameters that appear in the request path
-      query: string, query part of the request URI
-      body: string, the body serialized as JSON
-    """
-    query = self._build_query(query_params)
-    headers['accept'] = self.accept
-    headers['accept-encoding'] = 'gzip, deflate'
-    if 'user-agent' in headers:
-      headers['user-agent'] += ' '
-    else:
-      headers['user-agent'] = ''
-    headers['user-agent'] += 'google-api-python-client/%s (gzip)' % __version__
-
-    if body_value is not None:
-      headers['content-type'] = self.content_type
-      body_value = self.serialize(body_value)
-    self._log_request(headers, path_params, query, body_value)
-    return (headers, path_params, query, body_value)
-
-  def _build_query(self, params):
-    """Builds a query string.
-
-    Args:
-      params: dict, the query parameters
-
-    Returns:
-      The query parameters properly encoded into an HTTP URI query string.
-    """
-    if self.alt_param is not None:
-      params.update({'alt': self.alt_param})
-    astuples = []
-    for key, value in params.iteritems():
-      if type(value) == type([]):
-        for x in value:
-          x = x.encode('utf-8')
-          astuples.append((key, x))
-      else:
-        if getattr(value, 'encode', False) and callable(value.encode):
-          value = value.encode('utf-8')
-        astuples.append((key, value))
-    return '?' + urllib.urlencode(astuples)
-
-  def _log_response(self, resp, content):
-    """Logs debugging information about the response if requested."""
-    if dump_request_response:
-      logging.info('--response-start--')
-      for h, v in resp.iteritems():
-        logging.info('%s: %s', h, v)
-      if content:
-        logging.info(content)
-      logging.info('--response-end--')
-
-  def response(self, resp, content):
-    """Convert the response wire format into a Python object.
-
-    Args:
-      resp: httplib2.Response, the HTTP response headers and status
-      content: string, the body of the HTTP response
-
-    Returns:
-      The body de-serialized as a Python object.
-
-    Raises:
-      googleapiclient.errors.HttpError if a non 2xx response is received.
-    """
-    self._log_response(resp, content)
-    # Error handling is TBD, for example, do we retry
-    # for some operation/error combinations?
-    if resp.status < 300:
-      if resp.status == 204:
-        # A 204: No Content response should be treated differently
-        # to all the other success states
-        return self.no_content_response
-      return self.deserialize(content)
-    else:
-      logging.debug('Content from bad request was: %s' % content)
-      raise HttpError(resp, content)
-
-  def serialize(self, body_value):
-    """Perform the actual Python object serialization.
-
-    Args:
-      body_value: object, the request body as a Python object.
-
-    Returns:
-      string, the body in serialized form.
-    """
-    _abstract()
-
-  def deserialize(self, content):
-    """Perform the actual deserialization from response string to Python
-    object.
-
-    Args:
-      content: string, the body of the HTTP response
-
-    Returns:
-      The body de-serialized as a Python object.
-    """
-    _abstract()
-
-
-class JsonModel(BaseModel):
-  """Model class for JSON.
-
-  Serializes and de-serializes between JSON and the Python
-  object representation of HTTP request and response bodies.
-  """
-  accept = 'application/json'
-  content_type = 'application/json'
-  alt_param = 'json'
-
-  def __init__(self, data_wrapper=False):
-    """Construct a JsonModel.
-
-    Args:
-      data_wrapper: boolean, wrap requests and responses in a data wrapper
-    """
-    self._data_wrapper = data_wrapper
-
-  def serialize(self, body_value):
-    if (isinstance(body_value, dict) and 'data' not in body_value and
-        self._data_wrapper):
-      body_value = {'data': body_value}
-    return json.dumps(body_value)
-
-  def deserialize(self, content):
-    content = content.decode('utf-8')
-    body = json.loads(content)
-    if self._data_wrapper and isinstance(body, dict) and 'data' in body:
-      body = body['data']
-    return body
-
-  @property
-  def no_content_response(self):
-    return {}
-
-
-class RawModel(JsonModel):
-  """Model class for requests that don't return JSON.
-
-  Serializes and de-serializes between JSON and the Python
-  object representation of HTTP request, and returns the raw bytes
-  of the response body.
-  """
-  accept = '*/*'
-  content_type = 'application/json'
-  alt_param = None
-
-  def deserialize(self, content):
-    return content
-
-  @property
-  def no_content_response(self):
-    return ''
-
-
-class MediaModel(JsonModel):
-  """Model class for requests that return Media.
-
-  Serializes and de-serializes between JSON and the Python
-  object representation of HTTP request, and returns the raw bytes
-  of the response body.
-  """
-  accept = '*/*'
-  content_type = 'application/json'
-  alt_param = 'media'
-
-  def deserialize(self, content):
-    return content
-
-  @property
-  def no_content_response(self):
-    return ''
-
-
-class ProtocolBufferModel(BaseModel):
-  """Model class for protocol buffers.
-
-  Serializes and de-serializes the binary protocol buffer sent in the HTTP
-  request and response bodies.
-  """
-  accept = 'application/x-protobuf'
-  content_type = 'application/x-protobuf'
-  alt_param = 'proto'
-
-  def __init__(self, protocol_buffer):
-    """Constructs a ProtocolBufferModel.
-
-    The serialzed protocol buffer returned in an HTTP response will be
-    de-serialized using the given protocol buffer class.
-
-    Args:
-      protocol_buffer: The protocol buffer class used to de-serialize a
-      response from the API.
-    """
-    self._protocol_buffer = protocol_buffer
-
-  def serialize(self, body_value):
-    return body_value.SerializeToString()
-
-  def deserialize(self, content):
-    return self._protocol_buffer.FromString(content)
-
-  @property
-  def no_content_response(self):
-    return self._protocol_buffer()
-
-
-def makepatch(original, modified):
-  """Create a patch object.
-
-  Some methods support PATCH, an efficient way to send updates to a resource.
-  This method allows the easy construction of patch bodies by looking at the
-  differences between a resource before and after it was modified.
-
-  Args:
-    original: object, the original deserialized resource
-    modified: object, the modified deserialized resource
-  Returns:
-    An object that contains only the changes from original to modified, in a
-    form suitable to pass to a PATCH method.
-
-  Example usage:
-    item = service.activities().get(postid=postid, userid=userid).execute()
-    original = copy.deepcopy(item)
-    item['object']['content'] = 'This is updated.'
-    service.activities.patch(postid=postid, userid=userid,
-      body=makepatch(original, item)).execute()
-  """
-  patch = {}
-  for key, original_value in original.iteritems():
-    modified_value = modified.get(key, None)
-    if modified_value is None:
-      # Use None to signal that the element is deleted
-      patch[key] = None
-    elif original_value != modified_value:
-      if type(original_value) == type({}):
-        # Recursively descend objects
-        patch[key] = makepatch(original_value, modified_value)
-      else:
-        # In the case of simple types or arrays we just replace
-        patch[key] = modified_value
-    else:
-      # Don't add anything to patch if there's no change
-      pass
-  for key in modified:
-    if key not in original:
-      patch[key] = modified[key]
-
-  return patch
diff --git a/third_party/google_api_python_client/googleapiclient/sample_tools.py b/third_party/google_api_python_client/googleapiclient/sample_tools.py
deleted file mode 100644
index cbd6d6f..0000000
--- a/third_party/google_api_python_client/googleapiclient/sample_tools.py
+++ /dev/null
@@ -1,102 +0,0 @@
-# Copyright 2014 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Utilities for making samples.
-
-Consolidates a lot of code commonly repeated in sample applications.
-"""
-
-__author__ = 'jcgregorio@google.com (Joe Gregorio)'
-__all__ = ['init']
-
-
-import argparse
-import httplib2
-import os
-
-from googleapiclient import discovery
-from ...oauth2client import client
-from ...oauth2client import file
-from ...oauth2client import tools
-
-
-def init(argv, name, version, doc, filename, scope=None, parents=[], discovery_filename=None):
-  """A common initialization routine for samples.
-
-  Many of the sample applications do the same initialization, which has now
-  been consolidated into this function. This function uses common idioms found
-  in almost all the samples, i.e. for an API with name 'apiname', the
-  credentials are stored in a file named apiname.dat, and the
-  client_secrets.json file is stored in the same directory as the application
-  main file.
-
-  Args:
-    argv: list of string, the command-line parameters of the application.
-    name: string, name of the API.
-    version: string, version of the API.
-    doc: string, description of the application. Usually set to __doc__.
-    file: string, filename of the application. Usually set to __file__.
-    parents: list of argparse.ArgumentParser, additional command-line flags.
-    scope: string, The OAuth scope used.
-    discovery_filename: string, name of local discovery file (JSON). Use when discovery doc not available via URL.
-
-  Returns:
-    A tuple of (service, flags), where service is the service object and flags
-    is the parsed command-line flags.
-  """
-  if scope is None:
-    scope = 'https://www.googleapis.com/auth/' + name
-
-  # Parser command-line arguments.
-  parent_parsers = [tools.argparser]
-  parent_parsers.extend(parents)
-  parser = argparse.ArgumentParser(
-      description=doc,
-      formatter_class=argparse.RawDescriptionHelpFormatter,
-      parents=parent_parsers)
-  flags = parser.parse_args(argv[1:])
-
-  # Name of a file containing the OAuth 2.0 information for this
-  # application, including client_id and client_secret, which are found
-  # on the API Access tab on the Google APIs
-  # Console <http://code.google.com/apis/console>.
-  client_secrets = os.path.join(os.path.dirname(filename),
-                                'client_secrets.json')
-
-  # Set up a Flow object to be used if we need to authenticate.
-  flow = client.flow_from_clientsecrets(client_secrets,
-      scope=scope,
-      message=tools.message_if_missing(client_secrets))
-
-  # Prepare credentials, and authorize HTTP object with them.
-  # If the credentials don't exist or are invalid run through the native client
-  # flow. The Storage object will ensure that if successful the good
-  # credentials will get written back to a file.
-  storage = file.Storage(name + '.dat')
-  credentials = storage.get()
-  if credentials is None or credentials.invalid:
-    credentials = tools.run_flow(flow, storage, flags)
-  http = credentials.authorize(http = httplib2.Http())
-
-  if discovery_filename is None:
-    # Construct a service object via the discovery service.
-    service = discovery.build(name, version, http=http)
-  else:
-    # Construct a service object using a local discovery document file.
-	with open(discovery_filename) as discovery_file:
-	  service = discovery.build_from_document(
-		  discovery_file.read(),
-		  base='https://www.googleapis.com/',
-		  http=http)
-  return (service, flags)
diff --git a/third_party/google_api_python_client/googleapiclient/schema.py b/third_party/google_api_python_client/googleapiclient/schema.py
deleted file mode 100644
index af41317..0000000
--- a/third_party/google_api_python_client/googleapiclient/schema.py
+++ /dev/null
@@ -1,311 +0,0 @@
-# Copyright 2014 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Schema processing for discovery based APIs
-
-Schemas holds an APIs discovery schemas. It can return those schema as
-deserialized JSON objects, or pretty print them as prototype objects that
-conform to the schema.
-
-For example, given the schema:
-
- schema = \"\"\"{
-   "Foo": {
-    "type": "object",
-    "properties": {
-     "etag": {
-      "type": "string",
-      "description": "ETag of the collection."
-     },
-     "kind": {
-      "type": "string",
-      "description": "Type of the collection ('calendar#acl').",
-      "default": "calendar#acl"
-     },
-     "nextPageToken": {
-      "type": "string",
-      "description": "Token used to access the next
-         page of this result. Omitted if no further results are available."
-     }
-    }
-   }
- }\"\"\"
-
- s = Schemas(schema)
- print s.prettyPrintByName('Foo')
-
- Produces the following output:
-
-  {
-   "nextPageToken": "A String", # Token used to access the
-       # next page of this result. Omitted if no further results are available.
-   "kind": "A String", # Type of the collection ('calendar#acl').
-   "etag": "A String", # ETag of the collection.
-  },
-
-The constructor takes a discovery document in which to look up named schema.
-"""
-
-# TODO(jcgregorio) support format, enum, minimum, maximum
-
-__author__ = 'jcgregorio@google.com (Joe Gregorio)'
-
-import copy
-
-from oauth2client import util
-
-
-class Schemas(object):
-  """Schemas for an API."""
-
-  def __init__(self, discovery):
-    """Constructor.
-
-    Args:
-      discovery: object, Deserialized discovery document from which we pull
-        out the named schema.
-    """
-    self.schemas = discovery.get('schemas', {})
-
-    # Cache of pretty printed schemas.
-    self.pretty = {}
-
-  @util.positional(2)
-  def _prettyPrintByName(self, name, seen=None, dent=0):
-    """Get pretty printed object prototype from the schema name.
-
-    Args:
-      name: string, Name of schema in the discovery document.
-      seen: list of string, Names of schema already seen. Used to handle
-        recursive definitions.
-
-    Returns:
-      string, A string that contains a prototype object with
-        comments that conforms to the given schema.
-    """
-    if seen is None:
-      seen = []
-
-    if name in seen:
-      # Do not fall into an infinite loop over recursive definitions.
-      return '# Object with schema name: %s' % name
-    seen.append(name)
-
-    if name not in self.pretty:
-      self.pretty[name] = _SchemaToStruct(self.schemas[name],
-          seen, dent=dent).to_str(self._prettyPrintByName)
-
-    seen.pop()
-
-    return self.pretty[name]
-
-  def prettyPrintByName(self, name):
-    """Get pretty printed object prototype from the schema name.
-
-    Args:
-      name: string, Name of schema in the discovery document.
-
-    Returns:
-      string, A string that contains a prototype object with
-        comments that conforms to the given schema.
-    """
-    # Return with trailing comma and newline removed.
-    return self._prettyPrintByName(name, seen=[], dent=1)[:-2]
-
-  @util.positional(2)
-  def _prettyPrintSchema(self, schema, seen=None, dent=0):
-    """Get pretty printed object prototype of schema.
-
-    Args:
-      schema: object, Parsed JSON schema.
-      seen: list of string, Names of schema already seen. Used to handle
-        recursive definitions.
-
-    Returns:
-      string, A string that contains a prototype object with
-        comments that conforms to the given schema.
-    """
-    if seen is None:
-      seen = []
-
-    return _SchemaToStruct(schema, seen, dent=dent).to_str(self._prettyPrintByName)
-
-  def prettyPrintSchema(self, schema):
-    """Get pretty printed object prototype of schema.
-
-    Args:
-      schema: object, Parsed JSON schema.
-
-    Returns:
-      string, A string that contains a prototype object with
-        comments that conforms to the given schema.
-    """
-    # Return with trailing comma and newline removed.
-    return self._prettyPrintSchema(schema, dent=1)[:-2]
-
-  def get(self, name):
-    """Get deserialized JSON schema from the schema name.
-
-    Args:
-      name: string, Schema name.
-    """
-    return self.schemas[name]
-
-
-class _SchemaToStruct(object):
-  """Convert schema to a prototype object."""
-
-  @util.positional(3)
-  def __init__(self, schema, seen, dent=0):
-    """Constructor.
-
-    Args:
-      schema: object, Parsed JSON schema.
-      seen: list, List of names of schema already seen while parsing. Used to
-        handle recursive definitions.
-      dent: int, Initial indentation depth.
-    """
-    # The result of this parsing kept as list of strings.
-    self.value = []
-
-    # The final value of the parsing.
-    self.string = None
-
-    # The parsed JSON schema.
-    self.schema = schema
-
-    # Indentation level.
-    self.dent = dent
-
-    # Method that when called returns a prototype object for the schema with
-    # the given name.
-    self.from_cache = None
-
-    # List of names of schema already seen while parsing.
-    self.seen = seen
-
-  def emit(self, text):
-    """Add text as a line to the output.
-
-    Args:
-      text: string, Text to output.
-    """
-    self.value.extend(["  " * self.dent, text, '\n'])
-
-  def emitBegin(self, text):
-    """Add text to the output, but with no line terminator.
-
-    Args:
-      text: string, Text to output.
-      """
-    self.value.extend(["  " * self.dent, text])
-
-  def emitEnd(self, text, comment):
-    """Add text and comment to the output with line terminator.
-
-    Args:
-      text: string, Text to output.
-      comment: string, Python comment.
-    """
-    if comment:
-      divider = '\n' + '  ' * (self.dent + 2) + '# '
-      lines = comment.splitlines()
-      lines = [x.rstrip() for x in lines]
-      comment = divider.join(lines)
-      self.value.extend([text, ' # ', comment, '\n'])
-    else:
-      self.value.extend([text, '\n'])
-
-  def indent(self):
-    """Increase indentation level."""
-    self.dent += 1
-
-  def undent(self):
-    """Decrease indentation level."""
-    self.dent -= 1
-
-  def _to_str_impl(self, schema):
-    """Prototype object based on the schema, in Python code with comments.
-
-    Args:
-      schema: object, Parsed JSON schema file.
-
-    Returns:
-      Prototype object based on the schema, in Python code with comments.
-    """
-    stype = schema.get('type')
-    if stype == 'object':
-      self.emitEnd('{', schema.get('description', ''))
-      self.indent()
-      if 'properties' in schema:
-        for pname, pschema in schema.get('properties', {}).iteritems():
-          self.emitBegin('"%s": ' % pname)
-          self._to_str_impl(pschema)
-      elif 'additionalProperties' in schema:
-        self.emitBegin('"a_key": ')
-        self._to_str_impl(schema['additionalProperties'])
-      self.undent()
-      self.emit('},')
-    elif '$ref' in schema:
-      schemaName = schema['$ref']
-      description = schema.get('description', '')
-      s = self.from_cache(schemaName, seen=self.seen)
-      parts = s.splitlines()
-      self.emitEnd(parts[0], description)
-      for line in parts[1:]:
-        self.emit(line.rstrip())
-    elif stype == 'boolean':
-      value = schema.get('default', 'True or False')
-      self.emitEnd('%s,' % str(value), schema.get('description', ''))
-    elif stype == 'string':
-      value = schema.get('default', 'A String')
-      self.emitEnd('"%s",' % str(value), schema.get('description', ''))
-    elif stype == 'integer':
-      value = schema.get('default', '42')
-      self.emitEnd('%s,' % str(value), schema.get('description', ''))
-    elif stype == 'number':
-      value = schema.get('default', '3.14')
-      self.emitEnd('%s,' % str(value), schema.get('description', ''))
-    elif stype == 'null':
-      self.emitEnd('None,', schema.get('description', ''))
-    elif stype == 'any':
-      self.emitEnd('"",', schema.get('description', ''))
-    elif stype == 'array':
-      self.emitEnd('[', schema.get('description'))
-      self.indent()
-      self.emitBegin('')
-      self._to_str_impl(schema['items'])
-      self.undent()
-      self.emit('],')
-    else:
-      self.emit('Unknown type! %s' % stype)
-      self.emitEnd('', '')
-
-    self.string = ''.join(self.value)
-    return self.string
-
-  def to_str(self, from_cache):
-    """Prototype object based on the schema, in Python code with comments.
-
-    Args:
-      from_cache: callable(name, seen), Callable that retrieves an object
-         prototype for a schema with the given name. Seen is a list of schema
-         names already seen as we recursively descend the schema definition.
-
-    Returns:
-      Prototype object based on the schema, in Python code with comments.
-      The lines of the code will all be properly indented.
-    """
-    self.from_cache = from_cache
-    return self._to_str_impl(self.schema)
diff --git a/third_party/google_api_python_client/samples-index.py b/third_party/google_api_python_client/samples-index.py
deleted file mode 100644
index 712f552..0000000
--- a/third_party/google_api_python_client/samples-index.py
+++ /dev/null
@@ -1,246 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright 2014 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Build wiki page with a list of all samples.
-
-The information for the wiki page is built from data found in all the README
-files in the samples. The format of the README file is:
-
-
-   Description is everything up to the first blank line.
-
-   api: plus  (Used to look up the long name in discovery).
-   keywords: appengine (such as appengine, oauth2, cmdline)
-
-   The rest of the file is ignored when it comes to building the index.
-"""
-
-import httplib2
-import itertools
-import json
-import os
-import re
-
-BASE_HG_URI = ('http://code.google.com/p/google-api-python-client/source/'
-               'browse/#hg')
-
-http = httplib2.Http('.cache')
-r, c =  http.request('https://www.googleapis.com/discovery/v1/apis')
-if r.status != 200:
-  raise ValueError('Received non-200 response when retrieving Discovery.')
-
-# Dictionary mapping api names to their discovery description.
-DIRECTORY = {}
-for item in json.loads(c)['items']:
-  if item['preferred']:
-    DIRECTORY[item['name']] = item
-
-# A list of valid keywords. Should not be taken as complete, add to
-# this list as needed.
-KEYWORDS = {
-    'appengine': 'Google App Engine',
-    'oauth2': 'OAuth 2.0',
-    'cmdline': 'Command-line',
-    'django': 'Django',
-    'threading': 'Threading',
-    'pagination': 'Pagination',
-    'media': 'Media Upload and Download'
-    }
-
-
-def get_lines(name, lines):
-  """Return lines that begin with name.
-
-  Lines are expected to look like:
-
-     name: space separated values
-
-  Args:
-    name: string, parameter name.
-    lines: iterable of string, lines in the file.
-
-  Returns:
-    List of values in the lines that match.
-  """
-  retval = []
-  matches = itertools.ifilter(lambda x: x.startswith(name + ':'), lines)
-  for line in matches:
-    retval.extend(line[len(name)+1:].split())
-  return retval
-
-
-def wiki_escape(s):
-  """Detect WikiSyntax (i.e. InterCaps, a.k.a. CamelCase) and escape it."""
-  ret = []
-  for word in s.split():
-    if re.match(r'[A-Z]+[a-z]+[A-Z]', word):
-      word = '!%s' % word
-    ret.append(word)
-  return ' '.join(ret)
-
-
-def context_from_sample(api, keywords, dirname, desc, uri):
-  """Return info for expanding a sample into a template.
-
-  Args:
-    api: string, name of api.
-    keywords: list of string, list of keywords for the given api.
-    dirname: string, directory name of the sample.
-    desc: string, long description of the sample.
-    uri: string, uri of the sample code if provided in the README.
-
-  Returns:
-    A dictionary of values useful for template expansion.
-  """
-  if uri is None:
-    uri = BASE_HG_URI + dirname.replace('/', '%2F')
-  else:
-    uri = ''.join(uri)
-  if api is None:
-    return None
-  else:
-    entry = DIRECTORY[api]
-    context = {
-        'api': api,
-        'version': entry['version'],
-        'api_name': wiki_escape(entry.get('title', entry.get('description'))),
-        'api_desc': wiki_escape(entry['description']),
-        'api_icon': entry['icons']['x32'],
-        'keywords': keywords,
-        'dir': dirname,
-        'uri': uri,
-        'desc': wiki_escape(desc),
-        }
-    return context
-
-
-def keyword_context_from_sample(keywords, dirname, desc, uri):
-  """Return info for expanding a sample into a template.
-
-  Sample may not be about a specific api.
-
-  Args:
-    keywords: list of string, list of keywords for the given api.
-    dirname: string, directory name of the sample.
-    desc: string, long description of the sample.
-    uri: string, uri of the sample code if provided in the README.
-
-  Returns:
-    A dictionary of values useful for template expansion.
-  """
-  if uri is None:
-    uri = BASE_HG_URI + dirname.replace('/', '%2F')
-  else:
-    uri = ''.join(uri)
-  context = {
-      'keywords': keywords,
-      'dir': dirname,
-      'uri': uri,
-      'desc': wiki_escape(desc),
-      }
-  return context
-
-
-def scan_readme_files(dirname):
-  """Scans all subdirs of dirname for README files.
-
-  Args:
-    dirname: string, name of directory to walk.
-
-  Returns:
-    (samples, keyword_set): list of information about all samples, the union
-      of all keywords found.
-  """
-  samples = []
-  keyword_set = set()
-
-  for root, dirs, files in os.walk(dirname):
-    if 'README' in files:
-      filename = os.path.join(root, 'README')
-      with open(filename, 'r') as f:
-        content = f.read()
-        lines = content.splitlines()
-        desc = ' '.join(itertools.takewhile(lambda x: x, lines))
-        api = get_lines('api', lines)
-        keywords = get_lines('keywords', lines)
-        uri = get_lines('uri', lines)
-        if not uri:
-          uri = None
-
-        for k in keywords:
-          if k not in KEYWORDS:
-            raise ValueError(
-                '%s is not a valid keyword in file %s' % (k, filename))
-        keyword_set.update(keywords)
-        if not api:
-          api = [None]
-        samples.append((api[0], keywords, root[1:], desc, uri))
-
-  samples.sort()
-
-  return samples, keyword_set
-
-
-def main():
-  # Get all the information we need out of the README files in the samples.
-  samples, keyword_set = scan_readme_files('./samples')
-
-  # Now build a wiki page with all that information. Accumulate all the
-  # information as string to be concatenated when were done.
-  page = ['<wiki:toc max_depth="3" />\n= Samples By API =\n']
-
-  # All the samples, grouped by API.
-  current_api = None
-  for api, keywords, dirname, desc, uri in samples:
-    context = context_from_sample(api, keywords, dirname, desc, uri)
-    if context is None:
-      continue
-    if current_api != api:
-      page.append("""
-=== %(api_icon)s %(api_name)s ===
-
-%(api_desc)s
-
-Documentation for the %(api_name)s in [https://google-api-client-libraries.appspot.com/documentation/%(api)s/%(version)s/python/latest/ PyDoc]
-
-""" % context)
-      current_api = api
-
-    page.append('|| [%(uri)s %(dir)s] || %(desc)s ||\n' % context)
-
-  # Now group the samples by keywords.
-  for keyword, keyword_name in KEYWORDS.iteritems():
-    if keyword not in keyword_set:
-      continue
-    page.append('\n= %s Samples =\n\n' % keyword_name)
-    page.append('<table border=1 cellspacing=0 cellpadding=8px>\n')
-    for _, keywords, dirname, desc, uri in samples:
-      context = keyword_context_from_sample(keywords, dirname, desc, uri)
-      if keyword not in keywords:
-        continue
-      page.append("""
-<tr>
-  <td>[%(uri)s %(dir)s] </td>
-  <td> %(desc)s </td>
-</tr>""" % context)
-    page.append('</table>\n')
-
-  print ''.join(page)
-
-
-if __name__ == '__main__':
-  main()
diff --git a/third_party/google_api_python_client/setup.py b/third_party/google_api_python_client/setup.py
deleted file mode 100644
index 40dbc0f..0000000
--- a/third_party/google_api_python_client/setup.py
+++ /dev/null
@@ -1,94 +0,0 @@
-# Copyright 2014 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Setup script for Google API Python client.
-
-Also installs included versions of third party libraries, if those libraries
-are not already installed.
-"""
-from __future__ import print_function
-
-import sys
-
-if sys.version_info < (2, 6):
-  print('google-api-python-client requires python version >= 2.6.',
-        file=sys.stderr)
-  sys.exit(1)
-
-from setuptools import setup
-import pkg_resources
-
-def _DetectBadness():
-  import os
-  if 'SKIP_GOOGLEAPICLIENT_COMPAT_CHECK' in os.environ:
-    return
-  o2c_pkg = None
-  try:
-    o2c_pkg = pkg_resources.get_distribution('oauth2client')
-  except pkg_resources.DistributionNotFound:
-    pass
-  oauth2client = None
-  try:
-    import oauth2client
-  except ImportError:
-    pass
-  if o2c_pkg is None and oauth2client is not None:
-    raise RuntimeError(
-        'Previous version of google-api-python-client detected; due to a '
-        'packaging issue, we cannot perform an in-place upgrade. Please remove '
-        'the old version and re-install this package.'
-    )
-
-_DetectBadness()
-
-packages = [
-    'apiclient',
-    'googleapiclient',
-]
-
-install_requires = [
-    'httplib2>=0.8',
-    'oauth2client>=1.3',
-    'uritemplate>=0.6',
-]
-
-if sys.version_info < (2, 7):
-  install_requires.append('argparse')
-
-long_desc = """The Google API Client for Python is a client library for
-accessing the Plus, Moderator, and many other Google APIs."""
-
-import googleapiclient
-version = googleapiclient.__version__
-
-setup(
-    name="google-api-python-client",
-    version=version,
-    description="Google API Client Library for Python",
-    long_description=long_desc,
-    author="Google Inc.",
-    url="http://github.com/google/google-api-python-client/",
-    install_requires=install_requires,
-    packages=packages,
-    package_data={},
-    license="Apache 2.0",
-    keywords="google api client",
-    classifiers=[
-        'Development Status :: 5 - Production/Stable',
-        'Intended Audience :: Developers',
-        'License :: OSI Approved :: Apache Software License',
-        'Operating System :: POSIX',
-        'Topic :: Internet :: WWW/HTTP',
-    ],
-)
diff --git a/third_party/google_api_python_client/sitecustomize.py b/third_party/google_api_python_client/sitecustomize.py
deleted file mode 100644
index ef0f063..0000000
--- a/third_party/google_api_python_client/sitecustomize.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# Set up the system so that this development
-# version of google-api-python-client is run, even if
-# an older version is installed on the system.
-#
-# To make this totally automatic add the following to
-# your ~/.bash_profile:
-#
-# export PYTHONPATH=/path/to/where/you/checked/out/googleapiclient
-import sys
-import os
-
-sys.path.insert(0, os.path.dirname(__file__))
diff --git a/third_party/google_api_python_client/static/Credentials.png b/third_party/google_api_python_client/static/Credentials.png
deleted file mode 100644
index a5be2c5..0000000
--- a/third_party/google_api_python_client/static/Credentials.png
+++ /dev/null
Binary files differ
diff --git a/third_party/google_api_python_client/tox.ini b/third_party/google_api_python_client/tox.ini
deleted file mode 100644
index 5a5dfbc..0000000
--- a/third_party/google_api_python_client/tox.ini
+++ /dev/null
@@ -1,18 +0,0 @@
-[tox]
-envlist = py26, py27
-
-[testenv]
-deps = keyring
-       mox
-       pyopenssl
-       pycrypto==2.6
-       django
-       webtest
-       nose
-setenv = PYTHONPATH=../google_appengine
-
-[testenv:py26]
-commands = nosetests --ignore-files=test_oauth2client_appengine\.py
-
-[testenv:py27]
-commands = nosetests
diff --git a/third_party/uritemplate/.gitignore b/third_party/uritemplate/.gitignore
deleted file mode 100644
index 5b1b935..0000000
--- a/third_party/uritemplate/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-*.pyc
-build
-dist
-MANIFEST
-
diff --git a/third_party/uritemplate/.gitmodules b/third_party/uritemplate/.gitmodules
deleted file mode 100644
index 3258e94..0000000
--- a/third_party/uritemplate/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "test/cases"]
-	path = test/cases
-	url = git://github.com/uri-templates/uritemplate-test.git
diff --git a/third_party/uritemplate/.travis.yml b/third_party/uritemplate/.travis.yml
deleted file mode 100644
index 520ac1b..0000000
--- a/third_party/uritemplate/.travis.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-language: python
-python:
-  - "2.5"
-  - "2.6"
-  - "2.7"
-  - "3.3"
-  - "pypy"
-# dependencies
-install: pip install simplejson --use-mirrors
-# command to run tests
-script: "cd test; make"
diff --git a/third_party/uritemplate/MAINTAINERS.rst b/third_party/uritemplate/MAINTAINERS.rst
deleted file mode 100644
index 4918f84..0000000
--- a/third_party/uritemplate/MAINTAINERS.rst
+++ /dev/null
@@ -1,14 +0,0 @@
-Instructions for Maintainers
-============================
-
-Release
--------
-
-To release a build:
-
-1. Push all changes, verify CI passes (see link in README.rst).
-2. Increment __version__ in __init__.py
-3. ``git tag -a uri-template-py-[version]``
-4. ``git push --tags origin master``
-5. ``python setup.py sdist upload``
-6. Brew coffee or tea.
diff --git a/third_party/uritemplate/MANIFEST.in b/third_party/uritemplate/MANIFEST.in
deleted file mode 100644
index 9561fb1..0000000
--- a/third_party/uritemplate/MANIFEST.in
+++ /dev/null
@@ -1 +0,0 @@
-include README.rst
diff --git a/third_party/uritemplate/README.chromium b/third_party/uritemplate/README.chromium
deleted file mode 100644
index 0057f9a..0000000
--- a/third_party/uritemplate/README.chromium
+++ /dev/null
@@ -1,6 +0,0 @@
-URL: https://github.com/uri-templates/uritemplate-py/
-Version: 0.6
-Revision: 1e780a49412cdbb273e9421974cb91845c124f3f
-License: Apache License, Version 2.0 (the "License")
-
-No local changes
diff --git a/third_party/uritemplate/README.rst b/third_party/uritemplate/README.rst
deleted file mode 100644
index 80129cb..0000000
--- a/third_party/uritemplate/README.rst
+++ /dev/null
@@ -1,71 +0,0 @@
-uritemplate
-===========
-
-.. image:: https://secure.travis-ci.org/uri-templates/uritemplate-py.png?branch=master
-   :alt: build status
-   :target: http://travis-ci.org/uri-templates/uritemplate-py
-
-This is a Python implementation of `RFC6570`_, URI Template, and can
-expand templates up to and including Level 4 in that specification.
-
-It exposes a method, *expand*. For example:
-
-.. code-block:: python
-
-    >>> from uritemplate import expand
-    >>> expand("http://www.{domain}/", {"domain": "foo.com"})
-    'http://www.foo.com/'
-
-It also exposes a method *variables* that returns all variables used in a
-uritemplate. For example:
-
-.. code-block:: python
-
-    >>> from uritemplate import variables
-    >>> variables('http:www{.domain*}{/top,next}{?q:20}')
-    >>> set(['domain', 'next', 'q', 'top'])
-
-This function can be useful to determine what keywords are available to be
-expanded.
-
-.. _RFC6570: http://tools.ietf.org/html/rfc6570
-
-
-Requirements
-------------
-
-uritemplate works with Python 2.5+.
-
-.. note:: You need to install `simplejson`_ module for Python 2.5.
-
-.. _simplejson: https://pypi.python.org/pypi/simplejson/
-
-
-Install
--------
-
-The easiest way to install uritemplate is with pip::
-
-    $ pip install uritemplate
-
-See its `Python Package Index entry`_ for more.
-
-.. _Python Package Index entry: http://pypi.python.org/pypi/uritemplate
-
-
-License
-=======
-
-Copyright 2011-2013 Joe Gregorio
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
diff --git a/third_party/uritemplate/__init__.py b/third_party/uritemplate/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/third_party/uritemplate/__init__.py
+++ /dev/null
diff --git a/third_party/uritemplate/setup.py b/third_party/uritemplate/setup.py
deleted file mode 100755
index 9b71aae..0000000
--- a/third_party/uritemplate/setup.py
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/env python
-
-from distutils.core import setup
-import uritemplate
-
-base_url = "http://github.com/uri-templates/uritemplate-py/"
-
-setup(
-  name = 'uritemplate',
-  version = uritemplate.__version__,
-  description = 'URI Templates',
-  author = 'Joe Gregorio',
-  author_email = 'joe@bitworking.org',
-  url = base_url,
-  download_url = \
-    '%starball/uritemplate-py-%s' % (base_url, uritemplate.__version__),
-  packages = ['uritemplate'],
-  provides = ['uritemplate'],
-  long_description=open("README.rst").read(),
-  install_requires = ['simplejson >= 2.5.0'],
-  classifiers = [
-    'Development Status :: 4 - Beta',
-    'Intended Audience :: Developers',
-    'License :: OSI Approved :: Apache Software License',
-    'Programming Language :: Python',
-    'Programming Language :: Python :: 2',
-    'Programming Language :: Python :: 2.5',
-    'Programming Language :: Python :: 2.6',
-    'Programming Language :: Python :: 2.7',
-    'Programming Language :: Python :: 3',
-    'Programming Language :: Python :: 3.3',
-    'Operating System :: POSIX',
-    'Topic :: Internet :: WWW/HTTP',
-    'Topic :: Software Development :: Libraries :: Python Modules',
-  ]
-)
-
diff --git a/third_party/uritemplate/uritemplate/__init__.py b/third_party/uritemplate/uritemplate/__init__.py
deleted file mode 100755
index 712405d..0000000
--- a/third_party/uritemplate/uritemplate/__init__.py
+++ /dev/null
@@ -1,265 +0,0 @@
-#!/usr/bin/env python
-
-"""
-URI Template (RFC6570) Processor
-"""
-
-__copyright__ = """\
-Copyright 2011-2013 Joe Gregorio
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-"""
-
-import re
-try:
-   from urllib.parse import quote
-except ImportError:
-   from urllib import quote
-
-
-
-__version__ = "0.6"
-
-RESERVED = ":/?#[]@!$&'()*+,;="
-OPERATOR = "+#./;?&|!@"
-MODIFIER = ":^"
-TEMPLATE = re.compile("{([^\}]+)}")
-
-
-def variables(template):
-    '''Returns the set of keywords in a uri template'''
-    vars = set()
-    for varlist in TEMPLATE.findall(template):
-        if varlist[0] in OPERATOR:
-            varlist = varlist[1:]
-        varspecs = varlist.split(',')
-        for var in varspecs:
-            # handle prefix values
-            var = var.split(':')[0]
-            # handle composite values
-            if var.endswith('*'):
-                var = var[:-1]
-            vars.add(var)
-    return vars
-
-
-def _quote(value, safe, prefix=None):
-    if prefix is not None:
-        return quote(str(value)[:prefix], safe)
-    return quote(str(value), safe)
-
-
-def _tostring(varname, value, explode, prefix, operator, safe=""):
-    if isinstance(value, list):
-        return ",".join([_quote(x, safe) for x in value])
-    if isinstance(value, dict):
-        keys = sorted(value.keys())
-        if explode:
-            return ",".join([_quote(key, safe) + "=" + \
-                             _quote(value[key], safe) for key in keys])
-        else:
-            return ",".join([_quote(key, safe) + "," + \
-                             _quote(value[key], safe) for key in keys])
-    elif value is None:
-        return
-    else:
-        return _quote(value, safe, prefix)
-
-
-def _tostring_path(varname, value, explode, prefix, operator, safe=""):
-    joiner = operator
-    if isinstance(value, list):
-        if explode:
-            out = [_quote(x, safe) for x in value if value is not None]
-        else:
-            joiner = ","
-            out = [_quote(x, safe) for x in value if value is not None]
-        if out:
-            return joiner.join(out)
-        else:
-            return
-    elif isinstance(value, dict):
-        keys = sorted(value.keys())
-        if explode:
-            out = [_quote(key, safe) + "=" + \
-                   _quote(value[key], safe) for key in keys \
-                   if value[key] is not None]
-        else:
-            joiner = ","
-            out = [_quote(key, safe) + "," + \
-                   _quote(value[key], safe) \
-                   for key in keys if value[key] is not None]
-        if out:
-            return joiner.join(out)
-        else:
-            return
-    elif value is None:
-        return
-    else:
-        return _quote(value, safe, prefix)
-
-
-def _tostring_semi(varname, value, explode, prefix, operator, safe=""):
-    joiner = operator
-    if operator == "?":
-        joiner = "&"
-    if isinstance(value, list):
-        if explode:
-            out = [varname + "=" + _quote(x, safe) \
-                   for x in value if x is not None]
-            if out:
-                return joiner.join(out)
-            else:
-                return
-        else:
-            return varname + "=" + ",".join([_quote(x, safe) \
-                                             for x in value])
-    elif isinstance(value, dict):
-        keys = sorted(value.keys())
-        if explode:
-            return joiner.join([_quote(key, safe) + "=" + \
-                                _quote(value[key], safe) \
-                                for key in keys if key is not None])
-        else:
-            return varname + "=" + ",".join([_quote(key, safe) + "," + \
-                             _quote(value[key], safe) for key in keys \
-                             if key is not None])
-    else:
-        if value is None:
-            return
-        elif value:
-            return (varname + "=" + _quote(value, safe, prefix))
-        else:
-            return varname
-
-
-def _tostring_query(varname, value, explode, prefix, operator, safe=""):
-    joiner = operator
-    if operator in ["?", "&"]:
-        joiner = "&"
-    if isinstance(value, list):
-        if 0 == len(value):
-            return None
-        if explode:
-            return joiner.join([varname + "=" + _quote(x, safe) \
-                                for x in value])
-        else:
-            return (varname + "=" + ",".join([_quote(x, safe) \
-                                             for x in value]))
-    elif isinstance(value, dict):
-        if 0 == len(value):
-            return None
-        keys = sorted(value.keys())
-        if explode:
-            return joiner.join([_quote(key, safe) + "=" + \
-                                _quote(value[key], safe) \
-                                for key in keys])
-        else:
-            return varname + "=" + \
-                   ",".join([_quote(key, safe) + "," + \
-                             _quote(value[key], safe) for key in keys])
-    else:
-        if value is None:
-            return
-        elif value:
-            return (varname + "=" + _quote(value, safe, prefix))
-        else:
-            return (varname  + "=")
-
-
-TOSTRING = {
-    "" : _tostring,
-    "+": _tostring,
-    "#": _tostring,
-    ";": _tostring_semi,
-    "?": _tostring_query,
-    "&": _tostring_query,
-    "/": _tostring_path,
-    ".": _tostring_path,
-    }
-
-
-def expand(template, variables):
-    """
-    Expand template as a URI Template using variables.
-    """
-    def _sub(match):
-        expression = match.group(1)
-        operator = ""
-        if expression[0] in OPERATOR:
-            operator = expression[0]
-            varlist = expression[1:]
-        else:
-            varlist = expression
-
-        safe = ""
-        if operator in ["+", "#"]:
-            safe = RESERVED
-        varspecs = varlist.split(",")
-        varnames = []
-        defaults = {}
-        for varspec in varspecs:
-            default = None
-            explode = False
-            prefix = None
-            if "=" in varspec:
-                varname, default = tuple(varspec.split("=", 1))
-            else:
-                varname = varspec
-            if varname[-1] == "*":
-                explode = True
-                varname = varname[:-1]
-            elif ":" in varname:
-                try:
-                    prefix = int(varname[varname.index(":")+1:])
-                except ValueError:
-                    raise ValueError("non-integer prefix '{0}'".format(
-                       varname[varname.index(":")+1:]))
-                varname = varname[:varname.index(":")]
-            if default:
-                defaults[varname] = default
-            varnames.append((varname, explode, prefix))
-
-        retval = []
-        joiner = operator
-        start = operator
-        if operator == "+":
-            start = ""
-            joiner = ","
-        if operator == "#":
-            joiner = ","
-        if operator == "?":
-            joiner = "&"
-        if operator == "&":
-            start = "&"
-        if operator == "":
-            joiner = ","
-        for varname, explode, prefix in varnames:
-            if varname in variables:
-                value = variables[varname]
-                if not value and value != "" and varname in defaults:
-                    value = defaults[varname]
-            elif varname in defaults:
-                value = defaults[varname]
-            else:
-                continue
-            expanded = TOSTRING[operator](
-              varname, value, explode, prefix, operator, safe=safe)
-            if expanded is not None:
-                retval.append(expanded)
-        if len(retval) > 0:
-            return start + joiner.join(retval)
-        else:
-            return ""
-
-    return TEMPLATE.sub(_sub, template)