| import { | 
|   objectOrFunction, | 
|   isFunction | 
| } from './utils'; | 
|   | 
| import { | 
|   asap | 
| } from './asap'; | 
|   | 
| import originalThen from './then'; | 
| import originalResolve from './promise/resolve'; | 
|   | 
| export const PROMISE_ID = Math.random().toString(36).substring(2); | 
|   | 
| function noop() {} | 
|   | 
| const PENDING   = void 0; | 
| const FULFILLED = 1; | 
| const REJECTED  = 2; | 
|   | 
| const TRY_CATCH_ERROR = { error: null }; | 
|   | 
| function selfFulfillment() { | 
|   return new TypeError("You cannot resolve a promise with itself"); | 
| } | 
|   | 
| function cannotReturnOwn() { | 
|   return new TypeError('A promises callback cannot return that same promise.'); | 
| } | 
|   | 
| function getThen(promise) { | 
|   try { | 
|     return promise.then; | 
|   } catch(error) { | 
|     TRY_CATCH_ERROR.error = error; | 
|     return TRY_CATCH_ERROR; | 
|   } | 
| } | 
|   | 
| function tryThen(then, value, fulfillmentHandler, rejectionHandler) { | 
|   try { | 
|     then.call(value, fulfillmentHandler, rejectionHandler); | 
|   } catch(e) { | 
|     return e; | 
|   } | 
| } | 
|   | 
| function handleForeignThenable(promise, thenable, then) { | 
|    asap(promise => { | 
|     var sealed = false; | 
|     var error = tryThen(then, thenable, value => { | 
|       if (sealed) { return; } | 
|       sealed = true; | 
|       if (thenable !== value) { | 
|         resolve(promise, value); | 
|       } else { | 
|         fulfill(promise, value); | 
|       } | 
|     }, reason => { | 
|       if (sealed) { return; } | 
|       sealed = true; | 
|   | 
|       reject(promise, reason); | 
|     }, 'Settle: ' + (promise._label || ' unknown promise')); | 
|   | 
|     if (!sealed && error) { | 
|       sealed = true; | 
|       reject(promise, error); | 
|     } | 
|   }, promise); | 
| } | 
|   | 
| function handleOwnThenable(promise, thenable) { | 
|   if (thenable._state === FULFILLED) { | 
|     fulfill(promise, thenable._result); | 
|   } else if (thenable._state === REJECTED) { | 
|     reject(promise, thenable._result); | 
|   } else { | 
|     subscribe(thenable, undefined, value  => resolve(promise, value), | 
|                                    reason => reject(promise, reason)) | 
|   } | 
| } | 
|   | 
| function handleMaybeThenable(promise, maybeThenable, then) { | 
|   if (maybeThenable.constructor === promise.constructor && | 
|       then === originalThen && | 
|       maybeThenable.constructor.resolve === originalResolve) { | 
|     handleOwnThenable(promise, maybeThenable); | 
|   } else { | 
|     if (then === TRY_CATCH_ERROR) { | 
|       reject(promise, TRY_CATCH_ERROR.error); | 
|       TRY_CATCH_ERROR.error = null; | 
|     } else if (then === undefined) { | 
|       fulfill(promise, maybeThenable); | 
|     } else if (isFunction(then)) { | 
|       handleForeignThenable(promise, maybeThenable, then); | 
|     } else { | 
|       fulfill(promise, maybeThenable); | 
|     } | 
|   } | 
| } | 
|   | 
| function resolve(promise, value) { | 
|   if (promise === value) { | 
|     reject(promise, selfFulfillment()); | 
|   } else if (objectOrFunction(value)) { | 
|     handleMaybeThenable(promise, value, getThen(value)); | 
|   } else { | 
|     fulfill(promise, value); | 
|   } | 
| } | 
|   | 
| function publishRejection(promise) { | 
|   if (promise._onerror) { | 
|     promise._onerror(promise._result); | 
|   } | 
|   | 
|   publish(promise); | 
| } | 
|   | 
| function fulfill(promise, value) { | 
|   if (promise._state !== PENDING) { return; } | 
|   | 
|   promise._result = value; | 
|   promise._state = FULFILLED; | 
|   | 
|   if (promise._subscribers.length !== 0) { | 
|     asap(publish, promise); | 
|   } | 
| } | 
|   | 
| function reject(promise, reason) { | 
|   if (promise._state !== PENDING) { return; } | 
|   promise._state = REJECTED; | 
|   promise._result = reason; | 
|   | 
|   asap(publishRejection, promise); | 
| } | 
|   | 
| function subscribe(parent, child, onFulfillment, onRejection) { | 
|   let { _subscribers } = parent; | 
|   let { length } = _subscribers; | 
|   | 
|   parent._onerror = null; | 
|   | 
|   _subscribers[length] = child; | 
|   _subscribers[length + FULFILLED] = onFulfillment; | 
|   _subscribers[length + REJECTED]  = onRejection; | 
|   | 
|   if (length === 0 && parent._state) { | 
|     asap(publish, parent); | 
|   } | 
| } | 
|   | 
| function publish(promise) { | 
|   let subscribers = promise._subscribers; | 
|   let settled = promise._state; | 
|   | 
|   if (subscribers.length === 0) { return; } | 
|   | 
|   let child, callback, detail = promise._result; | 
|   | 
|   for (let i = 0; i < subscribers.length; i += 3) { | 
|     child = subscribers[i]; | 
|     callback = subscribers[i + settled]; | 
|   | 
|     if (child) { | 
|       invokeCallback(settled, child, callback, detail); | 
|     } else { | 
|       callback(detail); | 
|     } | 
|   } | 
|   | 
|   promise._subscribers.length = 0; | 
| } | 
|   | 
|   | 
| function tryCatch(callback, detail) { | 
|   try { | 
|     return callback(detail); | 
|   } catch(e) { | 
|     TRY_CATCH_ERROR.error = e; | 
|     return TRY_CATCH_ERROR; | 
|   } | 
| } | 
|   | 
| function invokeCallback(settled, promise, callback, detail) { | 
|   let hasCallback = isFunction(callback), | 
|       value, error, succeeded, failed; | 
|   | 
|   if (hasCallback) { | 
|     value = tryCatch(callback, detail); | 
|   | 
|     if (value === TRY_CATCH_ERROR) { | 
|       failed = true; | 
|       error = value.error; | 
|       value.error = null; | 
|     } else { | 
|       succeeded = true; | 
|     } | 
|   | 
|     if (promise === value) { | 
|       reject(promise, cannotReturnOwn()); | 
|       return; | 
|     } | 
|   | 
|   } else { | 
|     value = detail; | 
|     succeeded = true; | 
|   } | 
|   | 
|   if (promise._state !== PENDING) { | 
|     // noop | 
|   } else if (hasCallback && succeeded) { | 
|     resolve(promise, value); | 
|   } else if (failed) { | 
|     reject(promise, error); | 
|   } else if (settled === FULFILLED) { | 
|     fulfill(promise, value); | 
|   } else if (settled === REJECTED) { | 
|     reject(promise, value); | 
|   } | 
| } | 
|   | 
| function initializePromise(promise, resolver) { | 
|   try { | 
|     resolver(function resolvePromise(value){ | 
|       resolve(promise, value); | 
|     }, function rejectPromise(reason) { | 
|       reject(promise, reason); | 
|     }); | 
|   } catch(e) { | 
|     reject(promise, e); | 
|   } | 
| } | 
|   | 
| let id = 0; | 
| function nextId() { | 
|   return id++; | 
| } | 
|   | 
| function makePromise(promise) { | 
|   promise[PROMISE_ID] = id++; | 
|   promise._state = undefined; | 
|   promise._result = undefined; | 
|   promise._subscribers = []; | 
| } | 
|   | 
| export { | 
|   nextId, | 
|   makePromise, | 
|   getThen, | 
|   noop, | 
|   resolve, | 
|   reject, | 
|   fulfill, | 
|   subscribe, | 
|   publish, | 
|   publishRejection, | 
|   initializePromise, | 
|   invokeCallback, | 
|   FULFILLED, | 
|   REJECTED, | 
|   PENDING, | 
|   handleMaybeThenable | 
| }; |