| 'use strict'; | 
 |  | 
 | var PENDING = 'pending'; | 
 | var SETTLED = 'settled'; | 
 | var FULFILLED = 'fulfilled'; | 
 | var REJECTED = 'rejected'; | 
 | var NOOP = function () {}; | 
 | var isNode = typeof global !== 'undefined' && typeof global.process !== 'undefined' && typeof global.process.emit === 'function'; | 
 |  | 
 | var asyncSetTimer = typeof setImmediate === 'undefined' ? setTimeout : setImmediate; | 
 | var asyncQueue = []; | 
 | var asyncTimer; | 
 |  | 
 | function asyncFlush() { | 
 | 	// run promise callbacks | 
 | 	for (var i = 0; i < asyncQueue.length; i++) { | 
 | 		asyncQueue[i][0](asyncQueue[i][1]); | 
 | 	} | 
 |  | 
 | 	// reset async asyncQueue | 
 | 	asyncQueue = []; | 
 | 	asyncTimer = false; | 
 | } | 
 |  | 
 | function asyncCall(callback, arg) { | 
 | 	asyncQueue.push([callback, arg]); | 
 |  | 
 | 	if (!asyncTimer) { | 
 | 		asyncTimer = true; | 
 | 		asyncSetTimer(asyncFlush, 0); | 
 | 	} | 
 | } | 
 |  | 
 | function invokeResolver(resolver, promise) { | 
 | 	function resolvePromise(value) { | 
 | 		resolve(promise, value); | 
 | 	} | 
 |  | 
 | 	function rejectPromise(reason) { | 
 | 		reject(promise, reason); | 
 | 	} | 
 |  | 
 | 	try { | 
 | 		resolver(resolvePromise, rejectPromise); | 
 | 	} catch (e) { | 
 | 		rejectPromise(e); | 
 | 	} | 
 | } | 
 |  | 
 | function invokeCallback(subscriber) { | 
 | 	var owner = subscriber.owner; | 
 | 	var settled = owner._state; | 
 | 	var value = owner._data; | 
 | 	var callback = subscriber[settled]; | 
 | 	var promise = subscriber.then; | 
 |  | 
 | 	if (typeof callback === 'function') { | 
 | 		settled = FULFILLED; | 
 | 		try { | 
 | 			value = callback(value); | 
 | 		} catch (e) { | 
 | 			reject(promise, e); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if (!handleThenable(promise, value)) { | 
 | 		if (settled === FULFILLED) { | 
 | 			resolve(promise, value); | 
 | 		} | 
 |  | 
 | 		if (settled === REJECTED) { | 
 | 			reject(promise, value); | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | function handleThenable(promise, value) { | 
 | 	var resolved; | 
 |  | 
 | 	try { | 
 | 		if (promise === value) { | 
 | 			throw new TypeError('A promises callback cannot return that same promise.'); | 
 | 		} | 
 |  | 
 | 		if (value && (typeof value === 'function' || typeof value === 'object')) { | 
 | 			// then should be retrieved only once | 
 | 			var then = value.then; | 
 |  | 
 | 			if (typeof then === 'function') { | 
 | 				then.call(value, function (val) { | 
 | 					if (!resolved) { | 
 | 						resolved = true; | 
 |  | 
 | 						if (value === val) { | 
 | 							fulfill(promise, val); | 
 | 						} else { | 
 | 							resolve(promise, val); | 
 | 						} | 
 | 					} | 
 | 				}, function (reason) { | 
 | 					if (!resolved) { | 
 | 						resolved = true; | 
 |  | 
 | 						reject(promise, reason); | 
 | 					} | 
 | 				}); | 
 |  | 
 | 				return true; | 
 | 			} | 
 | 		} | 
 | 	} catch (e) { | 
 | 		if (!resolved) { | 
 | 			reject(promise, e); | 
 | 		} | 
 |  | 
 | 		return true; | 
 | 	} | 
 |  | 
 | 	return false; | 
 | } | 
 |  | 
 | function resolve(promise, value) { | 
 | 	if (promise === value || !handleThenable(promise, value)) { | 
 | 		fulfill(promise, value); | 
 | 	} | 
 | } | 
 |  | 
 | function fulfill(promise, value) { | 
 | 	if (promise._state === PENDING) { | 
 | 		promise._state = SETTLED; | 
 | 		promise._data = value; | 
 |  | 
 | 		asyncCall(publishFulfillment, promise); | 
 | 	} | 
 | } | 
 |  | 
 | function reject(promise, reason) { | 
 | 	if (promise._state === PENDING) { | 
 | 		promise._state = SETTLED; | 
 | 		promise._data = reason; | 
 |  | 
 | 		asyncCall(publishRejection, promise); | 
 | 	} | 
 | } | 
 |  | 
 | function publish(promise) { | 
 | 	promise._then = promise._then.forEach(invokeCallback); | 
 | } | 
 |  | 
 | function publishFulfillment(promise) { | 
 | 	promise._state = FULFILLED; | 
 | 	publish(promise); | 
 | } | 
 |  | 
 | function publishRejection(promise) { | 
 | 	promise._state = REJECTED; | 
 | 	publish(promise); | 
 | 	if (!promise._handled && isNode) { | 
 | 		global.process.emit('unhandledRejection', promise._data, promise); | 
 | 	} | 
 | } | 
 |  | 
 | function notifyRejectionHandled(promise) { | 
 | 	global.process.emit('rejectionHandled', promise); | 
 | } | 
 |  | 
 | /** | 
 |  * @class | 
 |  */ | 
 | function Promise(resolver) { | 
 | 	if (typeof resolver !== 'function') { | 
 | 		throw new TypeError('Promise resolver ' + resolver + ' is not a function'); | 
 | 	} | 
 |  | 
 | 	if (this instanceof Promise === false) { | 
 | 		throw new TypeError('Failed to construct \'Promise\': Please use the \'new\' operator, this object constructor cannot be called as a function.'); | 
 | 	} | 
 |  | 
 | 	this._then = []; | 
 |  | 
 | 	invokeResolver(resolver, this); | 
 | } | 
 |  | 
 | Promise.prototype = { | 
 | 	constructor: Promise, | 
 |  | 
 | 	_state: PENDING, | 
 | 	_then: null, | 
 | 	_data: undefined, | 
 | 	_handled: false, | 
 |  | 
 | 	then: function (onFulfillment, onRejection) { | 
 | 		var subscriber = { | 
 | 			owner: this, | 
 | 			then: new this.constructor(NOOP), | 
 | 			fulfilled: onFulfillment, | 
 | 			rejected: onRejection | 
 | 		}; | 
 |  | 
 | 		if ((onRejection || onFulfillment) && !this._handled) { | 
 | 			this._handled = true; | 
 | 			if (this._state === REJECTED && isNode) { | 
 | 				asyncCall(notifyRejectionHandled, this); | 
 | 			} | 
 | 		} | 
 |  | 
 | 		if (this._state === FULFILLED || this._state === REJECTED) { | 
 | 			// already resolved, call callback async | 
 | 			asyncCall(invokeCallback, subscriber); | 
 | 		} else { | 
 | 			// subscribe | 
 | 			this._then.push(subscriber); | 
 | 		} | 
 |  | 
 | 		return subscriber.then; | 
 | 	}, | 
 |  | 
 | 	catch: function (onRejection) { | 
 | 		return this.then(null, onRejection); | 
 | 	} | 
 | }; | 
 |  | 
 | Promise.all = function (promises) { | 
 | 	if (!Array.isArray(promises)) { | 
 | 		throw new TypeError('You must pass an array to Promise.all().'); | 
 | 	} | 
 |  | 
 | 	return new Promise(function (resolve, reject) { | 
 | 		var results = []; | 
 | 		var remaining = 0; | 
 |  | 
 | 		function resolver(index) { | 
 | 			remaining++; | 
 | 			return function (value) { | 
 | 				results[index] = value; | 
 | 				if (!--remaining) { | 
 | 					resolve(results); | 
 | 				} | 
 | 			}; | 
 | 		} | 
 |  | 
 | 		for (var i = 0, promise; i < promises.length; i++) { | 
 | 			promise = promises[i]; | 
 |  | 
 | 			if (promise && typeof promise.then === 'function') { | 
 | 				promise.then(resolver(i), reject); | 
 | 			} else { | 
 | 				results[i] = promise; | 
 | 			} | 
 | 		} | 
 |  | 
 | 		if (!remaining) { | 
 | 			resolve(results); | 
 | 		} | 
 | 	}); | 
 | }; | 
 |  | 
 | Promise.race = function (promises) { | 
 | 	if (!Array.isArray(promises)) { | 
 | 		throw new TypeError('You must pass an array to Promise.race().'); | 
 | 	} | 
 |  | 
 | 	return new Promise(function (resolve, reject) { | 
 | 		for (var i = 0, promise; i < promises.length; i++) { | 
 | 			promise = promises[i]; | 
 |  | 
 | 			if (promise && typeof promise.then === 'function') { | 
 | 				promise.then(resolve, reject); | 
 | 			} else { | 
 | 				resolve(promise); | 
 | 			} | 
 | 		} | 
 | 	}); | 
 | }; | 
 |  | 
 | Promise.resolve = function (value) { | 
 | 	if (value && typeof value === 'object' && value.constructor === Promise) { | 
 | 		return value; | 
 | 	} | 
 |  | 
 | 	return new Promise(function (resolve) { | 
 | 		resolve(value); | 
 | 	}); | 
 | }; | 
 |  | 
 | Promise.reject = function (reason) { | 
 | 	return new Promise(function (resolve, reject) { | 
 | 		reject(reason); | 
 | 	}); | 
 | }; | 
 |  | 
 | module.exports = Promise; |