     @socket.onmessage = @_waitForPong
 
   stop: =>
-    @cleanUp()
+    @_cleanUp()
 
   _open: =>
-    # TODO: include JSON client-side script for less awesome browsers
-    @socket.send JSON.stringify ping: 'PING'
+    @_sendPing()
     # TODO: consider making this timeout configurable somehow...
-    @pingTimeout = setTimeout @_error, 2000
+    @pingTimeout = setTimeout @_error, INITIAL_PING_TIMEOUT
 
   _waitForPong: (event) =>
-    o = try JSON.parse event.data catch e then {}
-    if o.pong is 'PONG'
-      # Not quite sure why this doesn't work in IE8:
-      # (Throws "TypeError: Array or arguments object expected")
-      # Firehose.Transport::_open.apply @, event
+    if isPong(try JSON.parse event.data catch e then {})
       @_succeeded = true
       @config.connected @
       clearTimeout @pingTimeout
       @socket.onmessage = @_message
+      @_restartKeepAlive()
     else @_message event
 
   _message: (event) =>
-    @config.message @config.parse event.data
+    @_restartKeepAlive()
+    msg = @config.parse event.data
+    @config.message msg if not isPong msg
 
   _close: (event) =>
-    if event?.wasClean then @cleanUp()
+    if event?.wasClean then @_cleanUp()
     else @_error event
 
   _error: (event) =>
-    @cleanUp()
+    @_cleanUp()
     super
 
-  cleanUp: ->
+  _cleanUp: =>
     if @socket?
       @socket.onopen    = null
       @socket.onclose   = null

# Unfortunately this needs to a global variable. The only other option is to
# hack into the internals of the web_socket.js plugin we are using.
window.WEB_SOCKET_SWF_LOCATION = '/assets/firehose/WebSocketMain.swf' if !window.WEB_SOCKET_SWF_LOCATION

class Firehose.WebSocket extends Firehose.Transport
  name: -> 'WebSocket'

      @socket.onmessage = null
      @socket.close()
      delete @socket

  _sendPing: =>
    @socket.send JSON.stringify ping: 'PING'

  _restartKeepAlive: =>
    doPing = =>
      console.log "Sending keepalive ping!"
      @_sendPing()
      setNextKeepAlive()
    setNextKeepAlive = =>
      @keepaliveTimeout = setTimeout doPing, KEEPALIVE_PING_TIMEOUT
    if @keepaliveTimeout?
      clearTimeout @keepaliveTimeout
      @keepaliveTimeout = null
    setNextKeepAlive()

isPong = (o) ->
  o.pong is 'PONG'
