spec/utils/javascripts/faye.js in faye-authentication-1.8.2 vs spec/utils/javascripts/faye.js in faye-authentication-1.9.0

- old
+ new

@@ -1,2639 +1,3046 @@ -(function() { -'use strict'; +var Faye = +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) +/******/ return installedModules[moduleId].exports; +/******/ +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ exports: {}, +/******/ id: moduleId, +/******/ loaded: false +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.loaded = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ function(module, exports, __webpack_require__) { -var Faye = { - VERSION: '1.0.3', + 'use strict'; - BAYEUX_VERSION: '1.0', - ID_LENGTH: 160, - JSONP_CALLBACK: 'jsonpcallback', - CONNECTION_TYPES: ['long-polling', 'cross-origin-long-polling', 'callback-polling', 'websocket', 'eventsource', 'in-process'], + var constants = __webpack_require__(1), + Logging = __webpack_require__(2); - MANDATORY_CONNECTION_TYPES: ['long-polling', 'callback-polling', 'in-process'], + var Faye = { + VERSION: constants.VERSION, - ENV: (typeof window !== 'undefined') ? window : global, + Client: __webpack_require__(4), + Scheduler: __webpack_require__(32) + }; - extend: function(dest, source, overwrite) { - if (!source) return dest; - for (var key in source) { - if (!source.hasOwnProperty(key)) continue; - if (dest.hasOwnProperty(key) && overwrite === false) continue; - if (dest[key] !== source[key]) - dest[key] = source[key]; - } - return dest; - }, + Logging.wrapper = Faye; - random: function(bitlength) { - bitlength = bitlength || this.ID_LENGTH; - var maxLength = Math.ceil(bitlength * Math.log(2) / Math.log(36)); - var string = csprng(bitlength, 36); - while (string.length < maxLength) string = '0' + string; - return string; - }, + module.exports = Faye; - clientIdFromMessages: function(messages) { - var connect = this.filter([].concat(messages), function(message) { - return message.channel === '/meta/connect'; - }); - return connect[0] && connect[0].clientId; - }, - copyObject: function(object) { - var clone, i, key; - if (object instanceof Array) { - clone = []; - i = object.length; - while (i--) clone[i] = Faye.copyObject(object[i]); - return clone; - } else if (typeof object === 'object') { - clone = (object === null) ? null : {}; - for (key in object) clone[key] = Faye.copyObject(object[key]); - return clone; - } else { - return object; - } - }, +/***/ }, +/* 1 */ +/***/ function(module, exports) { - commonElement: function(lista, listb) { - for (var i = 0, n = lista.length; i < n; i++) { - if (this.indexOf(listb, lista[i]) !== -1) - return lista[i]; - } - return null; - }, + module.exports = { + VERSION: '1.2.4', - indexOf: function(list, needle) { - if (list.indexOf) return list.indexOf(needle); + BAYEUX_VERSION: '1.0', + ID_LENGTH: 160, + JSONP_CALLBACK: 'jsonpcallback', + CONNECTION_TYPES: ['long-polling', 'cross-origin-long-polling', 'callback-polling', 'websocket', 'eventsource', 'in-process'], - for (var i = 0, n = list.length; i < n; i++) { - if (list[i] === needle) return i; - } - return -1; - }, + MANDATORY_CONNECTION_TYPES: ['long-polling', 'callback-polling', 'in-process'] + }; - map: function(object, callback, context) { - if (object.map) return object.map(callback, context); - var result = []; - if (object instanceof Array) { - for (var i = 0, n = object.length; i < n; i++) { - result.push(callback.call(context || null, object[i], i)); - } - } else { - for (var key in object) { - if (!object.hasOwnProperty(key)) continue; - result.push(callback.call(context || null, key, object[key])); - } - } - return result; - }, +/***/ }, +/* 2 */ +/***/ function(module, exports, __webpack_require__) { - filter: function(array, callback, context) { - if (array.filter) return array.filter(callback, context); - var result = []; - for (var i = 0, n = array.length; i < n; i++) { - if (callback.call(context || null, array[i], i)) - result.push(array[i]); + 'use strict'; + + var toJSON = __webpack_require__(3); + + var Logging = { + LOG_LEVELS: { + fatal: 4, + error: 3, + warn: 2, + info: 1, + debug: 0 + }, + + writeLog: function(messageArgs, level) { + var logger = Logging.logger || (Logging.wrapper || Logging).logger; + if (!logger) return; + + var args = Array.prototype.slice.apply(messageArgs), + banner = '[Faye', + klass = this.className, + + message = args.shift().replace(/\?/g, function() { + try { + return toJSON(args.shift()); + } catch (error) { + return '[Object]'; + } + }); + + if (klass) banner += '.' + klass; + banner += '] '; + + if (typeof logger[level] === 'function') + logger[level](banner + message); + else if (typeof logger === 'function') + logger(banner + message); } - return result; - }, + }; - asyncEach: function(list, iterator, callback, context) { - var n = list.length, - i = -1, - calls = 0, - looping = false; + for (var key in Logging.LOG_LEVELS) + (function(level) { + Logging[level] = function() { + this.writeLog(arguments, level); + }; + })(key); - var iterate = function() { - calls -= 1; - i += 1; - if (i === n) return callback && callback.call(context); - iterator(list[i], resume); - }; + module.exports = Logging; - var loop = function() { - if (looping) return; - looping = true; - while (calls > 0) iterate(); - looping = false; - }; - var resume = function() { - calls += 1; - loop(); - }; - resume(); - }, +/***/ }, +/* 3 */ +/***/ function(module, exports) { + 'use strict'; + // http://assanka.net/content/tech/2009/09/02/json2-js-vs-prototype/ - toJSON: function(object) { - if (!this.stringify) return JSON.stringify(object); - return this.stringify(object, function(key, value) { + module.exports = function(object) { + return JSON.stringify(object, function(key, value) { return (this[key] instanceof Array) ? this[key] : value; }); - } -}; + }; -if (typeof module !== 'undefined') - module.exports = Faye; -else if (typeof window !== 'undefined') - window.Faye = Faye; -Faye.Class = function(parent, methods) { - if (typeof parent !== 'function') { - methods = parent; - parent = Object; - } +/***/ }, +/* 4 */ +/***/ function(module, exports, __webpack_require__) { - var klass = function() { - if (!this.initialize) return this; - return this.initialize.apply(this, arguments) || this; - }; + /* WEBPACK VAR INJECTION */(function(global) {'use strict'; - var bridge = function() {}; - bridge.prototype = parent.prototype; + var asap = __webpack_require__(5), + Class = __webpack_require__(7), + Promise = __webpack_require__(9), + URI = __webpack_require__(10), + array = __webpack_require__(11), + browser = __webpack_require__(12), + constants = __webpack_require__(1), + extend = __webpack_require__(8), + validateOptions = __webpack_require__(13), + Deferrable = __webpack_require__(14), + Logging = __webpack_require__(2), + Publisher = __webpack_require__(15), + Channel = __webpack_require__(17), + Dispatcher = __webpack_require__(19), + Error = __webpack_require__(33), + Extensible = __webpack_require__(34), + Publication = __webpack_require__(35), + Subscription = __webpack_require__(36); - klass.prototype = new bridge(); - Faye.extend(klass.prototype, methods); + var Client = Class({ className: 'Client', + UNCONNECTED: 1, + CONNECTING: 2, + CONNECTED: 3, + DISCONNECTED: 4, - return klass; -}; + HANDSHAKE: 'handshake', + RETRY: 'retry', + NONE: 'none', -(function() { -var EventEmitter = Faye.EventEmitter = function() {}; + CONNECTION_TIMEOUT: 60, -/* -Copyright Joyent, Inc. and other Node contributors. All rights reserved. -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: + DEFAULT_ENDPOINT: '/bayeux', + INTERVAL: 0, -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + initialize: function(endpoint, options) { + this.info('New client created for ?', endpoint); + options = options || {}; -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ + validateOptions(options, ['interval', 'timeout', 'endpoints', 'proxy', 'retry', 'scheduler', 'websocketExtensions', 'tls', 'ca']); -var isArray = typeof Array.isArray === 'function' - ? Array.isArray - : function (xs) { - return Object.prototype.toString.call(xs) === '[object Array]' - } -; -function indexOf (xs, x) { - if (xs.indexOf) return xs.indexOf(x); - for (var i = 0; i < xs.length; i++) { - if (x === xs[i]) return i; - } - return -1; -} + this._channels = new Channel.Set(); + this._dispatcher = Dispatcher.create(this, endpoint || this.DEFAULT_ENDPOINT, options); + this._messageId = 0; + this._state = this.UNCONNECTED; -EventEmitter.prototype.emit = function(type) { - // If there is no 'error' event listener then throw. - if (type === 'error') { - if (!this._events || !this._events.error || - (isArray(this._events.error) && !this._events.error.length)) - { - if (arguments[1] instanceof Error) { - throw arguments[1]; // Unhandled 'error' event - } else { - throw new Error("Uncaught, unspecified 'error' event."); - } - return false; - } - } + this._responseCallbacks = {}; - if (!this._events) return false; - var handler = this._events[type]; - if (!handler) return false; + this._advice = { + reconnect: this.RETRY, + interval: 1000 * (options.interval || this.INTERVAL), + timeout: 1000 * (options.timeout || this.CONNECTION_TIMEOUT) + }; + this._dispatcher.timeout = this._advice.timeout / 1000; - if (typeof handler == 'function') { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - var args = Array.prototype.slice.call(arguments, 1); - handler.apply(this, args); - } - return true; + this._dispatcher.bind('message', this._receiveMessage, this); - } else if (isArray(handler)) { - var args = Array.prototype.slice.call(arguments, 1); + if (browser.Event && global.onbeforeunload !== undefined) + browser.Event.on(global, 'beforeunload', function() { + if (array.indexOf(this._dispatcher._disabled, 'autodisconnect') < 0) + this.disconnect(); + }, this); + }, - var listeners = handler.slice(); - for (var i = 0, l = listeners.length; i < l; i++) { - listeners[i].apply(this, args); - } - return true; + addWebsocketExtension: function(extension) { + return this._dispatcher.addWebsocketExtension(extension); + }, - } else { - return false; - } -}; + disable: function(feature) { + return this._dispatcher.disable(feature); + }, -// EventEmitter is defined in src/node_events.cc -// EventEmitter.prototype.emit() is also defined there. -EventEmitter.prototype.addListener = function(type, listener) { - if ('function' !== typeof listener) { - throw new Error('addListener only takes instances of Function'); - } + setHeader: function(name, value) { + return this._dispatcher.setHeader(name, value); + }, - if (!this._events) this._events = {}; + // Request + // MUST include: * channel + // * version + // * supportedConnectionTypes + // MAY include: * minimumVersion + // * ext + // * id + // + // Success Response Failed Response + // MUST include: * channel MUST include: * channel + // * version * successful + // * supportedConnectionTypes * error + // * clientId MAY include: * supportedConnectionTypes + // * successful * advice + // MAY include: * minimumVersion * version + // * advice * minimumVersion + // * ext * ext + // * id * id + // * authSuccessful + handshake: function(callback, context) { + if (this._advice.reconnect === this.NONE) return; + if (this._state !== this.UNCONNECTED) return; - // To avoid recursion in the case that type == "newListeners"! Before - // adding it to the listeners, first emit "newListeners". - this.emit('newListener', type, listener); + this._state = this.CONNECTING; + var self = this; - if (!this._events[type]) { - // Optimize the case of one listener. Don't need the extra array object. - this._events[type] = listener; - } else if (isArray(this._events[type])) { - // If we've already got an array, just append. - this._events[type].push(listener); - } else { - // Adding the second element, need to change to array. - this._events[type] = [this._events[type], listener]; - } + this.info('Initiating handshake with ?', URI.stringify(this._dispatcher.endpoint)); + this._dispatcher.selectTransport(constants.MANDATORY_CONNECTION_TYPES); - return this; -}; + this._sendMessage({ + channel: Channel.HANDSHAKE, + version: constants.BAYEUX_VERSION, + supportedConnectionTypes: this._dispatcher.getConnectionTypes() -EventEmitter.prototype.on = EventEmitter.prototype.addListener; + }, {}, function(response) { -EventEmitter.prototype.once = function(type, listener) { - var self = this; - self.on(type, function g() { - self.removeListener(type, g); - listener.apply(this, arguments); - }); + if (response.successful) { + this._state = this.CONNECTED; + this._dispatcher.clientId = response.clientId; - return this; -}; + this._dispatcher.selectTransport(response.supportedConnectionTypes); -EventEmitter.prototype.removeListener = function(type, listener) { - if ('function' !== typeof listener) { - throw new Error('removeListener only takes instances of Function'); - } + this.info('Handshake successful: ?', this._dispatcher.clientId); - // does not use listeners(), so no side effect of creating _events[type] - if (!this._events || !this._events[type]) return this; + this.subscribe(this._channels.getKeys(), true); + if (callback) asap(function() { callback.call(context) }); - var list = this._events[type]; + } else { + this.info('Handshake unsuccessful'); + global.setTimeout(function() { self.handshake(callback, context) }, this._dispatcher.retry * 1000); + this._state = this.UNCONNECTED; + } + }, this); + }, - if (isArray(list)) { - var i = indexOf(list, listener); - if (i < 0) return this; - list.splice(i, 1); - if (list.length == 0) - delete this._events[type]; - } else if (this._events[type] === listener) { - delete this._events[type]; - } + // Request Response + // MUST include: * channel MUST include: * channel + // * clientId * successful + // * connectionType * clientId + // MAY include: * ext MAY include: * error + // * id * advice + // * ext + // * id + // * timestamp + connect: function(callback, context) { + if (this._advice.reconnect === this.NONE) return; + if (this._state === this.DISCONNECTED) return; - return this; -}; + if (this._state === this.UNCONNECTED) + return this.handshake(function() { this.connect(callback, context) }, this); -EventEmitter.prototype.removeAllListeners = function(type) { - if (arguments.length === 0) { - this._events = {}; - return this; - } + this.callback(callback, context); + if (this._state !== this.CONNECTED) return; - // does not use listeners(), so no side effect of creating _events[type] - if (type && this._events && this._events[type]) this._events[type] = null; - return this; -}; + this.info('Calling deferred actions for ?', this._dispatcher.clientId); + this.setDeferredStatus('succeeded'); + this.setDeferredStatus('unknown'); -EventEmitter.prototype.listeners = function(type) { - if (!this._events) this._events = {}; - if (!this._events[type]) this._events[type] = []; - if (!isArray(this._events[type])) { - this._events[type] = [this._events[type]]; - } - return this._events[type]; -}; + if (this._connectRequest) return; + this._connectRequest = true; -})(); + this.info('Initiating connection for ?', this._dispatcher.clientId); -Faye.Namespace = Faye.Class({ - initialize: function() { - this._used = {}; - }, + this._sendMessage({ + channel: Channel.CONNECT, + clientId: this._dispatcher.clientId, + connectionType: this._dispatcher.connectionType - exists: function(id) { - return this._used.hasOwnProperty(id); - }, + }, {}, this._cycleConnection, this); + }, - generate: function() { - var name = Faye.random(); - while (this._used.hasOwnProperty(name)) - name = Faye.random(); - return this._used[name] = name; - }, + // Request Response + // MUST include: * channel MUST include: * channel + // * clientId * successful + // MAY include: * ext * clientId + // * id MAY include: * error + // * ext + // * id + disconnect: function() { + if (this._state !== this.CONNECTED) return; + this._state = this.DISCONNECTED; - release: function(id) { - delete this._used[id]; - } -}); + this.info('Disconnecting ?', this._dispatcher.clientId); + var promise = new Publication(); -(function() { -'use strict'; + this._sendMessage({ + channel: Channel.DISCONNECT, + clientId: this._dispatcher.clientId -var timeout = setTimeout; + }, {}, function(response) { + if (response.successful) { + this._dispatcher.close(); + promise.setDeferredStatus('succeeded'); + } else { + promise.setDeferredStatus('failed', Error.parse(response.error)); + } + }, this); -var defer; -if (typeof setImmediate === 'function') - defer = function(fn) { setImmediate(fn) }; -else if (typeof process === 'object' && process.nextTick) - defer = function(fn) { process.nextTick(fn) }; -else - defer = function(fn) { timeout(fn, 0) }; + this.info('Clearing channel listeners for ?', this._dispatcher.clientId); + this._channels = new Channel.Set(); -var PENDING = 0, - FULFILLED = 1, - REJECTED = 2; + return promise; + }, -var RETURN = function(x) { return x }, - THROW = function(x) { throw x }; + // Request Response + // MUST include: * channel MUST include: * channel + // * clientId * successful + // * subscription * clientId + // MAY include: * ext * subscription + // * id MAY include: * error + // * advice + // * ext + // * id + // * timestamp + subscribe: function(channel, callback, context) { + if (channel instanceof Array) + return array.map(channel, function(c) { + return this.subscribe(c, callback, context); + }, this); -var Promise = function(task) { - this._state = PENDING; - this._callbacks = []; - this._errbacks = []; + var subscription = new Subscription(this, channel, callback, context), + force = (callback === true), + hasSubscribe = this._channels.hasSubscription(channel); - if (typeof task !== 'function') return; - var self = this; + if (hasSubscribe && !force) { + this._channels.subscribe([channel], subscription); + subscription.setDeferredStatus('succeeded'); + return subscription; + } - task(function(value) { fulfill(self, value) }, - function(reason) { reject(self, reason) }); -}; + this.connect(function() { + this.info('Client ? attempting to subscribe to ?', this._dispatcher.clientId, channel); + if (!force) this._channels.subscribe([channel], subscription); -Promise.prototype.then = function(callback, errback) { - var next = {}, self = this; + this._sendMessage({ + channel: Channel.SUBSCRIBE, + clientId: this._dispatcher.clientId, + subscription: channel - next.promise = new Promise(function(fulfill, reject) { - next.fulfill = fulfill; - next.reject = reject; + }, {}, function(response) { + if (!response.successful) { + subscription.setDeferredStatus('failed', Error.parse(response.error)); + return this._channels.unsubscribe(channel, subscription); + } - registerCallback(self, callback, next); - registerErrback(self, errback, next); - }); - return next.promise; -}; + var channels = [].concat(response.subscription); + this.info('Subscription acknowledged for ? to ?', this._dispatcher.clientId, channels); + subscription.setDeferredStatus('succeeded'); + }, this); + }, this); -var registerCallback = function(promise, callback, next) { - if (typeof callback !== 'function') callback = RETURN; - var handler = function(value) { invoke(callback, value, next) }; - if (promise._state === PENDING) { - promise._callbacks.push(handler); - } else if (promise._state === FULFILLED) { - handler(promise._value); - } -}; + return subscription; + }, -var registerErrback = function(promise, errback, next) { - if (typeof errback !== 'function') errback = THROW; - var handler = function(reason) { invoke(errback, reason, next) }; - if (promise._state === PENDING) { - promise._errbacks.push(handler); - } else if (promise._state === REJECTED) { - handler(promise._reason); - } -}; + // Request Response + // MUST include: * channel MUST include: * channel + // * clientId * successful + // * subscription * clientId + // MAY include: * ext * subscription + // * id MAY include: * error + // * advice + // * ext + // * id + // * timestamp + unsubscribe: function(channel, subscription) { + if (channel instanceof Array) + return array.map(channel, function(c) { + return this.unsubscribe(c, subscription); + }, this); -var invoke = function(fn, value, next) { - defer(function() { _invoke(fn, value, next) }); -}; + var dead = this._channels.unsubscribe(channel, subscription); + if (!dead) return; -var _invoke = function(fn, value, next) { - var called = false, outcome, type, then; + this.connect(function() { + this.info('Client ? attempting to unsubscribe from ?', this._dispatcher.clientId, channel); - try { - outcome = fn(value); - type = typeof outcome; - then = outcome !== null && (type === 'function' || type === 'object') && outcome.then; + this._sendMessage({ + channel: Channel.UNSUBSCRIBE, + clientId: this._dispatcher.clientId, + subscription: channel - if (outcome === next.promise) - return next.reject(new TypeError('Recursive promise chain detected')); + }, {}, function(response) { + if (!response.successful) return; - if (typeof then !== 'function') return next.fulfill(outcome); + var channels = [].concat(response.subscription); + this.info('Unsubscription acknowledged for ? from ?', this._dispatcher.clientId, channels); + }, this); + }, this); + }, - then.call(outcome, function(v) { - if (called) return; - called = true; - _invoke(RETURN, v, next); - }, function(r) { - if (called) return; - called = true; - next.reject(r); - }); + // Request Response + // MUST include: * channel MUST include: * channel + // * data * successful + // MAY include: * clientId MAY include: * id + // * id * error + // * ext * ext + publish: function(channel, data, options) { + validateOptions(options || {}, ['attempts', 'deadline']); + var publication = new Publication(); - } catch (error) { - if (called) return; - called = true; - next.reject(error); - } -}; + this.connect(function() { + this.info('Client ? queueing published message to ?: ?', this._dispatcher.clientId, channel, data); -var fulfill = Promise.fulfill = Promise.resolve = function(promise, value) { - if (promise._state !== PENDING) return; + this._sendMessage({ + channel: channel, + data: data, + clientId: this._dispatcher.clientId - promise._state = FULFILLED; - promise._value = value; - promise._errbacks = []; + }, options, function(response) { + if (response.successful) + publication.setDeferredStatus('succeeded'); + else + publication.setDeferredStatus('failed', Error.parse(response.error)); + }, this); + }, this); - var callbacks = promise._callbacks, cb; - while (cb = callbacks.shift()) cb(value); -}; + return publication; + }, -var reject = Promise.reject = function(promise, reason) { - if (promise._state !== PENDING) return; + _sendMessage: function(message, options, callback, context) { + message.id = this._generateMessageId(); - promise._state = REJECTED; - promise._reason = reason; - promise._callbacks = []; + var timeout = this._advice.timeout + ? 1.2 * this._advice.timeout / 1000 + : 1.2 * this._dispatcher.retry; - var errbacks = promise._errbacks, eb; - while (eb = errbacks.shift()) eb(reason); -}; + this.pipeThroughExtensions('outgoing', message, null, function(message) { + if (!message) return; + if (callback) this._responseCallbacks[message.id] = [callback, context]; + this._dispatcher.sendMessage(message, timeout, options || {}); + }, this); + }, -Promise.defer = defer; + _generateMessageId: function() { + this._messageId += 1; + if (this._messageId >= Math.pow(2,32)) this._messageId = 0; + return this._messageId.toString(36); + }, -Promise.deferred = Promise.pending = function() { - var tuple = {}; + _receiveMessage: function(message) { + var id = message.id, callback; - tuple.promise = new Promise(function(fulfill, reject) { - tuple.fulfill = tuple.resolve = fulfill; - tuple.reject = reject; - }); - return tuple; -}; + if (message.successful !== undefined) { + callback = this._responseCallbacks[id]; + delete this._responseCallbacks[id]; + } -Promise.fulfilled = Promise.resolved = function(value) { - return new Promise(function(fulfill, reject) { fulfill(value) }); -}; + this.pipeThroughExtensions('incoming', message, null, function(message) { + if (!message) return; + if (message.advice) this._handleAdvice(message.advice); + this._deliverMessage(message); + if (callback) callback[0].call(callback[1], message); + }, this); + }, -Promise.rejected = function(reason) { - return new Promise(function(fulfill, reject) { reject(reason) }); -}; + _handleAdvice: function(advice) { + extend(this._advice, advice); + this._dispatcher.timeout = this._advice.timeout / 1000; -if (typeof Faye === 'undefined') - module.exports = Promise; -else - Faye.Promise = Promise; + if (this._advice.reconnect === this.HANDSHAKE && this._state !== this.DISCONNECTED) { + this._state = this.UNCONNECTED; + this._dispatcher.clientId = null; + this._cycleConnection(); + } + }, -})(); + _deliverMessage: function(message) { + if (!message.channel || message.data === undefined) return; + this.info('Client ? calling listeners for ? with ?', this._dispatcher.clientId, message.channel, message.data); + this._channels.distributeMessage(message); + }, -Faye.Set = Faye.Class({ - initialize: function() { - this._index = {}; - }, + _cycleConnection: function() { + if (this._connectRequest) { + this._connectRequest = null; + this.info('Closed connection for ?', this._dispatcher.clientId); + } + var self = this; + global.setTimeout(function() { self.connect() }, this._advice.interval); + } + }); - add: function(item) { - var key = (item.id !== undefined) ? item.id : item; - if (this._index.hasOwnProperty(key)) return false; - this._index[key] = item; - return true; - }, + extend(Client.prototype, Deferrable); + extend(Client.prototype, Publisher); + extend(Client.prototype, Logging); + extend(Client.prototype, Extensible); - forEach: function(block, context) { - for (var key in this._index) { - if (this._index.hasOwnProperty(key)) - block.call(context, this._index[key]); - } - }, + module.exports = Client; - isEmpty: function() { - for (var key in this._index) { - if (this._index.hasOwnProperty(key)) return false; - } - return true; - }, + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) - member: function(item) { - for (var key in this._index) { - if (this._index[key] === item) return true; - } - return false; - }, +/***/ }, +/* 5 */ +/***/ function(module, exports, __webpack_require__) { - remove: function(item) { - var key = (item.id !== undefined) ? item.id : item; - var removed = this._index[key]; - delete this._index[key]; - return removed; - }, + "use strict"; - toArray: function() { - var array = []; - this.forEach(function(item) { array.push(item) }); - return array; + // rawAsap provides everything we need except exception management. + var rawAsap = __webpack_require__(6); + // RawTasks are recycled to reduce GC churn. + var freeTasks = []; + // We queue errors to ensure they are thrown in right order (FIFO). + // Array-as-queue is good enough here, since we are just dealing with exceptions. + var pendingErrors = []; + var requestErrorThrow = rawAsap.makeRequestCallFromTimer(throwFirstError); + + function throwFirstError() { + if (pendingErrors.length) { + throw pendingErrors.shift(); + } } -}); -Faye.URI = { - isURI: function(uri) { - return uri && uri.protocol && uri.host && uri.path; - }, + /** + * Calls a task as soon as possible after returning, in its own event, with priority + * over other events like animation, reflow, and repaint. An error thrown from an + * event will not interrupt, nor even substantially slow down the processing of + * other events, but will be rather postponed to a lower priority event. + * @param {{call}} task A callable object, typically a function that takes no + * arguments. + */ + module.exports = asap; + function asap(task) { + var rawTask; + if (freeTasks.length) { + rawTask = freeTasks.pop(); + } else { + rawTask = new RawTask(); + } + rawTask.task = task; + rawAsap(rawTask); + } - isSameOrigin: function(uri) { - var location = Faye.ENV.location; - return uri.protocol === location.protocol && - uri.hostname === location.hostname && - uri.port === location.port; - }, + // We wrap tasks with recyclable task objects. A task object implements + // `call`, just like a function. + function RawTask() { + this.task = null; + } - parse: function(url) { - if (typeof url !== 'string') return url; - var uri = {}, parts, query, pairs, i, n, data; + // The sole purpose of wrapping the task is to catch the exception and recycle + // the task object after its single use. + RawTask.prototype.call = function () { + try { + this.task.call(); + } catch (error) { + if (asap.onerror) { + // This hook exists purely for testing purposes. + // Its name will be periodically randomized to break any code that + // depends on its existence. + asap.onerror(error); + } else { + // In a web browser, exceptions are not fatal. However, to avoid + // slowing down the queue of pending tasks, we rethrow the error in a + // lower priority turn. + pendingErrors.push(error); + requestErrorThrow(); + } + } finally { + this.task = null; + freeTasks[freeTasks.length] = this; + } + }; - var consume = function(name, pattern) { - url = url.replace(pattern, function(match) { - uri[name] = match; - return ''; - }); - uri[name] = uri[name] || ''; - }; - consume('protocol', /^[a-z]+\:/i); - consume('host', /^\/\/[^\/\?#]+/); +/***/ }, +/* 6 */ +/***/ function(module, exports) { - if (!/^\//.test(url) && !uri.host) - url = Faye.ENV.location.pathname.replace(/[^\/]*$/, '') + url; + /* WEBPACK VAR INJECTION */(function(global) {"use strict"; - consume('pathname', /^[^\?#]*/); - consume('search', /^\?[^#]*/); - consume('hash', /^#.*/); + // Use the fastest means possible to execute a task in its own turn, with + // priority over other events including IO, animation, reflow, and redraw + // events in browsers. + // + // An exception thrown by a task will permanently interrupt the processing of + // subsequent tasks. The higher level `asap` function ensures that if an + // exception is thrown by a task, that the task queue will continue flushing as + // soon as possible, but if you use `rawAsap` directly, you are responsible to + // either ensure that no exceptions are thrown from your task, or to manually + // call `rawAsap.requestFlush` if an exception is thrown. + module.exports = rawAsap; + function rawAsap(task) { + if (!queue.length) { + requestFlush(); + flushing = true; + } + // Equivalent to push, but avoids a function call. + queue[queue.length] = task; + } - uri.protocol = uri.protocol || Faye.ENV.location.protocol; + var queue = []; + // Once a flush has been requested, no further calls to `requestFlush` are + // necessary until the next `flush` completes. + var flushing = false; + // `requestFlush` is an implementation-specific method that attempts to kick + // off a `flush` event as quickly as possible. `flush` will attempt to exhaust + // the event queue before yielding to the browser's own event loop. + var requestFlush; + // The position of the next task to execute in the task queue. This is + // preserved between calls to `flush` so that it can be resumed if + // a task throws an exception. + var index = 0; + // If a task schedules additional tasks recursively, the task queue can grow + // unbounded. To prevent memory exhaustion, the task queue will periodically + // truncate already-completed tasks. + var capacity = 1024; - if (uri.host) { - uri.host = uri.host.substr(2); - parts = uri.host.split(':'); - uri.hostname = parts[0]; - uri.port = parts[1] || ''; - } else { - uri.host = Faye.ENV.location.host; - uri.hostname = Faye.ENV.location.hostname; - uri.port = Faye.ENV.location.port; - } + // The flush function processes all tasks that have been scheduled with + // `rawAsap` unless and until one of those tasks throws an exception. + // If a task throws an exception, `flush` ensures that its state will remain + // consistent and will resume where it left off when called again. + // However, `flush` does not make any arrangements to be called again if an + // exception is thrown. + function flush() { + while (index < queue.length) { + var currentIndex = index; + // Advance the index before calling the task. This ensures that we will + // begin flushing on the next task the task throws an error. + index = index + 1; + queue[currentIndex].call(); + // Prevent leaking memory for long chains of recursive calls to `asap`. + // If we call `asap` within tasks scheduled by `asap`, the queue will + // grow, but to avoid an O(n) walk for every task we execute, we don't + // shift tasks off the queue after they have been executed. + // Instead, we periodically shift 1024 tasks off the queue. + if (index > capacity) { + // Manually shift all values starting at the index back to the + // beginning of the queue. + for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) { + queue[scan] = queue[scan + index]; + } + queue.length -= index; + index = 0; + } + } + queue.length = 0; + index = 0; + flushing = false; + } - uri.pathname = uri.pathname || '/'; - uri.path = uri.pathname + uri.search; + // `requestFlush` is implemented using a strategy based on data collected from + // every available SauceLabs Selenium web driver worker at time of writing. + // https://docs.google.com/spreadsheets/d/1mG-5UYGup5qxGdEMWkhP6BWCz053NUb2E1QoUTU16uA/edit#gid=783724593 - query = uri.search.replace(/^\?/, ''); - pairs = query ? query.split('&') : []; - data = {}; + // Safari 6 and 6.1 for desktop, iPad, and iPhone are the only browsers that + // have WebKitMutationObserver but not un-prefixed MutationObserver. + // Must use `global` or `self` instead of `window` to work in both frames and web + // workers. `global` is a provision of Browserify, Mr, Mrs, or Mop. - for (i = 0, n = pairs.length; i < n; i++) { - parts = pairs[i].split('='); - data[decodeURIComponent(parts[0] || '')] = decodeURIComponent(parts[1] || ''); - } + /* globals self */ + var scope = typeof global !== "undefined" ? global : self; + var BrowserMutationObserver = scope.MutationObserver || scope.WebKitMutationObserver; - uri.query = data; + // MutationObservers are desirable because they have high priority and work + // reliably everywhere they are implemented. + // They are implemented in all modern browsers. + // + // - Android 4-4.3 + // - Chrome 26-34 + // - Firefox 14-29 + // - Internet Explorer 11 + // - iPad Safari 6-7.1 + // - iPhone Safari 7-7.1 + // - Safari 6-7 + if (typeof BrowserMutationObserver === "function") { + requestFlush = makeRequestCallFromMutationObserver(flush); - uri.href = this.stringify(uri); - return uri; - }, + // MessageChannels are desirable because they give direct access to the HTML + // task queue, are implemented in Internet Explorer 10, Safari 5.0-1, and Opera + // 11-12, and in web workers in many engines. + // Although message channels yield to any queued rendering and IO tasks, they + // would be better than imposing the 4ms delay of timers. + // However, they do not work reliably in Internet Explorer or Safari. - stringify: function(uri) { - var string = uri.protocol + '//' + uri.hostname; - if (uri.port) string += ':' + uri.port; - string += uri.pathname + this.queryString(uri.query) + (uri.hash || ''); - return string; - }, + // Internet Explorer 10 is the only browser that has setImmediate but does + // not have MutationObservers. + // Although setImmediate yields to the browser's renderer, it would be + // preferrable to falling back to setTimeout since it does not have + // the minimum 4ms penalty. + // Unfortunately there appears to be a bug in Internet Explorer 10 Mobile (and + // Desktop to a lesser extent) that renders both setImmediate and + // MessageChannel useless for the purposes of ASAP. + // https://github.com/kriskowal/q/issues/396 - queryString: function(query) { - var pairs = []; - for (var key in query) { - if (!query.hasOwnProperty(key)) continue; - pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(query[key])); - } - if (pairs.length === 0) return ''; - return '?' + pairs.join('&'); + // Timers are implemented universally. + // We fall back to timers in workers in most engines, and in foreground + // contexts in the following browsers. + // However, note that even this simple case requires nuances to operate in a + // broad spectrum of browsers. + // + // - Firefox 3-13 + // - Internet Explorer 6-9 + // - iPad Safari 4.3 + // - Lynx 2.8.7 + } else { + requestFlush = makeRequestCallFromTimer(flush); } -}; -Faye.Error = Faye.Class({ - initialize: function(code, params, message) { - this.code = code; - this.params = Array.prototype.slice.call(params); - this.message = message; - }, + // `requestFlush` requests that the high priority event queue be flushed as + // soon as possible. + // This is useful to prevent an error thrown in a task from stalling the event + // queue if the exception handled by Node.js’s + // `process.on("uncaughtException")` or by a domain. + rawAsap.requestFlush = requestFlush; - toString: function() { - return this.code + ':' + - this.params.join(',') + ':' + - this.message; + // To request a high priority event, we induce a mutation observer by toggling + // the text of a text node between "1" and "-1". + function makeRequestCallFromMutationObserver(callback) { + var toggle = 1; + var observer = new BrowserMutationObserver(callback); + var node = document.createTextNode(""); + observer.observe(node, {characterData: true}); + return function requestCall() { + toggle = -toggle; + node.data = toggle; + }; } -}); -Faye.Error.parse = function(message) { - message = message || ''; - if (!Faye.Grammar.ERROR.test(message)) return new this(null, [], message); + // The message channel technique was discovered by Malte Ubl and was the + // original foundation for this library. + // http://www.nonblocking.io/2011/06/windownexttick.html - var parts = message.split(':'), - code = parseInt(parts[0]), - params = parts[1].split(','), - message = parts[2]; + // Safari 6.0.5 (at least) intermittently fails to create message ports on a + // page's first load. Thankfully, this version of Safari supports + // MutationObservers, so we don't need to fall back in that case. - return new this(code, params, message); -}; + // function makeRequestCallFromMessageChannel(callback) { + // var channel = new MessageChannel(); + // channel.port1.onmessage = callback; + // return function requestCall() { + // channel.port2.postMessage(0); + // }; + // } + // For reasons explained above, we are also unable to use `setImmediate` + // under any circumstances. + // Even if we were, there is another bug in Internet Explorer 10. + // It is not sufficient to assign `setImmediate` to `requestFlush` because + // `setImmediate` must be called *by name* and therefore must be wrapped in a + // closure. + // Never forget. + // function makeRequestCallFromSetImmediate(callback) { + // return function requestCall() { + // setImmediate(callback); + // }; + // } + // Safari 6.0 has a problem where timers will get lost while the user is + // scrolling. This problem does not impact ASAP because Safari 6.0 supports + // mutation observers, so that implementation is used instead. + // However, if we ever elect to use timers in Safari, the prevalent work-around + // is to add a scroll event listener that calls for a flush. -Faye.Error.versionMismatch = function() { - return new this(300, arguments, 'Version mismatch').toString(); -}; + // `setTimeout` does not call the passed callback if the delay is less than + // approximately 7 in web workers in Firefox 8 through 18, and sometimes not + // even then. -Faye.Error.conntypeMismatch = function() { - return new this(301, arguments, 'Connection types not supported').toString(); -}; + function makeRequestCallFromTimer(callback) { + return function requestCall() { + // We dispatch a timeout with a specified delay of 0 for engines that + // can reliably accommodate that request. This will usually be snapped + // to a 4 milisecond delay, but once we're flushing, there's no delay + // between events. + var timeoutHandle = setTimeout(handleTimer, 0); + // However, since this timer gets frequently dropped in Firefox + // workers, we enlist an interval handle that will try to fire + // an event 20 times per second until it succeeds. + var intervalHandle = setInterval(handleTimer, 50); -Faye.Error.extMismatch = function() { - return new this(302, arguments, 'Extension mismatch').toString(); -}; + function handleTimer() { + // Whichever timer succeeds will cancel both timers and + // execute the callback. + clearTimeout(timeoutHandle); + clearInterval(intervalHandle); + callback(); + } + }; + } -Faye.Error.badRequest = function() { - return new this(400, arguments, 'Bad request').toString(); -}; + // This is for `asap.js` only. + // Its name will be periodically randomized to break any code that depends on + // its existence. + rawAsap.makeRequestCallFromTimer = makeRequestCallFromTimer; -Faye.Error.clientUnknown = function() { - return new this(401, arguments, 'Unknown client').toString(); -}; + // ASAP was originally a nextTick shim included in Q. This was factored out + // into this ASAP package. It was later adapted to RSVP which made further + // amendments. These decisions, particularly to marginalize MessageChannel and + // to capture the MutationObserver implementation in a closure, were integrated + // back into ASAP proper. + // https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js -Faye.Error.parameterMissing = function() { - return new this(402, arguments, 'Missing required parameter').toString(); -}; + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) -Faye.Error.channelForbidden = function() { - return new this(403, arguments, 'Forbidden channel').toString(); -}; +/***/ }, +/* 7 */ +/***/ function(module, exports, __webpack_require__) { -Faye.Error.channelUnknown = function() { - return new this(404, arguments, 'Unknown channel').toString(); -}; + 'use strict'; -Faye.Error.channelInvalid = function() { - return new this(405, arguments, 'Invalid channel').toString(); -}; + var extend = __webpack_require__(8); -Faye.Error.extUnknown = function() { - return new this(406, arguments, 'Unknown extension').toString(); -}; + module.exports = function(parent, methods) { + if (typeof parent !== 'function') { + methods = parent; + parent = Object; + } -Faye.Error.publishFailed = function() { - return new this(407, arguments, 'Failed to publish').toString(); -}; + var klass = function() { + if (!this.initialize) return this; + return this.initialize.apply(this, arguments) || this; + }; -Faye.Error.serverError = function() { - return new this(500, arguments, 'Internal server error').toString(); -}; + var bridge = function() {}; + bridge.prototype = parent.prototype; + klass.prototype = new bridge(); + extend(klass.prototype, methods); -Faye.Deferrable = { - then: function(callback, errback) { - var self = this; - if (!this._promise) - this._promise = new Faye.Promise(function(fulfill, reject) { - self._fulfill = fulfill; - self._reject = reject; - }); + return klass; + }; - if (arguments.length === 0) - return this._promise; - else - return this._promise.then(callback, errback); - }, - callback: function(callback, context) { - return this.then(function(value) { callback.call(context, value) }); - }, +/***/ }, +/* 8 */ +/***/ function(module, exports) { - errback: function(callback, context) { - return this.then(null, function(reason) { callback.call(context, reason) }); - }, + 'use strict'; - timeout: function(seconds, message) { - this.then(); - var self = this; - this._timer = Faye.ENV.setTimeout(function() { - self._reject(message); - }, seconds * 1000); - }, + module.exports = function(dest, source, overwrite) { + if (!source) return dest; + for (var key in source) { + if (!source.hasOwnProperty(key)) continue; + if (dest.hasOwnProperty(key) && overwrite === false) continue; + if (dest[key] !== source[key]) + dest[key] = source[key]; + } + return dest; + }; - setDeferredStatus: function(status, value) { - if (this._timer) Faye.ENV.clearTimeout(this._timer); - this.then(); +/***/ }, +/* 9 */ +/***/ function(module, exports, __webpack_require__) { - if (status === 'succeeded') - this._fulfill(value); - else if (status === 'failed') - this._reject(value); - else - delete this._promise; - } -}; + 'use strict'; -Faye.Publisher = { - countListeners: function(eventType) { - return this.listeners(eventType).length; - }, + var asap = __webpack_require__(5); - bind: function(eventType, listener, context) { - var slice = Array.prototype.slice, - handler = function() { listener.apply(context, slice.call(arguments)) }; + var PENDING = 0, + FULFILLED = 1, + REJECTED = 2; - this._listeners = this._listeners || []; - this._listeners.push([eventType, listener, context, handler]); - return this.on(eventType, handler); - }, + var RETURN = function(x) { return x }, + THROW = function(x) { throw x }; - unbind: function(eventType, listener, context) { - this._listeners = this._listeners || []; - var n = this._listeners.length, tuple; + var Promise = function(task) { + this._state = PENDING; + this._onFulfilled = []; + this._onRejected = []; - while (n--) { - tuple = this._listeners[n]; - if (tuple[0] !== eventType) continue; - if (listener && (tuple[1] !== listener || tuple[2] !== context)) continue; - this._listeners.splice(n, 1); - this.removeListener(eventType, tuple[3]); - } - } -}; + if (typeof task !== 'function') return; + var self = this; -Faye.extend(Faye.Publisher, Faye.EventEmitter.prototype); -Faye.Publisher.trigger = Faye.Publisher.emit; + task(function(value) { resolve(self, value) }, + function(reason) { reject(self, reason) }); + }; -Faye.Timeouts = { - addTimeout: function(name, delay, callback, context) { - this._timeouts = this._timeouts || {}; - if (this._timeouts.hasOwnProperty(name)) return; - var self = this; - this._timeouts[name] = Faye.ENV.setTimeout(function() { - delete self._timeouts[name]; - callback.call(context); - }, 1000 * delay); - }, + Promise.prototype.then = function(onFulfilled, onRejected) { + var next = new Promise(); + registerOnFulfilled(this, onFulfilled, next); + registerOnRejected(this, onRejected, next); + return next; + }; - removeTimeout: function(name) { - this._timeouts = this._timeouts || {}; - var timeout = this._timeouts[name]; - if (!timeout) return; - Faye.ENV.clearTimeout(timeout); - delete this._timeouts[name]; - }, + Promise.prototype['catch'] = function(onRejected) { + return this.then(null, onRejected); + }; - removeAllTimeouts: function() { - this._timeouts = this._timeouts || {}; - for (var name in this._timeouts) this.removeTimeout(name); - } -}; + var registerOnFulfilled = function(promise, onFulfilled, next) { + if (typeof onFulfilled !== 'function') onFulfilled = RETURN; + var handler = function(value) { invoke(onFulfilled, value, next) }; -Faye.Logging = { - LOG_LEVELS: { - fatal: 4, - error: 3, - warn: 2, - info: 1, - debug: 0 - }, + if (promise._state === PENDING) { + promise._onFulfilled.push(handler); + } else if (promise._state === FULFILLED) { + handler(promise._value); + } + }; - writeLog: function(messageArgs, level) { - if (!Faye.logger) return; + var registerOnRejected = function(promise, onRejected, next) { + if (typeof onRejected !== 'function') onRejected = THROW; + var handler = function(reason) { invoke(onRejected, reason, next) }; - var args = Array.prototype.slice.apply(messageArgs), - banner = '[Faye', - klass = this.className, + if (promise._state === PENDING) { + promise._onRejected.push(handler); + } else if (promise._state === REJECTED) { + handler(promise._reason); + } + }; - message = args.shift().replace(/\?/g, function() { - try { - return Faye.toJSON(args.shift()); - } catch (e) { - return '[Object]'; - } - }); + var invoke = function(fn, value, next) { + asap(function() { _invoke(fn, value, next) }); + }; - for (var key in Faye) { - if (klass) continue; - if (typeof Faye[key] !== 'function') continue; - if (this instanceof Faye[key]) klass = key; + var _invoke = function(fn, value, next) { + var outcome; + + try { + outcome = fn(value); + } catch (error) { + return reject(next, error); } - if (klass) banner += '.' + klass; - banner += '] '; - if (typeof Faye.logger[level] === 'function') - Faye.logger[level](banner + message); - else if (typeof Faye.logger === 'function') - Faye.logger(banner + message); - } -}; + if (outcome === next) { + reject(next, new TypeError('Recursive promise chain detected')); + } else { + resolve(next, outcome); + } + }; -(function() { - for (var key in Faye.Logging.LOG_LEVELS) - (function(level) { - Faye.Logging[level] = function() { - this.writeLog(arguments, level); - }; - })(key); -})(); + var resolve = function(promise, value) { + var called = false, type, then; -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])|\-|\_))*)*$/ -}; + try { + type = typeof value; + then = value !== null && (type === 'function' || type === 'object') && value.then; -Faye.Extensible = { - addExtension: function(extension) { - this._extensions = this._extensions || []; - this._extensions.push(extension); - if (extension.added) extension.added(this); - }, + if (typeof then !== 'function') return fulfill(promise, value); - removeExtension: function(extension) { - if (!this._extensions) return; - var i = this._extensions.length; - while (i--) { - if (this._extensions[i] !== extension) continue; - this._extensions.splice(i,1); - if (extension.removed) extension.removed(this); + then.call(value, function(v) { + if (!(called ^ (called = true))) return; + resolve(promise, v); + }, function(r) { + if (!(called ^ (called = true))) return; + reject(promise, r); + }); + } catch (error) { + if (!(called ^ (called = true))) return; + reject(promise, error); } - }, + }; - pipeThroughExtensions: function(stage, message, request, callback, context) { - this.debug('Passing through ? extensions: ?', stage, message); + var fulfill = function(promise, value) { + if (promise._state !== PENDING) return; - if (!this._extensions) return callback.call(context, message); - var extensions = this._extensions.slice(); + promise._state = FULFILLED; + promise._value = value; + promise._onRejected = []; - var pipe = function(message) { - if (!message) return callback.call(context, message); + var onFulfilled = promise._onFulfilled, fn; + while (fn = onFulfilled.shift()) fn(value); + }; - var extension = extensions.shift(); - if (!extension) return callback.call(context, message); + var reject = function(promise, reason) { + if (promise._state !== PENDING) return; - var fn = extension[stage]; - if (!fn) return pipe(message); + promise._state = REJECTED; + promise._reason = reason; + promise._onFulfilled = []; - if (fn.length >= 3) extension[stage](message, request, pipe); - else extension[stage](message, pipe); - }; - pipe(message); - } -}; + var onRejected = promise._onRejected, fn; + while (fn = onRejected.shift()) fn(reason); + }; -Faye.extend(Faye.Extensible, Faye.Logging); + Promise.resolve = function(value) { + return new Promise(function(resolve, reject) { resolve(value) }); + }; -Faye.Channel = Faye.Class({ - initialize: function(name) { - this.id = this.name = name; - }, + Promise.reject = function(reason) { + return new Promise(function(resolve, reject) { reject(reason) }); + }; - push: function(message) { - this.trigger('message', message); - }, + Promise.all = function(promises) { + return new Promise(function(resolve, reject) { + var list = [], n = promises.length, i; - isUnused: function() { - return this.countListeners('message') === 0; - } -}); + if (n === 0) return resolve(list); -Faye.extend(Faye.Channel.prototype, Faye.Publisher); + for (i = 0; i < n; i++) (function(promise, i) { + Promise.resolve(promise).then(function(value) { + list[i] = value; + if (--n === 0) resolve(list); + }, reject); + })(promises[i], i); + }); + }; -Faye.extend(Faye.Channel, { - HANDSHAKE: '/meta/handshake', - CONNECT: '/meta/connect', - SUBSCRIBE: '/meta/subscribe', - UNSUBSCRIBE: '/meta/unsubscribe', - DISCONNECT: '/meta/disconnect', + Promise.race = function(promises) { + return new Promise(function(resolve, reject) { + for (var i = 0, n = promises.length; i < n; i++) + Promise.resolve(promises[i]).then(resolve, reject); + }); + }; - META: 'meta', - SERVICE: 'service', + Promise.deferred = Promise.pending = function() { + var tuple = {}; - expand: function(name) { - var segments = this.parse(name), - channels = ['/**', name]; + tuple.promise = new Promise(function(resolve, reject) { + tuple.resolve = resolve; + tuple.reject = reject; + }); + return tuple; + }; - var copy = segments.slice(); - copy[copy.length - 1] = '*'; - channels.push(this.unparse(copy)); + module.exports = Promise; - for (var i = 1, n = segments.length; i < n; i++) { - copy = segments.slice(0, i); - copy.push('**'); - channels.push(this.unparse(copy)); - } - return channels; - }, +/***/ }, +/* 10 */ +/***/ function(module, exports) { - isValid: function(name) { - return Faye.Grammar.CHANNEL_NAME.test(name) || - Faye.Grammar.CHANNEL_PATTERN.test(name); - }, + 'use strict'; - parse: function(name) { - if (!this.isValid(name)) return null; - return name.split('/').slice(1); - }, + module.exports = { + isURI: function(uri) { + return uri && uri.protocol && uri.host && uri.path; + }, - unparse: function(segments) { - return '/' + segments.join('/'); - }, + isSameOrigin: function(uri) { + return uri.protocol === location.protocol && + uri.hostname === location.hostname && + uri.port === location.port; + }, - isMeta: function(name) { - var segments = this.parse(name); - return segments ? (segments[0] === this.META) : null; - }, + parse: function(url) { + if (typeof url !== 'string') return url; + var uri = {}, parts, query, pairs, i, n, data; - isService: function(name) { - var segments = this.parse(name); - return segments ? (segments[0] === this.SERVICE) : null; - }, + var consume = function(name, pattern) { + url = url.replace(pattern, function(match) { + uri[name] = match; + return ''; + }); + uri[name] = uri[name] || ''; + }; - isSubscribable: function(name) { - if (!this.isValid(name)) return null; - return !this.isMeta(name) && !this.isService(name); - }, + consume('protocol', /^[a-z]+\:/i); + consume('host', /^\/\/[^\/\?#]+/); - Set: Faye.Class({ - initialize: function() { - this._channels = {}; - }, + if (!/^\//.test(url) && !uri.host) + url = location.pathname.replace(/[^\/]*$/, '') + url; - getKeys: function() { - var keys = []; - for (var key in this._channels) keys.push(key); - return keys; + consume('pathname', /^[^\?#]*/); + consume('search', /^\?[^#]*/); + consume('hash', /^#.*/); + + uri.protocol = uri.protocol || location.protocol; + + if (uri.host) { + uri.host = uri.host.substr(2); + parts = uri.host.split(':'); + uri.hostname = parts[0]; + uri.port = parts[1] || ''; + } else { + uri.host = location.host; + uri.hostname = location.hostname; + uri.port = location.port; + } + + uri.pathname = uri.pathname || '/'; + uri.path = uri.pathname + uri.search; + + query = uri.search.replace(/^\?/, ''); + pairs = query ? query.split('&') : []; + data = {}; + + for (i = 0, n = pairs.length; i < n; i++) { + parts = pairs[i].split('='); + data[decodeURIComponent(parts[0] || '')] = decodeURIComponent(parts[1] || ''); + } + + uri.query = data; + + uri.href = this.stringify(uri); + return uri; }, - remove: function(name) { - delete this._channels[name]; + stringify: function(uri) { + var string = uri.protocol + '//' + uri.hostname; + if (uri.port) string += ':' + uri.port; + string += uri.pathname + this.queryString(uri.query) + (uri.hash || ''); + return string; }, - hasSubscription: function(name) { - return this._channels.hasOwnProperty(name); + queryString: function(query) { + var pairs = []; + for (var key in query) { + if (!query.hasOwnProperty(key)) continue; + pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(query[key])); + } + if (pairs.length === 0) return ''; + return '?' + pairs.join('&'); + } + }; + + +/***/ }, +/* 11 */ +/***/ function(module, exports) { + + 'use strict'; + + module.exports = { + commonElement: function(lista, listb) { + for (var i = 0, n = lista.length; i < n; i++) { + if (this.indexOf(listb, lista[i]) !== -1) + return lista[i]; + } + return null; }, - subscribe: function(names, callback, context) { - var name; - for (var i = 0, n = names.length; i < n; i++) { - name = names[i]; - var channel = this._channels[name] = this._channels[name] || new Faye.Channel(name); - if (callback) channel.bind('message', callback, context); + indexOf: function(list, needle) { + if (list.indexOf) return list.indexOf(needle); + + for (var i = 0, n = list.length; i < n; i++) { + if (list[i] === needle) return i; } + return -1; }, - unsubscribe: function(name, callback, context) { - var channel = this._channels[name]; - if (!channel) return false; - channel.unbind('message', callback, context); + map: function(object, callback, context) { + if (object.map) return object.map(callback, context); + var result = []; - if (channel.isUnused()) { - this.remove(name); - return true; + if (object instanceof Array) { + for (var i = 0, n = object.length; i < n; i++) { + result.push(callback.call(context || null, object[i], i)); + } } else { - return false; + for (var key in object) { + if (!object.hasOwnProperty(key)) continue; + result.push(callback.call(context || null, key, object[key])); + } } + return result; }, - distributeMessage: function(message) { - var channels = Faye.Channel.expand(message.channel); - - for (var i = 0, n = channels.length; i < n; i++) { - var channel = this._channels[channels[i]]; - if (channel) channel.trigger('message', message.data); + filter: function(array, callback, context) { + if (array.filter) return array.filter(callback, context); + var result = []; + for (var i = 0, n = array.length; i < n; i++) { + if (callback.call(context || null, array[i], i)) + result.push(array[i]); } - } - }) -}); + return result; + }, -Faye.Publication = Faye.Class(Faye.Deferrable); + asyncEach: function(list, iterator, callback, context) { + var n = list.length, + i = -1, + calls = 0, + looping = false; -Faye.Subscription = Faye.Class({ - initialize: function(client, channels, callback, context) { - this._client = client; - this._channels = channels; - this._callback = callback; - this._context = context; - this._cancelled = false; - }, + var iterate = function() { + calls -= 1; + i += 1; + if (i === n) return callback && callback.call(context); + iterator(list[i], resume); + }; - cancel: function() { - if (this._cancelled) return; - this._client.unsubscribe(this._channels, this._callback, this._context); - this._cancelled = true; - }, + var loop = function() { + if (looping) return; + looping = true; + while (calls > 0) iterate(); + looping = false; + }; - unsubscribe: function() { - this.cancel(); - } -}); + var resume = function() { + calls += 1; + loop(); + }; + resume(); + } + }; -Faye.extend(Faye.Subscription.prototype, Faye.Deferrable); -Faye.Client = Faye.Class({ - UNCONNECTED: 1, - CONNECTING: 2, - CONNECTED: 3, - DISCONNECTED: 4, +/***/ }, +/* 12 */ +/***/ function(module, exports) { - HANDSHAKE: 'handshake', - RETRY: 'retry', - NONE: 'none', + /* WEBPACK VAR INJECTION */(function(global) {'use strict'; - CONNECTION_TIMEOUT: 60, + var Event = { + _registry: [], - DEFAULT_ENDPOINT: '/bayeux', - INTERVAL: 0, + on: function(element, eventName, callback, context) { + var wrapped = function() { callback.call(context) }; - initialize: function(endpoint, options) { - this.info('New client created for ?', endpoint); - options = options || {}; + if (element.addEventListener) + element.addEventListener(eventName, wrapped, false); + else + element.attachEvent('on' + eventName, wrapped); - this._endpoint = endpoint || this.DEFAULT_ENDPOINT; - this._channels = new Faye.Channel.Set(); - this._dispatcher = new Faye.Dispatcher(this, this._endpoint, options); + this._registry.push({ + _element: element, + _type: eventName, + _callback: callback, + _context: context, + _handler: wrapped + }); + }, - this._messageId = 0; - this._state = this.UNCONNECTED; + detach: function(element, eventName, callback, context) { + var i = this._registry.length, register; + while (i--) { + register = this._registry[i]; - this._responseCallbacks = {}; + if ((element && element !== register._element) || + (eventName && eventName !== register._type) || + (callback && callback !== register._callback) || + (context && context !== register._context)) + continue; - this._advice = { - reconnect: this.RETRY, - interval: 1000 * (options.interval || this.INTERVAL), - timeout: 1000 * (options.timeout || this.CONNECTION_TIMEOUT) - }; - this._dispatcher.timeout = this._advice.timeout / 1000; + if (register._element.removeEventListener) + register._element.removeEventListener(register._type, register._handler, false); + else + register._element.detachEvent('on' + register._type, register._handler); - this._dispatcher.bind('message', this._receiveMessage, this); + this._registry.splice(i,1); + register = null; + } + } + }; - if (Faye.Event && Faye.ENV.onbeforeunload !== undefined) - Faye.Event.on(Faye.ENV, 'beforeunload', function() { - if (Faye.indexOf(this._dispatcher._disabled, 'autodisconnect') < 0) - this.disconnect(); - }, this); - }, + if (global.onunload !== undefined) + Event.on(global, 'unload', Event.detach, Event); - disable: function(feature) { - return this._dispatcher.disable(feature); - }, + module.exports = { + Event: Event + }; - setHeader: function(name, value) { - return this._dispatcher.setHeader(name, value); - }, + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) - // Request - // MUST include: * channel - // * version - // * supportedConnectionTypes - // MAY include: * minimumVersion - // * ext - // * id - // - // Success Response Failed Response - // MUST include: * channel MUST include: * channel - // * version * successful - // * supportedConnectionTypes * error - // * clientId MAY include: * supportedConnectionTypes - // * successful * advice - // MAY include: * minimumVersion * version - // * advice * minimumVersion - // * ext * ext - // * id * id - // * authSuccessful - handshake: function(callback, context) { - if (this._advice.reconnect === this.NONE) return; - if (this._state !== this.UNCONNECTED) return; +/***/ }, +/* 13 */ +/***/ function(module, exports, __webpack_require__) { - this._state = this.CONNECTING; - var self = this; + 'use strict'; - this.info('Initiating handshake with ?', Faye.URI.stringify(this._endpoint)); - this._dispatcher.selectTransport(Faye.MANDATORY_CONNECTION_TYPES); + var array = __webpack_require__(11); - this._sendMessage({ - channel: Faye.Channel.HANDSHAKE, - version: Faye.BAYEUX_VERSION, - supportedConnectionTypes: [this._dispatcher.connectionType] + module.exports = function(options, validKeys) { + for (var key in options) { + if (array.indexOf(validKeys, key) < 0) + throw new Error('Unrecognized option: ' + key); + } + }; - }, {}, function(response) { - if (response.successful) { - this._state = this.CONNECTED; - this._dispatcher.clientId = response.clientId; +/***/ }, +/* 14 */ +/***/ function(module, exports, __webpack_require__) { - this._dispatcher.selectTransport(response.supportedConnectionTypes); + /* WEBPACK VAR INJECTION */(function(global) {'use strict'; - this.info('Handshake successful: ?', this._dispatcher.clientId); + var Promise = __webpack_require__(9); - this.subscribe(this._channels.getKeys(), true); - if (callback) Faye.Promise.defer(function() { callback.call(context) }); + module.exports = { + then: function(callback, errback) { + var self = this; + if (!this._promise) + this._promise = new Promise(function(resolve, reject) { + self._resolve = resolve; + self._reject = reject; + }); - } else { - this.info('Handshake unsuccessful'); - Faye.ENV.setTimeout(function() { self.handshake(callback, context) }, this._dispatcher.retry * 1000); - this._state = this.UNCONNECTED; - } - }, this); - }, + if (arguments.length === 0) + return this._promise; + else + return this._promise.then(callback, errback); + }, - // Request Response - // MUST include: * channel MUST include: * channel - // * clientId * successful - // * connectionType * clientId - // MAY include: * ext MAY include: * error - // * id * advice - // * ext - // * id - // * timestamp - connect: function(callback, context) { - if (this._advice.reconnect === this.NONE) return; - if (this._state === this.DISCONNECTED) return; + callback: function(callback, context) { + return this.then(function(value) { callback.call(context, value) }); + }, - if (this._state === this.UNCONNECTED) - return this.handshake(function() { this.connect(callback, context) }, this); + errback: function(callback, context) { + return this.then(null, function(reason) { callback.call(context, reason) }); + }, - this.callback(callback, context); - if (this._state !== this.CONNECTED) return; + timeout: function(seconds, message) { + this.then(); + var self = this; + this._timer = global.setTimeout(function() { + self._reject(message); + }, seconds * 1000); + }, - this.info('Calling deferred actions for ?', this._dispatcher.clientId); - this.setDeferredStatus('succeeded'); - this.setDeferredStatus('unknown'); + setDeferredStatus: function(status, value) { + if (this._timer) global.clearTimeout(this._timer); - if (this._connectRequest) return; - this._connectRequest = true; + this.then(); - this.info('Initiating connection for ?', this._dispatcher.clientId); + if (status === 'succeeded') + this._resolve(value); + else if (status === 'failed') + this._reject(value); + else + delete this._promise; + } + }; - this._sendMessage({ - channel: Faye.Channel.CONNECT, - clientId: this._dispatcher.clientId, - connectionType: this._dispatcher.connectionType + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) - }, {}, this._cycleConnection, this); - }, +/***/ }, +/* 15 */ +/***/ function(module, exports, __webpack_require__) { - // Request Response - // MUST include: * channel MUST include: * channel - // * clientId * successful - // MAY include: * ext * clientId - // * id MAY include: * error - // * ext - // * id - disconnect: function() { - if (this._state !== this.CONNECTED) return; - this._state = this.DISCONNECTED; + 'use strict'; - this.info('Disconnecting ?', this._dispatcher.clientId); + var extend = __webpack_require__(8), + EventEmitter = __webpack_require__(16); - this._sendMessage({ - channel: Faye.Channel.DISCONNECT, - clientId: this._dispatcher.clientId + var Publisher = { + countListeners: function(eventType) { + return this.listeners(eventType).length; + }, - }, {}, function(response) { - if (response.successful) this._dispatcher.close(); - }, this); + bind: function(eventType, listener, context) { + var slice = Array.prototype.slice, + handler = function() { listener.apply(context, slice.call(arguments)) }; - this.info('Clearing channel listeners for ?', this._dispatcher.clientId); - this._channels = new Faye.Channel.Set(); - }, + this._listeners = this._listeners || []; + this._listeners.push([eventType, listener, context, handler]); + return this.on(eventType, handler); + }, - // Request Response - // MUST include: * channel MUST include: * channel - // * clientId * successful - // * subscription * clientId - // MAY include: * ext * subscription - // * id MAY include: * error - // * advice - // * ext - // * id - // * timestamp - subscribe: function(channel, callback, context) { - if (channel instanceof Array) - return Faye.map(channel, function(c) { - return this.subscribe(c, callback, context); - }, this); + unbind: function(eventType, listener, context) { + this._listeners = this._listeners || []; + var n = this._listeners.length, tuple; - var subscription = new Faye.Subscription(this, channel, callback, context), - force = (callback === true), - hasSubscribe = this._channels.hasSubscription(channel); - - if (hasSubscribe && !force) { - this._channels.subscribe([channel], callback, context); - subscription.setDeferredStatus('succeeded'); - return subscription; + while (n--) { + tuple = this._listeners[n]; + if (tuple[0] !== eventType) continue; + if (listener && (tuple[1] !== listener || tuple[2] !== context)) continue; + this._listeners.splice(n, 1); + this.removeListener(eventType, tuple[3]); + } } + }; - this.connect(function() { - this.info('Client ? attempting to subscribe to ?', this._dispatcher.clientId, channel); - if (!force) this._channels.subscribe([channel], callback, context); + extend(Publisher, EventEmitter.prototype); + Publisher.trigger = Publisher.emit; - this._sendMessage({ - channel: Faye.Channel.SUBSCRIBE, - clientId: this._dispatcher.clientId, - subscription: channel + module.exports = Publisher; - }, {}, function(response) { - if (!response.successful) { - subscription.setDeferredStatus('failed', Faye.Error.parse(response.error)); - return this._channels.unsubscribe(channel, callback, context); - } - var channels = [].concat(response.subscription); - this.info('Subscription acknowledged for ? to ?', this._dispatcher.clientId, channels); - subscription.setDeferredStatus('succeeded'); - }, this); - }, this); +/***/ }, +/* 16 */ +/***/ function(module, exports) { - return subscription; - }, + /* + Copyright Joyent, Inc. and other Node contributors. All rights reserved. + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: - // Request Response - // MUST include: * channel MUST include: * channel - // * clientId * successful - // * subscription * clientId - // MAY include: * ext * subscription - // * id MAY include: * error - // * advice - // * ext - // * id - // * timestamp - unsubscribe: function(channel, callback, context) { - if (channel instanceof Array) - return Faye.map(channel, function(c) { - return this.unsubscribe(c, callback, context); - }, this); + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. - var dead = this._channels.unsubscribe(channel, callback, context); - if (!dead) return; + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ - this.connect(function() { - this.info('Client ? attempting to unsubscribe from ?', this._dispatcher.clientId, channel); + var isArray = typeof Array.isArray === 'function' + ? Array.isArray + : function (xs) { + return Object.prototype.toString.call(xs) === '[object Array]' + } + ; + function indexOf (xs, x) { + if (xs.indexOf) return xs.indexOf(x); + for (var i = 0; i < xs.length; i++) { + if (x === xs[i]) return i; + } + return -1; + } - this._sendMessage({ - channel: Faye.Channel.UNSUBSCRIBE, - clientId: this._dispatcher.clientId, - subscription: channel + function EventEmitter() {} + module.exports = EventEmitter; - }, {}, function(response) { - if (!response.successful) return; + EventEmitter.prototype.emit = function(type) { + // If there is no 'error' event listener then throw. + if (type === 'error') { + if (!this._events || !this._events.error || + (isArray(this._events.error) && !this._events.error.length)) + { + if (arguments[1] instanceof Error) { + throw arguments[1]; // Unhandled 'error' event + } else { + throw new Error("Uncaught, unspecified 'error' event."); + } + return false; + } + } - var channels = [].concat(response.subscription); - this.info('Unsubscription acknowledged for ? from ?', this._dispatcher.clientId, channels); - }, this); - }, this); - }, + if (!this._events) return false; + var handler = this._events[type]; + if (!handler) return false; - // Request Response - // MUST include: * channel MUST include: * channel - // * data * successful - // MAY include: * clientId MAY include: * id - // * id * error - // * ext * ext - publish: function(channel, data, options) { - var publication = new Faye.Publication(); + if (typeof handler == 'function') { + switch (arguments.length) { + // fast cases + case 1: + handler.call(this); + break; + case 2: + handler.call(this, arguments[1]); + break; + case 3: + handler.call(this, arguments[1], arguments[2]); + break; + // slower + default: + var args = Array.prototype.slice.call(arguments, 1); + handler.apply(this, args); + } + return true; - this.connect(function() { - this.info('Client ? queueing published message to ?: ?', this._dispatcher.clientId, channel, data); + } else if (isArray(handler)) { + var args = Array.prototype.slice.call(arguments, 1); - this._sendMessage({ - channel: channel, - data: data, - clientId: this._dispatcher.clientId + var listeners = handler.slice(); + for (var i = 0, l = listeners.length; i < l; i++) { + listeners[i].apply(this, args); + } + return true; - }, options, function(response) { - if (response.successful) - publication.setDeferredStatus('succeeded'); - else - publication.setDeferredStatus('failed', Faye.Error.parse(response.error)); - }, this); - }, this); + } else { + return false; + } + }; - return publication; - }, + // EventEmitter is defined in src/node_events.cc + // EventEmitter.prototype.emit() is also defined there. + EventEmitter.prototype.addListener = function(type, listener) { + if ('function' !== typeof listener) { + throw new Error('addListener only takes instances of Function'); + } - _sendMessage: function(message, options, callback, context) { - message.id = this._generateMessageId(); + if (!this._events) this._events = {}; - var timeout = this._advice.timeout - ? 1.2 * this._advice.timeout / 1000 - : 1.2 * this._dispatcher.retry; + // To avoid recursion in the case that type == "newListeners"! Before + // adding it to the listeners, first emit "newListeners". + this.emit('newListener', type, listener); - this.pipeThroughExtensions('outgoing', message, null, function(message) { - if (!message) return; - if (callback) this._responseCallbacks[message.id] = [callback, context]; - this._dispatcher.sendMessage(message, timeout, options || {}); - }, this); - }, + if (!this._events[type]) { + // Optimize the case of one listener. Don't need the extra array object. + this._events[type] = listener; + } else if (isArray(this._events[type])) { + // If we've already got an array, just append. + this._events[type].push(listener); + } else { + // Adding the second element, need to change to array. + this._events[type] = [this._events[type], listener]; + } - _generateMessageId: function() { - this._messageId += 1; - if (this._messageId >= Math.pow(2,32)) this._messageId = 0; - return this._messageId.toString(36); - }, + return this; + }; - _receiveMessage: function(message) { - var id = message.id, callback; + EventEmitter.prototype.on = EventEmitter.prototype.addListener; - if (message.successful !== undefined) { - callback = this._responseCallbacks[id]; - delete this._responseCallbacks[id]; + EventEmitter.prototype.once = function(type, listener) { + var self = this; + self.on(type, function g() { + self.removeListener(type, g); + listener.apply(this, arguments); + }); + + return this; + }; + + EventEmitter.prototype.removeListener = function(type, listener) { + if ('function' !== typeof listener) { + throw new Error('removeListener only takes instances of Function'); } - this.pipeThroughExtensions('incoming', message, null, function(message) { - if (!message) return; - if (message.advice) this._handleAdvice(message.advice); - this._deliverMessage(message); - if (callback) callback[0].call(callback[1], message); - }, this); - }, + // does not use listeners(), so no side effect of creating _events[type] + if (!this._events || !this._events[type]) return this; - _handleAdvice: function(advice) { - Faye.extend(this._advice, advice); - this._dispatcher.timeout = this._advice.timeout / 1000; + var list = this._events[type]; - if (this._advice.reconnect === this.HANDSHAKE && this._state !== this.DISCONNECTED) { - this._state = this.UNCONNECTED; - this._dispatcher.clientId = null; - this._cycleConnection(); + if (isArray(list)) { + var i = indexOf(list, listener); + if (i < 0) return this; + list.splice(i, 1); + if (list.length == 0) + delete this._events[type]; + } else if (this._events[type] === listener) { + delete this._events[type]; } - }, - _deliverMessage: function(message) { - if (!message.channel || message.data === undefined) return; - this.info('Client ? calling listeners for ? with ?', this._dispatcher.clientId, message.channel, message.data); - this._channels.distributeMessage(message); - }, + return this; + }; - _cycleConnection: function() { - if (this._connectRequest) { - this._connectRequest = null; - this.info('Closed connection for ?', this._dispatcher.clientId); + EventEmitter.prototype.removeAllListeners = function(type) { + if (arguments.length === 0) { + this._events = {}; + return this; } - var self = this; - Faye.ENV.setTimeout(function() { self.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); + // does not use listeners(), so no side effect of creating _events[type] + if (type && this._events && this._events[type]) this._events[type] = null; + return this; + }; -Faye.Dispatcher = Faye.Class({ - MAX_REQUEST_SIZE: 2048, - DEFAULT_RETRY: 5, + EventEmitter.prototype.listeners = function(type) { + if (!this._events) this._events = {}; + if (!this._events[type]) this._events[type] = []; + if (!isArray(this._events[type])) { + this._events[type] = [this._events[type]]; + } + return this._events[type]; + }; - UP: 1, - DOWN: 2, - initialize: function(client, endpoint, options) { - this._client = client; - this.endpoint = Faye.URI.parse(endpoint); - this._alternates = options.endpoints || {}; +/***/ }, +/* 17 */ +/***/ function(module, exports, __webpack_require__) { - this.ca = options.ca; - this.cookies = Faye.Cookies && new Faye.Cookies.CookieJar(); - this._disabled = []; - this._envelopes = {}; - this.headers = {}; - this.retry = options.retry || this.DEFAULT_RETRY; - this._state = 0; - this.transports = {}; + 'use strict'; - for (var type in this._alternates) - this._alternates[type] = Faye.URI.parse(this._alternates[type]); + var Class = __webpack_require__(7), + extend = __webpack_require__(8), + Publisher = __webpack_require__(15), + Grammar = __webpack_require__(18); - this.maxRequestSize = this.MAX_REQUEST_SIZE; - }, + var Channel = Class({ + initialize: function(name) { + this.id = this.name = name; + }, - endpointFor: function(connectionType) { - return this._alternates[connectionType] || this.endpoint; - }, + push: function(message) { + this.trigger('message', message); + }, - disable: function(feature) { - this._disabled.push(feature); - }, + isUnused: function() { + return this.countListeners('message') === 0; + } + }); - setHeader: function(name, value) { - this.headers[name] = value; - }, + extend(Channel.prototype, Publisher); - close: function() { - var transport = this._transport; - delete this._transport; - if (transport) transport.close(); - }, + extend(Channel, { + HANDSHAKE: '/meta/handshake', + CONNECT: '/meta/connect', + SUBSCRIBE: '/meta/subscribe', + UNSUBSCRIBE: '/meta/unsubscribe', + DISCONNECT: '/meta/disconnect', - selectTransport: function(transportTypes) { - Faye.Transport.get(this, transportTypes, this._disabled, function(transport) { - this.debug('Selected ? transport for ?', transport.connectionType, Faye.URI.stringify(transport.endpoint)); + META: 'meta', + SERVICE: 'service', - if (transport === this._transport) return; - if (this._transport) this._transport.close(); + expand: function(name) { + var segments = this.parse(name), + channels = ['/**', name]; - this._transport = transport; - this.connectionType = transport.connectionType; - }, this); - }, + var copy = segments.slice(); + copy[copy.length - 1] = '*'; + channels.push(this.unparse(copy)); - sendMessage: function(message, timeout, options) { - if (!this._transport) return; - options = options || {}; + for (var i = 1, n = segments.length; i < n; i++) { + copy = segments.slice(0, i); + copy.push('**'); + channels.push(this.unparse(copy)); + } - var self = this, - id = message.id, - attempts = options.attempts, - deadline = options.deadline && new Date().getTime() + (options.deadline * 1000), + return channels; + }, - envelope = this._envelopes[id] = this._envelopes[id] || - {message: message, timeout: timeout, attempts: attempts, deadline: deadline}; + isValid: function(name) { + return Grammar.CHANNEL_NAME.test(name) || + Grammar.CHANNEL_PATTERN.test(name); + }, - if (envelope.request || envelope.timer) return; + parse: function(name) { + if (!this.isValid(name)) return null; + return name.split('/').slice(1); + }, - if (this._attemptsExhausted(envelope) || this._deadlinePassed(envelope)) { - delete this._envelopes[id]; - return; - } + unparse: function(segments) { + return '/' + segments.join('/'); + }, - envelope.timer = Faye.ENV.setTimeout(function() { - self.handleError(message); - }, timeout * 1000); + isMeta: function(name) { + var segments = this.parse(name); + return segments ? (segments[0] === this.META) : null; + }, - envelope.request = this._transport.sendMessage(message); - }, + isService: function(name) { + var segments = this.parse(name); + return segments ? (segments[0] === this.SERVICE) : null; + }, - handleResponse: function(reply) { - var envelope = this._envelopes[reply.id]; + isSubscribable: function(name) { + if (!this.isValid(name)) return null; + return !this.isMeta(name) && !this.isService(name); + }, - if (reply.successful !== undefined && envelope) { - delete this._envelopes[reply.id]; - Faye.ENV.clearTimeout(envelope.timer); - } + Set: Class({ + initialize: function() { + this._channels = {}; + }, - this.trigger('message', reply); + getKeys: function() { + var keys = []; + for (var key in this._channels) keys.push(key); + return keys; + }, - if (this._state === this.UP) return; - this._state = this.UP; - this._client.trigger('transport:up'); - }, + remove: function(name) { + delete this._channels[name]; + }, - handleError: function(message, immediate) { - var envelope = this._envelopes[message.id], - request = envelope && envelope.request, - self = this; + hasSubscription: function(name) { + return this._channels.hasOwnProperty(name); + }, - if (!request) return; + subscribe: function(names, subscription) { + var name; + for (var i = 0, n = names.length; i < n; i++) { + name = names[i]; + var channel = this._channels[name] = this._channels[name] || new Channel(name); + channel.bind('message', subscription); + } + }, - request.then(function(req) { - if (req && req.abort) req.abort(); - }); + unsubscribe: function(name, subscription) { + var channel = this._channels[name]; + if (!channel) return false; + channel.unbind('message', subscription); - Faye.ENV.clearTimeout(envelope.timer); - envelope.request = envelope.timer = null; + if (channel.isUnused()) { + this.remove(name); + return true; + } else { + return false; + } + }, - if (immediate) { - this.sendMessage(envelope.message, envelope.timeout); - } else { - envelope.timer = Faye.ENV.setTimeout(function() { - envelope.timer = null; - self.sendMessage(envelope.message, envelope.timeout); - }, this.retry * 1000); - } + distributeMessage: function(message) { + var channels = Channel.expand(message.channel); - if (this._state === this.DOWN) return; - this._state = this.DOWN; - this._client.trigger('transport:down'); - }, + for (var i = 0, n = channels.length; i < n; i++) { + var channel = this._channels[channels[i]]; + if (channel) channel.trigger('message', message); + } + } + }) + }); - _attemptsExhausted: function(envelope) { - if (envelope.attempts === undefined) return false; - envelope.attempts -= 1; - if (envelope.attempts >= 0) return false; - return true; - }, + module.exports = Channel; - _deadlinePassed: function(envelope) { - var deadline = envelope.deadline; - if (deadline === undefined) return false; - if (new Date().getTime() <= deadline) return false; - return true; - } -}); -Faye.extend(Faye.Dispatcher.prototype, Faye.Publisher); -Faye.extend(Faye.Dispatcher.prototype, Faye.Logging); +/***/ }, +/* 18 */ +/***/ function(module, exports) { -Faye.Transport = Faye.extend(Faye.Class({ - MAX_DELAY: 0, - batching: true, + 'use strict'; - initialize: function(dispatcher, endpoint) { - this._dispatcher = dispatcher; - this.endpoint = endpoint; - this._outbox = []; - }, + module.exports = { + 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])|\-|\_))*)*$/ + }; - close: function() {}, - encode: function(messages) { - return ''; - }, +/***/ }, +/* 19 */ +/***/ function(module, exports, __webpack_require__) { - sendMessage: function(message) { - this.debug('Client ? sending message to ?: ?', - this._dispatcher.clientId, Faye.URI.stringify(this.endpoint), message); + /* WEBPACK VAR INJECTION */(function(global) {'use strict'; - if (!this.batching) return Faye.Promise.fulfilled(this.request([message])); + var Class = __webpack_require__(7), + URI = __webpack_require__(10), + cookies = __webpack_require__(20), + extend = __webpack_require__(8), + Logging = __webpack_require__(2), + Publisher = __webpack_require__(15), + Transport = __webpack_require__(21), + Scheduler = __webpack_require__(32); - this._outbox.push(message); - this._flushLargeBatch(); - this._promise = this._promise || new Faye.Promise(); + var Dispatcher = Class({ className: 'Dispatcher', + MAX_REQUEST_SIZE: 2048, + DEFAULT_RETRY: 5, - if (message.channel === Faye.Channel.HANDSHAKE) { - this.addTimeout('publish', 0.01, this._flush, this); - return this._promise; - } + UP: 1, + DOWN: 2, - if (message.channel === Faye.Channel.CONNECT) - this._connectMessage = message; + initialize: function(client, endpoint, options) { + this._client = client; + this.endpoint = URI.parse(endpoint); + this._alternates = options.endpoints || {}; - this.addTimeout('publish', this.MAX_DELAY, this._flush, this); - return this._promise; - }, + this.cookies = cookies.CookieJar && new cookies.CookieJar(); + this._disabled = []; + this._envelopes = {}; + this.headers = {}; + this.retry = options.retry || this.DEFAULT_RETRY; + this._scheduler = options.scheduler || Scheduler; + this._state = 0; + this.transports = {}; + this.wsExtensions = []; - _flush: function() { - this.removeTimeout('publish'); + this.proxy = options.proxy || {}; + if (typeof this._proxy === 'string') this._proxy = {origin: this._proxy}; - if (this._outbox.length > 1 && this._connectMessage) - this._connectMessage.advice = {timeout: 0}; + var exts = options.websocketExtensions; + if (exts) { + exts = [].concat(exts); + for (var i = 0, n = exts.length; i < n; i++) + this.addWebsocketExtension(exts[i]); + } - Faye.Promise.fulfill(this._promise, this.request(this._outbox)); - delete this._promise; + this.tls = options.tls || {}; + this.tls.ca = this.tls.ca || options.ca; - this._connectMessage = null; - this._outbox = []; - }, + for (var type in this._alternates) + this._alternates[type] = URI.parse(this._alternates[type]); - _flushLargeBatch: function() { - var string = this.encode(this._outbox); - if (string.length < this._dispatcher.maxRequestSize) return; - var last = this._outbox.pop(); - this._flush(); - if (last) this._outbox.push(last); - }, + this.maxRequestSize = this.MAX_REQUEST_SIZE; + }, - _receive: function(replies) { - replies = [].concat(replies); + endpointFor: function(connectionType) { + return this._alternates[connectionType] || this.endpoint; + }, - this.debug('Client ? received from ? via ?: ?', - this._dispatcher.clientId, Faye.URI.stringify(this.endpoint), this.connectionType, replies); + addWebsocketExtension: function(extension) { + this.wsExtensions.push(extension); + }, - for (var i = 0, n = replies.length; i < n; i++) - this._dispatcher.handleResponse(replies[i]); - }, + disable: function(feature) { + this._disabled.push(feature); + }, - _handleError: function(messages, immediate) { - messages = [].concat(messages); + setHeader: function(name, value) { + this.headers[name] = value; + }, - this.debug('Client ? failed to send to ? via ?: ?', - this._dispatcher.clientId, Faye.URI.stringify(this.endpoint), this.connectionType, messages); + close: function() { + var transport = this._transport; + delete this._transport; + if (transport) transport.close(); + }, - for (var i = 0, n = messages.length; i < n; i++) - this._dispatcher.handleError(messages[i]); - }, + getConnectionTypes: function() { + return Transport.getConnectionTypes(); + }, - _getCookies: function() { - var cookies = this._dispatcher.cookies, - url = Faye.URI.stringify(this.endpoint); + selectTransport: function(transportTypes) { + Transport.get(this, transportTypes, this._disabled, function(transport) { + this.debug('Selected ? transport for ?', transport.connectionType, URI.stringify(transport.endpoint)); - if (!cookies) return ''; + if (transport === this._transport) return; + if (this._transport) this._transport.close(); - return Faye.map(cookies.getCookiesSync(url), function(cookie) { - return cookie.cookieString(); - }).join('; '); - }, + this._transport = transport; + this.connectionType = transport.connectionType; + }, this); + }, - _storeCookies: function(setCookie) { - var cookies = this._dispatcher.cookies, - url = Faye.URI.stringify(this.endpoint), - cookie; + sendMessage: function(message, timeout, options) { + options = options || {}; - if (!setCookie || !cookies) return; - setCookie = [].concat(setCookie); + var id = message.id, + attempts = options.attempts, + deadline = options.deadline && new Date().getTime() + (options.deadline * 1000), + envelope = this._envelopes[id], + scheduler; - for (var i = 0, n = setCookie.length; i < n; i++) { - cookie = Faye.Cookies.Cookie.parse(setCookie[i]); - cookies.setCookieSync(cookie, url); - } - } + if (!envelope) { + scheduler = new this._scheduler(message, {timeout: timeout, interval: this.retry, attempts: attempts, deadline: deadline}); + envelope = this._envelopes[id] = {message: message, scheduler: scheduler}; + } -}), { - get: function(dispatcher, allowed, disabled, callback, context) { - var endpoint = dispatcher.endpoint; + this._sendEnvelope(envelope); + }, - Faye.asyncEach(this._transports, function(pair, resume) { - var connType = pair[0], klass = pair[1], - connEndpoint = dispatcher.endpointFor(connType); + _sendEnvelope: function(envelope) { + if (!this._transport) return; + if (envelope.request || envelope.timer) return; - if (Faye.indexOf(disabled, connType) >= 0) - return resume(); + var message = envelope.message, + scheduler = envelope.scheduler, + self = this; - if (Faye.indexOf(allowed, connType) < 0) { - klass.isUsable(dispatcher, connEndpoint, function() {}); - return resume(); + if (!scheduler.isDeliverable()) { + scheduler.abort(); + delete this._envelopes[message.id]; + return; } - klass.isUsable(dispatcher, connEndpoint, function(isUsable) { - if (!isUsable) return resume(); - var transport = klass.hasOwnProperty('create') ? klass.create(dispatcher, connEndpoint) : new klass(dispatcher, connEndpoint); - callback.call(context, transport); - }); - }, function() { - throw new Error('Could not find a usable connection type for ' + Faye.URI.stringify(endpoint)); - }); - }, + envelope.timer = global.setTimeout(function() { + self.handleError(message); + }, scheduler.getTimeout() * 1000); - register: function(type, klass) { - this._transports.push([type, klass]); - klass.prototype.connectionType = type; - }, + scheduler.send(); + envelope.request = this._transport.sendMessage(message); + }, - _transports: [] -}); + handleResponse: function(reply) { + var envelope = this._envelopes[reply.id]; -Faye.extend(Faye.Transport.prototype, Faye.Logging); -Faye.extend(Faye.Transport.prototype, Faye.Timeouts); + if (reply.successful !== undefined && envelope) { + envelope.scheduler.succeed(); + delete this._envelopes[reply.id]; + global.clearTimeout(envelope.timer); + } -Faye.Event = { - _registry: [], + this.trigger('message', reply); - on: function(element, eventName, callback, context) { - var wrapped = function() { callback.call(context) }; + if (this._state === this.UP) return; + this._state = this.UP; + this._client.trigger('transport:up'); + }, - if (element.addEventListener) - element.addEventListener(eventName, wrapped, false); - else - element.attachEvent('on' + eventName, wrapped); + handleError: function(message, immediate) { + var envelope = this._envelopes[message.id], + request = envelope && envelope.request, + self = this; - this._registry.push({ - _element: element, - _type: eventName, - _callback: callback, - _context: context, - _handler: wrapped - }); - }, + if (!request) return; - detach: function(element, eventName, callback, context) { - var i = this._registry.length, register; - while (i--) { - register = this._registry[i]; + request.then(function(req) { + if (req && req.abort) req.abort(); + }); - if ((element && element !== register._element) || - (eventName && eventName !== register._type) || - (callback && callback !== register._callback) || - (context && context !== register._context)) - continue; + var scheduler = envelope.scheduler; + scheduler.fail(); - if (register._element.removeEventListener) - register._element.removeEventListener(register._type, register._handler, false); - else - register._element.detachEvent('on' + register._type, register._handler); + global.clearTimeout(envelope.timer); + envelope.request = envelope.timer = null; - this._registry.splice(i,1); - register = null; + if (immediate) { + this._sendEnvelope(envelope); + } else { + envelope.timer = global.setTimeout(function() { + envelope.timer = null; + self._sendEnvelope(envelope); + }, scheduler.getInterval() * 1000); + } + + if (this._state === this.DOWN) return; + this._state = this.DOWN; + this._client.trigger('transport:down'); } - } -}; + }); -if (Faye.ENV.onunload !== undefined) Faye.Event.on(Faye.ENV, 'unload', Faye.Event.detach, Faye.Event); + Dispatcher.create = function(client, endpoint, options) { + return new Dispatcher(client, endpoint, options); + }; -/* - json2.js - 2013-05-26 + extend(Dispatcher.prototype, Publisher); + extend(Dispatcher.prototype, Logging); - Public Domain. + module.exports = Dispatcher; - NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) - See http://www.JSON.org/js.html +/***/ }, +/* 20 */ +/***/ function(module, exports) { + 'use strict'; - This code should be minified before deployment. - See http://javascript.crockford.com/jsmin.html + module.exports = {}; - USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO - NOT CONTROL. +/***/ }, +/* 21 */ +/***/ function(module, exports, __webpack_require__) { - This file creates a global JSON object containing two methods: stringify - and parse. + 'use strict'; - JSON.stringify(value, replacer, space) - value any JavaScript value, usually an object or array. + var Transport = __webpack_require__(22); - replacer an optional parameter that determines how object - values are stringified for objects. It can be a - function or an array of strings. + Transport.register('websocket', __webpack_require__(24)); + Transport.register('eventsource', __webpack_require__(28)); + Transport.register('long-polling', __webpack_require__(29)); + Transport.register('cross-origin-long-polling', __webpack_require__(30)); + Transport.register('callback-polling', __webpack_require__(31)); - space an optional parameter that specifies the indentation - of nested structures. If it is omitted, the text will - be packed without extra whitespace. If it is a number, - it will specify the number of spaces to indent at each - level. If it is a string (such as '\t' or '&nbsp;'), - it contains the characters used to indent at each level. + module.exports = Transport; - This method produces a JSON text from a JavaScript value. - When an object value is found, if the object contains a toJSON - method, its toJSON method will be called and the result will be - stringified. A toJSON method does not serialize: it returns the - value represented by the name/value pair that should be serialized, - or undefined if nothing should be serialized. The toJSON method - will be passed the key associated with the value, and this will be - bound to the value +/***/ }, +/* 22 */ +/***/ function(module, exports, __webpack_require__) { - For example, this would serialize Dates as ISO strings. + 'use strict'; - Date.prototype.toJSON = function (key) { - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } + var Class = __webpack_require__(7), + Cookie = __webpack_require__(20).Cookie, + Promise = __webpack_require__(9), + URI = __webpack_require__(10), + array = __webpack_require__(11), + extend = __webpack_require__(8), + Logging = __webpack_require__(2), + Timeouts = __webpack_require__(23), + Channel = __webpack_require__(17); - return this.getUTCFullYear() + '-' + - f(this.getUTCMonth() + 1) + '-' + - f(this.getUTCDate()) + 'T' + - f(this.getUTCHours()) + ':' + - f(this.getUTCMinutes()) + ':' + - f(this.getUTCSeconds()) + 'Z'; - }; + var Transport = extend(Class({ className: 'Transport', + DEFAULT_PORTS: {'http:': 80, 'https:': 443, 'ws:': 80, 'wss:': 443}, + MAX_DELAY: 0, - You can provide an optional replacer method. It will be passed the - key and value of each member, with this bound to the containing - object. The value that is returned from your method will be - serialized. If your method returns undefined, then the member will - be excluded from the serialization. + batching: true, - If the replacer parameter is an array of strings, then it will be - used to select the members to be serialized. It filters the results - such that only members with keys listed in the replacer array are - stringified. + initialize: function(dispatcher, endpoint) { + this._dispatcher = dispatcher; + this.endpoint = endpoint; + this._outbox = []; + this._proxy = extend({}, this._dispatcher.proxy); - Values that do not have JSON representations, such as undefined or - functions, will not be serialized. Such values in objects will be - dropped; in arrays they will be replaced with null. You can use - a replacer function to replace those with JSON values. - JSON.stringify(undefined) returns undefined. + if (!this._proxy.origin) + this._proxy.origin = this._findProxy(); + }, - The optional space parameter produces a stringification of the - value that is filled with line breaks and indentation to make it - easier to read. + close: function() {}, - If the space parameter is a non-empty string, then that string will - be used for indentation. If the space parameter is a number, then - the indentation will be that many spaces. + encode: function(messages) { + return ''; + }, - Example: + sendMessage: function(message) { + this.debug('Client ? sending message to ?: ?', + this._dispatcher.clientId, URI.stringify(this.endpoint), message); - text = JSON.stringify(['e', {pluribus: 'unum'}]); - // text is '["e",{"pluribus":"unum"}]' + if (!this.batching) return Promise.resolve(this.request([message])); + this._outbox.push(message); + this._flushLargeBatch(); - text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); - // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' + if (message.channel === Channel.HANDSHAKE) + return this._publish(0.01); - text = JSON.stringify([new Date()], function (key, value) { - return this[key] instanceof Date ? - 'Date(' + this[key] + ')' : value; - }); - // text is '["Date(---current time---)"]' + if (message.channel === Channel.CONNECT) + this._connectMessage = message; + return this._publish(this.MAX_DELAY); + }, - JSON.parse(text, reviver) - This method parses a JSON text to produce an object or array. - It can throw a SyntaxError exception. + _makePromise: function() { + var self = this; - The optional reviver parameter is a function that can filter and - transform the results. It receives each of the keys and values, - and its return value is used instead of the original value. - If it returns what it received, then the structure is not modified. - If it returns undefined then the member is deleted. + this._requestPromise = this._requestPromise || new Promise(function(resolve) { + self._resolvePromise = resolve; + }); + }, - Example: + _publish: function(delay) { + this._makePromise(); - // Parse the text. Values that look like ISO date strings will - // be converted to Date objects. + this.addTimeout('publish', delay, function() { + this._flush(); + delete this._requestPromise; + }, this); - myData = JSON.parse(text, function (key, value) { - var a; - if (typeof value === 'string') { - a = -/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); - if (a) { - return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], - +a[5], +a[6])); - } - } - return value; - }); + return this._requestPromise; + }, - myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { - var d; - if (typeof value === 'string' && - value.slice(0, 5) === 'Date(' && - value.slice(-1) === ')') { - d = new Date(value.slice(5, -1)); - if (d) { - return d; - } - } - return value; - }); + _flush: function() { + this.removeTimeout('publish'); + if (this._outbox.length > 1 && this._connectMessage) + this._connectMessage.advice = {timeout: 0}; - This is a reference implementation. You are free to copy, modify, or - redistribute. -*/ + this._resolvePromise(this.request(this._outbox)); -/*jslint evil: true, regexp: true */ + this._connectMessage = null; + this._outbox = []; + }, -/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, - call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, - getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, - lastIndex, length, parse, prototype, push, replace, slice, stringify, - test, toJSON, toString, valueOf -*/ + _flushLargeBatch: function() { + var string = this.encode(this._outbox); + if (string.length < this._dispatcher.maxRequestSize) return; + var last = this._outbox.pop(); + this._makePromise(); + this._flush(); -// Create a JSON object only if one does not already exist. We create the -// methods in a closure to avoid creating global variables. + if (last) this._outbox.push(last); + }, -if (typeof JSON !== 'object') { - JSON = {}; -} + _receive: function(replies) { + if (!replies) return; + replies = [].concat(replies); -(function () { - 'use strict'; + this.debug('Client ? received from ? via ?: ?', + this._dispatcher.clientId, URI.stringify(this.endpoint), this.connectionType, replies); - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } + for (var i = 0, n = replies.length; i < n; i++) + this._dispatcher.handleResponse(replies[i]); + }, - if (typeof Date.prototype.toJSON !== 'function') { + _handleError: function(messages, immediate) { + messages = [].concat(messages); - Date.prototype.toJSON = function () { + this.debug('Client ? failed to send to ? via ?: ?', + this._dispatcher.clientId, URI.stringify(this.endpoint), this.connectionType, messages); - 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; - }; + for (var i = 0, n = messages.length; i < n; i++) + this._dispatcher.handleError(messages[i]); + }, - String.prototype.toJSON = - Number.prototype.toJSON = - Boolean.prototype.toJSON = function () { - return this.valueOf(); - }; - } + _getCookies: function() { + var cookies = this._dispatcher.cookies, + url = URI.stringify(this.endpoint); - 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 = { // table of character substitutions - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '"' : '\\"', - '\\': '\\\\' - }, - rep; + if (!cookies) return ''; + return array.map(cookies.getCookiesSync(url), function(cookie) { + return cookie.cookieString(); + }).join('; '); + }, - function quote(string) { + _storeCookies: function(setCookie) { + var cookies = this._dispatcher.cookies, + url = URI.stringify(this.endpoint), + cookie; -// If the string contains no control characters, no quote characters, and no -// backslash characters, then we can safely slap some quotes around it. -// Otherwise we must also replace the offending characters with safe escape -// sequences. + if (!setCookie || !cookies) return; + setCookie = [].concat(setCookie); - escapable.lastIndex = 0; - return escapable.test(string) ? '"' + string.replace(escapable, function (a) { - var c = meta[a]; - return typeof c === 'string' - ? c - : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }) + '"' : '"' + string + '"'; - } + for (var i = 0, n = setCookie.length; i < n; i++) { + cookie = Cookie.parse(setCookie[i]); + cookies.setCookieSync(cookie, url); + } + }, + _findProxy: function() { + if (typeof process === 'undefined') return undefined; - function str(key, holder) { + var protocol = this.endpoint.protocol; + if (!protocol) return undefined; -// Produce a string from holder[key]. + var name = protocol.replace(/:$/, '').toLowerCase() + '_proxy', + upcase = name.toUpperCase(), + env = process.env, + keys, proxy; - var i, // The loop counter. - k, // The member key. - v, // The member value. - length, - mind = gap, - partial, - value = holder[key]; + if (name === 'http_proxy' && env.REQUEST_METHOD) { + keys = Object.keys(env).filter(function(k) { return /^http_proxy$/i.test(k) }); + if (keys.length === 1) { + if (keys[0] === name && env[upcase] === undefined) + proxy = env[name]; + } else if (keys.length > 1) { + proxy = env[name]; + } + proxy = proxy || env['CGI_' + upcase]; + } else { + proxy = env[name] || env[upcase]; + if (proxy && !env[name]) + console.warn('The environment variable ' + upcase + + ' is discouraged. Use ' + name + '.'); + } + return proxy; + } -// If the value has a toJSON method, call it to obtain a replacement value. + }), { + get: function(dispatcher, allowed, disabled, callback, context) { + var endpoint = dispatcher.endpoint; - if (value && typeof value === 'object' && - typeof value.toJSON === 'function') { - value = value.toJSON(key); - } + array.asyncEach(this._transports, function(pair, resume) { + var connType = pair[0], klass = pair[1], + connEndpoint = dispatcher.endpointFor(connType); -// If we were called with a replacer function, then call the replacer to -// obtain a replacement value. + if (array.indexOf(disabled, connType) >= 0) + return resume(); - if (typeof rep === 'function') { - value = rep.call(holder, key, value); + if (array.indexOf(allowed, connType) < 0) { + klass.isUsable(dispatcher, connEndpoint, function() {}); + return resume(); } -// What happens next depends on the value's type. + klass.isUsable(dispatcher, connEndpoint, function(isUsable) { + if (!isUsable) return resume(); + var transport = klass.hasOwnProperty('create') ? klass.create(dispatcher, connEndpoint) : new klass(dispatcher, connEndpoint); + callback.call(context, transport); + }); + }, function() { + throw new Error('Could not find a usable connection type for ' + URI.stringify(endpoint)); + }); + }, - switch (typeof value) { - case 'string': - return quote(value); + register: function(type, klass) { + this._transports.push([type, klass]); + klass.prototype.connectionType = type; + }, - case 'number': + getConnectionTypes: function() { + return array.map(this._transports, function(t) { return t[0] }); + }, -// JSON numbers must be finite. Encode non-finite numbers as null. + _transports: [] + }); - return isFinite(value) ? String(value) : 'null'; + extend(Transport.prototype, Logging); + extend(Transport.prototype, Timeouts); - case 'boolean': - case 'null': + module.exports = Transport; -// If the value is a boolean or null, convert it to a string. Note: -// typeof null does not produce 'null'. The case is included here in -// the remote chance that this gets fixed someday. - return String(value); +/***/ }, +/* 23 */ +/***/ function(module, exports) { -// If the type is 'object', we might be dealing with an object or an array or -// null. + /* WEBPACK VAR INJECTION */(function(global) {'use strict'; - case 'object': + module.exports = { + addTimeout: function(name, delay, callback, context) { + this._timeouts = this._timeouts || {}; + if (this._timeouts.hasOwnProperty(name)) return; + var self = this; + this._timeouts[name] = global.setTimeout(function() { + delete self._timeouts[name]; + callback.call(context); + }, 1000 * delay); + }, -// Due to a specification blunder in ECMAScript, typeof null is 'object', -// so watch out for that case. + removeTimeout: function(name) { + this._timeouts = this._timeouts || {}; + var timeout = this._timeouts[name]; + if (!timeout) return; + global.clearTimeout(timeout); + delete this._timeouts[name]; + }, - if (!value) { - return 'null'; - } + removeAllTimeouts: function() { + this._timeouts = this._timeouts || {}; + for (var name in this._timeouts) this.removeTimeout(name); + } + }; -// Make an array to hold the partial results of stringifying this object value. + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) - gap += indent; - partial = []; +/***/ }, +/* 24 */ +/***/ function(module, exports, __webpack_require__) { -// Is the value an array? + /* WEBPACK VAR INJECTION */(function(global) {'use strict'; - if (Object.prototype.toString.apply(value) === '[object Array]') { + var Class = __webpack_require__(7), + Promise = __webpack_require__(9), + Set = __webpack_require__(25), + URI = __webpack_require__(10), + browser = __webpack_require__(12), + copyObject = __webpack_require__(26), + extend = __webpack_require__(8), + toJSON = __webpack_require__(3), + ws = __webpack_require__(27), + Deferrable = __webpack_require__(14), + Transport = __webpack_require__(22); -// The value is an array. Stringify every element. Use null as a placeholder -// for non-JSON values. + var WebSocket = extend(Class(Transport, { + UNCONNECTED: 1, + CONNECTING: 2, + CONNECTED: 3, - length = value.length; - for (i = 0; i < length; i += 1) { - partial[i] = str(i, value) || 'null'; - } + batching: false, -// Join all of the elements together, separated with commas, and wrap them in -// brackets. + isUsable: function(callback, context) { + this.callback(function() { callback.call(context, true) }); + this.errback(function() { callback.call(context, false) }); + this.connect(); + }, - v = partial.length === 0 - ? '[]' - : gap - ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' - : '[' + partial.join(',') + ']'; - gap = mind; - return v; - } + request: function(messages) { + this._pending = this._pending || new Set(); + for (var i = 0, n = messages.length; i < n; i++) this._pending.add(messages[i]); -// If the replacer is an array, use it to select the members to be stringified. + var self = this; - if (rep && typeof rep === 'object') { - length = rep.length; - for (i = 0; i < length; i += 1) { - if (typeof rep[i] === 'string') { - k = rep[i]; - v = str(k, value); - if (v) { - partial.push(quote(k) + (gap ? ': ' : ':') + v); - } - } - } - } else { + var promise = new Promise(function(resolve, reject) { + self.callback(function(socket) { + if (!socket || socket.readyState !== 1) return; + socket.send(toJSON(messages)); + resolve(socket); + }); -// Otherwise, iterate through all of the keys in the object. + self.connect(); + }); - for (k in value) { - if (Object.prototype.hasOwnProperty.call(value, k)) { - v = str(k, value); - if (v) { - partial.push(quote(k) + (gap ? ': ' : ':') + v); - } - } - } - } + return { + abort: function() { promise.then(function(ws) { ws.close() }) } + }; + }, -// Join all of the member texts together, separated with commas, -// and wrap them in braces. + connect: function() { + if (WebSocket._unloaded) return; - v = partial.length === 0 - ? '{}' - : gap - ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' - : '{' + partial.join(',') + '}'; - gap = mind; - return v; - } - } + this._state = this._state || this.UNCONNECTED; + if (this._state !== this.UNCONNECTED) return; + this._state = this.CONNECTING; -// If the JSON object does not yet have a stringify method, give it one. + var socket = this._createSocket(); + if (!socket) return this.setDeferredStatus('failed'); - Faye.stringify = function (value, replacer, space) { + var self = this; -// The stringify method takes a value and an optional replacer, and an optional -// space parameter, and returns a JSON text. The replacer can be a function -// that can replace values, or an array of strings that will select the keys. -// A default replacer method can be provided. Use of the space parameter can -// produce text that is more easily readable. + socket.onopen = function() { + if (socket.headers) self._storeCookies(socket.headers['set-cookie']); + self._socket = socket; + self._state = self.CONNECTED; + self._everConnected = true; + self._ping(); + self.setDeferredStatus('succeeded', socket); + }; - var i; - gap = ''; - indent = ''; + var closed = false; + socket.onclose = socket.onerror = function() { + if (closed) return; + closed = true; -// If the space parameter is a number, make an indent string containing that -// many spaces. + var wasConnected = (self._state === self.CONNECTED); + socket.onopen = socket.onclose = socket.onerror = socket.onmessage = null; - if (typeof space === 'number') { - for (i = 0; i < space; i += 1) { - indent += ' '; - } + delete self._socket; + self._state = self.UNCONNECTED; + self.removeTimeout('ping'); -// If the space parameter is a string, it will be used as the indent string. + var pending = self._pending ? self._pending.toArray() : []; + delete self._pending; - } else if (typeof space === 'string') { - indent = space; + if (wasConnected || self._everConnected) { + self.setDeferredStatus('unknown'); + self._handleError(pending, wasConnected); + } else { + self.setDeferredStatus('failed'); } + }; -// If there is a replacer, it must be a function or an array. -// Otherwise, throw an error. + socket.onmessage = function(event) { + var replies; + try { replies = JSON.parse(event.data) } catch (error) {} - rep = replacer; - if (replacer && typeof replacer !== 'function' && - (typeof replacer !== 'object' || - typeof replacer.length !== 'number')) { - throw new Error('JSON.stringify'); + if (!replies) return; + + replies = [].concat(replies); + + for (var i = 0, n = replies.length; i < n; i++) { + if (replies[i].successful === undefined) continue; + self._pending.remove(replies[i]); } + self._receive(replies); + }; + }, -// Make a fake root object containing our value under the key of ''. -// Return the result of stringifying the value. + close: function() { + if (!this._socket) return; + this._socket.close(); + }, - return str('', {'': value}); - }; + _createSocket: function() { + var url = WebSocket.getSocketUrl(this.endpoint), + headers = this._dispatcher.headers, + extensions = this._dispatcher.wsExtensions, + cookie = this._getCookies(), + tls = this._dispatcher.tls, + options = {extensions: extensions, headers: headers, proxy: this._proxy, tls: tls}; - if (typeof JSON.stringify !== 'function') { - JSON.stringify = Faye.stringify; - } + if (cookie !== '') options.headers['Cookie'] = cookie; -// If the JSON object does not yet have a parse method, give it one. + return ws.create(url, [], options); + }, - if (typeof JSON.parse !== 'function') { - JSON.parse = function (text, reviver) { + _ping: function() { + if (!this._socket || this._socket.readyState !== 1) return; + this._socket.send('[]'); + this.addTimeout('ping', this._dispatcher.timeout / 2, this._ping, this); + } -// The parse method takes a text and an optional reviver function, and returns -// a JavaScript value if the text is a valid JSON text. + }), { + PROTOCOLS: { + 'http:': 'ws:', + 'https:': 'wss:' + }, - var j; + create: function(dispatcher, endpoint) { + var sockets = dispatcher.transports.websocket = dispatcher.transports.websocket || {}; + sockets[endpoint.href] = sockets[endpoint.href] || new this(dispatcher, endpoint); + return sockets[endpoint.href]; + }, - function walk(holder, key) { + getSocketUrl: function(endpoint) { + endpoint = copyObject(endpoint); + endpoint.protocol = this.PROTOCOLS[endpoint.protocol]; + return URI.stringify(endpoint); + }, -// The walk method is used to recursively walk the resulting structure so -// that modifications can be made. + isUsable: function(dispatcher, endpoint, callback, context) { + this.create(dispatcher, endpoint).isUsable(callback, context); + } + }); - var k, v, value = holder[key]; - if (value && typeof value === 'object') { - for (k in value) { - if (Object.prototype.hasOwnProperty.call(value, k)) { - v = walk(value, k); - if (v !== undefined) { - value[k] = v; - } else { - delete value[k]; - } - } - } - } - return reviver.call(holder, key, value); - } + extend(WebSocket.prototype, Deferrable); + if (browser.Event && global.onbeforeunload !== undefined) + browser.Event.on(global, 'beforeunload', function() { WebSocket._unloaded = true }); -// Parsing happens in four stages. In the first stage, we replace certain -// Unicode characters with escape sequences. JavaScript handles many characters -// incorrectly, either silently deleting them, or treating them as line endings. + module.exports = WebSocket; - text = String(text); - cx.lastIndex = 0; - if (cx.test(text)) { - text = text.replace(cx, function (a) { - return '\\u' + - ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }); - } + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) -// In the second stage, we run the text against regular expressions that look -// for non-JSON patterns. We are especially concerned with '()' and 'new' -// because they can cause invocation, and '=' because it can cause mutation. -// But just to be safe, we want to reject all unexpected forms. +/***/ }, +/* 25 */ +/***/ function(module, exports, __webpack_require__) { -// We split the second stage into 4 regexp operations in order to work around -// crippling inefficiencies in IE's and Safari's regexp engines. First we -// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we -// replace all simple value tokens with ']' characters. Third, we delete all -// open brackets that follow a colon or comma or that begin the text. Finally, -// we look to see that the remaining characters are only whitespace or ']' or -// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. + 'use strict'; - if (/^[\],:{}\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, ''))) { + var Class = __webpack_require__(7); -// In the third stage we use the eval function to compile the text into a -// JavaScript structure. The '{' operator is subject to a syntactic ambiguity -// in JavaScript: it can begin a block or an object literal. We wrap the text -// in parens to eliminate the ambiguity. + module.exports = Class({ + initialize: function() { + this._index = {}; + }, - j = eval('(' + text + ')'); + add: function(item) { + var key = (item.id !== undefined) ? item.id : item; + if (this._index.hasOwnProperty(key)) return false; + this._index[key] = item; + return true; + }, -// In the optional fourth stage, we recursively walk the new structure, passing -// each name/value pair to a reviver function for possible transformation. + forEach: function(block, context) { + for (var key in this._index) { + if (this._index.hasOwnProperty(key)) + block.call(context, this._index[key]); + } + }, - return typeof reviver === 'function' - ? walk({'': j}, '') - : j; - } + isEmpty: function() { + for (var key in this._index) { + if (this._index.hasOwnProperty(key)) return false; + } + return true; + }, -// If the text is not JSON parseable, then a SyntaxError is thrown. + member: function(item) { + for (var key in this._index) { + if (this._index[key] === item) return true; + } + return false; + }, - throw new SyntaxError('JSON.parse'); - }; + remove: function(item) { + var key = (item.id !== undefined) ? item.id : item; + var removed = this._index[key]; + delete this._index[key]; + return removed; + }, + + toArray: function() { + var array = []; + this.forEach(function(item) { array.push(item) }); + return array; } -}()); + }); -Faye.Transport.WebSocket = Faye.extend(Faye.Class(Faye.Transport, { - UNCONNECTED: 1, - CONNECTING: 2, - CONNECTED: 3, - batching: false, +/***/ }, +/* 26 */ +/***/ function(module, exports) { - isUsable: function(callback, context) { - this.callback(function() { callback.call(context, true) }); - this.errback(function() { callback.call(context, false) }); - this.connect(); - }, + 'use strict'; - request: function(messages) { - this._pending = this._pending || new Faye.Set(); - for (var i = 0, n = messages.length; i < n; i++) this._pending.add(messages[i]); + var copyObject = function(object) { + var clone, i, key; + if (object instanceof Array) { + clone = []; + i = object.length; + while (i--) clone[i] = copyObject(object[i]); + return clone; + } else if (typeof object === 'object') { + clone = (object === null) ? null : {}; + for (key in object) clone[key] = copyObject(object[key]); + return clone; + } else { + return object; + } + }; - var promise = new Faye.Promise(); + module.exports = copyObject; - this.callback(function(socket) { - if (!socket) return; - socket.send(Faye.toJSON(messages)); - Faye.Promise.fulfill(promise, socket); - }, this); - this.connect(); +/***/ }, +/* 27 */ +/***/ function(module, exports) { - return { - abort: function() { promise.then(function(ws) { ws.close() }) } - }; - }, + /* WEBPACK VAR INJECTION */(function(global) {'use strict'; - connect: function() { - if (Faye.Transport.WebSocket._unloaded) return; + var WS = global.MozWebSocket || global.WebSocket; - this._state = this._state || this.UNCONNECTED; - if (this._state !== this.UNCONNECTED) return; - this._state = this.CONNECTING; + module.exports = { + create: function(url, protocols, options) { + if (typeof WS !== 'function') return null; + return new WS(url); + } + }; - var socket = this._createSocket(); - if (!socket) return this.setDeferredStatus('failed'); + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) - var self = this; +/***/ }, +/* 28 */ +/***/ function(module, exports, __webpack_require__) { - socket.onopen = function() { - if (socket.headers) self._storeCookies(socket.headers['set-cookie']); - self._socket = socket; - self._state = self.CONNECTED; - self._everConnected = true; - self._ping(); - self.setDeferredStatus('succeeded', socket); - }; + /* WEBPACK VAR INJECTION */(function(global) {'use strict'; - var closed = false; - socket.onclose = socket.onerror = function() { - if (closed) return; - closed = true; + var Class = __webpack_require__(7), + URI = __webpack_require__(10), + copyObject = __webpack_require__(26), + extend = __webpack_require__(8), + Deferrable = __webpack_require__(14), + Transport = __webpack_require__(22), + XHR = __webpack_require__(29); - var wasConnected = (self._state === self.CONNECTED); - socket.onopen = socket.onclose = socket.onerror = socket.onmessage = null; + var EventSource = extend(Class(Transport, { + initialize: function(dispatcher, endpoint) { + Transport.prototype.initialize.call(this, dispatcher, endpoint); + if (!global.EventSource) return this.setDeferredStatus('failed'); - delete self._socket; - self._state = self.UNCONNECTED; - self.removeTimeout('ping'); - self.setDeferredStatus('unknown'); + this._xhr = new XHR(dispatcher, endpoint); - var pending = self._pending ? self._pending.toArray() : []; - delete self._pending; + endpoint = copyObject(endpoint); + endpoint.pathname += '/' + dispatcher.clientId; - if (wasConnected) { - self._handleError(pending, true); - } else if (self._everConnected) { - self._handleError(pending); - } else { - self.setDeferredStatus('failed'); - } - }; + var socket = new global.EventSource(URI.stringify(endpoint)), + self = this; - socket.onmessage = function(event) { - var replies = JSON.parse(event.data); - if (!replies) return; + socket.onopen = function() { + self._everConnected = true; + self.setDeferredStatus('succeeded'); + }; - replies = [].concat(replies); + socket.onerror = function() { + if (self._everConnected) { + self._handleError([]); + } else { + self.setDeferredStatus('failed'); + socket.close(); + } + }; - for (var i = 0, n = replies.length; i < n; i++) { - if (replies[i].successful === undefined) continue; - self._pending.remove(replies[i]); - } - self._receive(replies); - }; - }, + socket.onmessage = function(event) { + var replies; + try { replies = JSON.parse(event.data) } catch (error) {} - close: function() { - if (!this._socket) return; - this._socket.close(); - }, + if (replies) + self._receive(replies); + else + self._handleError([]); + }; - _createSocket: function() { - var url = Faye.Transport.WebSocket.getSocketUrl(this.endpoint), - headers = Faye.copyObject(this._dispatcher.headers), - options = {headers: headers, ca: this._dispatcher.ca}; + this._socket = socket; + }, - options.headers['Cookie'] = this._getCookies(); + close: function() { + if (!this._socket) return; + this._socket.onopen = this._socket.onerror = this._socket.onmessage = null; + this._socket.close(); + delete this._socket; + }, - if (Faye.WebSocket) return new Faye.WebSocket.Client(url, [], options); - if (Faye.ENV.MozWebSocket) return new MozWebSocket(url); - if (Faye.ENV.WebSocket) return new WebSocket(url); - }, + isUsable: function(callback, context) { + this.callback(function() { callback.call(context, true) }); + this.errback(function() { callback.call(context, false) }); + }, - _ping: function() { - if (!this._socket) return; - this._socket.send('[]'); - this.addTimeout('ping', this._dispatcher.timeout / 2, this._ping, this); - } + encode: function(messages) { + return this._xhr.encode(messages); + }, -}), { - PROTOCOLS: { - 'http:': 'ws:', - 'https:': 'wss:' - }, + request: function(messages) { + return this._xhr.request(messages); + } - create: function(dispatcher, endpoint) { - var sockets = dispatcher.transports.websocket = dispatcher.transports.websocket || {}; - sockets[endpoint.href] = sockets[endpoint.href] || new this(dispatcher, endpoint); - return sockets[endpoint.href]; - }, + }), { + isUsable: function(dispatcher, endpoint, callback, context) { + var id = dispatcher.clientId; + if (!id) return callback.call(context, false); - getSocketUrl: function(endpoint) { - endpoint = Faye.copyObject(endpoint); - endpoint.protocol = this.PROTOCOLS[endpoint.protocol]; - return Faye.URI.stringify(endpoint); - }, + XHR.isUsable(dispatcher, endpoint, function(usable) { + if (!usable) return callback.call(context, false); + this.create(dispatcher, endpoint).isUsable(callback, context); + }, this); + }, - isUsable: function(dispatcher, endpoint, callback, context) { - this.create(dispatcher, endpoint).isUsable(callback, context); - } -}); + create: function(dispatcher, endpoint) { + var sockets = dispatcher.transports.eventsource = dispatcher.transports.eventsource || {}, + id = dispatcher.clientId; -Faye.extend(Faye.Transport.WebSocket.prototype, Faye.Deferrable); -Faye.Transport.register('websocket', Faye.Transport.WebSocket); + var url = copyObject(endpoint); + url.pathname += '/' + (id || ''); + url = URI.stringify(url); -if (Faye.Event && Faye.ENV.onbeforeunload !== undefined) - Faye.Event.on(Faye.ENV, 'beforeunload', function() { - Faye.Transport.WebSocket._unloaded = true; + sockets[url] = sockets[url] || new this(dispatcher, endpoint); + return sockets[url]; + } }); -Faye.Transport.EventSource = Faye.extend(Faye.Class(Faye.Transport, { - initialize: function(dispatcher, endpoint) { - Faye.Transport.prototype.initialize.call(this, dispatcher, endpoint); - if (!Faye.ENV.EventSource) return this.setDeferredStatus('failed'); + extend(EventSource.prototype, Deferrable); - this._xhr = new Faye.Transport.XHR(dispatcher, endpoint); + module.exports = EventSource; - endpoint = Faye.copyObject(endpoint); - endpoint.pathname += '/' + dispatcher.clientId; + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) - var socket = new EventSource(Faye.URI.stringify(endpoint)), - self = this; +/***/ }, +/* 29 */ +/***/ function(module, exports, __webpack_require__) { - socket.onopen = function() { - self._everConnected = true; - self.setDeferredStatus('succeeded'); - }; + /* WEBPACK VAR INJECTION */(function(global) {'use strict'; - socket.onerror = function() { - if (self._everConnected) { - self._handleError([]); + var Class = __webpack_require__(7), + URI = __webpack_require__(10), + browser = __webpack_require__(12), + extend = __webpack_require__(8), + toJSON = __webpack_require__(3), + Transport = __webpack_require__(22); + + var XHR = extend(Class(Transport, { + encode: function(messages) { + return toJSON(messages); + }, + + request: function(messages) { + var href = this.endpoint.href, + self = this, + xhr; + + // Prefer XMLHttpRequest over ActiveXObject if they both exist + if (global.XMLHttpRequest) { + xhr = new XMLHttpRequest(); + } else if (global.ActiveXObject) { + xhr = new ActiveXObject('Microsoft.XMLHTTP'); } else { - self.setDeferredStatus('failed'); - socket.close(); + return this._handleError(messages); } - }; - socket.onmessage = function(event) { - self._receive(JSON.parse(event.data)); - }; + xhr.open('POST', href, true); + xhr.setRequestHeader('Content-Type', 'application/json'); + xhr.setRequestHeader('Pragma', 'no-cache'); + xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); - this._socket = socket; - }, + var headers = this._dispatcher.headers; + for (var key in headers) { + if (!headers.hasOwnProperty(key)) continue; + xhr.setRequestHeader(key, headers[key]); + } - close: function() { - if (!this._socket) return; - this._socket.onopen = this._socket.onerror = this._socket.onmessage = null; - this._socket.close(); - delete this._socket; - }, + var abort = function() { xhr.abort() }; + if (global.onbeforeunload !== undefined) + browser.Event.on(global, 'beforeunload', abort); - isUsable: function(callback, context) { - this.callback(function() { callback.call(context, true) }); - this.errback(function() { callback.call(context, false) }); - }, + xhr.onreadystatechange = function() { + if (!xhr || xhr.readyState !== 4) return; - encode: function(messages) { - return this._xhr.encode(messages); - }, + var replies = null, + status = xhr.status, + text = xhr.responseText, + successful = (status >= 200 && status < 300) || status === 304 || status === 1223; - request: function(messages) { - return this._xhr.request(messages); - } + if (global.onbeforeunload !== undefined) + browser.Event.detach(global, 'beforeunload', abort); -}), { - isUsable: function(dispatcher, endpoint, callback, context) { - var id = dispatcher.clientId; - if (!id) return callback.call(context, false); + xhr.onreadystatechange = function() {}; + xhr = null; - Faye.Transport.XHR.isUsable(dispatcher, endpoint, function(usable) { - if (!usable) return callback.call(context, false); - this.create(dispatcher, endpoint).isUsable(callback, context); - }, this); - }, + if (!successful) return self._handleError(messages); - create: function(dispatcher, endpoint) { - var sockets = dispatcher.transports.eventsource = dispatcher.transports.eventsource || {}, - id = dispatcher.clientId; + try { + replies = JSON.parse(text); + } catch (error) {} - endpoint = Faye.copyObject(endpoint); - endpoint.pathname += '/' + (id || ''); - var url = Faye.URI.stringify(endpoint); + if (replies) + self._receive(replies); + else + self._handleError(messages); + }; - sockets[url] = sockets[url] || new this(dispatcher, endpoint); - return sockets[url]; - } -}); + xhr.send(this.encode(messages)); + return xhr; + } + }), { + isUsable: function(dispatcher, endpoint, callback, context) { + var usable = (navigator.product === 'ReactNative') + || URI.isSameOrigin(endpoint); -Faye.extend(Faye.Transport.EventSource.prototype, Faye.Deferrable); -Faye.Transport.register('eventsource', Faye.Transport.EventSource); + callback.call(context, usable); + } + }); -Faye.Transport.XHR = Faye.extend(Faye.Class(Faye.Transport, { - encode: function(messages) { - return Faye.toJSON(messages); - }, + module.exports = XHR; - request: function(messages) { - var href = this.endpoint.href, - xhr = Faye.ENV.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest(), - self = this; + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) - xhr.open('POST', href, true); - xhr.setRequestHeader('Content-Type', 'application/json'); - xhr.setRequestHeader('Pragma', 'no-cache'); - xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); +/***/ }, +/* 30 */ +/***/ function(module, exports, __webpack_require__) { - var headers = this._dispatcher.headers; - for (var key in headers) { - if (!headers.hasOwnProperty(key)) continue; - xhr.setRequestHeader(key, headers[key]); - } + /* WEBPACK VAR INJECTION */(function(global) {'use strict'; - var abort = function() { xhr.abort() }; - if (Faye.ENV.onbeforeunload !== undefined) Faye.Event.on(Faye.ENV, 'beforeunload', abort); + var Class = __webpack_require__(7), + Set = __webpack_require__(25), + URI = __webpack_require__(10), + extend = __webpack_require__(8), + toJSON = __webpack_require__(3), + Transport = __webpack_require__(22); - xhr.onreadystatechange = function() { - if (!xhr || xhr.readyState !== 4) return; + var CORS = extend(Class(Transport, { + encode: function(messages) { + return 'message=' + encodeURIComponent(toJSON(messages)); + }, - var replies = null, - status = xhr.status, - text = xhr.responseText, - successful = (status >= 200 && status < 300) || status === 304 || status === 1223; + request: function(messages) { + var xhrClass = global.XDomainRequest ? XDomainRequest : XMLHttpRequest, + xhr = new xhrClass(), + id = ++CORS._id, + headers = this._dispatcher.headers, + self = this, + key; - if (Faye.ENV.onbeforeunload !== undefined) Faye.Event.detach(Faye.ENV, 'beforeunload', abort); - xhr.onreadystatechange = function() {}; - xhr = null; + xhr.open('POST', URI.stringify(this.endpoint), true); - if (!successful) return self._handleError(messages); + if (xhr.setRequestHeader) { + xhr.setRequestHeader('Pragma', 'no-cache'); + for (key in headers) { + if (!headers.hasOwnProperty(key)) continue; + xhr.setRequestHeader(key, headers[key]); + } + } - try { - replies = JSON.parse(text); - } catch (e) {} + var cleanUp = function() { + if (!xhr) return false; + CORS._pending.remove(id); + xhr.onload = xhr.onerror = xhr.ontimeout = xhr.onprogress = null; + xhr = null; + }; - if (replies) - self._receive(replies); - else + xhr.onload = function() { + var replies; + try { replies = JSON.parse(xhr.responseText) } catch (error) {} + + cleanUp(); + + if (replies) + self._receive(replies); + else + self._handleError(messages); + }; + + xhr.onerror = xhr.ontimeout = function() { + cleanUp(); self._handleError(messages); - }; + }; - xhr.send(this.encode(messages)); - return xhr; - } -}), { - isUsable: function(dispatcher, endpoint, callback, context) { - callback.call(context, Faye.URI.isSameOrigin(endpoint)); - } -}); + xhr.onprogress = function() {}; -Faye.Transport.register('long-polling', Faye.Transport.XHR); + if (xhrClass === global.XDomainRequest) + CORS._pending.add({id: id, xhr: xhr}); -Faye.Transport.CORS = Faye.extend(Faye.Class(Faye.Transport, { - encode: function(messages) { - return 'message=' + encodeURIComponent(Faye.toJSON(messages)); - }, + xhr.send(this.encode(messages)); + return xhr; + } + }), { + _id: 0, + _pending: new Set(), - request: function(messages) { - var xhrClass = Faye.ENV.XDomainRequest ? XDomainRequest : XMLHttpRequest, - xhr = new xhrClass(), - headers = this._dispatcher.headers, - self = this, - key; + isUsable: function(dispatcher, endpoint, callback, context) { + if (URI.isSameOrigin(endpoint)) + return callback.call(context, false); - xhr.open('POST', Faye.URI.stringify(this.endpoint), true); + if (global.XDomainRequest) + return callback.call(context, endpoint.protocol === location.protocol); - if (xhr.setRequestHeader) { - xhr.setRequestHeader('Pragma', 'no-cache'); - for (key in headers) { - if (!headers.hasOwnProperty(key)) continue; - xhr.setRequestHeader(key, headers[key]); + if (global.XMLHttpRequest) { + var xhr = new XMLHttpRequest(); + return callback.call(context, xhr.withCredentials !== undefined); } + return callback.call(context, false); } + }); - var cleanUp = function() { - if (!xhr) return false; - xhr.onload = xhr.onerror = xhr.ontimeout = xhr.onprogress = null; - xhr = null; - }; + module.exports = CORS; - xhr.onload = function() { - var replies = null; - try { - replies = JSON.parse(xhr.responseText); - } catch (e) {} + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) - cleanUp(); +/***/ }, +/* 31 */ +/***/ function(module, exports, __webpack_require__) { - if (replies) + /* WEBPACK VAR INJECTION */(function(global) {'use strict'; + + var Class = __webpack_require__(7), + URI = __webpack_require__(10), + copyObject = __webpack_require__(26), + extend = __webpack_require__(8), + toJSON = __webpack_require__(3), + Transport = __webpack_require__(22); + + var JSONP = extend(Class(Transport, { + encode: function(messages) { + var url = copyObject(this.endpoint); + url.query.message = toJSON(messages); + url.query.jsonp = '__jsonp' + JSONP._cbCount + '__'; + return URI.stringify(url); + }, + + request: function(messages) { + var head = document.getElementsByTagName('head')[0], + script = document.createElement('script'), + callbackName = JSONP.getCallbackName(), + endpoint = copyObject(this.endpoint), + self = this; + + endpoint.query.message = toJSON(messages); + endpoint.query.jsonp = callbackName; + + var cleanup = function() { + if (!global[callbackName]) return false; + global[callbackName] = undefined; + try { delete global[callbackName] } catch (error) {} + script.parentNode.removeChild(script); + }; + + global[callbackName] = function(replies) { + cleanup(); self._receive(replies); - else + }; + + script.type = 'text/javascript'; + script.src = URI.stringify(endpoint); + head.appendChild(script); + + script.onerror = function() { + cleanup(); self._handleError(messages); - }; + }; - xhr.onerror = xhr.ontimeout = function() { - cleanUp(); - self._handleError(messages); - }; + return {abort: cleanup}; + } + }), { + _cbCount: 0, - xhr.onprogress = function() {}; - xhr.send(this.encode(messages)); - return xhr; - } -}), { - isUsable: function(dispatcher, endpoint, callback, context) { - if (Faye.URI.isSameOrigin(endpoint)) - return callback.call(context, false); + getCallbackName: function() { + this._cbCount += 1; + return '__jsonp' + this._cbCount + '__'; + }, - if (Faye.ENV.XDomainRequest) - return callback.call(context, endpoint.protocol === Faye.ENV.location.protocol); + isUsable: function(dispatcher, endpoint, callback, context) { + callback.call(context, true); + } + }); - if (Faye.ENV.XMLHttpRequest) { - var xhr = new Faye.ENV.XMLHttpRequest(); - return callback.call(context, xhr.withCredentials !== undefined); + module.exports = JSONP; + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }, +/* 32 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var extend = __webpack_require__(8); + + var Scheduler = function(message, options) { + this.message = message; + this.options = options; + this.attempts = 0; + }; + + extend(Scheduler.prototype, { + getTimeout: function() { + return this.options.timeout; + }, + + getInterval: function() { + return this.options.interval; + }, + + isDeliverable: function() { + var attempts = this.options.attempts, + made = this.attempts, + deadline = this.options.deadline, + now = new Date().getTime(); + + if (attempts !== undefined && made >= attempts) + return false; + + if (deadline !== undefined && now > deadline) + return false; + + return true; + }, + + send: function() { + this.attempts += 1; + }, + + succeed: function() {}, + + fail: function() {}, + + abort: function() {} + }); + + module.exports = Scheduler; + + +/***/ }, +/* 33 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var Class = __webpack_require__(7), + Grammar = __webpack_require__(18); + + var Error = Class({ + initialize: function(code, params, message) { + this.code = code; + this.params = Array.prototype.slice.call(params); + this.message = message; + }, + + toString: function() { + return this.code + ':' + + this.params.join(',') + ':' + + this.message; } - return callback.call(context, false); - } -}); + }); -Faye.Transport.register('cross-origin-long-polling', Faye.Transport.CORS); + Error.parse = function(message) { + message = message || ''; + if (!Grammar.ERROR.test(message)) return new Error(null, [], message); -Faye.Transport.JSONP = Faye.extend(Faye.Class(Faye.Transport, { - encode: function(messages) { - var url = Faye.copyObject(this.endpoint); - url.query.message = Faye.toJSON(messages); - url.query.jsonp = '__jsonp' + Faye.Transport.JSONP._cbCount + '__'; - return Faye.URI.stringify(url); - }, + var parts = message.split(':'), + code = parseInt(parts[0]), + params = parts[1].split(','), + message = parts[2]; - request: function(messages) { - var head = document.getElementsByTagName('head')[0], - script = document.createElement('script'), - callbackName = Faye.Transport.JSONP.getCallbackName(), - endpoint = Faye.copyObject(this.endpoint), - self = this; + return new Error(code, params, message); + }; - endpoint.query.message = Faye.toJSON(messages); - endpoint.query.jsonp = callbackName; + // http://code.google.com/p/cometd/wiki/BayeuxCodes + var errors = { + versionMismatch: [300, 'Version mismatch'], + conntypeMismatch: [301, 'Connection types not supported'], + extMismatch: [302, 'Extension mismatch'], + badRequest: [400, 'Bad request'], + clientUnknown: [401, 'Unknown client'], + parameterMissing: [402, 'Missing required parameter'], + channelForbidden: [403, 'Forbidden channel'], + channelUnknown: [404, 'Unknown channel'], + channelInvalid: [405, 'Invalid channel'], + extUnknown: [406, 'Unknown extension'], + publishFailed: [407, 'Failed to publish'], + serverError: [500, 'Internal server error'] + }; - var cleanup = function() { - if (!Faye.ENV[callbackName]) return false; - Faye.ENV[callbackName] = undefined; - try { delete Faye.ENV[callbackName] } catch (e) {} - script.parentNode.removeChild(script); - }; + for (var name in errors) + (function(name) { + Error[name] = function() { + return new Error(errors[name][0], arguments, errors[name][1]).toString(); + }; + })(name); - Faye.ENV[callbackName] = function(replies) { - cleanup(); - self._receive(replies); - }; + module.exports = Error; - script.type = 'text/javascript'; - script.src = Faye.URI.stringify(endpoint); - head.appendChild(script); - script.onerror = function() { - cleanup(); - self._handleError(messages); - }; +/***/ }, +/* 34 */ +/***/ function(module, exports, __webpack_require__) { - return {abort: cleanup}; - } -}), { - _cbCount: 0, + 'use strict'; - getCallbackName: function() { - this._cbCount += 1; - return '__jsonp' + this._cbCount + '__'; - }, + var extend = __webpack_require__(8), + Logging = __webpack_require__(2); - isUsable: function(dispatcher, endpoint, callback, context) { - callback.call(context, true); - } -}); + var Extensible = { + addExtension: function(extension) { + this._extensions = this._extensions || []; + this._extensions.push(extension); + if (extension.added) extension.added(this); + }, -Faye.Transport.register('callback-polling', Faye.Transport.JSONP); + removeExtension: function(extension) { + if (!this._extensions) return; + var i = this._extensions.length; + while (i--) { + if (this._extensions[i] !== extension) continue; + this._extensions.splice(i,1); + if (extension.removed) extension.removed(this); + } + }, -})(); \ No newline at end of file + pipeThroughExtensions: function(stage, message, request, callback, context) { + this.debug('Passing through ? extensions: ?', stage, message); + + if (!this._extensions) return callback.call(context, message); + var extensions = this._extensions.slice(); + + var pipe = function(message) { + if (!message) return callback.call(context, message); + + var extension = extensions.shift(); + if (!extension) return callback.call(context, message); + + var fn = extension[stage]; + if (!fn) return pipe(message); + + if (fn.length >= 3) extension[stage](message, request, pipe); + else extension[stage](message, pipe); + }; + pipe(message); + } + }; + + extend(Extensible, Logging); + + module.exports = Extensible; + + +/***/ }, +/* 35 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var Class = __webpack_require__(7), + Deferrable = __webpack_require__(14); + + module.exports = Class(Deferrable); + + +/***/ }, +/* 36 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var Class = __webpack_require__(7), + extend = __webpack_require__(8), + Deferrable = __webpack_require__(14); + + var Subscription = Class({ + initialize: function(client, channels, callback, context) { + this._client = client; + this._channels = channels; + this._callback = callback; + this._context = context; + this._cancelled = false; + }, + + withChannel: function(callback, context) { + this._withChannel = [callback, context]; + return this; + }, + + apply: function(context, args) { + var message = args[0]; + + if (this._callback) + this._callback.call(this._context, message.data); + + if (this._withChannel) + this._withChannel[0].call(this._withChannel[1], message.channel, message.data); + }, + + cancel: function() { + if (this._cancelled) return; + this._client.unsubscribe(this._channels, this); + this._cancelled = true; + }, + + unsubscribe: function() { + this.cancel(); + } + }); + + extend(Subscription.prototype, Deferrable); + + module.exports = Subscription; + + +/***/ } +/******/ ]); +//# sourceMappingURL=faye-browser.js.map