Preliminary commit for browserify compatibility

This is the first stage of my commits for issue #609 that will make the
npm module browserify friendly and browser friendly.

The grunt-browserify module has been introduced to replace
grunt-contrib-concat. Browserify automatically concatenates files and so
there is no need for a concat step.

The faye-websocket module was problematic so I moved the require out to
a separate module within the lib directory. The websocket module is a
folder containing a package.json, directing library consumers to the
entry point that is appropriate for their environment. Browserify picks
browser.js (which simply returns an object holding window.WebSocket)
while everyone else gets the faye-websocket module.

In addition, as browserify handles all the requires, there's no need to
detect the environment or include any pre-built modules. I've removed
the pre-built when and faye-websocket files in favour of letting
browserify use the modules within node_modules. This should make it
easier to maintain dependencies in future versions of this library.

One side effect of this browserify compatibility is that, in order to
allow the library to be globally available in the browser as `Mopidy`,
I've had to set Mopidy as the exported object instead of as a key of the
exported object. To elaborate further, the current API would be like the
following:

    var Mopidy = require('mopidy').Mopidy;

However, with this change, the API would be like this:

    var Mopidy = require('mopidy');

I'm not sure whether this would be an issue and so I think it's worth
discussing further. It's possible that node developers won't have a
problem but, if they did, a potential workaround within the mopidy.js
file would be:

   Mopidy.Mopidy = Mopidy;

This would allow developers to choose either of the following:

    var Mopidy = require('mopidy');
    var Mopidy = require('mopidy').Mopidy;

Could be a little odd to do this though

When testing the browserify build, I noticed a strange error thrown when
making the initial websocket connection. I managed to track it down to
an IE 'feature' that crops up when you alias in-built functions. In
particular, the when module was aliasing setImmediate to an internal
function (nextTick.) In a newer version of when, the function is
instead aliased to the browserify process.nextTick. This works well
because substack already had that covered.

With when@2.7.0, IE11 appears to be working well. IE10 is still pending
a test.
This commit is contained in:
Paul Connolley 2013-12-15 01:52:24 +00:00
parent 54caa95fb4
commit 418e5689dc
10 changed files with 294 additions and 1311 deletions

View File

@ -11,6 +11,7 @@ module.exports = function (grunt) {
" * Licensed under the Apache License, Version 2.0 */\n",
files: {
own: ["Gruntfile.js", "src/**/*.js", "test/**/*-test.js"],
main: "src/mopidy.js",
concat: "../mopidy/frontends/http/data/mopidy.js",
minified: "../mopidy/frontends/http/data/mopidy.min.js"
}
@ -18,19 +19,16 @@ module.exports = function (grunt) {
buster: {
all: {}
},
concat: {
options: {
banner: "<%= meta.banner %>",
stripBanners: true
},
all: {
browserify: {
dist: {
files: {
"<%= meta.files.concat %>": [
"lib/bane-*.js",
"lib/when-define-shim.js",
"lib/when-*.js",
"src/mopidy.js"
]
"<%= meta.files.concat %>": "<%= meta.files.main %>"
},
options: {
postBundleCB: function (err, src, next) {
next(null, grunt.template.process("<%= meta.banner %>") + src);
},
standalone: "Mopidy"
}
}
},
@ -71,11 +69,11 @@ module.exports = function (grunt) {
});
grunt.registerTask("test", ["jshint", "buster"]);
grunt.registerTask("build", ["test", "concat", "uglify"]);
grunt.registerTask("build", ["test", "browserify", "uglify"]);
grunt.registerTask("default", ["build"]);
grunt.loadNpmTasks("grunt-buster");
grunt.loadNpmTasks("grunt-contrib-concat");
grunt.loadNpmTasks("grunt-browserify");
grunt.loadNpmTasks("grunt-contrib-jshint");
grunt.loadNpmTasks("grunt-contrib-uglify");
grunt.loadNpmTasks("grunt-contrib-watch");

View File

@ -1,171 +0,0 @@
/**
* BANE - Browser globals, AMD and Node Events
*
* https://github.com/busterjs/bane
*
* @version 1.0.0
*/
((typeof define === "function" && define.amd && function (m) { define("bane", m); }) ||
(typeof module === "object" && function (m) { module.exports = m(); }) ||
function (m) { this.bane = m(); }
)(function () {
"use strict";
var slice = Array.prototype.slice;
function handleError(event, error, errbacks) {
var i, l = errbacks.length;
if (l > 0) {
for (i = 0; i < l; ++i) { errbacks[i](event, error); }
return;
}
setTimeout(function () {
error.message = event + " listener threw error: " + error.message;
throw error;
}, 0);
}
function assertFunction(fn) {
if (typeof fn !== "function") {
throw new TypeError("Listener is not function");
}
return fn;
}
function supervisors(object) {
if (!object.supervisors) { object.supervisors = []; }
return object.supervisors;
}
function listeners(object, event) {
if (!object.listeners) { object.listeners = {}; }
if (event && !object.listeners[event]) { object.listeners[event] = []; }
return event ? object.listeners[event] : object.listeners;
}
function errbacks(object) {
if (!object.errbacks) { object.errbacks = []; }
return object.errbacks;
}
/**
* @signature var emitter = bane.createEmitter([object]);
*
* Create a new event emitter. If an object is passed, it will be modified
* by adding the event emitter methods (see below).
*/
function createEventEmitter(object) {
object = object || {};
function notifyListener(event, listener, args) {
try {
listener.listener.apply(listener.thisp || object, args);
} catch (e) {
handleError(event, e, errbacks(object));
}
}
object.on = function (event, listener, thisp) {
if (typeof event === "function") {
return supervisors(this).push({
listener: event,
thisp: listener
});
}
listeners(this, event).push({
listener: assertFunction(listener),
thisp: thisp
});
};
object.off = function (event, listener) {
var fns, events, i, l;
if (!event) {
fns = supervisors(this);
fns.splice(0, fns.length);
events = listeners(this);
for (i in events) {
if (events.hasOwnProperty(i)) {
fns = listeners(this, i);
fns.splice(0, fns.length);
}
}
fns = errbacks(this);
fns.splice(0, fns.length);
return;
}
if (typeof event === "function") {
fns = supervisors(this);
listener = event;
} else {
fns = listeners(this, event);
}
if (!listener) {
fns.splice(0, fns.length);
return;
}
for (i = 0, l = fns.length; i < l; ++i) {
if (fns[i].listener === listener) {
fns.splice(i, 1);
return;
}
}
};
object.once = function (event, listener, thisp) {
var wrapper = function () {
object.off(event, wrapper);
listener.apply(this, arguments);
};
object.on(event, wrapper, thisp);
};
object.bind = function (object, events) {
var prop, i, l;
if (!events) {
for (prop in object) {
if (typeof object[prop] === "function") {
this.on(prop, object[prop], object);
}
}
} else {
for (i = 0, l = events.length; i < l; ++i) {
if (typeof object[events[i]] === "function") {
this.on(events[i], object[events[i]], object);
} else {
throw new Error("No such method " + events[i]);
}
}
}
return object;
};
object.emit = function (event) {
var toNotify = supervisors(this);
var args = slice.call(arguments), i, l;
for (i = 0, l = toNotify.length; i < l; ++i) {
notifyListener(event, toNotify[i], args);
}
toNotify = listeners(this, event).slice();
args = slice.call(arguments, 1);
for (i = 0, l = toNotify.length; i < l; ++i) {
notifyListener(event, toNotify[i], args);
}
};
object.errback = function (listener) {
if (!this.errbacks) { this.errbacks = []; }
this.errbacks.push(assertFunction(listener));
};
return object;
}
return { createEventEmitter: createEventEmitter };
});

View File

@ -0,0 +1 @@
module.exports = { Client: window.WebSocket };

View File

@ -0,0 +1,4 @@
{
"browser": "browser.js",
"main": "server.js"
}

View File

@ -0,0 +1 @@
module.exports = require('faye-websocket');

View File

@ -1,922 +0,0 @@
/** @license MIT License (c) copyright 2011-2013 original author or authors */
/**
* A lightweight CommonJS Promises/A and when() implementation
* when is part of the cujo.js family of libraries (http://cujojs.com/)
*
* Licensed under the MIT License at:
* http://www.opensource.org/licenses/mit-license.php
*
* @author Brian Cavalier
* @author John Hann
* @version 2.4.0
*/
(function(define, global) { 'use strict';
define(function (require) {
// Public API
when.promise = promise; // Create a pending promise
when.resolve = resolve; // Create a resolved promise
when.reject = reject; // Create a rejected promise
when.defer = defer; // Create a {promise, resolver} pair
when.join = join; // Join 2 or more promises
when.all = all; // Resolve a list of promises
when.map = map; // Array.map() for promises
when.reduce = reduce; // Array.reduce() for promises
when.settle = settle; // Settle a list of promises
when.any = any; // One-winner race
when.some = some; // Multi-winner race
when.isPromise = isPromiseLike; // DEPRECATED: use isPromiseLike
when.isPromiseLike = isPromiseLike; // Is something promise-like, aka thenable
/**
* Register an observer for a promise or immediate value.
*
* @param {*} promiseOrValue
* @param {function?} [onFulfilled] callback to be called when promiseOrValue is
* successfully fulfilled. If promiseOrValue is an immediate value, callback
* will be invoked immediately.
* @param {function?} [onRejected] callback to be called when promiseOrValue is
* rejected.
* @param {function?} [onProgress] callback to be called when progress updates
* are issued for promiseOrValue.
* @returns {Promise} a new {@link Promise} that will complete with the return
* value of callback or errback or the completion value of promiseOrValue if
* callback and/or errback is not supplied.
*/
function when(promiseOrValue, onFulfilled, onRejected, onProgress) {
// Get a trusted promise for the input promiseOrValue, and then
// register promise handlers
return resolve(promiseOrValue).then(onFulfilled, onRejected, onProgress);
}
/**
* Trusted Promise constructor. A Promise created from this constructor is
* a trusted when.js promise. Any other duck-typed promise is considered
* untrusted.
* @constructor
* @param {function} sendMessage function to deliver messages to the promise's handler
* @param {function?} inspect function that reports the promise's state
* @name Promise
*/
function Promise(sendMessage, inspect) {
this._message = sendMessage;
this.inspect = inspect;
}
Promise.prototype = {
/**
* Register handlers for this promise.
* @param [onFulfilled] {Function} fulfillment handler
* @param [onRejected] {Function} rejection handler
* @param [onProgress] {Function} progress handler
* @return {Promise} new Promise
*/
then: function(onFulfilled, onRejected, onProgress) {
/*jshint unused:false*/
var args, sendMessage;
args = arguments;
sendMessage = this._message;
return _promise(function(resolve, reject, notify) {
sendMessage('when', args, resolve, notify);
}, this._status && this._status.observed());
},
/**
* Register a rejection handler. Shortcut for .then(undefined, onRejected)
* @param {function?} onRejected
* @return {Promise}
*/
otherwise: function(onRejected) {
return this.then(undef, onRejected);
},
/**
* Ensures that onFulfilledOrRejected will be called regardless of whether
* this promise is fulfilled or rejected. onFulfilledOrRejected WILL NOT
* receive the promises' value or reason. Any returned value will be disregarded.
* onFulfilledOrRejected may throw or return a rejected promise to signal
* an additional error.
* @param {function} onFulfilledOrRejected handler to be called regardless of
* fulfillment or rejection
* @returns {Promise}
*/
ensure: function(onFulfilledOrRejected) {
return this.then(injectHandler, injectHandler)['yield'](this);
function injectHandler() {
return resolve(onFulfilledOrRejected());
}
},
/**
* Shortcut for .then(function() { return value; })
* @param {*} value
* @return {Promise} a promise that:
* - is fulfilled if value is not a promise, or
* - if value is a promise, will fulfill with its value, or reject
* with its reason.
*/
'yield': function(value) {
return this.then(function() {
return value;
});
},
/**
* Runs a side effect when this promise fulfills, without changing the
* fulfillment value.
* @param {function} onFulfilledSideEffect
* @returns {Promise}
*/
tap: function(onFulfilledSideEffect) {
return this.then(onFulfilledSideEffect)['yield'](this);
},
/**
* Assumes that this promise will fulfill with an array, and arranges
* for the onFulfilled to be called with the array as its argument list
* i.e. onFulfilled.apply(undefined, array).
* @param {function} onFulfilled function to receive spread arguments
* @return {Promise}
*/
spread: function(onFulfilled) {
return this.then(function(array) {
// array may contain promises, so resolve its contents.
return all(array, function(array) {
return onFulfilled.apply(undef, array);
});
});
},
/**
* Shortcut for .then(onFulfilledOrRejected, onFulfilledOrRejected)
* @deprecated
*/
always: function(onFulfilledOrRejected, onProgress) {
return this.then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress);
}
};
/**
* Returns a resolved promise. The returned promise will be
* - fulfilled with promiseOrValue if it is a value, or
* - if promiseOrValue is a promise
* - fulfilled with promiseOrValue's value after it is fulfilled
* - rejected with promiseOrValue's reason after it is rejected
* @param {*} value
* @return {Promise}
*/
function resolve(value) {
return promise(function(resolve) {
resolve(value);
});
}
/**
* Returns a rejected promise for the supplied promiseOrValue. The returned
* promise will be rejected with:
* - promiseOrValue, if it is a value, or
* - if promiseOrValue is a promise
* - promiseOrValue's value after it is fulfilled
* - promiseOrValue's reason after it is rejected
* @param {*} promiseOrValue the rejected value of the returned {@link Promise}
* @return {Promise} rejected {@link Promise}
*/
function reject(promiseOrValue) {
return when(promiseOrValue, rejected);
}
/**
* Creates a {promise, resolver} pair, either or both of which
* may be given out safely to consumers.
* The resolver has resolve, reject, and progress. The promise
* has then plus extended promise API.
*
* @return {{
* promise: Promise,
* resolve: function:Promise,
* reject: function:Promise,
* notify: function:Promise
* resolver: {
* resolve: function:Promise,
* reject: function:Promise,
* notify: function:Promise
* }}}
*/
function defer() {
var deferred, pending, resolved;
// Optimize object shape
deferred = {
promise: undef, resolve: undef, reject: undef, notify: undef,
resolver: { resolve: undef, reject: undef, notify: undef }
};
deferred.promise = pending = promise(makeDeferred);
return deferred;
function makeDeferred(resolvePending, rejectPending, notifyPending) {
deferred.resolve = deferred.resolver.resolve = function(value) {
if(resolved) {
return resolve(value);
}
resolved = true;
resolvePending(value);
return pending;
};
deferred.reject = deferred.resolver.reject = function(reason) {
if(resolved) {
return resolve(rejected(reason));
}
resolved = true;
rejectPending(reason);
return pending;
};
deferred.notify = deferred.resolver.notify = function(update) {
notifyPending(update);
return update;
};
}
}
/**
* Creates a new promise whose fate is determined by resolver.
* @param {function} resolver function(resolve, reject, notify)
* @returns {Promise} promise whose fate is determine by resolver
*/
function promise(resolver) {
return _promise(resolver, monitorApi.PromiseStatus && monitorApi.PromiseStatus());
}
/**
* Creates a new promise, linked to parent, whose fate is determined
* by resolver.
* @param {function} resolver function(resolve, reject, notify)
* @param {Promise?} status promise from which the new promise is begotten
* @returns {Promise} promise whose fate is determine by resolver
* @private
*/
function _promise(resolver, status) {
var self, value, consumers = [];
self = new Promise(_message, inspect);
self._status = status;
// Call the provider resolver to seal the promise's fate
try {
resolver(promiseResolve, promiseReject, promiseNotify);
} catch(e) {
promiseReject(e);
}
// Return the promise
return self;
/**
* Private message delivery. Queues and delivers messages to
* the promise's ultimate fulfillment value or rejection reason.
* @private
* @param {String} type
* @param {Array} args
* @param {Function} resolve
* @param {Function} notify
*/
function _message(type, args, resolve, notify) {
consumers ? consumers.push(deliver) : enqueue(function() { deliver(value); });
function deliver(p) {
p._message(type, args, resolve, notify);
}
}
/**
* Returns a snapshot of the promise's state at the instant inspect()
* is called. The returned object is not live and will not update as
* the promise's state changes.
* @returns {{ state:String, value?:*, reason?:* }} status snapshot
* of the promise.
*/
function inspect() {
return value ? value.inspect() : toPendingState();
}
/**
* Transition from pre-resolution state to post-resolution state, notifying
* all listeners of the ultimate fulfillment or rejection
* @param {*|Promise} val resolution value
*/
function promiseResolve(val) {
if(!consumers) {
return;
}
value = coerce(val);
scheduleConsumers(consumers, value);
consumers = undef;
if(status) {
updateStatus(value, status);
}
}
/**
* Reject this promise with the supplied reason, which will be used verbatim.
* @param {*} reason reason for the rejection
*/
function promiseReject(reason) {
promiseResolve(rejected(reason));
}
/**
* Issue a progress event, notifying all progress listeners
* @param {*} update progress event payload to pass to all listeners
*/
function promiseNotify(update) {
if(consumers) {
scheduleConsumers(consumers, progressed(update));
}
}
}
/**
* Creates a fulfilled, local promise as a proxy for a value
* NOTE: must never be exposed
* @param {*} value fulfillment value
* @returns {Promise}
*/
function fulfilled(value) {
return near(
new NearFulfilledProxy(value),
function() { return toFulfilledState(value); }
);
}
/**
* Creates a rejected, local promise with the supplied reason
* NOTE: must never be exposed
* @param {*} reason rejection reason
* @returns {Promise}
*/
function rejected(reason) {
return near(
new NearRejectedProxy(reason),
function() { return toRejectedState(reason); }
);
}
/**
* Creates a near promise using the provided proxy
* NOTE: must never be exposed
* @param {object} proxy proxy for the promise's ultimate value or reason
* @param {function} inspect function that returns a snapshot of the
* returned near promise's state
* @returns {Promise}
*/
function near(proxy, inspect) {
return new Promise(function (type, args, resolve) {
try {
resolve(proxy[type].apply(proxy, args));
} catch(e) {
resolve(rejected(e));
}
}, inspect);
}
/**
* Create a progress promise with the supplied update.
* @private
* @param {*} update
* @return {Promise} progress promise
*/
function progressed(update) {
return new Promise(function (type, args, _, notify) {
var onProgress = args[2];
try {
notify(typeof onProgress === 'function' ? onProgress(update) : update);
} catch(e) {
notify(e);
}
});
}
/**
* Coerces x to a trusted Promise
*
* @private
* @param {*} x thing to coerce
* @returns {*} Guaranteed to return a trusted Promise. If x
* is trusted, returns x, otherwise, returns a new, trusted, already-resolved
* Promise whose resolution value is:
* * the resolution value of x if it's a foreign promise, or
* * x if it's a value
*/
function coerce(x) {
if (x instanceof Promise) {
return x;
}
if (!(x === Object(x) && 'then' in x)) {
return fulfilled(x);
}
return promise(function(resolve, reject, notify) {
enqueue(function() {
try {
// We must check and assimilate in the same tick, but not the
// current tick, careful only to access promiseOrValue.then once.
var untrustedThen = x.then;
if(typeof untrustedThen === 'function') {
fcall(untrustedThen, x, resolve, reject, notify);
} else {
// It's a value, create a fulfilled wrapper
resolve(fulfilled(x));
}
} catch(e) {
// Something went wrong, reject
reject(e);
}
});
});
}
/**
* Proxy for a near, fulfilled value
* @param {*} value
* @constructor
*/
function NearFulfilledProxy(value) {
this.value = value;
}
NearFulfilledProxy.prototype.when = function(onResult) {
return typeof onResult === 'function' ? onResult(this.value) : this.value;
};
/**
* Proxy for a near rejection
* @param {*} reason
* @constructor
*/
function NearRejectedProxy(reason) {
this.reason = reason;
}
NearRejectedProxy.prototype.when = function(_, onError) {
if(typeof onError === 'function') {
return onError(this.reason);
} else {
throw this.reason;
}
};
/**
* Schedule a task that will process a list of handlers
* in the next queue drain run.
* @private
* @param {Array} handlers queue of handlers to execute
* @param {*} value passed as the only arg to each handler
*/
function scheduleConsumers(handlers, value) {
enqueue(function() {
var handler, i = 0;
while (handler = handlers[i++]) {
handler(value);
}
});
}
function updateStatus(value, status) {
value.then(statusFulfilled, statusRejected);
function statusFulfilled() { status.fulfilled(); }
function statusRejected(r) { status.rejected(r); }
}
/**
* Determines if x is promise-like, i.e. a thenable object
* NOTE: Will return true for *any thenable object*, and isn't truly
* safe, since it may attempt to access the `then` property of x (i.e.
* clever/malicious getters may do weird things)
* @param {*} x anything
* @returns {boolean} true if x is promise-like
*/
function isPromiseLike(x) {
return x && typeof x.then === 'function';
}
/**
* Initiates a competitive race, returning a promise that will resolve when
* howMany of the supplied promisesOrValues have resolved, or will reject when
* it becomes impossible for howMany to resolve, for example, when
* (promisesOrValues.length - howMany) + 1 input promises reject.
*
* @param {Array} promisesOrValues array of anything, may contain a mix
* of promises and values
* @param howMany {number} number of promisesOrValues to resolve
* @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then()
* @param {function?} [onRejected] DEPRECATED, use returnedPromise.then()
* @param {function?} [onProgress] DEPRECATED, use returnedPromise.then()
* @returns {Promise} promise that will resolve to an array of howMany values that
* resolved first, or will reject with an array of
* (promisesOrValues.length - howMany) + 1 rejection reasons.
*/
function some(promisesOrValues, howMany, onFulfilled, onRejected, onProgress) {
return when(promisesOrValues, function(promisesOrValues) {
return promise(resolveSome).then(onFulfilled, onRejected, onProgress);
function resolveSome(resolve, reject, notify) {
var toResolve, toReject, values, reasons, fulfillOne, rejectOne, len, i;
len = promisesOrValues.length >>> 0;
toResolve = Math.max(0, Math.min(howMany, len));
values = [];
toReject = (len - toResolve) + 1;
reasons = [];
// No items in the input, resolve immediately
if (!toResolve) {
resolve(values);
} else {
rejectOne = function(reason) {
reasons.push(reason);
if(!--toReject) {
fulfillOne = rejectOne = identity;
reject(reasons);
}
};
fulfillOne = function(val) {
// This orders the values based on promise resolution order
values.push(val);
if (!--toResolve) {
fulfillOne = rejectOne = identity;
resolve(values);
}
};
for(i = 0; i < len; ++i) {
if(i in promisesOrValues) {
when(promisesOrValues[i], fulfiller, rejecter, notify);
}
}
}
function rejecter(reason) {
rejectOne(reason);
}
function fulfiller(val) {
fulfillOne(val);
}
}
});
}
/**
* Initiates a competitive race, returning a promise that will resolve when
* any one of the supplied promisesOrValues has resolved or will reject when
* *all* promisesOrValues have rejected.
*
* @param {Array|Promise} promisesOrValues array of anything, may contain a mix
* of {@link Promise}s and values
* @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then()
* @param {function?} [onRejected] DEPRECATED, use returnedPromise.then()
* @param {function?} [onProgress] DEPRECATED, use returnedPromise.then()
* @returns {Promise} promise that will resolve to the value that resolved first, or
* will reject with an array of all rejected inputs.
*/
function any(promisesOrValues, onFulfilled, onRejected, onProgress) {
function unwrapSingleResult(val) {
return onFulfilled ? onFulfilled(val[0]) : val[0];
}
return some(promisesOrValues, 1, unwrapSingleResult, onRejected, onProgress);
}
/**
* Return a promise that will resolve only once all the supplied promisesOrValues
* have resolved. The resolution value of the returned promise will be an array
* containing the resolution values of each of the promisesOrValues.
* @memberOf when
*
* @param {Array|Promise} promisesOrValues array of anything, may contain a mix
* of {@link Promise}s and values
* @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then()
* @param {function?} [onRejected] DEPRECATED, use returnedPromise.then()
* @param {function?} [onProgress] DEPRECATED, use returnedPromise.then()
* @returns {Promise}
*/
function all(promisesOrValues, onFulfilled, onRejected, onProgress) {
return _map(promisesOrValues, identity).then(onFulfilled, onRejected, onProgress);
}
/**
* Joins multiple promises into a single returned promise.
* @return {Promise} a promise that will fulfill when *all* the input promises
* have fulfilled, or will reject when *any one* of the input promises rejects.
*/
function join(/* ...promises */) {
return _map(arguments, identity);
}
/**
* Settles all input promises such that they are guaranteed not to
* be pending once the returned promise fulfills. The returned promise
* will always fulfill, except in the case where `array` is a promise
* that rejects.
* @param {Array|Promise} array or promise for array of promises to settle
* @returns {Promise} promise that always fulfills with an array of
* outcome snapshots for each input promise.
*/
function settle(array) {
return _map(array, toFulfilledState, toRejectedState);
}
/**
* Promise-aware array map function, similar to `Array.prototype.map()`,
* but input array may contain promises or values.
* @param {Array|Promise} array array of anything, may contain promises and values
* @param {function} mapFunc map function which may return a promise or value
* @returns {Promise} promise that will fulfill with an array of mapped values
* or reject if any input promise rejects.
*/
function map(array, mapFunc) {
return _map(array, mapFunc);
}
/**
* Internal map that allows a fallback to handle rejections
* @param {Array|Promise} array array of anything, may contain promises and values
* @param {function} mapFunc map function which may return a promise or value
* @param {function?} fallback function to handle rejected promises
* @returns {Promise} promise that will fulfill with an array of mapped values
* or reject if any input promise rejects.
*/
function _map(array, mapFunc, fallback) {
return when(array, function(array) {
return _promise(resolveMap);
function resolveMap(resolve, reject, notify) {
var results, len, toResolve, i;
// Since we know the resulting length, we can preallocate the results
// array to avoid array expansions.
toResolve = len = array.length >>> 0;
results = [];
if(!toResolve) {
resolve(results);
return;
}
// Since mapFunc may be async, get all invocations of it into flight
for(i = 0; i < len; i++) {
if(i in array) {
resolveOne(array[i], i);
} else {
--toResolve;
}
}
function resolveOne(item, i) {
when(item, mapFunc, fallback).then(function(mapped) {
results[i] = mapped;
notify(mapped);
if(!--toResolve) {
resolve(results);
}
}, reject);
}
}
});
}
/**
* Traditional reduce function, similar to `Array.prototype.reduce()`, but
* input may contain promises and/or values, and reduceFunc
* may return either a value or a promise, *and* initialValue may
* be a promise for the starting value.
*
* @param {Array|Promise} promise array or promise for an array of anything,
* may contain a mix of promises and values.
* @param {function} reduceFunc reduce function reduce(currentValue, nextValue, index, total),
* where total is the total number of items being reduced, and will be the same
* in each call to reduceFunc.
* @returns {Promise} that will resolve to the final reduced value
*/
function reduce(promise, reduceFunc /*, initialValue */) {
var args = fcall(slice, arguments, 1);
return when(promise, function(array) {
var total;
total = array.length;
// Wrap the supplied reduceFunc with one that handles promises and then
// delegates to the supplied.
args[0] = function (current, val, i) {
return when(current, function (c) {
return when(val, function (value) {
return reduceFunc(c, value, i, total);
});
});
};
return reduceArray.apply(array, args);
});
}
// Snapshot states
/**
* Creates a fulfilled state snapshot
* @private
* @param {*} x any value
* @returns {{state:'fulfilled',value:*}}
*/
function toFulfilledState(x) {
return { state: 'fulfilled', value: x };
}
/**
* Creates a rejected state snapshot
* @private
* @param {*} x any reason
* @returns {{state:'rejected',reason:*}}
*/
function toRejectedState(x) {
return { state: 'rejected', reason: x };
}
/**
* Creates a pending state snapshot
* @private
* @returns {{state:'pending'}}
*/
function toPendingState() {
return { state: 'pending' };
}
//
// Internals, utilities, etc.
//
var reduceArray, slice, fcall, nextTick, handlerQueue,
setTimeout, funcProto, call, arrayProto, monitorApi,
cjsRequire, undef;
cjsRequire = require;
//
// Shared handler queue processing
//
// Credit to Twisol (https://github.com/Twisol) for suggesting
// this type of extensible queue + trampoline approach for
// next-tick conflation.
handlerQueue = [];
/**
* Enqueue a task. If the queue is not currently scheduled to be
* drained, schedule it.
* @param {function} task
*/
function enqueue(task) {
if(handlerQueue.push(task) === 1) {
nextTick(drainQueue);
}
}
/**
* Drain the handler queue entirely, being careful to allow the
* queue to be extended while it is being processed, and to continue
* processing until it is truly empty.
*/
function drainQueue() {
var task, i = 0;
while(task = handlerQueue[i++]) {
task();
}
handlerQueue = [];
}
// capture setTimeout to avoid being caught by fake timers
// used in time based tests
setTimeout = global.setTimeout;
// Allow attaching the monitor to when() if env has no console
monitorApi = typeof console != 'undefined' ? console : when;
// Prefer setImmediate or MessageChannel, cascade to node,
// vertx and finally setTimeout
/*global setImmediate,MessageChannel,process*/
if (typeof setImmediate === 'function') {
nextTick = setImmediate.bind(global);
} else if(typeof MessageChannel !== 'undefined') {
var channel = new MessageChannel();
channel.port1.onmessage = drainQueue;
nextTick = function() { channel.port2.postMessage(0); };
} else if (typeof process === 'object' && process.nextTick) {
nextTick = process.nextTick;
} else {
try {
// vert.x 1.x || 2.x
nextTick = cjsRequire('vertx').runOnLoop || cjsRequire('vertx').runOnContext;
} catch(ignore) {
nextTick = function(t) { setTimeout(t, 0); };
}
}
//
// Capture/polyfill function and array utils
//
// Safe function calls
funcProto = Function.prototype;
call = funcProto.call;
fcall = funcProto.bind
? call.bind(call)
: function(f, context) {
return f.apply(context, slice.call(arguments, 2));
};
// Safe array ops
arrayProto = [];
slice = arrayProto.slice;
// ES5 reduce implementation if native not available
// See: http://es5.github.com/#x15.4.4.21 as there are many
// specifics and edge cases. ES5 dictates that reduce.length === 1
// This implementation deviates from ES5 spec in the following ways:
// 1. It does not check if reduceFunc is a Callable
reduceArray = arrayProto.reduce ||
function(reduceFunc /*, initialValue */) {
/*jshint maxcomplexity: 7*/
var arr, args, reduced, len, i;
i = 0;
arr = Object(this);
len = arr.length >>> 0;
args = arguments;
// If no initialValue, use first item of array (we know length !== 0 here)
// and adjust i to start at second item
if(args.length <= 1) {
// Skip to the first real element in the array
for(;;) {
if(i in arr) {
reduced = arr[i++];
break;
}
// If we reached the end of the array without finding any real
// elements, it's a TypeError
if(++i >= len) {
throw new TypeError();
}
}
} else {
// If initialValue provided, use it
reduced = args[1];
}
// Do the actual reduce
for(;i < len; ++i) {
if(i in arr) {
reduced = reduceFunc(reduced, arr[i], i, arr);
}
}
return reduced;
};
function identity(x) {
return x;
}
return when;
});
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }, this);

View File

@ -16,13 +16,13 @@
"dependencies": {
"bane": "~1.0.0",
"faye-websocket": "~0.7.0",
"when": "~2.4.0"
"when": "~2.7.0"
},
"devDependencies": {
"buster": "~0.6.13",
"grunt": "~0.4.1",
"grunt-buster": "~0.2.1",
"grunt-contrib-concat": "~0.3.0",
"grunt-browserify": "~1.3.0",
"grunt-contrib-jshint": "~0.6.4",
"grunt-contrib-uglify": "~0.2.4",
"grunt-contrib-watch": "~0.5.3",

View File

@ -1,10 +1,8 @@
/*global exports:false, require:false*/
/*global module:true, require:false*/
if (typeof module === "object" && typeof require === "function") {
var bane = require("bane");
var websocket = require("faye-websocket");
var when = require("when");
}
var bane = require("bane");
var websocket = require("../lib/websocket/");
var when = require("when");
function Mopidy(settings) {
if (!(this instanceof Mopidy)) {
@ -26,11 +24,7 @@ function Mopidy(settings) {
}
}
if (typeof module === "object" && typeof require === "function") {
Mopidy.WebSocket = websocket.Client;
} else {
Mopidy.WebSocket = window.WebSocket;
}
Mopidy.WebSocket = websocket.Client;
Mopidy.prototype._configure = function (settings) {
var currentHost = (typeof document !== "undefined" &&
@ -295,6 +289,4 @@ Mopidy.prototype._snakeToCamel = function (name) {
});
};
if (typeof exports === "object") {
exports.Mopidy = Mopidy;
}
module.exports = Mopidy;

View File

@ -1,7 +1,11 @@
/*! Mopidy.js - built 2013-09-17
/*! Mopidy.js - built 2013-12-15
* http://www.mopidy.com/
* Copyright (c) 2013 Stein Magnus Jodal and contributors
* Licensed under the Apache License, Version 2.0 */
!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.Mopidy=e():"undefined"!=typeof global?global.Mopidy=e():"undefined"!=typeof self&&(self.Mopidy=e())}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
module.exports = { Client: window.WebSocket };
},{}],2:[function(require,module,exports){
((typeof define === "function" && define.amd && function (m) { define("bane", m); }) ||
(typeof module === "object" && function (m) { module.exports = m(); }) ||
function (m) { this.bane = m(); }
@ -166,18 +170,63 @@
return { createEventEmitter: createEventEmitter };
});
if (typeof window !== "undefined") {
window.define = function (factory) {
try {
delete window.define;
} catch (e) {
window.define = void 0; // IE
}
window.when = factory();
},{}],3:[function(require,module,exports){
// shim for using process in browser
var process = module.exports = {};
process.nextTick = (function () {
var canSetImmediate = typeof window !== 'undefined'
&& window.setImmediate;
var canPost = typeof window !== 'undefined'
&& window.postMessage && window.addEventListener
;
if (canSetImmediate) {
return function (f) { return window.setImmediate(f) };
}
if (canPost) {
var queue = [];
window.addEventListener('message', function (ev) {
if (ev.source === window && ev.data === 'process-tick') {
ev.stopPropagation();
if (queue.length > 0) {
var fn = queue.shift();
fn();
}
}
}, true);
return function nextTick(fn) {
queue.push(fn);
window.postMessage('process-tick', '*');
};
}
return function nextTick(fn) {
setTimeout(fn, 0);
};
window.define.amd = {};
})();
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
process.binding = function (name) {
throw new Error('process.binding is not supported');
}
// TODO(shtylman)
process.cwd = function () { return '/' };
process.chdir = function (dir) {
throw new Error('process.chdir is not supported');
};
},{}],4:[function(require,module,exports){
var process=require("__browserify_process");/** @license MIT License (c) copyright 2011-2013 original author or authors */
/**
* A lightweight CommonJS Promises/A and when() implementation
* when is part of the cujo.js family of libraries (http://cujojs.com/)
@ -187,9 +236,9 @@ if (typeof window !== "undefined") {
*
* @author Brian Cavalier
* @author John Hann
* @version 2.4.0
* @version 2.7.0
*/
(function(define, global) { 'use strict';
(function(define) { 'use strict';
define(function (require) {
// Public API
@ -230,7 +279,11 @@ define(function (require) {
function when(promiseOrValue, onFulfilled, onRejected, onProgress) {
// Get a trusted promise for the input promiseOrValue, and then
// register promise handlers
return resolve(promiseOrValue).then(onFulfilled, onRejected, onProgress);
return cast(promiseOrValue).then(onFulfilled, onRejected, onProgress);
}
function cast(x) {
return x instanceof Promise ? x : resolve(x);
}
/**
@ -247,102 +300,118 @@ define(function (require) {
this.inspect = inspect;
}
Promise.prototype = {
/**
* Register handlers for this promise.
* @param [onFulfilled] {Function} fulfillment handler
* @param [onRejected] {Function} rejection handler
* @param [onProgress] {Function} progress handler
* @return {Promise} new Promise
*/
then: function(onFulfilled, onRejected, onProgress) {
/*jshint unused:false*/
var args, sendMessage;
var promisePrototype = Promise.prototype;
args = arguments;
sendMessage = this._message;
/**
* Register handlers for this promise.
* @param [onFulfilled] {Function} fulfillment handler
* @param [onRejected] {Function} rejection handler
* @param [onProgress] {Function} progress handler
* @return {Promise} new Promise
*/
promisePrototype.then = function(onFulfilled, onRejected, onProgress) {
/*jshint unused:false*/
var args, sendMessage;
return _promise(function(resolve, reject, notify) {
sendMessage('when', args, resolve, notify);
}, this._status && this._status.observed());
},
args = arguments;
sendMessage = this._message;
/**
* Register a rejection handler. Shortcut for .then(undefined, onRejected)
* @param {function?} onRejected
* @return {Promise}
*/
otherwise: function(onRejected) {
return this.then(undef, onRejected);
},
return _promise(function(resolve, reject, notify) {
sendMessage('when', args, resolve, notify);
}, this._status && this._status.observed());
};
/**
* Ensures that onFulfilledOrRejected will be called regardless of whether
* this promise is fulfilled or rejected. onFulfilledOrRejected WILL NOT
* receive the promises' value or reason. Any returned value will be disregarded.
* onFulfilledOrRejected may throw or return a rejected promise to signal
* an additional error.
* @param {function} onFulfilledOrRejected handler to be called regardless of
* fulfillment or rejection
* @returns {Promise}
*/
ensure: function(onFulfilledOrRejected) {
return this.then(injectHandler, injectHandler)['yield'](this);
/**
* Register a rejection handler. Shortcut for .then(undefined, onRejected)
* @param {function?} onRejected
* @return {Promise}
*/
promisePrototype['catch'] = promisePrototype.otherwise = function(onRejected) {
return this.then(undef, onRejected);
};
function injectHandler() {
return resolve(onFulfilledOrRejected());
}
},
/**
* Ensures that onFulfilledOrRejected will be called regardless of whether
* this promise is fulfilled or rejected. onFulfilledOrRejected WILL NOT
* receive the promises' value or reason. Any returned value will be disregarded.
* onFulfilledOrRejected may throw or return a rejected promise to signal
* an additional error.
* @param {function} onFulfilledOrRejected handler to be called regardless of
* fulfillment or rejection
* @returns {Promise}
*/
promisePrototype['finally'] = promisePrototype.ensure = function(onFulfilledOrRejected) {
return typeof onFulfilledOrRejected === 'function'
? this.then(injectHandler, injectHandler)['yield'](this)
: this;
/**
* Shortcut for .then(function() { return value; })
* @param {*} value
* @return {Promise} a promise that:
* - is fulfilled if value is not a promise, or
* - if value is a promise, will fulfill with its value, or reject
* with its reason.
*/
'yield': function(value) {
return this.then(function() {
return value;
});
},
/**
* Runs a side effect when this promise fulfills, without changing the
* fulfillment value.
* @param {function} onFulfilledSideEffect
* @returns {Promise}
*/
tap: function(onFulfilledSideEffect) {
return this.then(onFulfilledSideEffect)['yield'](this);
},
/**
* Assumes that this promise will fulfill with an array, and arranges
* for the onFulfilled to be called with the array as its argument list
* i.e. onFulfilled.apply(undefined, array).
* @param {function} onFulfilled function to receive spread arguments
* @return {Promise}
*/
spread: function(onFulfilled) {
return this.then(function(array) {
// array may contain promises, so resolve its contents.
return all(array, function(array) {
return onFulfilled.apply(undef, array);
});
});
},
/**
* Shortcut for .then(onFulfilledOrRejected, onFulfilledOrRejected)
* @deprecated
*/
always: function(onFulfilledOrRejected, onProgress) {
return this.then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress);
function injectHandler() {
return resolve(onFulfilledOrRejected());
}
};
/**
* Terminate a promise chain by handling the ultimate fulfillment value or
* rejection reason, and assuming responsibility for all errors. if an
* error propagates out of handleResult or handleFatalError, it will be
* rethrown to the host, resulting in a loud stack track on most platforms
* and a crash on some.
* @param {function?} handleResult
* @param {function?} handleError
* @returns {undefined}
*/
promisePrototype.done = function(handleResult, handleError) {
this.then(handleResult, handleError).otherwise(crash);
};
/**
* Shortcut for .then(function() { return value; })
* @param {*} value
* @return {Promise} a promise that:
* - is fulfilled if value is not a promise, or
* - if value is a promise, will fulfill with its value, or reject
* with its reason.
*/
promisePrototype['yield'] = function(value) {
return this.then(function() {
return value;
});
};
/**
* Runs a side effect when this promise fulfills, without changing the
* fulfillment value.
* @param {function} onFulfilledSideEffect
* @returns {Promise}
*/
promisePrototype.tap = function(onFulfilledSideEffect) {
return this.then(onFulfilledSideEffect)['yield'](this);
};
/**
* Assumes that this promise will fulfill with an array, and arranges
* for the onFulfilled to be called with the array as its argument list
* i.e. onFulfilled.apply(undefined, array).
* @param {function} onFulfilled function to receive spread arguments
* @return {Promise}
*/
promisePrototype.spread = function(onFulfilled) {
return this.then(function(array) {
// array may contain promises, so resolve its contents.
return all(array, function(array) {
return onFulfilled.apply(undef, array);
});
});
};
/**
* Shortcut for .then(onFulfilledOrRejected, onFulfilledOrRejected)
* @deprecated
*/
promisePrototype.always = function(onFulfilledOrRejected, onProgress) {
return this.then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress);
};
/**
* Returns a resolved promise. The returned promise will be
* - fulfilled with promiseOrValue if it is a value, or
@ -499,13 +568,17 @@ define(function (require) {
return;
}
value = coerce(val);
scheduleConsumers(consumers, value);
var queue = consumers;
consumers = undef;
if(status) {
updateStatus(value, status);
}
enqueue(function () {
value = coerce(self, val);
if(status) {
updateStatus(value, status);
}
runHandlers(queue, value);
});
}
/**
@ -522,11 +595,24 @@ define(function (require) {
*/
function promiseNotify(update) {
if(consumers) {
scheduleConsumers(consumers, progressed(update));
var queue = consumers;
enqueue(function () {
runHandlers(queue, progressed(update));
});
}
}
}
/**
* Run a queue of functions as quickly as possible, passing
* value to each.
*/
function runHandlers(queue, value) {
for (var i = 0; i < queue.length; i++) {
queue[i](value);
}
}
/**
* Creates a fulfilled, local promise as a proxy for a value
* NOTE: must never be exposed
@ -590,8 +676,6 @@ define(function (require) {
/**
* Coerces x to a trusted Promise
*
* @private
* @param {*} x thing to coerce
* @returns {*} Guaranteed to return a trusted Promise. If x
* is trusted, returns x, otherwise, returns a new, trusted, already-resolved
@ -599,34 +683,35 @@ define(function (require) {
* * the resolution value of x if it's a foreign promise, or
* * x if it's a value
*/
function coerce(x) {
function coerce(self, x) {
if (x === self) {
return rejected(new TypeError());
}
if (x instanceof Promise) {
return x;
}
if (!(x === Object(x) && 'then' in x)) {
return fulfilled(x);
try {
var untrustedThen = x === Object(x) && x.then;
return typeof untrustedThen === 'function'
? assimilate(untrustedThen, x)
: fulfilled(x);
} catch(e) {
return rejected(e);
}
}
return promise(function(resolve, reject, notify) {
enqueue(function() {
try {
// We must check and assimilate in the same tick, but not the
// current tick, careful only to access promiseOrValue.then once.
var untrustedThen = x.then;
if(typeof untrustedThen === 'function') {
fcall(untrustedThen, x, resolve, reject, notify);
} else {
// It's a value, create a fulfilled wrapper
resolve(fulfilled(x));
}
} catch(e) {
// Something went wrong, reject
reject(e);
}
});
/**
* Safely assimilates a foreign thenable by wrapping it in a trusted promise
* @param {function} untrustedThen x's then() method
* @param {object|function} x thenable
* @returns {Promise}
*/
function assimilate(untrustedThen, x) {
return promise(function (resolve, reject) {
fcall(untrustedThen, x, resolve, reject);
});
}
@ -660,22 +745,6 @@ define(function (require) {
}
};
/**
* Schedule a task that will process a list of handlers
* in the next queue drain run.
* @private
* @param {Array} handlers queue of handlers to execute
* @param {*} value passed as the only arg to each handler
*/
function scheduleConsumers(handlers, value) {
enqueue(function() {
var handler, i = 0;
while (handler = handlers[i++]) {
handler(value);
}
});
}
function updateStatus(value, status) {
value.then(statusFulfilled, statusRejected);
@ -879,12 +948,11 @@ define(function (require) {
function resolveOne(item, i) {
when(item, mapFunc, fallback).then(function(mapped) {
results[i] = mapped;
notify(mapped);
if(!--toResolve) {
resolve(results);
}
}, reject);
}, reject, notify);
}
}
});
@ -961,8 +1029,8 @@ define(function (require) {
//
var reduceArray, slice, fcall, nextTick, handlerQueue,
setTimeout, funcProto, call, arrayProto, monitorApi,
cjsRequire, undef;
funcProto, call, arrayProto, monitorApi,
capturedSetTimeout, cjsRequire, MutationObs, undef;
cjsRequire = require;
@ -992,39 +1060,39 @@ define(function (require) {
* processing until it is truly empty.
*/
function drainQueue() {
var task, i = 0;
while(task = handlerQueue[i++]) {
task();
}
runHandlers(handlerQueue);
handlerQueue = [];
}
// capture setTimeout to avoid being caught by fake timers
// used in time based tests
setTimeout = global.setTimeout;
// Allow attaching the monitor to when() if env has no console
monitorApi = typeof console != 'undefined' ? console : when;
monitorApi = typeof console !== 'undefined' ? console : when;
// Prefer setImmediate or MessageChannel, cascade to node,
// vertx and finally setTimeout
/*global setImmediate,MessageChannel,process*/
if (typeof setImmediate === 'function') {
nextTick = setImmediate.bind(global);
} else if(typeof MessageChannel !== 'undefined') {
var channel = new MessageChannel();
channel.port1.onmessage = drainQueue;
nextTick = function() { channel.port2.postMessage(0); };
} else if (typeof process === 'object' && process.nextTick) {
// Sniff "best" async scheduling option
// Prefer process.nextTick or MutationObserver, then check for
// vertx and finally fall back to setTimeout
/*global process,document,setTimeout,MutationObserver,WebKitMutationObserver*/
if (typeof process === 'object' && process.nextTick) {
nextTick = process.nextTick;
} else if(MutationObs =
(typeof MutationObserver === 'function' && MutationObserver) ||
(typeof WebKitMutationObserver === 'function' && WebKitMutationObserver)) {
nextTick = (function(document, MutationObserver, drainQueue) {
var el = document.createElement('div');
new MutationObserver(drainQueue).observe(el, { attributes: true });
return function() {
el.setAttribute('x', 'x');
};
}(document, MutationObs, drainQueue));
} else {
try {
// vert.x 1.x || 2.x
nextTick = cjsRequire('vertx').runOnLoop || cjsRequire('vertx').runOnContext;
} catch(ignore) {
nextTick = function(t) { setTimeout(t, 0); };
// capture setTimeout to avoid being caught by fake timers
// used in time based tests
capturedSetTimeout = setTimeout;
nextTick = function(t) { capturedSetTimeout(t, 0); };
}
}
@ -1095,15 +1163,28 @@ define(function (require) {
return x;
}
function crash(fatalError) {
if(typeof monitorApi.reportUnhandled === 'function') {
monitorApi.reportUnhandled();
} else {
enqueue(function() {
throw fatalError;
});
}
throw fatalError;
}
return when;
});
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }, this);
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });
if (typeof module === "object" && typeof require === "function") {
var bane = require("bane");
var websocket = require("faye-websocket");
var when = require("when");
}
},{"__browserify_process":3}],5:[function(require,module,exports){
/*global module:true, require:false*/
var bane = require("bane");
var websocket = require("../lib/websocket/");
var when = require("when");
function Mopidy(settings) {
if (!(this instanceof Mopidy)) {
@ -1125,11 +1206,7 @@ function Mopidy(settings) {
}
}
if (typeof module === "object" && typeof require === "function") {
Mopidy.WebSocket = websocket.Client;
} else {
Mopidy.WebSocket = window.WebSocket;
}
Mopidy.WebSocket = websocket.Client;
Mopidy.prototype._configure = function (settings) {
var currentHost = (typeof document !== "undefined" &&
@ -1394,6 +1471,9 @@ Mopidy.prototype._snakeToCamel = function (name) {
});
};
if (typeof exports === "object") {
exports.Mopidy = Mopidy;
}
module.exports = Mopidy;
},{"../lib/websocket/":1,"bane":2,"when":4}]},{},[5])
(5)
});
;

File diff suppressed because one or more lines are too long