1/**
2@license
3Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
4This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7Code distributed by Google as part of the polymer project is also
8subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
9*/
10function MakePromise (asap) {
11  function Promise(fn) {
12		if (typeof this !== 'object' || typeof fn !== 'function') throw new TypeError();
13		this._state = null;
14		this._value = null;
15		this._deferreds = []
16
17		doResolve(fn, resolve.bind(this), reject.bind(this));
18	}
19
20	function handle(deferred) {
21		var me = this;
22		if (this._state === null) {
23			this._deferreds.push(deferred);
24			return
25		}
26		asap(function() {
27			var cb = me._state ? deferred.onFulfilled : deferred.onRejected
28			if (typeof cb !== 'function') {
29				(me._state ? deferred.resolve : deferred.reject)(me._value);
30				return;
31			}
32			var ret;
33			try {
34				ret = cb(me._value);
35			}
36			catch (e) {
37				deferred.reject(e);
38				return;
39			}
40			deferred.resolve(ret);
41		})
42	}
43
44	function resolve(newValue) {
45		try { //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
46			if (newValue === this) throw new TypeError();
47			if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
48				var then = newValue.then;
49				if (typeof then === 'function') {
50					doResolve(then.bind(newValue), resolve.bind(this), reject.bind(this));
51					return;
52				}
53			}
54			this._state = true;
55			this._value = newValue;
56			finale.call(this);
57		} catch (e) { reject.call(this, e); }
58	}
59
60	function reject(newValue) {
61		this._state = false;
62		this._value = newValue;
63		finale.call(this);
64	}
65
66	function finale() {
67		for (var i = 0, len = this._deferreds.length; i < len; i++) {
68			handle.call(this, this._deferreds[i]);
69		}
70		this._deferreds = null;
71	}
72
73	/**
74	 * Take a potentially misbehaving resolver function and make sure
75	 * onFulfilled and onRejected are only called once.
76	 *
77	 * Makes no guarantees about asynchrony.
78	 */
79	function doResolve(fn, onFulfilled, onRejected) {
80		var done = false;
81		try {
82			fn(function (value) {
83				if (done) return;
84				done = true;
85				onFulfilled(value);
86			}, function (reason) {
87				if (done) return;
88				done = true;
89				onRejected(reason);
90			})
91		} catch (ex) {
92			if (done) return;
93			done = true;
94			onRejected(ex);
95		}
96	}
97
98	Promise.prototype['catch'] = function (onRejected) {
99		return this.then(null, onRejected);
100	};
101
102	Promise.prototype.then = function(onFulfilled, onRejected) {
103		var me = this;
104		return new Promise(function(resolve, reject) {
105      handle.call(me, {
106        onFulfilled: onFulfilled,
107        onRejected: onRejected,
108        resolve: resolve,
109        reject: reject
110      });
111		})
112	};
113
114	Promise.resolve = function (value) {
115		if (value && typeof value === 'object' && value.constructor === Promise) {
116			return value;
117		}
118
119		return new Promise(function (resolve) {
120			resolve(value);
121		});
122	};
123
124	Promise.reject = function (value) {
125		return new Promise(function (resolve, reject) {
126			reject(value);
127		});
128	};
129
130
131  return Promise;
132}
133
134if (typeof module !== 'undefined') {
135  module.exports = MakePromise;
136}
137
138