Prezi

Present Remotely

Send the link below via email or IM

Copy

Present to your audience

Start remote presentation

  • Invited audience members will follow you as you navigate and present
  • People invited to a presentation do not need a Prezi account
  • This link expires 10 minutes after you close the presentation
  • A maximum of 30 users can follow your presentation
  • Learn more about this feature in the manual

Do you really want to delete this prezi?

Neither you, nor the coeditors you shared it with will be able to recover it again.

DeleteCancel

Make your likes visible on Facebook?

Connect your Facebook account to Prezi and let your likes appear on your timeline.
You can change this under Settings & Account at any time.

No, thanks

Wave Robots API: Behind the Scenes

Robots, Gadgets, Embed
by Pamela Fox on 6 July 2010

Comments (0)

Please log in to add your comment.

Report abuse

Transcript of Wave Robots API: Behind the Scenes

"events": [
{
"type": "WAVELET_SELF_ADDED",
"modifiedBy": "pamela.fox@wavesandbox.com",
"timestamp": 1269400482868,
"properties": {
"blipId": "b+FYYeTpCXJ"
}
}
],
"wavelet": {
"creationTime": 1269400451853,
"lastModifiedTime": 1269400482868,
"version": 14,
"participants": [
"pamela.fox@wavesandbox.com",
"emo-bot@appspot.com"
],
"creator": "pamela.fox@wavesandbox.com",
"rootBlipId": "b+FYYeTpCXJ",
"title": "Dear Diary,",
"waveId": "wavesandbox.com!w+FYYeTpCXI",
"waveletId": "wavesandbox.com!conv+root"
}, {"params": {
"blipId": "b+FYYeTpCXJ",
"waveletId": "wavesandbox.com!conv+root",
"waveId": "wavesandbox.com!w+FYYeTpCXI",
"modifyAction": {
"modifyHow": "REPLACE",
"elements": [
{
"type": "IMAGE",
"properties": {
"url": "http://emo-bot.appspot.com/smile.gif"
}
}
]
},
"modifyQuery": {
"textMatch": ":)",
"maxRes": -1
}
},
"method": "document.modify",
"id": "op2"
} Events Operations Robot Wave Wave Building the Wave Robots API import logging

from waveapi import appengine_robot_runner
from waveapi import element
from waveapi import events
from waveapi import ops
from waveapi import robot

anim_base = 'http://emo-bot.appspot.com/'
anim_ext = '.gif'
emoticons = {
':)' : 'smile',
':(' : 'frown',
'(heart)': 'heart'
}

def ProcessBlip(event, wavelet):
blip = event.blip
for emoticon in emoticons:
r = blip.all(emoticon)
if r:
r.replace(element.Image(anim_base + emoticons[emoticon] + anim_ext))
pass

if __name__ == '__main__':
emobot = robot.Robot('Emo Bot',
image_url='http://emo-bot.appspot.com/public/thumbnail.png',
profile_url='http://emo-bot.appspot.com')
emobot.register_handler(events.BlipSubmitted, ProcessBlip)
emobot.register_handler(events.WaveletSelfAdded, ProcessBlip)
appengine_robot_runner.run(emobot, debug=True) Profiles http://emo-bot.appspot.com/_wave/robot/profile {"profileUrl": "http://emo-bot.appspot.com",
"imageUrl": "https://emo-bot.appspot.com/public/thumbnail.png",
"name": "Emo Bot"} app.yaml application: emo-bot
version: 1
runtime: python

handlers:
- url: /_wave/.*
script: main.py
- url: /public/(.*)
static_files: public/\1
upload: public/(.*) import logging

from waveapi import appengine_robot_runner
from waveapi import element
from waveapi import events
from waveapi import ops
from waveapi import robot

anim_base = 'http://wave-skimmy.appspot.com'
anim_ext = '.gif'
emoticons = {
':)' : 'smile',
':(' : 'frown',
'(heart)': 'heart'
}

def ProcessBlip(event, wavelet):
blip = event.blip
for emoticon in emoticons:
r = blip.all(emoticon)
if r:
r.replace(element.Image(anim_base + emoticons[emoticon] + anim_ext))
pass

if __name__ == '__main__':
emobot = robot.Robot('Emo Bot',
image_url='http://emo-bot.appspot.com/public/thumbnail.png',
profile_url='http://emo-bot.appspot.com/')
emobot.register_handler(events.BlipSubmitted, ProcessBlip)
emobot.register_handler(events.WaveletSelfAdded, ProcessBlip)
appengine_robot_runner.run(emobot, debug=True) main.py
....

class ProfileHandler(webapp.RequestHandler):

def __init__(self, method, contenttype):
self._method = method
self._contenttype = contenttype

def get(self):
self.response.headers['Content-Type'] = self._contenttype
self.response.out.write(self._method())

def create_robot_webapp(robot):
return webapp.WSGIApplication([
('.*/_wave/robot/profile',
lambda: ProfileHandler(
robot.profile_json,
'application/json')),
('.*/_wave/capabilities.xml',
lambda: CapabilitiesHandler(
robot.capabilities_xml,
'application/xml')),
('.*/_wave/robot/jsonrpc',
lambda: RobotEventHandler(robot)),
('.*/_wave/verify_token',
lambda: RobotVerifyTokenHandler(robot)),
])

def run(robot):
app = create_robot_webapp(robot)
run_wsgi_app(app) appengine_robot_runner.py robot.py ...
def profile_json(self):
data = {'name': self.name,
'imageUrl': self.image_url,
'profileUrl': self.profile_url}
return simplejson.dumps(data)
... Capabilities which protocol version?
which events? Incoming JSON Outgoing JSON http://emo-bot.appspot.com/_wave/capabilities.xml <w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0">
<w:version>0xc5d908e</w:version>
<w:protocolversion>0.2</w:protocolversion>
<w:capabilities>
<w:capability name="BLIP_SUBMITTED"/>
<w:capability name="DOCUMENT_CHANGED"/>
<w:capability name="OPERATION_ERROR"/>
</w:capabilities>
</w:robot> application: emo-bot
version: 1
runtime: python

handlers:
- url: /_wave/.*
script: main.py
- url: /public/(.*)
static_files: public/\1
upload: public/(.*) import logging

from waveapi import appengine_robot_runner
from waveapi import element
from waveapi import events
from waveapi import ops
from waveapi import robot

anim_base = 'http://emo-bot.appspot.com'
anim_ext = '.gif'
emoticons = {
':)' : 'smile',
':(' : 'frown',
'(heart)': 'heart'
}

def ProcessBlip(event, wavelet):
blip = event.blip
for emoticon in emoticons:
r = blip.all(emoticon)
if r:
r.replace(element.Image(anim_base + emoticons[emoticon] + anim_ext))
pass

if __name__ == '__main__':
emobot = robot.Robot('Emo Bot',
image_url='http://emo-bot.appspot.com/public/thumbnail.png',
profile_url='http://emo-bot.appspot.com/')
emobot.register_handler(events.BlipSubmitted, ProcessBlip)
emobot.register_handler(events.WaveletSelfAdded, ProcessBlip)
appengine_robot_runner.run(emobot, debug=True) appengine_robot_runner.py robot.py class CapabilitiesHandler(webapp.RequestHandler):

def __init__(self, method, contenttype):
self._method = method
self._contenttype = contenttype

def get(self):
self.response.headers['Content-Type'] = self._contenttype
self.response.out.write(self._method())

def create_robot_webapp(robot):
return webapp.WSGIApplication([
('.*/_wave/robot/profile',
lambda: ProfileHandler(
robot.profile_json,
'application/json')),
('.*/_wave/capabilities.xml',
lambda: CapabilitiesHandler(
robot.capabilities_xml,
'application/xml')),
('.*/_wave/robot/jsonrpc',
lambda: RobotEventHandler(robot)),
('.*/_wave/verify_token',
lambda: RobotVerifyTokenHandler(robot)),
])

def run(robot):
app = create_robot_webapp(robot)
run_wsgi_app(app) app.yaml main.py 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" >/\n' % capability
lines.append(line)
return ('<?xml version="1.0"?>\n'
'<w:robot xmlns:w="http://.../robots/1.0">\n'
'<w:version>%s</w:version>\n'
'<w:protocolversion>%s</w:protocolversion>\n'
'<w:capabilities>\n'
'%s'
'</w:capabilities>\n'
'</w:robot>\n') % (self.capabilities_hash(),
ops.PROTOCOL_VERSION,
'\n'.join(lines)) [
{
"method": "robot.notifyCapabilitiesHash",
"params": {
"capabilitiesHash": "0xc5d908e"
}
}
] cache:
emo-bot.appspot.com
0x10962d0 Outgoing JSON http://emo-bot.appspot.com/_wave/capabilities.xml <w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0">
<w:version>0xc5d908e</w:version>
<w:protocolversion>0.2</w:protocolversion>
<w:capabilities>
<w:capability name="BLIP_SUBMITTED"/>
<w:capability name="DOCUMENT_CHANGED"/>
<w:capability name="OPERATION_ERROR"/>
</w:capabilities>
</w:robot> Problem Solution Auto Generation <w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0">
<w:version>0xc5d908e</w:version>
<w:protocolversion>0.2</w:protocolversion>
<w:capabilities>
<w:capability name="BLIP_SUBMITTED"/>
<w:capability name="DOCUMENT_CHANGED"/>
<w:capability name="OPERATION_ERROR"/>
</w:capabilities>
</w:robot> http://emo-bot.appspot.com/_wave/capabilities.xml Problem Solution def register_handler(self, event_class, handler, context=None, filter=None):
payload = (handler, event_class, context, filter)
self._handlers.append(payload)
self._capability_hash = (self._capability_hash * 13 +
hash(ops.PROTOCOL_VERSION) +
hash(event_class.type) +
hash(context) +
hash(filter)) & 0xfffffff

def process_events(self, json):
parsed = simplejson.loads(json)
pending_ops = ops.OperationQueue()
event_wavelet = self._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())
appengine_robot_runner.py main.py application: emo-bot
version: 1
runtime: python

handlers:
- url: /_wave/.*
script: main.py
- url: /public/(.*)
static_files: public/\1
upload: public/(.*) app.yaml import logging

from waveapi import appengine_robot_runner
from waveapi import element
from waveapi import events
from waveapi import ops
from waveapi import robot

anim_base = 'http://emo-bot.appspot.com'
anim_ext = '.gif'
emoticons = {
':)' : 'smile',
':(' : 'frown',
'(heart)': 'heart'
}

def ProcessBlip(event, wavelet):
blip = event.blip
for emoticon in emoticons:
r = blip.all(emoticon)
if r:
r.replace(element.Image(anim_base + emoticons[emoticon] + anim_ext))
pass

if __name__ == '__main__':
emobot = robot.Robot('Emo Bot',
image_url='http://emo-bot.appspot.com/public/thumbnail.png',
profile_url='http://emo-bot.appspot.com/')
emobot.register_handler(events.BlipSubmitted, ProcessBlip)
emobot.register_handler(events.WaveletSelfAdded, ProcessBlip)
appengine_robot_runner.run(emobot, debug=True) class RobotEventHandler(webapp.RequestHandler):

def __init__(self, robot):
self._robot = robot

def post(self):
json_body = self.request.body
json_response = self._robot.process_events(json_body)
self.response.headers['Content-Type'] = 'application/json; charset=utf-8'
self.response.out.write(json_response.encode('utf-8'))

def create_robot_webapp(robot):
return webapp.WSGIApplication([
('.*/_wave/robot/profile',
lambda: ProfileHandler(
robot.profile_json,
'application/json')),
('.*/_wave/capabilities.xml',
lambda: CapabilitiesHandler(
robot.capabilities_xml,
'application/xml')),
('.*/_wave/robot/jsonrpc',
lambda: RobotEventHandler(robot)),
('.*/_wave/verify_token',
lambda: RobotVerifyTokenHandler(robot)),
])

def run(robot):
app = create_robot_webapp(robot)
run_wsgi_app(app) Auto Generation robot.py Capabilities Hash {"params": {
"blipId": "b+FYYeTpCXJ",
"waveletId": "wavesandbox.com!conv+root",
"waveId": "wavesandbox.com!w+FYYeTpCXI",
"modifyAction": {
"modifyHow": "REPLACE",
"elements": [
{
"type": "IMAGE",
"properties": {
"url": "http://wave-skimmy.appspot.com/smile.gif"
}
}
]
},
"modifyQuery": {
"textMatch": ":)",
"maxRes": -1
}
},
"method": "document.modify",
"id": "op2"
} Outgoing JSON Problem Solution Outgoing JSON {"params": {
"blipId": "b+FYYeTpCXJ",
"waveletId": "wavesandbox.com!conv+root",
"waveId": "wavesandbox.com!w+FYYeTpCXI",
"modifyAction": {
"modifyHow": "REPLACE",
"elements": [
{
"type": "IMAGE",
"properties": {
"url": "http://wave-skimmy.appspot.com/smile.gif"
}
}
]
},
"modifyQuery": {
"textMatch": ":)",
"maxRes": -1
}
},
"method": "document.modify",
"id": "op2"
}
if __name__ == '__main__':
emobot = robot.Robot('Emo Bot',
image_url='http://emo-bot.appspot.com/public/thumbnail.png',
profile_url='http://emo-bot.appspot.com/')
emobot.register_handler(events.BlipSubmitted, ProcessBlip)
emobot.register_handler(events.WaveletSelfAdded, ProcessBlip)
emobot.set_verification_token_info('AOijR2fFR5awOGHmU...', '4203')
appengine_robot_runner.run(emobot, debug=True)
if __name__ == '__main__':
emobot = robot.Robot('Emo Bot',
image_url='http://emo-bot.appspot.com/public/thumbnail.png',
profile_url='http://emo-bot.appspot.com/')
emobot.register_handler(events.BlipSubmitted, ProcessBlip)
emobot.register_handler(events.WaveletSelfAdded, ProcessBlip)
emobot.setup_oauth('TOPSECRETKEY', 'TOPSECRETSECRET')
appengine_robot_runner.run(emobot, debug=True) def make_rpc(self, operations):
data = simplejson.dumps(queue.serialize())

oauth_request = oauth.OAuthRequest.from_consumer_and_token(
self._consumer, http_method='POST', http_url=self._server_rpc_base)
oauth_request.sign_request(WaveService.SIGNATURE_METHOD, self._consumer)

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) class RobotVerifyTokenHandler(webapp.RequestHandler):

def __init__(self, robot):
self._robot = robot

def get(self):
token, st = self._robot.get_verification_token_info()
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):
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)),
])

appengine_robot_runner.py main.py waveservice.py main.py OAuth Handling Active Operations Problem webapp + + + __init__.py
appengine_robot_runner.py
blip.py
element.py
errors.py
events.py
oauth/
ops.py
robot.py
search.py
simplejson/
util.py
wavelet.py
waveservice.py webapp + class CapabilitiesHandler(webapp.RequestHandler)
class RobotEventHandler(webapp.RequestHandler)
class ProfileHandler(webapp.RequestHandler)
class RobotVerifyTokenHandler(webapp.RequestHandler)
def appengine_post(url, data, headers)
def operation_error_handler(event, wavelet)
def create_robot_webapp(robot, debug=False)
def run(robot, debug=False, log_errors=True) Solution from django.conf.urls.defaults import *

urlpatterns = patterns('',
(r'^_wave/*', 'testproject.testbot.wave.OnWaveAnything')
) import logging

from waveapi import django_robot_runner
from waveapi import element
from waveapi import events
from waveapi import ops
from waveapi import robot

anim_base = 'http://emo-bot.appspot.com'
anim_ext = '.gif'
emoticons = {
':)' : 'smile',
':(' : 'frown',
'(heart)': 'heart'
}

def ProcessBlip(event, wavelet):
blip = event.blip
for emoticon in emoticons:
r = blip.all(emoticon)
if r:
r.replace(element.Image(anim_base + emoticons[emoticon] + anim_ext))
pass


def OnWaveAnything(request):
emobot = robot.Robot('Emo Bot',
image_url='http://emo-bot.appspot.com/public/thumbnail.png',
profile_url='http://emo-bot.appspot.com/')
emobot.register_handler(events.BlipSubmitted, ProcessBlip)
emobot.register_handler(events.WaveletSelfAdded, ProcessBlip)
emobot.setup_oauth(credentials.KEY, credentials.SECRET)
return django_robot_runner.handle(request, emobot) import logging
import sys

from django.http import HttpResponseRedirect
from django.http import HttpResponse
from django.shortcuts import render_to_response

import events

def CapabilitiesHandler(request, robot):
return HttpResponse(robot.capabilities_xml(), content_type='text/xml')

def ProfileHandler(request, robot):
response = robot.profile_json()
return HttpResponse(response, content_type='text/plain')

def RobotEventHandler(request, robot):
if request.method == 'POST':
json_body = request.raw_post_data

json_body = unicode(json_body, 'utf8')
json_response = robot.process_events(json_body)

response = (json_response.encode('utf-8'))
return HttpResponse(response, content_type='application/json; charset=utf-8')
else:
return HttpResponse('GET not implemented')


def operation_error_handler(event, wavelet):
if isinstance(event, events.OperationError):
logging.error('Previously operation failed: id=%s, message: %s',
event.operation_id, event.error_message)

def RobotVerifyTokenHandler(request, robot):
token, st = robot.get_verification_token_info()
if request.GET['st'] != st:
response = 'Invalid st value passed'
return
response = token
return HttpResponse(response)

def handle(request, robot):
robot.register_handler(events.OperationError, operation_error_handler)
if request.path.find('_wave/capabilities.xml') > -1:
return CapabilitiesHandler(request, robot)
if request.path.find('_wave/robot/profile') > -1:
return ProfileHandler(request, robot)
if request.path.find('_wave/robot/jsonrpc') > -1:
return RobotEventHandler(request, robot)
if request.path.find('_wave/verify_token') > -1:
return RobotVerifyTokenHandler(request, robot) + urls.py wave.py django_robot_runner.py Non-App Engine Robots Behind the Scenes Google Maps APIs Google Wave APIs Spreadsheets, Gadgets, App Engine, Blogger, Calendar, Picasa,
OpenSocial, Flickr, Amazon, ... JavaScript Python , PHP , JavaScript , Java About Me Wave Robots API v1 Wave Developer Preview June 1, 2009 March 1, 2010 Wave Robots API v2 Wave Consumer Preview Oct. 1, 2009 API History wave wavelet wavelet conv+O4Fsp5kfB conv+root wavesandbox.com!w+YTiBcVOfA wavelet conv+root blip b+O4Fsp5kfA b+YTiBcVOfB blip blip b+YTiBcVOfD blip b+Dad5DLZkB tags participants <body>
<line a="c"></line>
The pizza was awesome,
can't believe you missed it!
<line></line>
<image url="http://www.p.com/p.gif">
<line></line>More pics here.
</body> (17,24) : style/fontSize=1.3em
(17,24) : style/fontWeight=bold
(72,76) : link=http://www.p.com/p.gif
(1,77) : lang=en
b+Dad5DLZkB blip Google Wave Conversation Model Operational Transforms document items+positions operations skip, insert, delete insert 'ABCDE' skip 3, delete 1 Lessons Learned Automation
Versioning
Authentication
Cross-Framework
Language-Appropriate Google Wave Robot Python API v2
============================================

The :mod:`blip` Module
-------------------------
.. automodule:: blip
:members:
:undoc-members:

The :mod:`wavelet` Module
-------------------------
.. automodule:: wavelet
:members:
:undoc-members:

The :mod:`robot` Module
-------------------------
.. automodule:: robot
:members:
:undoc-members: index.rst ...
class Blips(object):
"""A dictionary-like object containing the blips, keyed on 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)
... blip.py sphinx-build
-b html
-d _build/doctrees
. _build/html
+ + Makefile = index.html Documentation Events -> Operations def process_events(self, json):
parsed = simplejson.loads(json)
pending_ops = ops.OperationQueue()
event_wavelet = self._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)

return simplejson.dumps(pending_ops.serialize()) appengine_robot_runner.py app.yaml main.py class RobotEventHandler(webapp.RequestHandler):

def __init__(self, robot):
self._robot = robot

def post(self):
json_body = self.request.body

json_body = unicode(json_body, 'utf8')
json_response = self._robot.process_events(json_body)

self.response.headers['Content-Type'] = 'application/json; charset=utf-8'
self.response.out.write(json_response.encode('utf-8'))

def create_robot_webapp(robot):
return webapp.WSGIApplication([
('.*/_wave/robot/profile',
lambda: ProfileHandler(
robot.profile_json,
'application/json')),
('.*/_wave/capabilities.xml',
lambda: CapabilitiesHandler(
robot.capabilities_xml,
'application/xml')),
('.*/_wave/robot/jsonrpc',
lambda: RobotEventHandler(robot)),
('.*/_wave/verify_token',
lambda: RobotVerifyTokenHandler(robot)),
])

def run(robot):
app = create_robot_webapp(robot)
run_wsgi_app(app) robot.py application: emo-bot
version: 1
runtime: python

handlers:
- url: /_wave/.*
script: main.py
- url: /public/(.*)
static_files: public/\1
upload: public/(.*) import logging

from waveapi import appengine_robot_runner
from waveapi import element
from waveapi import events
from waveapi import ops
from waveapi import robot

anim_base = 'http://emo-bot.appspot.com'
anim_ext = '.gif'
emoticons = {
':)' : 'smile',
':(' : 'frown',
'(heart)': 'heart'
}

def ProcessBlip(event, wavelet):
blip = event.blip
for emoticon in emoticons:
r = blip.all(emoticon)
if r:
r.replace(element.Image(anim_base + emoticons[emoticon] + anim_ext))
pass

if __name__ == '__main__':
emobot = robot.Robot('Emo Bot',
image_url='http://emo-bot.appspot.com/public/thumbnail.png',
profile_url='http://emo-bot.appspot.com/')
emobot.register_handler(events.BlipSubmitted, ProcessBlip)
emobot.register_handler(events.WaveletSelfAdded, ProcessBlip)
appengine_robot_runner.run(emobot, debug=True) Incoming JSON {"params": {
"blipId": "b+FYYeTpCXJ",
"waveletId": "wavesandbox.com!conv+root",
"waveId": "wavesandbox.com!w+FYYeTpCXI",
"modifyAction": {
"modifyHow": "REPLACE",
"elements": [
{
"type": "IMAGE",
"properties": {
"url": "http://wave-skimmy.appspot.com/smile.gif"
}
}
]
},
"modifyQuery": {
"textMatch": ":)",
"maxRes": -1
}
},
"method": "document.modify",
"id": "op2"
} "events": [
{
"type": "WAVELET_SELF_ADDED",
"modifiedBy": "pamela.fox@wavesandbox.com",
"timestamp": 1269400482868,
"properties": {
"blipId": "b+FYYeTpCXJ"
}
}
],
"wavelet": {
"creationTime": 1269400451853,
"lastModifiedTime": 1269400482868,
"version": 14,
"participants": [
"pamela.fox@wavesandbox.com",
"wave-skimmy@appspot.com"
],
"creator": "pamela.fox@wavesandbox.com",
"rootBlipId": "b+FYYeTpCXJ",
"title": "Dear Diary,",
"waveId": "wavesandbox.com!w+FYYeTpCXI",
"waveletId": "wavesandbox.com!conv+root"
}, Outgoing JSON Google Wave Behind the Scenes Google Wave Robots API Examples pamelafox@
@pamelafox skip 3, delete 1 skip 1, delete 1 skip 1, delete 1 skip 2, delete 1 Ferry Tasky Monty+Syntaxy Poker http://emo-bot.appspot.com/_wave/robot/jsonrpc http://emo-bot.appspot.com/_wave/robot/jsonrpc
See the full transcript