Merge in better json error handling from Ali Afshar
diff --git a/apiclient/ext/authtools.py b/apiclient/ext/authtools.py
new file mode 100644
index 0000000..5398bd8
--- /dev/null
+++ b/apiclient/ext/authtools.py
@@ -0,0 +1,140 @@
+# Copyright (C) 2010 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Command-line tools for authenticating via OAuth 1.0
+
+Do the OAuth 1.0 Three Legged Dance for
+a command line application. Stores the generated
+credentials in a common file that is used by
+other example apps in the same directory.
+"""
+
+__author__ = 'jcgregorio@google.com (Joe Gregorio)'
+__all__ = ["run"]
+
+import BaseHTTPServer
+import logging
+import pickle
+import socket
+import sys
+
+from optparse import OptionParser
+from apiclient.oauth import RequestError
+
+try:
+    from urlparse import parse_qsl
+except ImportError:
+    from cgi import parse_qsl
+
+
+class ClientRedirectServer(BaseHTTPServer.HTTPServer):
+  """A server to handle OAuth 1.0 redirects back to localhost.
+
+  Waits for a single request and parses the query parameters
+  into query_params and then stops serving.
+  """
+  query_params = {}
+
+
+class ClientRedirectHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+  """A handler for OAuth 2.0 redirects back to localhost.
+
+  Waits for a single request and parses the query parameters
+  into the servers query_params and then stops serving.
+  """
+
+  def do_GET(s):
+    """Handle a GET request
+
+    Parses the query parameters and prints a message
+    if the flow has completed. Note that we can't detect
+    if an error occurred.
+    """
+    s.send_response(200)
+    s.send_header("Content-type", "text/html")
+    s.end_headers()
+    query = s.path.split('?', 1)[-1]
+    query = dict(parse_qsl(query))
+    s.server.query_params = query
+    s.wfile.write("<html><head><title>Authentication Status</title></head>")
+    s.wfile.write("<body><p>The authentication flow has completed.</p>")
+    s.wfile.write("</body></html>")
+
+  def log_message(self, format, *args):
+    """Do not log messages to stdout while running as command line program."""
+    pass
+
+
+def run(flow, filename):
+  """Core code for a command-line application.
+  """
+  parser = OptionParser()
+  parser.add_option("-f", "--file", dest="filename",
+      default=filename, help="write credentials to FILE", metavar="FILE")
+  parser.add_option("-p", "--no_local_web_server", dest="localhost",
+      action="store_false",
+      default=True,
+      help="Do not run a web server on localhost to handle redirect URIs")
+  parser.add_option("-w", "--local_web_server", dest="localhost",
+      action="store_true",
+      default=True,
+      help="Run a web server on localhost to handle redirect URIs")
+
+  (options, args) = parser.parse_args()
+
+  host_name = 'localhost'
+  port_numbers = [8080, 8090]
+  if options.localhost:
+    server_class = BaseHTTPServer.HTTPServer
+    try:
+      port_number = port_numbers[0]
+      httpd = server_class((host_name, port_number), ClientRedirectHandler)
+    except socket.error:
+      port_number = port_numbers[1]
+      try:
+        httpd = server_class((host_name, port_number), ClientRedirectHandler)
+      except socket.error:
+        options.localhost = False
+
+  if options.localhost:
+    oauth_callback = 'http://%s:%s/' % (host_name, port_number)
+  else:
+    oauth_callback = 'oob'
+  authorize_url = flow.step1_get_authorize_url(oauth_callback)
+
+  print 'Go to the following link in your browser:'
+  print authorize_url
+  print
+
+  if options.localhost:
+    httpd.handle_request()
+    if 'error' in httpd.query_params:
+      sys.exit('Authentication request was rejected.')
+    if 'oauth_verifier' in httpd.query_params:
+      code = httpd.query_params['oauth_verifier']
+  else:
+    accepted = 'n'
+    while accepted.lower() == 'n':
+      accepted = raw_input('Have you authorized me? (y/n) ')
+    code = raw_input('What is the verification code? ').strip()
+
+  try:
+    credentials = flow.step2_exchange(code)
+  except RequestError:
+    sys.exit('The authentication has failed.')
+
+  f = open(filename, 'w')
+  f.write(pickle.dumps(credentials))
+  f.close()
+  print "You have successfully authenticated."
diff --git a/apiclient/http.py b/apiclient/http.py
index d616c07..31a8fe8 100644
--- a/apiclient/http.py
+++ b/apiclient/http.py
@@ -12,8 +12,8 @@
     'HttpRequest', 'RequestMockBuilder'
     ]
 
-from httplib2 import Response
-from apiclient.model import JsonModel
+import httplib2
+from model import JsonModel
 
 
 class HttpRequest(object):
@@ -86,7 +86,7 @@
     self.content = content
     self.postproc = postproc
     if resp is None:
-      self.resp = Response({'status': 200, 'reason': 'OK'})
+      self.resp = httplib2.Response({'status': 200, 'reason': 'OK'})
     if 'reason' in self.resp:
       self.resp.reason = self.resp['reason']
 
diff --git a/docs/apiclient.json.html b/docs/apiclient.anyjson.html
similarity index 89%
rename from docs/apiclient.json.html
rename to docs/apiclient.anyjson.html
index 00c56ab..df64fcd 100644
--- a/docs/apiclient.json.html
+++ b/docs/apiclient.anyjson.html
@@ -1,14 +1,14 @@
 
 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-<html><head><title>Python: module apiclient.json</title>
+<html><head><title>Python: module apiclient.anyjson</title>
 </head><body bgcolor="#f0f0f8">
 
 <table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading">
 <tr bgcolor="#7799ee">
 <td valign=bottom>&nbsp;<br>
-<font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.json</strong></big></big></font></td
+<font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.anyjson</strong></big></big></font></td
 ><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/json.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/json.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/anyjson.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/anyjson.py</a></font></td></tr></table>
     <p><tt>Utility&nbsp;module&nbsp;to&nbsp;import&nbsp;a&nbsp;JSON&nbsp;module<br>
 &nbsp;<br>
 Hides&nbsp;all&nbsp;the&nbsp;messy&nbsp;details&nbsp;of&nbsp;exactly&nbsp;where<br>
diff --git a/docs/apiclient.contrib.html b/docs/apiclient.contrib.html
index 513802a..488fdaa 100644
--- a/docs/apiclient.contrib.html
+++ b/docs/apiclient.contrib.html
@@ -8,7 +8,7 @@
 <td valign=bottom>&nbsp;<br>
 <font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.contrib</strong></big></big></font></td
 ><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/contrib/__init__.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/contrib/__init__.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/contrib/__init__.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/contrib/__init__.py</a></font></td></tr></table>
     <p></p>
 <p>
 <table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
diff --git a/docs/apiclient.discovery.html b/docs/apiclient.discovery.html
index 7936c9f..c7d0c54 100644
--- a/docs/apiclient.discovery.html
+++ b/docs/apiclient.discovery.html
@@ -8,7 +8,7 @@
 <td valign=bottom>&nbsp;<br>
 <font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.discovery</strong></big></big></font></td
 ><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/discovery.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/discovery.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/discovery.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/discovery.py</a></font></td></tr></table>
     <p><tt>Client&nbsp;for&nbsp;discovery&nbsp;based&nbsp;APIs<br>
 &nbsp;<br>
 A&nbsp;client&nbsp;library&nbsp;for&nbsp;Google's&nbsp;discovery<br>
diff --git a/docs/apiclient.errors.html b/docs/apiclient.errors.html
index af69a51..73d3765 100644
--- a/docs/apiclient.errors.html
+++ b/docs/apiclient.errors.html
@@ -8,7 +8,7 @@
 <td valign=bottom>&nbsp;<br>
 <font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.errors</strong></big></big></font></td
 ><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/errors.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/errors.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/errors.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/errors.py</a></font></td></tr></table>
     <p><tt>Errors&nbsp;for&nbsp;the&nbsp;library.<br>
 &nbsp;<br>
 All&nbsp;exceptions&nbsp;defined&nbsp;by&nbsp;the&nbsp;library<br>
diff --git a/docs/apiclient.ext.appengine.html b/docs/apiclient.ext.appengine.html
index 90cd6ca..a55ec26 100644
--- a/docs/apiclient.ext.appengine.html
+++ b/docs/apiclient.ext.appengine.html
@@ -8,7 +8,7 @@
 <td valign=bottom>&nbsp;<br>
 <font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.<a href="apiclient.ext.html"><font color="#ffffff">ext</font></a>.appengine</strong></big></big></font></td
 ><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/ext/appengine.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/ext/appengine.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/appengine.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/appengine.py</a></font></td></tr></table>
     <p><tt>Utilities&nbsp;for&nbsp;Google&nbsp;App&nbsp;Engine<br>
 &nbsp;<br>
 Utilities&nbsp;for&nbsp;making&nbsp;it&nbsp;easier&nbsp;to&nbsp;use&nbsp;the<br>
diff --git a/docs/apiclient.ext.django_orm.html b/docs/apiclient.ext.django_orm.html
index 7832fcf..163f80e 100644
--- a/docs/apiclient.ext.django_orm.html
+++ b/docs/apiclient.ext.django_orm.html
@@ -8,7 +8,7 @@
 <td valign=bottom>&nbsp;<br>
 <font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.<a href="apiclient.ext.html"><font color="#ffffff">ext</font></a>.django_orm</strong></big></big></font></td
 ><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/ext/django_orm.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/ext/django_orm.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/django_orm.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/django_orm.py</a></font></td></tr></table>
     <p></p>
 <p>
 <table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
diff --git a/docs/apiclient.ext.html b/docs/apiclient.ext.html
index f9b24a0..3a77941 100644
--- a/docs/apiclient.ext.html
+++ b/docs/apiclient.ext.html
@@ -8,7 +8,7 @@
 <td valign=bottom>&nbsp;<br>
 <font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.ext</strong></big></big></font></td
 ><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/ext/__init__.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/ext/__init__.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/__init__.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/__init__.py</a></font></td></tr></table>
     <p></p>
 <p>
 <table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
diff --git a/docs/apiclient.html b/docs/apiclient.html
index 6b8dfbb..bf91ae5 100644
--- a/docs/apiclient.html
+++ b/docs/apiclient.html
@@ -8,7 +8,7 @@
 <td valign=bottom>&nbsp;<br>
 <font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong>apiclient</strong></big></big></font></td
 ><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/__init__.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/__init__.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/__init__.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/__init__.py</a></font></td></tr></table>
     <p></p>
 <p>
 <table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
@@ -17,13 +17,14 @@
 <font color="#ffffff" face="helvetica, arial"><big><strong>Package Contents</strong></big></font></td></tr>
     
 <tr><td bgcolor="#aa55cc"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
-<td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top><a href="apiclient.contrib.html"><strong>contrib</strong>&nbsp;(package)</a><br>
+<td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top><a href="apiclient.anyjson.html">anyjson</a><br>
+<a href="apiclient.contrib.html"><strong>contrib</strong>&nbsp;(package)</a><br>
 <a href="apiclient.discovery.html">discovery</a><br>
 </td><td width="25%" valign=top><a href="apiclient.errors.html">errors</a><br>
 <a href="apiclient.ext.html"><strong>ext</strong>&nbsp;(package)</a><br>
-</td><td width="25%" valign=top><a href="apiclient.http.html">http</a><br>
-<a href="apiclient.json.html">json</a><br>
-</td><td width="25%" valign=top><a href="apiclient.model.html">model</a><br>
+<a href="apiclient.http.html">http</a><br>
+</td><td width="25%" valign=top><a href="apiclient.json.html">json</a><br>
+<a href="apiclient.model.html">model</a><br>
 <a href="apiclient.oauth.html">oauth</a><br>
-</td></tr></table></td></tr></table>
+</td><td width="25%" valign=top></td></tr></table></td></tr></table>
 </body></html>
\ No newline at end of file
diff --git a/docs/apiclient.http.html b/docs/apiclient.http.html
index 9810823..19883b6 100644
--- a/docs/apiclient.http.html
+++ b/docs/apiclient.http.html
@@ -8,7 +8,7 @@
 <td valign=bottom>&nbsp;<br>
 <font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.http</strong></big></big></font></td
 ><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/http.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/http.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/http.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/http.py</a></font></td></tr></table>
     <p><tt>Classes&nbsp;to&nbsp;encapsulate&nbsp;a&nbsp;single&nbsp;HTTP&nbsp;request.<br>
 &nbsp;<br>
 The&nbsp;classes&nbsp;implement&nbsp;a&nbsp;command&nbsp;pattern,&nbsp;with&nbsp;every<br>
diff --git a/docs/apiclient.model.html b/docs/apiclient.model.html
index 32ea8b9..585e348 100644
--- a/docs/apiclient.model.html
+++ b/docs/apiclient.model.html
@@ -8,7 +8,7 @@
 <td valign=bottom>&nbsp;<br>
 <font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.model</strong></big></big></font></td
 ><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/model.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/model.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/model.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/model.py</a></font></td></tr></table>
     <p><tt>Model&nbsp;objects&nbsp;for&nbsp;requests&nbsp;and&nbsp;responses<br>
 &nbsp;<br>
 Each&nbsp;API&nbsp;may&nbsp;support&nbsp;one&nbsp;or&nbsp;more&nbsp;serializations,&nbsp;such<br>
diff --git a/docs/apiclient.oauth.html b/docs/apiclient.oauth.html
index e55af8c..e5efa2d 100644
--- a/docs/apiclient.oauth.html
+++ b/docs/apiclient.oauth.html
@@ -8,7 +8,7 @@
 <td valign=bottom>&nbsp;<br>
 <font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.oauth</strong></big></big></font></td
 ><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/oauth.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/oauth.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/oauth.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/oauth.py</a></font></td></tr></table>
     <p><tt>Utilities&nbsp;for&nbsp;OAuth.<br>
 &nbsp;<br>
 Utilities&nbsp;for&nbsp;making&nbsp;it&nbsp;easier&nbsp;to&nbsp;work&nbsp;with&nbsp;OAuth.</tt></p>
diff --git a/docs/build.sh b/docs/build.sh
index 1ea5060..0a08b71 100755
--- a/docs/build.sh
+++ b/docs/build.sh
@@ -9,8 +9,8 @@
 # Notes: You may have to update the location of the
 #        App Engine library for your local system.
 
-set GOOGLE_APPENGINE=$HOME/projects/google_appengine/
-set DJANGO_SETTINGS_MODULE=fakesettings
-set PYTHONPATH=`pwd`/..:$GOOGLE_APPENGINE
+export GOOGLE_APPENGINE=$HOME/projects/google_appengine/
+export DJANGO_SETTINGS_MODULE=fakesettings
+export PYTHONPATH=`pwd`/..:$GOOGLE_APPENGINE
 find ../apiclient/ -name "*.py" | sed "s/\/__init__.py//" | sed "s/\.py//" | sed "s/^\.\.\///" | sed "s#/#.#g" | xargs pydoc -w
 
diff --git a/functional_tests/test_services.py b/functional_tests/test_services.py
index 17ee601..37a005e 100644
--- a/functional_tests/test_services.py
+++ b/functional_tests/test_services.py
@@ -131,11 +131,11 @@
     follower_count = following['totalResults']
     self.assertTrue(follower_count > 10000, follower_count)
 
-  def test_follower_count_is_zero_for_user_with_hidden_follower_count(self):
+  def test_follower_count_is_missing_for_user_with_hidden_follower_count(self):
     buzz = build('buzz', 'v1')
     following = buzz.people().list(userId='adewale', groupId='@followers').execute()
 
-    self.assertEquals(0, following['totalResults'])
+    self.assertFalse('totalResults' in following)
 
 
 class BuzzAuthenticatedFunctionalTest(unittest.TestCase):
diff --git a/oacurl.py b/oacurl.py
index 68b4ca9..64493b5 100644
--- a/oacurl.py
+++ b/oacurl.py
@@ -11,13 +11,18 @@
 # 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 optparse
+from apiclient.discovery import build
+from apiclient.oauth import FlowThreeLegged
+
+import datetime
 import httplib2
 import logging
 import oauth_wrap
+import optparse
 import os
 import sys
 
+
 def load_properties_file(path):
 	properties = {}
 	for line in open(path):
@@ -29,6 +34,20 @@
 		properties[key.strip()] = value.strip()
 	return properties
 
+
+def save_properties(consumer_key, consumer_secret, token_key, token_secret, path):
+	file = open(path, 'w')
+	
+	# File format and order is based on oacurl.java's defaults
+	now = datetime.datetime.today()
+	now_string = now.strftime('%a %b %d %H:%m:%S %Z %Y')
+	file.write('#%s\n' % now_string)
+	file.write('consumerSecret=%s\n' % consumer_secret)
+	file.write('accessToken=%s\n' % token_key)
+	file.write('consumerKey=%s\n' % consumer_key)
+	file.write('accessTokenSecret=%s\n' % token_secret)
+	file.close()
+
 def fetch(url):
 	logging.debug('Now fetching: %s' % url)
 	
@@ -38,6 +57,7 @@
 		
 		print 'You are not logged in'
 		sys.exit(1)
+
 	properties = load_properties_file(path)
 	oauth_parameters = {
 		'consumer_key': properties['consumerKey'], 
@@ -52,7 +72,48 @@
 	
 	return response,content
 
+
+def buzz_login():
+	buzz_discovery = build("buzz", "v1").auth_discovery()
+
+	flow = FlowThreeLegged(buzz_discovery,
+	                       consumer_key='anonymous',
+	                       consumer_secret='anonymous',
+	                       user_agent='google-api-client-python-buzz-cmdline/1.0',
+	                       domain='anonymous',
+	                       scope='https://www.googleapis.com/auth/buzz',
+	                       xoauth_displayname='oacurl.py')
+
+	authorize_url = flow.step1_get_authorize_url()
+
+	print 'Go to the following link in your browser:'
+	print authorize_url
+	print
+
+	accepted = 'n'
+	while accepted.lower() == 'n':
+	    accepted = raw_input('Have you authorized me? (y/n) ')
+	verification = raw_input('What is the verification code? ').strip()
+
+	credentials = flow.step2_exchange(verification)
+	path = os.path.expanduser('~/.oacurl.properties')
+	save_properties('anonymous', 'anonymous', credentials.token.key, credentials.token.secret,path)
+	
+	
+def generic_login():
+	#TODO(ade) Implement support for other services
+	print 'Support for services other than Buzz is not implemented yet. Sorry.'
+
+def login(options):
+	if options.buzz:
+		buzz_login()
+	else:
+		generic_login()
+
+
 def get_command(args):
+	if args[0] == 'login':
+		return 'login'
 	if args[0] == 'fetch':
 		return 'fetch'
 	return None
@@ -69,6 +130,7 @@
 	parser.set_defaults(verbose=False)
 	parser.add_option('-v', '--verbose', action='store_true', dest='verbose')
 	parser.add_option('-q', '--quiet', action='store_false', dest='verbose')
+	parser.add_option('--buzz', action='store_true', dest='buzz')
 	
 	(options, args) = parser.parse_args()
 
@@ -85,6 +147,10 @@
 		response, content = fetch(args[1])
 		print response
 		print content
+		return
+	
+	if command == 'login':
+		login(options)
 
 if __name__ == '__main__':
 	main()
\ No newline at end of file
diff --git a/runtests.py b/runtests.py
index ecd53b1..6fd426d 100644
--- a/runtests.py
+++ b/runtests.py
@@ -42,8 +42,11 @@
   cleanup()
 
 def main():
+  if '--help' in sys.argv:
+    print 'Usage: python runtests.py [--q|-quiet|--v|-verbose] [tests|functional_tests|contrib_tests]'
+    return
   verbosity = 1
-  if "-q" in sys.argv or '--quiet' in sys.argv:
+  if '-q' in sys.argv or '--quiet' in sys.argv:
     verbosity = 0
   if "-v" in sys.argv or '--verbose' in sys.argv:
     verbosity = 2
diff --git a/samples/api-python-client-doc/main.py b/samples/api-python-client-doc/main.py
index d5ae558..14f222e 100755
--- a/samples/api-python-client-doc/main.py
+++ b/samples/api-python-client-doc/main.py
@@ -73,6 +73,7 @@
       <li><a href='/diacritize/v1'>diacritize</a>
       <li><a href='/translate/v2'>translate</a>
       <li><a href='/prediction/v1.1'>prediction</a>
+      <li><a href='/shopping/v1'>shopping</a>
     </ul>
     """)
 
diff --git a/samples/buzz/three_legged_dance.py b/samples/buzz/three_legged_dance.py
index 9972455..2dc26e5 100644
--- a/samples/buzz/three_legged_dance.py
+++ b/samples/buzz/three_legged_dance.py
@@ -24,8 +24,8 @@
 
 from apiclient.discovery import build
 from apiclient.oauth import FlowThreeLegged
+from apiclient.ext.authtools import run
 
-import pickle
 
 buzz_discovery = build("buzz", "v1").auth_discovery()
 
@@ -37,19 +37,4 @@
                        scope='https://www.googleapis.com/auth/buzz',
                        xoauth_displayname='Google API Client Example App')
 
-authorize_url = flow.step1_get_authorize_url()
-
-print 'Go to the following link in your browser:'
-print authorize_url
-print
-
-accepted = 'n'
-while accepted.lower() == 'n':
-    accepted = raw_input('Have you authorized me? (y/n) ')
-verification = raw_input('What is the verification code? ').strip()
-
-credentials = flow.step2_exchange(verification)
-
-f = open('buzz.dat', 'w')
-f.write(pickle.dumps(credentials))
-f.close()
+run(flow, 'buzz.dat')
diff --git a/samples/latitude/three_legged_dance.py b/samples/latitude/three_legged_dance.py
index 56f4f59..45595bc 100644
--- a/samples/latitude/three_legged_dance.py
+++ b/samples/latitude/three_legged_dance.py
@@ -24,8 +24,7 @@
 
 from apiclient.discovery import build
 from apiclient.oauth import FlowThreeLegged
-
-import pickle
+from apiclient.ext.authtools import run
 
 moderator_discovery = build("latitude", "v1").auth_discovery()
 
@@ -44,19 +43,4 @@
                        granularity='city'
                        )
 
-authorize_url = flow.step1_get_authorize_url()
-
-print 'Go to the following link in your browser:'
-print authorize_url
-print
-
-accepted = 'n'
-while accepted.lower() == 'n':
-    accepted = raw_input('Have you authorized me? (y/n) ')
-verification = raw_input('What is the verification code? ').strip()
-
-credentials = flow.step2_exchange(verification)
-
-f = open('latitude.dat', 'w')
-f.write(pickle.dumps(credentials))
-f.close()
+run(flow, 'latitude.dat')
diff --git a/samples/moderator/three_legged_dance.py b/samples/moderator/three_legged_dance.py
index fbc90ec..32e624d 100644
--- a/samples/moderator/three_legged_dance.py
+++ b/samples/moderator/three_legged_dance.py
@@ -24,8 +24,8 @@
 
 from apiclient.discovery import build
 from apiclient.oauth import FlowThreeLegged
+from apiclient.ext.authtools import run
 
-import pickle
 
 moderator_discovery = build("moderator", "v1").auth_discovery()
 
@@ -38,19 +38,4 @@
                        #scope='tag:google.com,2010:auth/moderator',
                        xoauth_displayname='Google API Client Example App')
 
-authorize_url = flow.step1_get_authorize_url()
-
-print 'Go to the following link in your browser:'
-print authorize_url
-print
-
-accepted = 'n'
-while accepted.lower() == 'n':
-    accepted = raw_input('Have you authorized me? (y/n) ')
-verification = raw_input('What is the verification code? ').strip()
-
-credentials = flow.step2_exchange(verification)
-
-f = open('moderator.dat', 'w')
-f.write(pickle.dumps(credentials))
-f.close()
+run(flow, 'moderator.dat')
diff --git a/samples/shopping/main.py b/samples/shopping/main.py
new file mode 100644
index 0000000..ce9057b
--- /dev/null
+++ b/samples/shopping/main.py
@@ -0,0 +1,33 @@
+#!/usr/bin/python2.4
+# -*- coding: utf-8 -*-
+#
+# Copyright 2010 Google Inc. All Rights Reserved.
+
+"""Simple command-line example for The Google Search
+API for Shopping.
+
+Command-line application that does a search for products.
+"""
+
+__author__ = 'jcgregorio@google.com (Joe Gregorio)'
+
+from apiclient.discovery import build
+
+import pprint
+
+# Uncomment the next line to get very detailed logging
+# httplib2.debuglevel = 4
+
+
+def main():
+  p = build("shopping", "v1",
+            developerKey="AIzaSyDRRpR3GS1F1_jKNNM9HCNd2wJQyPG3oN0")
+  res = p.products().list(
+      country='US',
+      source='public',
+      q='logitech revue'
+      ).execute()
+  pprint.pprint(res)
+
+if __name__ == '__main__':
+  main()
diff --git a/samples/threadqueue/three_legged_dance.py b/samples/threadqueue/three_legged_dance.py
index b833e3a..12c495b 100644
--- a/samples/threadqueue/three_legged_dance.py
+++ b/samples/threadqueue/three_legged_dance.py
@@ -24,8 +24,8 @@
 
 from apiclient.discovery import build
 from apiclient.oauth import FlowThreeLegged
+from apiclient.ext.authtools import run
 
-import pickle
 
 moderator_discovery = build("moderator", "v1").auth_discovery()
 
@@ -38,19 +38,4 @@
                        #scope='tag:google.com,2010:auth/moderator',
                        xoauth_displayname='Google API Client Example App')
 
-authorize_url = flow.step1_get_authorize_url()
-
-print 'Go to the following link in your browser:'
-print authorize_url
-print
-
-accepted = 'n'
-while accepted.lower() == 'n':
-    accepted = raw_input('Have you authorized me? (y/n) ')
-verification = raw_input('What is the verification code? ').strip()
-
-credentials = flow.step2_exchange(verification)
-
-f = open('moderator.dat', 'w')
-f.write(pickle.dumps(credentials))
-f.close()
+run(flow, 'moderator.dat')