text: Faye.Transport.WebSocket = Faye.extend(Faye.Class(Faye.Transport, {
    UNCONNECTED:  1,
    CONNECTING:   2,
    CONNECTED:    3,
  
    batching:     false,
  
    isUsable: function(callback, context) {
      this.callback(function() { callback.call(context, true) });
      this.errback(function() { callback.call(context, false) });
      this.connect();
    },
  
    request: function(envelopes) {
      this._pending = this._pending || new Faye.Set();
      for (var i = 0, n = envelopes.length; i < n; i++) this._pending.add(envelopes[i]);
  
      this.callback(function(socket) {
        if (!socket) return;
        var messages = Faye.map(envelopes, function(e) { return e.message });
        socket.send(Faye.toJSON(messages));
      }, this);
      this.connect();
    },
  
    connect: function() {
      if (Faye.Transport.WebSocket._unloaded) return;
  
      this._state = this._state || this.UNCONNECTED;
      if (this._state !== this.UNCONNECTED) return;
      this._state = this.CONNECTING;
  
      var socket = this._createSocket();
      if (!socket) return this.setDeferredStatus('failed');
  
      var self = this;
  
      socket.onopen = function() {
        if (socket.headers) self._storeCookies(socket.headers['set-cookie']);
        self._socket = socket;
        self._state = self.CONNECTED;
        self._everConnected = true;
        self._ping();
        self.setDeferredStatus('succeeded', socket);
      };
  
      var closed = false;
      socket.onclose = socket.onerror = function() {
        if (closed) return;
        closed = true;
  
        var wasConnected = (self._state === self.CONNECTED);
        socket.onopen = socket.onclose = socket.onerror = socket.onmessage = null;
  
        delete self._socket;
        self._state = self.UNCONNECTED;
        self.removeTimeout('ping');
        self.setDeferredStatus('unknown');
  
        var pending = self._pending ? self._pending.toArray() : [];
        delete self._pending;
  
        if (wasConnected) {
          self.handleError(pending, true);
        } else if (self._everConnected) {
          self.handleError(pending);
        } else {
          self.setDeferredStatus('failed');
        }
      };
  
      socket.onmessage = function(event) {
        var messages  = JSON.parse(event.data),
            envelopes = [],
            envelope;
  
        if (!messages) return;
        messages = [].concat(messages);
  
        for (var i = 0, n = messages.length; i < n; i++) {
          if (messages[i].successful === undefined) continue;
          envelope = self._pending.remove(messages[i]);
          if (envelope) envelopes.push(envelope);
        }
        self.receive(envelopes, messages);
      };
    },
  
    close: function() {
      if (!this._socket) return;
      this._socket.close();
    },
  
    _createSocket: function() {
      var url     = Faye.Transport.WebSocket.getSocketUrl(this.endpoint),
          options = {headers: Faye.copyObject(this._client.headers), ca: this._client.ca};
  
      options.headers['Cookie'] = this._getCookies();
  
      if (Faye.WebSocket)        return new Faye.WebSocket.Client(url, [], options);
      if (Faye.ENV.MozWebSocket) return new MozWebSocket(url);
      if (Faye.ENV.WebSocket)    return new WebSocket(url);
    },
  
    _ping: function() {
      if (!this._socket) return;
      this._socket.send('[]');
      this.addTimeout('ping', this._client._advice.timeout/2000, this._ping, this);
    }
  
  }), {
    PROTOCOLS: {
      'http:':  'ws:',
      'https:': 'wss:'
    },
  
    create: function(client, endpoint) {
      var sockets = client.transports.websocket = client.transports.websocket || {};
      sockets[endpoint.href] = sockets[endpoint.href] || new this(client, endpoint);
      return sockets[endpoint.href];
    },
  
    getSocketUrl: function(endpoint) {
      endpoint = Faye.copyObject(endpoint);
      endpoint.protocol = this.PROTOCOLS[endpoint.protocol];
      return Faye.URI.stringify(endpoint);
    },
  
    isUsable: function(client, endpoint, callback, context) {
      this.create(client, endpoint).isUsable(callback, context);
    }
  });
  
  Faye.extend(Faye.Transport.WebSocket.prototype, Faye.Deferrable);
  Faye.Transport.register('websocket', Faye.Transport.WebSocket);
  
  if (Faye.Event && Faye.ENV.onbeforeunload !== undefined)
    Faye.Event.on(Faye.ENV, 'beforeunload', function() {
      Faye.Transport.WebSocket._unloaded = true;
    });
  
  