Add support for listing task instances

New client methods:
  ListTaskInstances
  GetTaskInstance

New example script:
  list_instances.py
diff --git a/README.md b/README.md
index 19f7660..9c4b47f 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,8 @@
 
 ./list_tasks.py --apikey APIKEY
 
+./list_instances.py --apikey APIKEY
+
 ./csv_uploader.py --apikey APIKEY file.csv
 
 Each script also supports other flags.  Use --help to see them.
diff --git a/client.py b/client.py
index 0d24ad1..0738c31 100644
--- a/client.py
+++ b/client.py
@@ -152,3 +152,37 @@
     if r.content:
       return r.json()
     return
+
+  def ListTaskInstances(self, page=1):
+    """Fetches a list of tasks.
+
+    Args:
+      page: Which page of results to return.
+
+    Returns:
+      A JSON encoded list of task instances.
+
+    Raises:
+      HTTPError: a 4XX client error or 5XX server error response was returned.
+    """
+    r = requests.get(self._Url('instances'), headers=self.headers,
+                     params={'page': page})
+    r.raise_for_status()
+    return r.json()
+
+  def GetTaskInstance(self, task_instance_id):
+    """Fetches a single task.
+
+    Args:
+      task_instance_id: An integer id for the task instance.
+
+    Returns:
+        A JSON encoded task instance.
+
+    Raises:
+      HTTPError: a 4XX client error or 5XX server error response was returned.
+    """
+    r = requests.get(self._Url('instances/%d' % task_instance_id),
+                     headers=self.headers)
+    r.raise_for_status()
+    return r.json()
diff --git a/list_instances.py b/list_instances.py
new file mode 100755
index 0000000..ff71b55
--- /dev/null
+++ b/list_instances.py
@@ -0,0 +1,60 @@
+# Copyright 2016 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.
+
+"""List all task instances for your Organization via the GCI API."""
+
+import argparse
+import re
+
+import client as gciclient
+
+
+argparser = argparse.ArgumentParser(description='GCI Task Instances')
+argparser.add_argument('--apikey', type=str, nargs='?', required=True,
+                       help='api key')
+argparser.add_argument('--url', type=str, nargs='?',
+                       default='https://codein.withgoogle.com',
+                       help='server url')
+argparser.add_argument('--debug', action='store_true',
+                       help='enable debug request logging')
+
+FLAGS = argparser.parse_args()
+
+
+def main():
+  client = gciclient.GCIAPIClient(
+      auth_token=FLAGS.apikey,
+      url_prefix=FLAGS.url,
+      debug=FLAGS.debug)
+
+  next_page = 1
+  while next_page > 0:
+    instances = client.ListTaskInstances(page=next_page)
+    for ti in instances['results']:
+      print '\t'.join([
+          str(ti['id']),
+          ti['status'],
+          ti['student_display_name'],
+          ti['task_definition_name']
+      ])
+
+    next_page = 0
+    if instances['next']:
+      result = re.search(r'page=(\d+)', instances['next'])
+      if result:
+        next_page = result.group(1)
+
+
+if __name__ == '__main__':
+  main()