Archive for June, 2009


Not Drowning, Waving

I spent some time with the good folks at Google Sydney and a heap of fun Australian developers exploring¬†Googles new “wave” technology.

In short is pretty cool, an already neat GUI wrapping some serious back-end firepower to creat a collaborative environment that merges Realtime Publishing, Chat and Email. After a morning briefing on the tech, I Spent my afternoon with fellow Python lover Carlo Piva ( creating a robot that objected to foul language and censored it. For those on Wave, try it by adding to any wave (aka conversation) and just try to be rude or racist ūüôā

The code to do this is short and sweet –¬†we decided in the name of expediency to use an existing site for the swearing correction.

This example shows off a couple of cool things :

  1. how to make a basic bot that communicate with an external¬†“web service” for its functionality
  2. how to do POST requests
  3. how to screen scrape the results
  4. how to update existing blips (posts)

Here is the Python me and my coding buddy came up with:

from waveapi import events
from waveapi import model
from waveapi import robot
from google.appengine.api import urlfetch
from google.appengine.ext.webapp.util import run_wsgi_app
import urllib

def OnParticipantsChanged(properties, context):
¬† “””Invoked when any participants have been added/removed.”””
¬† added = properties[‘participantsAdded’]
  for p in added:

def OnRobotAdded(properties, context):
¬† “””Invoked when the robot has been added.”””
  root_wavelet = context.GetRootWavelet()
¬† root_wavelet.CreateBlip().GetDocument().SetText(“I’m alive!”)

def Notify(context):
  root_wavelet = context.GetRootWavelet()
¬† root_wavelet.CreateBlip().GetDocument().SetText(“Hi everybody!”)

def OnBlip(properties, context):
¬† “””Invoked when the robot sees a blip”””
¬† blip = context.GetBlipById(properties[‘blipId’])
  contents = blip.GetDocument().GetText()
  good = unswear(contents)
  if (good!=contents):

def unswear(bad):
¬† url = “

  form_fields = {
¬†¬†¬† “action”: “translate”,
¬†¬†¬† “p”: bad,
¬†¬†¬† “racial”: “on”,
¬†¬†¬† “submit”: “Filter”

  form_data = urllib.urlencode(form_fields)
  result = urlfetch.fetch(url=url,
¬†¬†¬† headers={‘Content-Type’: ‘application/x-www-form-urlencoded’})
  html = result.content
¬† key_start = ‘<span style=”font-family: arial; font-size:12px;”>’
¬† key_end = ‘</span></div><br>’
  return html[html.find(key_start)+len(key_start):html.find(key_end)]

if __name__ == ‘__main__’:
¬† myRobot = robot.Robot(‘invectivedeleted’,
¬†¬†¬†¬†¬† image_url=’;,
¬†¬†¬†¬†¬† version=’9′,
¬†¬†¬†¬†¬† profile_url=’;)
  myRobot.RegisterHandler(events.WAVELET_PARTICIPANTS_CHANGED, OnParticipantsChanged)
  myRobot.RegisterHandler(events.WAVELET_SELF_ADDED, OnRobotAdded)
  myRobot.RegisterHandler(events.BLIP_SUBMITTED, OnBlip)

Have fun!