Removes python client. https://reviews.apache.org/r/45976
diff --git a/.gitignore b/.gitignore
index 267def7..a9cec8c 100755
--- a/.gitignore
+++ b/.gitignore
@@ -20,7 +20,6 @@
 */gwt-unitCache
 war/WEB-INF
 *.old
-*.log*
 .DS_Store
 
 ### IntelliJ Idea
@@ -50,7 +49,6 @@
 ### Generated Sources
 **/generated/
 ### Gwt Testing
-wave/gwt-unitCache
 ### config
 wave/local.net.cfg.lua
 wave/config/wave.conf
diff --git a/LICENSE b/LICENSE
index a2be50d..6bf7059 100644
--- a/LICENSE
+++ b/LICENSE
@@ -201,52 +201,6 @@
    limitations under the License.
 
 ***THE FOLLOWING LICENSE APPLIES TO***
-- The OAuth python library located at /src/python/api/oauth/
-  Copyright (c) 2007 Andy Smith
-
-The MIT License
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
-***THE FOLLOWING LICENSE APPLIES TO***
-- SimpleJSON located at /src/python/api/simplejson/
-  Copyright (c) 2006 Bob Ippolito
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
-***THE FOLLOWING LICENSE APPLIES TO***
 - Protobuf Descriptors located at /src/google/protobuf/descriptor.proto
 
 Protocol Buffers - Google's data interchange format
diff --git a/wave/dist/CHANGES b/wave/dist/CHANGES
index cf47949..a2d6c8e 100644
--- a/wave/dist/CHANGES
+++ b/wave/dist/CHANGES
@@ -437,147 +437,6 @@
 Date:   Sat Jan 18 16:06:56 2014 +0200
 
     Merge branch 'wave-0.4-release' into master
-    
-    Conflicts:
-    	.classpath
-    	.gitignore
-    	.project_template
-    	CHANGES
-    	NOTICE
-    	README
-    	build.properties
-    	build.xml
-    	jaas.config
-    	prosody.cfg.lua.example
-    	proto_src/org/waveprotocol/box/attachment/AttachmentProto.java
-    	proto_src/org/waveprotocol/box/server/persistence/protos/ProtoAccountStoreData.java
-    	run-server.bat
-    	server-config.xml
-    	server.federation.config
-    	src/com/google/gwt/build.xml
-    	src/com/google/gwt/websockets/WebSockets.gwt.xml
-    	src/com/google/wave/api/data/Data.gwt.xml
-    	src/com/google/wave/api/robot/Robot.gwt.xml
-    	src/org/waveprotocol/box/server/frontend/WaveletInfo.java
-    	src/org/waveprotocol/box/server/persistence/protos/delta-store.proto
-    	src/org/waveprotocol/box/server/waveserver/SimpleSearchProviderImpl.java
-    	src/org/waveprotocol/box/server/waveserver/Wave.java
-    	src/org/waveprotocol/box/webclient/search/i18n/SearchPresenterMessages_sl.properties
-    	src/org/waveprotocol/box/webclient/search/i18n/SearchWidgetMessages_sl.properties
-    	src/org/waveprotocol/box/webclient/search/mock/search.html
-    	src/org/waveprotocol/protobuf/build.xml
-    	src/org/waveprotocol/pst/templates/api/properties
-    	src/org/waveprotocol/pst/templates/builder/properties
-    	src/org/waveprotocol/pst/templates/gson/properties
-    	src/org/waveprotocol/pst/templates/jso/properties
-    	src/org/waveprotocol/pst/templates/pojo/properties
-    	src/org/waveprotocol/pst/templates/proto/properties
-    	src/org/waveprotocol/pst/templates/util/properties
-    	src/org/waveprotocol/wave/client/build.xml
-    	src/org/waveprotocol/wave/client/common/build.xml
-    	src/org/waveprotocol/wave/client/scheduler/build.xml
-    	src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/color/ComplexColorPicker.css
-    	src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/color/SimpleColorPicker.css
-    	src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/color/i18n/ColorPickerMessages_en.properties
-    	src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/color/i18n/ColorPickerMessages_es.properties
-    	src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/i18n/LinkerMessages_fr.properties
-    	src/org/waveprotocol/wave/common/build.xml
-    	src/org/waveprotocol/wave/communication/build.xml
-    	src/org/waveprotocol/wave/concurrencycontrol/build.xml
-    	src/org/waveprotocol/wave/crypto/build.xml
-    	src/org/waveprotocol/wave/diff/build.xml
-    	src/org/waveprotocol/wave/federation/build.xml
-    	src/org/waveprotocol/wave/media/build.xml
-    	src/org/waveprotocol/wave/model/build.xml
-    	src/org/waveprotocol/wave/testing/build.xml
-    	src/org/waveprotocol/wave/util/build.xml
-    	src/python/api/__init__.py
-    	src/python/api/appengine_robot_runner.py
-    	src/python/api/blip.py
-    	src/python/api/blip_test.py
-    	src/python/api/commandline_robot_runner.py
-    	src/python/api/commandline_robot_runner_test.py
-    	src/python/api/django_oauth.py
-    	src/python/api/element.py
-    	src/python/api/element_test.py
-    	src/python/api/errors.py
-    	src/python/api/events.py
-    	src/python/api/module_test_runner.py
-    	src/python/api/ops.py
-    	src/python/api/ops_test.py
-    	src/python/api/robot.py
-    	src/python/api/robot_test.py
-    	src/python/api/run_unit_tests.py
-    	src/python/api/search.py
-    	src/python/api/search_test.py
-    	src/python/api/testdata.py
-    	src/python/api/util.py
-    	src/python/api/util_test.py
-    	src/python/api/wavelet.py
-    	src/python/api/wavelet_test.py
-    	src/python/api/waveservice.py
-    	src/python/api/waveservice_test.py
-    	test/org/waveprotocol/wave/concurrencycontrol/Tests.gwt.xml
-    	test/org/waveprotocol/wave/model/experimental/schema/bad1.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad10.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad11.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad12.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad13.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad14.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad15.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad16.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad17.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad18.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad19.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad2.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad20.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad21.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad22.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad23.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad24.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad3.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad4.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad5.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad6.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad7.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad8.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/bad9.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/good1.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/good10.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/good11.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/good12.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/good13.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/good14.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/good15.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/good16.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/good2.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/good3.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/good4.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/good5.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/good6.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/good7.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/good8.schema
-    	test/org/waveprotocol/wave/model/experimental/schema/good9.schema
-    	test/org/waveprotocol/wave/model/supplement/tests.gwt.xml
-    	test/org/waveprotocol/wave/model/tests.gwt.xml
-    	third_party/codegen/gwt/README.google
-    	third_party/codegen/gwt/gwt-dev.jar
-    	third_party/codegen/gwt/gwt-user.jar
-    	third_party/runtime/bouncycastle/LICENSE.html
-    	third_party/runtime/gson/LICENSE
-    	third_party/runtime/guava/README.google
-    	third_party/runtime/jetty/README.google
-    	third_party/runtime/libidn/LICENSE
-    	third_party/runtime/libidn/README.google
-    	third_party/runtime/libidn/libidn-1.26.jar
-    	third_party/runtime/mongo-driver/README.google
-    	third_party/runtime/protobuf/README.google
-    	third_party/test/jmock/README.google
-    	third_party/test/mockito/README.google
-    	third_party/test/mockito/mockito-all-1.9.5.jar
-    	tools/eclipse-launch/src.org.waveprotocol.wave.client.editor.examples.img.Img_Example-launch
-    	tools/eclipse-launch/src.org.waveprotocol.wave.client.editor.harness.EditorTest-launch
-    	war/.gitignore
 
 commit 0b550672da3c923fbc6be0a963d2bf54c735b783
 Author: Yuri Zelikov <vega113@gmail.com>
@@ -911,45 +770,6 @@
 Date:   Tue Aug 27 19:14:34 2013 +0000
 
     Merge branch 'trunk' into 0.4-release-staging
-    
-    Conflicts:
-    	README
-    	src/org/waveprotocol/box/waveimport/WaveExport.java
-    	src/org/waveprotocol/box/waveimport/WaveImport.java
-    	src/org/waveprotocol/box/waveimport/google/RobotApi.java
-    	src/org/waveprotocol/box/waveimport/google/RobotSearchDigest.java
-    	src/org/waveprotocol/box/waveimport/google/RobotSearchDigestGsonImpl.java
-    	src/org/waveprotocol/box/waveimport/google/RobotSearchDigestImpl.java
-    	src/org/waveprotocol/box/waveimport/google/RobotSearchDigestUtil.java
-    	src/org/waveprotocol/box/waveimport/google/oauth/NeedNewOAuthTokenException.java
-    	src/org/waveprotocol/box/waveimport/google/oauth/OAuthCredentials.java
-    	src/org/waveprotocol/box/waveimport/google/oauth/OAuthRequestHelper.java
-    	src/org/waveprotocol/box/waveimport/google/oauth/OAuthedFetchService.java
-    	src/org/waveprotocol/box/waveimport/google/oauth/StableUserId.java
-    	src/org/waveprotocol/box/waveimport/google/oauth/UserContext.java
-    	src/org/waveprotocol/box/webclient/client/i18n/SessionMessages_es.properties
-    	src/org/waveprotocol/box/webclient/client/i18n/SessionMessages_fr.properties
-    	src/org/waveprotocol/box/webclient/client/i18n/WebClientMessages_es.properties
-    	src/org/waveprotocol/box/webclient/client/i18n/WebClientMessages_fr.properties
-    	src/org/waveprotocol/box/webclient/search/i18n/SearchPresenterMessages_sl.properties
-    	src/org/waveprotocol/box/webclient/search/i18n/SearchWidgetMessages_es.properties
-    	src/org/waveprotocol/box/webclient/search/i18n/SearchWidgetMessages_sl.properties
-    	src/org/waveprotocol/box/webclient/widget/error/i18n/ErrorMessages_es.properties
-    	src/org/waveprotocol/wave/client/wavepanel/impl/edit/i18n/ActionMessages_es.properties
-    	src/org/waveprotocol/wave/client/wavepanel/impl/menu/i18n/MenuMessages_fr.properties
-    	src/org/waveprotocol/wave/client/wavepanel/impl/menu/i18n/MenuMessages_sl.properties
-    	src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/attachment/i18n/AttachmentMessages_fr.properties
-    	src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/attachment/i18n/AttachmentMessages_sl.properties
-    	src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/gadget/i18n/GadgetCategoryMessages_es.properties
-    	src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/gadget/i18n/GadgetSelectorMessages_sl.properties
-    	src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/i18n/LinkerMessages_es.properties
-    	src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/i18n/LinkerMessages_fr.properties
-    	src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/i18n/ToolbarMessages_fr.properties
-    	src/org/waveprotocol/wave/client/wavepanel/view/dom/full/i18n/ReplyBoxMessages_es.properties
-    	src/org/waveprotocol/wave/client/wavepanel/view/dom/full/i18n/ReplyBoxMessages_fr.properties
-    	src/org/waveprotocol/wave/client/widget/profile/i18n/ProfilePopupMessages_es.properties
-    	src/org/waveprotocol/wave/migration/build.xml
-    
     git-svn-id: https://svn.apache.org/repos/asf/incubator/wave/branches/wave-0.4-release@1517927 13f79535-47bb-0310-9956-ffa450edef68
 
 commit 615d44352fccf53db12bc43829d7d7f2c2155410
diff --git a/wave/src/main/java/python/api/__init__.py b/wave/src/main/java/python/api/__init__.py
deleted file mode 100644
index a92a86c..0000000
--- a/wave/src/main/java/python/api/__init__.py
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Declares the api package."""
diff --git a/wave/src/main/java/python/api/appengine_robot_runner.py b/wave/src/main/java/python/api/appengine_robot_runner.py
deleted file mode 100644
index 776f825..0000000
--- a/wave/src/main/java/python/api/appengine_robot_runner.py
+++ /dev/null
@@ -1,204 +0,0 @@
-#!/usr/bin/python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""A module to run wave robots on app engine."""
-
-
-import logging
-import sys
-
-import events
-
-from google.appengine.api import urlfetch
-from google.appengine.ext import webapp
-from google.appengine.ext.webapp.util import run_wsgi_app
-
-
-class CapabilitiesHandler(webapp.RequestHandler):
-  """Handler to forward a request ot a handler of a robot."""
-
-  def __init__(self, method, contenttype):
-    """Initializes this handler with a specific robot."""
-    self._method = method
-    self._contenttype = contenttype
-
-  def get(self):
-    """Handles HTTP GET request."""
-    self.response.headers['Content-Type'] = self._contenttype
-    self.response.out.write(self._method())
-
-class ProfileHandler(webapp.RequestHandler):
-  """Handler to forward a request ot a handler of a robot."""
-
-  def __init__(self, method, contenttype):
-    """Initializes this handler with a specific robot."""
-    self._method = method
-    self._contenttype = contenttype
-
-  def get(self):
-    """Handles HTTP GET request."""
-    self.response.headers['Content-Type'] = self._contenttype
-    # Respond with proxied profile if name specified
-    if self.request.get('name'):
-      self.response.out.write(self._method(self.request.get('name')))
-    else:
-      self.response.out.write(self._method())
-
-class RobotEventHandler(webapp.RequestHandler):
-  """Handler for the dispatching of events to various handlers to a robot.
-
-  This handler only responds to post events with a JSON post body. Its primary
-  task is to separate out the context data from the events in the post body
-  and dispatch all events in order. Once all events have been dispatched
-  it serializes the context data and its associated operations as a response.
-  """
-
-  def __init__(self, robot):
-    """Initializes self with a specific robot."""
-    self._robot = robot
-
-  def get(self):
-    """Handles the get event for debugging.
-
-    This is useful for debugging but since event bundles tend to be
-    rather big it often won't fit for more complex requests.
-    """
-    ops = self.request.get('events')
-    if ops:
-      self.request.body = events
-      self.post()
-
-  def post(self):
-    """Handles HTTP POST requests."""
-    json_body = self.request.body
-    if not json_body:
-      # TODO(davidbyttow): Log error?
-      return
-
-    # Redirect stdout to stderr while executing handlers. This way, any stray
-    # "print" statements in bot code go to the error logs instead of breaking
-    # the JSON response sent to the HTTP channel.
-    saved_stdout, sys.stdout = sys.stdout, sys.stderr
-
-    json_body = unicode(json_body, 'utf8')
-    logging.info('Incoming: %s', json_body)
-    json_response = self._robot.process_events(json_body)
-    logging.info('Outgoing: %s', json_response)
-
-    sys.stdout = saved_stdout
-
-    # Build the response.
-    self.response.headers['Content-Type'] = 'application/json; charset=utf-8'
-    self.response.out.write(json_response.encode('utf-8'))
-
-
-def operation_error_handler(event, wavelet):
-  """Default operation error handler, logging what went wrong."""
-  if isinstance(event, events.OperationError):
-    logging.error('Previously operation failed: id=%s, message: %s',
-                  event.operation_id, event.error_message)
-
-
-def appengine_post(url, data, headers):
-  result = urlfetch.fetch(
-      method='POST',
-      url=url,
-      payload=data,
-      headers=headers,
-      deadline=10)
-  return result.status_code, result.content
-
-
-class RobotVerifyTokenHandler(webapp.RequestHandler):
-  """Handler for the token_verify request."""
-
-  def __init__(self, robot):
-    """Initializes self with a specific robot."""
-    self._robot = robot
-
-  def get(self):
-    """Handles the get event for debugging. Ops usually too long."""
-    token, st = self._robot.get_verification_token_info()
-    logging.info('token=' + token)
-    if token is None:
-      self.error(404)
-      self.response.out.write('No token set')
-      return
-    if st is not None:
-      if self.request.get('st') != st:
-        self.response.out.write('Invalid st value passed')
-        return
-    self.response.out.write(token)
-
-
-def create_robot_webapp(robot, debug=False, extra_handlers=None):
-  """Returns an instance of webapp.WSGIApplication with robot handlers."""
-  if not extra_handlers:
-    extra_handlers = []
-  return webapp.WSGIApplication([('.*/_wave/capabilities.xml',
-                                  lambda: CapabilitiesHandler(
-                                                     robot.capabilities_xml,
-                                                     'application/xml')),
-                                 ('.*/_wave/robot/profile',
-                                  lambda: ProfileHandler(
-                                                     robot.profile_json,
-                                                     'application/json')),
-                                 ('.*/_wave/robot/jsonrpc',
-                                  lambda: RobotEventHandler(robot)),
-                                 ('.*/_wave/verify_token',
-                                  lambda: RobotVerifyTokenHandler(robot)),
-                                ] + extra_handlers,
-                                debug=debug)
-
-
-def run(robot, debug=False, log_errors=True, extra_handlers=None):
-  """Sets up the webapp handlers for this robot and starts listening.
-
-    A robot is typically setup in the following steps:
-      1. Instantiate and define robot.
-      2. Register various handlers that it is interested in.
-      3. Call Run, which will setup the handlers for the app.
-    For example:
-      robot = Robot('Terminator',
-                    image_url='http://www.sky.net/models/t800.png',
-                    profile_url='http://www.sky.net/models/t800.html')
-      robot.register_handler(WAVELET_PARTICIPANTS_CHANGED, KillParticipant)
-      run(robot)
-
-    Args:
-      robot: the robot to run. This robot is modified to use app engines
-          urlfetch for posting http.
-      debug: Optional variable that defaults to False and is passed through
-          to the webapp application to determine if it should show debug info.
-      log_errors: Optional flag that defaults to True and determines whether
-          a default handlers to catch errors should be setup that uses the
-          app engine logging to log errors.
-      extra_handlers: Optional list of tuples that are passed to the webapp
-          to install more handlers. For example, passing
-            [('/about', AboutHandler),] would install an extra about handler
-            for the robot.
-  """
-  # App Engine expects to construct a class with no arguments, so we
-  # pass a lambda that constructs the appropriate handler with
-  # arguments from the enclosing scope.
-  if log_errors:
-    robot.register_handler(events.OperationError, operation_error_handler)
-  robot.set_http_post(appengine_post)
-  app = create_robot_webapp(robot, debug, extra_handlers)
-  run_wsgi_app(app)
diff --git a/wave/src/main/java/python/api/blip.py b/wave/src/main/java/python/api/blip.py
deleted file mode 100644
index 7f103d9..0000000
--- a/wave/src/main/java/python/api/blip.py
+++ /dev/null
@@ -1,949 +0,0 @@
-#!/usr/bin/python2.4
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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 UserDict
-
-import element
-import errors
-
-import util
-
-class Annotation(object):
-  """Models an annotation on a document.
-
-  Annotations are key/value pairs over a range of content. Annotations
-  can be used to store data or to be interpreted by a client when displaying
-  the data.
-  """
-
-  # Use the following constants to control the display of the client
-
-  #: Reserved annotation for setting background color of text.
-  BACKGROUND_COLOR = "style/backgroundColor"
-  #: Reserved annotation for setting color of text.
-  COLOR = "style/color"
-  #: Reserved annotation for setting font family of text.
-  FONT_FAMILY = "style/fontFamily"
-  #: Reserved annotation for setting font family of text.
-  FONT_SIZE = "style/fontSize"
-  #: Reserved annotation for setting font style of text.
-  FONT_STYLE = "style/fontStyle"
-  #: Reserved annotation for setting font weight of text.
-  FONT_WEIGHT = "style/fontWeight"
-  #: Reserved annotation for setting text decoration.
-  TEXT_DECORATION = "style/textDecoration"
-  #: Reserved annotation for setting vertical alignment.
-  VERTICAL_ALIGN = "style/verticalAlign"
-  #: Reserved annotation for setting link.
-  LINK = "link/manual"
-
-  def __init__(self, name, value, start, end):
-    self._name = name
-    self._value = value
-    self._start = start
-    self._end = end
-
-  @property
-  def name(self):
-    return self._name
-
-  @property
-  def value(self):
-    return self._value
-
-  @property
-  def start(self):
-    return self._start
-
-  @property
-  def end(self):
-    return self._end
-
-  def _shift(self, where, inc):
-    """Shift annotation by 'inc' if it (partly) overlaps with 'where'."""
-    if self._start >= where:
-      self._start += inc
-    if self._end >= where:
-      self._end += inc
-
-  def serialize(self):
-    """Serializes the annotation.
-
-    Returns:
-      A dict containing the name, value, and range values.
-    """
-    return {'name': self._name,
-            'value': self._value,
-            'range': {'start': self._start,
-                      'end': self._end}}
-
-
-class Annotations(object, UserDict.DictMixin):
-  """A dictionary-like object containing the annotations, keyed by name."""
-
-  def __init__(self, operation_queue, blip):
-    self._operation_queue = operation_queue
-    self._blip = blip
-    self._store = {}
-
-  def __contains__(self, what):
-    if isinstance(what, Annotation):
-      what = what.name
-    return what in self._store
-
-  def _add_internal(self, name, value, start, end):
-    """Internal add annotation does not send out operations."""
-    if name in self._store:
-      # TODO: use bisect to make this more efficient.
-      new_list = []
-      for existing in self._store[name]:
-        if start > existing.end or end < existing.start:
-          new_list.append(existing)
-        else:
-          if existing.value == value:
-            # merge the annotations:
-            start = min(existing.start, start)
-            end = max(existing.end, end)
-          else:
-            # chop the bits off the existing annotation
-            if existing.start < start:
-              new_list.append(Annotation(
-                  existing.name, existing.value, existing.start, start))
-            if existing.end > end:
-              new_list.append(Annotation(
-                  existing.name, existing.value, existing.end, end))
-      new_list.append(Annotation(name, value, start, end))
-      self._store[name] = new_list
-    else:
-      self._store[name] = [Annotation(name, value, start, end)]
-
-  def _delete_internal(self, name, start=0, end=-1):
-    """Remove the passed annotaion from the internal representation."""
-    if not name in self._store:
-      return
-    if end < 0:
-      end = len(self._blip) + end
-
-    new_list = []
-    for a in self._store[name]:
-      if start > a.end or end < a.start:
-        new_list.append(a)
-      elif start < a.start and end > a.end:
-        continue
-      else:
-        if a.start < start:
-          new_list.append(Annotation(name, a.value, a.start, start))
-        if a.end > end:
-          new_list.append(Annotation(name, a.value, end, a.end))
-    if new_list:
-      self._store[name] = new_list
-    else:
-      del self._store[name]
-
-  def _shift(self, where, inc):
-    """Shift annotation by 'inc' if it (partly) overlaps with 'where'."""
-    for annotations in self._store.values():
-      for annotation in annotations:
-        annotation._shift(where, inc)
-
-    # Merge fragmented annotations that should be contiguous, for example:
-    # Annotation('foo', 'bar', 1, 2) and Annotation('foo', 'bar', 2, 3).
-    for name, annotations in self._store.items():
-      new_list = []
-      for i, annotation in enumerate(annotations):
-        name = annotation.name
-        value = annotation.value
-        start = annotation.start
-        end = annotation.end
-
-        # Find the last end index.
-        for j, next_annotation in enumerate(annotations[i + 1:]):
-          # Not contiguous, skip.
-          if (end < next_annotation.start):
-            break
-
-          # Contiguous, merge.
-          if (end == next_annotation.start and value == next_annotation.value):
-            end = next_annotation.end
-            del annotations[j]
-        new_list.append(Annotation(name, value, start, end))
-      self._store[name] = new_list
-
-  def __len__(self):
-    return len(self._store)
-
-  def __getitem__(self, key):
-    return self._store[key]
-
-  def __iter__(self):
-    for l in self._store.values():
-      for ann in l:
-        yield ann
-
-  def names(self):
-    """Return the names of the annotations in the store."""
-    return self._store.keys()
-
-  def serialize(self):
-    """Return a list of the serialized annotations."""
-    res = []
-    for v in self._store.values():
-      res += [a.serialize() for a in v]
-    return res
-
-
-class Blips(object, UserDict.DictMixin):
-  """A dictionary-like object containing the blips, keyed on blip ID."""
-
-  def __init__(self, blips):
-    self._blips = blips
-
-  def __contains__(self, blip_id):
-    return blip_id in self._blips
-
-  def __getitem__(self, blip_id):
-    return self._blips[blip_id]
-
-  def __iter__(self):
-    return self._blips.__iter__()
-
-  def __len__(self):
-    return len(self._blips)
-
-  def _add(self, ablip):
-    self._blips[ablip.blip_id] = ablip
-
-  def _remove_with_id(self, blip_id):
-    del_blip = self._blips[blip_id]
-    if del_blip:
-      # Remove the reference to this blip from its parent.
-      parent_blip = self._blips[blip_id].parent_blip
-      if parent_blip:
-        parent_blip._child_blip_ids.remove(blip_id)
-    del self._blips[blip_id]
-
-  def get(self, blip_id, default_value=None):
-    """Retrieves a blip.
-
-    Returns:
-      A Blip object. If none found for the ID, it returns None,
-      or if default_value is specified, it returns that.
-    """
-    return self._blips.get(blip_id, default_value)
-
-  def serialize(self):
-    """Serializes the blips.
-    Returns:
-      A dict of serialized blips.
-    """
-    res = {}
-    for blip_id, item in self._blips.items():
-      res[blip_id] = item.serialize()
-    return res
-
-  def values(self):
-    """Return the blips themselves."""
-    return self._blips.values()
-
-
-class BlipRefs(object):
-  """Represents a set of references to contents in a blip.
-
-  For example, a BlipRefs instance can represent the results
-  of a search, an explicitly set range, a regular expression,
-  or refer to the entire blip. BlipRefs are used to express
-  operations on a blip in a consistent way that can easily
-  be transfered to the server.
-
-  The typical way of creating a BlipRefs object is to use
-  selector methods on the Blip object. Developers will not
-  usually instantiate a BlipRefs object directly.
-  """
-
-  DELETE = 'DELETE'
-  REPLACE = 'REPLACE'
-  INSERT = 'INSERT'
-  INSERT_AFTER = 'INSERT_AFTER'
-  ANNOTATE = 'ANNOTATE'
-  CLEAR_ANNOTATION = 'CLEAR_ANNOTATION'
-  UPDATE_ELEMENT = 'UPDATE_ELEMENT'
-
-  def __init__(self, blip, maxres=1):
-    self._blip = blip
-    self._maxres = maxres
-
-  @classmethod
-  def all(cls, blip, findwhat, maxres=-1, **restrictions):
-    """Construct an instance representing the search for text or elements."""
-    obj = cls(blip, maxres)
-    obj._findwhat = findwhat
-    obj._restrictions = restrictions
-    obj._hits = lambda: obj._find(findwhat, maxres, **restrictions)
-    if findwhat is None:
-      # No findWhat, take the entire blip
-      obj._params = {}
-    else:
-      query = {'maxRes': maxres}
-      if isinstance(findwhat, basestring):
-        query['textMatch'] = findwhat
-      else:
-        query['elementMatch'] = findwhat.class_type
-        query['restrictions'] = restrictions
-      obj._params = {'modifyQuery': query}
-    return obj
-
-  @classmethod
-  def range(cls, blip, begin, end):
-    """Constructs an instance representing an explicitly set range."""
-    obj = cls(blip)
-    obj._begin = begin
-    obj._end = end
-    obj._hits = lambda: [(begin, end)]
-    obj._params = {'range': {'start': begin, 'end': end}}
-    return obj
-
-  def _elem_matches(self, elem, clz, **restrictions):
-    if not isinstance(elem, clz):
-      return False
-    for key, val in restrictions.items():
-      if getattr(elem, key) != val:
-        return False
-    return True
-
-  def _find(self, what, maxres=-1, **restrictions):
-    """Iterates where 'what' occurs in the associated blip.
-
-    What can be either a string or a class reference.
-    Examples:
-        self._find('hello') will return the first occurence of the word hello
-        self._find(element.Gadget, url='http://example.com/gadget.xml')
-            will return the first gadget that has as url example.com.
-
-    Args:
-      what: what to search for. Can be a class or a string. The class
-          should be an element from element.py
-      maxres: number of results to return at most, or <= 0 for all.
-      restrictions: if what specifies a class, further restrictions
-         of the found instances.
-    Yields:
-      Tuples indicating the range of the matches. For a one
-      character/element match at position x, (x, x+1) is yielded.
-    """
-    blip = self._blip
-    if what is None:
-      yield 0, len(blip)
-      raise StopIteration
-    if isinstance(what, basestring):
-      idx = blip._content.find(what)
-      count = 0
-      while idx != -1:
-        yield idx, idx + len(what)
-        count += 1
-        if count == maxres:
-          raise StopIteration
-        idx = blip._content.find(what, idx + len(what))
-    else:
-      count = 0
-      for idx, el in blip._elements.items():
-        if self._elem_matches(el, what, **restrictions):
-          yield idx, idx + 1
-          count += 1
-          if count == maxres:
-            raise StopIteration
-
-  def _execute(self, modify_how, what, bundled_annotations=None):
-    """Executes this BlipRefs object.
-
-    Args:
-      modify_how: What to do. Any of the operation declared at the top.
-      what: Depending on the operation. For delete, has to be None.
-            For the others it is a singleton, a list or a function returning
-            what to do; for ANNOTATE tuples of (key, value), for the others
-            either string or elements.
-            If what is a function, it takes three parameters, the content of
-            the blip, the beginning of the matching range and the end.
-      bundled_annotations: Annotations to apply immediately.
-    Raises:
-      IndexError when trying to access content outside of the blip.
-      ValueError when called with the wrong values.
-    Returns:
-      self for chainability.
-    """
-    blip = self._blip
-
-    if modify_how != BlipRefs.DELETE:
-      if not isinstance(what, list):
-        what = [what]
-      next_index = 0
-
-    matched = []
-    # updated_elements is used to store the element type of the
-    # element to update
-    updated_elements = []
-    
-    # For now, if we find one markup, we'll use it everywhere.
-    next = None
-    hit_found = False
-
-    for start, end in self._hits():
-      hit_found = True
-      if start < 0:
-        start += len(blip)
-        if end == 0:
-          end += len(blip)
-      if end < 0:
-        end += len(blip)
-      if len(blip) == 0:
-        if start != 0 or end != 0:
-          raise IndexError('Start and end have to be 0 for empty document')
-      elif start < 0 or end < 1 or start >= len(blip) or end > len(blip):
-        raise IndexError('Position outside the document')
-      if modify_how == BlipRefs.DELETE:
-        for i in range(start, end):
-          if i in blip._elements:
-            del blip._elements[i]
-        blip._delete_annotations(start, end)
-        blip._shift(end, start - end)
-        blip._content = blip._content[:start] + blip._content[end:]
-      else:
-        if callable(what):
-          next = what(blip._content, start, end)
-          matched.append(next)
-        else:
-          next = what[next_index]
-          next_index = (next_index + 1) % len(what)
-        if isinstance(next, str):
-          next = util.force_unicode(next)
-        if modify_how == BlipRefs.ANNOTATE:
-          key, value = next
-          blip.annotations._add_internal(key, value, start, end)
-        elif modify_how == BlipRefs.CLEAR_ANNOTATION:
-          blip.annotations._delete_internal(next, start, end)
-        elif modify_how == BlipRefs.UPDATE_ELEMENT:
-          el = blip._elements.get(start)
-          if not el:
-            raise ValueError('No element found at index %s' % start)
-          # the passing around of types this way feels a bit dirty:
-          updated_elements.append(element.Element.from_json({'type': el.type,
-              'properties': next}))
-          for k, b in next.items():
-            setattr(el, k, b)
-        else:
-          if modify_how == BlipRefs.INSERT:
-            end = start
-          elif modify_how == BlipRefs.INSERT_AFTER:
-            start = end
-          elif modify_how == BlipRefs.REPLACE:
-            pass
-          else:
-            raise ValueError('Unexpected modify_how: ' + modify_how)
-
-          if isinstance(next, element.Element):
-            text = ' '
-          else:
-            text = next
-
-          # in the case of a replace, and the replacement text is shorter,
-          # delete the delta.
-          if start != end and len(text) < end - start:
-            blip._delete_annotations(start + len(text), end)
-
-          blip._shift(end, len(text) + start - end)
-          blip._content = blip._content[:start] + text + blip._content[end:]
-          if bundled_annotations:
-            end_annotation = start + len(text)
-            blip._delete_annotations(start, end_annotation)
-            for key, value in bundled_annotations:
-              blip.annotations._add_internal(key, value, start, end_annotation)
-
-          if isinstance(next, element.Element):
-            blip._elements[start] = next
-
-    # No match found, return immediately without generating op.
-    if not hit_found:
-      return
-
-    operation = blip._operation_queue.document_modify(blip.wave_id,
-                                                      blip.wavelet_id,
-                                                      blip.blip_id)
-    for param, value in self._params.items():
-      operation.set_param(param, value)
-
-    modify_action = {'modifyHow': modify_how}
-    if modify_how == BlipRefs.DELETE:
-      pass
-    elif modify_how == BlipRefs.UPDATE_ELEMENT:
-      modify_action['elements'] = updated_elements
-    elif (modify_how == BlipRefs.REPLACE or
-          modify_how == BlipRefs.INSERT or
-          modify_how == BlipRefs.INSERT_AFTER):
-      if callable(what):
-        what = matched
-      if what:
-        if not isinstance(next, element.Element):
-          modify_action['values'] = [util.force_unicode(value) for value in what]
-        else:
-          modify_action['elements'] = what
-    elif modify_how == BlipRefs.ANNOTATE:
-      modify_action['values'] = [x[1] for x in what]
-      modify_action['annotationKey'] = what[0][0]
-    elif modify_how == BlipRefs.CLEAR_ANNOTATION:
-      modify_action['annotationKey'] = what[0]
-    if bundled_annotations:
-      modify_action['bundledAnnotations'] = [
-          {'key': key, 'value': value} for key, value in bundled_annotations]
-    operation.set_param('modifyAction', modify_action)
-
-    return self
-
-  def insert(self, what, bundled_annotations=None):
-    """Inserts what at the matched positions."""
-    return self._execute(
-        BlipRefs.INSERT, what, bundled_annotations=bundled_annotations)
-
-  def insert_after(self, what, bundled_annotations=None):
-    """Inserts what just after the matched positions."""
-    return self._execute(
-        BlipRefs.INSERT_AFTER, what, bundled_annotations=bundled_annotations)
-
-  def replace(self, what, bundled_annotations=None):
-    """Replaces the matched positions with what."""
-    return self._execute(
-        BlipRefs.REPLACE, what, bundled_annotations=bundled_annotations)
-
-  def delete(self):
-    """Deletes the content at the matched positions."""
-    return self._execute(BlipRefs.DELETE, None)
-
-  def annotate(self, name, value=None):
-    """Annotates the content at the matched positions.
-
-    You can either specify both name and value to set the
-    same annotation, or supply as the first parameter something
-    that yields name/value pairs. The name and value should both be strings.
-    """
-    if value is None:
-      what = name
-    else:
-      what = (name, value)
-    return self._execute(BlipRefs.ANNOTATE, what)
-
-  def clear_annotation(self, name):
-    """Clears the annotation at the matched positions."""
-    return self._execute(BlipRefs.CLEAR_ANNOTATION, name)
-
-  def update_element(self, new_values):
-    """Update an existing element with a set of new values.
-
-    For example, this code would update a button value:
-    button.update_element({'value': 'Yes'})
-    This code would update the 'seen' key in a gadget's state:
-    gadget.update_element({'seen': 'yes'})
-
-    Args:
-      new_values: A dictionary of property names and values.
-    """
-    return self._execute(BlipRefs.UPDATE_ELEMENT, new_values)
-
-  def __nonzero__(self):
-    """Return whether we have a value."""
-    for start, end in self._hits():
-      return True
-    return False
-
-  def value(self):
-    """Convenience method to convert a BlipRefs to value of its first match."""
-    for start, end in self._hits():
-      if end - start == 1 and start in self._blip._elements:
-        return self._blip._elements[start]
-      else:
-        return self._blip.text[start:end]
-    raise ValueError('BlipRefs has no values')
-
-  def __getattr__(self, attribute):
-    """Mirror the getattr of value().
-
-    This allows for clever things like
-    first(IMAGE).url
-
-    or
-
-    blip.annotate_with(key, value).upper()
-    """
-    return getattr(self.value(), attribute)
-
-  def __radd__(self, other):
-    """Make it possible to add this to a string."""
-    return other + self.value()
-
-  def __cmp__(self, other):
-    """Support comparision with target."""
-    return cmp(self.value(), other)
-
-  def __iter__(self):
-    for start_end in self._hits():
-      yield start_end
-
-
-class Blip(object):
-  """Models a single blip instance.
-
-  Blips are essentially the documents that make up a conversation. Blips can
-  live in a hierarchy of blips. A root blip has no parent blip id, but all
-  blips have the ids of the wave and wavelet that they are associated with.
-
-  Blips also contain annotations, content and elements, which are accessed via
-  the Document object.
-  """ 
-
-  def __init__(self, json, other_blips, operation_queue, thread=None,
-               reply_threads=None):
-    """Inits this blip with JSON data.
-
-    Args:
-      json: JSON data dictionary from Wave server.
-      other_blips: A dictionary like object that can be used to resolve
-        ids of blips to blips.
-      thread: The BlipThread object that this blip belongs to.
-      reply_threads: A list BlipThread objects that are replies to this blip.
-      operation_queue: An OperationQueue object to store generated operations
-        in.
-    """
-    self._blip_id = json.get('blipId')
-    self._reply_threads = reply_threads or []
-    self._thread = thread
-    self._operation_queue = operation_queue
-    self._child_blip_ids = list(json.get('childBlipIds', []))
-    self._content = json.get('content', '')
-    self._contributors = set(json.get('contributors', []))
-    self._creator = json.get('creator')
-    self._last_modified_time = json.get('lastModifiedTime', 0)
-    self._version = json.get('version', 0)
-    self._parent_blip_id = json.get('parentBlipId')
-    self._wave_id = json.get('waveId')
-    self._wavelet_id = json.get('waveletId')
-    if isinstance(other_blips, Blips):
-      self._other_blips = other_blips
-    else:
-      self._other_blips = Blips(other_blips)
-    self._annotations = Annotations(operation_queue, self)
-    for annjson in json.get('annotations', []):
-      r = annjson['range']
-      self._annotations._add_internal(annjson['name'],
-                                      annjson['value'],
-                                      r['start'],
-                                      r['end'])
-    self._elements = {}
-    json_elements = json.get('elements', {})
-    for elem in json_elements:
-      self._elements[int(elem)] = element.Element.from_json(json_elements[elem])
-    self.raw_data = json
-
-  @property
-  def blip_id(self):
-    """The id of this blip."""
-    return self._blip_id
-
-  @property
-  def wave_id(self):
-    """The id of the wave that this blip belongs to."""
-    return self._wave_id
-
-  @property
-  def wavelet_id(self):
-    """The id of the wavelet that this blip belongs to."""
-    return self._wavelet_id
-
-  @property
-  def child_blip_ids(self):
-    """The list of the ids of this blip's children."""
-    return self._child_blip_ids
-
-  @property
-  def child_blips(self):
-    """The list of blips that are children of this blip."""
-    return [self._other_blips[blid_id] for blid_id in self._child_blip_ids
-                if blid_id in self._other_blips]
-
-  @property
-  def thread(self):
-    """The thread that this blip belongs to."""
-    return self._thread
-
-  @property
-  def reply_threads(self):
-    """The list of threads that are replies to this blip."""
-    return self._reply_threads
-
-  @property
-  def inline_reply_threads(self):
-    # TODO: Consider moving to constructor
-    inline_reply_threads = []
-    for reply_thread in self._reply_threads:
-      if reply_thread.location > -1:
-        inline_reply_threads.append(reply_thread)
-    return inline_reply_threads
-
-  @property
-  def contributors(self):
-    """The set of participant ids that contributed to this blip."""
-    return self._contributors
-
-  @property
-  def creator(self):
-    """The id of the participant that created this blip."""
-    return self._creator
-
-  @property
-  def last_modified_time(self):
-    """The time in seconds since epoch when this blip was last modified."""
-    return self._last_modified_time
-
-  @property
-  def version(self):
-    """The version of this blip."""
-    return self._version
-
-  @property
-  def parent_blip_id(self):
-    """The parent blip_id or None if this is the root blip."""
-    return self._parent_blip_id
-
-  @property
-  def parent_blip(self):
-    """The parent blip or None if it is the root."""
-    # if parent_blip_id is None, get will also return None
-    return self._other_blips.get(self._parent_blip_id)
-
-  @property
-  def inline_blip_offset(self):
-    """The offset in the parent if this blip is inline or -1 if not.
-
-    If the parent is not in the context, this function will always
-    return -1 since it can't determine the inline blip status.
-    """
-    parent = self.parent_blip
-    if not parent:
-      return -1
-    for offset, el in parent._elements.items():
-      if el.type == element.Element.INLINE_BLIP_TYPE and el.id == self.blip_id:
-        return offset
-    return -1
-
-  def is_root(self):
-    """Returns whether this is the root blip of a wavelet."""
-    return self._parent_blip_id is None
-
-  @property
-  def annotations(self):
-    """The annotations for this document."""
-    return self._annotations
-
-  @property
-  def elements(self):
-    """Returns a list of elements for this document.
-    The elements of a blip are things like forms elements and gadgets
-    that cannot be expressed as plain text. In the text of the blip, you'll
-    typically find a space as a place holder for the element.
-    If you want to retrieve the element at a particular index in the blip, use
-    blip[index].value().
-    """
-    return self._elements.values()
-
-  def __len__(self):
-    return len(self._content)
-
-  def __getitem__(self, item):
-    """returns a BlipRefs for the given slice."""
-    if isinstance(item, slice):
-      if item.step:
-        raise errors.Error('Step not supported for blip slices')
-      return self.range(item.start, item.stop)
-    else:
-      return self.at(item)
-
-  def __setitem__(self, item, value):
-    """short cut for self.range/at().replace(value)."""
-    self.__getitem__(item).replace(value)
-
-  def __delitem__(self, item):
-    """short cut for self.range/at().delete()."""
-    self.__getitem__(item).delete()
-
-  def _shift(self, where, inc):
-    """Move element and annotations after 'where' up by 'inc'."""
-    new_elements = {}
-    for idx, el in self._elements.items():
-      if idx >= where:
-        idx += inc
-      new_elements[idx] = el
-    self._elements = new_elements
-    self._annotations._shift(where, inc)
-    
-  def _delete_annotations(self, start, end):
-    """Delete all annotations between 'start' and 'end'."""
-    for annotation_name in self._annotations.names():
-      self._annotations._delete_internal(annotation_name, start, end)
-
-  def all(self, findwhat=None, maxres=-1, **restrictions):
-    """Returns a BlipRefs object representing all results for the search.
-    If searching for an element, the restrictions can be used to specify
-    additional element properties to filter on, like the url of a Gadget.
-    """
-    return BlipRefs.all(self, findwhat, maxres, **restrictions)
-
-  def first(self, findwhat=None, **restrictions):
-    """Returns a BlipRefs object representing the first result for the search.
-    If searching for an element, the restrictions can be used to specify
-    additional element properties to filter on, like the url of a Gadget.
-    """
-    return BlipRefs.all(self, findwhat, 1, **restrictions)
-
-  def at(self, index):
-    """Returns a BlipRefs object representing a 1-character range."""
-    return BlipRefs.range(self, index, index + 1)
-
-  def range(self, start, end):
-    """Returns a BlipRefs object representing the range."""
-    return BlipRefs.range(self, start, end)
-
-  def serialize(self):
-    """Return a dictionary representation of this blip ready for json."""
-    return {'blipId': self._blip_id,
-            'childBlipIds': list(self._child_blip_ids),
-            'content': self._content,
-            'creator': self._creator,
-            'contributors': list(self._contributors),
-            'lastModifiedTime': self._last_modified_time,
-            'version': self._version,
-            'parentBlipId': self._parent_blip_id,
-            'waveId': self._wave_id,
-            'waveletId': self._wavelet_id,
-            'annotations': self._annotations.serialize(),
-            'elements': dict([(index, e.serialize())
-                              for index, e in self._elements.items()])
-           }
-
-  def proxy_for(self, proxy_for_id):
-    """Return a view on this blip that will proxy for the specified id.
-
-    A shallow copy of the current blip is returned with the proxy_for_id
-    set. Any modifications made to this copy will be done using the
-    proxy_for_id, i.e. the robot+<proxy_for_id>@appspot.com address will
-    be used.
-    """
-    util.check_is_valid_proxy_for_id(proxy_for_id)
-    operation_queue = self._operation_queue.proxy_for(proxy_for_id)
-    res = Blip(json={},
-               other_blips={},
-               operation_queue=operation_queue)
-    res._blip_id = self._blip_id
-    res._child_blip_ids = self._child_blip_ids
-    res._content = self._content
-    res._contributors = self._contributors
-    res._creator = self._creator
-    res._last_modified_time = self._last_modified_time
-    res._version = self._version
-    res._parent_blip_id = self._parent_blip_id
-    res._wave_id = self._wave_id
-    res._wavelet_id = self._wavelet_id
-    res._other_blips = self._other_blips
-    res._annotations = self._annotations
-    res._elements = self._elements
-    res.raw_data = self.raw_data
-    return res
-
-  @property
-  def text(self):
-    """Returns the raw text content of this document."""
-    return self._content
-
-  def find(self, what, **restrictions):
-    """Iterate to matching bits of contents.
-
-    Yield either elements or pieces of text.
-    """
-    br = BlipRefs.all(self, what, **restrictions)
-    for start, end in br._hits():
-      if end - start == 1 and start in self._elements:
-        yield self._elements[start]
-      else:
-        yield self._content[start:end]
-    raise StopIteration
-
-  def append(self, what, bundled_annotations=None):
-    """Convenience method covering a common pattern."""
-    return BlipRefs.all(self, findwhat=None).insert_after(
-        what, bundled_annotations=bundled_annotations)
-
-  def continue_thread(self):
-    """Create and return a blip in the same thread as this blip."""
-    blip_data = self._operation_queue.blip_continue_thread(self.wave_id,
-                                                           self.wavelet_id,
-                                                           self.blip_id)
-    new_blip = Blip(blip_data, self._other_blips, self._operation_queue,
-                    thread=self._thread)
-    if self._thread:
-      self._thread._add_internal(new_blip)
-    self._other_blips._add(new_blip)
-    return new_blip
-
-  def reply(self):
-    """Create and return a reply to this blip."""
-    blip_data = self._operation_queue.blip_create_child(self.wave_id,
-                                                        self.wavelet_id,
-                                                        self.blip_id)
-    new_blip = Blip(blip_data, self._other_blips, self._operation_queue)
-    self._other_blips._add(new_blip)
-    return new_blip
-
-  def append_markup(self, markup):
-    """Interpret the markup text as xhtml and append the result to the doc.
-
-    Args:
-      markup: The markup'ed text to append.
-    """
-    markup = util.force_unicode(markup)
-    self._operation_queue.document_append_markup(self.wave_id,
-                                                 self.wavelet_id,
-                                                 self.blip_id,
-                                                 markup)
-    self._content += util.parse_markup(markup)
-
-  def insert_inline_blip(self, position):
-    """Inserts an inline blip into this blip at a specific position.
-
-    Args:
-      position: Position to insert the blip at. This has to be greater than 0.
-
-    Returns:
-      The JSON data of the blip that was created.
-    """
-    if position <= 0:
-      raise IndexError(('Illegal inline blip position: %d. Position has to ' +
-                        'be greater than 0.') % position)
-
-    blip_data = self._operation_queue.document_inline_blip_insert(
-        self.wave_id,
-        self.wavelet_id,
-        self.blip_id,
-        position)
-    new_blip = Blip(blip_data, self._other_blips, self._operation_queue)
-    self._other_blips._add(new_blip)
-    return new_blip
diff --git a/wave/src/main/java/python/api/blip_test.py b/wave/src/main/java/python/api/blip_test.py
deleted file mode 100644
index 7cd66e0..0000000
--- a/wave/src/main/java/python/api/blip_test.py
+++ /dev/null
@@ -1,383 +0,0 @@
-#!/usr/bin/python2.4
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Unit tests for the blip module."""
-
-
-import unittest
-
-import blip
-import element
-import ops
-import simplejson
-
-TEST_BLIP_DATA = {
-    'childBlipIds': [],
-    'content': '\nhello world!\nanother line',
-    'contributors': ['robot@test.com', 'user@test.com'],
-    'creator': 'user@test.com',
-    'lastModifiedTime': 1000,
-    'parentBlipId': None,
-    'annotations': [{'range': {'start': 2, 'end': 3},
-                     'name': 'key', 'value': 'val'}],
-    'waveId': 'test.com!w+g3h3im',
-    'waveletId': 'test.com!root+conv',
-    'elements':{'14':{'type':'GADGET','properties':{'url':'http://a/b.xml'}}},
-}
-
-CHILD_BLIP_ID = 'b+42'
-ROOT_BLIP_ID = 'b+43'
-
-
-class TestBlip(unittest.TestCase):
-  """Tests the primary data structures for the wave model."""
-
-  def assertBlipStartswith(self, expected, totest):
-    actual = totest.text[:len(expected)]
-    self.assertEquals(expected, actual)
-
-  def new_blip(self, **args):
-    """Create a blip for testing."""
-    data = TEST_BLIP_DATA.copy()
-    data.update(args)
-    res = blip.Blip(data, self.all_blips, self.operation_queue)
-    self.all_blips[res.blip_id] = res
-    return res
-
-  def setUp(self):
-    self.all_blips = {}
-    self.operation_queue = ops.OperationQueue()
-
-  def testBlipProperties(self):
-    root = self.new_blip(blipId=ROOT_BLIP_ID,
-                         childBlipIds=[CHILD_BLIP_ID])
-    child = self.new_blip(blipId=CHILD_BLIP_ID,
-                          parentBlipId=ROOT_BLIP_ID)
-    self.assertEquals(ROOT_BLIP_ID, root.blip_id)
-    self.assertEquals([CHILD_BLIP_ID], root.child_blip_ids)
-    self.assertEquals(set(TEST_BLIP_DATA['contributors']), root.contributors)
-    self.assertEquals(TEST_BLIP_DATA['creator'], root.creator)
-    self.assertEquals(TEST_BLIP_DATA['content'], root.text)
-    self.assertEquals(TEST_BLIP_DATA['lastModifiedTime'],
-                      root.last_modified_time)
-    self.assertEquals(TEST_BLIP_DATA['parentBlipId'], root.parent_blip_id)
-    self.assertEquals(TEST_BLIP_DATA['waveId'], root.wave_id)
-    self.assertEquals(TEST_BLIP_DATA['waveletId'], root.wavelet_id)
-    self.assertEquals(TEST_BLIP_DATA['content'][3], root[3])
-    self.assertEquals(element.Gadget.class_type, root[14].type)
-    self.assertEquals('http://a/b.xml', root[14].url)
-    self.assertEquals('a', root.text[14])
-    self.assertEquals(len(TEST_BLIP_DATA['content']), len(root))
-    self.assertTrue(root.is_root())
-    self.assertFalse(child.is_root())
-    self.assertEquals(root, child.parent_blip)
-
-  def testBlipSerialize(self):
-    root = self.new_blip(blipId=ROOT_BLIP_ID,
-                         childBlipIds=[CHILD_BLIP_ID])
-    serialized = root.serialize()
-    unserialized = blip.Blip(serialized, self.all_blips, self.operation_queue)
-    self.assertEquals(root.blip_id, unserialized.blip_id)
-    self.assertEquals(root.child_blip_ids, unserialized.child_blip_ids)
-    self.assertEquals(root.contributors, unserialized.contributors)
-    self.assertEquals(root.creator, unserialized.creator)
-    self.assertEquals(root.text, unserialized.text)
-    self.assertEquals(root.last_modified_time, unserialized.last_modified_time)
-    self.assertEquals(root.parent_blip_id, unserialized.parent_blip_id)
-    self.assertEquals(root.wave_id, unserialized.wave_id)
-    self.assertEquals(root.wavelet_id, unserialized.wavelet_id)
-    self.assertTrue(unserialized.is_root())
-
-  def testDocumentOperations(self):
-    blip = self.new_blip(blipId=ROOT_BLIP_ID)
-    newlines = [x for x in blip.find('\n')]
-    self.assertEquals(2, len(newlines))
-    blip.first('world').replace('jupiter')
-    bits = blip.text.split('\n')
-    self.assertEquals(3, len(bits))
-    self.assertEquals('hello jupiter!', bits[1])
-    blip.range(2, 5).delete()
-    self.assertBlipStartswith('\nho jupiter', blip)
-
-    blip.first('ho').insert_after('la')
-    self.assertBlipStartswith('\nhola jupiter', blip)
-    blip.at(3).insert(' ')
-    self.assertBlipStartswith('\nho la jupiter', blip)
-
-  def testElementHandling(self):
-    blip = self.new_blip(blipId=ROOT_BLIP_ID)
-    url = 'http://www.test.com/image.png'
-
-    org_len = len(blip)
-    blip.append(element.Image(url=url))
-
-    elems = [elem for elem in blip.find(element.Image, url=url)]
-    self.assertEquals(1, len(elems))
-    elem = elems[0]
-    self.assertTrue(isinstance(elem, element.Image))
-    blip.at(1).insert('twelve chars')
-    self.assertTrue(blip.text.startswith('\ntwelve charshello'))
-
-    elem = blip[org_len + 12].value()
-    self.assertTrue(isinstance(elem, element.Image))
-
-    blip.first('twelve ').delete()
-    self.assertTrue(blip.text.startswith('\nchars'))
-
-    elem = blip[org_len + 12 - len('twelve ')].value()
-    self.assertTrue(isinstance(elem, element.Image))
-
-    blip.first('chars').replace(element.Image(url=url))
-    elems = [elem for elem in blip.find(element.Image, url=url)]
-    self.assertEquals(2, len(elems))
-    self.assertTrue(blip.text.startswith('\n hello'))
-    elem = blip[1].value()
-    self.assertTrue(isinstance(elem, element.Image))
-
-  def testAnnotationHandling(self):
-    key = 'style/fontWeight'
-
-    def get_bold():
-      for an in blip.annotations[key]:
-        if an.value == 'bold':
-          return an
-      return None
-
-    json = ('[{"range":{"start":3,"end":6},"name":"%s","value":"bold"}]'
-            % key)
-    blip = self.new_blip(blipId=ROOT_BLIP_ID,
-                         annotations=simplejson.loads(json))
-    self.assertEquals(1, len(blip.annotations))
-    self.assertNotEqual(None, get_bold().value)
-    self.assertTrue(key in blip.annotations)
-
-    # extend the bold annotation by adding:
-    blip.range(5, 8).annotate(key, 'bold')
-    self.assertEquals(1, len(blip.annotations))
-    self.assertEquals(8, get_bold().end)
-
-    # clip by adding a same keyed:
-    blip[4:12].annotate(key, 'italic')
-    self.assertEquals(2, len(blip.annotations[key]))
-    self.assertEquals(4, get_bold().end)
-
-    # now split the italic one:
-    blip.range(6, 7).clear_annotation(key)
-    self.assertEquals(3, len(blip.annotations[key]))
-
-    # test names and iteration
-    self.assertEquals(1, len(blip.annotations.names()))
-    self.assertEquals(3, len([x for x in blip.annotations]))
-    blip[3: 5].annotate('foo', 'bar')
-    self.assertEquals(2, len(blip.annotations.names()))
-    self.assertEquals(4, len([x for x in blip.annotations]))
-    blip[3: 5].clear_annotation('foo')
-
-    # clear the whole thing
-    blip.all().clear_annotation(key)
-    # getting to the key should now throw an exception
-    self.assertRaises(KeyError, blip.annotations.__getitem__, key)
-
-  def testBlipOperations(self):
-    blip = self.new_blip(blipId=ROOT_BLIP_ID)
-    self.assertEquals(1, len(self.all_blips))
-
-    otherblip = blip.reply()
-    otherblip.append('hello world')
-    self.assertEquals('hello world', otherblip.text)
-    self.assertEquals(blip.blip_id, otherblip.parent_blip_id)
-    self.assertEquals(2, len(self.all_blips))
-
-    another = blip.continue_thread()
-    another.append('hello world')
-    self.assertEquals('hello world', another.text)
-    self.assertEquals(blip.parent_blip_id, another.parent_blip_id)
-    self.assertEquals(3, len(self.all_blips))
-
-    inline = blip.insert_inline_blip(3)
-    self.assertEquals(blip.blip_id, inline.parent_blip_id)
-    self.assertEquals(4, len(self.all_blips))
-
-  def testInsertInlineBlipCantInsertAtTheBeginning(self):
-    blip = self.new_blip(blipId=ROOT_BLIP_ID)
-    self.assertEquals(1, len(self.all_blips))
-    self.assertRaises(IndexError, blip.insert_inline_blip, 0)
-    self.assertEquals(1, len(self.all_blips))
-
-  def testDocumentModify(self):
-    blip = self.new_blip(blipId=ROOT_BLIP_ID)
-    blip.all().replace('a text with text and then some text')
-    blip[7].insert('text ')
-    blip.all('text').replace('thing')
-    self.assertEquals('a thing thing with thing and then some thing',
-                      blip.text)
-
-  def testIteration(self):
-    blip = self.new_blip(blipId=ROOT_BLIP_ID)
-    blip.all().replace('aaa 012 aaa 345 aaa 322')
-    count = 0
-    prev = -1
-    for start, end in blip.all('aaa'):
-      count += 1
-      self.assertTrue(prev < start)
-      prev = start
-    self.assertEquals(3, count)
-
-
-  def testBlipRefValue(self):
-    blip = self.new_blip(blipId=ROOT_BLIP_ID)
-    content = blip.text
-    content = content[:4] + content[5:]
-    del blip[4]
-    self.assertEquals(content, blip.text)
-
-    content = content[:2] + content[3:]
-    del blip[2:3]
-    self.assertEquals(content, blip.text)
-
-    blip[2:3] = 'bike'
-    content = content[:2] + 'bike' + content[3:]
-    self.assertEquals(content, blip.text)
-
-    url = 'http://www.test.com/image.png'
-    blip.append(element.Image(url=url))
-    self.assertEqual(url, blip.first(element.Image).url)
-
-    url2 = 'http://www.test.com/another.png'
-    blip[-1].update_element({'url': url2})
-    self.assertEqual(url2, blip.first(element.Image).url)
-
-    self.assertTrue(blip[3:5] == blip.text[3:5])
-
-    blip.append('geheim')
-    self.assertTrue(blip.first('geheim'))
-    self.assertFalse(blip.first(element.Button))
-    blip.append(element.Button(name='test1', value='Click'))
-    button = blip.first(element.Button)
-    button.update_element({'name': 'test2'})
-    self.assertEqual('test2', button.name)
-
-  def testReplace(self):
-    blip = self.new_blip(blipId=ROOT_BLIP_ID)
-    blip.all().replace('\nxxxx')
-    blip.all('yyy').replace('zzz')
-    self.assertEqual('\nxxxx', blip.text)
-
-  def testDeleteRangeThatSpansAcrossAnnotationEndPoint(self):
-    json = ('[{"range":{"start":1,"end":3},"name":"style","value":"bold"}]')
-    blip = self.new_blip(blipId=ROOT_BLIP_ID,
-                         annotations=simplejson.loads(json),
-                         content='\nFoo bar.')
-    blip.range(2, 4).delete()
-    self.assertEqual('\nF bar.', blip.text)
-    self.assertEqual(1, blip.annotations['style'][0].start)
-    self.assertEqual(2, blip.annotations['style'][0].end)
-
-  def testInsertBeforeAnnotationStartPoint(self):
-    json = ('[{"range":{"start":4,"end":9},"name":"style","value":"bold"}]')
-    blip = self.new_blip(blipId=ROOT_BLIP_ID,
-                         annotations=simplejson.loads(json),
-                         content='\nFoo bar.')
-    blip.at(4).insert('d and')
-    self.assertEqual('\nFood and bar.', blip.text)
-    self.assertEqual(9, blip.annotations['style'][0].start)
-    self.assertEqual(14, blip.annotations['style'][0].end)
-
-  def testDeleteRangeInsideAnnotation(self):
-    json = ('[{"range":{"start":1,"end":5},"name":"style","value":"bold"}]')
-    blip = self.new_blip(blipId=ROOT_BLIP_ID,
-                         annotations=simplejson.loads(json),
-                         content='\nFoo bar.')
-    blip.range(2, 4).delete()
-
-    self.assertEqual('\nF bar.', blip.text)
-    self.assertEqual(1, blip.annotations['style'][0].start)
-    self.assertEqual(3, blip.annotations['style'][0].end)
-
-  def testReplaceInsideAnnotation(self):
-    json = ('[{"range":{"start":1,"end":5},"name":"style","value":"bold"}]')
-    blip = self.new_blip(blipId=ROOT_BLIP_ID,
-                         annotations=simplejson.loads(json),
-                         content='\nFoo bar.')
-    blip.range(2, 4).replace('ooo')
-    self.assertEqual('\nFooo bar.', blip.text)
-    self.assertEqual(1, blip.annotations['style'][0].start)
-    self.assertEqual(6, blip.annotations['style'][0].end)
-
-    blip.range(2, 5).replace('o')
-    self.assertEqual('\nFo bar.', blip.text)
-    self.assertEqual(1, blip.annotations['style'][0].start)
-    self.assertEqual(4, blip.annotations['style'][0].end)
-
-  def testReplaceSpanAnnotation(self):
-    json = ('[{"range":{"start":1,"end":4},"name":"style","value":"bold"}]')
-    blip = self.new_blip(blipId=ROOT_BLIP_ID,
-                         annotations=simplejson.loads(json),
-                         content='\nFoo bar.')
-    blip.range(2, 9).replace('')
-    self.assertEqual('\nF', blip.text)
-    self.assertEqual(1, blip.annotations['style'][0].start)
-    self.assertEqual(2, blip.annotations['style'][0].end)
-
-  def testSearchWithNoMatchShouldNotGenerateOperation(self):
-    blip = self.new_blip(blipId=ROOT_BLIP_ID)
-    self.assertEqual(-1, blip.text.find(':('))
-    self.assertEqual(0, len(self.operation_queue))
-    blip.all(':(').replace(':)')
-    self.assertEqual(0, len(self.operation_queue))
-
-  def testBlipsRemoveWithId(self):
-    blip_dict = {
-        ROOT_BLIP_ID: self.new_blip(blipId=ROOT_BLIP_ID,
-                                    childBlipIds=[CHILD_BLIP_ID]),
-        CHILD_BLIP_ID: self.new_blip(blipId=CHILD_BLIP_ID,
-                                     parentBlipId=ROOT_BLIP_ID)
-    }
-    blips = blip.Blips(blip_dict)
-    blips._remove_with_id(CHILD_BLIP_ID)
-    self.assertEqual(1, len(blips))
-    self.assertEqual(0, len(blips[ROOT_BLIP_ID].child_blip_ids))
-
-  def testAppendMarkup(self):
-    blip = self.new_blip(blipId=ROOT_BLIP_ID, content='\nFoo bar.')
-    markup = '<p><span>markup<span> content</p>'
-    blip.append_markup(markup)
-    self.assertEqual(1, len(self.operation_queue))
-    self.assertEqual('\nFoo bar.\nmarkup content', blip.text)
-
-  def testBundledAnnotations(self):
-    blip = self.new_blip(blipId=ROOT_BLIP_ID, content='\nFoo bar.')
-    blip.append('not bold')
-    blip.append('bold', bundled_annotations=[('style/fontWeight', 'bold')])
-    self.assertEqual(2, len(blip.annotations))
-    self.assertEqual('bold', blip.annotations['style/fontWeight'][0].value)
-
-  def testInlineBlipOffset(self):
-    offset = 14
-    self.new_blip(blipId=ROOT_BLIP_ID,
-                  childBlipIds=[CHILD_BLIP_ID],
-                  elements={str(offset):
-                      {'type': element.Element.INLINE_BLIP_TYPE,
-                       'properties': {'id': CHILD_BLIP_ID}}})
-    child = self.new_blip(blipId=CHILD_BLIP_ID,
-                          parentBlipId=ROOT_BLIP_ID)
-    self.assertEqual(offset, child.inline_blip_offset)
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/wave/src/main/java/python/api/commandline_robot_runner.py b/wave/src/main/java/python/api/commandline_robot_runner.py
deleted file mode 100644
index 9cb3eab..0000000
--- a/wave/src/main/java/python/api/commandline_robot_runner.py
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/usr/bin/python2.4
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Run robot from the commandline for testing.
-
-This robot_runner let's you define event handlers using flags and takes the
-json input from the std in and writes out the json output to stdout.
-
-for example
-  cat events | commandline_robot_runner.py \
-      --eventdef-blip_submitted="wavelet.title='title'"
-"""
-
-__author__ = 'douwe@google.com (Douwe Osinga)'
-
-import sys
-import urllib
-
-from google3.pyglib import app
-from google3.pyglib import flags
-
-from google3.walkabout.externalagents import api
-
-from google3.walkabout.externalagents.api import blip
-from google3.walkabout.externalagents.api import element
-from google3.walkabout.externalagents.api import errors
-from google3.walkabout.externalagents.api import events
-from google3.walkabout.externalagents.api import ops
-from google3.walkabout.externalagents.api import robot
-from google3.walkabout.externalagents.api import util
-
-FLAGS = flags.FLAGS
-
-for event in events.ALL:
-  flags.DEFINE_string('eventdef_' + event.type.lower(),
-                      '',
-                      'Event definition for the %s event' % event.type)
-
-
-def handle_event(src, bot, e, w):
-  """Handle an event by executing the source code src."""
-  globs = {'e': e, 'w': w, 'api': api, 'bot': bot,
-           'blip': blip, 'element': element, 'errors': errors,
-           'events': events, 'ops': ops, 'robot': robot,
-           'util': util}
-  exec src in globs
-
-
-def run_bot(input_file, output_file):
-  """Run a robot defined on the command line."""
-  cmdbot = robot.Robot('Commandline bot')
-  for event in events.ALL:
-    src = getattr(FLAGS, 'eventdef_' + event.type.lower())
-    src = urllib.unquote_plus(src)
-    if src:
-      cmdbot.register_handler(event,
-          lambda event, wavelet, src=src, bot=cmdbot:
-              handle_event(src, bot, event, wavelet))
-  json_body = unicode(input_file.read(), 'utf8')
-  json_response = cmdbot.process_events(json_body)
-  output_file.write(json_response)
-
-
-def main(argv):
-  run_bot(sys.stdin, sys.stdout)
-
-if __name__ == '__main__':
-  app.run()
diff --git a/wave/src/main/java/python/api/commandline_robot_runner_test.py b/wave/src/main/java/python/api/commandline_robot_runner_test.py
deleted file mode 100644
index 3acbca5..0000000
--- a/wave/src/main/java/python/api/commandline_robot_runner_test.py
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/usr/bin/python2.4
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Tests for google3.walkabout.externalagents.api.commandline_robot_runner."""
-
-__author__ = 'douwe@google.com (Douwe Osinga)'
-
-import StringIO
-
-from google3.pyglib import app
-from google3.pyglib import flags
-
-from google3.testing.pybase import googletest
-from google3.walkabout.externalagents.api import commandline_robot_runner
-from google3.walkabout.externalagents.api import events
-
-FLAGS = flags.FLAGS
-
-
-BLIP_JSON = ('{"wdykLROk*13":'
-             '{"lastModifiedTime":1242079608457,'
-             '"contributors":["someguy@test.com"],'
-             '"waveletId":"test.com!conv+root",'
-             '"waveId":"test.com!wdykLROk*11",'
-             '"parentBlipId":null,'
-             '"version":3,'
-             '"creator":"someguy@test.com",'
-             '"content":"\\nContent!",'
-             '"blipId":"wdykLROk*13",'
-             '"annotations":[{"range":{"start":0,"end":1},'
-             '"name":"user/e/otherguy@test.com","value":"Other"}],'
-             '"elements":{},'
-             '"childBlipIds":[]}'
-             '}')
-
-WAVELET_JSON = ('{"lastModifiedTime":1242079611003,'
-                 '"title":"A title",'
-                 '"waveletId":"test.com!conv+root",'
-                 '"rootBlipId":"wdykLROk*13",'
-                 '"dataDocuments":null,'
-                 '"creationTime":1242079608457,'
-                 '"waveId":"test.com!wdykLROk*11",'
-                 '"participants":["someguy@test.com","monty@appspot.com"],'
-                 '"creator":"someguy@test.com",'
-                 '"rootThread": '
-                 '{"id":"", "location": "-1", "blipIds": ["wdykLROk*13"]},'
-                 '"version":5}')
-
-EVENTS_JSON = ('[{"timestamp":1242079611003,'
-               '"modifiedBy":"someguy@test.com",'
-               '"properties":{"participantsRemoved":[],'
-               '"participantsAdded":["monty@appspot.com"]},'
-               '"type":"WAVELET_PARTICIPANTS_CHANGED"}]')
-
-TEST_JSON = '{"blips":%s,"wavelet":%s,"events":%s}' % (
-    BLIP_JSON, WAVELET_JSON, EVENTS_JSON)
-
-
-class CommandlineRobotRunnerTest(googletest.TestCase):
-
-  def testSimpleFlow(self):
-    FLAGS.eventdef_wavelet_participants_changed = 'x'
-    flag = 'eventdef_' + events.WaveletParticipantsChanged.type.lower()
-    setattr(FLAGS, flag, 'w.title="New title!"')
-    input_stream = StringIO.StringIO(TEST_JSON)
-    output_stream = StringIO.StringIO()
-    commandline_robot_runner.run_bot(input_stream, output_stream)
-    res = output_stream.getvalue()
-    self.assertTrue('wavelet.setTitle' in res)
-
-
-def main(unused_argv):
-  googletest.main()
-
-
-if __name__ == '__main__':
-  app.run()
diff --git a/wave/src/main/java/python/api/django_oauth.py b/wave/src/main/java/python/api/django_oauth.py
deleted file mode 100644
index 6fd8a3f..0000000
--- a/wave/src/main/java/python/api/django_oauth.py
+++ /dev/null
@@ -1,114 +0,0 @@
-#!/usr/bin/python2.4
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Filter and decorator to wave enable django sites.
-
-If you want to require wave authentication for every handler, just add
-WaveOAuthMiddleware to your middleware. If you only want to require
-authentication for specific handlers, decorate those with @waveoauth.
-
-In any wave authenticated handler the request object should have a
-waveservice field that can be used to talk to wave.
-
-You can specify the following in your settings:
-WAVE_CONSUMER_KEY: the consumer key passed to the waveservice. defaults to
-    anonymous if not set.
-WAVE_CONSUMER_SECRET: the consumer key passed to the waveservice. defaults to
-    anonymous if not set.
-WAVE_USE_SANDBOX: whether to use the sandbox for this app. Defaults to false.
-"""
-
-from django.conf import settings
-from django.http import HttpResponse, HttpResponseRedirect
-from django.contrib.auth import authenticate
-
-import base64
-import logging
-from functools import wraps
-
-import waveservice
-
-
-class WaveOAuthMiddleware(object):
-  """Wave middleware to authenticate all requests at this site."""
-  def process_request(self, request):
-    return _oauth_helper(request)
-
-
-def waveoauth(func):
-  """Decorator used to specify that a handler requires wave authentication."""
-  @wraps(func)
-  def inner(request, *args, **kwargs):
-    result = _oauth_helper(request)
-    if result is not None:
-      return result
-    return func(request, *args, **kwargs)
-  return inner
-
-
-def _oauth_helper(request):
-  "Check if we're authenticated and if not, execute the oauth dance."
-
-  consumer_key = getattr(settings, 'WAVE_CONSUMER_KEY', 'anonymous')
-  consumer_secret = getattr(settings, 'WAVE_CONSUMER_SECRET', 'anonymous')
-  use_sandbox = getattr(settings, 'WAVE_USE_SANDBOX', False)
-
-  service = waveservice.WaveService(
-      consumer_key=consumer_key, consumer_secret=consumer_secret, use_sandbox=use_sandbox)
-
-  access_token = request.COOKIES.get('WAVE_ACCESS_TOKEN')
-  if access_token:
-    service.set_access_token(access_token)
-    request.waveservice = service
-    return None
-
-  # no access token. dance monkey dance.
-  oauth_token = request.GET.get('oauth_token')
-  verifier = request.GET.get('oauth_verifier')
-  request_token = request.COOKIES.get('WAVE_REQUEST_TOKEN')
-  meta = request.META
-
-  # you'd think there would be something better than this madness:
-  this_url = meta.get('HTTP_HOST')
-  if not this_url:
-    this_url = meta.get('SERVER_NAME')
-    port = meta.get('SEVER_PORT')
-    if port:
-      this_url += ':' + port
-  this_url += request.path
-  schema = meta.get('wsgi.url_scheme', 'http')
-  this_url = schema + '://' + this_url
-
-  if not oauth_token or not verifier or not request_token:
-    # we're here not returning from a callback. Start.
-    request_token = service.fetch_request_token(callback=this_url)
-    auth_url = service.generate_authorization_url()
-    response = HttpResponseRedirect(auth_url)
-    # set a session cookie
-    response.set_cookie('WAVE_REQUEST_TOKEN', request_token.to_string())
-    return response
-  else:
-    logging.info('upgrading to access token')
-    access_token = service.upgrade_to_access_token(request_token=request_token,
-                                                   verifier=verifier)
-    # This redirect could be avoided if the caller would set the cookie. This way
-    # however we keep the cgi arguments clean.
-    response = HttpResponseRedirect(this_url)
-    response.set_cookie('WAVE_ACCESS_TOKEN', access_token.to_string(), max_age=24*3600*365)
-    return response
diff --git a/wave/src/main/java/python/api/element.py b/wave/src/main/java/python/api/element.py
deleted file mode 100644
index 42e88b6..0000000
--- a/wave/src/main/java/python/api/element.py
+++ /dev/null
@@ -1,370 +0,0 @@
-#!/usr/bin/python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Elements are non-text bits living in blips like images, gadgets etc.
-
-This module defines the Element class and the derived classes.
-"""
-
-
-import base64
-import logging
-import sys
-
-import util
-
-
-class Element(object):
-  """Elements are non-text content within a document.
-
-  These are generally abstracted from the Robot. Although a Robot can query the
-  properties of an element it can only interact with the specific types that
-  the element represents.
-
-  Properties of elements are both accessible directly (image.url) and through
-  the get method (image.get('url')). In general, Element
-  should not be instantiated by robots, but rather rely on the derived classes.
-  """
-
-  # INLINE_BLIP_TYPE is not a separate type since it shouldn't be instantiated,
-  # only be used for introspection
-  INLINE_BLIP_TYPE = "INLINE_BLIP"
-
-  def __init__(self, element_type, **properties):
-    """Initializes self with the specified type and any properties.
-
-    Args:
-      element_type: string typed member of ELEMENT_TYPE
-      properties: either a dictionary of initial properties, or a dictionary
-          with just one member properties that is itself a dictionary of
-          properties. This allows us to both use
-          e = Element(atype, prop1=val1, prop2=prop2...)
-          and
-          e = Element(atype, properties={prop1:val1, prop2:prop2..})
-    """
-    if len(properties) == 1 and 'properties' in properties:
-      properties = properties['properties']
-    self._type = element_type
-    # as long as the operation_queue of an element in None, it is
-    # unattached. After an element is acquired by a blip, the blip
-    # will set the operation_queue to make sure all changes to the
-    # element are properly send to the server.
-    self._operation_queue = None
-    self._properties = properties.copy()
-  
-  @property
-  def type(self):
-    """The type of this element."""
-    return self._type
-
-  @classmethod
-  def from_json(cls, json):
-    """Class method to instantiate an Element based on a json string."""
-    etype = json['type']
-    props = json['properties'].copy()
-
-    element_class = ALL.get(etype)
-    if not element_class:
-      # Unknown type. Server could be newer than we are
-      return Element(element_type=etype, properties=props)
-
-    return element_class.from_props(props)
-
-  def get(self, key, default=None):
-    """Standard get interface."""
-    return self._properties.get(key, default)
-
-  def __getattr__(self, key):
-    return self._properties[key]
-
-  def serialize(self):
-    """Custom serializer for Elements."""
-    return util.serialize({'properties': util.non_none_dict(self._properties),
-                           'type': self._type})
-
-
-class Input(Element):
-  """A single-line input element."""
-
-  class_type = 'INPUT'
-
-  def __init__(self, name, value=''):
-    super(Input, self).__init__(Input.class_type,
-                                name=name,
-                                value=value,
-                                default_value=value)
-
-  @classmethod
-  def from_props(cls, props):
-    return Input(name=props.get('name'), value=props.get('value'))
-
-
-class Check(Element):
-  """A checkbox element."""
-
-  class_type = 'CHECK'
-
-  def __init__(self, name, value=''):
-    super(Check, self).__init__(Check.class_type,
-                                name=name, value=value, default_value=value)
-
-  @classmethod
-  def from_props(cls, props):
-    return Check(name=props.get('name'), value=props.get('value'))
-
-
-class Button(Element):
-  """A button element."""
-
-  class_type = 'BUTTON'
-
-  def __init__(self, name, value):
-    super(Button, self).__init__(Button.class_type,
-                                 name=name, value=value)
-
-  @classmethod
-  def from_props(cls, props):
-    return Button(name=props.get('name'), value=props.get('value'))
-
-
-class Label(Element):
-  """A label element."""
-
-  class_type = 'LABEL'
-
-  def __init__(self, label_for, caption):
-    super(Label, self).__init__(Label.class_type,
-                                name=label_for, value=caption)
-
-  @classmethod
-  def from_props(cls, props):
-    return Label(label_for=props.get('name'), caption=props.get('value'))
-
-
-class RadioButton(Element):
-  """A radio button element."""
-
-  class_type = 'RADIO_BUTTON'
-
-  def __init__(self, name, group):
-    super(RadioButton, self).__init__(RadioButton.class_type,
-                                      name=name, value=group)
-
-  @classmethod
-  def from_props(cls, props):
-    return RadioButton(name=props.get('name'), group=props.get('value'))
-
-
-class RadioButtonGroup(Element):
-  """A group of radio buttons."""
-
-  class_type = 'RADIO_BUTTON_GROUP'
-
-  def __init__(self, name, value):
-    super(RadioButtonGroup, self).__init__(RadioButtonGroup.class_type,
-                                           name=name, value=value)
-
-  @classmethod
-  def from_props(cls, props):
-    return RadioButtonGroup(name=props.get('name'), value=props.get('value'))
-
-
-class Password(Element):
-  """A password element."""
-
-  class_type = 'PASSWORD'
-
-  def __init__(self, name, value):
-    super(Password, self).__init__(Password.class_type,
-                                   name=name, value=value)
-
-  @classmethod
-  def from_props(cls, props):
-    return Password(name=props.get('name'), value=props.get('value'))
-
-
-class TextArea(Element):
-  """A text area element."""
-
-  class_type = 'TEXTAREA'
-
-  def __init__(self, name, value):
-    super(TextArea, self).__init__(TextArea.class_type,
-                                   name=name, value=value)
-
-  @classmethod
-  def from_props(cls, props):
-    return TextArea(name=props.get('name'), value=props.get('value'))
-
-
-class Line(Element):
-  """A line element.
-  
-  Note that Lines are represented in the text as newlines.
-  """
-
-  class_type = 'LINE'
-
-  # Possible line types:
-  #: Designates line as H1, largest heading.
-  TYPE_H1 = 'h1'
-  #: Designates line as H2 heading.
-  TYPE_H2 = 'h2'
-  #: Designates line as H3 heading.
-  TYPE_H3 = 'h3'
-  #: Designates line as H4 heading.
-  TYPE_H4 = 'h4'
-  #: Designates line as H5, smallest heading.
-  TYPE_H5 = 'h5'
-  #: Designates line as a bulleted list item.
-  TYPE_LI = 'li'
-
-  # Possible values for align
-  #: Sets line alignment to left.
-  ALIGN_LEFT = 'l'
-  #: Sets line alignment to right.
-  ALIGN_RIGHT = 'r'
-  #: Sets line alignment to centered.
-  ALIGN_CENTER = 'c'
-  #: Sets line alignment to justified.
-  ALIGN_JUSTIFIED = 'j'
-
-  def __init__(self,
-               line_type=None,
-               indent=None,
-               alignment=None,
-               direction=None):
-    super(Line, self).__init__(Line.class_type,
-                               lineType=line_type,
-                               indent=indent,
-                               alignment=alignment,
-                               direction=direction)
-
-  @classmethod
-  def from_props(cls, props):
-    return Line(line_type=props.get('lineType'),
-                indent=props.get('indent'),
-                alignment=props.get('alignment'),
-                direction=props.get('direction'))
-
-
-class Gadget(Element):
-  """A gadget element."""
-
-  class_type = 'GADGET'
-
-  def __init__(self, url, props=None):
-    if props is None:
-      props = {}
-    props['url'] = url
-    super(Gadget, self).__init__(Gadget.class_type, properties=props)
-
-  @classmethod
-  def from_props(cls, props):
-    return Gadget(props.get('url'), props)
-
-  def serialize(self):
-    """Gadgets allow for None values."""
-    return {'properties': self._properties, 'type': self._type}
-  
-  def keys(self):
-    """Get the valid keys for this gadget."""
-    return [x for x in self._properties.keys() if x != 'url']
-
-
-class Installer(Element):
-  """An installer element."""
-
-  class_type = 'INSTALLER'
-
-  def __init__(self, manifest):
-    super(Installer, self).__init__(Installer.class_type, manifest=manifest)
-
-  @classmethod
-  def from_props(cls, props):
-    return Installer(props.get('manifest'))
-
-
-
-class Image(Element):
-  """An image element."""
-
-  class_type = 'IMAGE'
-
-  def __init__(self, url='', width=None, height=None,
-               attachmentId=None, caption=None):
-    super(Image, self).__init__(Image.class_type, url=url, width=width,
-          height=height, attachmentId=attachmentId, caption=caption)
-
-  @classmethod
-  def from_props(cls, props):
-    props = dict([(key.encode('utf-8'), value)
-                  for key, value in props.items()])
-    return apply(Image, [], props)
-
-class Attachment(Element):
-  """An attachment element.
-
-  To create a new attachment, caption and data are needed.
-  mimeType, attachmentId and attachmentUrl are sent via events.
-  """
-
-  class_type = 'ATTACHMENT'
-
-  def __init__(self, caption=None, data=None, mimeType=None, attachmentId=None,
-                attachmentUrl=None):
-    Attachment.originalData = data
-    super(Attachment, self).__init__(Attachment.class_type, caption=caption,
-          data=data, mimeType=mimeType, attachmentId=attachmentId,
-          attachmentUrl=attachmentUrl)
-
-  def __getattr__(self, key):
-    if key and key == 'data':
-      return Attachment.originalData
-    return super(Attachment, self).__getattr__(key)
-
-  @classmethod
-  def from_props(cls, props):
-    props = dict([(key.encode('utf-8'), value)
-                  for key, value in props.items()])
-    return apply(Attachment, [], props)
-
-  def serialize(self):
-    """Serializes the attachment object into JSON.
-
-    The attachment data is base64 encoded.
-    """
-
-    if self.data:
-      self._properties['data'] = base64.encodestring(self.data)
-    return super(Attachment, self).serialize()
-
-
-def is_element(cls):
-  """Returns whether the passed class is an element."""
-  try:
-    if not issubclass(cls, Element):
-      return False
-    h = hasattr(cls, 'class_type')
-    return hasattr(cls, 'class_type')
-  except TypeError:
-    return False
-
-ALL = dict([(item.class_type, item) for item in globals().copy().values()
-            if is_element(item)])
diff --git a/wave/src/main/java/python/api/element_test.py b/wave/src/main/java/python/api/element_test.py
deleted file mode 100644
index f1be868..0000000
--- a/wave/src/main/java/python/api/element_test.py
+++ /dev/null
@@ -1,218 +0,0 @@
-#!/usr/bin/python2.4
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Unit tests for the element module."""
-
-
-import base64
-import unittest
-
-import element
-import util
-
-
-class TestElement(unittest.TestCase):
-  """Tests for the element.Element class."""
-
-  def testProperties(self):
-    el = element.Element(element.Gadget.class_type,
-                         key='value')
-    self.assertEquals('value', el.key)
-
-  def testFormElement(self):
-    el = element.Input('input')
-    self.assertEquals(element.Input.class_type, el.type)
-    self.assertEquals(el.value, '')
-    self.assertEquals(el.name, 'input')
-
-  def testImage(self):
-    image = element.Image('http://test.com/image.png', width=100, height=100)
-    self.assertEquals(element.Image.class_type, image.type)
-    self.assertEquals(image.url, 'http://test.com/image.png')
-    self.assertEquals(image.width, 100)
-    self.assertEquals(image.height, 100)
-
-  def testAttachment(self):
-    attachment = element.Attachment(caption='My Favorite', data='SomefakeData')
-    self.assertEquals(element.Attachment.class_type, attachment.type)
-    self.assertEquals(attachment.caption, 'My Favorite')
-    self.assertEquals(attachment.data, 'SomefakeData')
-
-  def testGadget(self):
-    gadget = element.Gadget('http://test.com/gadget.xml')
-    self.assertEquals(element.Gadget.class_type, gadget.type)
-    self.assertEquals(gadget.url, 'http://test.com/gadget.xml')
-
-  def testInstaller(self):
-    installer = element.Installer('http://test.com/installer.xml')
-    self.assertEquals(element.Installer.class_type, installer.type)
-    self.assertEquals(installer.manifest, 'http://test.com/installer.xml')
-
-  def testSerialize(self):
-    image = element.Image('http://test.com/image.png', width=100, height=100)
-    s = util.serialize(image)
-    k = s.keys()
-    k.sort()
-    # we should really only have three things to serialize
-    props = s['properties']
-    self.assertEquals(len(props), 3)
-    self.assertEquals(props['url'], 'http://test.com/image.png')
-    self.assertEquals(props['width'], 100)
-    self.assertEquals(props['height'], 100)
-
-  def testSerializeAttachment(self):
-    attachment = element.Attachment(caption='My Favorite', data='SomefakeData')
-    s = util.serialize(attachment)
-    k = s.keys()
-    k.sort()
-    # we should really have two things to serialize
-    props = s['properties']
-    self.assertEquals(len(props), 2)
-    self.assertEquals(props['caption'], 'My Favorite')
-    self.assertEquals(props['data'], base64.encodestring('SomefakeData'))
-    self.assertEquals(attachment.data, 'SomefakeData')
-
-  def testSerializeLine(self):
-    line = element.Line(element.Line.TYPE_H1, alignment=element.Line.ALIGN_LEFT)
-    s = util.serialize(line)
-    k = s.keys()
-    k.sort()
-    # we should really only have three things to serialize
-    props = s['properties']
-    self.assertEquals(len(props), 2)
-    self.assertEquals(props['alignment'], 'l')
-    self.assertEquals(props['lineType'], 'h1')
-
-  def testSerializeGadget(self):
-    gadget = element.Gadget('http://test.com', {'prop1': 'a', 'prop_cap': None}) 
-    s = util.serialize(gadget)
-    k = s.keys()
-    k.sort()
-    # we should really only have three things to serialize
-    props = s['properties']
-    self.assertEquals(len(props), 3)
-    self.assertEquals(props['url'], 'http://test.com')
-    self.assertEquals(props['prop1'], 'a')
-    self.assertEquals(props['prop_cap'], None)
-
-  def testGadgetElementFromJson(self):
-    url = 'http://www.foo.com/gadget.xml'
-    json = {
-      'type': element.Gadget.class_type,
-      'properties': {
-        'url': url,
-      }
-    }
-    gadget = element.Element.from_json(json)
-    self.assertEquals(element.Gadget.class_type, gadget.type)
-    self.assertEquals(url, gadget.url)
-
-  def testImageElementFromJson(self):
-    url = 'http://www.foo.com/image.png'
-    width = '32'
-    height = '32'
-    attachment_id = '2'
-    caption = 'Test Image'
-    json = {
-      'type': element.Image.class_type,
-      'properties': {
-        'url': url,
-        'width': width,
-        'height': height,
-        'attachmentId': attachment_id,
-        'caption': caption,
-      }
-    }
-    image = element.Element.from_json(json)
-    self.assertEquals(element.Image.class_type, image.type)
-    self.assertEquals(url, image.url)
-    self.assertEquals(width, image.width)
-    self.assertEquals(height, image.height)
-    self.assertEquals(attachment_id, image.attachmentId)
-    self.assertEquals(caption, image.caption)
-
-  def testAttachmentElementFromJson(self):
-    caption = 'fake caption'
-    data = 'fake data'
-    mime_type = 'fake mime'
-    attachment_id = 'fake id'
-    attachment_url = 'fake URL'
-    json = {
-      'type': element.Attachment.class_type,
-      'properties': {
-        'caption': caption,
-        'data': data,
-        'mimeType': mime_type,
-        'attachmentId': attachment_id,
-        'attachmentUrl': attachment_url,
-      }
-    }
-    attachment = element.Element.from_json(json)
-    self.assertEquals(element.Attachment.class_type, attachment.type)
-    self.assertEquals(caption, attachment.caption)
-    self.assertEquals(data, attachment.data)
-    self.assertEquals(mime_type, attachment.mimeType)
-    self.assertEquals(attachment_id, attachment.attachmentId)
-    self.assertEquals(attachment_url, attachment.attachmentUrl)
-
-  def testFormElementFromJson(self):
-    name = 'button'
-    value = 'value'
-    default_value = 'foo'
-    json = {
-      'type': element.Label.class_type,
-      'properties': {
-        'name': name,
-        'value': value,
-        'defaultValue': default_value,
-      }
-    }
-    el = element.Element.from_json(json)
-    self.assertEquals(element.Label.class_type, el.type)
-    self.assertEquals(name, el.name)
-    self.assertEquals(value, el.value)
-
-  def testCanInstantiate(self):
-    bag = [element.Check(name='check', value='value'),
-           element.Button(name='button', value='caption'),
-           element.Input(name='input', value='caption'),
-           element.Label(label_for='button', caption='caption'),
-           element.RadioButton(name='name', group='group'),
-           element.RadioButtonGroup(name='name', value='value'),
-           element.Password(name='name', value='geheim'),
-           element.TextArea(name='name', value='\n\n\n'),
-           element.Installer(manifest='test.com/installer.xml'),
-           element.Line(line_type='type',
-                        indent='3',
-                        alignment='r',
-                        direction='d'),
-           element.Gadget(url='test.com/gadget.xml',
-                          props={'key1': 'val1', 'key2': 'val2'}),
-           element.Image(url='test.com/image.png', width=100, height=200),
-           element.Attachment(caption='fake caption', data='fake data')]
-    types_constructed = set([type(x) for x in bag])
-    types_required = set(element.ALL.values())
-    missing_required = types_constructed.difference(types_required)
-    self.assertEquals(missing_required, set())
-    missing_constructed = types_required.difference(types_constructed)
-    self.assertEquals(missing_constructed, set())
-
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/wave/src/main/java/python/api/errors.py b/wave/src/main/java/python/api/errors.py
deleted file mode 100644
index 89ca0a5..0000000
--- a/wave/src/main/java/python/api/errors.py
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/usr/bin/python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Contains various API-specific exception classes.
-
-This module contains various specific exception classes that are raised by
-the library back to the client.
-"""
-
-
-class Error(Exception):
-  """Base library error type."""
-
-class RpcError(Error):
-  """Wave rpc error."""
diff --git a/wave/src/main/java/python/api/events.py b/wave/src/main/java/python/api/events.py
deleted file mode 100644
index d63b16a..0000000
--- a/wave/src/main/java/python/api/events.py
+++ /dev/null
@@ -1,304 +0,0 @@
-#!/usr/bin/python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Defines event types that are sent from the wave server.
-
-This module defines all of the event types currently supported by the wave
-server. Each event type is sub classed from Event and has its own
-properties depending on the type.
-"""
-
-
-class Context(object):
-  """Specifies constants representing different context requests."""
-
-  #: Requests the root blip.
-  ROOT = 'ROOT'
-  #: Requests the parent blip of the event blip.
-  PARENT = 'PARENT'
-  #: Requests the siblings blip of the event blip.
-  SIBLINGS = 'SIBLINGS'
-  #: Requests the child blips of the event blip.
-  CHILDREN = 'CHILDREN'
-  #: Requests the event blip itself.
-  SELF = 'SELF'
-  #: Requests all of the blips of the event wavelet.
-  ALL = 'ALL'
-
-
-class Event(object):
-  """Object describing a single event.
-
-  Attributes:
-    modified_by: Participant id that caused this event.
-
-    timestamp: Timestamp that this event occurred on the server.
-
-    type: Type string of this event.
-
-    properties: Dictionary of all extra properties. Typically the derrived
-        event type should have these explicitly set as attributes, but
-        experimental features might appear in properties before that.
-
-    blip_id: The blip_id of the blip for blip related events or the root
-        blip for wavelet related events.
-
-    blip: If available, the blip with id equal to the events blip_id.
-
-    proxying_for: If available, the proxyingFor id of the robot that caused the
-    event.
-  """
-
-  def __init__(self, json, wavelet):
-    """Inits this event with JSON data.
-
-    Args:
-      json: JSON data from Wave server.
-    """
-    self.modified_by = json.get('modifiedBy')
-    self.timestamp = json.get('timestamp', 0)
-    self.type = json.get('type')
-    self.raw_data = json
-    self.properties = json.get('properties', {})
-    self.blip_id = self.properties.get('blipId')
-    self.blip = wavelet.blips.get(self.blip_id)
-    self.proxying_for = json.get('proxyingFor')
-
-class WaveletBlipCreated(Event):
-  """Event triggered when a new blip is created.
-
-  Attributes:
-    new_blip_id: The id of the newly created blip.
-
-    new_blip: If in context, the actual new blip.
-  """
-  type = 'WAVELET_BLIP_CREATED'
-
-  def __init__(self, json, wavelet):
-    super(WaveletBlipCreated, self).__init__(json, wavelet)
-    self.new_blip_id = self.properties['newBlipId']
-    self.new_blip = wavelet.blips.get(self.new_blip_id)
-
-
-class WaveletBlipRemoved(Event):
-  """Event triggered when a new blip is removed.
-
-  Attributes:
-    removed_blip_id: the id of the removed blip
-
-    removed_blip: if in context, the removed blip
-  """
-  type = 'WAVELET_BLIP_REMOVED'
-
-  def __init__(self, json, wavelet):
-    super(WaveletBlipRemoved, self).__init__(json, wavelet)
-    self.removed_blip_id = self.properties['removedBlipId']
-    self.removed_blip = wavelet.blips.get(self.removed_blip_id)
-
-
-class WaveletParticipantsChanged(Event):
-  """Event triggered when the participants on a wave change.
-
-  Attributes:
-    participants_added: List of participants added.
-
-    participants_removed: List of participants removed.
-  """
-  type = 'WAVELET_PARTICIPANTS_CHANGED'
-
-  def __init__(self, json, wavelet):
-    super(WaveletParticipantsChanged, self).__init__(json, wavelet)
-    self.participants_added = self.properties['participantsAdded']
-    self.participants_removed = self.properties['participantsRemoved']
-
-
-class WaveletSelfAdded(Event):
-  """Event triggered when the robot is added to the wavelet."""
-  type = 'WAVELET_SELF_ADDED'
-
-
-class WaveletSelfRemoved(Event):
-  """Event triggered when the robot is removed from the wavelet."""
-  type = 'WAVELET_SELF_REMOVED'
-
-
-class WaveletTitleChanged(Event):
-  """Event triggered when the title of the wavelet has changed.
-
-  Attributes:
-    title: The new title.
-  """
-  type = 'WAVELET_TITLE_CHANGED'
-
-  def __init__(self, json, wavelet):
-    super(WaveletTitleChanged, self).__init__(json, wavelet)
-    self.title = self.properties['title']
-
-
-class BlipContributorsChanged(Event):
-  """Event triggered when the contributors to this blip change.
-
-  Attributes:
-    contributors_added: List of contributors that were added.
-
-    contributors_removed: List of contributors that were removed.
-  """
-  type = 'BLIP_CONTRIBUTORS_CHANGED'
-
-  def __init__(self, json, wavelet):
-    super(BlipContributorsChanged, self).__init__(json, wavelet)
-    self.contibutors_added = self.properties['contributorsAdded']
-    self.contibutors_removed = self.properties['contributorsRemoved']
-
-
-class BlipSubmitted(Event):
-  """Event triggered when a blip is submitted."""
-  type = 'BLIP_SUBMITTED'
-
-
-class DocumentChanged(Event):
-  """Event triggered when a document is changed.
-
-  This event is fired after any changes in the document and should be used
-  carefully to keep the amount of traffic to the robot reasonable. Use
-  filters where appropriate.
-  """
-  type = 'DOCUMENT_CHANGED'
-
-
-class FormButtonClicked(Event):
-  """Event triggered when a form button is clicked.
-
-  Attributes:
-    button_name: The name of the button that was clicked.
-  """
-  type = 'FORM_BUTTON_CLICKED'
-
-  def __init__(self, json, wavelet):
-    super(FormButtonClicked, self).__init__(json, wavelet)
-    self.button_name = self.properties['buttonName']
-
-
-class GadgetStateChanged(Event):
-  """Event triggered when the state of a gadget changes.
-
-  Attributes:
-    index: The index of the gadget that changed in the document.
-
-    old_state: The old state of the gadget.
-  """
-  type = 'GADGET_STATE_CHANGED'
-
-  def __init__(self, json, wavelet):
-    super(GadgetStateChanged, self).__init__(json, wavelet)
-    self.index = self.properties['index']
-    self.old_state = self.properties['oldState']
-
-
-class AnnotatedTextChanged(Event):
-  """Event triggered when text with an annotation has changed.
-
-  This is mainly useful in combination with a filter on the
-  name of the annotation.
-
-  Attributes:
-    name: The name of the annotation.
-
-    value: The value of the annotation that changed.
-  """
-  type = 'ANNOTATED_TEXT_CHANGED'
-
-  def __init__(self, json, wavelet):
-    super(AnnotatedTextChanged, self).__init__(json, wavelet)
-    self.name = self.properties['name']
-    self.value = self.properties.get('value')
-
-
-class OperationError(Event):
-  """Triggered when an event on the server occurred.
-
-  Attributes:
-    operation_id: The operation id of the failing operation.
-
-    error_message: More information as to what went wrong.
-  """
-  type = 'OPERATION_ERROR'
-
-  def __init__(self, json, wavelet):
-    super(OperationError, self).__init__(json, wavelet)
-    self.operation_id = self.properties['operationId']
-    self.error_message = self.properties['message']
-
-
-class WaveletCreated(Event):
-  """Triggered when a new wavelet is created.
-
-  This event is only triggered if the robot creates a new
-  wavelet and can be used to initialize the newly created wave.
-  wavelets created by other participants remain invisible
-  to the robot until the robot is added to the wave in
-  which case WaveletSelfAdded is triggered.
-
-  Attributes:
-    message: Whatever string was passed into the new_wave
-        call as message (if any).
-  """
-  type = 'WAVELET_CREATED'
-
-  def __init__(self, json, wavelet):
-    super(WaveletCreated, self).__init__(json, wavelet)
-    self.message = self.properties['message']
-
-
-class WaveletFetched(Event):
-  """Triggered when a new wavelet is fetched.
-
-  This event is triggered after a robot requests to
-  see another wavelet. The robot has to be on the other
-  wavelet already.
-
-  Attributes:
-    message: Whatever string was passed into the new_wave
-        call as message (if any).
-  """
-  type = 'WAVELET_FETCHED'
-
-  def __init__(self, json, wavelet):
-    super(WaveletFetched, self).__init__(json, wavelet)
-    self.message = self.properties['message']
-
-
-class WaveletTagsChanged(Event):
-  """Event triggered when the tags on a wavelet change."""
-  type = 'WAVELET_TAGS_CHANGED'
-
-  def __init__(self, json, wavelet):
-    super(WaveletTagsChanged, self).__init__(json, wavelet)
-
-
-def is_event(cls):
-  """Returns whether the passed class is an event."""
-  try:
-    if not issubclass(cls, Event):
-      return False
-    return hasattr(cls, 'type')
-  except TypeError:
-    return False
-
-ALL = [item for item in globals().copy().values() if is_event(item)]
diff --git a/wave/src/main/java/python/api/module_test_runner.py b/wave/src/main/java/python/api/module_test_runner.py
deleted file mode 100644
index 409519b..0000000
--- a/wave/src/main/java/python/api/module_test_runner.py
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Module defines the ModuleTestRunnerClass."""
-
-
-import unittest
-
-
-class ModuleTestRunner(object):
-  """Responsible for executing all test cases in a list of modules."""
-
-  def __init__(self, module_list=None, module_test_settings=None):
-    self.modules = module_list or []
-    self.settings = module_test_settings or {}
-
-  def RunAllTests(self):
-    """Executes all tests present in the list of modules."""
-    runner = unittest.TextTestRunner()
-    for module in self.modules:
-      for setting, value in self.settings.iteritems():
-        try:
-          setattr(module, setting, value)
-        except AttributeError:
-          print '\nError running ' + str(setting)
-      print '\nRunning all tests in module', module.__name__
-      runner.run(unittest.defaultTestLoader.loadTestsFromModule(module))
diff --git a/wave/src/main/java/python/api/oauth/LICENSE b/wave/src/main/java/python/api/oauth/LICENSE
deleted file mode 100644
index 89f0591..0000000
--- a/wave/src/main/java/python/api/oauth/LICENSE
+++ /dev/null
@@ -1,22 +0,0 @@
-The MIT License
-
-Copyright (c) 2007 Andy Smith
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
diff --git a/wave/src/main/java/python/api/oauth/__init__.py b/wave/src/main/java/python/api/oauth/__init__.py
deleted file mode 100644
index d69d952..0000000
--- a/wave/src/main/java/python/api/oauth/__init__.py
+++ /dev/null
@@ -1,541 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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 cgi
-import urllib
-import time
-import random
-import urlparse
-import hmac
-import base64
-
-VERSION = '1.0' # Hi Blaine!
-HTTP_METHOD = 'GET'
-SIGNATURE_METHOD = 'PLAINTEXT'
-
-# Generic exception class
-class OAuthError(RuntimeError):
-    def __init__(self, message='OAuth error occured.'):
-        self.message = message
-
-# optional WWW-Authenticate header (401 error)
-def build_authenticate_header(realm=''):
-    return {'WWW-Authenticate': 'OAuth realm="%s"' % realm}
-
-# url escape
-def escape(s):
-    # escape '/' too
-    return urllib.quote(s, safe='~')
-
-# util function: current timestamp
-# seconds since epoch (UTC)
-def generate_timestamp():
-    return int(time.time())
-
-# util function: nonce
-# pseudorandom number
-def generate_nonce(length=8):
-    return ''.join(str(random.randint(0, 9)) for i in range(length))
-
-# OAuthConsumer is a data type that represents the identity of the Consumer
-# via its shared secret with the Service Provider.
-class OAuthConsumer(object):
-    key = None
-    secret = None
-
-    def __init__(self, key, secret):
-        self.key = key
-        self.secret = secret
-
-# OAuthToken is a data type that represents an End User via either an access
-# or request token.     
-class OAuthToken(object):
-    # access tokens and request tokens
-    key = None
-    secret = None
-
-    '''
-    key = the token
-    secret = the token secret
-    '''
-    def __init__(self, key, secret):
-        self.key = key
-        self.secret = secret
-
-    def to_string(self):
-        return urllib.urlencode({'oauth_token': self.key, 'oauth_token_secret': self.secret})
-
-    # return a token from something like:
-    # oauth_token_secret=digg&oauth_token=digg
-    @staticmethod   
-    def from_string(s):
-        params = cgi.parse_qs(s, keep_blank_values=False)
-        key = params['oauth_token'][0]
-        secret = params['oauth_token_secret'][0]
-        return OAuthToken(key, secret)
-
-    def __str__(self):
-        return self.to_string()
-
-# OAuthRequest represents the request and can be serialized
-class OAuthRequest(object):
-    '''
-    OAuth parameters:
-        - oauth_consumer_key 
-        - oauth_token
-        - oauth_signature_method
-        - oauth_signature 
-        - oauth_timestamp 
-        - oauth_nonce
-        - oauth_version
-        ... any additional parameters, as defined by the Service Provider.
-    '''
-    parameters = None # oauth parameters
-    http_method = HTTP_METHOD
-    http_url = None
-    version = VERSION
-
-    def __init__(self, http_method=HTTP_METHOD, http_url=None, parameters=None):
-        self.http_method = http_method
-        self.http_url = http_url
-        self.parameters = parameters or {}
-
-    def set_parameter(self, parameter, value):
-        self.parameters[parameter] = value
-
-    def get_parameter(self, parameter):
-        try:
-            return self.parameters[parameter]
-        except:
-            raise OAuthError('Parameter not found: %s' % parameter)
-
-    def _get_timestamp_nonce(self):
-        return self.get_parameter('oauth_timestamp'), self.get_parameter('oauth_nonce')
-
-    # get any non-oauth parameters
-    def get_nonoauth_parameters(self):
-        parameters = {}
-        for k, v in self.parameters.iteritems():
-            # ignore oauth parameters
-            if k.find('oauth_') < 0:
-                parameters[k] = v
-        return parameters
-
-    # serialize as a header for an HTTPAuth request
-    def to_header(self, realm=''):
-        auth_header = 'OAuth realm="%s"' % realm
-        # add the oauth parameters
-        if self.parameters:
-            for k, v in self.parameters.iteritems():
-                auth_header += ', %s="%s"' % (k, escape(str(v)))
-        return {'Authorization': auth_header}
-
-    # serialize as post data for a POST request
-    def to_postdata(self):
-        return '&'.join('%s=%s' % (escape(str(k)), escape(str(v))) for k, v in self.parameters.iteritems())
-
-    # serialize as a url for a GET request
-    def to_url(self):
-        return '%s?%s' % (self.get_normalized_http_url(), self.to_postdata())
-
-    # return a string that consists of all the parameters that need to be signed
-    def get_normalized_parameters(self):
-        params = self.parameters
-        try:
-            # exclude the signature if it exists
-            del params['oauth_signature']
-        except:
-            pass
-        key_values = params.items()
-        # sort lexicographically, first after key, then after value
-        key_values.sort()
-        # combine key value pairs in string and escape
-        return '&'.join('%s=%s' % (escape(str(k)), escape(str(v))) for k, v in key_values)
-
-    # just uppercases the http method
-    def get_normalized_http_method(self):
-        return self.http_method.upper()
-
-    # parses the url and rebuilds it to be scheme://host/path
-    def get_normalized_http_url(self):
-        parts = urlparse.urlparse(self.http_url)
-        url_string = '%s://%s%s' % (parts[0], parts[1], parts[2]) # scheme, netloc, path
-        return url_string
-        
-    # set the signature parameter to the result of build_signature
-    def sign_request(self, signature_method, consumer, token):
-        # set the signature method
-        self.set_parameter('oauth_signature_method', signature_method.get_name())
-        # set the signature
-        self.set_parameter('oauth_signature', self.build_signature(signature_method, consumer, token))
-
-    def build_signature(self, signature_method, consumer, token):
-        # call the build signature method within the signature method
-        return signature_method.build_signature(self, consumer, token)
-
-    @staticmethod
-    def from_request(http_method, http_url, headers=None, parameters=None, query_string=None):
-        # combine multiple parameter sources
-        if parameters is None:
-            parameters = {}
-
-        # headers
-        if headers and 'Authorization' in headers:
-            auth_header = headers['Authorization']
-            # check that the authorization header is OAuth
-            if auth_header.index('OAuth') > -1:
-                try:
-                    # get the parameters from the header
-                    header_params = OAuthRequest._split_header(auth_header)
-                    parameters.update(header_params)
-                except:
-                    raise OAuthError('Unable to parse OAuth parameters from Authorization header.')
-
-        # GET or POST query string
-        if query_string:
-            query_params = OAuthRequest._split_url_string(query_string)
-            parameters.update(query_params)
-
-        # URL parameters
-        param_str = urlparse.urlparse(http_url)[4] # query
-        url_params = OAuthRequest._split_url_string(param_str)
-        parameters.update(url_params)
-
-        if parameters:
-            return OAuthRequest(http_method, http_url, parameters)
-
-        return None
-
-    @staticmethod
-    def from_consumer_and_token(oauth_consumer, token=None, http_method=HTTP_METHOD, http_url=None, parameters=None):
-        if not parameters:
-            parameters = {}
-
-        defaults = {
-            'oauth_consumer_key': oauth_consumer.key,
-            'oauth_timestamp': generate_timestamp(),
-            'oauth_nonce': generate_nonce(),
-            'oauth_version': OAuthRequest.version,
-        }
-
-        defaults.update(parameters)
-        parameters = defaults
-
-        if token:
-            parameters['oauth_token'] = token.key
-
-        return OAuthRequest(http_method, http_url, parameters)
-
-    @staticmethod
-    def from_token_and_callback(token, callback=None, http_method=HTTP_METHOD, http_url=None, parameters=None):
-        if not parameters:
-            parameters = {}
-
-        parameters['oauth_token'] = token.key
-
-        if callback:
-            parameters['oauth_callback'] = escape(callback)
-
-        return OAuthRequest(http_method, http_url, parameters)
-
-    # util function: turn Authorization: header into parameters, has to do some unescaping
-    @staticmethod
-    def _split_header(header):
-        params = {}
-        parts = header.split(',')
-        for param in parts:
-            # ignore realm parameter
-            if param.find('OAuth realm') > -1:
-                continue
-            # remove whitespace
-            param = param.strip()
-            # split key-value
-            param_parts = param.split('=', 1)
-            # remove quotes and unescape the value
-            params[param_parts[0]] = urllib.unquote(param_parts[1].strip('\"'))
-        return params
-    
-    # util function: turn url string into parameters, has to do some unescaping
-    @staticmethod
-    def _split_url_string(param_str):
-        parameters = cgi.parse_qs(param_str, keep_blank_values=False)
-        for k, v in parameters.iteritems():
-            parameters[k] = urllib.unquote(v[0])
-        return parameters
-
-# OAuthServer is a worker to check a requests validity against a data store
-class OAuthServer(object):
-    timestamp_threshold = 300 # in seconds, five minutes
-    version = VERSION
-    signature_methods = None
-    data_store = None
-
-    def __init__(self, data_store=None, signature_methods=None):
-        self.data_store = data_store
-        self.signature_methods = signature_methods or {}
-
-    def set_data_store(self, oauth_data_store):
-        self.data_store = data_store
-
-    def get_data_store(self):
-        return self.data_store
-
-    def add_signature_method(self, signature_method):
-        self.signature_methods[signature_method.get_name()] = signature_method
-        return self.signature_methods
-
-    # process a request_token request
-    # returns the request token on success
-    def fetch_request_token(self, oauth_request):
-        try:
-            # get the request token for authorization
-            token = self._get_token(oauth_request, 'request')
-        except OAuthError:
-            # no token required for the initial token request
-            version = self._get_version(oauth_request)
-            consumer = self._get_consumer(oauth_request)
-            self._check_signature(oauth_request, consumer, None)
-            # fetch a new token
-            token = self.data_store.fetch_request_token(consumer)
-        return token
-
-    # process an access_token request
-    # returns the access token on success
-    def fetch_access_token(self, oauth_request):
-        version = self._get_version(oauth_request)
-        consumer = self._get_consumer(oauth_request)
-        # get the request token
-        token = self._get_token(oauth_request, 'request')
-        self._check_signature(oauth_request, consumer, token)
-        new_token = self.data_store.fetch_access_token(consumer, token)
-        return new_token
-
-    # verify an api call, checks all the parameters
-    def verify_request(self, oauth_request):
-        # -> consumer and token
-        version = self._get_version(oauth_request)
-        consumer = self._get_consumer(oauth_request)
-        # get the access token
-        token = self._get_token(oauth_request, 'access')
-        self._check_signature(oauth_request, consumer, token)
-        parameters = oauth_request.get_nonoauth_parameters()
-        return consumer, token, parameters
-
-    # authorize a request token
-    def authorize_token(self, token, user):
-        return self.data_store.authorize_request_token(token, user)
-    
-    # get the callback url
-    def get_callback(self, oauth_request):
-        return oauth_request.get_parameter('oauth_callback')
-
-    # optional support for the authenticate header   
-    def build_authenticate_header(self, realm=''):
-        return {'WWW-Authenticate': 'OAuth realm="%s"' % realm}
-
-    # verify the correct version request for this server
-    def _get_version(self, oauth_request):
-        try:
-            version = oauth_request.get_parameter('oauth_version')
-        except:
-            version = VERSION
-        if version and version != self.version:
-            raise OAuthError('OAuth version %s not supported.' % str(version))
-        return version
-
-    # figure out the signature with some defaults
-    def _get_signature_method(self, oauth_request):
-        try:
-            signature_method = oauth_request.get_parameter('oauth_signature_method')
-        except:
-            signature_method = SIGNATURE_METHOD
-        try:
-            # get the signature method object
-            signature_method = self.signature_methods[signature_method]
-        except:
-            signature_method_names = ', '.join(self.signature_methods.keys())
-            raise OAuthError('Signature method %s not supported try one of the following: %s' % (signature_method, signature_method_names))
-
-        return signature_method
-
-    def _get_consumer(self, oauth_request):
-        consumer_key = oauth_request.get_parameter('oauth_consumer_key')
-        if not consumer_key:
-            raise OAuthError('Invalid consumer key.')
-        consumer = self.data_store.lookup_consumer(consumer_key)
-        if not consumer:
-            raise OAuthError('Invalid consumer.')
-        return consumer
-
-    # try to find the token for the provided request token key
-    def _get_token(self, oauth_request, token_type='access'):
-        token_field = oauth_request.get_parameter('oauth_token')
-        token = self.data_store.lookup_token(token_type, token_field)
-        if not token:
-            raise OAuthError('Invalid %s token: %s' % (token_type, token_field))
-        return token
-
-    def _check_signature(self, oauth_request, consumer, token):
-        timestamp, nonce = oauth_request._get_timestamp_nonce()
-        self._check_timestamp(timestamp)
-        self._check_nonce(consumer, token, nonce)
-        signature_method = self._get_signature_method(oauth_request)
-        try:
-            signature = oauth_request.get_parameter('oauth_signature')
-        except:
-            raise OAuthError('Missing signature.')
-        # validate the signature
-        valid_sig = signature_method.check_signature(oauth_request, consumer, token, signature)
-        if not valid_sig:
-            key, base = signature_method.build_signature_base_string(oauth_request, consumer, token)
-            raise OAuthError('Invalid signature. Expected signature base string: %s' % base)
-        built = signature_method.build_signature(oauth_request, consumer, token)
-
-    def _check_timestamp(self, timestamp):
-        # verify that timestamp is recentish
-        timestamp = int(timestamp)
-        now = int(time.time())
-        lapsed = now - timestamp
-        if lapsed > self.timestamp_threshold:
-            raise OAuthError('Expired timestamp: given %d and now %s has a greater difference than threshold %d' % (timestamp, now, self.timestamp_threshold))
-
-    def _check_nonce(self, consumer, token, nonce):
-        # verify that the nonce is uniqueish
-        nonce = self.data_store.lookup_nonce(consumer, token, nonce)
-        if nonce:
-            raise OAuthError('Nonce already used: %s' % str(nonce))
-
-# OAuthClient is a worker to attempt to execute a request
-class OAuthClient(object):
-    consumer = None
-    token = None
-
-    def __init__(self, oauth_consumer, oauth_token):
-        self.consumer = oauth_consumer
-        self.token = oauth_token
-
-    def get_consumer(self):
-        return self.consumer
-
-    def get_token(self):
-        return self.token
-
-    def fetch_request_token(self, oauth_request):
-        # -> OAuthToken
-        raise NotImplementedError
-
-    def fetch_access_token(self, oauth_request):
-        # -> OAuthToken
-        raise NotImplementedError
-
-    def access_resource(self, oauth_request):
-        # -> some protected resource
-        raise NotImplementedError
-
-# OAuthDataStore is a database abstraction used to lookup consumers and tokens
-class OAuthDataStore(object):
-
-    def lookup_consumer(self, key):
-        # -> OAuthConsumer
-        raise NotImplementedError
-
-    def lookup_token(self, oauth_consumer, token_type, token_token):
-        # -> OAuthToken
-        raise NotImplementedError
-
-    def lookup_nonce(self, oauth_consumer, oauth_token, nonce, timestamp):
-        # -> OAuthToken
-        raise NotImplementedError
-
-    def fetch_request_token(self, oauth_consumer):
-        # -> OAuthToken
-        raise NotImplementedError
-
-    def fetch_access_token(self, oauth_consumer, oauth_token):
-        # -> OAuthToken
-        raise NotImplementedError
-
-    def authorize_request_token(self, oauth_token, user):
-        # -> OAuthToken
-        raise NotImplementedError
-
-# OAuthSignatureMethod is a strategy class that implements a signature method
-class OAuthSignatureMethod(object):
-    def get_name(self):
-        # -> str
-        raise NotImplementedError
-
-    def build_signature_base_string(self, oauth_request, oauth_consumer, oauth_token):
-        # -> str key, str raw
-        raise NotImplementedError
-
-    def build_signature(self, oauth_request, oauth_consumer, oauth_token):
-        # -> str
-        raise NotImplementedError
-
-    def check_signature(self, oauth_request, consumer, token, signature):
-        built = self.build_signature(oauth_request, consumer, token)
-        return built == signature
-
-class OAuthSignatureMethod_HMAC_SHA1(OAuthSignatureMethod):
-
-    def get_name(self):
-        return 'HMAC-SHA1'
-        
-    def build_signature_base_string(self, oauth_request, consumer, token):
-        sig = (
-            escape(oauth_request.get_normalized_http_method()),
-            escape(oauth_request.get_normalized_http_url()),
-            escape(oauth_request.get_normalized_parameters()),
-        )
-
-        key = '%s&' % escape(consumer.secret)
-        if token:
-            key += escape(token.secret)
-        raw = '&'.join(sig)
-        return key, raw
-
-    def build_signature(self, oauth_request, consumer, token):
-        # build the base signature string
-        key, raw = self.build_signature_base_string(oauth_request, consumer, token)
-
-        # hmac object
-        try:
-            import hashlib # 2.5
-            hashed = hmac.new(key, raw, hashlib.sha1)
-        except:
-            import sha # deprecated
-            hashed = hmac.new(key, raw, sha)
-
-        # calculate the digest base 64
-        return base64.b64encode(hashed.digest())
-
-class OAuthSignatureMethod_PLAINTEXT(OAuthSignatureMethod):
-
-    def get_name(self):
-        return 'PLAINTEXT'
-
-    def build_signature_base_string(self, oauth_request, consumer, token):
-        # concatenate the consumer key and secret
-        sig = escape(consumer.secret) + '&'
-        if token:
-            sig = sig + escape(token.secret)
-        return sig
-
-    def build_signature(self, oauth_request, consumer, token):
-        return self.build_signature_base_string(oauth_request, consumer, token)
diff --git a/wave/src/main/java/python/api/ops.py b/wave/src/main/java/python/api/ops.py
deleted file mode 100644
index 862c4b5..0000000
--- a/wave/src/main/java/python/api/ops.py
+++ /dev/null
@@ -1,482 +0,0 @@
-#!/usr/bin/python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Support for operations that can be applied to the server.
-
-Contains classes and utilities for creating operations that are to be
-applied on the server.
-"""
-
-import errors
-import random
-import util
-import sys
-
-
-PROTOCOL_VERSION = '0.22'
-
-# Operation Types
-WAVELET_APPEND_BLIP = 'wavelet.appendBlip'
-WAVELET_SET_TITLE = 'wavelet.setTitle'
-WAVELET_ADD_PARTICIPANT = 'wavelet.participant.add'
-WAVELET_DATADOC_SET = 'wavelet.datadoc.set'
-WAVELET_MODIFY_TAG = 'wavelet.modifyTag'
-WAVELET_MODIFY_PARTICIPANT_ROLE = 'wavelet.modifyParticipantRole'
-BLIP_CONTINUE_THREAD = 'blip.continueThread'
-BLIP_CREATE_CHILD = 'blip.createChild'
-BLIP_DELETE = 'blip.delete'
-DOCUMENT_APPEND_MARKUP = 'document.appendMarkup'
-DOCUMENT_INLINE_BLIP_INSERT = 'document.inlineBlip.insert'
-DOCUMENT_MODIFY = 'document.modify'
-ROBOT_CREATE_WAVELET = 'robot.createWavelet'
-ROBOT_FETCH_WAVE = 'robot.fetchWave'
-ROBOT_NOTIFY = 'robot.notify'
-ROBOT_SEARCH = 'robot.search'
-
-# Assign always NOTIFY_OP_ID to the notify operation so
-# we can easily filter it out later
-NOTIFY_OP_ID = '0'
-
-class Operation(object):
-  """Represents a generic operation applied on the server.
-
-  This operation class contains data that is filled in depending on the
-  operation type.
-
-  It can be used directly, but doing so will not result
-  in local, transient reflection of state on the blips. In other words,
-  creating a 'delete blip' operation will not remove the blip from the local
-  context for the duration of this session. It is better to use the OpBased
-  model classes directly instead.
-  """
-
-  def __init__(self, method, opid, params):
-    """Initializes this operation with contextual data.
-
-    Args:
-      method: Method to call or type of operation.
-      opid: The id of the operation. Any callbacks will refer to these.
-      params: An operation type dependent dictionary
-    """
-    self.method = method
-    self.id = opid
-    self.params = params
-
-  def __str__(self):
-    return '%s[%s]%s' % (self.method, self.id, str(self.params))
-
-  def set_param(self, param, value):
-    self.params[param] = value
-    return self
-
-  def serialize(self, method_prefix=''):
-    """Serialize the operation.
-
-    Args:
-      method_prefix: prefixed for each method name to allow for specifying
-      a namespace.
-
-    Returns:
-      a dict representation of the operation.
-    """
-    if method_prefix and not method_prefix.endswith('.'):
-      method_prefix += '.'
-    return {'method': method_prefix + self.method,
-            'id': self.id,
-            'params': util.serialize(self.params)}
-
-  def set_optional(self, param, value):
-    """Sets an optional parameter.
-
-    If value is None or "", this is a no op. Otherwise it calls
-    set_param.
-    """
-    if value == '' or value is None:
-      return self
-    else:
-      return self.set_param(param, value)
-
-
-class OperationQueue(object):
-  """Wraps the queuing of operations using easily callable functions.
-
-  The operation queue wraps single operations as functions and queues the
-  resulting operations in-order. Typically there shouldn't be a need to
-  call this directly unless operations are needed on entities outside
-  of the scope of the robot. For example, to modify a blip that
-  does not exist in the current context, you might specify the wave, wavelet
-  and blip id to generate an operation.
-
-  Any calls to this will not be reflected in the robot in any way.
-  For example, calling wavelet_append_blip will not result in a new blip
-  being added to the robot, only an operation to be applied on the
-  server.
-  """
-
-  # Some class global counters:
-  _next_operation_id = 1
-
-  def __init__(self, proxy_for_id=None):
-    self.__pending = []
-    self._capability_hash = None
-    self._proxy_for_id = proxy_for_id
-
-  def _new_blipdata(self, wave_id, wavelet_id, initial_content='',
-                    parent_blip_id=None):
-    """Creates JSON of the blip used for this session."""
-    temp_blip_id = 'TBD_%s_%s' % (wavelet_id,
-                                  hex(random.randint(0, sys.maxint)))
-    return {'waveId': wave_id,
-            'waveletId': wavelet_id,
-            'blipId': temp_blip_id,
-            'content': initial_content,
-            'parentBlipId': parent_blip_id}
-
-  def _new_waveletdata(self, domain, participants):
-    """Creates an ephemeral WaveletData instance used for this session.
-
-    Args:
-      domain: the domain to create the data for.
-      participants initially on the wavelet
-    Returns:
-      Blipdata (for the rootblip), WaveletData.
-    """
-    wave_id = domain + '!TBD_%s' % hex(random.randint(0, sys.maxint))
-    wavelet_id = domain + '!conv+root'
-    root_blip_data = self._new_blipdata(wave_id, wavelet_id)
-    participants = set(participants)
-    wavelet_data = {'waveId': wave_id,
-                    'waveletId': wavelet_id,
-                    'rootBlipId': root_blip_data['blipId'],
-                    'participants': participants}
-    return root_blip_data, wavelet_data
-
-  def __len__(self):
-    return len(self.__pending)
-
-  def __iter__(self):
-    return self.__pending.__iter__()
-
-  def clear(self):
-    self.__pending = []
-
-  def proxy_for(self, proxy):
-    """Return a view of this operation queue with the proxying for set to proxy.
-
-    This method returns a new instance of an operation queue that shares the
-    operation list, but has a different proxying_for_id set so the robot using
-    this new queue will send out operations with the proxying_for field set.
-    """
-    res = OperationQueue()
-    res.__pending = self.__pending
-    res._capability_hash = self._capability_hash
-    res._proxy_for_id = proxy
-    return res
-
-  def set_capability_hash(self, capability_hash):
-    self._capability_hash = capability_hash
-
-  def serialize(self, method_prefix=''):
-    first = Operation(ROBOT_NOTIFY,
-                      NOTIFY_OP_ID,
-                      {'capabilitiesHash': self._capability_hash,
-                       'protocolVersion': PROTOCOL_VERSION})
-    operations = [first] + self.__pending
-    return [op.serialize(method_prefix=method_prefix) for op in operations]
-    res = util.serialize(operations)
-    return res
-
-  def copy_operations(self, other_queue):
-    """Copy the pending operations from other_queue into this one."""
-    for op in other_queue:
-      self.__pending.append(op)
-
-  def new_operation(self, method, wave_id, wavelet_id, props=None, **kwprops):
-    """Creates and adds a new operation to the operation list."""
-    if props is None:
-      props = {}
-    props.update(kwprops)
-    if wave_id is not None:
-      props['waveId'] = wave_id
-    if wavelet_id is not None:
-      props['waveletId'] = wavelet_id
-    if self._proxy_for_id:
-      props['proxyingFor'] = self._proxy_for_id
-    operation = Operation(method,
-                          'op%s' % OperationQueue._next_operation_id,
-                          props)
-    self.__pending.append(operation)
-    OperationQueue._next_operation_id += 1
-    return operation
-
-  def wavelet_append_blip(self, wave_id, wavelet_id, initial_content=''):
-    """Appends a blip to a wavelet.
-
-    Args:
-      wave_id: The wave id owning the containing wavelet.
-      wavelet_id: The wavelet id that this blip should be appended to.
-      initial_content: optionally the content to start with
-
-    Returns:
-      JSON representing the information of the new blip.
-    """
-    blip_data = self._new_blipdata(wave_id, wavelet_id, initial_content)
-    self.new_operation(WAVELET_APPEND_BLIP, wave_id,
-                       wavelet_id, blipData=blip_data)
-    return blip_data
-
-  def wavelet_add_participant(self, wave_id, wavelet_id, participant_id):
-    """Adds a participant to a wavelet.
-
-    Args:
-      wave_id: The wave id owning that this operation is applied to.
-      wavelet_id: The wavelet id that this operation is applied to.
-      participant_id: Id of the participant to add.
-
-    Returns:
-      data for the root_blip, wavelet
-    """
-    return self.new_operation(WAVELET_ADD_PARTICIPANT, wave_id, wavelet_id,
-                              participantId=participant_id)
-
-  def wavelet_datadoc_set(self, wave_id, wavelet_id, name, data):
-    """Sets a key/value pair on the data document of a wavelet.
-
-    Args:
-      wave_id: The wave id owning that this operation is applied to.
-      wavelet_id: The wavelet id that this operation is applied to.
-      name: The key name for this data.
-      data: The value of the data to set.
-    Returns:
-      The operation created.
-    """
-    return self.new_operation(WAVELET_DATADOC_SET, wave_id, wavelet_id,
-                              datadocName=name, datadocValue=data)
-
-  def robot_create_wavelet(self, domain, participants=None, message=''):
-    """Creates a new wavelet.
-
-    Args:
-      domain: the domain to create the wave in
-      participants: initial participants on this wavelet or None if none
-      message: an optional payload that is returned with the corresponding
-          event.
-
-    Returns:
-      data for the root_blip, wavelet
-    """
-    if participants is None:
-      participants = []
-    blip_data, wavelet_data = self._new_waveletdata(domain, participants)
-    op = self.new_operation(ROBOT_CREATE_WAVELET,
-                            wave_id=wavelet_data['waveId'],
-                            wavelet_id=wavelet_data['waveletId'],
-                            waveletData=wavelet_data)
-    op.set_optional('message', message)
-    return blip_data, wavelet_data
-
-  def robot_search(self, query, index=None, num_results=None):
-    """Execute a search request.
-
-    For now this only makes sense in the data API. Wave does not maintain
-    an index for robots so no results will be returned in that scenario.
-
-    Args:
-      query: what to search for
-      index: what index to search from
-      num_results: how many results to return
-    Returns:
-      The operation created.
-    """
-    op = self.new_operation(
-        ROBOT_SEARCH, wave_id=None, wavelet_id=None, query=query)
-    if index is not None:
-      op.set_param('index', index)
-    if num_results is not None:
-      op.set_param('numResults', num_results)
-    return op
-
-  def robot_fetch_wave(self, wave_id, wavelet_id,
-      raw_deltas_from_version=-1, return_raw_snapshot=False):
-    """Requests a snapshot of the specified wavelet.
-
-    Args:
-      wave_id: The wave id owning that this operation is applied to.
-      wavelet_id: The wavelet id that this operation is applied to.
-      raw_deltas_from_version: If specified, return a raw dump of the
-        delta history of this wavelet, starting at the given version.
-        This may return only part of the history; use additional
-        requests with higher raw_deltas_from_version parameters to
-        get the rest.
-      return_raw_snapshot: if true, return the raw data for this
-        wavelet.
-    Returns:
-      The operation created.
-    """
-    op = self.new_operation(ROBOT_FETCH_WAVE, wave_id, wavelet_id)
-    if raw_deltas_from_version != -1:
-      op.set_param('rawDeltasFromVersion', raw_deltas_from_version)
-    if return_raw_snapshot:
-      op.set_param('returnRawSnapshot', return_raw_snapshot)
-    return op
-
-  def wavelet_set_title(self, wave_id, wavelet_id, title):
-    """Sets the title of a wavelet.
-
-    Args:
-      wave_id: The wave id owning that this operation is applied to.
-      wavelet_id: The wavelet id that this operation is applied to.
-      title: The title to set.
-    Returns:
-      The operation created.
-    """
-    return self.new_operation(WAVELET_SET_TITLE, wave_id, wavelet_id,
-                              waveletTitle=title)
-
-  def wavelet_modify_participant_role(
-      self, wave_id, wavelet_id, participant_id, role):
-    """Modify the role of a participant on a wavelet.
-
-    Args:
-      wave_id: The wave id owning that this operation is applied to.
-      wavelet_id: The wavelet id that this operation is applied to.
-      participant_id: Id of the participant to add.
-      role: the new roles
-
-    Returns:
-      data for the root_blip, wavelet
-    """
-    return self.new_operation(WAVELET_MODIFY_PARTICIPANT_ROLE, wave_id,
-                              wavelet_id, participantId=participant_id,
-                              participantRole=role)
-
-  def wavelet_modify_tag(self, wave_id, wavelet_id, tag, modify_how=None):
-    """Modifies a tag in a wavelet.
-
-    Args:
-      wave_id: The wave id owning that this operation is applied to.
-      wavelet_id: The wavelet id that this operation is applied to.
-      tag: The tag (a string).
-      modify_how: (optional) how to apply the tag. The default is to add
-        the tag. Specify 'remove' to remove. Specify None or 'add' to
-        add.
-    Returns:
-      The operation created.
-    """
-    return self.new_operation(WAVELET_MODIFY_TAG, wave_id, wavelet_id,
-                             name=tag).set_optional("modify_how", modify_how)
-
-  def blip_create_child(self, wave_id, wavelet_id, blip_id):
-    """Creates a child blip of another blip.
-
-    Args:
-      wave_id: The wave id owning that this operation is applied to.
-      wavelet_id: The wavelet id that this operation is applied to.
-      blip_id: The blip id that this operation is applied to.
-
-    Returns:
-      JSON of blip for which further operations can be applied.
-    """
-    blip_data = self._new_blipdata(wave_id, wavelet_id, parent_blip_id=blip_id)
-    self.new_operation(BLIP_CREATE_CHILD, wave_id, wavelet_id,
-                       blipId=blip_id,
-                       blipData=blip_data)
-    return blip_data
-
-  def blip_continue_thread(self, wave_id, wavelet_id, blip_id):
-    """Creates a blip in same thread as specified blip.
-
-    Args:
-      wave_id: The wave id owning that this operation is applied to.
-      wavelet_id: The wavelet id that this operation is applied to.
-      blip_id: The blip id that this operation is applied to.
-
-    Returns:
-      JSON of blip for which further operations can be applied.
-    """
-    blip_data = self._new_blipdata(wave_id, wavelet_id)
-    self.new_operation(BLIP_CONTINUE_THREAD, wave_id, wavelet_id,
-                       blipId=blip_id,
-                       blipData=blip_data)
-    return blip_data
-
-
-  def blip_delete(self, wave_id, wavelet_id, blip_id):
-    """Deletes the specified blip.
-
-    Args:
-      wave_id: The wave id owning that this operation is applied to.
-      wavelet_id: The wavelet id that this operation is applied to.
-      blip_id: The blip id that this operation is applied to.
-    Returns:
-      The operation created.
-    """
-    return self.new_operation(BLIP_DELETE, wave_id, wavelet_id, blipId=blip_id)
-
-  def document_append_markup(self, wave_id, wavelet_id, blip_id, content):
-    """Appends content with markup to a document.
-
-    Args:
-      wave_id: The wave id owning that this operation is applied to.
-      wavelet_id: The wavelet id that this operation is applied to.
-      blip_id: The blip id that this operation is applied to.
-      content: The markup content to append.
-    Returns:
-      The operation created.
-    """
-    return self.new_operation(DOCUMENT_APPEND_MARKUP, wave_id, wavelet_id,
-                              blipId=blip_id, content=content)
-
-  def document_modify(self, wave_id, wavelet_id, blip_id):
-    """Creates and queues a document modify operation
-
-    The returned operation still needs to be filled with details before
-    it makes sense.
-
-    Args:
-      wave_id: The wave id owning that this operation is applied to.
-      wavelet_id: The wavelet id that this operation is applied to.
-      blip_id: The blip id that this operation is applied to.
-    Returns:
-      The operation created.
-    """
-    return self.new_operation(DOCUMENT_MODIFY,
-                              wave_id,
-                              wavelet_id,
-                              blipId=blip_id)
-
-  def document_inline_blip_insert(self, wave_id, wavelet_id, blip_id, position):
-    """Inserts an inline blip at a specific location.
-
-    Args:
-      wave_id: The wave id owning that this operation is applied to.
-      wavelet_id: The wavelet id that this operation is applied to.
-      blip_id: The blip id that this operation is applied to.
-      position: The position in the document to insert the blip.
-
-    Returns:
-      JSON data for the blip that was created for further operations.
-    """
-    inline_blip_data = self._new_blipdata(wave_id, wavelet_id)
-    inline_blip_data['parentBlipId'] = blip_id
-    self.new_operation(DOCUMENT_INLINE_BLIP_INSERT, wave_id, wavelet_id,
-                       blipId=blip_id,
-                       index=position,
-                       blipData=inline_blip_data)
-    return inline_blip_data
diff --git a/wave/src/main/java/python/api/ops_test.py b/wave/src/main/java/python/api/ops_test.py
deleted file mode 100644
index 37f1d85..0000000
--- a/wave/src/main/java/python/api/ops_test.py
+++ /dev/null
@@ -1,75 +0,0 @@
-#!/usr/bin/python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Unit tests for the ops module."""
-
-
-import unittest
-
-import ops
-
-
-class TestOperation(unittest.TestCase):
-  """Test case for Operation class."""
-
-  def testFields(self):
-    op = ops.Operation(ops.WAVELET_SET_TITLE, 'opid02',
-                       {'waveId': 'wavelet-id',
-                        'title': 'a title'})
-    self.assertEqual(ops.WAVELET_SET_TITLE, op.method)
-    self.assertEqual('opid02', op.id)
-    self.assertEqual(2, len(op.params))
-
-  def testConstructModifyTag(self):
-    q = ops.OperationQueue()
-    op = q.wavelet_modify_tag('waveid', 'waveletid', 'tag')
-    self.assertEqual(3, len(op.params))
-    op = q.wavelet_modify_tag(
-        'waveid', 'waveletid', 'tag', modify_how='remove')
-    self.assertEqual(4, len(op.params))
-
-  def testConstructRobotFetchWave(self):
-    q = ops.OperationQueue('proxyid')
-    op = q.robot_fetch_wave('wave1', 'wavelet1')
-    self.assertEqual(3, len(op.params))
-    self.assertEqual('proxyid', op.params['proxyingFor'])
-    self.assertEqual('wave1', op.params['waveId'])
-    self.assertEqual('wavelet1', op.params['waveletId'])
-    op = q.robot_fetch_wave('wave1', 'wavelet1',
-                            raw_deltas_from_version=5, return_raw_snapshot=True)
-    self.assertEqual(5, len(op.params))
-    self.assertEqual(5, op.params['rawDeltasFromVersion'])
-    self.assertEqual(True, op.params['returnRawSnapshot'])
-
-class TestOperationQueue(unittest.TestCase):
-  """Test case for OperationQueue class."""
-
-  def testSerialize(self):
-    q = ops.OperationQueue()
-    q.set_capability_hash('hash')
-    op = q.wavelet_modify_tag('waveid', 'waveletid', 'tag')
-    json = q.serialize()
-    self.assertEqual(2, len(json))
-    self.assertEqual('robot.notify', json[0]['method'])
-    self.assertEqual('hash', json[0]['params']['capabilitiesHash'])
-    self.assertEqual(ops.PROTOCOL_VERSION, json[0]['params']['protocolVersion'])
-    self.assertEqual('wavelet.modifyTag', json[1]['method'])
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/wave/src/main/java/python/api/robot.py b/wave/src/main/java/python/api/robot.py
deleted file mode 100644
index 99561f6..0000000
--- a/wave/src/main/java/python/api/robot.py
+++ /dev/null
@@ -1,343 +0,0 @@
-#!/usr/bin/python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Defines the generic robot classes.
-
-This module provides the Robot class and RobotListener interface,
-as well as some helper functions for web requests and responses.
-"""
-
-import logging
-import sys
-
-try:
-  __import__('google3') # setup internal test environment
-except ImportError:
-  pass
-
-import simplejson
-import blip
-import errors
-import ops
-import simplejson
-import wavelet
-import waveservice
-
-DEFAULT_PROFILE_URL = (
-    'http://code.google.com/apis/wave/extensions/robots/python-tutorial.html')
-
-
-class Robot(object):
-  """Robot metadata class.
-
-  This class holds on to basic robot information like the name and profile.
-  It also maintains the list of event handlers and cron jobs and
-  dispatches events to the appropriate handlers.
-  """
-
-  def __init__(self, name, image_url='', profile_url=DEFAULT_PROFILE_URL):
-    """Initializes self with robot information.
-
-    Args:
-      name: The name of the robot
-      image_url: (optional) url of an image that should be used as the avatar
-          for this robot.
-      profile_url: (optional) url of a webpage with more information about
-          this robot.
-    """
-    self._handlers = {}
-    self._name = name
-    self._verification_token = None
-    self._st = None
-    self._waveservice = waveservice.WaveService()
-    self._profile_handler = None
-    self._image_url = image_url
-    self._profile_url = profile_url
-    self._capability_hash = 0
-    self._consumer_key = None
-    self._http_post = None
-
-  @property
-  def name(self):
-    """Returns the name of the robot."""
-    return self._name
-
-  @property
-  def image_url(self):
-    """Returns the URL of the avatar image."""
-    return self._image_url
-
-  @property
-  def profile_url(self):
-    """Returns the URL of an info page for the robot."""
-    return self._profile_url
-
-  def get_verification_token_info(self):
-    """Returns the verification token and ST parameter."""
-    return self._verification_token, self._st
-
-  def get_waveservice(self):
-    """Return the currently installed waveservice if available.
-
-    Raises:
-      Error: if no service is installed.
-    """
-    if self._waveservice is None:
-      raise errors.Error('Oauth has not been setup')
-    return self._waveservice
-
-  def capabilities_hash(self):
-    """Return the capabilities hash as a hex string."""
-    return hex(self._capability_hash)
-
-  def register_handler(self, event_class, handler, context=None, filter=None):
-    """Registers a handler on a specific event type.
-
-    Multiple handlers may be registered on a single event type and are
-    guaranteed to be called in order of registration.
-
-    The handler takes two arguments, the event object and the corresponding
-    wavelet.
-
-    Args:
-      event_class: An event to listen for from the classes defined in the
-          events module.
-
-      handler: A function handler which takes two arguments, the wavelet for
-          the event and the event object.
-
-      context: The context to provide for this handler.
-
-      filter: Depending on the event, a filter can be specified that restricts
-          for which values the event handler will be called from the server.
-          Valuable to restrict the amount of traffic send to the robot.
-    """
-    payload = (handler, event_class, context, filter)
-    self._handlers.setdefault(event_class.type, []).append(payload)
-    if isinstance(context, list):
-      context = ','.join(context)
-    self._capability_hash = (self._capability_hash * 13 +
-                             hash(ops.PROTOCOL_VERSION) +
-                             hash(event_class.type) +
-                             hash(context) +
-                             hash(filter)) & 0xfffffff
-
-  def set_verification_token_info(self, token, st=None):
-    """Set the verification token used in the ownership verification.
-
-    /wave/robot/register starts this process up and will produce this token.
-
-    Args:
-      token: the token provided by /wave/robot/register.
-
-      st: optional parameter to verify the request for the token came from
-          the wave server.
-    """
-    self._verification_token = token
-    self._st = st
-
-  def set_http_post(self, http_post):
-    """Set the http_post handler to use when posting."""
-    self._http_post = http_post
-    if self._waveservice:
-      self._waveservice.set_http_post(http_post)
-
-  def setup_oauth(self, consumer_key, consumer_secret,
-      server_rpc_base='https://www-opensocial.googleusercontent.com/api/rpc'):
-    """Configure this robot to use the oauth'd json rpc.
-
-    Args:
-      consumer_key: consumer key received from the verification process.
-
-      consumer_secret: secret received from the verification process.
-
-      server_rpc_base: url of the rpc gateway to use. Specify None for default.
-          For wave preview, https://www-opensocial.googleusercontent.com/api/rpc
-          should be used.
-          For wave sandbox,
-          https://www-opensocial-sandbox.googleusercontent.com/api/rpc should be used.
-    """
-
-    consumer_key_prefix = ''
-    # NOTE(ljvderijk): Present for backwards capability.
-    if server_rpc_base in [waveservice.WaveService.SANDBOX_RPC_URL,
-                           waveservice.WaveService.RPC_URL]:
-      consumer_key_prefix = 'google.com:'
-
-    self._consumer_key = consumer_key_prefix + consumer_key
-    self._waveservice = waveservice.WaveService(
-        consumer_key=consumer_key,
-        consumer_secret=consumer_secret,
-        server_rpc_base=server_rpc_base,
-        http_post=self._http_post)
-
-  def register_profile_handler(self, handler):
-    """Sets the profile handler for this robot.
-
-    The profile handler will be called when a profile is needed. The handler
-    gets passed the name for which a profile is needed or None for the
-    robot itself. A dictionary with keys for name, imageUrl and
-    profileUrl should be returned.
-    """
-    self._profile_handler = handler
-
-  def capabilities_xml(self):
-    """Return this robot's capabilities as an XML string."""
-    lines = []
-    for capability, payloads in self._handlers.items():
-      for payload in payloads:
-        handler, event_class, context, filter = payload
-        line = '  <w:capability name="%s"' % capability
-        if context:
-          if isinstance(context, list):
-            context = ','.join(context)
-          line += ' context="%s"' % context
-        if filter:
-          line += ' filter="%s"' % filter
-        line += '/>\n'
-        lines.append(line)
-    if self._consumer_key:
-      oauth_tag = '<w:consumer_key>%s</w:consumer_key>\n' % self._consumer_key
-    else:
-      oauth_tag = ''
-    return ('<?xml version="1.0"?>\n'
-            '<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0">\n'
-            '<w:version>%s</w:version>\n'
-            '%s'
-            '<w:protocolversion>%s</w:protocolversion>\n'
-            '<w:capabilities>\n'
-            '%s'
-            '</w:capabilities>\n'
-            '</w:robot>\n') % (self.capabilities_hash(),
-                               oauth_tag,
-                               ops.PROTOCOL_VERSION,
-                               '\n'.join(lines))
-
-  def profile_json(self, name=None):
-    """Returns a JSON representation of the profile.
-
-    This method is called both for the basic profile of the robot and to
-    get a proxying for profile, in which case name is set. By default
-    the information supplied at registration is returned.
-
-    Use register_profile_handler to override this default behavior.
-    """
-    if self._profile_handler:
-      data = self._profile_handler(name)
-    else:
-      data = {'name': self.name,
-              'imageUrl': self.image_url,
-              'profileUrl': self.profile_url}
-    return simplejson.dumps(data)
-
-  def process_events(self, json):
-    """Process an incoming set of events encoded as json."""
-    parsed = simplejson.loads(json)
-    pending_ops = ops.OperationQueue()
-    event_wavelet = self.get_waveservice()._wavelet_from_json(parsed, pending_ops)
-
-    for event_data in parsed['events']:
-      for payload in self._handlers.get(event_data['type'], []):
-        handler, event_class, context, filter = payload
-        event = event_class(event_data, event_wavelet)
-        handler(event, event_wavelet)
-
-    pending_ops.set_capability_hash(self.capabilities_hash())
-    return simplejson.dumps(pending_ops.serialize())
-
-  def new_wave(self, domain, participants=None, message='', proxy_for_id=None,
-               submit=False):
-    """Create a new wave with the initial participants on it.
-
-    A new wave is returned with its own operation queue. It the
-    responsibility of the caller to make sure this wave gets
-    submitted to the server, either by calling robot.submit() or
-    by calling .submit_with() on the returned wave.
-
-    Args:
-      domain: the domain to create the wavelet on. This should
-          in general correspond to the domain of the incoming
-          wavelet. (wavelet.domain). Exceptions are situations
-          where the robot is calling new_wave outside of an
-          event or when the server is handling multiple domains.
-
-      participants: initial participants on the wave. The robot
-          as the creator of the wave is always added.
-
-      message: a string that will be passed back to the robot
-          when the WAVELET_CREATOR event is fired. This is a
-          lightweight way to pass around state.
-
-      submit: if true, use the active gateway to make a round
-          trip to the server. This will return immediately an
-          actual waveid/waveletid and blipId for the root blip.
-
-    """
-    return self.get_waveservice().new_wave(
-        domain, participants, message, proxy_for_id, submit)
-
-  def fetch_wavelet(self, wave_id, wavelet_id=None, proxy_for_id=None,
-                    raw_deltas_from_version=-1, return_raw_snapshot=False):
-    """Use the REST interface to fetch a wave and return it.
-
-    The returned wavelet contains a snapshot of the state of the
-    wavelet at that point. It can be used to modify the wavelet,
-    but the wavelet might change in between, so treat carefully.
-
-    Also note that the wavelet returned has its own operation
-    queue. It the responsibility of the caller to make sure this
-    wavelet gets submited to the server, either by calling
-    robot.submit() or by calling .submit_with() on the returned
-    wavelet.
-    """
-    return self.get_waveservice().fetch_wavelet(
-        wave_id, wavelet_id, proxy_for_id, raw_deltas_from_version,
-        return_raw_snapshot)
-
-  def blind_wavelet(self, json, proxy_for_id=None):
-    """Construct a blind wave from a json string.
-
-    Call this method if you have a snapshot of a wave that you
-    want to operate on outside of an event. Since the wave might
-    have changed since you last saw it, you should take care to
-    submit operations that are as safe as possible.
-
-    Args:
-      json: a json object or string containing at least a key
-        wavelet defining the wavelet and a key blips defining the
-        blips in the view.
-
-      proxy_for_id: the proxying information that will be set on the wavelet's
-        operation queue.
-
-    Returns:
-      A new wavelet with its own operation queue. It the
-      responsibility of the caller to make sure this wavelet gets
-      submited to the server, either by calling robot.submit() or
-      by calling .submit_with() on the returned wavelet.
-    """
-    return self.get_waveservice().blind_wavelet(json, proxy_for_id)
-
-  def submit(self, wavelet_to_submit):
-    """Submit the pending operations associated with wavelet_to_submit.
-
-    Typically the wavelet will be the result of fetch_wavelet, blind_wavelet
-    or new_wave.
-    """
-    return self.get_waveservice().submit(wavelet_to_submit)
diff --git a/wave/src/main/java/python/api/robot_test.py b/wave/src/main/java/python/api/robot_test.py
deleted file mode 100644
index 8d079b1..0000000
--- a/wave/src/main/java/python/api/robot_test.py
+++ /dev/null
@@ -1,257 +0,0 @@
-#!/usr/bin/python2.4
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Unit tests for the robot module."""
-
-import unittest
-
-import events
-import ops
-import robot
-import simplejson
-
-BLIP_JSON = ('{"wdykLROk*13":'
-               '{"lastModifiedTime":1242079608457,'
-               '"contributors":["someguy@test.com"],'
-               '"waveletId":"test.com!conv+root",'
-               '"waveId":"test.com!wdykLROk*11",'
-               '"parentBlipId":null,'
-               '"version":3,'
-               '"creator":"someguy@test.com",'
-               '"content":"\\nContent!",'
-               '"blipId":"wdykLROk*13","'
-               'annotations":[{"range":{"start":0,"end":1},'
-                   '"name":"user/e/davidbyttow@google.com","value":"David"}],'
-               '"elements":{},'
-               '"threadId": "",'
-               '"childBlipIds":[]}'
-             '}')
-
-WAVELET_JSON = ('{"lastModifiedTime":1242079611003,'
-                 '"title":"A title",'
-                 '"waveletId":"test.com!conv+root",'
-                 '"rootBlipId":"wdykLROk*13",'
-                 '"dataDocuments":null,'
-                 '"creationTime":1242079608457,'
-                 '"waveId":"test.com!wdykLROk*11",'
-                 '"participants":["someguy@test.com","monty@appspot.com"],'
-                 '"creator":"someguy@test.com",'
-                 '"rootThread": '
-                 '{"id":"", "location": "-1", "blipIds": ["wdykLROk*13"]},'
-                 '"version":5}')
-
-EVENTS_JSON = ('[{"timestamp":1242079611003,'
-                '"modifiedBy":"someguy@test.com",'
-                '"properties":{"participantsRemoved":[],'
-                    '"participantsAdded":["monty@appspot.com"]},'
-                '"type":"WAVELET_PARTICIPANTS_CHANGED"}]')
-
-TEST_JSON = '{"blips":%s,"wavelet":%s,"events":%s, "threads": {}}' % (
-    BLIP_JSON, WAVELET_JSON, EVENTS_JSON)
-
-NEW_WAVE_JSON = [{"data":
-                  {"waveletId": "wavesandbox.com!conv+root",
-                   "blipId": "b+LrODcLZkDlu", "waveId":
-                   "wavesandbox.com!w+LrODcLZkDlt"},
-                  "id": "op2"}]
-
-
-class TestRobot(unittest.TestCase):
-  """Tests for testing the basic parsing of json in robots."""
-
-  def setUp(self):
-    self.robot = robot.Robot('Testy')
-
-  def testCreateWave(self):
-    self.robot.get_waveservice().submit = lambda x: NEW_WAVE_JSON
-    new_wave = self.robot.new_wave('wavesandbox.com', submit=True)
-    self.assertEqual('wavesandbox.com!w+LrODcLZkDlt', new_wave.wave_id)
-
-  def testEventParsing(self):
-    def check(event, wavelet):
-      # Test some basic properties; the rest should be covered by
-      # ops.CreateContext.
-      root = wavelet.root_blip
-      self.assertEqual(1, len(wavelet.blips))
-      self.assertEqual('wdykLROk*13', root.blip_id)
-      self.assertEqual('test.com!wdykLROk*11', root.wave_id)
-      self.assertEqual('test.com!conv+root', root.wavelet_id)
-      self.assertEqual('WAVELET_PARTICIPANTS_CHANGED', event.type)
-      self.assertEqual({'participantsRemoved': [],
-                        'participantsAdded': ['monty@appspot.com']},
-                       event.properties)
-      self.robot.test_called = True
-
-    self.robot.test_called = False
-    self.robot.register_handler(events.WaveletParticipantsChanged,
-                                check)
-    json = self.robot.process_events(TEST_JSON)
-    self.assertTrue(self.robot.test_called)
-    operations = simplejson.loads(json)
-    # there should be one operation indicating the current version:
-    self.assertEqual(1, len(operations))
-
-  def testWrongEventsIgnored(self):
-    self.robot.test_called = True
-
-    def check(event, wavelet):
-      called = True
-
-    self.robot.test_called = False
-    self.robot.register_handler(events.BlipSubmitted,
-                                check)
-    self.robot.process_events(TEST_JSON)
-    self.assertFalse(self.robot.test_called)
-
-  def testOperationParsing(self):
-    def check(event, wavelet):
-      wavelet.reply()
-      wavelet.title = 'new title'
-      wavelet.root_blip.append_markup('<b>Hello</b>')
-
-    self.robot.register_handler(events.WaveletParticipantsChanged,
-                                check)
-    json = self.robot.process_events(TEST_JSON)
-    operations = simplejson.loads(json)
-    expected = set([ops.ROBOT_NOTIFY,
-                    ops.WAVELET_APPEND_BLIP,
-                    ops.WAVELET_SET_TITLE,
-                    ops.DOCUMENT_APPEND_MARKUP])
-    methods = [operation['method'] for operation in operations]
-    for method in methods:
-      self.assertTrue(method in expected)
-      expected.remove(method)
-    self.assertEquals(0, len(expected))
-
-  def testSerializeWavelets(self):
-    wavelet = self.robot.blind_wavelet(TEST_JSON)
-    serialized = wavelet.serialize()
-    unserialized = self.robot.blind_wavelet(serialized)
-    self.assertEquals(wavelet.creator, unserialized.creator)
-    self.assertEquals(wavelet.creation_time, unserialized.creation_time)
-    self.assertEquals(wavelet.last_modified_time,
-                      unserialized.last_modified_time)
-    self.assertEquals(wavelet.root_blip.blip_id, unserialized.root_blip.blip_id)
-    self.assertEquals(wavelet.title, unserialized.title)
-    self.assertEquals(wavelet.wave_id, unserialized.wave_id)
-    self.assertEquals(wavelet.wavelet_id, unserialized.wavelet_id)
-    self.assertEquals(wavelet.domain, unserialized.domain)
-
-  def testProxiedBlindWavelet(self):
-    def handler(event, wavelet):
-      blind_wavelet = self.robot.blind_wavelet(TEST_JSON, 'proxyid')
-      blind_wavelet.reply()
-      blind_wavelet.submit_with(wavelet)
-
-    self.robot.register_handler(events.WaveletParticipantsChanged, handler)
-    json = self.robot.process_events(TEST_JSON)
-    operations = simplejson.loads(json)
-
-    self.assertEqual(2, len(operations))
-    self.assertEquals(ops.ROBOT_NOTIFY,
-                      operations[0]['method'])
-    self.assertEquals(ops.WAVELET_APPEND_BLIP, operations[1]['method'])
-    self.assertEquals('proxyid', operations[1]['params']['proxyingFor'])
-
-  def testCapabilitiesHashIncludesContextAndFilter(self):
-    robot1 = robot.Robot('Robot1')
-    robot1.register_handler(events.WaveletSelfAdded, lambda: '')
-
-    robot2 = robot.Robot('Robot2')
-    robot2.register_handler(events.WaveletSelfAdded, lambda: '',
-                            context=events.Context.ALL)
-    self.assertNotEqual(robot1.capabilities_hash(), robot2.capabilities_hash())
-
-    robot3 = robot.Robot('Robot3')
-    robot2.register_handler(events.WaveletSelfAdded, lambda: '',
-                            context=events.Context.ALL, filter="foo")
-    self.assertNotEqual(robot1.capabilities_hash(), robot2.capabilities_hash())
-    self.assertNotEqual(robot1.capabilities_hash(), robot3.capabilities_hash())
-    self.assertNotEqual(robot2.capabilities_hash(), robot3.capabilities_hash())
-
-class TestGetCapabilitiesXml(unittest.TestCase):
-
-  def setUp(self):
-    self.robot = robot.Robot('Testy')
-    self.robot.capabilities_hash = lambda: '1'
-
-  def assertStringsEqual(self, s1, s2):
-    self.assertEqual(s1, s2, 'Strings differ:\n%s--\n%s' % (s1, s2))
-
-  def testDefault(self):
-    expected = (
-        '<?xml version="1.0"?>\n'
-        '<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0">\n'
-        '<w:version>1</w:version>\n'
-        '<w:protocolversion>%s</w:protocolversion>\n'
-        '<w:capabilities>\n</w:capabilities>\n'
-        '</w:robot>\n') % ops.PROTOCOL_VERSION
-    xml = self.robot.capabilities_xml()
-    self.assertStringsEqual(expected, xml)
-
-  def testUrls(self):
-    profile_robot = robot.Robot(
-        'Testy',
-        image_url='http://example.com/image.png',
-        profile_url='http://example.com/profile.xml')
-    profile_robot.capabilities_hash = lambda: '1'
-    expected = (
-        '<?xml version="1.0"?>\n'
-        '<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0">\n'
-        '<w:version>1</w:version>\n'
-        '<w:protocolversion>%s</w:protocolversion>\n'
-        '<w:capabilities>\n</w:capabilities>\n'
-        '</w:robot>\n') % ops.PROTOCOL_VERSION
-    xml = profile_robot.capabilities_xml()
-    self.assertStringsEqual(expected, xml)
-
-  def testConsumerKey(self):
-    # setup_oauth doesn't work during testing, so heavy handed setting of
-    # properties it is:
-    self.robot._consumer_key = 'consumer'
-    expected = (
-        '<?xml version="1.0"?>\n'
-        '<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0">\n'
-        '<w:version>1</w:version>\n'
-        '<w:consumer_key>consumer</w:consumer_key>\n'
-        '<w:protocolversion>%s</w:protocolversion>\n'
-        '<w:capabilities>\n</w:capabilities>\n'
-        '</w:robot>\n') % ops.PROTOCOL_VERSION
-    xml = self.robot.capabilities_xml()
-    self.assertStringsEqual(expected, xml)
-
-  def testCapsAndEvents(self):
-    self.robot.register_handler(events.BlipSubmitted, None,
-                                context=[events.Context.SELF,
-                                         events.Context.ROOT])
-    expected = (
-        '<?xml version="1.0"?>\n'
-        '<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0">\n'
-        '<w:version>1</w:version>\n'
-        '<w:protocolversion>%s</w:protocolversion>\n'
-        '<w:capabilities>\n'
-        '  <w:capability name="%s" context="SELF,ROOT"/>\n'
-        '</w:capabilities>\n'
-        '</w:robot>\n') % (ops.PROTOCOL_VERSION, events.BlipSubmitted.type)
-    xml = self.robot.capabilities_xml()
-    self.assertStringsEqual(expected, xml)
-
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/wave/src/main/java/python/api/run_unit_tests.py b/wave/src/main/java/python/api/run_unit_tests.py
deleted file mode 100644
index abb69f4..0000000
--- a/wave/src/main/java/python/api/run_unit_tests.py
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/usr/bin/python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Script to run all unit tests in this package."""
-
-
-import blip_test
-import element_test
-import module_test_runner
-import ops_test
-import robot_test
-import util_test
-import wavelet_test
-import search_test
-
-
-def RunUnitTests():
-  """Runs all registered unit tests."""
-  test_runner = module_test_runner.ModuleTestRunner()
-  test_runner.modules = [
-      blip_test,
-      element_test,
-      ops_test,
-      robot_test,
-      util_test,
-      wavelet_test,
-      search_test,
-  ]
-  test_runner.RunAllTests()
-
-
-if __name__ == "__main__":
-  RunUnitTests()
diff --git a/wave/src/main/java/python/api/search.py b/wave/src/main/java/python/api/search.py
deleted file mode 100644
index 2167114..0000000
--- a/wave/src/main/java/python/api/search.py
+++ /dev/null
@@ -1,153 +0,0 @@
-#!/usr/bin/python2.4
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Defines classes that are needed to model a search (results)."""
-
-import errors
-import logging
-import wavelet
-
-class Results(object):
-  """Models a set of search results.
-
-  Search results are composed of a list of digests, query, and number of
-  results.
-  """
-
-  def __init__(self, json):
-    """Inits this results object with JSON data.
-
-    Args:
-      json: JSON data dictionary from Wave server.
-    """
-    if 'searchResults' in json:
-      json = json['searchResults']
-    self._query = json.get('query')
-    self._num_results = json.get('numResults')
-    self._digests = []
-    self._digests = [Digest(digest_data) for digest_data in json['digests']]
-
-  @property
-  def query(self):
-    """Returns the query for this search."""
-    return self._query
-
-  @property
-  def num_results(self):
-    """Returns the number of results for this search."""
-    return self._num_results
-
-  @property
-  def digests(self):
-    """Returns a list of digests."""
-    return self._digests
-
-  def __iter__(self):
-    """Iterate over the list of digests."""
-    return iter(self._digests)
-
-  def serialize(self):
-    """Return a dict of the search results properties."""
-    return {'query': self._query,
-            'numResults': self._num_results,
-            'digests': [digest.serialize() for digest in self._digests]
-           }
-
-
-class Digest(object):
-  """Models a single digest.
-
-  A digest is composed of title, wave ID, snippet, and participants.
-  """
-
-  def __init__(self, json):
-    """Inits this digest with JSON data.
-
-    Args:
-      json: JSON data dictionary from Wave server.
-    """
-    self._wave_id = json.get('waveId')
-    self._title = json.get('title')
-    self._snippet = json.get('snippet')
-    self._blip_count = int(json.get('blipCount'))
-    self._unread_count = int(json.get('unreadCount'))
-    self._last_modified = json.get('lastModified')
-    self._participants = wavelet.Participants(json.get('participants', []),
-                                      {},
-                                      self._wave_id,
-                                      '',
-                                      None)
-    self._raw_data = json
-
-  @property
-  def blip_count(self):
-    """Returns the number of blips in this wave."""
-    return self._blip_count
-
-  @property
-  def unread_count(self):
-    """Returns the number of unread blips in this wave."""
-    return self._unread_count
-
-  @property
-  def last_modified(self):
-    """Returns the last modified date of the wave."""
-    return self._last_modified
-
-  @property
-  def wave_id(self):
-    """Returns the digest wave id."""
-    return self._wave_id
-
-  @property
-  def snippet(self):
-    """Returns the snippet for the digest."""
-    return self._snippet
-
-  @property
-  def domain(self):
-    """Return the domain that the wave belongs to."""
-    p = self._wave_id.find('!')
-    if p == -1:
-      return None
-    else:
-      return self._wave_id[:p]
-
-  @property
-  def participants(self):
-    """Returns a set of participants on this wave."""
-    return self._participants
-
-  @property
-  def title(self):
-    return self._title
-
-  def serialize(self):
-    """Return a dict of the digest properties."""
-    return {'waveId': self._wave_id,
-            'participants': self._participants.serialize(),
-            'title': self._title,
-            'snippet': self._snippet,
-            'blipCount': self._blip_count,
-            'unreadCount': self._unread_count,
-            'lastModified': self._last_modified,
-           }
-
-  def __str__(self):
-    return self._title
diff --git a/wave/src/main/java/python/api/search_test.py b/wave/src/main/java/python/api/search_test.py
deleted file mode 100644
index 9f70beb..0000000
--- a/wave/src/main/java/python/api/search_test.py
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/usr/bin/python2.4
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Unit tests for the search module."""
-
-
-import unittest
-
-import search
-import simplejson
-
-TEST_DIGEST_DATA = {
-    'title': 'Title',
-    'participants': ['pamela.fox@googlewave.com'],
-    'waveId': 'test.com!w+g3h3im',
-    'snippet': 'Best test ever',
-    'blipCount': '10',
-    'unreadCount': '2',
-    'lastModified': '1275658457',
-}
-
-
-TEST_RESULTS_DATA = {
-    'query': 'in:inbox',
-    'numResults': 10,
-    'digests': [
-      TEST_DIGEST_DATA,
-      TEST_DIGEST_DATA
-    ]}
-
-
-class TestResults(unittest.TestCase):
-  """Tests the wavelet class."""
-
-  def setUp(self):
-    self.results = search.Results(TEST_RESULTS_DATA)
-
-  def testResultsProperties(self):
-    r = self.results
-    self.assertEquals(TEST_RESULTS_DATA['query'], r.query)
-    self.assertEquals(TEST_RESULTS_DATA['numResults'], r.num_results)
-    self.assertEquals(len(TEST_RESULTS_DATA['digests']), len(r.digests))
-
-
-class TestDigest(unittest.TestCase):
-  """Tests the wavelet class."""
-
-  def setUp(self):
-    self.digest = search.Digest(TEST_DIGEST_DATA)
-
-  def testDigestProperties(self):
-    d = self.digest
-    self.assertEquals(TEST_DIGEST_DATA['title'], d.title)
-    self.assertEquals(TEST_DIGEST_DATA['waveId'], d.wave_id)
-    self.assertEquals(TEST_DIGEST_DATA['snippet'], d.snippet)
-    self.assertEquals(TEST_DIGEST_DATA['blipCount'], str(d.blip_count))
-    self.assertEquals(TEST_DIGEST_DATA['unreadCount'], str(d.unread_count))
-    self.assertEquals(TEST_DIGEST_DATA['lastModified'], d.last_modified)
-    self.assertTrue(TEST_DIGEST_DATA['participants'][0] in d.participants)
-    self.assertEquals('test.com', d.domain)
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/wave/src/main/java/python/api/simplejson/LICENSE b/wave/src/main/java/python/api/simplejson/LICENSE
deleted file mode 100644
index 8676302..0000000
--- a/wave/src/main/java/python/api/simplejson/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2006 Bob Ippolito
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
\ No newline at end of file
diff --git a/wave/src/main/java/python/api/simplejson/__init__.py b/wave/src/main/java/python/api/simplejson/__init__.py
deleted file mode 100644
index a111e0c..0000000
--- a/wave/src/main/java/python/api/simplejson/__init__.py
+++ /dev/null
@@ -1,424 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-#
-#
-r"""JSON (JavaScript Object Notation) <http://json.org> is a subset of
-JavaScript syntax (ECMA-262 3rd edition) used as a lightweight data
-interchange format.
-
-:mod:`simplejson` exposes an API familiar to users of the standard library
-:mod:`marshal` and :mod:`pickle` modules. It is the externally maintained
-version of the :mod:`json` library contained in Python 2.6, but maintains
-compatibility with Python 2.4 and Python 2.5 and (currently) has
-significant performance advantages, even without using the optional C
-extension for speedups.
-
-Encoding basic Python object hierarchies::
-
-    >>> import simplejson as json
-    >>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
-    '["foo", {"bar": ["baz", null, 1.0, 2]}]'
-    >>> print json.dumps("\"foo\bar")
-    "\"foo\bar"
-    >>> print json.dumps(u'\u1234')
-    "\u1234"
-    >>> print json.dumps('\\')
-    "\\"
-    >>> print json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True)
-    {"a": 0, "b": 0, "c": 0}
-    >>> from StringIO import StringIO
-    >>> io = StringIO()
-    >>> json.dump(['streaming API'], io)
-    >>> io.getvalue()
-    '["streaming API"]'
-
-Compact encoding::
-
-    >>> import simplejson as json
-    >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':'))
-    '[1,2,3,{"4":5,"6":7}]'
-
-Pretty printing::
-
-    >>> import simplejson as json
-    >>> s = json.dumps({'4': 5, '6': 7}, sort_keys=True, indent='    ')
-    >>> print '\n'.join([l.rstrip() for l in  s.splitlines()])
-    {
-        "4": 5,
-        "6": 7
-    }
-
-Decoding JSON::
-
-    >>> import simplejson as json
-    >>> obj = [u'foo', {u'bar': [u'baz', None, 1.0, 2]}]
-    >>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]') == obj
-    True
-    >>> json.loads('"\\"foo\\bar"') == u'"foo\x08ar'
-    True
-    >>> from StringIO import StringIO
-    >>> io = StringIO('["streaming API"]')
-    >>> json.load(io)[0] == 'streaming API'
-    True
-
-Specializing JSON object decoding::
-
-    >>> import simplejson as json
-    >>> def as_complex(dct):
-    ...     if '__complex__' in dct:
-    ...         return complex(dct['real'], dct['imag'])
-    ...     return dct
-    ...
-    >>> json.loads('{"__complex__": true, "real": 1, "imag": 2}',
-    ...     object_hook=as_complex)
-    (1+2j)
-    >>> from decimal import Decimal
-    >>> json.loads('1.1', parse_float=Decimal) == Decimal('1.1')
-    True
-
-Specializing JSON object encoding::
-
-    >>> import simplejson as json
-    >>> def encode_complex(obj):
-    ...     if isinstance(obj, complex):
-    ...         return [obj.real, obj.imag]
-    ...     raise TypeError(repr(o) + " is not JSON serializable")
-    ...
-    >>> json.dumps(2 + 1j, default=encode_complex)
-    '[2.0, 1.0]'
-    >>> json.JSONEncoder(default=encode_complex).encode(2 + 1j)
-    '[2.0, 1.0]'
-    >>> ''.join(json.JSONEncoder(default=encode_complex).iterencode(2 + 1j))
-    '[2.0, 1.0]'
-
-
-Using simplejson.tool from the shell to validate and pretty-print::
-
-    $ echo '{"json":"obj"}' | python -m simplejson.tool
-    {
-        "json": "obj"
-    }
-    $ echo '{ 1.2:3.4}' | python -m simplejson.tool
-    Expecting property name: line 1 column 2 (char 2)
-"""
-__version__ = '2.1.0'
-__all__ = [
-    'dump', 'dumps', 'load', 'loads',
-    'JSONDecoder', 'JSONDecodeError', 'JSONEncoder',
-    'OrderedDict',
-]
-
-__author__ = 'Bob Ippolito <bob@redivi.com>'
-
-from decoder import JSONDecoder, JSONDecodeError
-from encoder import JSONEncoder
-try:
-    from collections import OrderedDict
-except ImportError:
-    from ordered_dict import OrderedDict
-
-_default_encoder = JSONEncoder(
-    skipkeys=False,
-    ensure_ascii=True,
-    check_circular=True,
-    allow_nan=True,
-    indent=None,
-    separators=None,
-    encoding='utf-8',
-    default=None,
-)
-
-def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
-        allow_nan=True, cls=None, indent=None, separators=None,
-        encoding='utf-8', default=None, **kw):
-    """Serialize ``obj`` as a JSON formatted stream to ``fp`` (a
-    ``.write()``-supporting file-like object).
-
-    If ``skipkeys`` is true then ``dict`` keys that are not basic types
-    (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
-    will be skipped instead of raising a ``TypeError``.
-
-    If ``ensure_ascii`` is false, then the some chunks written to ``fp``
-    may be ``unicode`` instances, subject to normal Python ``str`` to
-    ``unicode`` coercion rules. Unless ``fp.write()`` explicitly
-    understands ``unicode`` (as in ``codecs.getwriter()``) this is likely
-    to cause an error.
-
-    If ``check_circular`` is false, then the circular reference check
-    for container types will be skipped and a circular reference will
-    result in an ``OverflowError`` (or worse).
-
-    If ``allow_nan`` is false, then it will be a ``ValueError`` to
-    serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``)
-    in strict compliance of the JSON specification, instead of using the
-    JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``).
-
-    If *indent* is a string, then JSON array elements and object members
-    will be pretty-printed with a newline followed by that string repeated
-    for each level of nesting. ``None`` (the default) selects the most compact
-    representation without any newlines. For backwards compatibility with
-    versions of simplejson earlier than 2.1.0, an integer is also accepted
-    and is converted to a string with that many spaces.
-
-    If ``separators`` is an ``(item_separator, dict_separator)`` tuple
-    then it will be used instead of the default ``(', ', ': ')`` separators.
-    ``(',', ':')`` is the most compact JSON representation.
-
-    ``encoding`` is the character encoding for str instances, default is UTF-8.
-
-    ``default(obj)`` is a function that should return a serializable version
-    of obj or raise TypeError. The default simply raises TypeError.
-
-    To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
-    ``.default()`` method to serialize additional types), specify it with
-    the ``cls`` kwarg.
-
-    """
-    # cached encoder
-    if (not skipkeys and ensure_ascii and
-        check_circular and allow_nan and
-        cls is None and indent is None and separators is None and
-        encoding == 'utf-8' and default is None and not kw):
-        iterable = _default_encoder.iterencode(obj)
-    else:
-        if cls is None:
-            cls = JSONEncoder
-        iterable = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii,
-            check_circular=check_circular, allow_nan=allow_nan, indent=indent,
-            separators=separators, encoding=encoding,
-            default=default, **kw).iterencode(obj)
-    # could accelerate with writelines in some versions of Python, at
-    # a debuggability cost
-    for chunk in iterable:
-        fp.write(chunk)
-
-
-def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
-        allow_nan=True, cls=None, indent=None, separators=None,
-        encoding='utf-8', default=None, **kw):
-    """Serialize ``obj`` to a JSON formatted ``str``.
-
-    If ``skipkeys`` is false then ``dict`` keys that are not basic types
-    (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
-    will be skipped instead of raising a ``TypeError``.
-
-    If ``ensure_ascii`` is false, then the return value will be a
-    ``unicode`` instance subject to normal Python ``str`` to ``unicode``
-    coercion rules instead of being escaped to an ASCII ``str``.
-
-    If ``check_circular`` is false, then the circular reference check
-    for container types will be skipped and a circular reference will
-    result in an ``OverflowError`` (or worse).
-
-    If ``allow_nan`` is false, then it will be a ``ValueError`` to
-    serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) in
-    strict compliance of the JSON specification, instead of using the
-    JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``).
-
-    If ``indent`` is a string, then JSON array elements and object members
-    will be pretty-printed with a newline followed by that string repeated
-    for each level of nesting. ``None`` (the default) selects the most compact
-    representation without any newlines. For backwards compatibility with
-    versions of simplejson earlier than 2.1.0, an integer is also accepted
-    and is converted to a string with that many spaces.
-
-    If ``separators`` is an ``(item_separator, dict_separator)`` tuple
-    then it will be used instead of the default ``(', ', ': ')`` separators.
-    ``(',', ':')`` is the most compact JSON representation.
-
-    ``encoding`` is the character encoding for str instances, default is UTF-8.
-
-    ``default(obj)`` is a function that should return a serializable version
-    of obj or raise TypeError. The default simply raises TypeError.
-
-    To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
-    ``.default()`` method to serialize additional types), specify it with
-    the ``cls`` kwarg.
-
-    """
-    # cached encoder
-    if (not skipkeys and ensure_ascii and
-        check_circular and allow_nan and
-        cls is None and indent is None and separators is None and
-        encoding == 'utf-8' and default is None and not kw):
-        return _default_encoder.encode(obj)
-    if cls is None:
-        cls = JSONEncoder
-    return cls(
-        skipkeys=skipkeys, ensure_ascii=ensure_ascii,
-        check_circular=check_circular, allow_nan=allow_nan, indent=indent,
-        separators=separators, encoding=encoding, default=default,
-        **kw).encode(obj)
-
-
-_default_decoder = JSONDecoder(encoding=None, object_hook=None,
-                               object_pairs_hook=None)
-
-
-def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None,
-        parse_int=None, parse_constant=None, object_pairs_hook=None, **kw):
-    """Deserialize ``fp`` (a ``.read()``-supporting file-like object containing
-    a JSON document) to a Python object.
-
-    *encoding* determines the encoding used to interpret any
-    :class:`str` objects decoded by this instance (``'utf-8'`` by
-    default).  It has no effect when decoding :class:`unicode` objects.
-
-    Note that currently only encodings that are a superset of ASCII work,
-    strings of other encodings should be passed in as :class:`unicode`.
-
-    *object_hook*, if specified, will be called with the result of every
-    JSON object decoded and its return value will be used in place of the
-    given :class:`dict`.  This can be used to provide custom
-    deserializations (e.g. to support JSON-RPC class hinting).
-
-    *object_pairs_hook* is an optional function that will be called with
-    the result of any object literal decode with an ordered list of pairs.
-    The return value of *object_pairs_hook* will be used instead of the
-    :class:`dict`.  This feature can be used to implement custom decoders
-    that rely on the order that the key and value pairs are decoded (for
-    example, :func:`collections.OrderedDict` will remember the order of
-    insertion). If *object_hook* is also defined, the *object_pairs_hook*
-    takes priority.
-
-    *parse_float*, if specified, will be called with the string of every
-    JSON float to be decoded.  By default, this is equivalent to
-    ``float(num_str)``. This can be used to use another datatype or parser
-    for JSON floats (e.g. :class:`decimal.Decimal`).
-
-    *parse_int*, if specified, will be called with the string of every
-    JSON int to be decoded.  By default, this is equivalent to
-    ``int(num_str)``.  This can be used to use another datatype or parser
-    for JSON integers (e.g. :class:`float`).
-
-    *parse_constant*, if specified, will be called with one of the
-    following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``.  This
-    can be used to raise an exception if invalid JSON numbers are
-    encountered.
-
-    To use a custom ``JSONDecoder`` subclass, specify it with the ``cls``
-    kwarg.
-
-    """
-    return loads(fp.read(),
-        encoding=encoding, cls=cls, object_hook=object_hook,
-        parse_float=parse_float, parse_int=parse_int,
-        parse_constant=parse_constant, object_pairs_hook=object_pairs_hook,
-        **kw)
-
-
-def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None,
-        parse_int=None, parse_constant=None, object_pairs_hook=None, **kw):
-    """Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON
-    document) to a Python object.
-
-    *encoding* determines the encoding used to interpret any
-    :class:`str` objects decoded by this instance (``'utf-8'`` by
-    default).  It has no effect when decoding :class:`unicode` objects.
-
-    Note that currently only encodings that are a superset of ASCII work,
-    strings of other encodings should be passed in as :class:`unicode`.
-
-    *object_hook*, if specified, will be called with the result of every
-    JSON object decoded and its return value will be used in place of the
-    given :class:`dict`.  This can be used to provide custom
-    deserializations (e.g. to support JSON-RPC class hinting).
-
-    *object_pairs_hook* is an optional function that will be called with
-    the result of any object literal decode with an ordered list of pairs.
-    The return value of *object_pairs_hook* will be used instead of the
-    :class:`dict`.  This feature can be used to implement custom decoders
-    that rely on the order that the key and value pairs are decoded (for
-    example, :func:`collections.OrderedDict` will remember the order of
-    insertion). If *object_hook* is also defined, the *object_pairs_hook*
-    takes priority.
-
-    *parse_float*, if specified, will be called with the string of every
-    JSON float to be decoded.  By default, this is equivalent to
-    ``float(num_str)``. This can be used to use another datatype or parser
-    for JSON floats (e.g. :class:`decimal.Decimal`).
-
-    *parse_int*, if specified, will be called with the string of every
-    JSON int to be decoded.  By default, this is equivalent to
-    ``int(num_str)``.  This can be used to use another datatype or parser
-    for JSON integers (e.g. :class:`float`).
-
-    *parse_constant*, if specified, will be called with one of the
-    following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``.  This
-    can be used to raise an exception if invalid JSON numbers are
-    encountered.
-
-    To use a custom ``JSONDecoder`` subclass, specify it with the ``cls``
-    kwarg.
-
-    """
-    if (cls is None and encoding is None and object_hook is None and
-            parse_int is None and parse_float is None and
-            parse_constant is None and object_pairs_hook is None and not kw):
-        return _default_decoder.decode(s)
-    if cls is None:
-        cls = JSONDecoder
-    if object_hook is not None:
-        kw['object_hook'] = object_hook
-    if object_pairs_hook is not None:
-        kw['object_pairs_hook'] = object_pairs_hook
-    if parse_float is not None:
-        kw['parse_float'] = parse_float
-    if parse_int is not None:
-        kw['parse_int'] = parse_int
-    if parse_constant is not None:
-        kw['parse_constant'] = parse_constant
-    return cls(encoding=encoding, **kw).decode(s)
-
-
-def _toggle_speedups(enabled):
-    import simplejson.decoder as dec
-    import simplejson.encoder as enc
-    import simplejson.scanner as scan
-    try:
-        from simplejson._speedups import make_encoder as c_make_encoder
-    except ImportError:
-        c_make_encoder = None
-    if enabled:
-        dec.scanstring = dec.c_scanstring or dec.py_scanstring
-        enc.c_make_encoder = c_make_encoder
-        enc.encode_basestring_ascii = (enc.c_encode_basestring_ascii or 
-            enc.py_encode_basestring_ascii)
-        scan.make_scanner = scan.c_make_scanner or scan.py_make_scanner
-    else:
-        dec.scanstring = dec.py_scanstring
-        enc.c_make_encoder = None
-        enc.encode_basestring_ascii = enc.py_encode_basestring_ascii
-        scan.make_scanner = scan.py_make_scanner
-    dec.make_scanner = scan.make_scanner
-    global _default_decoder
-    _default_decoder = JSONDecoder(
-        encoding=None,
-        object_hook=None,
-        object_pairs_hook=None,
-    )
-    global _default_encoder
-    _default_encoder = JSONEncoder(
-       skipkeys=False,
-       ensure_ascii=True,
-       check_circular=True,
-       allow_nan=True,
-       indent=None,
-       separators=None,
-       encoding='utf-8',
-       default=None,
-   )
diff --git a/wave/src/main/java/python/api/simplejson/decoder.py b/wave/src/main/java/python/api/simplejson/decoder.py
deleted file mode 100644
index 95e4f5f..0000000
--- a/wave/src/main/java/python/api/simplejson/decoder.py
+++ /dev/null
@@ -1,431 +0,0 @@
-#
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-#
-#
-"""Implementation of JSONDecoder
-"""
-import re
-import sys
-import struct
-
-from scanner import make_scanner
-try:
-    from _speedups import scanstring as c_scanstring
-except ImportError:
-    c_scanstring = None
-
-__all__ = ['JSONDecoder']
-
-FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL
-
-def _floatconstants():
-    _BYTES = '7FF80000000000007FF0000000000000'.decode('hex')
-    # The struct module in Python 2.4 would get frexp() out of range here
-    # when an endian is specified in the format string. Fixed in Python 2.5+
-    if sys.byteorder != 'big':
-        _BYTES = _BYTES[:8][::-1] + _BYTES[8:][::-1]
-    nan, inf = struct.unpack('dd', _BYTES)
-    return nan, inf, -inf
-
-NaN, PosInf, NegInf = _floatconstants()
-
-
-class JSONDecodeError(ValueError):
-    """Subclass of ValueError with the following additional properties:
-    
-    msg: The unformatted error message
-    doc: The JSON document being parsed
-    pos: The start index of doc where parsing failed
-    end: The end index of doc where parsing failed (may be None)
-    lineno: The line corresponding to pos
-    colno: The column corresponding to pos
-    endlineno: The line corresponding to end (may be None)
-    endcolno: The column corresponding to end (may be None)
-    
-    """
-    def __init__(self, msg, doc, pos, end=None):
-        ValueError.__init__(self, errmsg(msg, doc, pos, end=end))
-        self.msg = msg
-        self.doc = doc
-        self.pos = pos
-        self.end = end
-        self.lineno, self.colno = linecol(doc, pos)
-        if end is not None:
-            self.endlineno, self.endcolno = linecol(doc, pos)
-        else:
-            self.endlineno, self.endcolno = None, None
-
-
-def linecol(doc, pos):
-    lineno = doc.count('\n', 0, pos) + 1
-    if lineno == 1:
-        colno = pos
-    else:
-        colno = pos - doc.rindex('\n', 0, pos)
-    return lineno, colno
-
-
-def errmsg(msg, doc, pos, end=None):
-    # Note that this function is called from _speedups
-    lineno, colno = linecol(doc, pos)
-    if end is None:
-        #fmt = '{0}: line {1} column {2} (char {3})'
-        #return fmt.format(msg, lineno, colno, pos)
-        fmt = '%s: line %d column %d (char %d)'
-        return fmt % (msg, lineno, colno, pos)
-    endlineno, endcolno = linecol(doc, end)
-    #fmt = '{0}: line {1} column {2} - line {3} column {4} (char {5} - {6})'
-    #return fmt.format(msg, lineno, colno, endlineno, endcolno, pos, end)
-    fmt = '%s: line %d column %d - line %d column %d (char %d - %d)'
-    return fmt % (msg, lineno, colno, endlineno, endcolno, pos, end)
-
-
-_CONSTANTS = {
-    '-Infinity': NegInf,
-    'Infinity': PosInf,
-    'NaN': NaN,
-}
-
-STRINGCHUNK = re.compile(r'(.*?)(["\\\x00-\x1f])', FLAGS)
-BACKSLASH = {
-    '"': u'"', '\\': u'\\', '/': u'/',
-    'b': u'\b', 'f': u'\f', 'n': u'\n', 'r': u'\r', 't': u'\t',
-}
-
-DEFAULT_ENCODING = "utf-8"
-
-def py_scanstring(s, end, encoding=None, strict=True,
-        _b=BACKSLASH, _m=STRINGCHUNK.match):
-    """Scan the string s for a JSON string. End is the index of the
-    character in s after the quote that started the JSON string.
-    Unescapes all valid JSON string escape sequences and raises ValueError
-    on attempt to decode an invalid string. If strict is False then literal
-    control characters are allowed in the string.
-
-    Returns a tuple of the decoded string and the index of the character in s
-    after the end quote."""
-    if encoding is None:
-        encoding = DEFAULT_ENCODING
-    chunks = []
-    _append = chunks.append
-    begin = end - 1
-    while 1:
-        chunk = _m(s, end)
-        if chunk is None:
-            raise JSONDecodeError(
-                "Unterminated string starting at", s, begin)
-        end = chunk.end()
-        content, terminator = chunk.groups()
-        # Content is contains zero or more unescaped string characters
-        if content:
-            if not isinstance(content, unicode):
-                content = unicode(content, encoding)
-            _append(content)
-        # Terminator is the end of string, a literal control character,
-        # or a backslash denoting that an escape sequence follows
-        if terminator == '"':
-            break
-        elif terminator != '\\':
-            if strict:
-                msg = "Invalid control character %r at" % (terminator,)
-                #msg = "Invalid control character {0!r} at".format(terminator)
-                raise JSONDecodeError(msg, s, end)
-            else:
-                _append(terminator)
-                continue
-        try:
-            esc = s[end]
-        except IndexError:
-            raise JSONDecodeError(
-                "Unterminated string starting at", s, begin)
-        # If not a unicode escape sequence, must be in the lookup table
-        if esc != 'u':
-            try:
-                char = _b[esc]
-            except KeyError:
-                msg = "Invalid \\escape: " + repr(esc)
-                raise JSONDecodeError(msg, s, end)
-            end += 1
-        else:
-            # Unicode escape sequence
-            esc = s[end + 1:end + 5]
-            next_end = end + 5
-            if len(esc) != 4:
-                msg = "Invalid \\uXXXX escape"
-                raise JSONDecodeError(msg, s, end)
-            uni = int(esc, 16)
-            # Check for surrogate pair on UCS-4 systems
-            if 0xd800 <= uni <= 0xdbff and sys.maxunicode > 65535:
-                msg = "Invalid \\uXXXX\\uXXXX surrogate pair"
-                if not s[end + 5:end + 7] == '\\u':
-                    raise JSONDecodeError(msg, s, end)
-                esc2 = s[end + 7:end + 11]
-                if len(esc2) != 4:
-                    raise JSONDecodeError(msg, s, end)
-                uni2 = int(esc2, 16)
-                uni = 0x10000 + (((uni - 0xd800) << 10) | (uni2 - 0xdc00))
-                next_end += 6
-            char = unichr(uni)
-            end = next_end
-        # Append the unescaped character
-        _append(char)
-    return u''.join(chunks), end
-
-
-# Use speedup if available
-scanstring = c_scanstring or py_scanstring
-
-WHITESPACE = re.compile(r'[ \t\n\r]*', FLAGS)
-WHITESPACE_STR = ' \t\n\r'
-
-def JSONObject((s, end), encoding, strict, scan_once, object_hook,
-        object_pairs_hook, _w=WHITESPACE.match, _ws=WHITESPACE_STR):
-    pairs = []
-    # Use a slice to prevent IndexError from being raised, the following
-    # check will raise a more specific ValueError if the string is empty
-    nextchar = s[end:end + 1]
-    # Normally we expect nextchar == '"'
-    if nextchar != '"':
-        if nextchar in _ws:
-            end = _w(s, end).end()
-            nextchar = s[end:end + 1]
-        # Trivial empty object
-        if nextchar == '}':
-            if object_pairs_hook is not None:
-                result = object_pairs_hook(pairs)
-                return result, end
-            pairs = {}
-            if object_hook is not None:
-                pairs = object_hook(pairs)
-            return pairs, end + 1
-        elif nextchar != '"':
-            raise JSONDecodeError("Expecting property name", s, end)
-    end += 1
-    while True:
-        key, end = scanstring(s, end, encoding, strict)
-
-        # To skip some function call overhead we optimize the fast paths where
-        # the JSON key separator is ": " or just ":".
-        if s[end:end + 1] != ':':
-            end = _w(s, end).end()
-            if s[end:end + 1] != ':':
-                raise JSONDecodeError("Expecting : delimiter", s, end)
-
-        end += 1
-
-        try:
-            if s[end] in _ws:
-                end += 1
-                if s[end] in _ws:
-                    end = _w(s, end + 1).end()
-        except IndexError:
-            pass
-
-        try:
-            value, end = scan_once(s, end)
-        except StopIteration:
-            raise JSONDecodeError("Expecting object", s, end)
-        pairs.append((key, value))
-
-        try:
-            nextchar = s[end]
-            if nextchar in _ws:
-                end = _w(s, end + 1).end()
-                nextchar = s[end]
-        except IndexError:
-            nextchar = ''
-        end += 1
-
-        if nextchar == '}':
-            break
-        elif nextchar != ',':
-            raise JSONDecodeError("Expecting , delimiter", s, end - 1)
-
-        try:
-            nextchar = s[end]
-            if nextchar in _ws:
-                end += 1
-                nextchar = s[end]
-                if nextchar in _ws:
-                    end = _w(s, end + 1).end()
-                    nextchar = s[end]
-        except IndexError:
-            nextchar = ''
-
-        end += 1
-        if nextchar != '"':
-            raise JSONDecodeError("Expecting property name", s, end - 1)
-
-    if object_pairs_hook is not None:
-        result = object_pairs_hook(pairs)
-        return result, end
-    pairs = dict(pairs)
-    if object_hook is not None:
-        pairs = object_hook(pairs)
-    return pairs, end
-
-def JSONArray((s, end), scan_once, _w=WHITESPACE.match, _ws=WHITESPACE_STR):
-    values = []
-    nextchar = s[end:end + 1]
-    if nextchar in _ws:
-        end = _w(s, end + 1).end()
-        nextchar = s[end:end + 1]
-    # Look-ahead for trivial empty array
-    if nextchar == ']':
-        return values, end + 1
-    _append = values.append
-    while True:
-        try:
-            value, end = scan_once(s, end)
-        except StopIteration:
-            raise JSONDecodeError("Expecting object", s, end)
-        _append(value)
-        nextchar = s[end:end + 1]
-        if nextchar in _ws:
-            end = _w(s, end + 1).end()
-            nextchar = s[end:end + 1]
-        end += 1
-        if nextchar == ']':
-            break
-        elif nextchar != ',':
-            raise JSONDecodeError("Expecting , delimiter", s, end)
-
-        try:
-            if s[end] in _ws:
-                end += 1
-                if s[end] in _ws:
-                    end = _w(s, end + 1).end()
-        except IndexError:
-            pass
-
-    return values, end
-
-class JSONDecoder(object):
-    """Simple JSON <http://json.org> decoder
-
-    Performs the following translations in decoding by default:
-
-    +---------------+-------------------+
-    | JSON          | Python            |
-    +===============+===================+
-    | object        | dict              |
-    +---------------+-------------------+
-    | array         | list              |
-    +---------------+-------------------+
-    | string        | unicode           |
-    +---------------+-------------------+
-    | number (int)  | int, long         |
-    +---------------+-------------------+
-    | number (real) | float             |
-    +---------------+-------------------+
-    | true          | True              |
-    +---------------+-------------------+
-    | false         | False             |
-    +---------------+-------------------+
-    | null          | None              |
-    +---------------+-------------------+
-
-    It also understands ``NaN``, ``Infinity``, and ``-Infinity`` as
-    their corresponding ``float`` values, which is outside the JSON spec.
-
-    """
-
-    def __init__(self, encoding=None, object_hook=None, parse_float=None,
-            parse_int=None, parse_constant=None, strict=True,
-            object_pairs_hook=None):
-        """
-        *encoding* determines the encoding used to interpret any
-        :class:`str` objects decoded by this instance (``'utf-8'`` by
-        default).  It has no effect when decoding :class:`unicode` objects.
-
-        Note that currently only encodings that are a superset of ASCII work,
-        strings of other encodings should be passed in as :class:`unicode`.
-
-        *object_hook*, if specified, will be called with the result of every
-        JSON object decoded and its return value will be used in place of the
-        given :class:`dict`.  This can be used to provide custom
-        deserializations (e.g. to support JSON-RPC class hinting).
-
-        *object_pairs_hook* is an optional function that will be called with
-        the result of any object literal decode with an ordered list of pairs.
-        The return value of *object_pairs_hook* will be used instead of the
-        :class:`dict`.  This feature can be used to implement custom decoders
-        that rely on the order that the key and value pairs are decoded (for
-        example, :func:`collections.OrderedDict` will remember the order of
-        insertion). If *object_hook* is also defined, the *object_pairs_hook*
-        takes priority.
-
-        *parse_float*, if specified, will be called with the string of every
-        JSON float to be decoded.  By default, this is equivalent to
-        ``float(num_str)``. This can be used to use another datatype or parser
-        for JSON floats (e.g. :class:`decimal.Decimal`).
-
-        *parse_int*, if specified, will be called with the string of every
-        JSON int to be decoded.  By default, this is equivalent to
-        ``int(num_str)``.  This can be used to use another datatype or parser
-        for JSON integers (e.g. :class:`float`).
-
-        *parse_constant*, if specified, will be called with one of the
-        following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``.  This
-        can be used to raise an exception if invalid JSON numbers are
-        encountered.
-
-        *strict* controls the parser's behavior when it encounters an
-        invalid control character in a string. The default setting of
-        ``True`` means that unescaped control characters are parse errors, if
-        ``False`` then control characters will be allowed in strings.
-
-        """
-        self.encoding = encoding
-        self.object_hook = object_hook
-        self.object_pairs_hook = object_pairs_hook
-        self.parse_float = parse_float or float
-        self.parse_int = parse_int or int
-        self.parse_constant = parse_constant or _CONSTANTS.__getitem__
-        self.strict = strict
-        self.parse_object = JSONObject
-        self.parse_array = JSONArray
-        self.parse_string = scanstring
-        self.scan_once = make_scanner(self)
-
-    def decode(self, s, _w=WHITESPACE.match):
-        """Return the Python representation of ``s`` (a ``str`` or ``unicode``
-        instance containing a JSON document)
-
-        """
-        obj, end = self.raw_decode(s, idx=_w(s, 0).end())
-        end = _w(s, end).end()
-        if end != len(s):
-            raise JSONDecodeError("Extra data", s, end, len(s))
-        return obj
-
-    def raw_decode(self, s, idx=0):
-        """Decode a JSON document from ``s`` (a ``str`` or ``unicode``
-        beginning with a JSON document) and return a 2-tuple of the Python
-        representation and the index in ``s`` where the document ended.
-
-        This can be used to decode a JSON document from a string that may
-        have extraneous data at the end.
-
-        """
-        try:
-            obj, end = self.scan_once(s, idx)
-        except StopIteration:
-            raise JSONDecodeError("No JSON object could be decoded", s, idx)
-        return obj, end
diff --git a/wave/src/main/java/python/api/simplejson/encoder.py b/wave/src/main/java/python/api/simplejson/encoder.py
deleted file mode 100644
index 1ddf35c..0000000
--- a/wave/src/main/java/python/api/simplejson/encoder.py
+++ /dev/null
@@ -1,476 +0,0 @@
-#
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-#
-#
-"""Implementation of JSONEncoder
-"""
-import re
-
-try:
-    from _speedups import encode_basestring_ascii as \
-        c_encode_basestring_ascii
-except ImportError:
-    c_encode_basestring_ascii = None
-try:
-    from _speedups import make_encoder as c_make_encoder
-except ImportError:
-    c_make_encoder = None
-
-from decoder import PosInf
-
-ESCAPE = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t]')
-ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])')
-HAS_UTF8 = re.compile(r'[\x80-\xff]')
-ESCAPE_DCT = {
-    '\\': '\\\\',
-    '"': '\\"',
-    '\b': '\\b',
-    '\f': '\\f',
-    '\n': '\\n',
-    '\r': '\\r',
-    '\t': '\\t',
-}
-for i in range(0x20):
-    #ESCAPE_DCT.setdefault(chr(i), '\\u{0:04x}'.format(i))
-    ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))
-
-FLOAT_REPR = repr
-
-def encode_basestring(s):
-    """Return a JSON representation of a Python string
-
-    """
-    if isinstance(s, str) and HAS_UTF8.search(s) is not None:
-        s = s.decode('utf-8')
-    def replace(match):
-        return ESCAPE_DCT[match.group(0)]
-    return u'"' + ESCAPE.sub(replace, s) + u'"'
-
-
-def py_encode_basestring_ascii(s):
-    """Return an ASCII-only JSON representation of a Python string
-
-    """
-    if isinstance(s, str) and HAS_UTF8.search(s) is not None:
-        s = s.decode('utf-8')
-    def replace(match):
-        s = match.group(0)
-        try:
-            return ESCAPE_DCT[s]
-        except KeyError:
-            n = ord(s)
-            if n < 0x10000:
-                #return '\\u{0:04x}'.format(n)
-                return '\\u%04x' % (n,)
-            else:
-                # surrogate pair
-                n -= 0x10000
-                s1 = 0xd800 | ((n >> 10) & 0x3ff)
-                s2 = 0xdc00 | (n & 0x3ff)
-                #return '\\u{0:04x}\\u{1:04x}'.format(s1, s2)
-                return '\\u%04x\\u%04x' % (s1, s2)
-    return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"'
-
-
-encode_basestring_ascii = (
-    c_encode_basestring_ascii or py_encode_basestring_ascii)
-
-class JSONEncoder(object):
-    """Extensible JSON <http://json.org> encoder for Python data structures.
-
-    Supports the following objects and types by default:
-
-    +-------------------+---------------+
-    | Python            | JSON          |
-    +===================+===============+
-    | dict              | object        |
-    +-------------------+---------------+
-    | list, tuple       | array         |
-    +-------------------+---------------+
-    | str, unicode      | string        |
-    +-------------------+---------------+
-    | int, long, float  | number        |
-    +-------------------+---------------+
-    | True              | true          |
-    +-------------------+---------------+
-    | False             | false         |
-    +-------------------+---------------+
-    | None              | null          |
-    +-------------------+---------------+
-
-    To extend this to recognize other objects, subclass and implement a
-    ``.default()`` method with another method that returns a serializable
-    object for ``o`` if possible, otherwise it should call the superclass
-    implementation (to raise ``TypeError``).
-
-    """
-    item_separator = ', '
-    key_separator = ': '
-    def __init__(self, skipkeys=False, ensure_ascii=True,
-            check_circular=True, allow_nan=True, sort_keys=False,
-            indent=None, separators=None, encoding='utf-8', default=None):
-        """Constructor for JSONEncoder, with sensible defaults.
-
-        If skipkeys is false, then it is a TypeError to attempt
-        encoding of keys that are not str, int, long, float or None.  If
-        skipkeys is True, such items are simply skipped.
-
-        If ensure_ascii is true, the output is guaranteed to be str
-        objects with all incoming unicode characters escaped.  If
-        ensure_ascii is false, the output will be unicode object.
-
-        If check_circular is true, then lists, dicts, and custom encoded
-        objects will be checked for circular references during encoding to
-        prevent an infinite recursion (which would cause an OverflowError).
-        Otherwise, no such check takes place.
-
-        If allow_nan is true, then NaN, Infinity, and -Infinity will be
-        encoded as such.  This behavior is not JSON specification compliant,
-        but is consistent with most JavaScript based encoders and decoders.
-        Otherwise, it will be a ValueError to encode such floats.
-
-        If sort_keys is true, then the output of dictionaries will be
-        sorted by key; this is useful for regression tests to ensure
-        that JSON serializations can be compared on a day-to-day basis.
-
-        If indent is a string, then JSON array elements and object members
-        will be pretty-printed with a newline followed by that string repeated
-        for each level of nesting. ``None`` (the default) selects the most compact
-        representation without any newlines. For backwards compatibility with
-        versions of simplejson earlier than 2.1.0, an integer is also accepted
-        and is converted to a string with that many spaces.
-
-        If specified, separators should be a (item_separator, key_separator)
-        tuple.  The default is (', ', ': ').  To get the most compact JSON
-        representation you should specify (',', ':') to eliminate whitespace.
-
-        If specified, default is a function that gets called for objects
-        that can't otherwise be serialized.  It should return a JSON encodable
-        version of the object or raise a ``TypeError``.
-
-        If encoding is not None, then all input strings will be
-        transformed into unicode using that encoding prior to JSON-encoding.
-        The default is UTF-8.
-
-        """
-
-        self.skipkeys = skipkeys
-        self.ensure_ascii = ensure_ascii
-        self.check_circular = check_circular
-        self.allow_nan = allow_nan
-        self.sort_keys = sort_keys
-        if isinstance(indent, (int, long)):
-            indent = ' ' * indent
-        self.indent = indent
-        if separators is not None:
-            self.item_separator, self.key_separator = separators
-        if default is not None:
-            self.default = default
-        self.encoding = encoding
-
-    def default(self, o):
-        """Implement this method in a subclass such that it returns
-        a serializable object for ``o``, or calls the base implementation
-        (to raise a ``TypeError``).
-
-        For example, to support arbitrary iterators, you could
-        implement default like this::
-
-            def default(self, o):
-                try:
-                    iterable = iter(o)
-                except TypeError:
-                    pass
-                else:
-                    return list(iterable)
-                return JSONEncoder.default(self, o)
-
-        """
-        raise TypeError(repr(o) + " is not JSON serializable")
-
-    def encode(self, o):
-        """Return a JSON string representation of a Python data structure.
-
-        >>> from simplejson import JSONEncoder
-        >>> JSONEncoder().encode({"foo": ["bar", "baz"]})
-        '{"foo": ["bar", "baz"]}'
-
-        """
-        # This is for extremely simple cases and benchmarks.
-        if isinstance(o, basestring):
-            if isinstance(o, str):
-                _encoding = self.encoding
-                if (_encoding is not None
-                        and not (_encoding == 'utf-8')):
-                    o = o.decode(_encoding)
-            if self.ensure_ascii:
-                return encode_basestring_ascii(o)
-            else:
-                return encode_basestring(o)
-        # This doesn't pass the iterator directly to ''.join() because the
-        # exceptions aren't as detailed.  The list call should be roughly
-        # equivalent to the PySequence_Fast that ''.join() would do.
-        chunks = self.iterencode(o, _one_shot=True)
-        if not isinstance(chunks, (list, tuple)):
-            chunks = list(chunks)
-        if self.ensure_ascii:
-            return ''.join(chunks)
-        else:
-            return u''.join(chunks)
-
-    def iterencode(self, o, _one_shot=False):
-        """Encode the given object and yield each string
-        representation as available.
-
-        For example::
-
-            for chunk in JSONEncoder().iterencode(bigobject):
-                mysocket.write(chunk)
-
-        """
-        if self.check_circular:
-            markers = {}
-        else:
-            markers = None
-        if self.ensure_ascii:
-            _encoder = encode_basestring_ascii
-        else:
-            _encoder = encode_basestring
-        if self.encoding != 'utf-8':
-            def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding):
-                if isinstance(o, str):
-                    o = o.decode(_encoding)
-                return _orig_encoder(o)
-
-        def floatstr(o, allow_nan=self.allow_nan,
-                _repr=FLOAT_REPR, _inf=PosInf, _neginf=-PosInf):
-            # Check for specials. Note that this type of test is processor
-            # and/or platform-specific, so do tests which don't depend on
-            # the internals.
-
-            if o != o:
-                text = 'NaN'
-            elif o == _inf:
-                text = 'Infinity'
-            elif o == _neginf:
-                text = '-Infinity'
-            else:
-                return _repr(o)
-
-            if not allow_nan:
-                raise ValueError(
-                    "Out of range float values are not JSON compliant: " +
-                    repr(o))
-
-            return text
-
-
-        if (_one_shot and c_make_encoder is not None
-                and not self.indent and not self.sort_keys):
-            _iterencode = c_make_encoder(
-                markers, self.default, _encoder, self.indent,
-                self.key_separator, self.item_separator, self.sort_keys,
-                self.skipkeys, self.allow_nan)
-        else:
-            _iterencode = _make_iterencode(
-                markers, self.default, _encoder, self.indent, floatstr,
-                self.key_separator, self.item_separator, self.sort_keys,
-                self.skipkeys, _one_shot)
-        return _iterencode(o, 0)
-
-def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
-        _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,
-        ## HACK: hand-optimized bytecode; turn globals into locals
-        False=False,
-        True=True,
-        ValueError=ValueError,
-        basestring=basestring,
-        dict=dict,
-        float=float,
-        id=id,
-        int=int,
-        isinstance=isinstance,
-        list=list,
-        long=long,
-        str=str,
-        tuple=tuple,
-    ):
-
-    def _iterencode_list(lst, _current_indent_level):
-        if not lst:
-            yield '[]'
-            return
-        if markers is not None:
-            markerid = id(lst)
-            if markerid in markers:
-                raise ValueError("Circular reference detected")
-            markers[markerid] = lst
-        buf = '['
-        if _indent is not None:
-            _current_indent_level += 1
-            newline_indent = '\n' + (_indent * _current_indent_level)
-            separator = _item_separator + newline_indent
-            buf += newline_indent
-        else:
-            newline_indent = None
-            separator = _item_separator
-        first = True
-        for value in lst:
-            if first:
-                first = False
-            else:
-                buf = separator
-            if isinstance(value, basestring):
-                yield buf + _encoder(value)
-            elif value is None:
-                yield buf + 'null'
-            elif value is True:
-                yield buf + 'true'
-            elif value is False:
-                yield buf + 'false'
-            elif isinstance(value, (int, long)):
-                yield buf + str(value)
-            elif isinstance(value, float):
-                yield buf + _floatstr(value)
-            else:
-                yield buf
-                if isinstance(value, (list, tuple)):
-                    chunks = _iterencode_list(value, _current_indent_level)
-                elif isinstance(value, dict):
-                    chunks = _iterencode_dict(value, _current_indent_level)
-                else:
-                    chunks = _iterencode(value, _current_indent_level)
-                for chunk in chunks:
-                    yield chunk
-        if newline_indent is not None:
-            _current_indent_level -= 1
-            yield '\n' + (_indent * _current_indent_level)
-        yield ']'
-        if markers is not None:
-            del markers[markerid]
-
-    def _iterencode_dict(dct, _current_indent_level):
-        if not dct:
-            yield '{}'
-            return
-        if markers is not None:
-            markerid = id(dct)
-            if markerid in markers:
-                raise ValueError("Circular reference detected")
-            markers[markerid] = dct
-        yield '{'
-        if _indent is not None:
-            _current_indent_level += 1
-            newline_indent = '\n' + (_indent * _current_indent_level)
-            item_separator = _item_separator + newline_indent
-            yield newline_indent
-        else:
-            newline_indent = None
-            item_separator = _item_separator
-        first = True
-        if _sort_keys:
-            items = dct.items()
-            items.sort(key=lambda kv: kv[0])
-        else:
-            items = dct.iteritems()
-        for key, value in items:
-            if isinstance(key, basestring):
-                pass
-            # JavaScript is weakly typed for these, so it makes sense to
-            # also allow them.  Many encoders seem to do something like this.
-            elif isinstance(key, float):
-                key = _floatstr(key)
-            elif key is True:
-                key = 'true'
-            elif key is False:
-                key = 'false'
-            elif key is None:
-                key = 'null'
-            elif isinstance(key, (int, long)):
-                key = str(key)
-            elif _skipkeys:
-                continue
-            else:
-                raise TypeError("key " + repr(key) + " is not a string")
-            if first:
-                first = False
-            else:
-                yield item_separator
-            yield _encoder(key)
-            yield _key_separator
-            if isinstance(value, basestring):
-                yield _encoder(value)
-            elif value is None:
-                yield 'null'
-            elif value is True:
-                yield 'true'
-            elif value is False:
-                yield 'false'
-            elif isinstance(value, (int, long)):
-                yield str(value)
-            elif isinstance(value, float):
-                yield _floatstr(value)
-            else:
-                if isinstance(value, (list, tuple)):
-                    chunks = _iterencode_list(value, _current_indent_level)
-                elif isinstance(value, dict):
-                    chunks = _iterencode_dict(value, _current_indent_level)
-                else:
-                    chunks = _iterencode(value, _current_indent_level)
-                for chunk in chunks:
-                    yield chunk
-        if newline_indent is not None:
-            _current_indent_level -= 1
-            yield '\n' + (_indent * _current_indent_level)
-        yield '}'
-        if markers is not None:
-            del markers[markerid]
-
-    def _iterencode(o, _current_indent_level):
-        if isinstance(o, basestring):
-            yield _encoder(o)
-        elif o is None:
-            yield 'null'
-        elif o is True:
-            yield 'true'
-        elif o is False:
-            yield 'false'
-        elif isinstance(o, (int, long)):
-            yield str(o)
-        elif isinstance(o, float):
-            yield _floatstr(o)
-        elif isinstance(o, (list, tuple)):
-            for chunk in _iterencode_list(o, _current_indent_level):
-                yield chunk
-        elif isinstance(o, dict):
-            for chunk in _iterencode_dict(o, _current_indent_level):
-                yield chunk
-        else:
-            if markers is not None:
-                markerid = id(o)
-                if markerid in markers:
-                    raise ValueError("Circular reference detected")
-                markers[markerid] = o
-            o = _default(o)
-            for chunk in _iterencode(o, _current_indent_level):
-                yield chunk
-            if markers is not None:
-                del markers[markerid]
-
-    return _iterencode
diff --git a/wave/src/main/java/python/api/simplejson/jsonfilter.py b/wave/src/main/java/python/api/simplejson/jsonfilter.py
deleted file mode 100644
index 7c0da57..0000000
--- a/wave/src/main/java/python/api/simplejson/jsonfilter.py
+++ /dev/null
@@ -1,60 +0,0 @@
-#
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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 simplejson
-import cgi
-
-class JSONFilter(object):
-    def __init__(self, app, mime_type='text/x-json'):
-        self.app = app
-        self.mime_type = mime_type
-
-    def __call__(self, environ, start_response):
-        # Read JSON POST input to jsonfilter.json if matching mime type
-        response = {'status': '200 OK', 'headers': []}
-        def json_start_response(status, headers):
-            response['status'] = status
-            response['headers'].extend(headers)
-        environ['jsonfilter.mime_type'] = self.mime_type
-        if environ.get('REQUEST_METHOD', '') == 'POST':
-            if environ.get('CONTENT_TYPE', '') == self.mime_type:
-                args = [_ for _ in [environ.get('CONTENT_LENGTH')] if _]
-                data = environ['wsgi.input'].read(*map(int, args))
-                environ['jsonfilter.json'] = simplejson.loads(data)
-        res = simplejson.dumps(self.app(environ, json_start_response))
-        jsonp = cgi.parse_qs(environ.get('QUERY_STRING', '')).get('jsonp')
-        if jsonp:
-            content_type = 'text/javascript'
-            res = ''.join(jsonp + ['(', res, ')'])
-        elif 'Opera' in environ.get('HTTP_USER_AGENT', ''):
-            # Opera has bunk XMLHttpRequest support for most mime types
-            content_type = 'text/plain'
-        else:
-            content_type = self.mime_type
-        headers = [
-            ('Content-type', content_type),
-            ('Content-length', len(res)),
-        ]
-        headers.extend(response['headers'])
-        start_response(response['status'], headers)
-        return [res]
-
-def factory(app, global_conf, **kw):
-    return JSONFilter(app, **kw)
diff --git a/wave/src/main/java/python/api/simplejson/ordered_dict.py b/wave/src/main/java/python/api/simplejson/ordered_dict.py
deleted file mode 100644
index a186e77..0000000
--- a/wave/src/main/java/python/api/simplejson/ordered_dict.py
+++ /dev/null
@@ -1,139 +0,0 @@
-#
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-#
-#
-"""Drop-in replacement for collections.OrderedDict by Raymond Hettinger
-
-http://code.activestate.com/recipes/576693/
-
-"""
-from UserDict import DictMixin
-
-# Modified from original to support Python 2.4, see
-# http://code.google.com/p/simplejson/issues/detail?id=53
-try:
-    all
-except NameError:
-    def all(seq):
-        for elem in seq:
-            if not elem:
-                return False
-        return True
-
-class OrderedDict(dict, DictMixin):
-
-    def __init__(self, *args, **kwds):
-        if len(args) > 1:
-            raise TypeError('expected at most 1 arguments, got %d' % len(args))
-        try:
-            self.__end
-        except AttributeError:
-            self.clear()
-        self.update(*args, **kwds)
-
-    def clear(self):
-        self.__end = end = []
-        end += [None, end, end]         # sentinel node for doubly linked list
-        self.__map = {}                 # key --> [key, prev, next]
-        dict.clear(self)
-
-    def __setitem__(self, key, value):
-        if key not in self:
-            end = self.__end
-            curr = end[1]
-            curr[2] = end[1] = self.__map[key] = [key, curr, end]
-        dict.__setitem__(self, key, value)
-
-    def __delitem__(self, key):
-        dict.__delitem__(self, key)
-        key, prev, next = self.__map.pop(key)
-        prev[2] = next
-        next[1] = prev
-
-    def __iter__(self):
-        end = self.__end
-        curr = end[2]
-        while curr is not end:
-            yield curr[0]
-            curr = curr[2]
-
-    def __reversed__(self):
-        end = self.__end
-        curr = end[1]
-        while curr is not end:
-            yield curr[0]
-            curr = curr[1]
-
-    def popitem(self, last=True):
-        if not self:
-            raise KeyError('dictionary is empty')
-        # Modified from original to support Python 2.4, see
-        # http://code.google.com/p/simplejson/issues/detail?id=53
-        if last:
-            key = reversed(self).next()
-        else:
-            key = iter(self).next()
-        value = self.pop(key)
-        return key, value
-
-    def __reduce__(self):
-        items = [[k, self[k]] for k in self]
-        tmp = self.__map, self.__end
-        del self.__map, self.__end
-        inst_dict = vars(self).copy()
-        self.__map, self.__end = tmp
-        if inst_dict:
-            return (self.__class__, (items,), inst_dict)
-        return self.__class__, (items,)
-
-    def keys(self):
-        return list(self)
-
-    setdefault = DictMixin.setdefault
-    update = DictMixin.update
-    pop = DictMixin.pop
-    values = DictMixin.values
-    items = DictMixin.items
-    iterkeys = DictMixin.iterkeys
-    itervalues = DictMixin.itervalues
-    iteritems = DictMixin.iteritems
-
-    def __repr__(self):
-        if not self:
-            return '%s()' % (self.__class__.__name__,)
-        return '%s(%r)' % (self.__class__.__name__, self.items())
-
-    def copy(self):
-        return self.__class__(self)
-
-    @classmethod
-    def fromkeys(cls, iterable, value=None):
-        d = cls()
-        for key in iterable:
-            d[key] = value
-        return d
-
-    def __eq__(self, other):
-        if isinstance(other, OrderedDict):
-            return len(self)==len(other) and \
-                   all(p==q for p, q in  zip(self.items(), other.items()))
-        return dict.__eq__(self, other)
-
-    def __ne__(self, other):
-        return not self == other
diff --git a/wave/src/main/java/python/api/simplejson/scanner.py b/wave/src/main/java/python/api/simplejson/scanner.py
deleted file mode 100644
index 4e01271..0000000
--- a/wave/src/main/java/python/api/simplejson/scanner.py
+++ /dev/null
@@ -1,87 +0,0 @@
-#
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-#
-#
-"""JSON token scanner
-"""
-import re
-try:
-    from simplejson._speedups import make_scanner as c_make_scanner
-except ImportError:
-    c_make_scanner = None
-
-__all__ = ['make_scanner']
-
-NUMBER_RE = re.compile(
-    r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?',
-    (re.VERBOSE | re.MULTILINE | re.DOTALL))
-
-def py_make_scanner(context):
-    parse_object = context.parse_object
-    parse_array = context.parse_array
-    parse_string = context.parse_string
-    match_number = NUMBER_RE.match
-    encoding = context.encoding
-    strict = context.strict
-    parse_float = context.parse_float
-    parse_int = context.parse_int
-    parse_constant = context.parse_constant
-    object_hook = context.object_hook
-    object_pairs_hook = context.object_pairs_hook
-
-    def _scan_once(string, idx):
-        try:
-            nextchar = string[idx]
-        except IndexError:
-            raise StopIteration
-
-        if nextchar == '"':
-            return parse_string(string, idx + 1, encoding, strict)
-        elif nextchar == '{':
-            return parse_object((string, idx + 1), encoding, strict,
-                _scan_once, object_hook, object_pairs_hook)
-        elif nextchar == '[':
-            return parse_array((string, idx + 1), _scan_once)
-        elif nextchar == 'n' and string[idx:idx + 4] == 'null':
-            return None, idx + 4
-        elif nextchar == 't' and string[idx:idx + 4] == 'true':
-            return True, idx + 4
-        elif nextchar == 'f' and string[idx:idx + 5] == 'false':
-            return False, idx + 5
-
-        m = match_number(string, idx)
-        if m is not None:
-            integer, frac, exp = m.groups()
-            if frac or exp:
-                res = parse_float(integer + (frac or '') + (exp or ''))
-            else:
-                res = parse_int(integer)
-            return res, m.end()
-        elif nextchar == 'N' and string[idx:idx + 3] == 'NaN':
-            return parse_constant('NaN'), idx + 3
-        elif nextchar == 'I' and string[idx:idx + 8] == 'Infinity':
-            return parse_constant('Infinity'), idx + 8
-        elif nextchar == '-' and string[idx:idx + 9] == '-Infinity':
-            return parse_constant('-Infinity'), idx + 9
-        else:
-            raise StopIteration
-
-    return _scan_once
-
-make_scanner = c_make_scanner or py_make_scanner
diff --git a/wave/src/main/java/python/api/simplejson/tool.py b/wave/src/main/java/python/api/simplejson/tool.py
deleted file mode 100644
index 646d254..0000000
--- a/wave/src/main/java/python/api/simplejson/tool.py
+++ /dev/null
@@ -1,57 +0,0 @@
-#
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-#
-#
-r"""Command-line tool to validate and pretty-print JSON
-
-Usage::
-
-    $ echo '{"json":"obj"}' | python -m simplejson.tool
-    {
-        "json": "obj"
-    }
-    $ echo '{ 1.2:3.4}' | python -m simplejson.tool
-    Expecting property name: line 1 column 2 (char 2)
-
-"""
-import sys
-import simplejson as json
-
-def main():
-    if len(sys.argv) == 1:
-        infile = sys.stdin
-        outfile = sys.stdout
-    elif len(sys.argv) == 2:
-        infile = open(sys.argv[1], 'rb')
-        outfile = sys.stdout
-    elif len(sys.argv) == 3:
-        infile = open(sys.argv[1], 'rb')
-        outfile = open(sys.argv[2], 'wb')
-    else:
-        raise SystemExit(sys.argv[0] + " [infile [outfile]]")
-    try:
-        obj = json.load(infile, object_pairs_hook=json.OrderedDict)
-    except ValueError, e:
-        raise SystemExit(e)
-    json.dump(obj, outfile, sort_keys=True, indent='    ')
-    outfile.write('\n')
-
-
-if __name__ == '__main__':
-    main()
diff --git a/wave/src/main/java/python/api/testdata.py b/wave/src/main/java/python/api/testdata.py
deleted file mode 100644
index fd6b248..0000000
--- a/wave/src/main/java/python/api/testdata.py
+++ /dev/null
@@ -1,225 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-
-json_string = """{
-    "wavelet": {
-        "creationTime": 1277873815463,
-        "lastModifiedTime": 1277873843515,
-        "version": 51,
-        "participants": [
-            "pamela.fox@wavesandbox.com",
-            "5.latest.exporty-bot@appspot.com"
-        ],
-        "participantRoles": {
-            "5.latest.exporty-bot@appspot.com": "FULL",
-            "pamela.fox@wavesandbox.com": "FULL"
-        },
-        "dataDocuments": {
-        },
-        "tags": [
-        ],
-        "creator": "pamela.fox@wavesandbox.com",
-        "rootBlipId": "b+IvD7RCuWB",
-        "title": "Test",
-        "waveId": "wavesandbox.com!w+IvD7RCuWA",
-        "waveletId": "wavesandbox.com!conv+root",
-        "rootThread": {
-            "id": "",
-            "location": -1,
-            "blipIds": [
-                "b+IvD7RCuWB",
-                "b+IvD7RCuWC",
-                "b+IvD7RCuWE"
-            ]
-        }
-    },
-    "blips": {
-        "b+IvD7RCuWB": {
-            "annotations": [],
-            "elements": {},
-            "blipId": "b+IvD7RCuWB",
-            "childBlipIds": [
-                "b+IvD7RCuWD"
-            ],
-            "contributors": [
-                "pamela.fox@wavesandbox.com"
-            ],
-            "creator": "pamela.fox@wavesandbox.com",
-            "content": "test",
-            "lastModifiedTime": 1277873815441,
-            "parentBlipId": null,
-            "version": 5,
-            "waveId": "wavesandbox.com!w+IvD7RCuWA",
-            "waveletId": "wavesandbox.com!conv+root",
-            "replyThreadIds": [
-                "b+IvD7RCuWD"
-            ],
-            "threadId": ""
-        },
-        "b+IvD7RCuWC": {
-            "annotations": [
-            ],
-            "elements": {
-            },
-            "blipId": "b+IvD7RCuWC",
-            "childBlipIds": [
-                "b+IvD7RCuWF",
-                "b+IvD7RCuWG",
-                "b+IvD7RCuWH"
-            ],
-            "contributors": [
-                "pamela.fox@wavesandbox.com"
-            ],
-            "creator": "pamela.fox@wavesandbox.com",
-            "content": "\\ntest",
-            "lastModifiedTime": 1277873818083,
-            "parentBlipId": null,
-            "version": 10,
-            "waveId": "wavesandbox.com!w+IvD7RCuWA",
-            "waveletId": "wavesandbox.com!conv+root",
-            "replyThreadIds": [
-                "b+IvD7RCuWF"
-            ],
-            "threadId": ""
-        },
-        "b+IvD7RCuWH": {
-            "annotations": [
-            ],
-            "elements": {
-            },
-            "blipId": "b+IvD7RCuWH",
-            "childBlipIds": [
-            ],
-            "contributors": [
-                "pamela.fox@wavesandbox.com"
-            ],
-            "creator": "pamela.fox@wavesandbox.com",
-            "content": "\\ntest",
-            "lastModifiedTime": 1277873830724,
-            "parentBlipId": "b+IvD7RCuWC",
-            "version": 48,
-            "waveId": "wavesandbox.com!w+IvD7RCuWA",
-            "waveletId": "wavesandbox.com!conv+root",
-            "replyThreadIds": [
-            ],
-            "threadId": "b+IvD7RCuWF"
-        },
-        "b+IvD7RCuWF": {
-            "annotations": [
-            ],
-            "elements": {
-            },
-            "blipId": "b+IvD7RCuWF",
-            "childBlipIds": [
-            ],
-            "contributors": [
-                "pamela.fox@wavesandbox.com"
-            ],
-            "creator": "pamela.fox@wavesandbox.com",
-            "content": "\\ntest\\n",
-            "lastModifiedTime": 1277873824775,
-            "parentBlipId": "b+IvD7RCuWC",
-            "version": 32,
-            "waveId": "wavesandbox.com!w+IvD7RCuWA",
-            "waveletId": "wavesandbox.com!conv+root",
-            "replyThreadIds": [
-            ],
-            "threadId": "b+IvD7RCuWF"
-        },
-        "b+IvD7RCuWG": {
-            "annotations": [
-            ],
-            "elements": {
-            },
-            "blipId": "b+IvD7RCuWG",
-            "childBlipIds": [
-            ],
-            "contributors": [
-                "pamela.fox@wavesandbox.com"
-            ],
-            "creator": "pamela.fox@wavesandbox.com",
-            "content": "\\ntest\\n",
-            "lastModifiedTime": 1277873828985,
-            "parentBlipId": "b+IvD7RCuWC",
-            "version": 41,
-            "waveId": "wavesandbox.com!w+IvD7RCuWA",
-            "waveletId": "wavesandbox.com!conv+root",
-            "replyThreadIds": [
-            ],
-            "threadId": "b+IvD7RCuWF"
-        },
-        "b+IvD7RCuWD": {
-            "annotations": [],
-            "elements": { },
-            "blipId": "b+IvD7RCuWD",
-            "childBlipIds": [ ],
-            "contributors": [
-                "pamela.fox@wavesandbox.com"
-            ],
-            "creator": "pamela.fox@wavesandbox.com",
-            "content": "\\ntest",
-            "lastModifiedTime": 1277873819390,
-            "parentBlipId": "b+IvD7RCuWB",
-            "version": 18,
-            "waveId": "wavesandbox.com!w+IvD7RCuWA",
-            "waveletId": "wavesandbox.com!conv+root",
-            "replyThreadIds": [
-            ],
-            "threadId": "b+IvD7RCuWD"
-        },
-        "b+IvD7RCuWE": {
-            "annotations": [],
-            "elements": {},
-            "blipId": "b+IvD7RCuWE",
-            "childBlipIds": [
-            ],
-            "contributors": [
-                "pamela.fox@wavesandbox.com"
-            ],
-            "creator": "pamela.fox@wavesandbox.com",
-            "content": "\\nTest",
-            "lastModifiedTime": 1277873822476,
-            "parentBlipId": null,
-            "version": 26,
-            "waveId": "wavesandbox.com!w+IvD7RCuWA",
-            "waveletId": "wavesandbox.com!conv+root",
-            "replyThreadIds": [
-            ],
-            "threadId": ""
-        }
-    },
-    "threads": {
-        "b+IvD7RCuWF": {
-            "id": "b+IvD7RCuWF",
-            "location": -1,
-            "blipIds": [
-                "b+IvD7RCuWF",
-                "b+IvD7RCuWG",
-                "b+IvD7RCuWH"
-            ]
-        },
-        "b+IvD7RCuWD": {
-            "id": "b+IvD7RCuWD",
-            "location": -1,
-            "blipIds": [
-                "b+IvD7RCuWD"
-            ]
-        }
-    },
-    "robotAddress": "5.latest.exporty-bot@appspot.com"
-}"""
diff --git a/wave/src/main/java/python/api/util.py b/wave/src/main/java/python/api/util.py
deleted file mode 100644
index ab7bc2c..0000000
--- a/wave/src/main/java/python/api/util.py
+++ /dev/null
@@ -1,198 +0,0 @@
-#!/usr/bin/python2.4
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Utility library containing various helpers used by the API."""
-
-import re
-
-CUSTOM_SERIALIZE_METHOD_NAME = 'serialize'
-
-MARKUP_RE = re.compile(r'<([^>]*?)>')
-RESERVED_PROXY_FOR_CHARS_RE = re.compile(ur'[\s\u0000-\u001F@,:<>\u007F]')
-
-def force_unicode(object):
-  """ Return the Unicode string version of object, with UTF-8 encoding. """
-  if isinstance(object, unicode):
-    return object
-  return unicode(str(object), 'utf-8')
-
-def parse_markup(markup):
-  """Parses a bit of markup into robot compatible text.
-  
-  For now this is a rough approximation.
-  """
-  def replace_tag(group):
-    if not group.groups:
-      return ''
-    tag = group.groups()[0].split(' ', 1)[0]
-    if (tag == 'p' or tag == 'br'):
-      return '\n'
-    return ''
-
-  return MARKUP_RE.sub(replace_tag, markup)
-
-def is_iterable(inst):
-  """Returns whether or not this is a list, tuple, set or dict .
-
-  Note that this does not return true for strings.
-  """
-  return hasattr(inst, '__iter__')
-
-def is_dict(inst):
-  """Returns whether or not the specified instance is a dict."""
-  return hasattr(inst, 'iteritems')
-
-
-def is_user_defined_new_style_class(obj):
-  """Returns whether or not the specified instance is a user-defined type."""
-  return type(obj).__module__ != '__builtin__'
-
-def lower_camel_case(s):
-  """Converts a string to lower camel case.
-
-  Examples:
-    foo => foo
-    foo_bar => fooBar
-    foo__bar => fooBar
-    foo_bar_baz => fooBarBaz
-
-  Args:
-    s: The string to convert to lower camel case.
-
-  Returns:
-    The lower camel cased string.
-  """
-  return reduce(lambda a, b: a + (a and b.capitalize() or b), s.split('_'))
-
-def non_none_dict(d):
-  """return a copy of the dictionary without none values."""
-  return dict([a for a in d.items() if a[1] is not None])
-
-def _serialize_attributes(obj):
-  """Serializes attributes of an instance.
-
-  Iterates all attributes of an object and invokes serialize if they are
-  public and not callable.
-
-  Args:
-    obj: The instance to serialize.
-
-  Returns:
-    The serialized object.
-  """
-  data = {}
-  for attr_name in dir(obj):
-    if attr_name.startswith('_'):
-      continue
-    attr = getattr(obj, attr_name)
-    if attr is None or callable(attr):
-      continue
-    # Looks okay, serialize it.
-    data[lower_camel_case(attr_name)] = serialize(attr)
-  return data
-
-
-def _serialize_dict(d):
-  """Invokes serialize on all of its key/value pairs.
-
-  Args:
-    d: The dict instance to serialize.
-
-  Returns:
-    The serialized dict.
-  """
-  data = {}
-  for k, v in d.items():
-    data[lower_camel_case(k)] = serialize(v)
-  return data
-
-
-def serialize(obj):
-  """Serializes any instance.
-
-  If this is a user-defined instance
-  type, it will first check for a custom Serialize() function and use that
-  if it exists. Otherwise, it will invoke serialize all of its public
-  attributes. Lists and dicts are serialized trivially.
-
-  Args:
-    obj: The instance to serialize.
-
-  Returns:
-    The serialized object.
-  """
-  if is_user_defined_new_style_class(obj):
-    if obj and hasattr(obj, CUSTOM_SERIALIZE_METHOD_NAME):
-      method = getattr(obj, CUSTOM_SERIALIZE_METHOD_NAME)
-      if callable(method):
-        return method()
-    return _serialize_attributes(obj)
-  elif is_dict(obj):
-    return _serialize_dict(obj)
-  elif is_iterable(obj):
-    return [serialize(v) for v in obj]
-  return obj
-
-def is_valid_proxy_for_id(s):
-  """ Checks if the given string is a valid proxy id.
-
-  This method asserts whether the string contains reserved characters or not.
-  This check is to ensure that when we concatenate the robot id and the proxy
-  id, it doesn't result in an invalid participant id.
-
-  The reserved characters are:
-  - whitespaces
-  - non-printing characters: decimal 0 - 31 (hex 00 - 1F), and decimal 127
-    (hex 7F)
-  - @, comma, :, <, and >
-  If you need to pass in an arbitrary string as the proxy id, please consider
-  encoding the string with a URL encoder (for example, urllib.quote_plus) or
-  base64 encoder (for example, base64.b64encode) first.
-
-  Args:
-    s: the string to be checked.
-
-  Returns:
-    True if the string is a valid proxy for id.
-  """
-  return RESERVED_PROXY_FOR_CHARS_RE.search(s) == None
-
-def check_is_valid_proxy_for_id(s):
-  """ Checks if the given string is a valid proxy id.
-
-  Please see isValidProxyForId(String) for more details on the assertion. This
-  method raises a ValueError exception if the input string is not a valid proxy
-  id.
-
-  Args:
-    s: the string to be checked.
-  """
-  if s != None and not is_valid_proxy_for_id(s):
-    raise ValueError(s + ' is not a valid proxy for id.')
-
-class StringEnum(object):
-  """Enum like class that is configured with a list of values.
-
-  This class effectively implements an enum for Elements, except for that
-  the actual values of the enums will be the string values.
-  """
-
-  def __init__(self, *values):
-    for name in values:
-      setattr(self, name, name)
diff --git a/wave/src/main/java/python/api/util_test.py b/wave/src/main/java/python/api/util_test.py
deleted file mode 100644
index 4682821..0000000
--- a/wave/src/main/java/python/api/util_test.py
+++ /dev/null
@@ -1,187 +0,0 @@
-#!/usr/bin/python2.4
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Unit tests for the util module."""
-
-
-__author__ = 'davidbyttow@google.com (David Byttow)'
-
-
-import unittest
-import urllib
-
-import ops
-import util
-
-
-class TestUtils(unittest.TestCase):
-  """Tests utility functions."""
-
-  def testIsIterable(self):
-    self.assertTrue(util.is_iterable([]))
-    self.assertTrue(util.is_iterable({}))
-    self.assertTrue(util.is_iterable(set()))
-    self.assertTrue(util.is_iterable(()))
-    self.assertFalse(util.is_iterable(42))
-    self.assertFalse(util.is_iterable('list?'))
-    self.assertFalse(util.is_iterable(object))
-
-  def testIsDict(self):
-    self.assertFalse(util.is_dict([]))
-    self.assertTrue(util.is_dict({}))
-    self.assertFalse(util.is_dict(set()))
-    self.assertFalse(util.is_dict(()))
-    self.assertFalse(util.is_dict(42))
-    self.assertFalse(util.is_dict('dict?'))
-    self.assertFalse(util.is_dict(object))
-
-  def testIsUserDefinedNewStyleClass(self):
-    class OldClass:
-      pass
-
-    class NewClass(object):
-      pass
-
-    self.assertFalse(util.is_user_defined_new_style_class(OldClass()))
-    self.assertTrue(util.is_user_defined_new_style_class(NewClass()))
-    self.assertFalse(util.is_user_defined_new_style_class({}))
-    self.assertFalse(util.is_user_defined_new_style_class(()))
-    self.assertFalse(util.is_user_defined_new_style_class(42))
-    self.assertFalse(util.is_user_defined_new_style_class('instance?'))
-
-  def testLowerCamelCase(self):
-    self.assertEquals('foo', util.lower_camel_case('foo'))
-    self.assertEquals('fooBar', util.lower_camel_case('foo_bar'))
-    self.assertEquals('fooBar', util.lower_camel_case('fooBar'))
-    self.assertEquals('blipId', util.lower_camel_case('blip_id'))
-    self.assertEquals('fooBar', util.lower_camel_case('foo__bar'))
-    self.assertEquals('fooBarBaz', util.lower_camel_case('foo_bar_baz'))
-    self.assertEquals('f', util.lower_camel_case('f'))
-    self.assertEquals('f', util.lower_camel_case('f_'))
-    self.assertEquals('', util.lower_camel_case(''))
-    self.assertEquals('', util.lower_camel_case('_'))
-    self.assertEquals('aBCDEF', util.lower_camel_case('_a_b_c_d_e_f_'))
-
-  def assertListsEqual(self, a, b):
-    self.assertEquals(len(a), len(b))
-    for i in range(len(a)):
-      self.assertEquals(a[i], b[i])
-
-  def assertDictsEqual(self, a, b):
-    self.assertEquals(len(a.keys()), len(b.keys()))
-    for k, v in a.iteritems():
-      self.assertEquals(v, b[k])
-
-  def assertNotRaises(self, exception, function, *args):
-    try:
-      function(*args)
-    except ValueError:
-      fail()
-
-  def testSerializeList(self):
-    data = [1, 2, 3]
-    output = util.serialize(data)
-    self.assertListsEqual(data, output)
-
-  def testSerializeDict(self):
-    data = {'key': 'value', 'under_score': 'value2'}
-    expected = {'key': 'value', 'underScore': 'value2'}
-    output = util.serialize(data)
-    self.assertDictsEqual(expected, output)
-
-  def testNonNoneDict(self):
-    a = {'a': 1, 'b': 1}
-    self.assertDictsEqual(a, util.non_none_dict(a))
-    b = a.copy()
-    b['c'] = None
-    self.assertDictsEqual(a, util.non_none_dict(b))
-
-  def testForceUnicode(self):
-    self.assertEquals(u"aaa", util.force_unicode("aaa"))
-    self.assertEquals(u"12", util.force_unicode(12))
-    self.assertEquals(u"\u0430\u0431\u0432",
-                      util.force_unicode("\xd0\xb0\xd0\xb1\xd0\xb2"))
-    self.assertEquals(u'\u30e6\u30cb\u30b3\u30fc\u30c9',
-                      util.force_unicode(u'\u30e6\u30cb\u30b3\u30fc\u30c9'))
-
-  def testSerializeAttributes(self):
-
-    class Data(object):
-      def __init__(self):
-        self.public = 1
-        self._protected = 2
-        self.__private = 3
-
-      def Func(self):
-        pass
-
-    data = Data()
-    output = util.serialize(data)
-    # Functions and non-public fields should not be serialized.
-    self.assertEquals(1, len(output.keys()))
-    self.assertEquals(data.public, output['public'])
-
-  def testStringEnum(self):
-    util.StringEnum()
-    single = util.StringEnum('foo')
-    self.assertEquals('foo', single.foo)
-    multi = util.StringEnum('foo', 'bar')
-    self.assertEquals('foo', multi.foo)
-    self.assertEquals('bar', multi.bar)
-
-  def testParseMarkup(self):
-    self.assertEquals('foo', util.parse_markup('foo'))
-    self.assertEquals('foo bar', util.parse_markup('foo <b>bar</b>'))
-    self.assertEquals('foo\nbar', util.parse_markup('foo<br>bar'))
-    self.assertEquals('foo\nbar', util.parse_markup('foo<p indent="3">bar'))
-
-  def testIsValidProxyForId(self):
-    self.assertTrue(util.is_valid_proxy_for_id(''))
-    self.assertTrue(util.is_valid_proxy_for_id('proxyid'))
-    self.assertTrue(util.is_valid_proxy_for_id('proxy-id1+gmail.com'))
-    self.assertTrue(util.is_valid_proxy_for_id('proxy-id1_at_gmail.com'))
-    self.assertTrue(util.is_valid_proxy_for_id('proxy-id%201_at_gmail.com'))
-    self.assertTrue(util.is_valid_proxy_for_id(urllib.quote('proxyid@bar.com')))
-
-    self.assertFalse(util.is_valid_proxy_for_id('proxy id1'))
-    self.assertFalse(util.is_valid_proxy_for_id(u'proxy\u0000id1'))
-    self.assertFalse(util.is_valid_proxy_for_id(u'proxy\u0009id1'))
-    self.assertFalse(util.is_valid_proxy_for_id(u'proxy\u001Fid1'))
-    self.assertFalse(util.is_valid_proxy_for_id('proxy@id'))
-    self.assertFalse(util.is_valid_proxy_for_id('proxy,id'))
-    self.assertFalse(util.is_valid_proxy_for_id('proxy:id'))
-    self.assertFalse(util.is_valid_proxy_for_id('proxy<id'))
-    self.assertFalse(util.is_valid_proxy_for_id('proxy>id'))
-    self.assertFalse(util.is_valid_proxy_for_id(u'proxy\u007Fid'))
-
-  def testCheckIsValidProxyForId(self):
-    self.assertRaises(ValueError, util.check_is_valid_proxy_for_id,
-                      'foo@bar.com')
-    self.assertNotRaises(ValueError, util.check_is_valid_proxy_for_id,
-                         None)
-    self.assertNotRaises(ValueError, util.check_is_valid_proxy_for_id,
-                         '')
-    self.assertNotRaises(ValueError, util.check_is_valid_proxy_for_id,
-                         'foo+bar.com')
-    self.assertNotRaises(ValueError, util.check_is_valid_proxy_for_id,
-                         urllib.quote('foo@bar.com'))
-    self.assertNotRaises(ValueError, util.check_is_valid_proxy_for_id, None)
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/wave/src/main/java/python/api/wavelet.py b/wave/src/main/java/python/api/wavelet.py
deleted file mode 100644
index c3352e4..0000000
--- a/wave/src/main/java/python/api/wavelet.py
+++ /dev/null
@@ -1,481 +0,0 @@
-#!/usr/bin/python2.4
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Defines classes that are needed to model a wavelet."""
-
-import blip
-import errors
-import util
-
-
-class DataDocs(object):
-  """Class modeling a bunch of data documents in pythonic way."""
-
-  def __init__(self, init_docs, wave_id, wavelet_id, operation_queue):
-    self._docs = init_docs
-    self._wave_id = wave_id
-    self._wavelet_id = wavelet_id
-    self._operation_queue = operation_queue
-
-  def __iter__(self):
-    return self._docs.__iter__()
-
-  def __contains__(self, key):
-    return key in self._docs
-
-  def __delitem__(self, key):
-    if not key in self._docs:
-      return
-    self._operation_queue.wavelet_datadoc_set(
-        self._wave_id, self._wavelet_id, key, None)
-    del self._docs[key]
-
-  def __getitem__(self, key):
-    return self._docs[key]
-
-  def __setitem__(self, key, value):
-    self._operation_queue.wavelet_datadoc_set(
-        self._wave_id, self._wavelet_id, key, value)
-    if value is None and key in self._docs:
-      del self._docs[key]
-    else:
-      self._docs[key] = value
-
-  def __len__(self):
-    return len(self._docs)
-
-  def keys(self):
-    return self._docs.keys()
-
-  def serialize(self):
-    """Returns a dictionary of the data documents."""
-    return self._docs
-
-
-class Participants(object):
-  """Class modelling a set of participants in pythonic way."""
-
-  #: Designates full access (read/write) role.
-  ROLE_FULL = "FULL"
-
-  #: Designates read-only role.
-  ROLE_READ_ONLY = "READ_ONLY"
-
-  def __init__(self, participants, roles, wave_id, wavelet_id, operation_queue):
-    self._participants = set(participants)
-    self._roles = roles.copy()
-    self._wave_id = wave_id
-    self._wavelet_id = wavelet_id
-    self._operation_queue = operation_queue
-
-  def __contains__(self, participant):
-    return participant in self._participants
-
-  def __len__(self):
-    return len(self._participants)
-
-  def __iter__(self):
-    return self._participants.__iter__()
-
-  def add(self, participant_id):
-    """Adds a participant by their ID (address)."""
-    self._operation_queue.wavelet_add_participant(
-        self._wave_id, self._wavelet_id, participant_id)
-    self._participants.add(participant_id)
-
-  def get_role(self, participant_id):
-    """Return the role for the given participant_id."""
-    return self._roles.get(participant_id, Participants.ROLE_FULL)
-
-  def set_role(self, participant_id, role):
-    """Sets the role for the given participant_id."""
-    if role != Participants.ROLE_FULL and role != Participants.ROLE_READ_ONLY:
-      raise ValueError(role + ' is not a valid role')
-    self._operation_queue.wavelet_modify_participant_role(
-        self._wave_id, self._wavelet_id, participant_id, role)
-    self._roles[participant_id] = role
-
-  def serialize(self):
-    """Returns a list of the participants."""
-    return list(self._participants)
-
-
-class Tags(object):
-  """Class modelling a list of tags."""
-  def __init__(self, tags, wave_id, wavelet_id, operation_queue):
-    self._tags = list(tags)
-    self._wave_id = wave_id
-    self._wavelet_id = wavelet_id
-    self._operation_queue = operation_queue
-
-  def __getitem__(self, index):
-    return self._tags[index]
-
-  def __len__(self):
-    return len(self._tags)
-
-  def __iter__(self):
-    return self._tags.__iter__()
-
-  def append(self, tag):
-    """Appends a tag if it doesn't already exist."""
-    tag = util.force_unicode(tag)
-    if tag in self._tags:
-      return
-    self._operation_queue.wavelet_modify_tag(
-        self._wave_id, self._wavelet_id, tag)
-    self._tags.append(tag)
-
-  def remove(self, tag):
-    """Removes a tag if it exists."""
-    tag = util.force_unicode(tag)
-    if not tag in self._tags:
-      return
-    self._operation_queue.wavelet_modify_tag(
-        self._wave_id, self._wavelet_id, tag, modify_how='remove')
-    self._tags.remove(tag)
-
-  def serialize(self):
-    """Returns a list of tags."""
-    return list(self._tags)
-
-
-class BlipThread(object):
-  """ Models a group of blips in a wave."""
-
-  def __init__(self, id, location, blip_ids, all_blips, operation_queue):
-    self._id = id
-    self._location = location
-    self._blip_ids = blip_ids
-    self._all_blips = all_blips
-    self._operation_queue = operation_queue
-
-  @property
-  def id(self):
-    """Returns this thread's id."""
-    return self._id
-
-  @property
-  def location(self):
-    """Returns this thread's location."""
-    return self._location
-
-  @property
-  def blip_ids(self):
-    """Returns the blip IDs in this thread."""
-    return self._blip_ids
-
-  @property
-  def blips(self):
-    """Returns the blips in this thread."""
-    blips = []
-    for blip_id in self._blip_ids:
-      blips.append(self._all_blips[blip_id])
-    return blips
-
-  def _add_internal(self, blip):
-    """Adds a blip to the thread, sends out no operations."""
-    self._blip_ids.append(blip.blip_id)
-    self._all_blips[blip.blip_id] = blip
-
-  def serialize(self):
-    """ Returns serialized properties."""
-    return {'id': self._id,
-            'location': self._location,
-            'blipIds': self._blip_ids}
-
-
-class Wavelet(object):
-  """Models a single wavelet.
-
-  A single wavelet is composed of metadata, participants, and its blips.
-  To guarantee that all blips are available, specify Context.ALL for events.
-  """
-
-  def __init__(self, json, blips, root_thread, operation_queue, raw_deltas=None):
-    """Inits this wavelet with JSON data.
-
-    Args:
-      json: JSON data dictionary from Wave server.
-      blips: a dictionary object that can be used to resolve blips.
-      root_thread: a BlipThread object containing the blips in the root thread.
-      operation_queue: an OperationQueue object to be used to
-        send any generated operations to.
-    """
-    self._operation_queue = operation_queue
-    self._root_thread = root_thread
-    self._wave_id = json.get('waveId')
-    self._wavelet_id = json.get('waveletId')
-    self._creator = json.get('creator')
-    self._raw_deltas = raw_deltas
-    self._raw_snapshot = json.get('rawSnapshot')
-    self._creation_time = json.get('creationTime', 0)
-    self._data_documents = DataDocs(json.get('dataDocuments', {}),
-                                    self._wave_id,
-                                    self._wavelet_id,
-                                    operation_queue)
-    self._last_modified_time = json.get('lastModifiedTime')
-    self._participants = Participants(json.get('participants', []),
-                                      json.get('participantRoles', {}),
-                                      self._wave_id,
-                                      self._wavelet_id,
-                                      operation_queue)
-    self._title = json.get('title', '')
-    self._tags = Tags(json.get('tags', []),
-                      self._wave_id,
-                      self._wavelet_id,
-                      operation_queue)
-
-    self._raw_data = json
-    self._blips = blip.Blips(blips)
-    self._root_blip_id = json.get('rootBlipId')
-    if self._root_blip_id and self._root_blip_id in self._blips:
-      self._root_blip = self._blips[self._root_blip_id]
-    else:
-      self._root_blip = None
-    self._robot_address = None
-
-  @property
-  def wavelet_id(self):
-    """Returns this wavelet's id."""
-    return self._wavelet_id
-
-  @property
-  def wave_id(self):
-    """Returns this wavelet's parent wave id."""
-    return self._wave_id
-
-  @property
-  def creator(self):
-    """Returns the participant id of the creator of this wavelet."""
-    return self._creator
-
-  @property
-  def creation_time(self):
-    """Returns the time that this wavelet was first created in milliseconds."""
-    return self._creation_time
-
-  @property
-  def data_documents(self):
-    """Returns the data documents for this wavelet based on key name."""
-    return self._data_documents
-
-  @property
-  def domain(self):
-    """Return the domain that wavelet belongs to."""
-    p = self._wave_id.find('!')
-    if p == -1:
-      return None
-    else:
-      return self._wave_id[:p]
-
-  @property
-  def last_modified_time(self):
-    """Returns the time that this wavelet was last modified in ms."""
-    return self._last_modified_time
-
-  @property
-  def participants(self):
-    """Returns a set of participants on this wavelet."""
-    return self._participants
-
-  @property
-  def root_thread(self):
-    """Returns the root thread of this wavelet."""
-    return self._root_thread
-
-  @property
-  def tags(self):
-    """Returns a list of tags for this wavelet."""
-    return self._tags
-
-  @property
-  def raw_deltas(self):
-    """If present, return the raw deltas for this wavelet."""
-    return self._raw_deltas
-  
-  @property
-  def raw_snapshot(self):
-    """If present, return the raw snapshot for this wavelet."""
-    return self._raw_snapshot
-
-  def _get_title(self):
-    return self._title
-
-  def _set_title(self, title):
-    title = util.force_unicode(title)
-
-    if title.find('\n') != -1:
-      raise errors.Error('Wavelet title should not contain a newline ' +
-                         'character. Specified: ' + title)
-
-    self._operation_queue.wavelet_set_title(self.wave_id, self.wavelet_id,
-                                            title)
-    self._title = title
-
-    # Adjust the content of the root blip, if it is available in the context.
-    if self._root_blip:
-      content = '\n'
-      splits = self._root_blip._content.split('\n', 2)
-      if len(splits) == 3:
-        content += splits[2]
-      self._root_blip._content = '\n' + title + content
-
-  #: Returns or sets the wavelet's title.
-  title = property(_get_title, _set_title,
-                   doc='Get or set the title of the wavelet.')
-
-  def _get_robot_address(self):
-    return self._robot_address
-
-  def _set_robot_address(self, address):
-    if self._robot_address:
-      raise errors.Error('robot address already set')
-    self._robot_address = address
-
-  robot_address = property(_get_robot_address, _set_robot_address,
-                           doc='Get or set the address of the current robot.')
-
-  @property
-  def root_blip(self):
-    """Returns this wavelet's root blip."""
-    return self._root_blip
-
-  @property
-  def blips(self):
-    """Returns the blips for this wavelet."""
-    return self._blips
-
-  def get_operation_queue(self):
-    """Returns the OperationQueue for this wavelet."""
-    return self._operation_queue
-
-  def serialize(self):
-    """Return a dict of the wavelet properties."""
-    return {'waveId': self._wave_id,
-            'waveletId': self._wavelet_id,
-            'creator': self._creator,
-            'creationTime': self._creation_time,
-            'dataDocuments': self._data_documents.serialize(),
-            'lastModifiedTime': self._last_modified_time,
-            'participants': self._participants.serialize(),
-            'title': self._title,
-            'blips': self._blips.serialize(),
-            'rootBlipId': self._root_blip_id,
-            'rootThread': self._root_thread.serialize()
-           }
-
-  def proxy_for(self, proxy_for_id):
-    """Return a view on this wavelet that will proxy for the specified id.
-
-    A shallow copy of the current wavelet is returned with the proxy_for_id
-    set. Any modifications made to this copy will be done using the
-    proxy_for_id, i.e. the robot+<proxy_for_id>@appspot.com address will
-    be used.
-
-    If the wavelet was retrieved using the Active Robot API, that is
-    by fetch_wavelet, then the address of the robot must be added to the
-    wavelet by setting wavelet.robot_address before calling proxy_for().
-    """
-    util.check_is_valid_proxy_for_id(proxy_for_id)
-    self.add_proxying_participant(proxy_for_id)
-    operation_queue = self.get_operation_queue().proxy_for(proxy_for_id)
-    res = Wavelet(json={},
-                  blips={}, root_thread=None,
-                  operation_queue=operation_queue)
-    res._wave_id = self._wave_id
-    res._wavelet_id = self._wavelet_id
-    res._creator = self._creator
-    res._creation_time = self._creation_time
-    res._data_documents = self._data_documents
-    res._last_modified_time = self._last_modified_time
-    res._participants = self._participants
-    res._title = self._title
-    res._raw_data = self._raw_data
-    res._blips = self._blips
-    res._root_blip = self._root_blip
-    res._root_thread = self._root_thread
-    return res
-
-  def add_proxying_participant(self, id):
-    """Ads a proxying participant to the wave.
-
-    Proxying participants are of the form robot+proxy@domain.com. This
-    convenience method constructs this id and then calls participants.add.
-    """
-    if not self.robot_address:
-      raise errors.Error(
-          'Need a robot address to add a proxying for participant')
-    robotid, domain = self.robot_address.split('@', 1)
-    if '#' in robotid:
-      robotid, version = robotid.split('#')
-    else:
-      version = None
-    if '+' in robotid:
-      newid = robotid.split('+', 1)[0] + '+' + id
-    else:
-      newid = robotid + '+' + id
-    if version:
-      newid += '#' + version
-    newid += '@' + domain
-    self.participants.add(newid)
-
-  def submit_with(self, other_wavelet):
-    """Submit this wavelet when the passed other wavelet is submited.
-
-    wavelets constructed outside of the event callback need to
-    be either explicitly submited using robot.submit(wavelet) or be
-    associated with a different wavelet that will be submited or
-    is part of the event callback.
-    """
-    other_wavelet._operation_queue.copy_operations(self._operation_queue)
-    self._operation_queue = other_wavelet._operation_queue
-
-  def reply(self, initial_content=None):
-    """Replies to the conversation in this wavelet.
-
-    Args:
-      initial_content: If set, start with this (string) content.
-
-    Returns:
-      A transient version of the blip that contains the reply.
-    """
-    if not initial_content:
-      initial_content = u'\n'
-    initial_content = util.force_unicode(initial_content)
-    blip_data = self._operation_queue.wavelet_append_blip(
-       self.wave_id, self.wavelet_id, initial_content)
-
-    instance = blip.Blip(blip_data, self._blips, self._operation_queue)
-    self._blips._add(instance)
-    self.root_blip.child_blip_ids.append(instance.blip_id)
-    return instance
-
-  def delete(self, todelete):
-    """Remove a blip from this wavelet.
-
-    Args:
-      todelete: either a blip or a blip id to be removed.
-    """
-    if isinstance(todelete, blip.Blip):
-      blip_id = todelete.blip_id
-    else:
-      blip_id = todelete
-    self._operation_queue.blip_delete(self.wave_id, self.wavelet_id, blip_id)
-    self._blips._remove_with_id(blip_id)
diff --git a/wave/src/main/java/python/api/wavelet_test.py b/wave/src/main/java/python/api/wavelet_test.py
deleted file mode 100644
index a238eb7..0000000
--- a/wave/src/main/java/python/api/wavelet_test.py
+++ /dev/null
@@ -1,199 +0,0 @@
-#!/usr/bin/python2.4
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Unit tests for the wavelet module."""
-
-
-import unittest
-
-import blip
-import element
-import ops
-import wavelet
-
-import simplejson
-
-ROBOT_NAME = 'robot@appspot.com'
-
-TEST_WAVELET_DATA = {
-    'creator': ROBOT_NAME,
-    'creationTime': 100,
-    'lastModifiedTime': 101,
-    'participants': [ROBOT_NAME],
-    'participantsRoles': {ROBOT_NAME: wavelet.Participants.ROLE_FULL},
-    'rootBlipId': 'blip-1',
-    'title': 'Title',
-    'waveId': 'test.com!w+g3h3im',
-    'waveletId': 'test.com!root+conv',
-    'tags': ['tag1', 'tag2'],
-    'rootThread': {
-        'id': '',
-        'location': -1,
-        'blipIds': ['blip-1']
-    }
-}
-
-TEST_BLIP_DATA = {
-    'blipId': TEST_WAVELET_DATA['rootBlipId'],
-    'childBlipIds': [],
-    'content': '\ntesting',
-    'contributors': [TEST_WAVELET_DATA['creator'], 'robot@google.com'],
-    'creator': TEST_WAVELET_DATA['creator'],
-    'lastModifiedTime': TEST_WAVELET_DATA['lastModifiedTime'],
-    'parentBlipId': None,
-    'waveId': TEST_WAVELET_DATA['waveId'],
-    'elements': {},
-    'waveletId': TEST_WAVELET_DATA['waveletId'],
-    'replyThreadIds': [],
-    'threadId': ''
-}
-
-
-class TestWavelet(unittest.TestCase):
-  """Tests the wavelet class."""
-
-  def setUp(self):
-    self.operation_queue = ops.OperationQueue()
-    self.all_blips = {}
-    self.blip = blip.Blip(TEST_BLIP_DATA,
-                          self.all_blips,
-                          self.operation_queue)
-    self.all_blips[self.blip.blip_id] = self.blip
-    root_thread_data = TEST_WAVELET_DATA.get('rootThread')
-    root_thread = wavelet.BlipThread('',
-                                     root_thread_data.get('location'),
-                                     root_thread_data.get('blipIds', []),
-                                     self.all_blips,
-                                     self.operation_queue)
- 
-    self.wavelet = wavelet.Wavelet(TEST_WAVELET_DATA,
-                                   self.all_blips,
-                                   root_thread,
-                                   self.operation_queue)
-    self.wavelet.robot_address = ROBOT_NAME
-
-  def testWaveletProperties(self):
-    w = self.wavelet
-    self.assertEquals(TEST_WAVELET_DATA['creator'], w.creator)
-    self.assertEquals(TEST_WAVELET_DATA['creationTime'], w.creation_time)
-    self.assertEquals(TEST_WAVELET_DATA['lastModifiedTime'],
-                      w.last_modified_time)
-    self.assertEquals(len(TEST_WAVELET_DATA['participants']),
-                      len(w.participants))
-    self.assertTrue(TEST_WAVELET_DATA['participants'][0] in w.participants)
-    self.assertEquals(TEST_WAVELET_DATA['rootBlipId'], w.root_blip.blip_id)
-    self.assertEquals(TEST_WAVELET_DATA['title'], w.title)
-    self.assertEquals(TEST_WAVELET_DATA['waveId'], w.wave_id)
-    self.assertEquals(TEST_WAVELET_DATA['waveletId'], w.wavelet_id)
-    self.assertEquals(TEST_WAVELET_DATA['rootThread']['id'], w.root_thread.id)
-    self.assertEquals(TEST_WAVELET_DATA['rootThread']['location'],
-                      w.root_thread.location)
-    self.assertEquals(len(TEST_WAVELET_DATA['rootThread']['blipIds']),
-                      len(w.root_thread.blips))
-    self.assertEquals('test.com', w.domain)
-
-  def testWaveletMethods(self):
-    w = self.wavelet
-    reply = w.reply()
-    self.assertEquals(2, len(w.blips))
-    w.delete(reply)
-    self.assertEquals(1, len(w.blips))
-    self.assertEquals(0, len(w.data_documents))
-    self.wavelet.data_documents['key'] = 'value'
-    self.assert_('key' in w.data_documents)
-    self.assertEquals(1, len(w.data_documents))
-    for key in w.data_documents:
-      self.assertEquals(key, 'key')
-    self.assertEquals(1, len(w.data_documents.keys()))
-    self.wavelet.data_documents['key'] = None
-    self.assertEquals(0, len(w.data_documents))
-    num_participants = len(w.participants)
-    w.proxy_for('proxy').reply()
-    self.assertEquals(2, len(w.blips))
-    # check that the new proxy for participant was added
-    self.assertEquals(num_participants + 1, len(w.participants))
-    w._robot_address = ROBOT_NAME.replace('@', '+proxy@')
-    w.proxy_for('proxy').reply()
-    self.assertEquals(num_participants + 1, len(w.participants))
-    self.assertEquals(3, len(w.blips))
-
-  def testSetTitle(self):
-    self.blip._content = '\nOld title\n\nContent'
-    self.wavelet.title = 'New title \xd0\xb0\xd0\xb1\xd0\xb2'
-    self.assertEquals(1, len(self.operation_queue))
-    self.assertEquals('wavelet.setTitle',
-                      self.operation_queue.serialize()[1]['method'])
-    self.assertEquals(u'\nNew title \u0430\u0431\u0432\n\nContent',
-                      self.blip._content)
-
-  def testSetTitleAdjustRootBlipWithOneLineProperly(self):
-    self.blip._content = '\nOld title'
-    self.wavelet.title = 'New title'
-    self.assertEquals(1, len(self.operation_queue))
-    self.assertEquals('wavelet.setTitle',
-                      self.operation_queue.serialize()[1]['method'])
-    self.assertEquals('\nNew title\n', self.blip._content)
-
-  def testSetTitleAdjustEmptyRootBlipProperly(self):
-    self.blip._content = '\n'
-    self.wavelet.title = 'New title'
-    self.assertEquals(1, len(self.operation_queue))
-    self.assertEquals('wavelet.setTitle',
-                      self.operation_queue.serialize()[1]['method'])
-    self.assertEquals('\nNew title\n', self.blip._content)
-
-  def testTags(self):
-    w = self.wavelet
-    self.assertEquals(2, len(w.tags))
-    w.tags.append('tag3')
-    self.assertEquals(3, len(w.tags))
-    w.tags.append('tag3')
-    self.assertEquals(3, len(w.tags))
-    w.tags.remove('tag1')
-    self.assertEquals(2, len(w.tags))
-    self.assertEquals('tag2', w.tags[0])
-
-  def testParticipantRoles(self):
-    w = self.wavelet
-    self.assertEquals(wavelet.Participants.ROLE_FULL,
-                      w.participants.get_role(ROBOT_NAME))
-    w.participants.set_role(ROBOT_NAME, wavelet.Participants.ROLE_READ_ONLY)
-    self.assertEquals(wavelet.Participants.ROLE_READ_ONLY,
-                      w.participants.get_role(ROBOT_NAME))
-
-  def testSerialize(self):
-    self.blip.append(element.Gadget('http://test.com', {'a': 3}))
-    self.wavelet.title = 'A wavelet title'
-    self.blip.append(element.Image(url='http://www.google.com/logos/clickortreat1.gif',
-                              width=320, height=118))
-    self.blip.append(element.Attachment(caption='fake', data='fake data'))
-    self.blip.append(element.Line(line_type='li', indent='2'))
-    self.blip.append('bulleted!')
-    self.blip.append(element.Installer(
-        'http://wave-skynet.appspot.com/public/extensions/areyouin/manifest.xml'))
-    self.wavelet.proxy_for('proxy').reply().append('hi from douwe')
-    inlineBlip = self.blip.insert_inline_blip(5)
-    inlineBlip.append('hello again!')
-
-    serialized = self.wavelet.serialize()
-    serialized = simplejson.dumps(serialized)
-    self.assertTrue(serialized.find('test.com') > 0)
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/wave/src/main/java/python/api/waveservice.py b/wave/src/main/java/python/api/waveservice.py
deleted file mode 100644
index 444a26b..0000000
--- a/wave/src/main/java/python/api/waveservice.py
+++ /dev/null
@@ -1,468 +0,0 @@
-#!/usr/bin/python2.4
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Base class to use OAuth to talk to the wave service."""
-
-import httplib
-import logging
-import urllib
-import urlparse
-
-import oauth
-import simplejson
-
-import ops
-import blip
-import errors
-import events
-import search
-import util
-import wavelet
-
-
-class WaveService(object):
-  # Google OAuth URLs
-  REQUEST_TOKEN_URL = 'https://www.google.com/accounts/OAuthGetRequestToken'
-  ACCESS_TOKEN_URL = 'https://www.google.com/accounts/OAuthGetAccessToken'
-  AUTHORIZATION_URL = 'https://www.google.com/accounts/OAuthAuthorizeToken'
-
-  # Wave OAuth URLS
-  SCOPE = 'http://wave.googleusercontent.com/api/rpc'
-  SIGNATURE_METHOD = oauth.OAuthSignatureMethod_HMAC_SHA1()
-
-  # Wave RPC URLs
-  RPC_URL = 'https://www-opensocial.googleusercontent.com/api/rpc'
-  SANDBOX_RPC_URL = (
-      'https://www-opensocial-sandbox.googleusercontent.com/api/rpc')
-
-  def __init__(self, use_sandbox=False, server_rpc_base=None,
-               consumer_key='anonymous', consumer_secret='anonymous',
-               http_post=None):
-    """Initializes a service that can perform the various OAuth steps.
-
-    Args:
-      use_sandbox: A boolean indicating whether to use Wave Sandbox URLs
-      server_rpc_base: optional explicit url to use for rpc,
-          overriding use_sandbox.
-      consumer_key: A string for the consumer key, defaults to 'anonymous'
-      consumer_secret: A string for the consumer secret, defaults to 'anonymous'
-      http_post: handler to call to execute a http post.
-    """
-    self._consumer = oauth.OAuthConsumer(consumer_key, consumer_secret)
-    logging.info('server_rpc_base: %s', server_rpc_base)
-    if server_rpc_base:
-      self._server_rpc_base = server_rpc_base
-    elif use_sandbox:
-      self._server_rpc_base = WaveService.SANDBOX_RPC_URL
-    else:
-      self._server_rpc_base = WaveService.RPC_URL
-    logging.info('server:' + self._server_rpc_base)
-
-    self._http_post = self.http_post
-    self._connection = httplib.HTTPSConnection('www.google.com')
-    self._access_token = None
-
-  def _make_token(self, token):
-    """If passed an oauth token, return that. If passed a string, convert."""
-    if isinstance(token, basestring):
-      return oauth.OAuthToken.from_string(token)
-    else:
-      return token
-
-  def set_http_post(self, http_post):
-    """Set the http_post handler to use when posting."""
-    self._http_post = http_post
-
-  def get_token_from_request(self, oauth_request):
-    """Convenience function to returning the token from a request.
-
-    Args:
-      oauth_request: An OAuthRequest object
-    Returns:
-      An OAuthToken object
-    """
-    # Send request to the request token URL
-    self._connection.request(oauth_request.http_method, oauth_request.to_url())
-
-    # Extract token from response
-    response = self._connection.getresponse().read()
-    self._request_token = oauth.OAuthToken.from_string(response)
-    return self._request_token
-
-  def fetch_request_token(self, callback=None):
-    """Fetches the request token to start the oauth dance.
-
-    Args:
-      callback: the URL to where the service will redirect to after
-          access is granted.
-    Returns:
-      An OAuthToken object
-    """
-    # Create and sign OAuth request
-    params = {'scope': WaveService.SCOPE}
-    if callback:
-      params['oauth_callback'] = callback
-    oauth_request = oauth.OAuthRequest.from_consumer_and_token(self._consumer,
-        http_url=WaveService.REQUEST_TOKEN_URL, parameters=params)
-    oauth_request.sign_request(WaveService.SIGNATURE_METHOD, self._consumer, None)
-
-    return self.get_token_from_request(oauth_request)
-
-  def generate_authorization_url(self, request_token=None):
-    """Generates the authorization URL (Step 2).
-
-    Args:
-      request_token: An OAuthToken object
-    Returns:
-      An authorization URL
-    """
-    # Create Authorization URL request
-    if request_token is None:
-      request_token = self._request_token
-    oauth_request = oauth.OAuthRequest.from_token_and_callback(
-        token=request_token, http_url=WaveService.AUTHORIZATION_URL)
-
-    # Send request
-    self._connection.request(oauth_request.http_method, oauth_request.to_url())
-
-    # Extract location from the response
-    response = self._connection.getresponse()
-    return response.getheader('location')
-
-  def upgrade_to_access_token(self, request_token, verifier=None):
-    """Upgrades the request_token to an access token (Step 3).
-
-    Args:
-      request_token: An OAuthToken object or string
-      verifier: A verifier string
-    Returns:
-      An OAuthToken object
-    """
-    request_token = self._make_token(request_token)
-    params = {}
-    if verifier:
-      params['oauth_verifier'] = verifier
-    oauth_request = oauth.OAuthRequest.from_consumer_and_token(self._consumer,
-        token=request_token, http_url=WaveService.ACCESS_TOKEN_URL,
-        parameters=params)
-    oauth_request.sign_request(WaveService.SIGNATURE_METHOD, self._consumer,
-                               request_token)
-
-    self._access_token = self.get_token_from_request(oauth_request)
-    return self._access_token
-
-  def set_access_token(self, access_token):
-    self._access_token = self._make_token(access_token)
-
-  def http_post(self, url, data, headers):
-    """Execute an http post.
-
-    You can provide a different method to use in the constructor. This
-    is mostly useful when running on app engine and you want to set
-    the time out to something different than the default 5 seconds.
-
-    Args:
-        url: to post to
-        body: post body
-        headers: extra headers to pass along
-    Returns:
-        response_code, returned_page
-    """
-    import urllib2
-    req = urllib2.Request(url,
-                          data=data,
-                          headers=headers)
-    try:
-      f = urllib2.urlopen(req)
-      return f.code, f.read()
-    except urllib2.HTTPError, e:
-      return e.code, e.read()
-
-  def make_rpc(self, operations):
-    """Make an rpc call, submitting the specified operations."""
-
-    rpc_host = urlparse.urlparse(self._server_rpc_base).netloc
-
-    # We either expect an operationqueue, a single op or a list
-    # of ops:
-    if (not isinstance(operations, ops.OperationQueue)):
-      if not isinstance(operations, list):
-        operations = [operations]
-      queue = ops.OperationQueue()
-      queue.copy_operations(operations)
-    else:
-      queue = operations
-
-
-    data = simplejson.dumps(queue.serialize(method_prefix='wave'))
-
-    oauth_request = oauth.OAuthRequest.from_consumer_and_token(self._consumer,
-         token=self._access_token, http_method='POST',
-         http_url=self._server_rpc_base)
-    oauth_request.sign_request(WaveService.SIGNATURE_METHOD,
-         self._consumer, self._access_token)
-
-    logging.info('Active URL: %s'  % self._server_rpc_base)
-    logging.info('Active Outgoing: %s' % data)
-    headers = {'Content-Type': 'application/json'}
-    headers.update(oauth_request.to_header());
-    status, content = self._http_post(
-         url=self._server_rpc_base,
-         data=data,
-         headers=headers)
-
-    if status != 200:
-      raise errors.RpcError('code: %s\n%s' % (status, content))
-    return simplejson.loads(content)
-
-  def _first_rpc_result(self, result):
-    """result is returned from make_rpc. Get the first data record
-    or throw an exception if it was an error. Ignore responses to
-    NOTIFY_OP_ID."""
-    result = [record for record in result if record['id'] != ops.NOTIFY_OP_ID]
-    if not result:
-      raise errors.RpcError('No results found.')
-    result = result[0]
-    error = result.get('error')
-    if error:
-      raise errors.RpcError(str(error['code'])
-          + ': ' + error['message'])
-    data = result.get('data')
-    if data is not None:
-      return data
-    raise errors.Error('RPC Error: No data record.')
-
-  def _wavelet_from_json(self, json, pending_ops):
-    """Construct a wavelet from the passed json.
-
-    The json should either contain a wavelet and a blips record that
-    define those respective object. The returned wavelet
-    will be constructed using the passed pending_ops
-    OperationQueue.
-    Alternatively the json can be the result of a previous
-    wavelet.serialize() call. In that case the blips will
-    be contaned in the wavelet record.
-    """
-    if isinstance(json, basestring):
-      json = simplejson.loads(json)
-
-    # Create blips dict so we can pass into BlipThread objects
-    blips = {}
-
-    # Setup threads first, as the Blips and Wavelet need to know about them
-    threads = {}
-    # In case of blind_wavelet or new_wave, we may not have threads indo
-    threads_data = json.get('threads', {})
-    # Create remaining thread objects
-    for thread_id, raw_thread_data in threads_data.items():
-      threads[thread_id] = wavelet.BlipThread(thread_id,
-          raw_thread_data.get('location'), raw_thread_data.get('blipIds', []),
-          blips, pending_ops)
-
-    # If being called from blind_wavelet, wavelet is top level info
-    if 'wavelet' in json:
-      raw_wavelet_data = json['wavelet']
-    elif 'waveletData' in json:
-      raw_wavelet_data = json['waveletData']
-    else:
-      raw_wavelet_data = json
-    root_thread_data = raw_wavelet_data.get('rootThread')
-    root_thread = wavelet.BlipThread('',
-                             root_thread_data.get('location'),
-                             root_thread_data.get('blipIds', []),
-                             blips,
-                             pending_ops)
-    threads[''] = root_thread
-
-    # Setup the blips, pass  in reply threads
-    for blip_id, raw_blip_data in json['blips'].items():
-      reply_threads = [threads[id] for id in raw_blip_data.get('replyThreadIds',
-                                                               [])]
-      thread = threads.get(raw_blip_data.get('threadId'))
-      blips[blip_id] = blip.Blip(raw_blip_data, blips, pending_ops,
-                                 thread=thread, reply_threads=reply_threads)
-
-    result = wavelet.Wavelet(raw_wavelet_data, blips, root_thread, pending_ops,
-                             raw_deltas=json.get('rawDeltas'))
-
-    robot_address = json.get('robotAddress')
-    if robot_address:
-      result.robot_address = robot_address
-
-    return result
-
-  def search(self, query, index=None, num_results=None):
-    """Execute a search request.
-
-    Args:
-      query: what to search for, for example [in:inbox]
-      index: index of the first result to return
-      num_results: how many results to return
-    """
-    operation_queue = ops.OperationQueue()
-    operation_queue.robot_search(query, index, num_results)
-    result = self._first_rpc_result(self.make_rpc(operation_queue))
-    return search.Results(result)
-
-  def new_wave(self, domain, participants=None, message='', proxy_for_id=None,
-               submit=False):
-    """Create a new wave with the initial participants on it.
-
-    A new wave is returned with its own operation queue. It the
-    responsibility of the caller to make sure this wave gets
-    submitted to the server, either by calling robot.submit() or
-    by calling .submit_with() on the returned wave.
-
-    Args:
-      domain: the domain to create the wavelet on. This should
-          in general correspond to the domain of the incoming
-          wavelet. (wavelet.domain). Exceptions are situations
-          where the robot is calling new_wave outside of an
-          event or when the server is handling multiple domains.
-
-      participants: initial participants on the wave. The robot
-          as the creator of the wave is always added.
-
-      message: a string that will be passed back to the robot
-          when the WAVELET_CREATOR event is fired. This is a
-          lightweight way to pass around state.
-
-      submit: if true, use the active gateway to make a round
-          trip to the server. This will return immediately an
-          actual waveid/waveletid and blipId for the root blip.
-
-    """
-    util.check_is_valid_proxy_for_id(proxy_for_id)
-    operation_queue = ops.OperationQueue(proxy_for_id)
-    if not isinstance(message, basestring):
-      message = simplejson.dumps(message)
-
-    # Create temporary wavelet data
-    blip_data, wavelet_data = operation_queue.robot_create_wavelet(
-        domain=domain,
-        participants=participants,
-        message=message)
-
-    # Create temporary blips dictionary
-    blips = {}
-    root_blip = blip.Blip(blip_data, blips, operation_queue)
-    blips[root_blip.blip_id] = root_blip
-
-    if submit:
-      # Submit operation to server and return actual wave/blip IDs
-      temp_wavelet = wavelet.Wavelet(wavelet_data,
-                                blips=blips,
-                                root_thread=None,
-                                operation_queue=operation_queue)
-      result = self._first_rpc_result(self.submit(temp_wavelet))
-      if isinstance(result, list):
-        result = result[0]
-      if 'blipId' in result:
-        blip_data['blipId'] = result['blipId']
-        wavelet_data['rootBlipId'] = result['blipId']
-      for field in 'waveId', 'waveletId':
-        if field in result:
-          wavelet_data[field] = result[field]
-          blip_data[field] = result[field]
-      blips = {}
-      root_blip = blip.Blip(blip_data, blips, operation_queue)
-      blips[root_blip.blip_id] = root_blip
-
-    root_thread = wavelet.BlipThread('',
-                             -1,
-                             [root_blip.blip_id],
-                             blips,
-                             operation_queue)
-    new_wavelet = wavelet.Wavelet(wavelet_data,
-                              blips=blips,
-                              root_thread=root_thread,
-                              operation_queue=operation_queue)
-    return new_wavelet
-
-  def fetch_wavelet(self, wave_id, wavelet_id=None, proxy_for_id=None,
-                    raw_deltas_from_version=-1, return_raw_snapshot=False):
-    """Use the REST interface to fetch a wave and return it.
-
-    The returned wavelet contains a snapshot of the state of the
-    wavelet at that point. It can be used to modify the wavelet,
-    but the wavelet might change in between, so treat carefully.
-
-    Also note that the wavelet returned has its own operation
-    queue. It the responsibility of the caller to make sure this
-    wavelet gets submited to the server, either by calling
-    robot.submit() or by calling .submit_with() on the returned
-    wavelet.
-
-    Args:
-      wave_id: the wave id
-      wavelet_id: the wavelet_id
-      proxy_for_id: on whose behalf to execute the operation
-      raw_deltas_from_version: If specified, return a raw dump of the
-        delta history of this wavelet, starting at the given version.
-        This may return only part of the history; use additional
-        requests with higher raw_deltas_from_version parameters to
-        get the rest.
-      return_raw_snapshot: if true, return the raw data for this
-        wavelet.
-    """
-    util.check_is_valid_proxy_for_id(proxy_for_id)
-    if not wavelet_id:
-      domain, id = wave_id.split('!', 1)
-      wavelet_id = domain + '!conv+root'
-    operation_queue = ops.OperationQueue(proxy_for_id)
-    operation_queue.robot_fetch_wave(wave_id, wavelet_id,
-        raw_deltas_from_version, return_raw_snapshot)
-    result = self._first_rpc_result(self.make_rpc(operation_queue))
-    return self._wavelet_from_json(result, ops.OperationQueue(proxy_for_id))
-
-  def blind_wavelet(self, json, proxy_for_id=None):
-    """Construct a blind wave from a json string.
-
-    Call this method if you have a snapshot of a wave that you
-    want to operate on outside of an event. Since the wave might
-    have changed since you last saw it, you should take care to
-    submit operations that are as safe as possible.
-
-    Args:
-      json: a json object or string containing at least a key
-        wavelet defining the wavelet and a key blips defining the
-        blips in the view.
-
-      proxy_for_id: the proxying information that will be set on the wavelet's
-        operation queue.
-
-    Returns:
-      A new wavelet with its own operation queue. It the
-      responsibility of the caller to make sure this wavelet gets
-      submited to the server, either by calling robot.submit() or
-      by calling .submit_with() on the returned wavelet.
-    """
-    util.check_is_valid_proxy_for_id(proxy_for_id)
-    return self._wavelet_from_json(json, ops.OperationQueue(proxy_for_id))
-
-  def submit(self, wavelet_to_submit):
-    """Submit the pending operations associated with wavelet_to_submit.
-
-    Typically the wavelet will be the result of fetch_wavelet, blind_wavelet
-    or new_wave.
-    """
-    pending = wavelet_to_submit.get_operation_queue()
-    res = self.make_rpc(pending)
-    pending.clear()
-    return res
diff --git a/wave/src/main/java/python/api/waveservice_test.py b/wave/src/main/java/python/api/waveservice_test.py
deleted file mode 100644
index da433da..0000000
--- a/wave/src/main/java/python/api/waveservice_test.py
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/usr/bin/python2.4
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-"""Unit tests for the wavelet module."""
-
-
-import unittest
-
-import blip
-import element
-import ops
-import wavelet
-import waveservice
-import simplejson
-import testdata
-
-
-class TestWavelet(unittest.TestCase):
-  """Tests the wavelet class."""
-
-  def setUp(self):
-    self.waveservice = waveservice.WaveService()
-
-  def testWaveletProperties(self):
-    operation_queue = ops.OperationQueue()
-    TEST_DATA = simplejson.loads(testdata.json_string)
-    w = self.waveservice._wavelet_from_json(TEST_DATA,
-                                            operation_queue)
-    self.assertEquals(TEST_DATA['wavelet']['waveId'], w.wave_id)
-    self.assertEquals(TEST_DATA['wavelet']['rootThread']['id'],
-                      w.root_thread.id)
-    self.assertEquals(TEST_DATA['wavelet']['rootThread']['location'],
-                      w.root_thread.location)
-    self.assertEquals(len(TEST_DATA['wavelet']['rootThread']['blipIds']),
-                      len(w.root_thread.blips))
-
-    b = w.root_blip
-    self.assertEquals(len(TEST_DATA['blips']['b+IvD7RCuWB']['replyThreadIds']),
-                      len(b.reply_threads))
-
-
-  def testWaveletBlipMethods(self):
-    operation_queue = ops.OperationQueue()
-    TEST_DATA = simplejson.loads(testdata.json_string)
-    w = self.waveservice._wavelet_from_json(TEST_DATA,
-                                            operation_queue)
-    root_blip = w.root_blip
-    blip = root_blip.continue_thread()
-    self.assertEquals(blip.parent_blip_id, root_blip.parent_blip_id)
-    self.assertEquals(8, len(w.blips))
-    self.assertEquals(4, len(w.root_thread.blips))
-
-
-
-if __name__ == '__main__':
-  unittest.main()