faye-rails 2.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7bd83a3a2e962e010685339f78b0a1eb76e03566
4
- data.tar.gz: abf0cbaa64b7c53a407aa550eba83de311a5e35d
3
+ metadata.gz: a067e501ae8521dbcde427e15bdb99087d4fe073
4
+ data.tar.gz: 0740930e6060920c1a332ca435a5708da96b130b
5
5
  SHA512:
6
- metadata.gz: 3b3a36d23a807a8bab2443cafb911f1d14f0e57cf5d25e5bb3b1248345ef56a97d43f294d2c33c98eb8e8fbe9c110e830fde936c05e0da6143def36920a71b4d
7
- data.tar.gz: 544853c580199160d8bfcf19530c574ea17585346b2b7cbd942be8a9eb852105b7bdfde4106814fc4a864d42fcb871422ed53652d6574d6ee4255f10ad61314b
6
+ metadata.gz: dc80e029e4cb53524aa6dce5e86159c1f66adad01a21853d9d6dd0c7445ea4e7e5a978f746dfde1467c630e3b661963e4642f71c974619f3082c5aa698085f7f
7
+ data.tar.gz: fc6793202bbdcd376dfea3fa160451f314508ecea62d329551f235ce8eab7d6efe0cf910caad1fff583a24fbd3ec2c809f7603a13c30915895cc4381efc2b8b7
data/README.md CHANGED
@@ -5,53 +5,51 @@ faye-rails is a Ruby gem which handles embedding Faye's rack-based server into t
5
5
  [![Build Status](https://travis-ci.org/jamesotron/faye-rails.png?branch=master)](https://travis-ci.org/jamesotron/faye-rails)
6
6
  [![Dependency Status](https://gemnasium.com/jamesotron/faye-rails.png)](https://gemnasium.com/jamesotron/faye-rails)
7
7
  [![Code Climate](https://codeclimate.com/github/jamesotron/faye-rails.png)](https://codeclimate.com/github/jamesotron/faye-rails)
8
- [![jcog:secure](http://sociable.co.nz/downloads/images/jcog_secure.png)](http://sociable.co.nz/blog/2013/04/18/offical-jcog-secure-badge-for-all-your-software-security-needs/)
9
8
 
10
9
  A *very* small demonstration app is available for your perusal [on Heroku](http://faye-rails-demo.herokuapp.com/). The source is [here on Github](https://github.com/jamesotron/faye-rails-demo).
11
10
 
11
+ # Heroku Add-on
12
+
13
+ If you're planning on running Faye on Heroku you're probably going to have a bad time. Take a look at [MessageRocket](https://messagerocket.co/) as an alternative, and help support the author to maintain more great open source projects.
14
+
12
15
  # Embedded server
13
16
 
14
- Due to the limitations of most Rack-based web servers available Faye can only be run on Thin, however if you are using thin, then you can add as many Faye servers as you want to the Rails router like so:
17
+ Due to the limitations of most Rack-based web servers available Faye can only be run on Thin, however if you are using thin, then you can add as many Faye servers as you want to the Rails middleware stack like so:
15
18
 
16
19
  ```ruby
17
- App::Application.routes.draw do
18
- faye_server '/faye', :timeout => 25
19
- end
20
+ # application.rb
21
+ config.middleware.use FayeRails::Middleware, mount: '/faye', :timeout => 25
20
22
  ```
21
23
 
22
24
  You can also pass a block to `faye_server` which will be executed in the context of the Faye server, thus you can call any methods on `Faye::RackAdapter` from within the block:
23
25
 
24
26
  ```ruby
25
- App::Application.routes.draw do
26
- faye_server '/faye', :timeout => 25 do
27
- class MockExtension
28
- def incoming(message, callback)
29
- callback.call(message)
30
- end
27
+ config.middleware.use FayeRails::Middleware, mount: '/faye', :timeout => 25 do
28
+ # can be defined anywhere, like app/faye_extensions/mock_extension.rb
29
+ class MockExtension
30
+ def incoming(message, callback)
31
+ callback.call(message)
31
32
  end
32
- add_extension(MockExtension.new)
33
33
  end
34
+
35
+ add_extension(MockExtension.new)
34
36
  end
35
37
  ```
36
38
 
37
39
  If you really want to, you can ask Faye to start it's own listening Thin server on an arbitrary port:
38
40
 
39
41
  ```ruby
40
- App::Application.routes.draw do
41
- faye_server '/faye', :timeout => 25 do
42
- listen(9292)
43
- end
42
+ config.middleware.use FayeRails::Middleware, mount: '/faye', :timeout => 25 do
43
+ listen(9292)
44
44
  end
45
45
  ```
46
46
 
47
47
  You can also do some rudimentary routing using the map method:
48
48
 
49
49
  ```ruby
50
- App::Application.routes.draw do
51
- faye_server '/faye', :timeout => 25 do
52
- map '/widgets/**' => WidgetsController
53
- map :default => :block
54
- end
50
+ config.middleware.use FayeRails::Middleware, mount: '/faye', :timeout => 25 do
51
+ map '/widgets/**' => WidgetsController
52
+ map :default => :block
55
53
  end
56
54
  ```
57
55
 
@@ -142,21 +140,19 @@ end
142
140
  Often you'll find yourself running the Rails environment without the server running - eg when doing background job processing, or running the console. If you have any actions which use Faye then you'll need to make sure that you have the EventMachine reactor running. The easiest solution to this is to create an initialiser in `config/initializers` which calls `Faye.ensure_reactor_running!`. For workers in production you probably also want to make sure that you are using the Redis engine for Faye to ensure that multiple server instances see the same data.
143
141
 
144
142
  ```ruby
145
- App::Application.routes.draw do
146
- faye_server '/faye', timeout: 25, engine: {type: Faye::Redis, host: 'localhost'} do
147
- map '/announce/**' => SomeController
148
- end
143
+ config.middleware.use FayeRails::Middleware, mount: '/faye', engine: {type: Faye::Redis, host: 'localhost'}, :timeout => 25 do
144
+ map '/announce/**' => SomeController
149
145
  end
150
146
  ```
151
147
 
148
+ See more details in [this issue on GitHub](https://github.com/jamesotron/faye-rails/issues/26).
149
+
152
150
  # Running on Phusion Passenger
153
151
 
154
152
  If you want to run faye-rails on passenger, make sure you are using passenger 4.0 standalone or passenger 4.0 on nginx 1.4+ for nginx with websocket support. Passenger on apache is not supported. Because passenger uses a multi-process model, you must use the faye redis backend. Add `gem 'faye-redis'` to your Gemfile and configure your routes like this:
155
153
 
156
154
  ```ruby
157
- App::Application.routes.draw do
158
- faye_server '/faye', timeout: 25, server: 'passenger', engine: {type: Faye::Redis, host: 'localhost'}
159
- end
155
+ config.middleware.use FayeRails::Middleware, mount: '/faye', :timeout => 25, server: 'passenger', engine: {type: Faye::Redis, host: 'localhost'}
160
156
  ```
161
157
 
162
158
  # Thanks.
@@ -14,6 +14,7 @@ module FayeRails
14
14
  autoload :Controller, File.join(ROOT, 'faye-rails', 'controller')
15
15
  autoload :RackAdapter, File.join(ROOT, 'faye-rails', 'rack_adapter')
16
16
  autoload :Filter, File.join(ROOT, 'faye-rails', 'filter')
17
+ autoload :Matcher, File.join(ROOT, 'faye-rails', 'matcher')
17
18
 
18
19
  def self.servers
19
20
  @servers ||= ServerList.new
@@ -25,7 +25,7 @@ module FayeRails
25
25
  m.client_id = args.shift
26
26
  m.channel = args.shift
27
27
  m.data = args.shift
28
- m.instance_eval(&block) if File.fnmatch(channel, m.channel)
28
+ m.instance_eval(&block) if FayeRails::Matcher.match? channel, m.channel
29
29
  end
30
30
  end
31
31
  end
@@ -40,7 +40,7 @@ module FayeRails
40
40
 
41
41
  def subscribe(&block)
42
42
  EM.schedule do
43
- @subscription = FayeRails.client(endpoint).subscribe(channel) do |message|
43
+ FayeRails.client(endpoint).subscribe(channel) do |message|
44
44
  Message.new.tap do |m|
45
45
  m.message = message
46
46
  m.channel = channel
@@ -52,7 +52,7 @@ module FayeRails
52
52
 
53
53
  def unsubscribe
54
54
  EM.schedule do
55
- FayeRails.client(endpoint).unsubscribe(@subscription)
55
+ FayeRails.client(endpoint).unsubscribe(channel)
56
56
  end
57
57
  end
58
58
 
@@ -133,7 +133,7 @@ module FayeRails
133
133
  end
134
134
 
135
135
  def channel_matches?(glob,test)
136
- File.fnmatch? glob, test
136
+ FayeRails::Matcher.match? glob, test
137
137
  end
138
138
 
139
139
  def subscription?(channel)
@@ -0,0 +1,8 @@
1
+ module FayeRails
2
+ module Matcher
3
+ def self.match?(pattern, value)
4
+ return false if value.include? "\0"
5
+ File.fnmatch? pattern, value
6
+ end
7
+ end
8
+ end
@@ -41,7 +41,8 @@ to your application config in application.rb
41
41
  end
42
42
 
43
43
  options = DEFAULTS.merge(options)
44
- Faye::WebSocket.load_adapter(options.delete(:server))
44
+ server = options.delete(:server)
45
+ Faye::WebSocket.load_adapter(server) if server && server != 'passenger'
45
46
 
46
47
  @adapter = FayeRails::RackAdapter.new(@app, options)
47
48
  @adapter.instance_eval(&block) if block.respond_to? :call
@@ -40,7 +40,7 @@ module FayeRails
40
40
  if opts.is_a? Hash
41
41
  opts.each do |channel, controller|
42
42
  if channel.is_a? String
43
- if File.fnmatch?('/**', channel)
43
+ if FayeRails::Matcher.match? '/**', channel
44
44
  routing_extension.map(channel, controller)
45
45
  else
46
46
  raise ArgumentError, "Invalid channel: #{channel}"
@@ -109,9 +109,9 @@ module FayeRails
109
109
  take_action_for message, callback, message['subscription']
110
110
  elsif message['channel'] == '/meta/unsubscribe'
111
111
  take_action_for message, callback, message['subscription']
112
- elsif File.fnmatch?('/meta/*', message['channel'])
112
+ elsif FayeRails::Matcher.match? '/meta/*', message['channel']
113
113
  callback.call(message)
114
- elsif File.fnmatch?('/service/**', message['channel'])
114
+ elsif FayeRails::Matcher.match? '/service/**', message['channel']
115
115
  callback.call(message)
116
116
  else
117
117
  take_action_for message, callback, message['channel']
@@ -119,7 +119,7 @@ module FayeRails
119
119
  end
120
120
 
121
121
  def map(channel, controller)
122
- if File.fnmatch?('/**', channel)
122
+ if FayeRails::Matcher.match? '/**', channel
123
123
  (@mappings[channel] ||= []) << controller
124
124
  else
125
125
  raise ArgumentError, "Invalid channel name: #{channel}"
@@ -139,7 +139,7 @@ module FayeRails
139
139
  end
140
140
 
141
141
  def take_action_for(message, callback, test='')
142
- if @mappings.keys.select { |glob| File.fnmatch?(glob,test) }.size > 0
142
+ if @mappings.keys.select { |glob| FayeRails::Matcher.match? glob, test }.size > 0
143
143
  callback.call(message)
144
144
  elsif @default == :block
145
145
  message['error'] = "Permission denied"
@@ -1,3 +1,3 @@
1
1
  module FayeRails
2
- VERSION = "2.0.0"
2
+ VERSION = "2.0.1"
3
3
  end
@@ -1,5 +1,5 @@
1
1
  (function() {
2
- !function(){"use strict";var Faye={VERSION:"1.0.1",BAYEUX_VERSION:"1.0",ID_LENGTH:160,JSONP_CALLBACK:"jsonpcallback",CONNECTION_TYPES:["long-polling","cross-origin-long-polling","callback-polling","websocket","eventsource","in-process"],MANDATORY_CONNECTION_TYPES:["long-polling","callback-polling","in-process"],ENV:"undefined"!=typeof window?window:global,extend:function(e,t,n){if(!t)return e;for(var i in t)t.hasOwnProperty(i)&&(e.hasOwnProperty(i)&&n===!1||e[i]!==t[i]&&(e[i]=t[i]));return e},random:function(e){return e=e||this.ID_LENGTH,csprng(e,36)},clientIdFromMessages:function(e){var t=this.filter([].concat(e),function(e){return"/meta/connect"===e.channel});return t[0]&&t[0].clientId},copyObject:function(e){var t,n,i;if(e instanceof Array){for(t=[],n=e.length;n--;)t[n]=Faye.copyObject(e[n]);return t}if("object"==typeof e){t=null===e?null:{};for(i in e)t[i]=Faye.copyObject(e[i]);return t}return e},commonElement:function(e,t){for(var n=0,i=e.length;i>n;n++)if(-1!==this.indexOf(t,e[n]))return e[n];return null},indexOf:function(e,t){if(e.indexOf)return e.indexOf(t);for(var n=0,i=e.length;i>n;n++)if(e[n]===t)return n;return-1},map:function(e,t,n){if(e.map)return e.map(t,n);var i=[];if(e instanceof Array)for(var s=0,r=e.length;r>s;s++)i.push(t.call(n||null,e[s],s));else for(var o in e)e.hasOwnProperty(o)&&i.push(t.call(n||null,o,e[o]));return i},filter:function(e,t,n){if(e.filter)return e.filter(t,n);for(var i=[],s=0,r=e.length;r>s;s++)t.call(n||null,e[s],s)&&i.push(e[s]);return i},asyncEach:function(e,t,n,i){var s=e.length,r=-1,o=0,a=!1,c=function(){return o-=1,r+=1,r===s?n&&n.call(i):(t(e[r],h),void 0)},u=function(){if(!a){for(a=!0;o>0;)c();a=!1}},h=function(){o+=1,u()};h()},toJSON:function(e){return this.stringify?this.stringify(e,function(e,t){return this[e]instanceof Array?this[e]:t}):JSON.stringify(e)}};"undefined"!=typeof module?module.exports=Faye:"undefined"!=typeof window&&(window.Faye=Faye),Faye.Class=function(e,t){"function"!=typeof e&&(t=e,e=Object);var n=function(){return this.initialize?this.initialize.apply(this,arguments)||this:this},i=function(){};return i.prototype=e.prototype,n.prototype=new i,Faye.extend(n.prototype,t),n},function(){function e(e,t){if(e.indexOf)return e.indexOf(t);for(var n=0;n<e.length;n++)if(t===e[n])return n;return-1}var t=Faye.EventEmitter=function(){},n="function"==typeof Array.isArray?Array.isArray:function(e){return"[object Array]"===Object.prototype.toString.call(e)};t.prototype.emit=function(e){if("error"===e&&(!this._events||!this._events.error||n(this._events.error)&&!this._events.error.length))throw arguments[1]instanceof Error?arguments[1]:Error("Uncaught, unspecified 'error' event.");if(!this._events)return!1;var t=this._events[e];if(!t)return!1;if("function"==typeof t){switch(arguments.length){case 1:t.call(this);break;case 2:t.call(this,arguments[1]);break;case 3:t.call(this,arguments[1],arguments[2]);break;default:var i=Array.prototype.slice.call(arguments,1);t.apply(this,i)}return!0}if(n(t)){for(var i=Array.prototype.slice.call(arguments,1),s=t.slice(),r=0,o=s.length;o>r;r++)s[r].apply(this,i);return!0}return!1},t.prototype.addListener=function(e,t){if("function"!=typeof t)throw Error("addListener only takes instances of Function");return this._events||(this._events={}),this.emit("newListener",e,t),this._events[e]?n(this._events[e])?this._events[e].push(t):this._events[e]=[this._events[e],t]:this._events[e]=t,this},t.prototype.on=t.prototype.addListener,t.prototype.once=function(e,t){var n=this;return n.on(e,function i(){n.removeListener(e,i),t.apply(this,arguments)}),this},t.prototype.removeListener=function(t,i){if("function"!=typeof i)throw Error("removeListener only takes instances of Function");if(!this._events||!this._events[t])return this;var s=this._events[t];if(n(s)){var r=e(s,i);if(0>r)return this;s.splice(r,1),0==s.length&&delete this._events[t]}else this._events[t]===i&&delete this._events[t];return this},t.prototype.removeAllListeners=function(e){return 0===arguments.length?(this._events={},this):(e&&this._events&&this._events[e]&&(this._events[e]=null),this)},t.prototype.listeners=function(e){return this._events||(this._events={}),this._events[e]||(this._events[e]=[]),n(this._events[e])||(this._events[e]=[this._events[e]]),this._events[e]}}(),Faye.Namespace=Faye.Class({initialize:function(){this._used={}},exists:function(e){return this._used.hasOwnProperty(e)},generate:function(){for(var e=Faye.random();this._used.hasOwnProperty(e);)e=Faye.random();return this._used[e]=e},release:function(e){delete this._used[e]}}),function(){var e,t=setTimeout;e="function"==typeof setImmediate?function(e){setImmediate(e)}:"object"==typeof process&&process.nextTick?function(e){process.nextTick(e)}:function(e){t(e,0)};var n=0,i=1,s=2,r=function(e){return e},o=function(e){throw e},a=function(e){if(this._state=n,this._callbacks=[],this._errbacks=[],"function"==typeof e){var t=this;e(function(e){f(t,e)},function(e){p(t,e)})}};a.prototype.then=function(e,t){var n={},i=this;return n.promise=new a(function(s,r){n.fulfill=s,n.reject=r,c(i,e,n),u(i,t,n)}),n.promise};var c=function(e,t,s){"function"!=typeof t&&(t=r);var o=function(e){h(t,e,s)};e._state===n?e._callbacks.push(o):e._state===i&&o(e._value)},u=function(e,t,i){"function"!=typeof t&&(t=o);var r=function(e){h(t,e,i)};e._state===n?e._errbacks.push(r):e._state===s&&r(e._reason)},h=function(t,n,i){e(function(){l(t,n,i)})},l=function(e,t,n){var i,s,o,a=!1;try{if(i=e(t),s=typeof i,o=null!==i&&("function"===s||"object"===s)&&i.then,i===n.promise)return n.reject(new TypeError("Recursive promise chain detected"));if("function"!=typeof o)return n.fulfill(i);o.call(i,function(e){a||(a=!0,l(r,e,n))},function(e){a||(a=!0,n.reject(e))})}catch(c){if(a)return;a=!0,n.reject(c)}},f=a.fulfill=a.resolve=function(e,t){if(e._state===n){e._state=i,e._value=t,e._errbacks=[];for(var s,r=e._callbacks;s=r.shift();)s(t)}},p=a.reject=function(e,t){if(e._state===n){e._state=s,e._reason=t,e._callbacks=[];for(var i,r=e._errbacks;i=r.shift();)i(t)}};a.defer=e,a.deferred=a.pending=function(){var e={};return e.promise=new a(function(t,n){e.fulfill=e.resolve=t,e.reject=n}),e},a.fulfilled=a.resolved=function(e){return new a(function(t){t(e)})},a.rejected=function(e){return new a(function(t,n){n(e)})},void 0===Faye?module.exports=a:Faye.Promise=a}(),Faye.Set=Faye.Class({initialize:function(){this._index={}},add:function(e){var t=void 0!==e.id?e.id:e;return this._index.hasOwnProperty(t)?!1:(this._index[t]=e,!0)},forEach:function(e,t){for(var n in this._index)this._index.hasOwnProperty(n)&&e.call(t,this._index[n])},isEmpty:function(){for(var e in this._index)if(this._index.hasOwnProperty(e))return!1;return!0},member:function(e){for(var t in this._index)if(this._index[t]===e)return!0;return!1},remove:function(e){var t=void 0!==e.id?e.id:e,n=this._index[t];return delete this._index[t],n},toArray:function(){var e=[];return this.forEach(function(t){e.push(t)}),e}}),Faye.URI={isURI:function(e){return e&&e.protocol&&e.host&&e.path},isSameOrigin:function(e){var t=Faye.ENV.location;return e.protocol===t.protocol&&e.hostname===t.hostname&&e.port===t.port},parse:function(e){if("string"!=typeof e)return e;var t,n,i,s,r,o,a={},c=function(t,n){e=e.replace(n,function(e){return a[t]=e,""}),a[t]=a[t]||""};for(c("protocol",/^[a-z]+\:/i),c("host",/^\/\/[^\/\?#]+/),/^\//.test(e)||a.host||(e=Faye.ENV.location.pathname.replace(/[^\/]*$/,"")+e),c("pathname",/^[^\?#]*/),c("search",/^\?[^#]*/),c("hash",/^#.*/),a.protocol=a.protocol||Faye.ENV.location.protocol,a.host?(a.host=a.host.substr(2),t=a.host.split(":"),a.hostname=t[0],a.port=t[1]||""):(a.host=Faye.ENV.location.host,a.hostname=Faye.ENV.location.hostname,a.port=Faye.ENV.location.port),a.pathname=a.pathname||"/",a.path=a.pathname+a.search,n=a.search.replace(/^\?/,""),i=n?n.split("&"):[],o={},s=0,r=i.length;r>s;s++)t=i[s].split("="),o[decodeURIComponent(t[0]||"")]=decodeURIComponent(t[1]||"");return a.query=o,a.href=this.stringify(a),a},stringify:function(e){var t=e.protocol+"//"+e.hostname;return e.port&&(t+=":"+e.port),t+=e.pathname+this.queryString(e.query)+(e.hash||"")},queryString:function(e){var t=[];for(var n in e)e.hasOwnProperty(n)&&t.push(encodeURIComponent(n)+"="+encodeURIComponent(e[n]));return 0===t.length?"":"?"+t.join("&")}},Faye.Error=Faye.Class({initialize:function(e,t,n){this.code=e,this.params=Array.prototype.slice.call(t),this.message=n},toString:function(){return this.code+":"+this.params.join(",")+":"+this.message}}),Faye.Error.parse=function(e){if(e=e||"",!Faye.Grammar.ERROR.test(e))return new this(null,[],e);var t=e.split(":"),n=parseInt(t[0]),i=t[1].split(","),e=t[2];return new this(n,i,e)},Faye.Error.versionMismatch=function(){return""+new this(300,arguments,"Version mismatch")},Faye.Error.conntypeMismatch=function(){return""+new this(301,arguments,"Connection types not supported")},Faye.Error.extMismatch=function(){return""+new this(302,arguments,"Extension mismatch")},Faye.Error.badRequest=function(){return""+new this(400,arguments,"Bad request")},Faye.Error.clientUnknown=function(){return""+new this(401,arguments,"Unknown client")},Faye.Error.parameterMissing=function(){return""+new this(402,arguments,"Missing required parameter")},Faye.Error.channelForbidden=function(){return""+new this(403,arguments,"Forbidden channel")},Faye.Error.channelUnknown=function(){return""+new this(404,arguments,"Unknown channel")},Faye.Error.channelInvalid=function(){return""+new this(405,arguments,"Invalid channel")},Faye.Error.extUnknown=function(){return""+new this(406,arguments,"Unknown extension")},Faye.Error.publishFailed=function(){return""+new this(407,arguments,"Failed to publish")},Faye.Error.serverError=function(){return""+new this(500,arguments,"Internal server error")},Faye.Deferrable={then:function(e,t){var n=this;return this._promise||(this._promise=new Faye.Promise(function(e,t){n._fulfill=e,n._reject=t})),0===arguments.length?this._promise:this._promise.then(e,t)},callback:function(e,t){return this.then(function(n){e.call(t,n)})},errback:function(e,t){return this.then(null,function(n){e.call(t,n)})},timeout:function(e,t){this.then();var n=this;this._timer=Faye.ENV.setTimeout(function(){n._reject(t)},1e3*e)},setDeferredStatus:function(e,t){this._timer&&Faye.ENV.clearTimeout(this._timer);this.then();"succeeded"===e?this._fulfill(t):"failed"===e?this._reject(t):delete this._promise}},Faye.Publisher={countListeners:function(e){return this.listeners(e).length},bind:function(e,t,n){var i=Array.prototype.slice,s=function(){t.apply(n,i.call(arguments))};return this._listeners=this._listeners||[],this._listeners.push([e,t,n,s]),this.on(e,s)},unbind:function(e,t,n){this._listeners=this._listeners||[];for(var i,s=this._listeners.length;s--;)i=this._listeners[s],i[0]===e&&(!t||i[1]===t&&i[2]===n)&&(this._listeners.splice(s,1),this.removeListener(e,i[3]))}},Faye.extend(Faye.Publisher,Faye.EventEmitter.prototype),Faye.Publisher.trigger=Faye.Publisher.emit,Faye.Timeouts={addTimeout:function(e,t,n,i){if(this._timeouts=this._timeouts||{},!this._timeouts.hasOwnProperty(e)){var s=this;this._timeouts[e]=Faye.ENV.setTimeout(function(){delete s._timeouts[e],n.call(i)},1e3*t)}},removeTimeout:function(e){this._timeouts=this._timeouts||{};var t=this._timeouts[e];t&&(clearTimeout(t),delete this._timeouts[e])},removeAllTimeouts:function(){this._timeouts=this._timeouts||{};for(var e in this._timeouts)this.removeTimeout(e)}},Faye.Logging={LOG_LEVELS:{fatal:4,error:3,warn:2,info:1,debug:0},writeLog:function(e,t){if(Faye.logger){var e=Array.prototype.slice.apply(e),n="[Faye",i=this.className,s=e.shift().replace(/\?/g,function(){try{return Faye.toJSON(e.shift())}catch(t){return"[Object]"}});for(var r in Faye)i||"function"==typeof Faye[r]&&this instanceof Faye[r]&&(i=r);i&&(n+="."+i),n+="] ","function"==typeof Faye.logger[t]?Faye.logger[t](n+s):"function"==typeof Faye.logger&&Faye.logger(n+s)}}},function(){for(var e in Faye.Logging.LOG_LEVELS)(function(e){Faye.Logging[e]=function(){this.writeLog(arguments,e)}})(e,Faye.Logging.LOG_LEVELS[e])}(),Faye.Grammar={CHANNEL_NAME:/^\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,CHANNEL_PATTERN:/^(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*\/\*{1,2}$/,ERROR:/^([0-9][0-9][0-9]:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*|[0-9][0-9][0-9]::(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)$/,VERSION:/^([0-9])+(\.(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*)*$/},Faye.Extensible={addExtension:function(e){this._extensions=this._extensions||[],this._extensions.push(e),e.added&&e.added(this)},removeExtension:function(e){if(this._extensions)for(var t=this._extensions.length;t--;)this._extensions[t]===e&&(this._extensions.splice(t,1),e.removed&&e.removed(this))},pipeThroughExtensions:function(e,t,n,i,s){if(this.debug("Passing through ? extensions: ?",e,t),!this._extensions)return i.call(s,t);var r=this._extensions.slice(),o=function(t){if(!t)return i.call(s,t);var a=r.shift();if(!a)return i.call(s,t);var c=a[e];return c?(c.length>=3?a[e](t,n,o):a[e](t,o),void 0):o(t)};o(t)}},Faye.extend(Faye.Extensible,Faye.Logging),Faye.Channel=Faye.Class({initialize:function(e){this.id=this.name=e},push:function(e){this.trigger("message",e)},isUnused:function(){return 0===this.countListeners("message")}}),Faye.extend(Faye.Channel.prototype,Faye.Publisher),Faye.extend(Faye.Channel,{HANDSHAKE:"/meta/handshake",CONNECT:"/meta/connect",SUBSCRIBE:"/meta/subscribe",UNSUBSCRIBE:"/meta/unsubscribe",DISCONNECT:"/meta/disconnect",META:"meta",SERVICE:"service",expand:function(e){var t=this.parse(e),n=["/**",e],i=t.slice();i[i.length-1]="*",n.push(this.unparse(i));for(var s=1,r=t.length;r>s;s++)i=t.slice(0,s),i.push("**"),n.push(this.unparse(i));return n},isValid:function(e){return Faye.Grammar.CHANNEL_NAME.test(e)||Faye.Grammar.CHANNEL_PATTERN.test(e)},parse:function(e){return this.isValid(e)?e.split("/").slice(1):null},unparse:function(e){return"/"+e.join("/")},isMeta:function(e){var t=this.parse(e);return t?t[0]===this.META:null},isService:function(e){var t=this.parse(e);return t?t[0]===this.SERVICE:null},isSubscribable:function(e){return this.isValid(e)?!this.isMeta(e)&&!this.isService(e):null},Set:Faye.Class({initialize:function(){this._channels={}},getKeys:function(){var e=[];for(var t in this._channels)e.push(t);return e},remove:function(e){delete this._channels[e]},hasSubscription:function(e){return this._channels.hasOwnProperty(e)},subscribe:function(e,t,n){if(t)for(var i,s=0,r=e.length;r>s;s++){i=e[s];var o=this._channels[i]=this._channels[i]||new Faye.Channel(i);o.bind("message",t,n)}},unsubscribe:function(e,t,n){var i=this._channels[e];return i?(i.unbind("message",t,n),i.isUnused()?(this.remove(e),!0):!1):!1},distributeMessage:function(e){for(var t=Faye.Channel.expand(e.channel),n=0,i=t.length;i>n;n++){var s=this._channels[t[n]];s&&s.trigger("message",e.data)}}})}),Faye.Envelope=Faye.Class({initialize:function(e,t){this.id=e.id,this.message=e,void 0!==t&&this.timeout(t/1e3,!1)}}),Faye.extend(Faye.Envelope.prototype,Faye.Deferrable),Faye.Publication=Faye.Class(Faye.Deferrable),Faye.Subscription=Faye.Class({initialize:function(e,t,n,i){this._client=e,this._channels=t,this._callback=n,this._context=i,this._cancelled=!1},cancel:function(){this._cancelled||(this._client.unsubscribe(this._channels,this._callback,this._context),this._cancelled=!0)},unsubscribe:function(){this.cancel()}}),Faye.extend(Faye.Subscription.prototype,Faye.Deferrable),Faye.Client=Faye.Class({UNCONNECTED:1,CONNECTING:2,CONNECTED:3,DISCONNECTED:4,HANDSHAKE:"handshake",RETRY:"retry",NONE:"none",CONNECTION_TIMEOUT:60,DEFAULT_RETRY:5,MAX_REQUEST_SIZE:2048,DEFAULT_ENDPOINT:"/bayeux",INTERVAL:0,initialize:function(e,t){this.info("New client created for ?",e),this._options=t||{},this.endpoint=Faye.URI.parse(e||this.DEFAULT_ENDPOINT),this.endpoints=this._options.endpoints||{},this.transports={},this.cookies=Faye.CookieJar&&new Faye.CookieJar,this.headers={},this.ca=this._options.ca,this._disabled=[],this._retry=this._options.retry||this.DEFAULT_RETRY;for(var n in this.endpoints)this.endpoints[n]=Faye.URI.parse(this.endpoints[n]);this.maxRequestSize=this.MAX_REQUEST_SIZE,this._state=this.UNCONNECTED,this._channels=new Faye.Channel.Set,this._messageId=0,this._responseCallbacks={},this._advice={reconnect:this.RETRY,interval:1e3*(this._options.interval||this.INTERVAL),timeout:1e3*(this._options.timeout||this.CONNECTION_TIMEOUT)},Faye.Event&&void 0!==Faye.ENV.onbeforeunload&&Faye.Event.on(Faye.ENV,"beforeunload",function(){Faye.indexOf(this._disabled,"autodisconnect")<0&&this.disconnect()},this)},disable:function(e){this._disabled.push(e)},setHeader:function(e,t){this.headers[e]=t},handshake:function(e,t){if(this._advice.reconnect!==this.NONE&&this._state===this.UNCONNECTED){this._state=this.CONNECTING;var n=this;this.info("Initiating handshake with ?",Faye.URI.stringify(this.endpoint)),this._selectTransport(Faye.MANDATORY_CONNECTION_TYPES),this._send({channel:Faye.Channel.HANDSHAKE,version:Faye.BAYEUX_VERSION,supportedConnectionTypes:[this._transport.connectionType]},function(i){i.successful?(this._state=this.CONNECTED,this._clientId=i.clientId,this._selectTransport(i.supportedConnectionTypes),this.info("Handshake successful: ?",this._clientId),this.subscribe(this._channels.getKeys(),!0),e&&Faye.Promise.defer(function(){e.call(t)})):(this.info("Handshake unsuccessful"),Faye.ENV.setTimeout(function(){n.handshake(e,t)},this._advice.interval),this._state=this.UNCONNECTED)},this)}},connect:function(e,t){if(this._advice.reconnect!==this.NONE&&this._state!==this.DISCONNECTED){if(this._state===this.UNCONNECTED)return this.handshake(function(){this.connect(e,t)},this);this.callback(e,t),this._state===this.CONNECTED&&(this.info("Calling deferred actions for ?",this._clientId),this.setDeferredStatus("succeeded"),this.setDeferredStatus("unknown"),this._connectRequest||(this._connectRequest=!0,this.info("Initiating connection for ?",this._clientId),this._send({channel:Faye.Channel.CONNECT,clientId:this._clientId,connectionType:this._transport.connectionType},this._cycleConnection,this)))}},disconnect:function(){this._state===this.CONNECTED&&(this._state=this.DISCONNECTED,this.info("Disconnecting ?",this._clientId),this._send({channel:Faye.Channel.DISCONNECT,clientId:this._clientId},function(e){e.successful&&(this._transport.close(),delete this._transport)},this),this.info("Clearing channel listeners for ?",this._clientId),this._channels=new Faye.Channel.Set)},subscribe:function(e,t,n){if(e instanceof Array)return Faye.map(e,function(e){return this.subscribe(e,t,n)},this);var i=new Faye.Subscription(this,e,t,n),s=t===!0,r=this._channels.hasSubscription(e);return r&&!s?(this._channels.subscribe([e],t,n),i.setDeferredStatus("succeeded"),i):(this.connect(function(){this.info("Client ? attempting to subscribe to ?",this._clientId,e),s||this._channels.subscribe([e],t,n),this._send({channel:Faye.Channel.SUBSCRIBE,clientId:this._clientId,subscription:e},function(s){if(!s.successful)return i.setDeferredStatus("failed",Faye.Error.parse(s.error)),this._channels.unsubscribe(e,t,n);var r=[].concat(s.subscription);this.info("Subscription acknowledged for ? to ?",this._clientId,r),i.setDeferredStatus("succeeded")},this)},this),i)},unsubscribe:function(e,t,n){if(e instanceof Array)return Faye.map(e,function(e){return this.unsubscribe(e,t,n)},this);var i=this._channels.unsubscribe(e,t,n);i&&this.connect(function(){this.info("Client ? attempting to unsubscribe from ?",this._clientId,e),this._send({channel:Faye.Channel.UNSUBSCRIBE,clientId:this._clientId,subscription:e},function(e){if(e.successful){var t=[].concat(e.subscription);this.info("Unsubscription acknowledged for ? from ?",this._clientId,t)}},this)},this)},publish:function(e,t){var n=new Faye.Publication;return this.connect(function(){this.info("Client ? queueing published message to ?: ?",this._clientId,e,t),this._send({channel:e,data:t,clientId:this._clientId},function(e){e.successful?n.setDeferredStatus("succeeded"):n.setDeferredStatus("failed",Faye.Error.parse(e.error))},this)},this),n},receiveMessage:function(e){var t,n=e.id;void 0!==e.successful&&(t=this._responseCallbacks[n],delete this._responseCallbacks[n]),this.pipeThroughExtensions("incoming",e,null,function(e){e&&(e.advice&&this._handleAdvice(e.advice),this._deliverMessage(e),t&&t[0].call(t[1],e))},this),this._transportUp!==!0&&(this._transportUp=!0,this.trigger("transport:up"))},messageError:function(e,t){for(var n,i,s=this._retry,r=this,o=0,a=e.length;a>o;o++)i=e[o],n=i.id,t?this._transportSend(i):Faye.ENV.setTimeout(function(){r._transportSend(i)},1e3*s);t||this._transportUp===!1||(this._transportUp=!1,this.trigger("transport:down"))},_selectTransport:function(e){Faye.Transport.get(this,e,this._disabled,function(e){this.debug("Selected ? transport for ?",e.connectionType,Faye.URI.stringify(e.endpoint)),e!==this._transport&&(this._transport&&this._transport.close(),this._transport=e)},this)},_send:function(e,t,n){this._transport&&(e.id=e.id||this._generateMessageId(),this.pipeThroughExtensions("outgoing",e,null,function(e){e&&(t&&(this._responseCallbacks[e.id]=[t,n]),this._transportSend(e))},this))},_transportSend:function(e){if(this._transport){var t=1.2*(this._advice.timeout||1e3*this._retry),n=new Faye.Envelope(e,t);n.errback(function(t){this.messageError([e],t)},this),this._transport.send(n)}},_generateMessageId:function(){return this._messageId+=1,this._messageId>=Math.pow(2,32)&&(this._messageId=0),this._messageId.toString(36)},_handleAdvice:function(e){Faye.extend(this._advice,e),this._advice.reconnect===this.HANDSHAKE&&this._state!==this.DISCONNECTED&&(this._state=this.UNCONNECTED,this._clientId=null,this._cycleConnection())},_deliverMessage:function(e){e.channel&&void 0!==e.data&&(this.info("Client ? calling listeners for ? with ?",this._clientId,e.channel,e.data),this._channels.distributeMessage(e))},_cycleConnection:function(){this._connectRequest&&(this._connectRequest=null,this.info("Closed connection for ?",this._clientId));var e=this;Faye.ENV.setTimeout(function(){e.connect()},this._advice.interval)}}),Faye.extend(Faye.Client.prototype,Faye.Deferrable),Faye.extend(Faye.Client.prototype,Faye.Publisher),Faye.extend(Faye.Client.prototype,Faye.Logging),Faye.extend(Faye.Client.prototype,Faye.Extensible),Faye.Transport=Faye.extend(Faye.Class({MAX_DELAY:0,batching:!0,initialize:function(e,t){this._client=e,this.endpoint=t,this._outbox=[]},close:function(){},encode:function(){return""},send:function(e){var t=e.message;return this.debug("Client ? sending message to ?: ?",this._client._clientId,Faye.URI.stringify(this.endpoint),t),this.batching?(this._outbox.push(e),t.channel===Faye.Channel.HANDSHAKE?this.addTimeout("publish",.01,this.flush,this):(t.channel===Faye.Channel.CONNECT&&(this._connectMessage=t),this.flushLargeBatch(),this.addTimeout("publish",this.MAX_DELAY,this.flush,this),void 0)):this.request([e])},flush:function(){this.removeTimeout("publish"),this._outbox.length>1&&this._connectMessage&&(this._connectMessage.advice={timeout:0}),this.request(this._outbox),this._connectMessage=null,this._outbox=[]},flushLargeBatch:function(){var e=this.encode(this._outbox);if(!(e.length<this._client.maxRequestSize)){var t=this._outbox.pop();this.flush(),t&&this._outbox.push(t)}},receive:function(e,t){for(var n=e.length;n--;)e[n].setDeferredStatus("succeeded");t=[].concat(t),this.debug("Client ? received from ?: ?",this._client._clientId,Faye.URI.stringify(this.endpoint),t);for(var i=0,n=t.length;n>i;i++)this._client.receiveMessage(t[i])},handleError:function(e,t){for(var n=e.length;n--;)e[n].setDeferredStatus("failed",t)},_getCookies:function(){var e=this._client.cookies;return e?e.getCookies({domain:this.endpoint.hostname,path:this.endpoint.path,secure:"https:"===this.endpoint.protocol}).toValueString():""},_storeCookies:function(e){if(e&&this._client.cookies){e=[].concat(e);for(var t,n=0,i=e.length;i>n;n++)t=this._client.cookies.setCookie(e[n]),t=t[0]||t,t.domain=t.domain||this.endpoint.hostname}}}),{get:function(e,t,n,i,s){var r=e.endpoint;Faye.asyncEach(this._transports,function(o,a){var c=o[0],u=o[1],h=e.endpoints[c]||r;return Faye.indexOf(n,c)>=0?a():Faye.indexOf(t,c)<0?(u.isUsable(e,h,function(){}),a()):(u.isUsable(e,h,function(t){if(!t)return a();var n=u.hasOwnProperty("create")?u.create(e,h):new u(e,h);i.call(s,n)}),void 0)},function(){throw Error("Could not find a usable connection type for "+Faye.URI.stringify(r))})},register:function(e,t){this._transports.push([e,t]),t.prototype.connectionType=e},_transports:[]}),Faye.extend(Faye.Transport.prototype,Faye.Logging),Faye.extend(Faye.Transport.prototype,Faye.Timeouts),Faye.Event={_registry:[],on:function(e,t,n,i){var s=function(){n.call(i)};e.addEventListener?e.addEventListener(t,s,!1):e.attachEvent("on"+t,s),this._registry.push({_element:e,_type:t,_callback:n,_context:i,_handler:s})},detach:function(e,t,n,i){for(var s,r=this._registry.length;r--;)s=this._registry[r],e&&e!==s._element||t&&t!==s._type||n&&n!==s._callback||i&&i!==s._context||(s._element.removeEventListener?s._element.removeEventListener(s._type,s._handler,!1):s._element.detachEvent("on"+s._type,s._handler),this._registry.splice(r,1),s=null)}},void 0!==Faye.ENV.onunload&&Faye.Event.on(Faye.ENV,"unload",Faye.Event.detach,Faye.Event),"object"!=typeof JSON&&(JSON={}),function(){function f(e){return 10>e?"0"+e:e}function quote(e){return escapable.lastIndex=0,escapable.test(e)?'"'+e.replace(escapable,function(e){var t=meta[e];return"string"==typeof t?t:"\\u"+("0000"+e.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+e+'"'}function str(e,t){var n,i,s,r,o,a=gap,c=t[e];switch(c&&"object"==typeof c&&"function"==typeof c.toJSON&&(c=c.toJSON(e)),"function"==typeof rep&&(c=rep.call(t,e,c)),typeof c){case"string":return quote(c);case"number":return isFinite(c)?c+"":"null";case"boolean":case"null":return c+"";case"object":if(!c)return"null";if(gap+=indent,o=[],"[object Array]"===Object.prototype.toString.apply(c)){for(r=c.length,n=0;r>n;n+=1)o[n]=str(n,c)||"null";return s=0===o.length?"[]":gap?"[\n"+gap+o.join(",\n"+gap)+"\n"+a+"]":"["+o.join(",")+"]",gap=a,s}if(rep&&"object"==typeof rep)for(r=rep.length,n=0;r>n;n+=1)"string"==typeof rep[n]&&(i=rep[n],s=str(i,c),s&&o.push(quote(i)+(gap?": ":":")+s));else for(i in c)Object.prototype.hasOwnProperty.call(c,i)&&(s=str(i,c),s&&o.push(quote(i)+(gap?": ":":")+s));return s=0===o.length?"{}":gap?"{\n"+gap+o.join(",\n"+gap)+"\n"+a+"}":"{"+o.join(",")+"}",gap=a,s}}"function"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()});var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;Faye.stringify=function(e,t,n){var i;if(gap="",indent="","number"==typeof n)for(i=0;n>i;i+=1)indent+=" ";else"string"==typeof n&&(indent=n);if(rep=t,t&&"function"!=typeof t&&("object"!=typeof t||"number"!=typeof t.length))throw Error("JSON.stringify");return str("",{"":e})},"function"!=typeof JSON.stringify&&(JSON.stringify=Faye.stringify),"function"!=typeof JSON.parse&&(JSON.parse=function(text,reviver){function walk(e,t){var n,i,s=e[t];if(s&&"object"==typeof s)for(n in s)Object.prototype.hasOwnProperty.call(s,n)&&(i=walk(s,n),void 0!==i?s[n]=i:delete s[n]);return reviver.call(e,t,s)}var j;if(text+="",cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(e){return"\\u"+("0000"+e.charCodeAt(0).toString(16)).slice(-4)})),/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return j=eval("("+text+")"),"function"==typeof reviver?walk({"":j},""):j;throw new SyntaxError("JSON.parse")})}(),Faye.Transport.WebSocket=Faye.extend(Faye.Class(Faye.Transport,{UNCONNECTED:1,CONNECTING:2,CONNECTED:3,batching:!1,isUsable:function(e,t){this.callback(function(){e.call(t,!0)}),this.errback(function(){e.call(t,!1)}),this.connect()},request:function(e){this._pending=this._pending||new Faye.Set;for(var t=0,n=e.length;n>t;t++)this._pending.add(e[t]);this.callback(function(t){if(t){var n=Faye.map(e,function(e){return e.message});t.send(Faye.toJSON(n))}},this),this.connect()},connect:function(){if(!Faye.Transport.WebSocket._unloaded&&(this._state=this._state||this.UNCONNECTED,this._state===this.UNCONNECTED)){this._state=this.CONNECTING;var e=this._createSocket();if(!e)return this.setDeferredStatus("failed");var t=this;e.onopen=function(){e.headers&&t._storeCookies(e.headers["set-cookie"]),t._socket=e,t._state=t.CONNECTED,t._everConnected=!0,t._ping(),t.setDeferredStatus("succeeded",e)};var n=!1;e.onclose=e.onerror=function(){if(!n){n=!0;var i=t._state===t.CONNECTED;e.onopen=e.onclose=e.onerror=e.onmessage=null,delete t._socket,t._state=t.UNCONNECTED,t.removeTimeout("ping"),t.setDeferredStatus("unknown");var s=t._pending?t._pending.toArray():[];delete t._pending,i?t.handleError(s,!0):t._everConnected?t.handleError(s):t.setDeferredStatus("failed")}},e.onmessage=function(e){var n,i=JSON.parse(e.data),s=[];if(i){i=[].concat(i);for(var r=0,o=i.length;o>r;r++)void 0!==i[r].successful&&(n=t._pending.remove(i[r]),n&&s.push(n));t.receive(s,i)}}}},close:function(){this._socket&&this._socket.close()},_createSocket:function(){var e=Faye.Transport.WebSocket.getSocketUrl(this.endpoint),t={headers:Faye.copyObject(this._client.headers),ca:this._client.ca};return t.headers.Cookie=this._getCookies(),Faye.WebSocket?new Faye.WebSocket.Client(e,[],t):Faye.ENV.MozWebSocket?new MozWebSocket(e):Faye.ENV.WebSocket?new WebSocket(e):void 0},_ping:function(){this._socket&&(this._socket.send("[]"),this.addTimeout("ping",this._client._advice.timeout/2e3,this._ping,this))}}),{PROTOCOLS:{"http:":"ws:","https:":"wss:"},create:function(e,t){var n=e.transports.websocket=e.transports.websocket||{};return n[t.href]=n[t.href]||new this(e,t),n[t.href]},getSocketUrl:function(e){return e=Faye.copyObject(e),e.protocol=this.PROTOCOLS[e.protocol],Faye.URI.stringify(e)},isUsable:function(e,t,n,i){this.create(e,t).isUsable(n,i)}}),Faye.extend(Faye.Transport.WebSocket.prototype,Faye.Deferrable),Faye.Transport.register("websocket",Faye.Transport.WebSocket),Faye.Event&&Faye.Event.on(Faye.ENV,"beforeunload",function(){Faye.Transport.WebSocket._unloaded=!0}),Faye.Transport.EventSource=Faye.extend(Faye.Class(Faye.Transport,{initialize:function(e,t){if(Faye.Transport.prototype.initialize.call(this,e,t),!Faye.ENV.EventSource)return this.setDeferredStatus("failed");this._xhr=new Faye.Transport.XHR(e,t),t=Faye.copyObject(t),t.pathname+="/"+e._clientId;var n=new EventSource(Faye.URI.stringify(t)),i=this;n.onopen=function(){i._everConnected=!0,i.setDeferredStatus("succeeded")},n.onerror=function(){i._everConnected?i._client.messageError([]):(i.setDeferredStatus("failed"),n.close())},n.onmessage=function(e){i.receive([],JSON.parse(e.data))},this._socket=n},close:function(){this._socket&&(this._socket.onopen=this._socket.onerror=this._socket.onmessage=null,this._socket.close(),delete this._socket)},isUsable:function(e,t){this.callback(function(){e.call(t,!0)}),this.errback(function(){e.call(t,!1)})},encode:function(e){return this._xhr.encode(e)},request:function(e){this._xhr.request(e)}}),{isUsable:function(e,t,n,i){var s=e._clientId;
3
- return s?(Faye.Transport.XHR.isUsable(e,t,function(s){return s?(this.create(e,t).isUsable(n,i),void 0):n.call(i,!1)},this),void 0):n.call(i,!1)},create:function(e,t){var n=e.transports.eventsource=e.transports.eventsource||{},i=e._clientId;t=Faye.copyObject(t),t.pathname+="/"+(i||"");var s=Faye.URI.stringify(t);return n[s]=n[s]||new this(e,t),n[s]}}),Faye.extend(Faye.Transport.EventSource.prototype,Faye.Deferrable),Faye.Transport.register("eventsource",Faye.Transport.EventSource),Faye.Transport.XHR=Faye.extend(Faye.Class(Faye.Transport,{encode:function(e){var t=Faye.map(e,function(e){return e.message});return Faye.toJSON(t)},request:function(e){var t=this.endpoint.path,n=Faye.ENV.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest,i=this;n.open("POST",t,!0),n.setRequestHeader("Content-Type","application/json"),n.setRequestHeader("Pragma","no-cache"),n.setRequestHeader("X-Requested-With","XMLHttpRequest");var s=this._client.headers;for(var r in s)s.hasOwnProperty(r)&&n.setRequestHeader(r,s[r]);var o=function(){n.abort()};Faye.Event.on(Faye.ENV,"beforeunload",o),n.onreadystatechange=function(){if(n&&4===n.readyState){var t=null,s=n.status,r=n.responseText,a=s>=200&&300>s||304===s||1223===s;if(Faye.Event.detach(Faye.ENV,"beforeunload",o),n.onreadystatechange=function(){},n=null,!a)return i.handleError(e);try{t=JSON.parse(r)}catch(c){}t?i.receive(e,t):i.handleError(e)}},n.send(this.encode(e))}}),{isUsable:function(e,t,n,i){n.call(i,Faye.URI.isSameOrigin(t))}}),Faye.Transport.register("long-polling",Faye.Transport.XHR),Faye.Transport.CORS=Faye.extend(Faye.Class(Faye.Transport,{encode:function(e){var t=Faye.map(e,function(e){return e.message});return"message="+encodeURIComponent(Faye.toJSON(t))},request:function(e){var t,n=Faye.ENV.XDomainRequest?XDomainRequest:XMLHttpRequest,i=new n,s=this._client.headers,r=this;if(i.open("POST",Faye.URI.stringify(this.endpoint),!0),i.setRequestHeader){i.setRequestHeader("Pragma","no-cache");for(t in s)s.hasOwnProperty(t)&&i.setRequestHeader(t,s[t])}var o=function(){return i?(i.onload=i.onerror=i.ontimeout=i.onprogress=null,i=null,void 0):!1};i.onload=function(){var t=null;try{t=JSON.parse(i.responseText)}catch(n){}o(),t?r.receive(e,t):r.handleError(e)},i.onerror=i.ontimeout=function(){o(),r.handleError(e)},i.onprogress=function(){},i.send(this.encode(e))}}),{isUsable:function(e,t,n,i){if(Faye.URI.isSameOrigin(t))return n.call(i,!1);if(Faye.ENV.XDomainRequest)return n.call(i,t.protocol===Faye.ENV.location.protocol);if(Faye.ENV.XMLHttpRequest){var s=new Faye.ENV.XMLHttpRequest;return n.call(i,void 0!==s.withCredentials)}return n.call(i,!1)}}),Faye.Transport.register("cross-origin-long-polling",Faye.Transport.CORS),Faye.Transport.JSONP=Faye.extend(Faye.Class(Faye.Transport,{encode:function(e){var t=Faye.map(e,function(e){return e.message}),n=Faye.copyObject(this.endpoint);return n.query.message=Faye.toJSON(t),n.query.jsonp="__jsonp"+Faye.Transport.JSONP._cbCount+"__",Faye.URI.stringify(n)},request:function(e){var t=Faye.map(e,function(e){return e.message}),n=document.getElementsByTagName("head")[0],i=document.createElement("script"),s=Faye.Transport.JSONP.getCallbackName(),r=Faye.copyObject(this.endpoint),o=this;r.query.message=Faye.toJSON(t),r.query.jsonp=s,Faye.ENV[s]=function(t){if(!Faye.ENV[s])return!1;Faye.ENV[s]=void 0;try{delete Faye.ENV[s]}catch(n){}i.parentNode.removeChild(i),o.receive(e,t)},i.type="text/javascript",i.src=Faye.URI.stringify(r),n.appendChild(i)}}),{_cbCount:0,getCallbackName:function(){return this._cbCount+=1,"__jsonp"+this._cbCount+"__"},isUsable:function(e,t,n,i){n.call(i,!0)}}),Faye.Transport.register("callback-polling",Faye.Transport.JSONP)}();
4
- //@ sourceMappingURL=faye-browser-min.js.map
2
+ !function(){"use strict";var Faye={VERSION:"1.1.1",BAYEUX_VERSION:"1.0",ID_LENGTH:160,JSONP_CALLBACK:"jsonpcallback",CONNECTION_TYPES:["long-polling","cross-origin-long-polling","callback-polling","websocket","eventsource","in-process"],MANDATORY_CONNECTION_TYPES:["long-polling","callback-polling","in-process"],ENV:"undefined"!=typeof window?window:global,extend:function(e,t,n){if(!t)return e;for(var i in t)t.hasOwnProperty(i)&&(e.hasOwnProperty(i)&&n===!1||e[i]!==t[i]&&(e[i]=t[i]));return e},random:function(e){e=e||this.ID_LENGTH;for(var t=Math.ceil(e*Math.log(2)/Math.log(36)),n=csprng(e,36);n.length<t;)n="0"+n;return n},validateOptions:function(e,t){for(var n in e)if(this.indexOf(t,n)<0)throw Error("Unrecognized option: "+n)},clientIdFromMessages:function(e){var t=this.filter([].concat(e),function(e){return"/meta/connect"===e.channel});return t[0]&&t[0].clientId},copyObject:function(e){var t,n,i;if(e instanceof Array){for(t=[],n=e.length;n--;)t[n]=Faye.copyObject(e[n]);return t}if("object"==typeof e){t=null===e?null:{};for(i in e)t[i]=Faye.copyObject(e[i]);return t}return e},commonElement:function(e,t){for(var n=0,i=e.length;i>n;n++)if(-1!==this.indexOf(t,e[n]))return e[n];return null},indexOf:function(e,t){if(e.indexOf)return e.indexOf(t);for(var n=0,i=e.length;i>n;n++)if(e[n]===t)return n;return-1},map:function(e,t,n){if(e.map)return e.map(t,n);var i=[];if(e instanceof Array)for(var s=0,r=e.length;r>s;s++)i.push(t.call(n||null,e[s],s));else for(var o in e)e.hasOwnProperty(o)&&i.push(t.call(n||null,o,e[o]));return i},filter:function(e,t,n){if(e.filter)return e.filter(t,n);for(var i=[],s=0,r=e.length;r>s;s++)t.call(n||null,e[s],s)&&i.push(e[s]);return i},asyncEach:function(e,t,n,i){var s=e.length,r=-1,o=0,a=!1,c=function(){return o-=1,r+=1,r===s?n&&n.call(i):void t(e[r],u)},h=function(){if(!a){for(a=!0;o>0;)c();a=!1}},u=function(){o+=1,h()};u()},toJSON:function(e){return this.stringify?this.stringify(e,function(e,t){return this[e]instanceof Array?this[e]:t}):JSON.stringify(e)}};"undefined"!=typeof module?module.exports=Faye:"undefined"!=typeof window&&(window.Faye=Faye),Faye.Class=function(e,t){"function"!=typeof e&&(t=e,e=Object);var n=function(){return this.initialize?this.initialize.apply(this,arguments)||this:this},i=function(){};return i.prototype=e.prototype,n.prototype=new i,Faye.extend(n.prototype,t),n},function(){function e(e,t){if(e.indexOf)return e.indexOf(t);for(var n=0;n<e.length;n++)if(t===e[n])return n;return-1}var t=Faye.EventEmitter=function(){},n="function"==typeof Array.isArray?Array.isArray:function(e){return"[object Array]"===Object.prototype.toString.call(e)};t.prototype.emit=function(e){if("error"===e&&(!this._events||!this._events.error||n(this._events.error)&&!this._events.error.length))throw arguments[1]instanceof Error?arguments[1]:Error("Uncaught, unspecified 'error' event.");if(!this._events)return!1;var t=this._events[e];if(!t)return!1;if("function"==typeof t){switch(arguments.length){case 1:t.call(this);break;case 2:t.call(this,arguments[1]);break;case 3:t.call(this,arguments[1],arguments[2]);break;default:var i=Array.prototype.slice.call(arguments,1);t.apply(this,i)}return!0}if(n(t)){for(var i=Array.prototype.slice.call(arguments,1),s=t.slice(),r=0,o=s.length;o>r;r++)s[r].apply(this,i);return!0}return!1},t.prototype.addListener=function(e,t){if("function"!=typeof t)throw Error("addListener only takes instances of Function");return this._events||(this._events={}),this.emit("newListener",e,t),this._events[e]?n(this._events[e])?this._events[e].push(t):this._events[e]=[this._events[e],t]:this._events[e]=t,this},t.prototype.on=t.prototype.addListener,t.prototype.once=function(e,t){var n=this;return n.on(e,function i(){n.removeListener(e,i),t.apply(this,arguments)}),this},t.prototype.removeListener=function(t,i){if("function"!=typeof i)throw Error("removeListener only takes instances of Function");if(!this._events||!this._events[t])return this;var s=this._events[t];if(n(s)){var r=e(s,i);if(0>r)return this;s.splice(r,1),0==s.length&&delete this._events[t]}else this._events[t]===i&&delete this._events[t];return this},t.prototype.removeAllListeners=function(e){return 0===arguments.length?(this._events={},this):(e&&this._events&&this._events[e]&&(this._events[e]=null),this)},t.prototype.listeners=function(e){return this._events||(this._events={}),this._events[e]||(this._events[e]=[]),n(this._events[e])||(this._events[e]=[this._events[e]]),this._events[e]}}(),Faye.Namespace=Faye.Class({initialize:function(){this._used={}},exists:function(e){return this._used.hasOwnProperty(e)},generate:function(){for(var e=Faye.random();this._used.hasOwnProperty(e);)e=Faye.random();return this._used[e]=e},release:function(e){delete this._used[e]}}),function(){var e,t=setTimeout;e="function"==typeof setImmediate?function(e){setImmediate(e)}:"object"==typeof process&&process.nextTick?function(e){process.nextTick(e)}:function(e){t(e,0)};var n=0,i=1,s=2,r=function(e){return e},o=function(e){throw e},a=function(e){if(this._state=n,this._onFulfilled=[],this._onRejected=[],"function"==typeof e){var t=this;e(function(e){f(t,e)},function(e){d(t,e)})}};a.prototype.then=function(e,t){var n=new a;return c(this,e,n),h(this,t,n),n};var c=function(e,t,s){"function"!=typeof t&&(t=r);var o=function(e){u(t,e,s)};e._state===n?e._onFulfilled.push(o):e._state===i&&o(e._value)},h=function(e,t,i){"function"!=typeof t&&(t=o);var r=function(e){u(t,e,i)};e._state===n?e._onRejected.push(r):e._state===s&&r(e._reason)},u=function(t,n,i){e(function(){l(t,n,i)})},l=function(e,t,n){var i;try{i=e(t)}catch(s){return d(n,s)}i===n?d(n,new TypeError("Recursive promise chain detected")):f(n,i)},f=a.fulfill=a.resolve=function(e,t){var n,i,s=!1;try{if(n=typeof t,i=null!==t&&("function"===n||"object"===n)&&t.then,"function"!=typeof i)return p(e,t);i.call(t,function(t){s^(s=!0)&&f(e,t)},function(t){s^(s=!0)&&d(e,t)})}catch(r){if(!(s^(s=!0)))return;d(e,r)}},p=function(e,t){if(e._state===n){e._state=i,e._value=t,e._onRejected=[];for(var s,r=e._onFulfilled;s=r.shift();)s(t)}},d=a.reject=function(e,t){if(e._state===n){e._state=s,e._reason=t,e._onFulfilled=[];for(var i,r=e._onRejected;i=r.shift();)i(t)}};a.all=function(e){return new a(function(t,n){var i,s=[],r=e.length;if(0===r)return t(s);for(i=0;r>i;i++)(function(e,i){a.fulfilled(e).then(function(e){s[i]=e,0===--r&&t(s)},n)})(e[i],i)})},a.defer=e,a.deferred=a.pending=function(){var e={};return e.promise=new a(function(t,n){e.fulfill=e.resolve=t,e.reject=n}),e},a.fulfilled=a.resolved=function(e){return new a(function(t){t(e)})},a.rejected=function(e){return new a(function(t,n){n(e)})},void 0===Faye?module.exports=a:Faye.Promise=a}(),Faye.Set=Faye.Class({initialize:function(){this._index={}},add:function(e){var t=void 0!==e.id?e.id:e;return this._index.hasOwnProperty(t)?!1:(this._index[t]=e,!0)},forEach:function(e,t){for(var n in this._index)this._index.hasOwnProperty(n)&&e.call(t,this._index[n])},isEmpty:function(){for(var e in this._index)if(this._index.hasOwnProperty(e))return!1;return!0},member:function(e){for(var t in this._index)if(this._index[t]===e)return!0;return!1},remove:function(e){var t=void 0!==e.id?e.id:e,n=this._index[t];return delete this._index[t],n},toArray:function(){var e=[];return this.forEach(function(t){e.push(t)}),e}}),Faye.URI={isURI:function(e){return e&&e.protocol&&e.host&&e.path},isSameOrigin:function(e){var t=Faye.ENV.location;return e.protocol===t.protocol&&e.hostname===t.hostname&&e.port===t.port},parse:function(e){if("string"!=typeof e)return e;var t,n,i,s,r,o,a={},c=function(t,n){e=e.replace(n,function(e){return a[t]=e,""}),a[t]=a[t]||""};for(c("protocol",/^[a-z]+\:/i),c("host",/^\/\/[^\/\?#]+/),/^\//.test(e)||a.host||(e=Faye.ENV.location.pathname.replace(/[^\/]*$/,"")+e),c("pathname",/^[^\?#]*/),c("search",/^\?[^#]*/),c("hash",/^#.*/),a.protocol=a.protocol||Faye.ENV.location.protocol,a.host?(a.host=a.host.substr(2),t=a.host.split(":"),a.hostname=t[0],a.port=t[1]||""):(a.host=Faye.ENV.location.host,a.hostname=Faye.ENV.location.hostname,a.port=Faye.ENV.location.port),a.pathname=a.pathname||"/",a.path=a.pathname+a.search,n=a.search.replace(/^\?/,""),i=n?n.split("&"):[],o={},s=0,r=i.length;r>s;s++)t=i[s].split("="),o[decodeURIComponent(t[0]||"")]=decodeURIComponent(t[1]||"");return a.query=o,a.href=this.stringify(a),a},stringify:function(e){var t=e.protocol+"//"+e.hostname;return e.port&&(t+=":"+e.port),t+=e.pathname+this.queryString(e.query)+(e.hash||"")},queryString:function(e){var t=[];for(var n in e)e.hasOwnProperty(n)&&t.push(encodeURIComponent(n)+"="+encodeURIComponent(e[n]));return 0===t.length?"":"?"+t.join("&")}},Faye.Error=Faye.Class({initialize:function(e,t,n){this.code=e,this.params=Array.prototype.slice.call(t),this.message=n},toString:function(){return this.code+":"+this.params.join(",")+":"+this.message}}),Faye.Error.parse=function(e){if(e=e||"",!Faye.Grammar.ERROR.test(e))return new this(null,[],e);var t=e.split(":"),n=parseInt(t[0]),i=t[1].split(","),e=t[2];return new this(n,i,e)},Faye.Error.versionMismatch=function(){return""+new this(300,arguments,"Version mismatch")},Faye.Error.conntypeMismatch=function(){return""+new this(301,arguments,"Connection types not supported")},Faye.Error.extMismatch=function(){return""+new this(302,arguments,"Extension mismatch")},Faye.Error.badRequest=function(){return""+new this(400,arguments,"Bad request")},Faye.Error.clientUnknown=function(){return""+new this(401,arguments,"Unknown client")},Faye.Error.parameterMissing=function(){return""+new this(402,arguments,"Missing required parameter")},Faye.Error.channelForbidden=function(){return""+new this(403,arguments,"Forbidden channel")},Faye.Error.channelUnknown=function(){return""+new this(404,arguments,"Unknown channel")},Faye.Error.channelInvalid=function(){return""+new this(405,arguments,"Invalid channel")},Faye.Error.extUnknown=function(){return""+new this(406,arguments,"Unknown extension")},Faye.Error.publishFailed=function(){return""+new this(407,arguments,"Failed to publish")},Faye.Error.serverError=function(){return""+new this(500,arguments,"Internal server error")},Faye.Deferrable={then:function(e,t){var n=this;return this._promise||(this._promise=new Faye.Promise(function(e,t){n._fulfill=e,n._reject=t})),0===arguments.length?this._promise:this._promise.then(e,t)},callback:function(e,t){return this.then(function(n){e.call(t,n)})},errback:function(e,t){return this.then(null,function(n){e.call(t,n)})},timeout:function(e,t){this.then();var n=this;this._timer=Faye.ENV.setTimeout(function(){n._reject(t)},1e3*e)},setDeferredStatus:function(e,t){this._timer&&Faye.ENV.clearTimeout(this._timer),this.then(),"succeeded"===e?this._fulfill(t):"failed"===e?this._reject(t):delete this._promise}},Faye.Publisher={countListeners:function(e){return this.listeners(e).length},bind:function(e,t,n){var i=Array.prototype.slice,s=function(){t.apply(n,i.call(arguments))};return this._listeners=this._listeners||[],this._listeners.push([e,t,n,s]),this.on(e,s)},unbind:function(e,t,n){this._listeners=this._listeners||[];for(var i,s=this._listeners.length;s--;)i=this._listeners[s],i[0]===e&&(!t||i[1]===t&&i[2]===n)&&(this._listeners.splice(s,1),this.removeListener(e,i[3]))}},Faye.extend(Faye.Publisher,Faye.EventEmitter.prototype),Faye.Publisher.trigger=Faye.Publisher.emit,Faye.Timeouts={addTimeout:function(e,t,n,i){if(this._timeouts=this._timeouts||{},!this._timeouts.hasOwnProperty(e)){var s=this;this._timeouts[e]=Faye.ENV.setTimeout(function(){delete s._timeouts[e],n.call(i)},1e3*t)}},removeTimeout:function(e){this._timeouts=this._timeouts||{};var t=this._timeouts[e];t&&(Faye.ENV.clearTimeout(t),delete this._timeouts[e])},removeAllTimeouts:function(){this._timeouts=this._timeouts||{};for(var e in this._timeouts)this.removeTimeout(e)}},Faye.Logging={LOG_LEVELS:{fatal:4,error:3,warn:2,info:1,debug:0},writeLog:function(e,t){if(Faye.logger){var n=Array.prototype.slice.apply(e),i="[Faye",s=this.className,r=n.shift().replace(/\?/g,function(){try{return Faye.toJSON(n.shift())}catch(e){return"[Object]"}});for(var o in Faye)s||"function"==typeof Faye[o]&&this instanceof Faye[o]&&(s=o);s&&(i+="."+s),i+="] ","function"==typeof Faye.logger[t]?Faye.logger[t](i+r):"function"==typeof Faye.logger&&Faye.logger(i+r)}}},function(){for(var e in Faye.Logging.LOG_LEVELS)(function(e){Faye.Logging[e]=function(){this.writeLog(arguments,e)}})(e)}(),Faye.Grammar={CHANNEL_NAME:/^\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,CHANNEL_PATTERN:/^(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*\/\*{1,2}$/,ERROR:/^([0-9][0-9][0-9]:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*|[0-9][0-9][0-9]::(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)$/,VERSION:/^([0-9])+(\.(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*)*$/},Faye.Extensible={addExtension:function(e){this._extensions=this._extensions||[],this._extensions.push(e),e.added&&e.added(this)},removeExtension:function(e){if(this._extensions)for(var t=this._extensions.length;t--;)this._extensions[t]===e&&(this._extensions.splice(t,1),e.removed&&e.removed(this))},pipeThroughExtensions:function(e,t,n,i,s){if(this.debug("Passing through ? extensions: ?",e,t),!this._extensions)return i.call(s,t);var r=this._extensions.slice(),o=function(t){if(!t)return i.call(s,t);var a=r.shift();if(!a)return i.call(s,t);var c=a[e];return c?void(c.length>=3?a[e](t,n,o):a[e](t,o)):o(t)};o(t)}},Faye.extend(Faye.Extensible,Faye.Logging),Faye.Channel=Faye.Class({initialize:function(e){this.id=this.name=e},push:function(e){this.trigger("message",e)},isUnused:function(){return 0===this.countListeners("message")}}),Faye.extend(Faye.Channel.prototype,Faye.Publisher),Faye.extend(Faye.Channel,{HANDSHAKE:"/meta/handshake",CONNECT:"/meta/connect",SUBSCRIBE:"/meta/subscribe",UNSUBSCRIBE:"/meta/unsubscribe",DISCONNECT:"/meta/disconnect",META:"meta",SERVICE:"service",expand:function(e){var t=this.parse(e),n=["/**",e],i=t.slice();i[i.length-1]="*",n.push(this.unparse(i));for(var s=1,r=t.length;r>s;s++)i=t.slice(0,s),i.push("**"),n.push(this.unparse(i));return n},isValid:function(e){return Faye.Grammar.CHANNEL_NAME.test(e)||Faye.Grammar.CHANNEL_PATTERN.test(e)},parse:function(e){return this.isValid(e)?e.split("/").slice(1):null},unparse:function(e){return"/"+e.join("/")},isMeta:function(e){var t=this.parse(e);return t?t[0]===this.META:null},isService:function(e){var t=this.parse(e);return t?t[0]===this.SERVICE:null},isSubscribable:function(e){return this.isValid(e)?!this.isMeta(e)&&!this.isService(e):null},Set:Faye.Class({initialize:function(){this._channels={}},getKeys:function(){var e=[];for(var t in this._channels)e.push(t);return e},remove:function(e){delete this._channels[e]},hasSubscription:function(e){return this._channels.hasOwnProperty(e)},subscribe:function(e,t,n){for(var i,s=0,r=e.length;r>s;s++){i=e[s];var o=this._channels[i]=this._channels[i]||new Faye.Channel(i);t&&o.bind("message",t,n)}},unsubscribe:function(e,t,n){var i=this._channels[e];return i?(i.unbind("message",t,n),i.isUnused()?(this.remove(e),!0):!1):!1},distributeMessage:function(e){for(var t=Faye.Channel.expand(e.channel),n=0,i=t.length;i>n;n++){var s=this._channels[t[n]];s&&s.trigger("message",e.data)}}})}),Faye.Publication=Faye.Class(Faye.Deferrable),Faye.Subscription=Faye.Class({initialize:function(e,t,n,i){this._client=e,this._channels=t,this._callback=n,this._context=i,this._cancelled=!1},cancel:function(){this._cancelled||(this._client.unsubscribe(this._channels,this._callback,this._context),this._cancelled=!0)},unsubscribe:function(){this.cancel()}}),Faye.extend(Faye.Subscription.prototype,Faye.Deferrable),Faye.Client=Faye.Class({UNCONNECTED:1,CONNECTING:2,CONNECTED:3,DISCONNECTED:4,HANDSHAKE:"handshake",RETRY:"retry",NONE:"none",CONNECTION_TIMEOUT:60,DEFAULT_ENDPOINT:"/bayeux",INTERVAL:0,initialize:function(e,t){this.info("New client created for ?",e),t=t||{},Faye.validateOptions(t,["interval","timeout","endpoints","proxy","retry","scheduler","websocketExtensions","tls","ca"]),this._endpoint=e||this.DEFAULT_ENDPOINT,this._channels=new Faye.Channel.Set,this._dispatcher=new Faye.Dispatcher(this,this._endpoint,t),this._messageId=0,this._state=this.UNCONNECTED,this._responseCallbacks={},this._advice={reconnect:this.RETRY,interval:1e3*(t.interval||this.INTERVAL),timeout:1e3*(t.timeout||this.CONNECTION_TIMEOUT)},this._dispatcher.timeout=this._advice.timeout/1e3,this._dispatcher.bind("message",this._receiveMessage,this),Faye.Event&&void 0!==Faye.ENV.onbeforeunload&&Faye.Event.on(Faye.ENV,"beforeunload",function(){Faye.indexOf(this._dispatcher._disabled,"autodisconnect")<0&&this.disconnect()},this)},addWebsocketExtension:function(e){return this._dispatcher.addWebsocketExtension(e)},disable:function(e){return this._dispatcher.disable(e)},setHeader:function(e,t){return this._dispatcher.setHeader(e,t)},handshake:function(e,t){if(this._advice.reconnect!==this.NONE&&this._state===this.UNCONNECTED){this._state=this.CONNECTING;var n=this;this.info("Initiating handshake with ?",Faye.URI.stringify(this._endpoint)),this._dispatcher.selectTransport(Faye.MANDATORY_CONNECTION_TYPES),this._sendMessage({channel:Faye.Channel.HANDSHAKE,version:Faye.BAYEUX_VERSION,supportedConnectionTypes:this._dispatcher.getConnectionTypes()},{},function(i){i.successful?(this._state=this.CONNECTED,this._dispatcher.clientId=i.clientId,this._dispatcher.selectTransport(i.supportedConnectionTypes),this.info("Handshake successful: ?",this._dispatcher.clientId),this.subscribe(this._channels.getKeys(),!0),e&&Faye.Promise.defer(function(){e.call(t)})):(this.info("Handshake unsuccessful"),Faye.ENV.setTimeout(function(){n.handshake(e,t)},1e3*this._dispatcher.retry),this._state=this.UNCONNECTED)},this)}},connect:function(e,t){if(this._advice.reconnect!==this.NONE&&this._state!==this.DISCONNECTED){if(this._state===this.UNCONNECTED)return this.handshake(function(){this.connect(e,t)},this);this.callback(e,t),this._state===this.CONNECTED&&(this.info("Calling deferred actions for ?",this._dispatcher.clientId),this.setDeferredStatus("succeeded"),this.setDeferredStatus("unknown"),this._connectRequest||(this._connectRequest=!0,this.info("Initiating connection for ?",this._dispatcher.clientId),this._sendMessage({channel:Faye.Channel.CONNECT,clientId:this._dispatcher.clientId,connectionType:this._dispatcher.connectionType},{},this._cycleConnection,this)))}},disconnect:function(){if(this._state===this.CONNECTED){this._state=this.DISCONNECTED,this.info("Disconnecting ?",this._dispatcher.clientId);var e=new Faye.Publication;return this._sendMessage({channel:Faye.Channel.DISCONNECT,clientId:this._dispatcher.clientId},{},function(t){t.successful?(this._dispatcher.close(),e.setDeferredStatus("succeeded")):e.setDeferredStatus("failed",Faye.Error.parse(t.error))},this),this.info("Clearing channel listeners for ?",this._dispatcher.clientId),this._channels=new Faye.Channel.Set,e}},subscribe:function(e,t,n){if(e instanceof Array)return Faye.map(e,function(e){return this.subscribe(e,t,n)},this);var i=new Faye.Subscription(this,e,t,n),s=t===!0,r=this._channels.hasSubscription(e);return r&&!s?(this._channels.subscribe([e],t,n),i.setDeferredStatus("succeeded"),i):(this.connect(function(){this.info("Client ? attempting to subscribe to ?",this._dispatcher.clientId,e),s||this._channels.subscribe([e],t,n),this._sendMessage({channel:Faye.Channel.SUBSCRIBE,clientId:this._dispatcher.clientId,subscription:e},{},function(s){if(!s.successful)return i.setDeferredStatus("failed",Faye.Error.parse(s.error)),this._channels.unsubscribe(e,t,n);var r=[].concat(s.subscription);this.info("Subscription acknowledged for ? to ?",this._dispatcher.clientId,r),i.setDeferredStatus("succeeded")},this)},this),i)},unsubscribe:function(e,t,n){if(e instanceof Array)return Faye.map(e,function(e){return this.unsubscribe(e,t,n)},this);var i=this._channels.unsubscribe(e,t,n);i&&this.connect(function(){this.info("Client ? attempting to unsubscribe from ?",this._dispatcher.clientId,e),this._sendMessage({channel:Faye.Channel.UNSUBSCRIBE,clientId:this._dispatcher.clientId,subscription:e},{},function(e){if(e.successful){var t=[].concat(e.subscription);this.info("Unsubscription acknowledged for ? from ?",this._dispatcher.clientId,t)}},this)},this)},publish:function(e,t,n){Faye.validateOptions(n||{},["attempts","deadline"]);var i=new Faye.Publication;return this.connect(function(){this.info("Client ? queueing published message to ?: ?",this._dispatcher.clientId,e,t),this._sendMessage({channel:e,data:t,clientId:this._dispatcher.clientId},n,function(e){e.successful?i.setDeferredStatus("succeeded"):i.setDeferredStatus("failed",Faye.Error.parse(e.error))},this)},this),i},_sendMessage:function(e,t,n,i){e.id=this._generateMessageId();var s=this._advice.timeout?1.2*this._advice.timeout/1e3:1.2*this._dispatcher.retry;this.pipeThroughExtensions("outgoing",e,null,function(e){e&&(n&&(this._responseCallbacks[e.id]=[n,i]),this._dispatcher.sendMessage(e,s,t||{}))},this)},_generateMessageId:function(){return this._messageId+=1,this._messageId>=Math.pow(2,32)&&(this._messageId=0),this._messageId.toString(36)},_receiveMessage:function(e){var t,n=e.id;void 0!==e.successful&&(t=this._responseCallbacks[n],delete this._responseCallbacks[n]),this.pipeThroughExtensions("incoming",e,null,function(e){e&&(e.advice&&this._handleAdvice(e.advice),this._deliverMessage(e),t&&t[0].call(t[1],e))},this)},_handleAdvice:function(e){Faye.extend(this._advice,e),this._dispatcher.timeout=this._advice.timeout/1e3,this._advice.reconnect===this.HANDSHAKE&&this._state!==this.DISCONNECTED&&(this._state=this.UNCONNECTED,this._dispatcher.clientId=null,this._cycleConnection())},_deliverMessage:function(e){e.channel&&void 0!==e.data&&(this.info("Client ? calling listeners for ? with ?",this._dispatcher.clientId,e.channel,e.data),this._channels.distributeMessage(e))},_cycleConnection:function(){this._connectRequest&&(this._connectRequest=null,this.info("Closed connection for ?",this._dispatcher.clientId));var e=this;Faye.ENV.setTimeout(function(){e.connect()},this._advice.interval)}}),Faye.extend(Faye.Client.prototype,Faye.Deferrable),Faye.extend(Faye.Client.prototype,Faye.Publisher),Faye.extend(Faye.Client.prototype,Faye.Logging),Faye.extend(Faye.Client.prototype,Faye.Extensible),Faye.Dispatcher=Faye.Class({MAX_REQUEST_SIZE:2048,DEFAULT_RETRY:5,UP:1,DOWN:2,initialize:function(e,t,n){this._client=e,this.endpoint=Faye.URI.parse(t),this._alternates=n.endpoints||{},this.cookies=Faye.Cookies&&new Faye.Cookies.CookieJar,this._disabled=[],this._envelopes={},this.headers={},this.retry=n.retry||this.DEFAULT_RETRY,this._scheduler=n.scheduler||Faye.Scheduler,this._state=0,this.transports={},this.wsExtensions=[],this.proxy=n.proxy||{},"string"==typeof this._proxy&&(this._proxy={origin:this._proxy});var i=n.websocketExtensions;if(i){i=[].concat(i);for(var s=0,r=i.length;r>s;s++)this.addWebsocketExtension(i[s])}this.tls=n.tls||{},this.tls.ca=this.tls.ca||n.ca;for(var o in this._alternates)this._alternates[o]=Faye.URI.parse(this._alternates[o]);this.maxRequestSize=this.MAX_REQUEST_SIZE},endpointFor:function(e){return this._alternates[e]||this.endpoint},addWebsocketExtension:function(e){this.wsExtensions.push(e)},disable:function(e){this._disabled.push(e)},setHeader:function(e,t){this.headers[e]=t},close:function(){var e=this._transport;delete this._transport,e&&e.close()},getConnectionTypes:function(){return Faye.Transport.getConnectionTypes()},selectTransport:function(e){Faye.Transport.get(this,e,this._disabled,function(e){this.debug("Selected ? transport for ?",e.connectionType,Faye.URI.stringify(e.endpoint)),e!==this._transport&&(this._transport&&this._transport.close(),this._transport=e,this.connectionType=e.connectionType)},this)},sendMessage:function(e,t,n){n=n||{};var i,s=e.id,r=n.attempts,o=n.deadline&&(new Date).getTime()+1e3*n.deadline,a=this._envelopes[s];a||(i=new this._scheduler(e,{timeout:t,interval:this.retry,attempts:r,deadline:o}),a=this._envelopes[s]={message:e,scheduler:i}),this._sendEnvelope(a)},_sendEnvelope:function(e){if(this._transport&&!e.request&&!e.timer){var t=e.message,n=e.scheduler,i=this;if(!n.isDeliverable())return n.abort(),void delete this._envelopes[t.id];e.timer=Faye.ENV.setTimeout(function(){i.handleError(t)},1e3*n.getTimeout()),n.send(),e.request=this._transport.sendMessage(t)}},handleResponse:function(e){var t=this._envelopes[e.id];void 0!==e.successful&&t&&(t.scheduler.succeed(),delete this._envelopes[e.id],Faye.ENV.clearTimeout(t.timer)),this.trigger("message",e),this._state!==this.UP&&(this._state=this.UP,this._client.trigger("transport:up"))},handleError:function(e,t){var n=this._envelopes[e.id],i=n&&n.request,s=this;if(i){i.then(function(e){e&&e.abort&&e.abort()});var r=n.scheduler;r.fail(),Faye.ENV.clearTimeout(n.timer),n.request=n.timer=null,t?this._sendEnvelope(n):n.timer=Faye.ENV.setTimeout(function(){n.timer=null,s._sendEnvelope(n)},1e3*r.getInterval()),this._state!==this.DOWN&&(this._state=this.DOWN,this._client.trigger("transport:down"))}}}),Faye.extend(Faye.Dispatcher.prototype,Faye.Publisher),Faye.extend(Faye.Dispatcher.prototype,Faye.Logging),Faye.Scheduler=function(e,t){this.message=e,this.options=t,this.attempts=0},Faye.extend(Faye.Scheduler.prototype,{getTimeout:function(){return this.options.timeout},getInterval:function(){return this.options.interval},isDeliverable:function(){var e=this.options.attempts,t=this.attempts,n=this.options.deadline,i=(new Date).getTime();return void 0!==e&&t>=e?!1:void 0!==n&&i>n?!1:!0},send:function(){this.attempts+=1},succeed:function(){},fail:function(){},abort:function(){}}),Faye.Transport=Faye.extend(Faye.Class({DEFAULT_PORTS:{"http:":80,"https:":443,"ws:":80,"wss:":443},SECURE_PROTOCOLS:["https:","wss:"],MAX_DELAY:0,batching:!0,initialize:function(e,t){this._dispatcher=e,this.endpoint=t,this._outbox=[],this._proxy=Faye.extend({},this._dispatcher.proxy),!this._proxy.origin&&Faye.NodeAdapter&&(this._proxy.origin=Faye.indexOf(this.SECURE_PROTOCOLS,this.endpoint.protocol)>=0?process.env.HTTPS_PROXY||process.env.https_proxy:process.env.HTTP_PROXY||process.env.http_proxy)},close:function(){},encode:function(){return""},sendMessage:function(e){return this.debug("Client ? sending message to ?: ?",this._dispatcher.clientId,Faye.URI.stringify(this.endpoint),e),this.batching?(this._outbox.push(e),this._flushLargeBatch(),this._promise=this._promise||new Faye.Promise,e.channel===Faye.Channel.HANDSHAKE?(this.addTimeout("publish",.01,this._flush,this),this._promise):(e.channel===Faye.Channel.CONNECT&&(this._connectMessage=e),this.addTimeout("publish",this.MAX_DELAY,this._flush,this),this._promise)):Faye.Promise.fulfilled(this.request([e]))},_flush:function(){this.removeTimeout("publish"),this._outbox.length>1&&this._connectMessage&&(this._connectMessage.advice={timeout:0}),Faye.Promise.fulfill(this._promise,this.request(this._outbox)),delete this._promise,this._connectMessage=null,this._outbox=[]},_flushLargeBatch:function(){var e=this.encode(this._outbox);if(!(e.length<this._dispatcher.maxRequestSize)){var t=this._outbox.pop();this._flush(),t&&this._outbox.push(t)}},_receive:function(e){if(e){e=[].concat(e),this.debug("Client ? received from ? via ?: ?",this._dispatcher.clientId,Faye.URI.stringify(this.endpoint),this.connectionType,e);for(var t=0,n=e.length;n>t;t++)this._dispatcher.handleResponse(e[t])}},_handleError:function(e){e=[].concat(e),this.debug("Client ? failed to send to ? via ?: ?",this._dispatcher.clientId,Faye.URI.stringify(this.endpoint),this.connectionType,e);for(var t=0,n=e.length;n>t;t++)this._dispatcher.handleError(e[t])},_getCookies:function(){var e=this._dispatcher.cookies,t=Faye.URI.stringify(this.endpoint);return e?Faye.map(e.getCookiesSync(t),function(e){return e.cookieString()}).join("; "):""},_storeCookies:function(e){var t,n=this._dispatcher.cookies,i=Faye.URI.stringify(this.endpoint);if(e&&n){e=[].concat(e);for(var s=0,r=e.length;r>s;s++)t=Faye.Cookies.Cookie.parse(e[s]),n.setCookieSync(t,i)}}}),{get:function(e,t,n,i,s){var r=e.endpoint;Faye.asyncEach(this._transports,function(r,o){var a=r[0],c=r[1],h=e.endpointFor(a);return Faye.indexOf(n,a)>=0?o():Faye.indexOf(t,a)<0?(c.isUsable(e,h,function(){}),o()):void c.isUsable(e,h,function(t){if(!t)return o();var n=c.hasOwnProperty("create")?c.create(e,h):new c(e,h);i.call(s,n)})},function(){throw Error("Could not find a usable connection type for "+Faye.URI.stringify(r))})},register:function(e,t){this._transports.push([e,t]),t.prototype.connectionType=e},getConnectionTypes:function(){return Faye.map(this._transports,function(e){return e[0]})},_transports:[]}),Faye.extend(Faye.Transport.prototype,Faye.Logging),Faye.extend(Faye.Transport.prototype,Faye.Timeouts),Faye.Event={_registry:[],on:function(e,t,n,i){var s=function(){n.call(i)};e.addEventListener?e.addEventListener(t,s,!1):e.attachEvent("on"+t,s),this._registry.push({_element:e,_type:t,_callback:n,_context:i,_handler:s})},detach:function(e,t,n,i){for(var s,r=this._registry.length;r--;)s=this._registry[r],e&&e!==s._element||t&&t!==s._type||n&&n!==s._callback||i&&i!==s._context||(s._element.removeEventListener?s._element.removeEventListener(s._type,s._handler,!1):s._element.detachEvent("on"+s._type,s._handler),this._registry.splice(r,1),s=null)}},void 0!==Faye.ENV.onunload&&Faye.Event.on(Faye.ENV,"unload",Faye.Event.detach,Faye.Event),"object"!=typeof JSON&&(JSON={}),function(){function f(e){return 10>e?"0"+e:e}function quote(e){return escapable.lastIndex=0,escapable.test(e)?'"'+e.replace(escapable,function(e){var t=meta[e];return"string"==typeof t?t:"\\u"+("0000"+e.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+e+'"'}function str(e,t){var n,i,s,r,o,a=gap,c=t[e];switch(c&&"object"==typeof c&&"function"==typeof c.toJSON&&(c=c.toJSON(e)),"function"==typeof rep&&(c=rep.call(t,e,c)),typeof c){case"string":return quote(c);case"number":return isFinite(c)?c+"":"null";case"boolean":case"null":return c+"";case"object":if(!c)return"null";if(gap+=indent,o=[],"[object Array]"===Object.prototype.toString.apply(c)){for(r=c.length,n=0;r>n;n+=1)o[n]=str(n,c)||"null";return s=0===o.length?"[]":gap?"[\n"+gap+o.join(",\n"+gap)+"\n"+a+"]":"["+o.join(",")+"]",gap=a,s}if(rep&&"object"==typeof rep)for(r=rep.length,n=0;r>n;n+=1)"string"==typeof rep[n]&&(i=rep[n],s=str(i,c),s&&o.push(quote(i)+(gap?": ":":")+s));else for(i in c)Object.prototype.hasOwnProperty.call(c,i)&&(s=str(i,c),s&&o.push(quote(i)+(gap?": ":":")+s));return s=0===o.length?"{}":gap?"{\n"+gap+o.join(",\n"+gap)+"\n"+a+"}":"{"+o.join(",")+"}",gap=a,s}}"function"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()});var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;Faye.stringify=function(e,t,n){var i;if(gap="",indent="","number"==typeof n)for(i=0;n>i;i+=1)indent+=" ";else"string"==typeof n&&(indent=n);if(rep=t,t&&"function"!=typeof t&&("object"!=typeof t||"number"!=typeof t.length))throw Error("JSON.stringify");return str("",{"":e})},"function"!=typeof JSON.stringify&&(JSON.stringify=Faye.stringify),"function"!=typeof JSON.parse&&(JSON.parse=function(text,reviver){function walk(e,t){var n,i,s=e[t];if(s&&"object"==typeof s)for(n in s)Object.prototype.hasOwnProperty.call(s,n)&&(i=walk(s,n),void 0!==i?s[n]=i:delete s[n]);
3
+ return reviver.call(e,t,s)}var j;if(text+="",cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(e){return"\\u"+("0000"+e.charCodeAt(0).toString(16)).slice(-4)})),/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return j=eval("("+text+")"),"function"==typeof reviver?walk({"":j},""):j;throw new SyntaxError("JSON.parse")})}(),Faye.Transport.WebSocket=Faye.extend(Faye.Class(Faye.Transport,{UNCONNECTED:1,CONNECTING:2,CONNECTED:3,batching:!1,isUsable:function(e,t){this.callback(function(){e.call(t,!0)}),this.errback(function(){e.call(t,!1)}),this.connect()},request:function(e){this._pending=this._pending||new Faye.Set;for(var t=0,n=e.length;n>t;t++)this._pending.add(e[t]);var i=new Faye.Promise;return this.callback(function(t){t&&(t.send(Faye.toJSON(e)),Faye.Promise.fulfill(i,t))},this),this.connect(),{abort:function(){i.then(function(e){e.close()})}}},connect:function(){if(!Faye.Transport.WebSocket._unloaded&&(this._state=this._state||this.UNCONNECTED,this._state===this.UNCONNECTED)){this._state=this.CONNECTING;var e=this._createSocket();if(!e)return this.setDeferredStatus("failed");var t=this;e.onopen=function(){e.headers&&t._storeCookies(e.headers["set-cookie"]),t._socket=e,t._state=t.CONNECTED,t._everConnected=!0,t._ping(),t.setDeferredStatus("succeeded",e)};var n=!1;e.onclose=e.onerror=function(){if(!n){n=!0;var i=t._state===t.CONNECTED;e.onopen=e.onclose=e.onerror=e.onmessage=null,delete t._socket,t._state=t.UNCONNECTED,t.removeTimeout("ping"),t.setDeferredStatus("unknown");var s=t._pending?t._pending.toArray():[];delete t._pending,i?t._handleError(s,!0):t._everConnected?t._handleError(s):t.setDeferredStatus("failed")}},e.onmessage=function(e){var n=JSON.parse(e.data);if(n){n=[].concat(n);for(var i=0,s=n.length;s>i;i++)void 0!==n[i].successful&&t._pending.remove(n[i]);t._receive(n)}}}},close:function(){this._socket&&this._socket.close()},_createSocket:function(){var e=Faye.Transport.WebSocket.getSocketUrl(this.endpoint),t=this._dispatcher.headers,n=this._dispatcher.wsExtensions,i=this._getCookies(),s=this._dispatcher.tls,r={extensions:n,headers:t,proxy:this._proxy,tls:s};return""!==i&&(r.headers.Cookie=i),Faye.WebSocket?new Faye.WebSocket.Client(e,[],r):Faye.ENV.MozWebSocket?new MozWebSocket(e):Faye.ENV.WebSocket?new WebSocket(e):void 0},_ping:function(){this._socket&&(this._socket.send("[]"),this.addTimeout("ping",this._dispatcher.timeout/2,this._ping,this))}}),{PROTOCOLS:{"http:":"ws:","https:":"wss:"},create:function(e,t){var n=e.transports.websocket=e.transports.websocket||{};return n[t.href]=n[t.href]||new this(e,t),n[t.href]},getSocketUrl:function(e){return e=Faye.copyObject(e),e.protocol=this.PROTOCOLS[e.protocol],Faye.URI.stringify(e)},isUsable:function(e,t,n,i){this.create(e,t).isUsable(n,i)}}),Faye.extend(Faye.Transport.WebSocket.prototype,Faye.Deferrable),Faye.Transport.register("websocket",Faye.Transport.WebSocket),Faye.Event&&void 0!==Faye.ENV.onbeforeunload&&Faye.Event.on(Faye.ENV,"beforeunload",function(){Faye.Transport.WebSocket._unloaded=!0}),Faye.Transport.EventSource=Faye.extend(Faye.Class(Faye.Transport,{initialize:function(e,t){if(Faye.Transport.prototype.initialize.call(this,e,t),!Faye.ENV.EventSource)return this.setDeferredStatus("failed");this._xhr=new Faye.Transport.XHR(e,t),t=Faye.copyObject(t),t.pathname+="/"+e.clientId;var n=new EventSource(Faye.URI.stringify(t)),i=this;n.onopen=function(){i._everConnected=!0,i.setDeferredStatus("succeeded")},n.onerror=function(){i._everConnected?i._handleError([]):(i.setDeferredStatus("failed"),n.close())},n.onmessage=function(e){i._receive(JSON.parse(e.data))},this._socket=n},close:function(){this._socket&&(this._socket.onopen=this._socket.onerror=this._socket.onmessage=null,this._socket.close(),delete this._socket)},isUsable:function(e,t){this.callback(function(){e.call(t,!0)}),this.errback(function(){e.call(t,!1)})},encode:function(e){return this._xhr.encode(e)},request:function(e){return this._xhr.request(e)}}),{isUsable:function(e,t,n,i){var s=e.clientId;return s?void Faye.Transport.XHR.isUsable(e,t,function(s){return s?void this.create(e,t).isUsable(n,i):n.call(i,!1)},this):n.call(i,!1)},create:function(e,t){var n=e.transports.eventsource=e.transports.eventsource||{},i=e.clientId,s=Faye.copyObject(t);return s.pathname+="/"+(i||""),s=Faye.URI.stringify(s),n[s]=n[s]||new this(e,t),n[s]}}),Faye.extend(Faye.Transport.EventSource.prototype,Faye.Deferrable),Faye.Transport.register("eventsource",Faye.Transport.EventSource),Faye.Transport.XHR=Faye.extend(Faye.Class(Faye.Transport,{encode:function(e){return Faye.toJSON(e)},request:function(e){var t=this.endpoint.href,n=Faye.ENV.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest,i=this;n.open("POST",t,!0),n.setRequestHeader("Content-Type","application/json"),n.setRequestHeader("Pragma","no-cache"),n.setRequestHeader("X-Requested-With","XMLHttpRequest");var s=this._dispatcher.headers;for(var r in s)s.hasOwnProperty(r)&&n.setRequestHeader(r,s[r]);var o=function(){n.abort()};return void 0!==Faye.ENV.onbeforeunload&&Faye.Event.on(Faye.ENV,"beforeunload",o),n.onreadystatechange=function(){if(n&&4===n.readyState){var t=null,s=n.status,r=n.responseText,a=s>=200&&300>s||304===s||1223===s;if(void 0!==Faye.ENV.onbeforeunload&&Faye.Event.detach(Faye.ENV,"beforeunload",o),n.onreadystatechange=function(){},n=null,!a)return i._handleError(e);try{t=JSON.parse(r)}catch(c){}t?i._receive(t):i._handleError(e)}},n.send(this.encode(e)),n}}),{isUsable:function(e,t,n,i){n.call(i,Faye.URI.isSameOrigin(t))}}),Faye.Transport.register("long-polling",Faye.Transport.XHR),Faye.Transport.CORS=Faye.extend(Faye.Class(Faye.Transport,{encode:function(e){return"message="+encodeURIComponent(Faye.toJSON(e))},request:function(e){var t,n=Faye.ENV.XDomainRequest?XDomainRequest:XMLHttpRequest,i=new n,s=this._dispatcher.headers,r=this;if(i.open("POST",Faye.URI.stringify(this.endpoint),!0),i.setRequestHeader){i.setRequestHeader("Pragma","no-cache");for(t in s)s.hasOwnProperty(t)&&i.setRequestHeader(t,s[t])}var o=function(){return i?(i.onload=i.onerror=i.ontimeout=i.onprogress=null,void(i=null)):!1};return i.onload=function(){var t=null;try{t=JSON.parse(i.responseText)}catch(n){}o(),t?r._receive(t):r._handleError(e)},i.onerror=i.ontimeout=function(){o(),r._handleError(e)},i.onprogress=function(){},i.send(this.encode(e)),i}}),{isUsable:function(e,t,n,i){if(Faye.URI.isSameOrigin(t))return n.call(i,!1);if(Faye.ENV.XDomainRequest)return n.call(i,t.protocol===Faye.ENV.location.protocol);if(Faye.ENV.XMLHttpRequest){var s=new Faye.ENV.XMLHttpRequest;return n.call(i,void 0!==s.withCredentials)}return n.call(i,!1)}}),Faye.Transport.register("cross-origin-long-polling",Faye.Transport.CORS),Faye.Transport.JSONP=Faye.extend(Faye.Class(Faye.Transport,{encode:function(e){var t=Faye.copyObject(this.endpoint);return t.query.message=Faye.toJSON(e),t.query.jsonp="__jsonp"+Faye.Transport.JSONP._cbCount+"__",Faye.URI.stringify(t)},request:function(e){var t=document.getElementsByTagName("head")[0],n=document.createElement("script"),i=Faye.Transport.JSONP.getCallbackName(),s=Faye.copyObject(this.endpoint),r=this;s.query.message=Faye.toJSON(e),s.query.jsonp=i;var o=function(){if(!Faye.ENV[i])return!1;Faye.ENV[i]=void 0;try{delete Faye.ENV[i]}catch(e){}n.parentNode.removeChild(n)};return Faye.ENV[i]=function(e){o(),r._receive(e)},n.type="text/javascript",n.src=Faye.URI.stringify(s),t.appendChild(n),n.onerror=function(){o(),r._handleError(e)},{abort:o}}}),{_cbCount:0,getCallbackName:function(){return this._cbCount+=1,"__jsonp"+this._cbCount+"__"},isUsable:function(e,t,n,i){n.call(i,!0)}}),Faye.Transport.register("callback-polling",Faye.Transport.JSONP)}();
4
+ //# sourceMappingURL=faye-browser-min.js.map
5
5
  })(this);
@@ -3,7 +3,7 @@
3
3
  'use strict';
4
4
 
5
5
  var Faye = {
6
- VERSION: '1.0.1',
6
+ VERSION: '1.1.1',
7
7
 
8
8
  BAYEUX_VERSION: '1.0',
9
9
  ID_LENGTH: 160,
@@ -27,7 +27,17 @@ var Faye = {
27
27
 
28
28
  random: function(bitlength) {
29
29
  bitlength = bitlength || this.ID_LENGTH;
30
- return csprng(bitlength, 36);
30
+ var maxLength = Math.ceil(bitlength * Math.log(2) / Math.log(36));
31
+ var string = csprng(bitlength, 36);
32
+ while (string.length < maxLength) string = '0' + string;
33
+ return string;
34
+ },
35
+
36
+ validateOptions: function(options, validKeys) {
37
+ for (var key in options) {
38
+ if (this.indexOf(validKeys, key) < 0)
39
+ throw new Error('Unrecognized option: ' + key);
40
+ }
31
41
  },
32
42
 
33
43
  clientIdFromMessages: function(messages) {
@@ -358,9 +368,8 @@ Faye.Namespace = Faye.Class({
358
368
  (function() {
359
369
  'use strict';
360
370
 
361
- var timeout = setTimeout;
371
+ var timeout = setTimeout, defer;
362
372
 
363
- var defer;
364
373
  if (typeof setImmediate === 'function')
365
374
  defer = function(fn) { setImmediate(fn) };
366
375
  else if (typeof process === 'object' && process.nextTick)
@@ -373,12 +382,12 @@ var PENDING = 0,
373
382
  REJECTED = 2;
374
383
 
375
384
  var RETURN = function(x) { return x },
376
- THROW = function(x) { throw x };
385
+ THROW = function(x) { throw x };
377
386
 
378
387
  var Promise = function(task) {
379
- this._state = PENDING;
380
- this._callbacks = [];
381
- this._errbacks = [];
388
+ this._state = PENDING;
389
+ this._onFulfilled = [];
390
+ this._onRejected = [];
382
391
 
383
392
  if (typeof task !== 'function') return;
384
393
  var self = this;
@@ -387,34 +396,30 @@ var Promise = function(task) {
387
396
  function(reason) { reject(self, reason) });
388
397
  };
389
398
 
390
- Promise.prototype.then = function(callback, errback) {
391
- var next = {}, self = this;
392
-
393
- next.promise = new Promise(function(fulfill, reject) {
394
- next.fulfill = fulfill;
395
- next.reject = reject;
396
-
397
- registerCallback(self, callback, next);
398
- registerErrback(self, errback, next);
399
- });
400
- return next.promise;
399
+ Promise.prototype.then = function(onFulfilled, onRejected) {
400
+ var next = new Promise();
401
+ registerOnFulfilled(this, onFulfilled, next);
402
+ registerOnRejected(this, onRejected, next);
403
+ return next;
401
404
  };
402
405
 
403
- var registerCallback = function(promise, callback, next) {
404
- if (typeof callback !== 'function') callback = RETURN;
405
- var handler = function(value) { invoke(callback, value, next) };
406
+ var registerOnFulfilled = function(promise, onFulfilled, next) {
407
+ if (typeof onFulfilled !== 'function') onFulfilled = RETURN;
408
+ var handler = function(value) { invoke(onFulfilled, value, next) };
409
+
406
410
  if (promise._state === PENDING) {
407
- promise._callbacks.push(handler);
411
+ promise._onFulfilled.push(handler);
408
412
  } else if (promise._state === FULFILLED) {
409
413
  handler(promise._value);
410
414
  }
411
415
  };
412
416
 
413
- var registerErrback = function(promise, errback, next) {
414
- if (typeof errback !== 'function') errback = THROW;
415
- var handler = function(reason) { invoke(errback, reason, next) };
417
+ var registerOnRejected = function(promise, onRejected, next) {
418
+ if (typeof onRejected !== 'function') onRejected = THROW;
419
+ var handler = function(reason) { invoke(onRejected, reason, next) };
420
+
416
421
  if (promise._state === PENDING) {
417
- promise._errbacks.push(handler);
422
+ promise._onRejected.push(handler);
418
423
  } else if (promise._state === REJECTED) {
419
424
  handler(promise._reason);
420
425
  }
@@ -425,55 +430,80 @@ var invoke = function(fn, value, next) {
425
430
  };
426
431
 
427
432
  var _invoke = function(fn, value, next) {
428
- var called = false, outcome, type, then;
433
+ var outcome;
429
434
 
430
435
  try {
431
436
  outcome = fn(value);
432
- type = typeof outcome;
433
- then = outcome !== null && (type === 'function' || type === 'object') && outcome.then;
437
+ } catch (error) {
438
+ return reject(next, error);
439
+ }
440
+
441
+ if (outcome === next) {
442
+ reject(next, new TypeError('Recursive promise chain detected'));
443
+ } else {
444
+ fulfill(next, outcome);
445
+ }
446
+ };
434
447
 
435
- if (outcome === next.promise)
436
- return next.reject(new TypeError('Recursive promise chain detected'));
448
+ var fulfill = Promise.fulfill = Promise.resolve = function(promise, value) {
449
+ var called = false, type, then;
450
+
451
+ try {
452
+ type = typeof value;
453
+ then = value !== null && (type === 'function' || type === 'object') && value.then;
437
454
 
438
- if (typeof then !== 'function') return next.fulfill(outcome);
455
+ if (typeof then !== 'function') return _fulfill(promise, value);
439
456
 
440
- then.call(outcome, function(v) {
441
- if (called) return;
442
- called = true;
443
- _invoke(RETURN, v, next);
457
+ then.call(value, function(v) {
458
+ if (!(called ^ (called = true))) return;
459
+ fulfill(promise, v);
444
460
  }, function(r) {
445
- if (called) return;
446
- called = true;
447
- next.reject(r);
461
+ if (!(called ^ (called = true))) return;
462
+ reject(promise, r);
448
463
  });
449
-
450
464
  } catch (error) {
451
- if (called) return;
452
- called = true;
453
- next.reject(error);
465
+ if (!(called ^ (called = true))) return;
466
+ reject(promise, error);
454
467
  }
455
468
  };
456
469
 
457
- var fulfill = Promise.fulfill = Promise.resolve = function(promise, value) {
470
+ var _fulfill = function(promise, value) {
458
471
  if (promise._state !== PENDING) return;
459
472
 
460
- promise._state = FULFILLED;
461
- promise._value = value;
462
- promise._errbacks = [];
473
+ promise._state = FULFILLED;
474
+ promise._value = value;
475
+ promise._onRejected = [];
463
476
 
464
- var callbacks = promise._callbacks, cb;
465
- while (cb = callbacks.shift()) cb(value);
477
+ var onFulfilled = promise._onFulfilled, fn;
478
+ while (fn = onFulfilled.shift()) fn(value);
466
479
  };
467
480
 
468
481
  var reject = Promise.reject = function(promise, reason) {
469
482
  if (promise._state !== PENDING) return;
470
483
 
471
- promise._state = REJECTED;
472
- promise._reason = reason;
473
- promise._callbacks = [];
484
+ promise._state = REJECTED;
485
+ promise._reason = reason;
486
+ promise._onFulfilled = [];
487
+
488
+ var onRejected = promise._onRejected, fn;
489
+ while (fn = onRejected.shift()) fn(reason);
490
+ };
491
+
492
+ Promise.all = function(promises) {
493
+ return new Promise(function(fulfill, reject) {
494
+ var list = [],
495
+ n = promises.length,
496
+ i;
497
+
498
+ if (n === 0) return fulfill(list);
474
499
 
475
- var errbacks = promise._errbacks, eb;
476
- while (eb = errbacks.shift()) eb(reason);
500
+ for (i = 0; i < n; i++) (function(promise, i) {
501
+ Promise.fulfilled(promise).then(function(value) {
502
+ list[i] = value;
503
+ if (--n === 0) fulfill(list);
504
+ }, reject);
505
+ })(promises[i], i);
506
+ });
477
507
  };
478
508
 
479
509
  Promise.defer = defer;
@@ -745,7 +775,7 @@ Faye.Deferrable = {
745
775
  setDeferredStatus: function(status, value) {
746
776
  if (this._timer) Faye.ENV.clearTimeout(this._timer);
747
777
 
748
- var promise = this.then();
778
+ this.then();
749
779
 
750
780
  if (status === 'succeeded')
751
781
  this._fulfill(value);
@@ -802,7 +832,7 @@ Faye.Timeouts = {
802
832
  this._timeouts = this._timeouts || {};
803
833
  var timeout = this._timeouts[name];
804
834
  if (!timeout) return;
805
- clearTimeout(timeout);
835
+ Faye.ENV.clearTimeout(timeout);
806
836
  delete this._timeouts[name];
807
837
  },
808
838
 
@@ -824,13 +854,13 @@ Faye.Logging = {
824
854
  writeLog: function(messageArgs, level) {
825
855
  if (!Faye.logger) return;
826
856
 
827
- var messageArgs = Array.prototype.slice.apply(messageArgs),
828
- banner = '[Faye',
829
- klass = this.className,
857
+ var args = Array.prototype.slice.apply(messageArgs),
858
+ banner = '[Faye',
859
+ klass = this.className,
830
860
 
831
- message = messageArgs.shift().replace(/\?/g, function() {
861
+ message = args.shift().replace(/\?/g, function() {
832
862
  try {
833
- return Faye.toJSON(messageArgs.shift());
863
+ return Faye.toJSON(args.shift());
834
864
  } catch (e) {
835
865
  return '[Object]';
836
866
  }
@@ -853,11 +883,11 @@ Faye.Logging = {
853
883
 
854
884
  (function() {
855
885
  for (var key in Faye.Logging.LOG_LEVELS)
856
- (function(level, value) {
886
+ (function(level) {
857
887
  Faye.Logging[level] = function() {
858
888
  this.writeLog(arguments, level);
859
889
  };
860
- })(key, Faye.Logging.LOG_LEVELS[key]);
890
+ })(key);
861
891
  })();
862
892
 
863
893
  Faye.Grammar = {
@@ -1000,12 +1030,11 @@ Faye.extend(Faye.Channel, {
1000
1030
  },
1001
1031
 
1002
1032
  subscribe: function(names, callback, context) {
1003
- if (!callback) return;
1004
1033
  var name;
1005
1034
  for (var i = 0, n = names.length; i < n; i++) {
1006
1035
  name = names[i];
1007
1036
  var channel = this._channels[name] = this._channels[name] || new Faye.Channel(name);
1008
- channel.bind('message', callback, context);
1037
+ if (callback) channel.bind('message', callback, context);
1009
1038
  }
1010
1039
  },
1011
1040
 
@@ -1033,17 +1062,6 @@ Faye.extend(Faye.Channel, {
1033
1062
  })
1034
1063
  });
1035
1064
 
1036
- Faye.Envelope = Faye.Class({
1037
- initialize: function(message, timeout) {
1038
- this.id = message.id;
1039
- this.message = message;
1040
-
1041
- if (timeout !== undefined) this.timeout(timeout / 1000, false);
1042
- }
1043
- });
1044
-
1045
- Faye.extend(Faye.Envelope.prototype, Faye.Deferrable);
1046
-
1047
1065
  Faye.Publication = Faye.Class(Faye.Deferrable);
1048
1066
 
1049
1067
  Faye.Subscription = Faye.Class({
@@ -1069,65 +1087,61 @@ Faye.Subscription = Faye.Class({
1069
1087
  Faye.extend(Faye.Subscription.prototype, Faye.Deferrable);
1070
1088
 
1071
1089
  Faye.Client = Faye.Class({
1072
- UNCONNECTED: 1,
1073
- CONNECTING: 2,
1074
- CONNECTED: 3,
1075
- DISCONNECTED: 4,
1090
+ UNCONNECTED: 1,
1091
+ CONNECTING: 2,
1092
+ CONNECTED: 3,
1093
+ DISCONNECTED: 4,
1076
1094
 
1077
- HANDSHAKE: 'handshake',
1078
- RETRY: 'retry',
1079
- NONE: 'none',
1095
+ HANDSHAKE: 'handshake',
1096
+ RETRY: 'retry',
1097
+ NONE: 'none',
1080
1098
 
1081
- CONNECTION_TIMEOUT: 60,
1082
- DEFAULT_RETRY: 5,
1083
- MAX_REQUEST_SIZE: 2048,
1099
+ CONNECTION_TIMEOUT: 60,
1084
1100
 
1085
- DEFAULT_ENDPOINT: '/bayeux',
1086
- INTERVAL: 0,
1101
+ DEFAULT_ENDPOINT: '/bayeux',
1102
+ INTERVAL: 0,
1087
1103
 
1088
1104
  initialize: function(endpoint, options) {
1089
1105
  this.info('New client created for ?', endpoint);
1106
+ options = options || {};
1090
1107
 
1091
- this._options = options || {};
1092
- this.endpoint = Faye.URI.parse(endpoint || this.DEFAULT_ENDPOINT);
1093
- this.endpoints = this._options.endpoints || {};
1094
- this.transports = {};
1095
- this.cookies = Faye.CookieJar && new Faye.CookieJar();
1096
- this.headers = {};
1097
- this.ca = this._options.ca;
1098
- this._disabled = [];
1099
- this._retry = this._options.retry || this.DEFAULT_RETRY;
1100
-
1101
- for (var key in this.endpoints)
1102
- this.endpoints[key] = Faye.URI.parse(this.endpoints[key]);
1108
+ Faye.validateOptions(options, ['interval', 'timeout', 'endpoints', 'proxy', 'retry', 'scheduler', 'websocketExtensions', 'tls', 'ca']);
1103
1109
 
1104
- this.maxRequestSize = this.MAX_REQUEST_SIZE;
1110
+ this._endpoint = endpoint || this.DEFAULT_ENDPOINT;
1111
+ this._channels = new Faye.Channel.Set();
1112
+ this._dispatcher = new Faye.Dispatcher(this, this._endpoint, options);
1105
1113
 
1106
- this._state = this.UNCONNECTED;
1107
- this._channels = new Faye.Channel.Set();
1108
1114
  this._messageId = 0;
1115
+ this._state = this.UNCONNECTED;
1109
1116
 
1110
1117
  this._responseCallbacks = {};
1111
1118
 
1112
1119
  this._advice = {
1113
1120
  reconnect: this.RETRY,
1114
- interval: 1000 * (this._options.interval || this.INTERVAL),
1115
- timeout: 1000 * (this._options.timeout || this.CONNECTION_TIMEOUT)
1121
+ interval: 1000 * (options.interval || this.INTERVAL),
1122
+ timeout: 1000 * (options.timeout || this.CONNECTION_TIMEOUT)
1116
1123
  };
1124
+ this._dispatcher.timeout = this._advice.timeout / 1000;
1125
+
1126
+ this._dispatcher.bind('message', this._receiveMessage, this);
1117
1127
 
1118
1128
  if (Faye.Event && Faye.ENV.onbeforeunload !== undefined)
1119
1129
  Faye.Event.on(Faye.ENV, 'beforeunload', function() {
1120
- if (Faye.indexOf(this._disabled, 'autodisconnect') < 0)
1130
+ if (Faye.indexOf(this._dispatcher._disabled, 'autodisconnect') < 0)
1121
1131
  this.disconnect();
1122
1132
  }, this);
1123
1133
  },
1124
1134
 
1135
+ addWebsocketExtension: function(extension) {
1136
+ return this._dispatcher.addWebsocketExtension(extension);
1137
+ },
1138
+
1125
1139
  disable: function(feature) {
1126
- this._disabled.push(feature);
1140
+ return this._dispatcher.disable(feature);
1127
1141
  },
1128
1142
 
1129
1143
  setHeader: function(name, value) {
1130
- this.headers[name] = value;
1144
+ return this._dispatcher.setHeader(name, value);
1131
1145
  },
1132
1146
 
1133
1147
  // Request
@@ -1156,30 +1170,30 @@ Faye.Client = Faye.Class({
1156
1170
  this._state = this.CONNECTING;
1157
1171
  var self = this;
1158
1172
 
1159
- this.info('Initiating handshake with ?', Faye.URI.stringify(this.endpoint));
1160
- this._selectTransport(Faye.MANDATORY_CONNECTION_TYPES);
1173
+ this.info('Initiating handshake with ?', Faye.URI.stringify(this._endpoint));
1174
+ this._dispatcher.selectTransport(Faye.MANDATORY_CONNECTION_TYPES);
1161
1175
 
1162
- this._send({
1176
+ this._sendMessage({
1163
1177
  channel: Faye.Channel.HANDSHAKE,
1164
1178
  version: Faye.BAYEUX_VERSION,
1165
- supportedConnectionTypes: [this._transport.connectionType]
1179
+ supportedConnectionTypes: this._dispatcher.getConnectionTypes()
1166
1180
 
1167
- }, function(response) {
1181
+ }, {}, function(response) {
1168
1182
 
1169
1183
  if (response.successful) {
1170
- this._state = this.CONNECTED;
1171
- this._clientId = response.clientId;
1184
+ this._state = this.CONNECTED;
1185
+ this._dispatcher.clientId = response.clientId;
1172
1186
 
1173
- this._selectTransport(response.supportedConnectionTypes);
1187
+ this._dispatcher.selectTransport(response.supportedConnectionTypes);
1174
1188
 
1175
- this.info('Handshake successful: ?', this._clientId);
1189
+ this.info('Handshake successful: ?', this._dispatcher.clientId);
1176
1190
 
1177
1191
  this.subscribe(this._channels.getKeys(), true);
1178
1192
  if (callback) Faye.Promise.defer(function() { callback.call(context) });
1179
1193
 
1180
1194
  } else {
1181
1195
  this.info('Handshake unsuccessful');
1182
- Faye.ENV.setTimeout(function() { self.handshake(callback, context) }, this._advice.interval);
1196
+ Faye.ENV.setTimeout(function() { self.handshake(callback, context) }, this._dispatcher.retry * 1000);
1183
1197
  this._state = this.UNCONNECTED;
1184
1198
  }
1185
1199
  }, this);
@@ -1204,21 +1218,21 @@ Faye.Client = Faye.Class({
1204
1218
  this.callback(callback, context);
1205
1219
  if (this._state !== this.CONNECTED) return;
1206
1220
 
1207
- this.info('Calling deferred actions for ?', this._clientId);
1221
+ this.info('Calling deferred actions for ?', this._dispatcher.clientId);
1208
1222
  this.setDeferredStatus('succeeded');
1209
1223
  this.setDeferredStatus('unknown');
1210
1224
 
1211
1225
  if (this._connectRequest) return;
1212
1226
  this._connectRequest = true;
1213
1227
 
1214
- this.info('Initiating connection for ?', this._clientId);
1228
+ this.info('Initiating connection for ?', this._dispatcher.clientId);
1215
1229
 
1216
- this._send({
1230
+ this._sendMessage({
1217
1231
  channel: Faye.Channel.CONNECT,
1218
- clientId: this._clientId,
1219
- connectionType: this._transport.connectionType
1232
+ clientId: this._dispatcher.clientId,
1233
+ connectionType: this._dispatcher.connectionType
1220
1234
 
1221
- }, this._cycleConnection, this);
1235
+ }, {}, this._cycleConnection, this);
1222
1236
  },
1223
1237
 
1224
1238
  // Request Response
@@ -1232,20 +1246,26 @@ Faye.Client = Faye.Class({
1232
1246
  if (this._state !== this.CONNECTED) return;
1233
1247
  this._state = this.DISCONNECTED;
1234
1248
 
1235
- this.info('Disconnecting ?', this._clientId);
1249
+ this.info('Disconnecting ?', this._dispatcher.clientId);
1250
+ var promise = new Faye.Publication();
1236
1251
 
1237
- this._send({
1252
+ this._sendMessage({
1238
1253
  channel: Faye.Channel.DISCONNECT,
1239
- clientId: this._clientId
1254
+ clientId: this._dispatcher.clientId
1240
1255
 
1241
- }, function(response) {
1242
- if (!response.successful) return;
1243
- this._transport.close();
1244
- delete this._transport;
1256
+ }, {}, function(response) {
1257
+ if (response.successful) {
1258
+ this._dispatcher.close();
1259
+ promise.setDeferredStatus('succeeded');
1260
+ } else {
1261
+ promise.setDeferredStatus('failed', Faye.Error.parse(response.error));
1262
+ }
1245
1263
  }, this);
1246
1264
 
1247
- this.info('Clearing channel listeners for ?', this._clientId);
1265
+ this.info('Clearing channel listeners for ?', this._dispatcher.clientId);
1248
1266
  this._channels = new Faye.Channel.Set();
1267
+
1268
+ return promise;
1249
1269
  },
1250
1270
 
1251
1271
  // Request Response
@@ -1275,22 +1295,22 @@ Faye.Client = Faye.Class({
1275
1295
  }
1276
1296
 
1277
1297
  this.connect(function() {
1278
- this.info('Client ? attempting to subscribe to ?', this._clientId, channel);
1298
+ this.info('Client ? attempting to subscribe to ?', this._dispatcher.clientId, channel);
1279
1299
  if (!force) this._channels.subscribe([channel], callback, context);
1280
1300
 
1281
- this._send({
1301
+ this._sendMessage({
1282
1302
  channel: Faye.Channel.SUBSCRIBE,
1283
- clientId: this._clientId,
1303
+ clientId: this._dispatcher.clientId,
1284
1304
  subscription: channel
1285
1305
 
1286
- }, function(response) {
1306
+ }, {}, function(response) {
1287
1307
  if (!response.successful) {
1288
1308
  subscription.setDeferredStatus('failed', Faye.Error.parse(response.error));
1289
1309
  return this._channels.unsubscribe(channel, callback, context);
1290
1310
  }
1291
1311
 
1292
1312
  var channels = [].concat(response.subscription);
1293
- this.info('Subscription acknowledged for ? to ?', this._clientId, channels);
1313
+ this.info('Subscription acknowledged for ? to ?', this._dispatcher.clientId, channels);
1294
1314
  subscription.setDeferredStatus('succeeded');
1295
1315
  }, this);
1296
1316
  }, this);
@@ -1318,18 +1338,18 @@ Faye.Client = Faye.Class({
1318
1338
  if (!dead) return;
1319
1339
 
1320
1340
  this.connect(function() {
1321
- this.info('Client ? attempting to unsubscribe from ?', this._clientId, channel);
1341
+ this.info('Client ? attempting to unsubscribe from ?', this._dispatcher.clientId, channel);
1322
1342
 
1323
- this._send({
1343
+ this._sendMessage({
1324
1344
  channel: Faye.Channel.UNSUBSCRIBE,
1325
- clientId: this._clientId,
1345
+ clientId: this._dispatcher.clientId,
1326
1346
  subscription: channel
1327
1347
 
1328
- }, function(response) {
1348
+ }, {}, function(response) {
1329
1349
  if (!response.successful) return;
1330
1350
 
1331
1351
  var channels = [].concat(response.subscription);
1332
- this.info('Unsubscription acknowledged for ? from ?', this._clientId, channels);
1352
+ this.info('Unsubscription acknowledged for ? from ?', this._dispatcher.clientId, channels);
1333
1353
  }, this);
1334
1354
  }, this);
1335
1355
  },
@@ -1340,18 +1360,19 @@ Faye.Client = Faye.Class({
1340
1360
  // MAY include: * clientId MAY include: * id
1341
1361
  // * id * error
1342
1362
  // * ext * ext
1343
- publish: function(channel, data) {
1363
+ publish: function(channel, data, options) {
1364
+ Faye.validateOptions(options || {}, ['attempts', 'deadline']);
1344
1365
  var publication = new Faye.Publication();
1345
1366
 
1346
1367
  this.connect(function() {
1347
- this.info('Client ? queueing published message to ?: ?', this._clientId, channel, data);
1368
+ this.info('Client ? queueing published message to ?: ?', this._dispatcher.clientId, channel, data);
1348
1369
 
1349
- this._send({
1370
+ this._sendMessage({
1350
1371
  channel: channel,
1351
1372
  data: data,
1352
- clientId: this._clientId
1373
+ clientId: this._dispatcher.clientId
1353
1374
 
1354
- }, function(response) {
1375
+ }, options, function(response) {
1355
1376
  if (response.successful)
1356
1377
  publication.setDeferredStatus('succeeded');
1357
1378
  else
@@ -1362,8 +1383,28 @@ Faye.Client = Faye.Class({
1362
1383
  return publication;
1363
1384
  },
1364
1385
 
1365
- receiveMessage: function(message) {
1366
- var id = message.id, timeout, callback;
1386
+ _sendMessage: function(message, options, callback, context) {
1387
+ message.id = this._generateMessageId();
1388
+
1389
+ var timeout = this._advice.timeout
1390
+ ? 1.2 * this._advice.timeout / 1000
1391
+ : 1.2 * this._dispatcher.retry;
1392
+
1393
+ this.pipeThroughExtensions('outgoing', message, null, function(message) {
1394
+ if (!message) return;
1395
+ if (callback) this._responseCallbacks[message.id] = [callback, context];
1396
+ this._dispatcher.sendMessage(message, timeout, options || {});
1397
+ }, this);
1398
+ },
1399
+
1400
+ _generateMessageId: function() {
1401
+ this._messageId += 1;
1402
+ if (this._messageId >= Math.pow(2,32)) this._messageId = 0;
1403
+ return this._messageId.toString(36);
1404
+ },
1405
+
1406
+ _receiveMessage: function(message) {
1407
+ var id = message.id, callback;
1367
1408
 
1368
1409
  if (message.successful !== undefined) {
1369
1410
  callback = this._responseCallbacks[id];
@@ -1372,39 +1413,112 @@ Faye.Client = Faye.Class({
1372
1413
 
1373
1414
  this.pipeThroughExtensions('incoming', message, null, function(message) {
1374
1415
  if (!message) return;
1375
-
1376
1416
  if (message.advice) this._handleAdvice(message.advice);
1377
1417
  this._deliverMessage(message);
1378
-
1379
1418
  if (callback) callback[0].call(callback[1], message);
1380
1419
  }, this);
1420
+ },
1421
+
1422
+ _handleAdvice: function(advice) {
1423
+ Faye.extend(this._advice, advice);
1424
+ this._dispatcher.timeout = this._advice.timeout / 1000;
1381
1425
 
1382
- if (this._transportUp === true) return;
1383
- this._transportUp = true;
1384
- this.trigger('transport:up');
1426
+ if (this._advice.reconnect === this.HANDSHAKE && this._state !== this.DISCONNECTED) {
1427
+ this._state = this.UNCONNECTED;
1428
+ this._dispatcher.clientId = null;
1429
+ this._cycleConnection();
1430
+ }
1385
1431
  },
1386
1432
 
1387
- messageError: function(messages, immediate) {
1388
- var retry = this._retry,
1389
- self = this,
1390
- id, message, timeout;
1433
+ _deliverMessage: function(message) {
1434
+ if (!message.channel || message.data === undefined) return;
1435
+ this.info('Client ? calling listeners for ? with ?', this._dispatcher.clientId, message.channel, message.data);
1436
+ this._channels.distributeMessage(message);
1437
+ },
1391
1438
 
1392
- for (var i = 0, n = messages.length; i < n; i++) {
1393
- message = messages[i];
1394
- id = message.id;
1439
+ _cycleConnection: function() {
1440
+ if (this._connectRequest) {
1441
+ this._connectRequest = null;
1442
+ this.info('Closed connection for ?', this._dispatcher.clientId);
1443
+ }
1444
+ var self = this;
1445
+ Faye.ENV.setTimeout(function() { self.connect() }, this._advice.interval);
1446
+ }
1447
+ });
1395
1448
 
1396
- if (immediate)
1397
- this._transportSend(message);
1398
- else
1399
- Faye.ENV.setTimeout(function() { self._transportSend(message) }, retry * 1000);
1449
+ Faye.extend(Faye.Client.prototype, Faye.Deferrable);
1450
+ Faye.extend(Faye.Client.prototype, Faye.Publisher);
1451
+ Faye.extend(Faye.Client.prototype, Faye.Logging);
1452
+ Faye.extend(Faye.Client.prototype, Faye.Extensible);
1453
+
1454
+ Faye.Dispatcher = Faye.Class({
1455
+ MAX_REQUEST_SIZE: 2048,
1456
+ DEFAULT_RETRY: 5,
1457
+
1458
+ UP: 1,
1459
+ DOWN: 2,
1460
+
1461
+ initialize: function(client, endpoint, options) {
1462
+ this._client = client;
1463
+ this.endpoint = Faye.URI.parse(endpoint);
1464
+ this._alternates = options.endpoints || {};
1465
+
1466
+ this.cookies = Faye.Cookies && new Faye.Cookies.CookieJar();
1467
+ this._disabled = [];
1468
+ this._envelopes = {};
1469
+ this.headers = {};
1470
+ this.retry = options.retry || this.DEFAULT_RETRY;
1471
+ this._scheduler = options.scheduler || Faye.Scheduler;
1472
+ this._state = 0;
1473
+ this.transports = {};
1474
+ this.wsExtensions = [];
1475
+
1476
+ this.proxy = options.proxy || {};
1477
+ if (typeof this._proxy === 'string') this._proxy = {origin: this._proxy};
1478
+
1479
+ var exts = options.websocketExtensions;
1480
+ if (exts) {
1481
+ exts = [].concat(exts);
1482
+ for (var i = 0, n = exts.length; i < n; i++)
1483
+ this.addWebsocketExtension(exts[i]);
1400
1484
  }
1401
1485
 
1402
- if (immediate || this._transportUp === false) return;
1403
- this._transportUp = false;
1404
- this.trigger('transport:down');
1486
+ this.tls = options.tls || {};
1487
+ this.tls.ca = this.tls.ca || options.ca;
1488
+
1489
+ for (var type in this._alternates)
1490
+ this._alternates[type] = Faye.URI.parse(this._alternates[type]);
1491
+
1492
+ this.maxRequestSize = this.MAX_REQUEST_SIZE;
1493
+ },
1494
+
1495
+ endpointFor: function(connectionType) {
1496
+ return this._alternates[connectionType] || this.endpoint;
1497
+ },
1498
+
1499
+ addWebsocketExtension: function(extension) {
1500
+ this.wsExtensions.push(extension);
1501
+ },
1502
+
1503
+ disable: function(feature) {
1504
+ this._disabled.push(feature);
1505
+ },
1506
+
1507
+ setHeader: function(name, value) {
1508
+ this.headers[name] = value;
1405
1509
  },
1406
1510
 
1407
- _selectTransport: function(transportTypes) {
1511
+ close: function() {
1512
+ var transport = this._transport;
1513
+ delete this._transport;
1514
+ if (transport) transport.close();
1515
+ },
1516
+
1517
+ getConnectionTypes: function() {
1518
+ return Faye.Transport.getConnectionTypes();
1519
+ },
1520
+
1521
+ selectTransport: function(transportTypes) {
1408
1522
  Faye.Transport.get(this, transportTypes, this._disabled, function(transport) {
1409
1523
  this.debug('Selected ? transport for ?', transport.connectionType, Faye.URI.stringify(transport.endpoint));
1410
1524
 
@@ -1412,186 +1526,275 @@ Faye.Client = Faye.Class({
1412
1526
  if (this._transport) this._transport.close();
1413
1527
 
1414
1528
  this._transport = transport;
1529
+ this.connectionType = transport.connectionType;
1415
1530
  }, this);
1416
1531
  },
1417
1532
 
1418
- _send: function(message, callback, context) {
1419
- if (!this._transport) return;
1420
- message.id = message.id || this._generateMessageId();
1533
+ sendMessage: function(message, timeout, options) {
1534
+ options = options || {};
1421
1535
 
1422
- this.pipeThroughExtensions('outgoing', message, null, function(message) {
1423
- if (!message) return;
1424
- if (callback) this._responseCallbacks[message.id] = [callback, context];
1425
- this._transportSend(message);
1426
- }, this);
1536
+ var id = message.id,
1537
+ attempts = options.attempts,
1538
+ deadline = options.deadline && new Date().getTime() + (options.deadline * 1000),
1539
+ envelope = this._envelopes[id],
1540
+ scheduler;
1541
+
1542
+ if (!envelope) {
1543
+ scheduler = new this._scheduler(message, {timeout: timeout, interval: this.retry, attempts: attempts, deadline: deadline});
1544
+ envelope = this._envelopes[id] = {message: message, scheduler: scheduler};
1545
+ }
1546
+
1547
+ this._sendEnvelope(envelope);
1427
1548
  },
1428
1549
 
1429
- _transportSend: function(message) {
1550
+ _sendEnvelope: function(envelope) {
1430
1551
  if (!this._transport) return;
1552
+ if (envelope.request || envelope.timer) return;
1431
1553
 
1432
- var timeout = 1.2 * (this._advice.timeout || this._retry * 1000),
1433
- envelope = new Faye.Envelope(message, timeout);
1554
+ var message = envelope.message,
1555
+ scheduler = envelope.scheduler,
1556
+ self = this;
1434
1557
 
1435
- envelope.errback(function(immediate) {
1436
- this.messageError([message], immediate);
1437
- }, this);
1558
+ if (!scheduler.isDeliverable()) {
1559
+ scheduler.abort();
1560
+ delete this._envelopes[message.id];
1561
+ return;
1562
+ }
1438
1563
 
1439
- this._transport.send(envelope);
1440
- },
1564
+ envelope.timer = Faye.ENV.setTimeout(function() {
1565
+ self.handleError(message);
1566
+ }, scheduler.getTimeout() * 1000);
1441
1567
 
1442
- _generateMessageId: function() {
1443
- this._messageId += 1;
1444
- if (this._messageId >= Math.pow(2,32)) this._messageId = 0;
1445
- return this._messageId.toString(36);
1568
+ scheduler.send();
1569
+ envelope.request = this._transport.sendMessage(message);
1446
1570
  },
1447
1571
 
1448
- _handleAdvice: function(advice) {
1449
- Faye.extend(this._advice, advice);
1572
+ handleResponse: function(reply) {
1573
+ var envelope = this._envelopes[reply.id];
1450
1574
 
1451
- if (this._advice.reconnect === this.HANDSHAKE && this._state !== this.DISCONNECTED) {
1452
- this._state = this.UNCONNECTED;
1453
- this._clientId = null;
1454
- this._cycleConnection();
1575
+ if (reply.successful !== undefined && envelope) {
1576
+ envelope.scheduler.succeed();
1577
+ delete this._envelopes[reply.id];
1578
+ Faye.ENV.clearTimeout(envelope.timer);
1455
1579
  }
1456
- },
1457
1580
 
1458
- _deliverMessage: function(message) {
1459
- if (!message.channel || message.data === undefined) return;
1460
- this.info('Client ? calling listeners for ? with ?', this._clientId, message.channel, message.data);
1461
- this._channels.distributeMessage(message);
1581
+ this.trigger('message', reply);
1582
+
1583
+ if (this._state === this.UP) return;
1584
+ this._state = this.UP;
1585
+ this._client.trigger('transport:up');
1462
1586
  },
1463
1587
 
1464
- _cycleConnection: function() {
1465
- if (this._connectRequest) {
1466
- this._connectRequest = null;
1467
- this.info('Closed connection for ?', this._clientId);
1588
+ handleError: function(message, immediate) {
1589
+ var envelope = this._envelopes[message.id],
1590
+ request = envelope && envelope.request,
1591
+ self = this;
1592
+
1593
+ if (!request) return;
1594
+
1595
+ request.then(function(req) {
1596
+ if (req && req.abort) req.abort();
1597
+ });
1598
+
1599
+ var scheduler = envelope.scheduler;
1600
+ scheduler.fail();
1601
+
1602
+ Faye.ENV.clearTimeout(envelope.timer);
1603
+ envelope.request = envelope.timer = null;
1604
+
1605
+ if (immediate) {
1606
+ this._sendEnvelope(envelope);
1607
+ } else {
1608
+ envelope.timer = Faye.ENV.setTimeout(function() {
1609
+ envelope.timer = null;
1610
+ self._sendEnvelope(envelope);
1611
+ }, scheduler.getInterval() * 1000);
1468
1612
  }
1469
- var self = this;
1470
- Faye.ENV.setTimeout(function() { self.connect() }, this._advice.interval);
1613
+
1614
+ if (this._state === this.DOWN) return;
1615
+ this._state = this.DOWN;
1616
+ this._client.trigger('transport:down');
1471
1617
  }
1472
1618
  });
1473
1619
 
1474
- Faye.extend(Faye.Client.prototype, Faye.Deferrable);
1475
- Faye.extend(Faye.Client.prototype, Faye.Publisher);
1476
- Faye.extend(Faye.Client.prototype, Faye.Logging);
1477
- Faye.extend(Faye.Client.prototype, Faye.Extensible);
1620
+ Faye.extend(Faye.Dispatcher.prototype, Faye.Publisher);
1621
+ Faye.extend(Faye.Dispatcher.prototype, Faye.Logging);
1622
+
1623
+ Faye.Scheduler = function(message, options) {
1624
+ this.message = message;
1625
+ this.options = options;
1626
+ this.attempts = 0;
1627
+ };
1628
+
1629
+ Faye.extend(Faye.Scheduler.prototype, {
1630
+ getTimeout: function() {
1631
+ return this.options.timeout;
1632
+ },
1633
+
1634
+ getInterval: function() {
1635
+ return this.options.interval;
1636
+ },
1637
+
1638
+ isDeliverable: function() {
1639
+ var attempts = this.options.attempts,
1640
+ made = this.attempts,
1641
+ deadline = this.options.deadline,
1642
+ now = new Date().getTime();
1643
+
1644
+ if (attempts !== undefined && made >= attempts)
1645
+ return false;
1646
+
1647
+ if (deadline !== undefined && now > deadline)
1648
+ return false;
1649
+
1650
+ return true;
1651
+ },
1652
+
1653
+ send: function() {
1654
+ this.attempts += 1;
1655
+ },
1656
+
1657
+ succeed: function() {},
1658
+
1659
+ fail: function() {},
1660
+
1661
+ abort: function() {}
1662
+ });
1478
1663
 
1479
1664
  Faye.Transport = Faye.extend(Faye.Class({
1480
- MAX_DELAY: 0,
1665
+ DEFAULT_PORTS: {'http:': 80, 'https:': 443, 'ws:': 80, 'wss:': 443},
1666
+ SECURE_PROTOCOLS: ['https:', 'wss:'],
1667
+ MAX_DELAY: 0,
1668
+
1481
1669
  batching: true,
1482
1670
 
1483
- initialize: function(client, endpoint) {
1484
- this._client = client;
1485
- this.endpoint = endpoint;
1486
- this._outbox = [];
1671
+ initialize: function(dispatcher, endpoint) {
1672
+ this._dispatcher = dispatcher;
1673
+ this.endpoint = endpoint;
1674
+ this._outbox = [];
1675
+ this._proxy = Faye.extend({}, this._dispatcher.proxy);
1676
+
1677
+ if (!this._proxy.origin && Faye.NodeAdapter) {
1678
+ this._proxy.origin = Faye.indexOf(this.SECURE_PROTOCOLS, this.endpoint.protocol) >= 0
1679
+ ? (process.env.HTTPS_PROXY || process.env.https_proxy)
1680
+ : (process.env.HTTP_PROXY || process.env.http_proxy);
1681
+ }
1487
1682
  },
1488
1683
 
1489
1684
  close: function() {},
1490
1685
 
1491
- encode: function(envelopes) {
1686
+ encode: function(messages) {
1492
1687
  return '';
1493
1688
  },
1494
1689
 
1495
- send: function(envelope) {
1496
- var message = envelope.message;
1497
-
1690
+ sendMessage: function(message) {
1498
1691
  this.debug('Client ? sending message to ?: ?',
1499
- this._client._clientId, Faye.URI.stringify(this.endpoint), message);
1692
+ this._dispatcher.clientId, Faye.URI.stringify(this.endpoint), message);
1500
1693
 
1501
- if (!this.batching) return this.request([envelope]);
1694
+ if (!this.batching) return Faye.Promise.fulfilled(this.request([message]));
1502
1695
 
1503
- this._outbox.push(envelope);
1696
+ this._outbox.push(message);
1697
+ this._flushLargeBatch();
1698
+ this._promise = this._promise || new Faye.Promise();
1504
1699
 
1505
- if (message.channel === Faye.Channel.HANDSHAKE)
1506
- return this.addTimeout('publish', 0.01, this.flush, this);
1700
+ if (message.channel === Faye.Channel.HANDSHAKE) {
1701
+ this.addTimeout('publish', 0.01, this._flush, this);
1702
+ return this._promise;
1703
+ }
1507
1704
 
1508
1705
  if (message.channel === Faye.Channel.CONNECT)
1509
1706
  this._connectMessage = message;
1510
1707
 
1511
- this.flushLargeBatch();
1512
- this.addTimeout('publish', this.MAX_DELAY, this.flush, this);
1708
+ this.addTimeout('publish', this.MAX_DELAY, this._flush, this);
1709
+ return this._promise;
1513
1710
  },
1514
1711
 
1515
- flush: function() {
1712
+ _flush: function() {
1516
1713
  this.removeTimeout('publish');
1517
1714
 
1518
1715
  if (this._outbox.length > 1 && this._connectMessage)
1519
1716
  this._connectMessage.advice = {timeout: 0};
1520
1717
 
1521
- this.request(this._outbox);
1718
+ Faye.Promise.fulfill(this._promise, this.request(this._outbox));
1719
+ delete this._promise;
1522
1720
 
1523
1721
  this._connectMessage = null;
1524
1722
  this._outbox = [];
1525
1723
  },
1526
1724
 
1527
- flushLargeBatch: function() {
1725
+ _flushLargeBatch: function() {
1528
1726
  var string = this.encode(this._outbox);
1529
- if (string.length < this._client.maxRequestSize) return;
1727
+ if (string.length < this._dispatcher.maxRequestSize) return;
1530
1728
  var last = this._outbox.pop();
1531
- this.flush();
1729
+ this._flush();
1532
1730
  if (last) this._outbox.push(last);
1533
1731
  },
1534
1732
 
1535
- receive: function(envelopes, responses) {
1536
- var n = envelopes.length;
1537
- while (n--) envelopes[n].setDeferredStatus('succeeded');
1733
+ _receive: function(replies) {
1734
+ if (!replies) return;
1735
+ replies = [].concat(replies);
1538
1736
 
1539
- responses = [].concat(responses);
1737
+ this.debug('Client ? received from ? via ?: ?',
1738
+ this._dispatcher.clientId, Faye.URI.stringify(this.endpoint), this.connectionType, replies);
1540
1739
 
1541
- this.debug('Client ? received from ?: ?',
1542
- this._client._clientId, Faye.URI.stringify(this.endpoint), responses);
1543
-
1544
- for (var i = 0, n = responses.length; i < n; i++)
1545
- this._client.receiveMessage(responses[i]);
1740
+ for (var i = 0, n = replies.length; i < n; i++)
1741
+ this._dispatcher.handleResponse(replies[i]);
1546
1742
  },
1547
1743
 
1548
- handleError: function(envelopes, immediate) {
1549
- var n = envelopes.length;
1550
- while (n--) envelopes[n].setDeferredStatus('failed', immediate);
1744
+ _handleError: function(messages, immediate) {
1745
+ messages = [].concat(messages);
1746
+
1747
+ this.debug('Client ? failed to send to ? via ?: ?',
1748
+ this._dispatcher.clientId, Faye.URI.stringify(this.endpoint), this.connectionType, messages);
1749
+
1750
+ for (var i = 0, n = messages.length; i < n; i++)
1751
+ this._dispatcher.handleError(messages[i]);
1551
1752
  },
1552
1753
 
1553
1754
  _getCookies: function() {
1554
- var cookies = this._client.cookies;
1755
+ var cookies = this._dispatcher.cookies,
1756
+ url = Faye.URI.stringify(this.endpoint);
1757
+
1555
1758
  if (!cookies) return '';
1556
1759
 
1557
- return cookies.getCookies({
1558
- domain: this.endpoint.hostname,
1559
- path: this.endpoint.path,
1560
- secure: this.endpoint.protocol === 'https:'
1561
- }).toValueString();
1760
+ return Faye.map(cookies.getCookiesSync(url), function(cookie) {
1761
+ return cookie.cookieString();
1762
+ }).join('; ');
1562
1763
  },
1563
1764
 
1564
1765
  _storeCookies: function(setCookie) {
1565
- if (!setCookie || !this._client.cookies) return;
1766
+ var cookies = this._dispatcher.cookies,
1767
+ url = Faye.URI.stringify(this.endpoint),
1768
+ cookie;
1769
+
1770
+ if (!setCookie || !cookies) return;
1566
1771
  setCookie = [].concat(setCookie);
1567
- var cookie;
1568
1772
 
1569
1773
  for (var i = 0, n = setCookie.length; i < n; i++) {
1570
- cookie = this._client.cookies.setCookie(setCookie[i]);
1571
- cookie = cookie[0] || cookie;
1572
- cookie.domain = cookie.domain || this.endpoint.hostname;
1774
+ cookie = Faye.Cookies.Cookie.parse(setCookie[i]);
1775
+ cookies.setCookieSync(cookie, url);
1573
1776
  }
1574
1777
  }
1575
1778
 
1576
1779
  }), {
1577
- get: function(client, allowed, disabled, callback, context) {
1578
- var endpoint = client.endpoint;
1780
+ get: function(dispatcher, allowed, disabled, callback, context) {
1781
+ var endpoint = dispatcher.endpoint;
1579
1782
 
1580
1783
  Faye.asyncEach(this._transports, function(pair, resume) {
1581
1784
  var connType = pair[0], klass = pair[1],
1582
- connEndpoint = client.endpoints[connType] || endpoint;
1785
+ connEndpoint = dispatcher.endpointFor(connType);
1583
1786
 
1584
1787
  if (Faye.indexOf(disabled, connType) >= 0)
1585
1788
  return resume();
1586
1789
 
1587
1790
  if (Faye.indexOf(allowed, connType) < 0) {
1588
- klass.isUsable(client, connEndpoint, function() {});
1791
+ klass.isUsable(dispatcher, connEndpoint, function() {});
1589
1792
  return resume();
1590
1793
  }
1591
1794
 
1592
- klass.isUsable(client, connEndpoint, function(isUsable) {
1795
+ klass.isUsable(dispatcher, connEndpoint, function(isUsable) {
1593
1796
  if (!isUsable) return resume();
1594
- var transport = klass.hasOwnProperty('create') ? klass.create(client, connEndpoint) : new klass(client, connEndpoint);
1797
+ var transport = klass.hasOwnProperty('create') ? klass.create(dispatcher, connEndpoint) : new klass(dispatcher, connEndpoint);
1595
1798
  callback.call(context, transport);
1596
1799
  });
1597
1800
  }, function() {
@@ -1604,6 +1807,10 @@ Faye.Transport = Faye.extend(Faye.Class({
1604
1807
  klass.prototype.connectionType = type;
1605
1808
  },
1606
1809
 
1810
+ getConnectionTypes: function() {
1811
+ return Faye.map(this._transports, function(t) { return t[0] });
1812
+ },
1813
+
1607
1814
  _transports: []
1608
1815
  });
1609
1816
 
@@ -2155,16 +2362,23 @@ Faye.Transport.WebSocket = Faye.extend(Faye.Class(Faye.Transport, {
2155
2362
  this.connect();
2156
2363
  },
2157
2364
 
2158
- request: function(envelopes) {
2365
+ request: function(messages) {
2159
2366
  this._pending = this._pending || new Faye.Set();
2160
- for (var i = 0, n = envelopes.length; i < n; i++) this._pending.add(envelopes[i]);
2367
+ for (var i = 0, n = messages.length; i < n; i++) this._pending.add(messages[i]);
2368
+
2369
+ var promise = new Faye.Promise();
2161
2370
 
2162
2371
  this.callback(function(socket) {
2163
2372
  if (!socket) return;
2164
- var messages = Faye.map(envelopes, function(e) { return e.message });
2165
2373
  socket.send(Faye.toJSON(messages));
2374
+ Faye.Promise.fulfill(promise, socket);
2166
2375
  }, this);
2376
+
2167
2377
  this.connect();
2378
+
2379
+ return {
2380
+ abort: function() { promise.then(function(ws) { ws.close() }) }
2381
+ };
2168
2382
  },
2169
2383
 
2170
2384
  connect: function() {
@@ -2205,28 +2419,25 @@ Faye.Transport.WebSocket = Faye.extend(Faye.Class(Faye.Transport, {
2205
2419
  delete self._pending;
2206
2420
 
2207
2421
  if (wasConnected) {
2208
- self.handleError(pending, true);
2422
+ self._handleError(pending, true);
2209
2423
  } else if (self._everConnected) {
2210
- self.handleError(pending);
2424
+ self._handleError(pending);
2211
2425
  } else {
2212
2426
  self.setDeferredStatus('failed');
2213
2427
  }
2214
2428
  };
2215
2429
 
2216
2430
  socket.onmessage = function(event) {
2217
- var messages = JSON.parse(event.data),
2218
- envelopes = [],
2219
- envelope;
2431
+ var replies = JSON.parse(event.data);
2432
+ if (!replies) return;
2220
2433
 
2221
- if (!messages) return;
2222
- messages = [].concat(messages);
2434
+ replies = [].concat(replies);
2223
2435
 
2224
- for (var i = 0, n = messages.length; i < n; i++) {
2225
- if (messages[i].successful === undefined) continue;
2226
- envelope = self._pending.remove(messages[i]);
2227
- if (envelope) envelopes.push(envelope);
2436
+ for (var i = 0, n = replies.length; i < n; i++) {
2437
+ if (replies[i].successful === undefined) continue;
2438
+ self._pending.remove(replies[i]);
2228
2439
  }
2229
- self.receive(envelopes, messages);
2440
+ self._receive(replies);
2230
2441
  };
2231
2442
  },
2232
2443
 
@@ -2236,10 +2447,14 @@ Faye.Transport.WebSocket = Faye.extend(Faye.Class(Faye.Transport, {
2236
2447
  },
2237
2448
 
2238
2449
  _createSocket: function() {
2239
- var url = Faye.Transport.WebSocket.getSocketUrl(this.endpoint),
2240
- options = {headers: Faye.copyObject(this._client.headers), ca: this._client.ca};
2450
+ var url = Faye.Transport.WebSocket.getSocketUrl(this.endpoint),
2451
+ headers = this._dispatcher.headers,
2452
+ extensions = this._dispatcher.wsExtensions,
2453
+ cookie = this._getCookies(),
2454
+ tls = this._dispatcher.tls,
2455
+ options = {extensions: extensions, headers: headers, proxy: this._proxy, tls: tls};
2241
2456
 
2242
- options.headers['Cookie'] = this._getCookies();
2457
+ if (cookie !== '') options.headers['Cookie'] = cookie;
2243
2458
 
2244
2459
  if (Faye.WebSocket) return new Faye.WebSocket.Client(url, [], options);
2245
2460
  if (Faye.ENV.MozWebSocket) return new MozWebSocket(url);
@@ -2249,7 +2464,7 @@ Faye.Transport.WebSocket = Faye.extend(Faye.Class(Faye.Transport, {
2249
2464
  _ping: function() {
2250
2465
  if (!this._socket) return;
2251
2466
  this._socket.send('[]');
2252
- this.addTimeout('ping', this._client._advice.timeout/2000, this._ping, this);
2467
+ this.addTimeout('ping', this._dispatcher.timeout / 2, this._ping, this);
2253
2468
  }
2254
2469
 
2255
2470
  }), {
@@ -2258,9 +2473,9 @@ Faye.Transport.WebSocket = Faye.extend(Faye.Class(Faye.Transport, {
2258
2473
  'https:': 'wss:'
2259
2474
  },
2260
2475
 
2261
- create: function(client, endpoint) {
2262
- var sockets = client.transports.websocket = client.transports.websocket || {};
2263
- sockets[endpoint.href] = sockets[endpoint.href] || new this(client, endpoint);
2476
+ create: function(dispatcher, endpoint) {
2477
+ var sockets = dispatcher.transports.websocket = dispatcher.transports.websocket || {};
2478
+ sockets[endpoint.href] = sockets[endpoint.href] || new this(dispatcher, endpoint);
2264
2479
  return sockets[endpoint.href];
2265
2480
  },
2266
2481
 
@@ -2270,28 +2485,28 @@ Faye.Transport.WebSocket = Faye.extend(Faye.Class(Faye.Transport, {
2270
2485
  return Faye.URI.stringify(endpoint);
2271
2486
  },
2272
2487
 
2273
- isUsable: function(client, endpoint, callback, context) {
2274
- this.create(client, endpoint).isUsable(callback, context);
2488
+ isUsable: function(dispatcher, endpoint, callback, context) {
2489
+ this.create(dispatcher, endpoint).isUsable(callback, context);
2275
2490
  }
2276
2491
  });
2277
2492
 
2278
2493
  Faye.extend(Faye.Transport.WebSocket.prototype, Faye.Deferrable);
2279
2494
  Faye.Transport.register('websocket', Faye.Transport.WebSocket);
2280
2495
 
2281
- if (Faye.Event)
2496
+ if (Faye.Event && Faye.ENV.onbeforeunload !== undefined)
2282
2497
  Faye.Event.on(Faye.ENV, 'beforeunload', function() {
2283
2498
  Faye.Transport.WebSocket._unloaded = true;
2284
2499
  });
2285
2500
 
2286
2501
  Faye.Transport.EventSource = Faye.extend(Faye.Class(Faye.Transport, {
2287
- initialize: function(client, endpoint) {
2288
- Faye.Transport.prototype.initialize.call(this, client, endpoint);
2502
+ initialize: function(dispatcher, endpoint) {
2503
+ Faye.Transport.prototype.initialize.call(this, dispatcher, endpoint);
2289
2504
  if (!Faye.ENV.EventSource) return this.setDeferredStatus('failed');
2290
2505
 
2291
- this._xhr = new Faye.Transport.XHR(client, endpoint);
2506
+ this._xhr = new Faye.Transport.XHR(dispatcher, endpoint);
2292
2507
 
2293
2508
  endpoint = Faye.copyObject(endpoint);
2294
- endpoint.pathname += '/' + client._clientId;
2509
+ endpoint.pathname += '/' + dispatcher.clientId;
2295
2510
 
2296
2511
  var socket = new EventSource(Faye.URI.stringify(endpoint)),
2297
2512
  self = this;
@@ -2303,7 +2518,7 @@ Faye.Transport.EventSource = Faye.extend(Faye.Class(Faye.Transport, {
2303
2518
 
2304
2519
  socket.onerror = function() {
2305
2520
  if (self._everConnected) {
2306
- self._client.messageError([]);
2521
+ self._handleError([]);
2307
2522
  } else {
2308
2523
  self.setDeferredStatus('failed');
2309
2524
  socket.close();
@@ -2311,7 +2526,7 @@ Faye.Transport.EventSource = Faye.extend(Faye.Class(Faye.Transport, {
2311
2526
  };
2312
2527
 
2313
2528
  socket.onmessage = function(event) {
2314
- self.receive([], JSON.parse(event.data));
2529
+ self._receive(JSON.parse(event.data));
2315
2530
  };
2316
2531
 
2317
2532
  this._socket = socket;
@@ -2329,34 +2544,34 @@ Faye.Transport.EventSource = Faye.extend(Faye.Class(Faye.Transport, {
2329
2544
  this.errback(function() { callback.call(context, false) });
2330
2545
  },
2331
2546
 
2332
- encode: function(envelopes) {
2333
- return this._xhr.encode(envelopes);
2547
+ encode: function(messages) {
2548
+ return this._xhr.encode(messages);
2334
2549
  },
2335
2550
 
2336
- request: function(envelopes) {
2337
- this._xhr.request(envelopes);
2551
+ request: function(messages) {
2552
+ return this._xhr.request(messages);
2338
2553
  }
2339
2554
 
2340
2555
  }), {
2341
- isUsable: function(client, endpoint, callback, context) {
2342
- var id = client._clientId;
2556
+ isUsable: function(dispatcher, endpoint, callback, context) {
2557
+ var id = dispatcher.clientId;
2343
2558
  if (!id) return callback.call(context, false);
2344
2559
 
2345
- Faye.Transport.XHR.isUsable(client, endpoint, function(usable) {
2560
+ Faye.Transport.XHR.isUsable(dispatcher, endpoint, function(usable) {
2346
2561
  if (!usable) return callback.call(context, false);
2347
- this.create(client, endpoint).isUsable(callback, context);
2562
+ this.create(dispatcher, endpoint).isUsable(callback, context);
2348
2563
  }, this);
2349
2564
  },
2350
2565
 
2351
- create: function(client, endpoint) {
2352
- var sockets = client.transports.eventsource = client.transports.eventsource || {},
2353
- id = client._clientId;
2566
+ create: function(dispatcher, endpoint) {
2567
+ var sockets = dispatcher.transports.eventsource = dispatcher.transports.eventsource || {},
2568
+ id = dispatcher.clientId;
2354
2569
 
2355
- endpoint = Faye.copyObject(endpoint);
2356
- endpoint.pathname += '/' + (id || '');
2357
- var url = Faye.URI.stringify(endpoint);
2570
+ var url = Faye.copyObject(endpoint);
2571
+ url.pathname += '/' + (id || '');
2572
+ url = Faye.URI.stringify(url);
2358
2573
 
2359
- sockets[url] = sockets[url] || new this(client, endpoint);
2574
+ sockets[url] = sockets[url] || new this(dispatcher, endpoint);
2360
2575
  return sockets[url];
2361
2576
  }
2362
2577
  });
@@ -2365,58 +2580,58 @@ Faye.extend(Faye.Transport.EventSource.prototype, Faye.Deferrable);
2365
2580
  Faye.Transport.register('eventsource', Faye.Transport.EventSource);
2366
2581
 
2367
2582
  Faye.Transport.XHR = Faye.extend(Faye.Class(Faye.Transport, {
2368
- encode: function(envelopes) {
2369
- var messages = Faye.map(envelopes, function(e) { return e.message });
2583
+ encode: function(messages) {
2370
2584
  return Faye.toJSON(messages);
2371
2585
  },
2372
2586
 
2373
- request: function(envelopes) {
2374
- var path = this.endpoint.path,
2587
+ request: function(messages) {
2588
+ var href = this.endpoint.href,
2375
2589
  xhr = Faye.ENV.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest(),
2376
2590
  self = this;
2377
2591
 
2378
- xhr.open('POST', path, true);
2592
+ xhr.open('POST', href, true);
2379
2593
  xhr.setRequestHeader('Content-Type', 'application/json');
2380
2594
  xhr.setRequestHeader('Pragma', 'no-cache');
2381
2595
  xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
2382
2596
 
2383
- var headers = this._client.headers;
2597
+ var headers = this._dispatcher.headers;
2384
2598
  for (var key in headers) {
2385
2599
  if (!headers.hasOwnProperty(key)) continue;
2386
2600
  xhr.setRequestHeader(key, headers[key]);
2387
2601
  }
2388
2602
 
2389
2603
  var abort = function() { xhr.abort() };
2390
- Faye.Event.on(Faye.ENV, 'beforeunload', abort);
2604
+ if (Faye.ENV.onbeforeunload !== undefined) Faye.Event.on(Faye.ENV, 'beforeunload', abort);
2391
2605
 
2392
2606
  xhr.onreadystatechange = function() {
2393
2607
  if (!xhr || xhr.readyState !== 4) return;
2394
2608
 
2395
- var parsedMessage = null,
2396
- status = xhr.status,
2397
- text = xhr.responseText,
2398
- successful = (status >= 200 && status < 300) || status === 304 || status === 1223;
2609
+ var replies = null,
2610
+ status = xhr.status,
2611
+ text = xhr.responseText,
2612
+ successful = (status >= 200 && status < 300) || status === 304 || status === 1223;
2399
2613
 
2400
- Faye.Event.detach(Faye.ENV, 'beforeunload', abort);
2614
+ if (Faye.ENV.onbeforeunload !== undefined) Faye.Event.detach(Faye.ENV, 'beforeunload', abort);
2401
2615
  xhr.onreadystatechange = function() {};
2402
2616
  xhr = null;
2403
2617
 
2404
- if (!successful) return self.handleError(envelopes);
2618
+ if (!successful) return self._handleError(messages);
2405
2619
 
2406
2620
  try {
2407
- parsedMessage = JSON.parse(text);
2621
+ replies = JSON.parse(text);
2408
2622
  } catch (e) {}
2409
2623
 
2410
- if (parsedMessage)
2411
- self.receive(envelopes, parsedMessage);
2624
+ if (replies)
2625
+ self._receive(replies);
2412
2626
  else
2413
- self.handleError(envelopes);
2627
+ self._handleError(messages);
2414
2628
  };
2415
2629
 
2416
- xhr.send(this.encode(envelopes));
2630
+ xhr.send(this.encode(messages));
2631
+ return xhr;
2417
2632
  }
2418
2633
  }), {
2419
- isUsable: function(client, endpoint, callback, context) {
2634
+ isUsable: function(dispatcher, endpoint, callback, context) {
2420
2635
  callback.call(context, Faye.URI.isSameOrigin(endpoint));
2421
2636
  }
2422
2637
  });
@@ -2424,15 +2639,14 @@ Faye.Transport.XHR = Faye.extend(Faye.Class(Faye.Transport, {
2424
2639
  Faye.Transport.register('long-polling', Faye.Transport.XHR);
2425
2640
 
2426
2641
  Faye.Transport.CORS = Faye.extend(Faye.Class(Faye.Transport, {
2427
- encode: function(envelopes) {
2428
- var messages = Faye.map(envelopes, function(e) { return e.message });
2642
+ encode: function(messages) {
2429
2643
  return 'message=' + encodeURIComponent(Faye.toJSON(messages));
2430
2644
  },
2431
2645
 
2432
- request: function(envelopes) {
2646
+ request: function(messages) {
2433
2647
  var xhrClass = Faye.ENV.XDomainRequest ? XDomainRequest : XMLHttpRequest,
2434
2648
  xhr = new xhrClass(),
2435
- headers = this._client.headers,
2649
+ headers = this._dispatcher.headers,
2436
2650
  self = this,
2437
2651
  key;
2438
2652
 
@@ -2453,29 +2667,30 @@ Faye.Transport.CORS = Faye.extend(Faye.Class(Faye.Transport, {
2453
2667
  };
2454
2668
 
2455
2669
  xhr.onload = function() {
2456
- var parsedMessage = null;
2670
+ var replies = null;
2457
2671
  try {
2458
- parsedMessage = JSON.parse(xhr.responseText);
2672
+ replies = JSON.parse(xhr.responseText);
2459
2673
  } catch (e) {}
2460
2674
 
2461
2675
  cleanUp();
2462
2676
 
2463
- if (parsedMessage)
2464
- self.receive(envelopes, parsedMessage);
2677
+ if (replies)
2678
+ self._receive(replies);
2465
2679
  else
2466
- self.handleError(envelopes);
2680
+ self._handleError(messages);
2467
2681
  };
2468
2682
 
2469
2683
  xhr.onerror = xhr.ontimeout = function() {
2470
2684
  cleanUp();
2471
- self.handleError(envelopes);
2685
+ self._handleError(messages);
2472
2686
  };
2473
2687
 
2474
2688
  xhr.onprogress = function() {};
2475
- xhr.send(this.encode(envelopes));
2689
+ xhr.send(this.encode(messages));
2690
+ return xhr;
2476
2691
  }
2477
2692
  }), {
2478
- isUsable: function(client, endpoint, callback, context) {
2693
+ isUsable: function(dispatcher, endpoint, callback, context) {
2479
2694
  if (Faye.URI.isSameOrigin(endpoint))
2480
2695
  return callback.call(context, false);
2481
2696
 
@@ -2493,17 +2708,15 @@ Faye.Transport.CORS = Faye.extend(Faye.Class(Faye.Transport, {
2493
2708
  Faye.Transport.register('cross-origin-long-polling', Faye.Transport.CORS);
2494
2709
 
2495
2710
  Faye.Transport.JSONP = Faye.extend(Faye.Class(Faye.Transport, {
2496
- encode: function(envelopes) {
2497
- var messages = Faye.map(envelopes, function(e) { return e.message });
2711
+ encode: function(messages) {
2498
2712
  var url = Faye.copyObject(this.endpoint);
2499
2713
  url.query.message = Faye.toJSON(messages);
2500
2714
  url.query.jsonp = '__jsonp' + Faye.Transport.JSONP._cbCount + '__';
2501
2715
  return Faye.URI.stringify(url);
2502
2716
  },
2503
2717
 
2504
- request: function(envelopes) {
2505
- var messages = Faye.map(envelopes, function(e) { return e.message }),
2506
- head = document.getElementsByTagName('head')[0],
2718
+ request: function(messages) {
2719
+ var head = document.getElementsByTagName('head')[0],
2507
2720
  script = document.createElement('script'),
2508
2721
  callbackName = Faye.Transport.JSONP.getCallbackName(),
2509
2722
  endpoint = Faye.copyObject(this.endpoint),
@@ -2512,17 +2725,28 @@ Faye.Transport.JSONP = Faye.extend(Faye.Class(Faye.Transport, {
2512
2725
  endpoint.query.message = Faye.toJSON(messages);
2513
2726
  endpoint.query.jsonp = callbackName;
2514
2727
 
2515
- Faye.ENV[callbackName] = function(data) {
2728
+ var cleanup = function() {
2516
2729
  if (!Faye.ENV[callbackName]) return false;
2517
2730
  Faye.ENV[callbackName] = undefined;
2518
2731
  try { delete Faye.ENV[callbackName] } catch (e) {}
2519
2732
  script.parentNode.removeChild(script);
2520
- self.receive(envelopes, data);
2733
+ };
2734
+
2735
+ Faye.ENV[callbackName] = function(replies) {
2736
+ cleanup();
2737
+ self._receive(replies);
2521
2738
  };
2522
2739
 
2523
2740
  script.type = 'text/javascript';
2524
2741
  script.src = Faye.URI.stringify(endpoint);
2525
2742
  head.appendChild(script);
2743
+
2744
+ script.onerror = function() {
2745
+ cleanup();
2746
+ self._handleError(messages);
2747
+ };
2748
+
2749
+ return {abort: cleanup};
2526
2750
  }
2527
2751
  }), {
2528
2752
  _cbCount: 0,
@@ -2532,7 +2756,7 @@ Faye.Transport.JSONP = Faye.extend(Faye.Class(Faye.Transport, {
2532
2756
  return '__jsonp' + this._cbCount + '__';
2533
2757
  },
2534
2758
 
2535
- isUsable: function(client, endpoint, callback, context) {
2759
+ isUsable: function(dispatcher, endpoint, callback, context) {
2536
2760
  callback.call(context, true);
2537
2761
  }
2538
2762
  });