text: 'use strict';
  var $          = require('./$')
    , LIBRARY    = require('./$.library')
    , global     = require('./$.global')
    , ctx        = require('./$.ctx')
    , classof    = require('./$.classof')
    , $def       = require('./$.def')
    , isObject   = require('./$.is-object')
    , anObject   = require('./$.an-object')
    , aFunction  = require('./$.a-function')
    , strictNew  = require('./$.strict-new')
    , forOf      = require('./$.for-of')
    , setProto   = require('./$.set-proto').set
    , same       = require('./$.same')
    , species    = require('./$.species')
    , SPECIES    = require('./$.wks')('species')
    , RECORD     = require('./$.uid')('record')
    , PROMISE    = 'Promise'
    , process    = global.process
    , isNode     = classof(process) == 'process'
    , asap       = process && process.nextTick || require('./$.task').set
    , P          = global[PROMISE]
    , Wrapper;
  
  function testResolve(sub){
    var test = new P(function(){});
    if(sub)test.constructor = Object;
    return P.resolve(test) === test;
  }
  
  var useNative = function(){
    var works = false;
    function P2(x){
      var self = new P(x);
      setProto(self, P2.prototype);
      return self;
    }
    try {
      works = P && P.resolve && testResolve();
      setProto(P2, P);
      P2.prototype = $.create(P.prototype, {constructor: {value: P2}});
      // actual Firefox has broken subclass support, test that
      if(!(P2.resolve(5).then(function(){}) instanceof P2)){
        works = false;
      }
      // actual V8 bug, https://code.google.com/p/v8/issues/detail?id=4162
      if(works && require('./$.support-desc')){
        var thenableThenGotten = false;
        P.resolve($.setDesc({}, 'then', {
          get: function(){ thenableThenGotten = true; }
        }));
        works = thenableThenGotten;
      }
    } catch(e){ works = false; }
    return works;
  }();
  
  // helpers
  function isPromise(it){
    return isObject(it) && (useNative ? classof(it) == 'Promise' : RECORD in it);
  }
  function sameConstructor(a, b){
    // library wrapper special case
    if(LIBRARY && a === P && b === Wrapper)return true;
    return same(a, b);
  }
  function getConstructor(C){
    var S = anObject(C)[SPECIES];
    return S != undefined ? S : C;
  }
  function isThenable(it){
    var then;
    return isObject(it) && typeof (then = it.then) == 'function' ? then : false;
  }
  function notify(record, isReject){
    if(record.n)return;
    record.n = true;
    var chain = record.c;
    // strange IE + webpack dev server bug - use .call(global)
    asap.call(global, function(){
      var value = record.v
        , ok    = record.s == 1
        , i     = 0;
      function run(react){
        var cb = ok ? react.ok : react.fail
          , ret, then;
        try {
          if(cb){
            if(!ok)record.h = true;
            ret = cb === true ? value : cb(value);
            if(ret === react.P){
              react.rej(TypeError('Promise-chain cycle'));
            } else if(then = isThenable(ret)){
              then.call(ret, react.res, react.rej);
            } else react.res(ret);
          } else react.rej(value);
        } catch(err){
          react.rej(err);
        }
      }
      while(chain.length > i)run(chain[i++]); // variable length - can't use forEach
      chain.length = 0;
      record.n = false;
      if(isReject)setTimeout(function(){
        // strange IE + webpack dev server bug - use .call(global)
        asap.call(global, function(){
          if(isUnhandled(record.p)){
            if(isNode){
              process.emit('unhandledRejection', value, record.p);
            } else if(global.console && console.error){
              console.error('Unhandled promise rejection', value);
            }
          }
          record.a = undefined;
        });
      }, 1);
    });
  }
  function isUnhandled(promise){
    var record = promise[RECORD]
      , chain  = record.a || record.c
      , i      = 0
      , react;
    if(record.h)return false;
    while(chain.length > i){
      react = chain[i++];
      if(react.fail || !isUnhandled(react.P))return false;
    } return true;
  }
  function $reject(value){
    var record = this;
    if(record.d)return;
    record.d = true;
    record = record.r || record; // unwrap
    record.v = value;
    record.s = 2;
    record.a = record.c.slice();
    notify(record, true);
  }
  function $resolve(value){
    var record = this
      , then;
    if(record.d)return;
    record.d = true;
    record = record.r || record; // unwrap
    try {
      if(then = isThenable(value)){
        // strange IE + webpack dev server bug - use .call(global)
        asap.call(global, function(){
          var wrapper = {r: record, d: false}; // wrap
          try {
            then.call(value, ctx($resolve, wrapper, 1), ctx($reject, wrapper, 1));
          } catch(e){
            $reject.call(wrapper, e);
          }
        });
      } else {
        record.v = value;
        record.s = 1;
        notify(record, false);
      }
    } catch(e){
      $reject.call({r: record, d: false}, e); // wrap
    }
  }
  
  // constructor polyfill
  if(!useNative){
    // 25.4.3.1 Promise(executor)
    P = function Promise(executor){
      aFunction(executor);
      var record = {
        p: strictNew(this, P, PROMISE),         // <- promise
        c: [],                                  // <- awaiting reactions
        a: undefined,                           // <- checked in isUnhandled reactions
        s: 0,                                   // <- state
        d: false,                               // <- done
        v: undefined,                           // <- value
        h: false,                               // <- handled rejection
        n: false                                // <- notify
      };
      this[RECORD] = record;
      try {
        executor(ctx($resolve, record, 1), ctx($reject, record, 1));
      } catch(err){
        $reject.call(record, err);
      }
    };
    require('./$.mix')(P.prototype, {
      // 25.4.5.3 Promise.prototype.then(onFulfilled, onRejected)
      then: function then(onFulfilled, onRejected){
        var S = anObject(anObject(this).constructor)[SPECIES];
        var react = {
          ok:   typeof onFulfilled == 'function' ? onFulfilled : true,
          fail: typeof onRejected == 'function'  ? onRejected  : false
        };
        var promise = react.P = new (S != undefined ? S : P)(function(res, rej){
          react.res = aFunction(res);
          react.rej = aFunction(rej);
        });
        var record = this[RECORD];
        record.c.push(react);
        if(record.a)record.a.push(react);
        if(record.s)notify(record, false);
        return promise;
      },
      // 25.4.5.1 Promise.prototype.catch(onRejected)
      'catch': function(onRejected){
        return this.then(undefined, onRejected);
      }
    });
  }
  
  // export
  $def($def.G + $def.W + $def.F * !useNative, {Promise: P});
  require('./$.tag')(P, PROMISE);
  species(P);
  species(Wrapper = require('./$.core')[PROMISE]);
  
  // statics
  $def($def.S + $def.F * !useNative, PROMISE, {
    // 25.4.4.5 Promise.reject(r)
    reject: function reject(r){
      return new this(function(res, rej){ rej(r); });
    }
  });
  $def($def.S + $def.F * (!useNative || testResolve(true)), PROMISE, {
    // 25.4.4.6 Promise.resolve(x)
    resolve: function resolve(x){
      return isPromise(x) && sameConstructor(x.constructor, this)
        ? x : new this(function(res){ res(x); });
    }
  });
  $def($def.S + $def.F * !(useNative && require('./$.iter-detect')(function(iter){
    P.all(iter)['catch'](function(){});
  })), PROMISE, {
    // 25.4.4.1 Promise.all(iterable)
    all: function all(iterable){
      var C      = getConstructor(this)
        , values = [];
      return new C(function(res, rej){
        forOf(iterable, false, values.push, values);
        var remaining = values.length
          , results   = Array(remaining);
        if(remaining)$.each.call(values, function(promise, index){
          C.resolve(promise).then(function(value){
            results[index] = value;
            --remaining || res(results);
          }, rej);
        });
        else res(results);
      });
    },
    // 25.4.4.4 Promise.race(iterable)
    race: function race(iterable){
      var C = getConstructor(this);
      return new C(function(res, rej){
        forOf(iterable, false, function(promise){
          C.resolve(promise).then(res, rej);
        });
      });
    }
  });