text: !function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.Promise=e():"undefined"!=typeof global?global.Promise=e():"undefined"!=typeof self&&(self.Promise=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){
  /** @license MIT License (c) copyright 2010-2014 original author or authors */
  /** @author Brian Cavalier */
  /** @author John Hann */
  
  /**
   * ES6 global Promise shim
   */
  var unhandledRejections = require('../lib/decorators/unhandledRejection');
  var PromiseConstructor = unhandledRejections(require('../lib/Promise'));
  
  module.exports = typeof global != 'undefined' ? (global.Promise = PromiseConstructor)
  	           : typeof self   != 'undefined' ? (self.Promise   = PromiseConstructor)
  	           : PromiseConstructor;
  
  },{"../lib/Promise":2,"../lib/decorators/unhandledRejection":4}],2:[function(require,module,exports){
  /** @license MIT License (c) copyright 2010-2014 original author or authors */
  /** @author Brian Cavalier */
  /** @author John Hann */
  
  (function(define) { 'use strict';
  define(function (require) {
  
  	var makePromise = require('./makePromise');
  	var Scheduler = require('./Scheduler');
  	var async = require('./env').asap;
  
  	return makePromise({
  		scheduler: new Scheduler(async)
  	});
  
  });
  })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });
  
  },{"./Scheduler":3,"./env":5,"./makePromise":7}],3:[function(require,module,exports){
  /** @license MIT License (c) copyright 2010-2014 original author or authors */
  /** @author Brian Cavalier */
  /** @author John Hann */
  
  (function(define) { 'use strict';
  define(function() {
  
  	// Credit to Twisol (https://github.com/Twisol) for suggesting
  	// this type of extensible queue + trampoline approach for next-tick conflation.
  
  	/**
  	 * Async task scheduler
  	 * @param {function} async function to schedule a single async function
  	 * @constructor
  	 */
  	function Scheduler(async) {
  		this._async = async;
  		this._running = false;
  
  		this._queue = this;
  		this._queueLen = 0;
  		this._afterQueue = {};
  		this._afterQueueLen = 0;
  
  		var self = this;
  		this.drain = function() {
  			self._drain();
  		};
  	}
  
  	/**
  	 * Enqueue a task
  	 * @param {{ run:function }} task
  	 */
  	Scheduler.prototype.enqueue = function(task) {
  		this._queue[this._queueLen++] = task;
  		this.run();
  	};
  
  	/**
  	 * Enqueue a task to run after the main task queue
  	 * @param {{ run:function }} task
  	 */
  	Scheduler.prototype.afterQueue = function(task) {
  		this._afterQueue[this._afterQueueLen++] = task;
  		this.run();
  	};
  
  	Scheduler.prototype.run = function() {
  		if (!this._running) {
  			this._running = true;
  			this._async(this.drain);
  		}
  	};
  
  	/**
  	 * Drain the handler queue entirely, and then the after queue
  	 */
  	Scheduler.prototype._drain = function() {
  		var i = 0;
  		for (; i < this._queueLen; ++i) {
  			this._queue[i].run();
  			this._queue[i] = void 0;
  		}
  
  		this._queueLen = 0;
  		this._running = false;
  
  		for (i = 0; i < this._afterQueueLen; ++i) {
  			this._afterQueue[i].run();
  			this._afterQueue[i] = void 0;
  		}
  
  		this._afterQueueLen = 0;
  	};
  
  	return Scheduler;
  
  });
  }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
  
  },{}],4:[function(require,module,exports){
  /** @license MIT License (c) copyright 2010-2014 original author or authors */
  /** @author Brian Cavalier */
  /** @author John Hann */
  
  (function(define) { 'use strict';
  define(function(require) {
  
  	var setTimer = require('../env').setTimer;
  	var format = require('../format');
  
  	return function unhandledRejection(Promise) {
  
  		var logError = noop;
  		var logInfo = noop;
  		var localConsole;
  
  		if(typeof console !== 'undefined') {
  			// Alias console to prevent things like uglify's drop_console option from
  			// removing console.log/error. Unhandled rejections fall into the same
  			// category as uncaught exceptions, and build tools shouldn't silence them.
  			localConsole = console;
  			logError = typeof localConsole.error !== 'undefined'
  				? function (e) { localConsole.error(e); }
  				: function (e) { localConsole.log(e); };
  
  			logInfo = typeof localConsole.info !== 'undefined'
  				? function (e) { localConsole.info(e); }
  				: function (e) { localConsole.log(e); };
  		}
  
  		Promise.onPotentiallyUnhandledRejection = function(rejection) {
  			enqueue(report, rejection);
  		};
  
  		Promise.onPotentiallyUnhandledRejectionHandled = function(rejection) {
  			enqueue(unreport, rejection);
  		};
  
  		Promise.onFatalRejection = function(rejection) {
  			enqueue(throwit, rejection.value);
  		};
  
  		var tasks = [];
  		var reported = [];
  		var running = null;
  
  		function report(r) {
  			if(!r.handled) {
  				reported.push(r);
  				logError('Potentially unhandled rejection [' + r.id + '] ' + format.formatError(r.value));
  			}
  		}
  
  		function unreport(r) {
  			var i = reported.indexOf(r);
  			if(i >= 0) {
  				reported.splice(i, 1);
  				logInfo('Handled previous rejection [' + r.id + '] ' + format.formatObject(r.value));
  			}
  		}
  
  		function enqueue(f, x) {
  			tasks.push(f, x);
  			if(running === null) {
  				running = setTimer(flush, 0);
  			}
  		}
  
  		function flush() {
  			running = null;
  			while(tasks.length > 0) {
  				tasks.shift()(tasks.shift());
  			}
  		}
  
  		return Promise;
  	};
  
  	function throwit(e) {
  		throw e;
  	}
  
  	function noop() {}
  
  });
  }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
  
  },{"../env":5,"../format":6}],5:[function(require,module,exports){
  /** @license MIT License (c) copyright 2010-2014 original author or authors */
  /** @author Brian Cavalier */
  /** @author John Hann */
  
  /*global process,document,setTimeout,clearTimeout,MutationObserver,WebKitMutationObserver*/
  (function(define) { 'use strict';
  define(function(require) {
  	/*jshint maxcomplexity:6*/
  
  	// Sniff "best" async scheduling option
  	// Prefer process.nextTick or MutationObserver, then check for
  	// setTimeout, and finally vertx, since its the only env that doesn't
  	// have setTimeout
  
  	var MutationObs;
  	var capturedSetTimeout = typeof setTimeout !== 'undefined' && setTimeout;
  
  	// Default env
  	var setTimer = function(f, ms) { return setTimeout(f, ms); };
  	var clearTimer = function(t) { return clearTimeout(t); };
  	var asap = function (f) { return capturedSetTimeout(f, 0); };
  
  	// Detect specific env
  	if (isNode()) { // Node
  		asap = function (f) { return process.nextTick(f); };
  
  	} else if (MutationObs = hasMutationObserver()) { // Modern browser
  		asap = initMutationObserver(MutationObs);
  
  	} else if (!capturedSetTimeout) { // vert.x
  		var vertxRequire = require;
  		var vertx = vertxRequire('vertx');
  		setTimer = function (f, ms) { return vertx.setTimer(ms, f); };
  		clearTimer = vertx.cancelTimer;
  		asap = vertx.runOnLoop || vertx.runOnContext;
  	}
  
  	return {
  		setTimer: setTimer,
  		clearTimer: clearTimer,
  		asap: asap
  	};
  
  	function isNode () {
  		return typeof process !== 'undefined' && process !== null &&
  			typeof process.nextTick === 'function';
  	}
  
  	function hasMutationObserver () {
  		return (typeof MutationObserver === 'function' && MutationObserver) ||
  			(typeof WebKitMutationObserver === 'function' && WebKitMutationObserver);
  	}
  
  	function initMutationObserver(MutationObserver) {
  		var scheduled;
  		var node = document.createTextNode('');
  		var o = new MutationObserver(run);
  		o.observe(node, { characterData: true });
  
  		function run() {
  			var f = scheduled;
  			scheduled = void 0;
  			f();
  		}
  
  		var i = 0;
  		return function (f) {
  			scheduled = f;
  			node.data = (i ^= 1);
  		};
  	}
  });
  }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
  
  },{}],6:[function(require,module,exports){
  /** @license MIT License (c) copyright 2010-2014 original author or authors */
  /** @author Brian Cavalier */
  /** @author John Hann */
  
  (function(define) { 'use strict';
  define(function() {
  
  	return {
  		formatError: formatError,
  		formatObject: formatObject,
  		tryStringify: tryStringify
  	};
  
  	/**
  	 * Format an error into a string.  If e is an Error and has a stack property,
  	 * it's returned.  Otherwise, e is formatted using formatObject, with a
  	 * warning added about e not being a proper Error.
  	 * @param {*} e
  	 * @returns {String} formatted string, suitable for output to developers
  	 */
  	function formatError(e) {
  		var s = typeof e === 'object' && e !== null && e.stack ? e.stack : formatObject(e);
  		return e instanceof Error ? s : s + ' (WARNING: non-Error used)';
  	}
  
  	/**
  	 * Format an object, detecting "plain" objects and running them through
  	 * JSON.stringify if possible.
  	 * @param {Object} o
  	 * @returns {string}
  	 */
  	function formatObject(o) {
  		var s = String(o);
  		if(s === '[object Object]' && typeof JSON !== 'undefined') {
  			s = tryStringify(o, s);
  		}
  		return s;
  	}
  
  	/**
  	 * Try to return the result of JSON.stringify(x).  If that fails, return
  	 * defaultValue
  	 * @param {*} x
  	 * @param {*} defaultValue
  	 * @returns {String|*} JSON.stringify(x) or defaultValue
  	 */
  	function tryStringify(x, defaultValue) {
  		try {
  			return JSON.stringify(x);
  		} catch(e) {
  			return defaultValue;
  		}
  	}
  
  });
  }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
  
  },{}],7:[function(require,module,exports){
  /** @license MIT License (c) copyright 2010-2014 original author or authors */
  /** @author Brian Cavalier */
  /** @author John Hann */
  
  (function(define) { 'use strict';
  define(function() {
  
  	return function makePromise(environment) {
  
  		var tasks = environment.scheduler;
  		var emitRejection = initEmitRejection();
  
  		var objectCreate = Object.create ||
  			function(proto) {
  				function Child() {}
  				Child.prototype = proto;
  				return new Child();
  			};
  
  		/**
  		 * Create a promise whose fate is determined by resolver
  		 * @constructor
  		 * @returns {Promise} promise
  		 * @name Promise
  		 */
  		function Promise(resolver, handler) {
  			this._handler = resolver === Handler ? handler : init(resolver);
  		}
  
  		/**
  		 * Run the supplied resolver
  		 * @param resolver
  		 * @returns {Pending}
  		 */
  		function init(resolver) {
  			var handler = new Pending();
  
  			try {
  				resolver(promiseResolve, promiseReject, promiseNotify);
  			} catch (e) {
  				promiseReject(e);
  			}
  
  			return handler;
  
  			/**
  			 * Transition from pre-resolution state to post-resolution state, notifying
  			 * all listeners of the ultimate fulfillment or rejection
  			 * @param {*} x resolution value
  			 */
  			function promiseResolve (x) {
  				handler.resolve(x);
  			}
  			/**
  			 * Reject this promise with reason, which will be used verbatim
  			 * @param {Error|*} reason rejection reason, strongly suggested
  			 *   to be an Error type
  			 */
  			function promiseReject (reason) {
  				handler.reject(reason);
  			}
  
  			/**
  			 * @deprecated
  			 * Issue a progress event, notifying all progress listeners
  			 * @param {*} x progress event payload to pass to all listeners
  			 */
  			function promiseNotify (x) {
  				handler.notify(x);
  			}
  		}
  
  		// Creation
  
  		Promise.resolve = resolve;
  		Promise.reject = reject;
  		Promise.never = never;
  
  		Promise._defer = defer;
  		Promise._handler = getHandler;
  
  		/**
  		 * Returns a trusted promise. If x is already a trusted promise, it is
  		 * returned, otherwise returns a new trusted Promise which follows x.
  		 * @param  {*} x
  		 * @return {Promise} promise
  		 */
  		function resolve(x) {
  			return isPromise(x) ? x
  				: new Promise(Handler, new Async(getHandler(x)));
  		}
  
  		/**
  		 * Return a reject promise with x as its reason (x is used verbatim)
  		 * @param {*} x
  		 * @returns {Promise} rejected promise
  		 */
  		function reject(x) {
  			return new Promise(Handler, new Async(new Rejected(x)));
  		}
  
  		/**
  		 * Return a promise that remains pending forever
  		 * @returns {Promise} forever-pending promise.
  		 */
  		function never() {
  			return foreverPendingPromise; // Should be frozen
  		}
  
  		/**
  		 * Creates an internal {promise, resolver} pair
  		 * @private
  		 * @returns {Promise}
  		 */
  		function defer() {
  			return new Promise(Handler, new Pending());
  		}
  
  		// Transformation and flow control
  
  		/**
  		 * Transform this promise's fulfillment value, returning a new Promise
  		 * for the transformed result.  If the promise cannot be fulfilled, onRejected
  		 * is called with the reason.  onProgress *may* be called with updates toward
  		 * this promise's fulfillment.
  		 * @param {function=} onFulfilled fulfillment handler
  		 * @param {function=} onRejected rejection handler
  		 * @param {function=} onProgress @deprecated progress handler
  		 * @return {Promise} new promise
  		 */
  		Promise.prototype.then = function(onFulfilled, onRejected, onProgress) {
  			var parent = this._handler;
  			var state = parent.join().state();
  
  			if ((typeof onFulfilled !== 'function' && state > 0) ||
  				(typeof onRejected !== 'function' && state < 0)) {
  				// Short circuit: value will not change, simply share handler
  				return new this.constructor(Handler, parent);
  			}
  
  			var p = this._beget();
  			var child = p._handler;
  
  			parent.chain(child, parent.receiver, onFulfilled, onRejected, onProgress);
  
  			return p;
  		};
  
  		/**
  		 * If this promise cannot be fulfilled due to an error, call onRejected to
  		 * handle the error. Shortcut for .then(undefined, onRejected)
  		 * @param {function?} onRejected
  		 * @return {Promise}
  		 */
  		Promise.prototype['catch'] = function(onRejected) {
  			return this.then(void 0, onRejected);
  		};
  
  		/**
  		 * Creates a new, pending promise of the same type as this promise
  		 * @private
  		 * @returns {Promise}
  		 */
  		Promise.prototype._beget = function() {
  			return begetFrom(this._handler, this.constructor);
  		};
  
  		function begetFrom(parent, Promise) {
  			var child = new Pending(parent.receiver, parent.join().context);
  			return new Promise(Handler, child);
  		}
  
  		// Array combinators
  
  		Promise.all = all;
  		Promise.race = race;
  		Promise._traverse = traverse;
  
  		/**
  		 * Return a promise that will fulfill when all promises in the
  		 * input array have fulfilled, or will reject when one of the
  		 * promises rejects.
  		 * @param {array} promises array of promises
  		 * @returns {Promise} promise for array of fulfillment values
  		 */
  		function all(promises) {
  			return traverseWith(snd, null, promises);
  		}
  
  		/**
  		 * Array<Promise<X>> -> Promise<Array<f(X)>>
  		 * @private
  		 * @param {function} f function to apply to each promise's value
  		 * @param {Array} promises array of promises
  		 * @returns {Promise} promise for transformed values
  		 */
  		function traverse(f, promises) {
  			return traverseWith(tryCatch2, f, promises);
  		}
  
  		function traverseWith(tryMap, f, promises) {
  			var handler = typeof f === 'function' ? mapAt : settleAt;
  
  			var resolver = new Pending();
  			var pending = promises.length >>> 0;
  			var results = new Array(pending);
  
  			for (var i = 0, x; i < promises.length && !resolver.resolved; ++i) {
  				x = promises[i];
  
  				if (x === void 0 && !(i in promises)) {
  					--pending;
  					continue;
  				}
  
  				traverseAt(promises, handler, i, x, resolver);
  			}
  
  			if(pending === 0) {
  				resolver.become(new Fulfilled(results));
  			}
  
  			return new Promise(Handler, resolver);
  
  			function mapAt(i, x, resolver) {
  				if(!resolver.resolved) {
  					traverseAt(promises, settleAt, i, tryMap(f, x, i), resolver);
  				}
  			}
  
  			function settleAt(i, x, resolver) {
  				results[i] = x;
  				if(--pending === 0) {
  					resolver.become(new Fulfilled(results));
  				}
  			}
  		}
  
  		function traverseAt(promises, handler, i, x, resolver) {
  			if (maybeThenable(x)) {
  				var h = getHandlerMaybeThenable(x);
  				var s = h.state();
  
  				if (s === 0) {
  					h.fold(handler, i, void 0, resolver);
  				} else if (s > 0) {
  					handler(i, h.value, resolver);
  				} else {
  					resolver.become(h);
  					visitRemaining(promises, i+1, h);
  				}
  			} else {
  				handler(i, x, resolver);
  			}
  		}
  
  		Promise._visitRemaining = visitRemaining;
  		function visitRemaining(promises, start, handler) {
  			for(var i=start; i<promises.length; ++i) {
  				markAsHandled(getHandler(promises[i]), handler);
  			}
  		}
  
  		function markAsHandled(h, handler) {
  			if(h === handler) {
  				return;
  			}
  
  			var s = h.state();
  			if(s === 0) {
  				h.visit(h, void 0, h._unreport);
  			} else if(s < 0) {
  				h._unreport();
  			}
  		}
  
  		/**
  		 * Fulfill-reject competitive race. Return a promise that will settle
  		 * to the same state as the earliest input promise to settle.
  		 *
  		 * WARNING: The ES6 Promise spec requires that race()ing an empty array
  		 * must return a promise that is pending forever.  This implementation
  		 * returns a singleton forever-pending promise, the same singleton that is
  		 * returned by Promise.never(), thus can be checked with ===
  		 *
  		 * @param {array} promises array of promises to race
  		 * @returns {Promise} if input is non-empty, a promise that will settle
  		 * to the same outcome as the earliest input promise to settle. if empty
  		 * is empty, returns a promise that will never settle.
  		 */
  		function race(promises) {
  			if(typeof promises !== 'object' || promises === null) {
  				return reject(new TypeError('non-iterable passed to race()'));
  			}
  
  			// Sigh, race([]) is untestable unless we return *something*
  			// that is recognizable without calling .then() on it.
  			return promises.length === 0 ? never()
  				 : promises.length === 1 ? resolve(promises[0])
  				 : runRace(promises);
  		}
  
  		function runRace(promises) {
  			var resolver = new Pending();
  			var i, x, h;
  			for(i=0; i<promises.length; ++i) {
  				x = promises[i];
  				if (x === void 0 && !(i in promises)) {
  					continue;
  				}
  
  				h = getHandler(x);
  				if(h.state() !== 0) {
  					resolver.become(h);
  					visitRemaining(promises, i+1, h);
  					break;
  				} else {
  					h.visit(resolver, resolver.resolve, resolver.reject);
  				}
  			}
  			return new Promise(Handler, resolver);
  		}
  
  		// Promise internals
  		// Below this, everything is @private
  
  		/**
  		 * Get an appropriate handler for x, without checking for cycles
  		 * @param {*} x
  		 * @returns {object} handler
  		 */
  		function getHandler(x) {
  			if(isPromise(x)) {
  				return x._handler.join();
  			}
  			return maybeThenable(x) ? getHandlerUntrusted(x) : new Fulfilled(x);
  		}
  
  		/**
  		 * Get a handler for thenable x.
  		 * NOTE: You must only call this if maybeThenable(x) == true
  		 * @param {object|function|Promise} x
  		 * @returns {object} handler
  		 */
  		function getHandlerMaybeThenable(x) {
  			return isPromise(x) ? x._handler.join() : getHandlerUntrusted(x);
  		}
  
  		/**
  		 * Get a handler for potentially untrusted thenable x
  		 * @param {*} x
  		 * @returns {object} handler
  		 */
  		function getHandlerUntrusted(x) {
  			try {
  				var untrustedThen = x.then;
  				return typeof untrustedThen === 'function'
  					? new Thenable(untrustedThen, x)
  					: new Fulfilled(x);
  			} catch(e) {
  				return new Rejected(e);
  			}
  		}
  
  		/**
  		 * Handler for a promise that is pending forever
  		 * @constructor
  		 */
  		function Handler() {}
  
  		Handler.prototype.when
  			= Handler.prototype.become
  			= Handler.prototype.notify // deprecated
  			= Handler.prototype.fail
  			= Handler.prototype._unreport
  			= Handler.prototype._report
  			= noop;
  
  		Handler.prototype._state = 0;
  
  		Handler.prototype.state = function() {
  			return this._state;
  		};
  
  		/**
  		 * Recursively collapse handler chain to find the handler
  		 * nearest to the fully resolved value.
  		 * @returns {object} handler nearest the fully resolved value
  		 */
  		Handler.prototype.join = function() {
  			var h = this;
  			while(h.handler !== void 0) {
  				h = h.handler;
  			}
  			return h;
  		};
  
  		Handler.prototype.chain = function(to, receiver, fulfilled, rejected, progress) {
  			this.when({
  				resolver: to,
  				receiver: receiver,
  				fulfilled: fulfilled,
  				rejected: rejected,
  				progress: progress
  			});
  		};
  
  		Handler.prototype.visit = function(receiver, fulfilled, rejected, progress) {
  			this.chain(failIfRejected, receiver, fulfilled, rejected, progress);
  		};
  
  		Handler.prototype.fold = function(f, z, c, to) {
  			this.when(new Fold(f, z, c, to));
  		};
  
  		/**
  		 * Handler that invokes fail() on any handler it becomes
  		 * @constructor
  		 */
  		function FailIfRejected() {}
  
  		inherit(Handler, FailIfRejected);
  
  		FailIfRejected.prototype.become = function(h) {
  			h.fail();
  		};
  
  		var failIfRejected = new FailIfRejected();
  
  		/**
  		 * Handler that manages a queue of consumers waiting on a pending promise
  		 * @constructor
  		 */
  		function Pending(receiver, inheritedContext) {
  			Promise.createContext(this, inheritedContext);
  
  			this.consumers = void 0;
  			this.receiver = receiver;
  			this.handler = void 0;
  			this.resolved = false;
  		}
  
  		inherit(Handler, Pending);
  
  		Pending.prototype._state = 0;
  
  		Pending.prototype.resolve = function(x) {
  			this.become(getHandler(x));
  		};
  
  		Pending.prototype.reject = function(x) {
  			if(this.resolved) {
  				return;
  			}
  
  			this.become(new Rejected(x));
  		};
  
  		Pending.prototype.join = function() {
  			if (!this.resolved) {
  				return this;
  			}
  
  			var h = this;
  
  			while (h.handler !== void 0) {
  				h = h.handler;
  				if (h === this) {
  					return this.handler = cycle();
  				}
  			}
  
  			return h;
  		};
  
  		Pending.prototype.run = function() {
  			var q = this.consumers;
  			var handler = this.handler;
  			this.handler = this.handler.join();
  			this.consumers = void 0;
  
  			for (var i = 0; i < q.length; ++i) {
  				handler.when(q[i]);
  			}
  		};
  
  		Pending.prototype.become = function(handler) {
  			if(this.resolved) {
  				return;
  			}
  
  			this.resolved = true;
  			this.handler = handler;
  			if(this.consumers !== void 0) {
  				tasks.enqueue(this);
  			}
  
  			if(this.context !== void 0) {
  				handler._report(this.context);
  			}
  		};
  
  		Pending.prototype.when = function(continuation) {
  			if(this.resolved) {
  				tasks.enqueue(new ContinuationTask(continuation, this.handler));
  			} else {
  				if(this.consumers === void 0) {
  					this.consumers = [continuation];
  				} else {
  					this.consumers.push(continuation);
  				}
  			}
  		};
  
  		/**
  		 * @deprecated
  		 */
  		Pending.prototype.notify = function(x) {
  			if(!this.resolved) {
  				tasks.enqueue(new ProgressTask(x, this));
  			}
  		};
  
  		Pending.prototype.fail = function(context) {
  			var c = typeof context === 'undefined' ? this.context : context;
  			this.resolved && this.handler.join().fail(c);
  		};
  
  		Pending.prototype._report = function(context) {
  			this.resolved && this.handler.join()._report(context);
  		};
  
  		Pending.prototype._unreport = function() {
  			this.resolved && this.handler.join()._unreport();
  		};
  
  		/**
  		 * Wrap another handler and force it into a future stack
  		 * @param {object} handler
  		 * @constructor
  		 */
  		function Async(handler) {
  			this.handler = handler;
  		}
  
  		inherit(Handler, Async);
  
  		Async.prototype.when = function(continuation) {
  			tasks.enqueue(new ContinuationTask(continuation, this));
  		};
  
  		Async.prototype._report = function(context) {
  			this.join()._report(context);
  		};
  
  		Async.prototype._unreport = function() {
  			this.join()._unreport();
  		};
  
  		/**
  		 * Handler that wraps an untrusted thenable and assimilates it in a future stack
  		 * @param {function} then
  		 * @param {{then: function}} thenable
  		 * @constructor
  		 */
  		function Thenable(then, thenable) {
  			Pending.call(this);
  			tasks.enqueue(new AssimilateTask(then, thenable, this));
  		}
  
  		inherit(Pending, Thenable);
  
  		/**
  		 * Handler for a fulfilled promise
  		 * @param {*} x fulfillment value
  		 * @constructor
  		 */
  		function Fulfilled(x) {
  			Promise.createContext(this);
  			this.value = x;
  		}
  
  		inherit(Handler, Fulfilled);
  
  		Fulfilled.prototype._state = 1;
  
  		Fulfilled.prototype.fold = function(f, z, c, to) {
  			runContinuation3(f, z, this, c, to);
  		};
  
  		Fulfilled.prototype.when = function(cont) {
  			runContinuation1(cont.fulfilled, this, cont.receiver, cont.resolver);
  		};
  
  		var errorId = 0;
  
  		/**
  		 * Handler for a rejected promise
  		 * @param {*} x rejection reason
  		 * @constructor
  		 */
  		function Rejected(x) {
  			Promise.createContext(this);
  
  			this.id = ++errorId;
  			this.value = x;
  			this.handled = false;
  			this.reported = false;
  
  			this._report();
  		}
  
  		inherit(Handler, Rejected);
  
  		Rejected.prototype._state = -1;
  
  		Rejected.prototype.fold = function(f, z, c, to) {
  			to.become(this);
  		};
  
  		Rejected.prototype.when = function(cont) {
  			if(typeof cont.rejected === 'function') {
  				this._unreport();
  			}
  			runContinuation1(cont.rejected, this, cont.receiver, cont.resolver);
  		};
  
  		Rejected.prototype._report = function(context) {
  			tasks.afterQueue(new ReportTask(this, context));
  		};
  
  		Rejected.prototype._unreport = function() {
  			if(this.handled) {
  				return;
  			}
  			this.handled = true;
  			tasks.afterQueue(new UnreportTask(this));
  		};
  
  		Rejected.prototype.fail = function(context) {
  			this.reported = true;
  			emitRejection('unhandledRejection', this);
  			Promise.onFatalRejection(this, context === void 0 ? this.context : context);
  		};
  
  		function ReportTask(rejection, context) {
  			this.rejection = rejection;
  			this.context = context;
  		}
  
  		ReportTask.prototype.run = function() {
  			if(!this.rejection.handled && !this.rejection.reported) {
  				this.rejection.reported = true;
  				emitRejection('unhandledRejection', this.rejection) ||
  					Promise.onPotentiallyUnhandledRejection(this.rejection, this.context);
  			}
  		};
  
  		function UnreportTask(rejection) {
  			this.rejection = rejection;
  		}
  
  		UnreportTask.prototype.run = function() {
  			if(this.rejection.reported) {
  				emitRejection('rejectionHandled', this.rejection) ||
  					Promise.onPotentiallyUnhandledRejectionHandled(this.rejection);
  			}
  		};
  
  		// Unhandled rejection hooks
  		// By default, everything is a noop
  
  		Promise.createContext
  			= Promise.enterContext
  			= Promise.exitContext
  			= Promise.onPotentiallyUnhandledRejection
  			= Promise.onPotentiallyUnhandledRejectionHandled
  			= Promise.onFatalRejection
  			= noop;
  
  		// Errors and singletons
  
  		var foreverPendingHandler = new Handler();
  		var foreverPendingPromise = new Promise(Handler, foreverPendingHandler);
  
  		function cycle() {
  			return new Rejected(new TypeError('Promise cycle'));
  		}
  
  		// Task runners
  
  		/**
  		 * Run a single consumer
  		 * @constructor
  		 */
  		function ContinuationTask(continuation, handler) {
  			this.continuation = continuation;
  			this.handler = handler;
  		}
  
  		ContinuationTask.prototype.run = function() {
  			this.handler.join().when(this.continuation);
  		};
  
  		/**
  		 * Run a queue of progress handlers
  		 * @constructor
  		 */
  		function ProgressTask(value, handler) {
  			this.handler = handler;
  			this.value = value;
  		}
  
  		ProgressTask.prototype.run = function() {
  			var q = this.handler.consumers;
  			if(q === void 0) {
  				return;
  			}
  
  			for (var c, i = 0; i < q.length; ++i) {
  				c = q[i];
  				runNotify(c.progress, this.value, this.handler, c.receiver, c.resolver);
  			}
  		};
  
  		/**
  		 * Assimilate a thenable, sending it's value to resolver
  		 * @param {function} then
  		 * @param {object|function} thenable
  		 * @param {object} resolver
  		 * @constructor
  		 */
  		function AssimilateTask(then, thenable, resolver) {
  			this._then = then;
  			this.thenable = thenable;
  			this.resolver = resolver;
  		}
  
  		AssimilateTask.prototype.run = function() {
  			var h = this.resolver;
  			tryAssimilate(this._then, this.thenable, _resolve, _reject, _notify);
  
  			function _resolve(x) { h.resolve(x); }
  			function _reject(x)  { h.reject(x); }
  			function _notify(x)  { h.notify(x); }
  		};
  
  		function tryAssimilate(then, thenable, resolve, reject, notify) {
  			try {
  				then.call(thenable, resolve, reject, notify);
  			} catch (e) {
  				reject(e);
  			}
  		}
  
  		/**
  		 * Fold a handler value with z
  		 * @constructor
  		 */
  		function Fold(f, z, c, to) {
  			this.f = f; this.z = z; this.c = c; this.to = to;
  			this.resolver = failIfRejected;
  			this.receiver = this;
  		}
  
  		Fold.prototype.fulfilled = function(x) {
  			this.f.call(this.c, this.z, x, this.to);
  		};
  
  		Fold.prototype.rejected = function(x) {
  			this.to.reject(x);
  		};
  
  		Fold.prototype.progress = function(x) {
  			this.to.notify(x);
  		};
  
  		// Other helpers
  
  		/**
  		 * @param {*} x
  		 * @returns {boolean} true iff x is a trusted Promise
  		 */
  		function isPromise(x) {
  			return x instanceof Promise;
  		}
  
  		/**
  		 * Test just enough to rule out primitives, in order to take faster
  		 * paths in some code
  		 * @param {*} x
  		 * @returns {boolean} false iff x is guaranteed *not* to be a thenable
  		 */
  		function maybeThenable(x) {
  			return (typeof x === 'object' || typeof x === 'function') && x !== null;
  		}
  
  		function runContinuation1(f, h, receiver, next) {
  			if(typeof f !== 'function') {
  				return next.become(h);
  			}
  
  			Promise.enterContext(h);
  			tryCatchReject(f, h.value, receiver, next);
  			Promise.exitContext();
  		}
  
  		function runContinuation3(f, x, h, receiver, next) {
  			if(typeof f !== 'function') {
  				return next.become(h);
  			}
  
  			Promise.enterContext(h);
  			tryCatchReject3(f, x, h.value, receiver, next);
  			Promise.exitContext();
  		}
  
  		/**
  		 * @deprecated
  		 */
  		function runNotify(f, x, h, receiver, next) {
  			if(typeof f !== 'function') {
  				return next.notify(x);
  			}
  
  			Promise.enterContext(h);
  			tryCatchReturn(f, x, receiver, next);
  			Promise.exitContext();
  		}
  
  		function tryCatch2(f, a, b) {
  			try {
  				return f(a, b);
  			} catch(e) {
  				return reject(e);
  			}
  		}
  
  		/**
  		 * Return f.call(thisArg, x), or if it throws return a rejected promise for
  		 * the thrown exception
  		 */
  		function tryCatchReject(f, x, thisArg, next) {
  			try {
  				next.become(getHandler(f.call(thisArg, x)));
  			} catch(e) {
  				next.become(new Rejected(e));
  			}
  		}
  
  		/**
  		 * Same as above, but includes the extra argument parameter.
  		 */
  		function tryCatchReject3(f, x, y, thisArg, next) {
  			try {
  				f.call(thisArg, x, y, next);
  			} catch(e) {
  				next.become(new Rejected(e));
  			}
  		}
  
  		/**
  		 * @deprecated
  		 * Return f.call(thisArg, x), or if it throws, *return* the exception
  		 */
  		function tryCatchReturn(f, x, thisArg, next) {
  			try {
  				next.notify(f.call(thisArg, x));
  			} catch(e) {
  				next.notify(e);
  			}
  		}
  
  		function inherit(Parent, Child) {
  			Child.prototype = objectCreate(Parent.prototype);
  			Child.prototype.constructor = Child;
  		}
  
  		function snd(x, y) {
  			return y;
  		}
  
  		function noop() {}
  
  		function initEmitRejection() {
  			/*global process, self, CustomEvent*/
  			if(typeof process !== 'undefined' && process !== null
  				&& typeof process.emit === 'function') {
  				// Returning falsy here means to call the default
  				// onPotentiallyUnhandledRejection API.  This is safe even in
  				// browserify since process.emit always returns falsy in browserify:
  				// https://github.com/defunctzombie/node-process/blob/master/browser.js#L40-L46
  				return function(type, rejection) {
  					return type === 'unhandledRejection'
  						? process.emit(type, rejection.value, rejection)
  						: process.emit(type, rejection);
  				};
  			} else if(typeof self !== 'undefined' && typeof CustomEvent === 'function') {
  				return (function(noop, self, CustomEvent) {
  					var hasCustomEvent = false;
  					try {
  						var ev = new CustomEvent('unhandledRejection');
  						hasCustomEvent = ev instanceof CustomEvent;
  					} catch (e) {}
  
  					return !hasCustomEvent ? noop : function(type, rejection) {
  						var ev = new CustomEvent(type, {
  							detail: {
  								reason: rejection.value,
  								key: rejection
  							},
  							bubbles: false,
  							cancelable: true
  						});
  
  						return !self.dispatchEvent(ev);
  					};
  				}(noop, self, CustomEvent));
  			}
  
  			return noop;
  		}
  
  		return Promise;
  	};
  });
  }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
  
  },{}]},{},[1])
  (1)
  });
  ;
  (function(__global) {
    
  $__Object$getPrototypeOf = Object.getPrototypeOf || function(obj) {
    return obj.__proto__;
  };
  
  var $__Object$defineProperty;
  (function () {
    try {
      if (!!Object.defineProperty({}, 'a', {})) {
        $__Object$defineProperty = Object.defineProperty;
      }
    } catch (e) {
      $__Object$defineProperty = function (obj, prop, opt) {
        try {
          obj[prop] = opt.value || opt.get.call(obj);
        }
        catch(e) {}
      }
    }
  }());
  
  $__Object$create = Object.create || function(o, props) {
    function F() {}
    F.prototype = o;
  
    if (typeof(props) === "object") {
      for (prop in props) {
        if (props.hasOwnProperty((prop))) {
          F[prop] = props[prop];
        }
      }
    }
    return new F();
  };
  
  /*
  *********************************************************************************************
  
    Dynamic Module Loader Polyfill
  
      - Implemented exactly to the former 2014-08-24 ES6 Specification Draft Rev 27, Section 15
        http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts#august_24_2014_draft_rev_27
  
      - Functions are commented with their spec numbers, with spec differences commented.
  
      - Spec bugs are commented in this code with links.
  
      - Abstract functions have been combined where possible, and their associated functions
        commented.
  
      - Realm implementation is entirely omitted.
  
  *********************************************************************************************
  */
  
  // Some Helpers
  
  // logs a linkset snapshot for debugging
  /* function snapshot(loader) {
    console.log('---Snapshot---');
    for (var i = 0; i < loader.loads.length; i++) {
      var load = loader.loads[i];
      var linkSetLog = '  ' + load.name + ' (' + load.status + '): ';
  
      for (var j = 0; j < load.linkSets.length; j++) {
        linkSetLog += '{' + logloads(load.linkSets[j].loads) + '} ';
      }
      console.log(linkSetLog);
    }
    console.log('');
  }
  function logloads(loads) {
    var log = '';
    for (var k = 0; k < loads.length; k++)
      log += loads[k].name + (k != loads.length - 1 ? ' ' : '');
    return log;
  } */
  
  
  /* function checkInvariants() {
    // see https://bugs.ecmascript.org/show_bug.cgi?id=2603#c1
  
    var loads = System._loader.loads;
    var linkSets = [];
  
    for (var i = 0; i < loads.length; i++) {
      var load = loads[i];
      console.assert(load.status == 'loading' || load.status == 'loaded', 'Each load is loading or loaded');
  
      for (var j = 0; j < load.linkSets.length; j++) {
        var linkSet = load.linkSets[j];
  
        for (var k = 0; k < linkSet.loads.length; k++)
          console.assert(loads.indexOf(linkSet.loads[k]) != -1, 'linkSet loads are a subset of loader loads');
  
        if (linkSets.indexOf(linkSet) == -1)
          linkSets.push(linkSet);
      }
    }
  
    for (var i = 0; i < loads.length; i++) {
      var load = loads[i];
      for (var j = 0; j < linkSets.length; j++) {
        var linkSet = linkSets[j];
  
        if (linkSet.loads.indexOf(load) != -1)
          console.assert(load.linkSets.indexOf(linkSet) != -1, 'linkSet contains load -> load contains linkSet');
  
        if (load.linkSets.indexOf(linkSet) != -1)
          console.assert(linkSet.loads.indexOf(load) != -1, 'load contains linkSet -> linkSet contains load');
      }
    }
  
    for (var i = 0; i < linkSets.length; i++) {
      var linkSet = linkSets[i];
      for (var j = 0; j < linkSet.loads.length; j++) {
        var load = linkSet.loads[j];
  
        for (var k = 0; k < load.dependencies.length; k++) {
          var depName = load.dependencies[k].value;
          var depLoad;
          for (var l = 0; l < loads.length; l++) {
            if (loads[l].name != depName)
              continue;
            depLoad = loads[l];
            break;
          }
  
          // loading records are allowed not to have their dependencies yet
          // if (load.status != 'loading')
          //  console.assert(depLoad, 'depLoad found');
  
          // console.assert(linkSet.loads.indexOf(depLoad) != -1, 'linkset contains all dependencies');
        }
      }
    }
  } */
  
  
  (function() {
    var Promise = __global.Promise || require('when/es6-shim/Promise');
    if (__global.console)
      console.assert = console.assert || function() {};
  
    // IE8 support
    var indexOf = Array.prototype.indexOf || function(item) {
      for (var i = 0, thisLen = this.length; i < thisLen; i++) {
        if (this[i] === item) {
          return i;
        }
      }
      return -1;
    };
    var defineProperty = $__Object$defineProperty;
  
    // 15.2.3 - Runtime Semantics: Loader State
  
    // 15.2.3.11
    function createLoaderLoad(object) {
      return {
        // modules is an object for ES5 implementation
        modules: {},
        loads: [],
        loaderObj: object
      };
    }
  
    // 15.2.3.2 Load Records and LoadRequest Objects
  
    // 15.2.3.2.1
    function createLoad(name) {
      return {
        status: 'loading',
        name: name,
        linkSets: [],
        dependencies: [],
        metadata: {}
      };
    }
  
    // 15.2.3.2.2 createLoadRequestObject, absorbed into calling functions
  
    // 15.2.4
  
    // 15.2.4.1
    function loadModule(loader, name, options) {
      return new Promise(asyncStartLoadPartwayThrough({
        step: options.address ? 'fetch' : 'locate',
        loader: loader,
        moduleName: name,
        // allow metadata for import https://bugs.ecmascript.org/show_bug.cgi?id=3091
        moduleMetadata: options && options.metadata || {},
        moduleSource: options.source,
        moduleAddress: options.address
      }));
    }
  
    // 15.2.4.2
    function requestLoad(loader, request, refererName, refererAddress) {
      // 15.2.4.2.1 CallNormalize
      return new Promise(function(resolve, reject) {
        resolve(loader.loaderObj.normalize(request, refererName, refererAddress));
      })
      // 15.2.4.2.2 GetOrCreateLoad
      .then(function(name) {
        var load;
        if (loader.modules[name]) {
          load = createLoad(name);
          load.status = 'linked';
          // https://bugs.ecmascript.org/show_bug.cgi?id=2795
          load.module = loader.modules[name];
          return load;
        }
  
        for (var i = 0, l = loader.loads.length; i < l; i++) {
          load = loader.loads[i];
          if (load.name != name)
            continue;
          console.assert(load.status == 'loading' || load.status == 'loaded', 'loading or loaded');
          return load;
        }
  
        load = createLoad(name);
        loader.loads.push(load);
  
        proceedToLocate(loader, load);
  
        return load;
      });
    }
  
    // 15.2.4.3
    function proceedToLocate(loader, load) {
      proceedToFetch(loader, load,
        Promise.resolve()
        // 15.2.4.3.1 CallLocate
        .then(function() {
          return loader.loaderObj.locate({ name: load.name, metadata: load.metadata });
        })
      );
    }
  
    // 15.2.4.4
    function proceedToFetch(loader, load, p) {
      proceedToTranslate(loader, load,
        p
        // 15.2.4.4.1 CallFetch
        .then(function(address) {
          // adjusted, see https://bugs.ecmascript.org/show_bug.cgi?id=2602
          if (load.status != 'loading')
            return;
          load.address = address;
  
          return loader.loaderObj.fetch({ name: load.name, metadata: load.metadata, address: address });
        })
      );
    }
  
    var anonCnt = 0;
  
    // 15.2.4.5
    function proceedToTranslate(loader, load, p) {
      p
      // 15.2.4.5.1 CallTranslate
      .then(function(source) {
        if (load.status != 'loading')
          return;
  
        return Promise.resolve(loader.loaderObj.translate({ name: load.name, metadata: load.metadata, address: load.address, source: source }))
  
        // 15.2.4.5.2 CallInstantiate
        .then(function(source) {
          if(load.status != 'loading') {
            return;
          }
          load.source = source;
          return loader.loaderObj.instantiate({ name: load.name, metadata: load.metadata, address: load.address, source: source });
        })
  
        // 15.2.4.5.3 InstantiateSucceeded
        .then(function(instantiateResult) {
          if(load.status != 'loading') {
            return;
          }
          if (instantiateResult === undefined) {
            load.address = load.address || '<Anonymous Module ' + ++anonCnt + '>';
  
            // instead of load.kind, use load.isDeclarative
            load.isDeclarative = true;
            return loader.loaderObj.transpile(load)
            .then(function(transpiled) {
              // Hijack System.register to set declare function
              var curSystem = __global.System;
              var curRegister = curSystem.register;
              curSystem.register = function(name, deps, declare) {
                if (typeof name != 'string') {
                  declare = deps;
                  deps = name;
                }
                // store the registered declaration as load.declare
                // store the deps as load.deps
                load.declare = declare;
                load.depsList = deps;
              }            
              __eval(transpiled, __global, load);
              curSystem.register = curRegister;
            });
          }
          else if (typeof instantiateResult == 'object') {
            load.depsList = instantiateResult.deps || [];
            load.execute = instantiateResult.execute;
            load.isDeclarative = false;
          }
          else
            throw TypeError('Invalid instantiate return value');
        })
        // 15.2.4.6 ProcessLoadDependencies
        .then(function() {
          if(load.status != 'loading') {
            return;
          }
          load.dependencies = [];
          var depsList = load.depsList;
  
          var loadPromises = [];
          for (var i = 0, l = depsList.length; i < l; i++) (function(request, index) {
            loadPromises.push(
              requestLoad(loader, request, load.name, load.address)
  
              // 15.2.4.6.1 AddDependencyLoad (load is parentLoad)
              .then(function(depLoad) {
  
                // adjusted from spec to maintain dependency order
                // this is due to the System.register internal implementation needs
                load.dependencies[index] = {
                  key: request,
                  value: depLoad.name
                };
  
                if (depLoad.status != 'linked') {
                  var linkSets = load.linkSets.concat([]);
                  for (var i = 0, l = linkSets.length; i < l; i++)
                    addLoadToLinkSet(linkSets[i], depLoad);
                }
  
                // console.log('AddDependencyLoad ' + depLoad.name + ' for ' + load.name);
                // snapshot(loader);
              })
            );
          })(depsList[i], i);
  
          return Promise.all(loadPromises);
        })
  
        // 15.2.4.6.2 LoadSucceeded
        .then(function() {
          // console.log('LoadSucceeded ' + load.name);
          // snapshot(loader);
          if(load.status != 'loading') {
            return;
          }
  
          console.assert(load.status == 'loading', 'is loading');
  
          load.status = 'loaded';
  
          var linkSets = load.linkSets.concat([]);
          for (var i = 0, l = linkSets.length; i < l; i++)
            updateLinkSetOnLoad(linkSets[i], load);
        });
      })
      // 15.2.4.5.4 LoadFailed
      ['catch'](function(exc) {
        load.status = 'failed';
        load.exception = exc;
  
        var linkSets = load.linkSets.concat([]);
        for (var i = 0, l = linkSets.length; i < l; i++) {
          linkSetFailed(linkSets[i], load, exc);
        }
  
        console.assert(load.linkSets.length == 0, 'linkSets not removed');
      });
    }
  
    // 15.2.4.7 PromiseOfStartLoadPartwayThrough absorbed into calling functions
  
    // 15.2.4.7.1
    function asyncStartLoadPartwayThrough(stepState) {
      return function(resolve, reject) {
        var loader = stepState.loader;
        var name = stepState.moduleName;
        var step = stepState.step;
  
        if (loader.modules[name])
          throw new TypeError('"' + name + '" already exists in the module table');
  
        // adjusted to pick up existing loads
        var existingLoad;
        for (var i = 0, l = loader.loads.length; i < l; i++) {
          if (loader.loads[i].name == name) {
            existingLoad = loader.loads[i];
  
            if(step == 'translate' && !existingLoad.source) {
              existingLoad.address = stepState.moduleAddress;
              proceedToTranslate(loader, existingLoad, Promise.resolve(stepState.moduleSource));
            }
  
            return existingLoad.linkSets[0].done.then(function() {
              resolve(existingLoad);
            });
          }
        }
  
        var load = createLoad(name);
  
        load.metadata = stepState.moduleMetadata;
  
        var linkSet = createLinkSet(loader, load);
  
        loader.loads.push(load);
  
        resolve(linkSet.done);
  
        if (step == 'locate')
          proceedToLocate(loader, load);
  
        else if (step == 'fetch')
          proceedToFetch(loader, load, Promise.resolve(stepState.moduleAddress));
  
        else {
          console.assert(step == 'translate', 'translate step');
          load.address = stepState.moduleAddress;
          proceedToTranslate(loader, load, Promise.resolve(stepState.moduleSource));
        }
      }
    }
  
    // Declarative linking functions run through alternative implementation:
    // 15.2.5.1.1 CreateModuleLinkageRecord not implemented
    // 15.2.5.1.2 LookupExport not implemented
    // 15.2.5.1.3 LookupModuleDependency not implemented
  
    // 15.2.5.2.1
    function createLinkSet(loader, startingLoad) {
      var linkSet = {
        loader: loader,
        loads: [],
        startingLoad: startingLoad, // added see spec bug https://bugs.ecmascript.org/show_bug.cgi?id=2995
        loadingCount: 0
      };
      linkSet.done = new Promise(function(resolve, reject) {
        linkSet.resolve = resolve;
        linkSet.reject = reject;
      });
      addLoadToLinkSet(linkSet, startingLoad);
      return linkSet;
    }
    // 15.2.5.2.2
    function addLoadToLinkSet(linkSet, load) {
      console.assert(load.status == 'loading' || load.status == 'loaded', 'loading or loaded on link set');
  
      for (var i = 0, l = linkSet.loads.length; i < l; i++)
        if (linkSet.loads[i] == load)
          return;
  
      linkSet.loads.push(load);
      load.linkSets.push(linkSet);
  
      // adjustment, see https://bugs.ecmascript.org/show_bug.cgi?id=2603
      if (load.status != 'loaded') {
        linkSet.loadingCount++;
      }
  
      var loader = linkSet.loader;
  
      for (var i = 0, l = load.dependencies.length; i < l; i++) {
        var name = load.dependencies[i].value;
  
        if (loader.modules[name])
          continue;
  
        for (var j = 0, d = loader.loads.length; j < d; j++) {
          if (loader.loads[j].name != name)
            continue;
  
          addLoadToLinkSet(linkSet, loader.loads[j]);
          break;
        }
      }
      // console.log('add to linkset ' + load.name);
      // snapshot(linkSet.loader);
    }
  
    // linking errors can be generic or load-specific
    // this is necessary for debugging info
    function doLink(linkSet) {
      var error = false;
      try {
        link(linkSet, function(load, exc) {
          linkSetFailed(linkSet, load, exc);
          error = true;
        });
      }
      catch(e) {
        linkSetFailed(linkSet, null, e);
        error = true;
      }
      return error;
    }
  
    // 15.2.5.2.3
    function updateLinkSetOnLoad(linkSet, load) {
      // console.log('update linkset on load ' + load.name);
      // snapshot(linkSet.loader);
  
      console.assert(load.status == 'loaded' || load.status == 'linked', 'loaded or linked');
  
      linkSet.loadingCount--;
  
      if (linkSet.loadingCount > 0)
        return;
  
      // adjusted for spec bug https://bugs.ecmascript.org/show_bug.cgi?id=2995
      var startingLoad = linkSet.startingLoad;
  
      // non-executing link variation for loader tracing
      // on the server. Not in spec.
      /***/
      if (linkSet.loader.loaderObj.execute === false) {
        var loads = [].concat(linkSet.loads);
        for (var i = 0, l = loads.length; i < l; i++) {
          var load = loads[i];
          load.module = !load.isDeclarative ? {
            module: _newModule({})
          } : {
            name: load.name,
            module: _newModule({}),
            evaluated: true
          };
          load.status = 'linked';
          finishLoad(linkSet.loader, load);
        }
        return linkSet.resolve(startingLoad);
      }
      /***/
  
      var abrupt = doLink(linkSet);
  
      if (abrupt)
        return;
  
      console.assert(linkSet.loads.length == 0, 'loads cleared');
  
      linkSet.resolve(startingLoad);
    }
  
    // 15.2.5.2.4
    function linkSetFailed(linkSet, load, exc) {
      var loader = linkSet.loader;
  
      if (linkSet.loads[0].name != load.name)
        exc = addToError(exc, 'Error loading "' + load.name + '" from "' + linkSet.loads[0].name + '" at ' + (linkSet.loads[0].address || '<unknown>') + '\n');
  
      exc = addToError(exc, 'Error loading "' + load.name + '" at ' + (load.address || '<unknown>') + '\n');
  
      var loads = linkSet.loads.concat([]);
      for (var i = 0, l = loads.length; i < l; i++) {
        var load = loads[i];
  
        // store all failed load records
        loader.loaderObj.failed = loader.loaderObj.failed || [];
        if (indexOf.call(loader.loaderObj.failed, load) == -1)
          loader.loaderObj.failed.push(load);
  
        var linkIndex = indexOf.call(load.linkSets, linkSet);
        console.assert(linkIndex != -1, 'link not present');
        load.linkSets.splice(linkIndex, 1);
        if (load.linkSets.length == 0) {
          var globalLoadsIndex = indexOf.call(linkSet.loader.loads, load);
          if (globalLoadsIndex != -1)
            linkSet.loader.loads.splice(globalLoadsIndex, 1);
        }
      }
      linkSet.reject(exc);
    }
  
    // 15.2.5.2.5
    function finishLoad(loader, load) {
      // add to global trace if tracing
      if (loader.loaderObj.trace) {
        if (!loader.loaderObj.loads)
          loader.loaderObj.loads = {};
        var depMap = {};
        load.dependencies.forEach(function(dep) {
          depMap[dep.key] = dep.value;
        });
        loader.loaderObj.loads[load.name] = {
          name: load.name,
          deps: load.dependencies.map(function(dep){ return dep.key }),
          depMap: depMap,
          address: load.address,
          metadata: load.metadata,
          source: load.source,
          kind: load.isDeclarative ? 'declarative' : 'dynamic'
        };
      }
      // if not anonymous, add to the module table
      if (load.name) {
        console.assert(!loader.modules[load.name], 'load not in module table');
        loader.modules[load.name] = load.module;
      }
      var loadIndex = indexOf.call(loader.loads, load);
      if (loadIndex != -1)
        loader.loads.splice(loadIndex, 1);
      for (var i = 0, l = load.linkSets.length; i < l; i++) {
        loadIndex = indexOf.call(load.linkSets[i].loads, load);
        if (loadIndex != -1)
          load.linkSets[i].loads.splice(loadIndex, 1);
      }
      load.linkSets.splice(0, load.linkSets.length);
    }
  
    // 15.2.5.3 Module Linking Groups
  
    // 15.2.5.3.2 BuildLinkageGroups alternative implementation
    // Adjustments (also see https://bugs.ecmascript.org/show_bug.cgi?id=2755)
    // 1. groups is an already-interleaved array of group kinds
    // 2. load.groupIndex is set when this function runs
    // 3. load.groupIndex is the interleaved index ie 0 declarative, 1 dynamic, 2 declarative, ... (or starting with dynamic)
    function buildLinkageGroups(load, loads, groups) {
      groups[load.groupIndex] = groups[load.groupIndex] || [];
  
      // if the load already has a group index and its in its group, its already been done
      // this logic naturally handles cycles
      if (indexOf.call(groups[load.groupIndex], load) != -1)
        return;
  
      // now add it to the group to indicate its been seen
      groups[load.groupIndex].push(load);
  
      for (var i = 0, l = loads.length; i < l; i++) {
        var loadDep = loads[i];
  
        // dependencies not found are already linked
        for (var j = 0; j < load.dependencies.length; j++) {
          if (loadDep.name == load.dependencies[j].value) {
            // by definition all loads in linkset are loaded, not linked
            console.assert(loadDep.status == 'loaded', 'Load in linkSet not loaded!');
  
            // if it is a group transition, the index of the dependency has gone up
            // otherwise it is the same as the parent
            var loadDepGroupIndex = load.groupIndex + (loadDep.isDeclarative != load.isDeclarative);
  
            // the group index of an entry is always the maximum
            if (loadDep.groupIndex === undefined || loadDep.groupIndex < loadDepGroupIndex) {
  
              // if already in a group, remove from the old group
              if (loadDep.groupIndex !== undefined) {
                groups[loadDep.groupIndex].splice(indexOf.call(groups[loadDep.groupIndex], loadDep), 1);
  
                // if the old group is empty, then we have a mixed depndency cycle
                if (groups[loadDep.groupIndex].length == 0)
                  throw new TypeError("Mixed dependency cycle detected");
              }
  
              loadDep.groupIndex = loadDepGroupIndex;
            }
  
            buildLinkageGroups(loadDep, loads, groups);
          }
        }
      }
    }
  
    function doDynamicExecute(linkSet, load, linkError) {
      try {
        var module = load.execute();
      }
      catch(e) {
        linkError(load, e);
        return;
      }
      if (!module || !(module instanceof Module))
        linkError(load, new TypeError('Execution must define a Module instance'));
      else
        return module;
    }
  
    // 15.2.5.4
    function link(linkSet, linkError) {
  
      var loader = linkSet.loader;
  
      if (!linkSet.loads.length)
        return;
  
      // console.log('linking {' + logloads(linkSet.loads) + '}');
      // snapshot(loader);
  
      // 15.2.5.3.1 LinkageGroups alternative implementation
  
      // build all the groups
      // because the first load represents the top of the tree
      // for a given linkset, we can work down from there
      var groups = [];
      var startingLoad = linkSet.loads[0];
      startingLoad.groupIndex = 0;
      buildLinkageGroups(startingLoad, linkSet.loads, groups);
  
      // determine the kind of the bottom group
      var curGroupDeclarative = startingLoad.isDeclarative == groups.length % 2;
  
      // run through the groups from bottom to top
      for (var i = groups.length - 1; i >= 0; i--) {
        var group = groups[i];
        for (var j = 0; j < group.length; j++) {
          var load = group[j];
  
          // 15.2.5.5 LinkDeclarativeModules adjusted
          if (curGroupDeclarative) {
            linkDeclarativeModule(load, linkSet.loads, loader);
          }
          // 15.2.5.6 LinkDynamicModules adjusted
          else {
            var module = doDynamicExecute(linkSet, load, linkError);
            if (!module)
              return;
            load.module = {
              name: load.name,
              module: module
            };
            load.status = 'linked';
          }
          finishLoad(loader, load);
        }
  
        // alternative current kind for next loop
        curGroupDeclarative = !curGroupDeclarative;
      }
    }
  
  
    // custom module records for binding graph
    // store linking module records in a separate table
    function getOrCreateModuleRecord(name, loader) {
      var moduleRecords = loader.moduleRecords;
      return moduleRecords[name] || (moduleRecords[name] = {
        name: name,
        dependencies: [],
        module: new Module(), // start from an empty module and extend
        importers: []
      });
    }
  
    // custom declarative linking function
    function linkDeclarativeModule(load, loads, loader) {
      if (load.module)
        return;
  
      var module = load.module = getOrCreateModuleRecord(load.name, loader);
      var moduleObj = load.module.module;
  
      var registryEntry = load.declare.call(__global, function(name, value) {
        // NB This should be an Object.defineProperty, but that is very slow.
        //    By disaling this module write-protection we gain performance.
        //    It could be useful to allow an option to enable or disable this.
        module.locked = true;
        moduleObj[name] = value;
  
        for (var i = 0, l = module.importers.length; i < l; i++) {
          var importerModule = module.importers[i];
          if (!importerModule.locked) {
            var importerIndex = indexOf.call(importerModule.dependencies, module);
            importerModule.setters[importerIndex](moduleObj);
          }
        }
  
        module.locked = false;
        return value;
      });
  
      // setup our setters and execution function
      module.setters = registryEntry.setters;
      module.execute = registryEntry.execute;
  
      // now link all the module dependencies
      // amending the depMap as we go
      for (var i = 0, l = load.dependencies.length; i < l; i++) {
        var depName = load.dependencies[i].value;
        var depModule = loader.modules[depName];
  
        // if dependency not already in the module registry
        // then try and link it now
        if (!depModule) {
          // get the dependency load record
          for (var j = 0; j < loads.length; j++) {
            if (loads[j].name != depName)
              continue;
  
            // only link if already not already started linking (stops at circular / dynamic)
            if (!loads[j].module) {
              linkDeclarativeModule(loads[j], loads, loader);
              depModule = loads[j].module;
            }
            // if circular, create the module record
            else {
              depModule = getOrCreateModuleRecord(depName, loader);
            }
          }
        }
  
        // only declarative modules have dynamic bindings
        if (depModule.importers) {
          module.dependencies.push(depModule);
          depModule.importers.push(module);
        }
        else {
          // track dynamic records as null module records as already linked
          module.dependencies.push(null);
        }
  
        // run the setter for this dependency
        if (module.setters[i])
          module.setters[i](depModule.module);
      }
  
      load.status = 'linked';
    }
  
  
  
    // 15.2.5.5.1 LinkImports not implemented
    // 15.2.5.7 ResolveExportEntries not implemented
    // 15.2.5.8 ResolveExports not implemented
    // 15.2.5.9 ResolveExport not implemented
    // 15.2.5.10 ResolveImportEntries not implemented
  
    // 15.2.6.1
    function evaluateLoadedModule(loader, load) {
      console.assert(load.status == 'linked', 'is linked ' + load.name);
  
      doEnsureEvaluated(load.module, [], loader);
      return load.module.module;
    }
  
    /*
     * Module Object non-exotic for ES5:
     *
     * module.module        bound module object
     * module.execute       execution function for module
     * module.dependencies  list of module objects for dependencies
     * See getOrCreateModuleRecord for all properties
     *
     */
    function doExecute(module) {
      try {
        module.execute.call(__global);
      }
      catch(e) {
        return e;
      }
    }
  
    // propogate execution errors
    // see https://bugs.ecmascript.org/show_bug.cgi?id=2993
    function doEnsureEvaluated(module, seen, loader) {
      var err = ensureEvaluated(module, seen, loader);
      if (err)
        throw err;
    }
    // 15.2.6.2 EnsureEvaluated adjusted
    function ensureEvaluated(module, seen, loader) {
      if (module.evaluated || !module.dependencies)
        return;
  
      seen.push(module);
  
      var deps = module.dependencies;
      var err;
  
      for (var i = 0, l = deps.length; i < l; i++) {
        var dep = deps[i];
        // dynamic dependencies are empty in module.dependencies
        // as they are already linked
        if (!dep)
          continue;
        if (indexOf.call(seen, dep) == -1) {
          err = ensureEvaluated(dep, seen, loader);
          // stop on error, see https://bugs.ecmascript.org/show_bug.cgi?id=2996
          if (err) {
            err = addToError(err, 'Error evaluating ' + dep.name + '\n');
            return err;
          }
        }
      }
  
      if (module.failed)
        return new Error('Module failed execution.');
  
      if (module.evaluated)
        return;
  
      module.evaluated = true;
      err = doExecute(module);
      if (err) {
        module.failed = true;
      }
      else if (Object.preventExtensions) {
        // spec variation
        // we don't create a new module here because it was created and ammended
        // we just disable further extensions instead
        Object.preventExtensions(module.module);
      }
  
      module.execute = undefined;
      return err;
    }
  
    function addToError(err, msg) {
      if (err instanceof Error)
        err.message = msg + err.message;
      else
        err = msg + err;
      return err;
    }
  
    // 26.3 Loader
  
    // 26.3.1.1
    function Loader(options) {
      if (typeof options != 'object')
        throw new TypeError('Options must be an object');
  
      if (options.normalize)
        this.normalize = options.normalize;
      if (options.locate)
        this.locate = options.locate;
      if (options.fetch)
        this.fetch = options.fetch;
      if (options.translate)
        this.translate = options.translate;
      if (options.instantiate)
        this.instantiate = options.instantiate;
  
      this._loader = {
        loaderObj: this,
        loads: [],
        modules: {},
        importPromises: {},
        moduleRecords: {}
      };
  
      // 26.3.3.6
      defineProperty(this, 'global', {
        get: function() {
          return __global;
        }
      });
  
      // 26.3.3.13 realm not implemented
    }
  
    function Module() {}
  
    // importPromises adds ability to import a module twice without error - https://bugs.ecmascript.org/show_bug.cgi?id=2601
    function createImportPromise(loader, name, promise) {
      var importPromises = loader._loader.importPromises;
      return importPromises[name] = promise.then(function(m) {
        importPromises[name] = undefined;
        return m;
      }, function(e) {
        importPromises[name] = undefined;
        throw e;
      });
    }
  
    Loader.prototype = {
      // 26.3.3.1
      constructor: Loader,
      // 26.3.3.2
      define: function(name, source, options) {
        // check if already defined
        if (this._loader.importPromises[name])
          throw new TypeError('Module is already loading.');
        return createImportPromise(this, name, new Promise(asyncStartLoadPartwayThrough({
          step: 'translate',
          loader: this._loader,
          moduleName: name,
          moduleMetadata: options && options.metadata || {},
          moduleSource: source,
          moduleAddress: options && options.address
        })));
      },
      // 26.3.3.3
      'delete': function(name) {
        var loader = this._loader;
        delete loader.importPromises[name];
        delete loader.moduleRecords[name];
        return loader.modules[name] ? delete loader.modules[name] : false;
      },
      // 26.3.3.4 entries not implemented
      // 26.3.3.5
      get: function(key) {
        if (!this._loader.modules[key])
          return;
        doEnsureEvaluated(this._loader.modules[key], [], this);
        return this._loader.modules[key].module;
      },
      // 26.3.3.7
      has: function(name) {
        return !!this._loader.modules[name];
      },
      // 26.3.3.8
      'import': function(name, options) {
        // run normalize first
        var loaderObj = this;
  
        // added, see https://bugs.ecmascript.org/show_bug.cgi?id=2659
        return Promise.resolve(loaderObj.normalize(name, options && options.name, options && options.address))
        .then(function(name) {
          var loader = loaderObj._loader;
  
          if (loader.modules[name]) {
            doEnsureEvaluated(loader.modules[name], [], loader._loader);
            return loader.modules[name].module;
          }
  
          return loader.importPromises[name] || createImportPromise(loaderObj, name,
            loadModule(loader, name, options || {})
            .then(function(load) {
              delete loader.importPromises[name];
              return evaluateLoadedModule(loader, load);
            }));
        });
      },
      // 26.3.3.9 keys not implemented
      // 26.3.3.10
      load: function(name, options) {
        if (this._loader.modules[name]) {
          doEnsureEvaluated(this._loader.modules[name], [], this._loader);
          return Promise.resolve(this._loader.modules[name].module);
        }
        return this._loader.importPromises[name] || createImportPromise(this, name, loadModule(this._loader, name, {}));
      },
      // 26.3.3.11
      module: function(source, options) {
        var load = createLoad();
        load.address = options && options.address;
        var linkSet = createLinkSet(this._loader, load);
        var sourcePromise = Promise.resolve(source);
        var loader = this._loader;
        var p = linkSet.done.then(function() {
          return evaluateLoadedModule(loader, load);
        });
        proceedToTranslate(loader, load, sourcePromise);
        return p;
      },
      // 26.3.3.12
      newModule: function (obj) {
        if (typeof obj != 'object')
          throw new TypeError('Expected object');
  
        // we do this to be able to tell if a module is a module privately in ES5
        // by doing m instanceof Module
        var m = new Module();
  
        var pNames;
        if (Object.getOwnPropertyNames && obj != null) {
          pNames = Object.getOwnPropertyNames(obj);
        }
        else {
          pNames = [];
          for (var key in obj)
            pNames.push(key);
        }
  
        for (var i = 0; i < pNames.length; i++) (function(key) {
          defineProperty(m, key, {
            configurable: false,
            enumerable: true,
            get: function () {
              return obj[key];
            }
          });
        })(pNames[i]);
  
        if (Object.preventExtensions)
          Object.preventExtensions(m);
  
        return m;
      },
      // 26.3.3.14
      set: function(name, module) {
        if (!(module instanceof Module))
          throw new TypeError('Loader.set(' + name + ', module) must be a module');
        this._loader.modules[name] = {
          module: module
        };
      },
      // 26.3.3.15 values not implemented
      // 26.3.3.16 @@iterator not implemented
      // 26.3.3.17 @@toStringTag not implemented
  
      // 26.3.3.18.1
      normalize: function(name, referrerName, referrerAddress) {
        return name;
      },
      // 26.3.3.18.2
      locate: function(load) {
        return load.name;
      },
      // 26.3.3.18.3
      fetch: function(load) {
        throw new TypeError('Fetch not implemented');
      },
      // 26.3.3.18.4
      translate: function(load) {
        return load.source;
      },
      // 26.3.3.18.5
      instantiate: function(load) {
      }
    };
  
    var _newModule = Loader.prototype.newModule;
  
    if (typeof exports === 'object')
      module.exports = Loader;
  
    __global.Reflect = __global.Reflect || {};
    __global.Reflect.Loader = __global.Reflect.Loader || Loader;
    __global.Reflect.global = __global.Reflect.global || __global;
    __global.LoaderPolyfill = Loader;
  
  })();
  
  /*
   * Traceur and Babel transpile hook for Loader
   */
  (function(Loader) {
    var g = __global;
  
    function getTranspilerModule(loader, globalName) {
      return loader.newModule({ 'default': g[globalName], __useDefault: true });
    }
  
    // use Traceur by default
    Loader.prototype.transpiler = 'traceur';
  
    Loader.prototype.transpile = function(load) {
      var self = this;
  
      // pick up Transpiler modules from existing globals on first run if set
      if (!self.transpilerHasRun) {
        if (g.traceur && !self.has('traceur'))
          self.set('traceur', getTranspilerModule(self, 'traceur'));
        if (g.babel && !self.has('babel'))
          self.set('babel', getTranspilerModule(self, 'babel'));
        self.transpilerHasRun = true;
      }
      
      return self['import'](self.transpiler).then(function(transpiler) {
        if (transpiler.__useDefault)
          transpiler = transpiler['default'];
        return 'var __moduleAddress = "' + load.address + '";' + (transpiler.Compiler ? traceurTranspile : babelTranspile).call(self, load, transpiler);
      });
    };
  
    Loader.prototype.instantiate = function(load) {
      var self = this;
      return Promise.resolve(self.normalize(self.transpiler))
      .then(function(transpilerNormalized) {
        // load transpiler as a global (avoiding System clobbering)
        if (load.name === transpilerNormalized) {
          return {
            deps: [],
            execute: function() {
              var curSystem = g.System;
              var curLoader = g.Reflect.Loader;
              // ensure not detected as CommonJS
              __eval('(function(require,exports,module){' + load.source + '})();', g, load);
              g.System = curSystem;
              g.Reflect.Loader = curLoader;
              return getTranspilerModule(self, load.name);
            }
          };
        }
      });
    };
  
    function traceurTranspile(load, traceur) {
      var options = this.traceurOptions || {};
      options.modules = 'instantiate';
      options.script = false;
      options.sourceMaps = 'inline';
      options.filename = load.address;
      options.inputSourceMap = load.metadata.sourceMap;
      options.moduleName = false;
  
      var compiler = new traceur.Compiler(options);
      var source = doTraceurCompile(load.source, compiler, options.filename);
  
      // add "!eval" to end of Traceur sourceURL
      // I believe this does something?
      source += '!eval';
  
      return source;
    }
    function doTraceurCompile(source, compiler, filename) {
      try {
        return compiler.compile(source, filename);
      }
      catch(e) {
        // traceur throws an error array
        throw e[0];
      }
    }
  
    function babelTranspile(load, babel) {
      var options = this.babelOptions || {};
      options.modules = 'system';
      options.sourceMap = 'inline';
      options.filename = load.address;
      options.code = true;
      options.ast = false;
      
      if (!options.blacklist)
        options.blacklist = ['react'];
  
      var source = babel.transform(load.source, options).code;
  
      // add "!eval" to end of Babel sourceURL
      // I believe this does something?
      return source + '\n//# sourceURL=' + load.address + '!eval';
    }
  
  
  })(__global.LoaderPolyfill);
  /*
  *********************************************************************************************
  
    System Loader Implementation
  
      - Implemented to https://github.com/jorendorff/js-loaders/blob/master/browser-loader.js
  
      - <script type="module"> supported
  
  *********************************************************************************************
  */
  
  
  
  (function() {
    var isWorker = typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
    var isBrowser = typeof window != 'undefined' && !isWorker;
    var isWindows = typeof process != 'undefined' && !!process.platform.match(/^win/);
    var Promise = __global.Promise || require('when/es6-shim/Promise');
  
    // Helpers
    // Absolute URL parsing, from https://gist.github.com/Yaffle/1088850
    function parseURI(url) {
      var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@\/?#]*(?::[^:@\/?#]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);
      // authority = '//' + user + ':' + pass '@' + hostname + ':' port
      return (m ? {
        href     : m[0] || '',
        protocol : m[1] || '',
        authority: m[2] || '',
        host     : m[3] || '',
        hostname : m[4] || '',
        port     : m[5] || '',
        pathname : m[6] || '',
        search   : m[7] || '',
        hash     : m[8] || ''
      } : null);
    }
  
    function removeDotSegments(input) {
      var output = [];
      input.replace(/^(\.\.?(\/|$))+/, '')
        .replace(/\/(\.(\/|$))+/g, '/')
        .replace(/\/\.\.$/, '/../')
        .replace(/\/?[^\/]*/g, function (p) {
          if (p === '/..')
            output.pop();
          else
            output.push(p);
      });
      return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : '');
    }
  
    function toAbsoluteURL(base, href) {
  
      if (isWindows)
        href = href.replace(/\\/g, '/');
  
      href = parseURI(href || '');
      base = parseURI(base || '');
  
      return !href || !base ? null : (href.protocol || base.protocol) +
        (href.protocol || href.authority ? href.authority : base.authority) +
        removeDotSegments(href.protocol || href.authority || href.pathname.charAt(0) === '/' ? href.pathname : (href.pathname ? ((base.authority && !base.pathname ? '/' : '') + base.pathname.slice(0, base.pathname.lastIndexOf('/') + 1) + href.pathname) : base.pathname)) +
        (href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) +
        href.hash;
    }
  
    var fetchTextFromURL;
  
    if (typeof XMLHttpRequest != 'undefined') {
      fetchTextFromURL = function(url, fulfill, reject) {
        var xhr = new XMLHttpRequest();
        var sameDomain = true;
        var doTimeout = false;
        if (!('withCredentials' in xhr)) {
          // check if same domain
          var domainCheck = /^(\w+:)?\/\/([^\/]+)/.exec(url);
          if (domainCheck) {
            sameDomain = domainCheck[2] === window.location.host;
            if (domainCheck[1])
              sameDomain &= domainCheck[1] === window.location.protocol;
          }
        }
        if (!sameDomain && typeof XDomainRequest != 'undefined') {
          xhr = new XDomainRequest();
          xhr.onload = load;
          xhr.onerror = error;
          xhr.ontimeout = error;
          xhr.onprogress = function() {};
          xhr.timeout = 0;
          doTimeout = true;
        }
        function load() {
          fulfill(xhr.responseText);
        }
        function error() {
          reject(xhr.statusText + ': ' + url || 'XHR error');
        }
  
        xhr.onreadystatechange = function () {
          if (xhr.readyState === 4) {
            if (xhr.status === 200 || (xhr.status == 0 && xhr.responseText)) {
              load();
            } else {
              error();
            }
          }
        };
        xhr.open("GET", url, true);
  
        if (doTimeout)
          setTimeout(function() {
            xhr.send();
          }, 0);
  
        xhr.send(null);
      }
    }
    else if (typeof require != 'undefined') {
      var fs;
      fetchTextFromURL = function(url, fulfill, reject) {
        if (url.substr(0, 5) != 'file:')
          throw 'Only file URLs of the form file: allowed running in Node.';
        fs = fs || require('fs');
        url = url.substr(5);
        if (isWindows)
          url = url.replace(/\//g, '\\');
        return fs.readFile(url, function(err, data) {
          if (err)
            return reject(err);
          else
            fulfill(data + '');
        });
      }
    }
    else {
      throw new TypeError('No environment fetch API available.');
    }
  
    var SystemLoader = function($__super) {
      function SystemLoader(options) {
        $__super.call(this, options || {});
  
        // Set default baseURL and paths
        if (typeof location != 'undefined' && location.href) {
          var href = __global.location.href.split('#')[0].split('?')[0];
          this.baseURL = href.substring(0, href.lastIndexOf('/') + 1);
        }
        else if (typeof process != 'undefined' && process.cwd) {
          this.baseURL = 'file:' + process.cwd() + '/';
          if (isWindows)
            this.baseURL = this.baseURL.replace(/\\/g, '/');
        }
        else {
          throw new TypeError('No environment baseURL');
        }
        this.paths = { '*': '*.js' };
      }
  
      SystemLoader.__proto__ = ($__super !== null ? $__super : Function.prototype);
      SystemLoader.prototype = $__Object$create(($__super !== null ? $__super.prototype : null));
  
      $__Object$defineProperty(SystemLoader.prototype, "constructor", {
        value: SystemLoader
      });
  
      $__Object$defineProperty(SystemLoader.prototype, "global", {
        get: function() {
          return isBrowser ? window : (isWorker ? self : __global);
        },
  
        enumerable: false
      });
  
      $__Object$defineProperty(SystemLoader.prototype, "strict", {
        get: function() { return true; },
        enumerable: false
      });
  
      $__Object$defineProperty(SystemLoader.prototype, "normalize", {
        value: function(name, parentName, parentAddress) {
          if (typeof name != 'string')
            throw new TypeError('Module name must be a string');
  
          var segments = name.split('/');
  
          if (segments.length == 0)
            throw new TypeError('No module name provided');
  
          // current segment
          var i = 0;
          // is the module name relative
          var rel = false;
          // number of backtracking segments
          var dotdots = 0;
          if (segments[0] == '.') {
            i++;
            if (i == segments.length)
              throw new TypeError('Illegal module name "' + name + '"');
            rel = true;
          }
          else {
            while (segments[i] == '..') {
              i++;
              if (i == segments.length)
                throw new TypeError('Illegal module name "' + name + '"');
            }
            if (i)
              rel = true;
            dotdots = i;
          }
  
          for (var j = i; j < segments.length; j++) {
            var segment = segments[j];
            if (segment == '' || segment == '.' || segment == '..')
              throw new TypeError('Illegal module name "' + name + '"');
          }
  
          if (!rel)
            return name;
  
          // build the full module name
          var normalizedParts = [];
          var parentParts = (parentName || '').split('/');
          var normalizedLen = parentParts.length - 1 - dotdots;
  
          normalizedParts = normalizedParts.concat(parentParts.splice(0, parentParts.length - 1 - dotdots));
          normalizedParts = normalizedParts.concat(segments.splice(i, segments.length - i));
  
          return normalizedParts.join('/');
        },
  
        enumerable: false,
        writable: true
      });
  
      $__Object$defineProperty(SystemLoader.prototype, "locate", {
        value: function(load) {
          var name = load.name;
  
          // NB no specification provided for System.paths, used ideas discussed in https://github.com/jorendorff/js-loaders/issues/25
  
          // most specific (longest) match wins
          var pathMatch = '', wildcard;
  
          // check to see if we have a paths entry
          for (var p in this.paths) {
            var pathParts = p.split('*');
            if (pathParts.length > 2)
              throw new TypeError('Only one wildcard in a path is permitted');
  
            // exact path match
            if (pathParts.length == 1) {
              if (name == p && p.length > pathMatch.length) {
                pathMatch = p;
                break;
              }
            }
  
            // wildcard path match
            else {
              if (name.substr(0, pathParts[0].length) == pathParts[0] && name.substr(name.length - pathParts[1].length) == pathParts[1]) {
                pathMatch = p;
                wildcard = name.substr(pathParts[0].length, name.length - pathParts[1].length - pathParts[0].length);
              }
            }
          }
  
          var outPath = this.paths[pathMatch];
          if (wildcard)
            outPath = outPath.replace('*', wildcard);
  
          // percent encode just '#' in module names
          // according to https://github.com/jorendorff/js-loaders/blob/master/browser-loader.js#L238
          // we should encode everything, but it breaks for servers that don't expect it 
          // like in (https://github.com/systemjs/systemjs/issues/168)
          if (isBrowser)
            outPath = outPath.replace(/#/g, '%23');
  
          return toAbsoluteURL(this.baseURL, outPath);
        },
  
        enumerable: false,
        writable: true
      });
  
      $__Object$defineProperty(SystemLoader.prototype, "fetch", {
        value: function(load) {
          var self = this;
          return new Promise(function(resolve, reject) {
            fetchTextFromURL(toAbsoluteURL(self.baseURL, load.address), function(source) {
              resolve(source);
            }, reject);
          });
        },
  
        enumerable: false,
        writable: true
      });
  
      return SystemLoader;
    }(__global.LoaderPolyfill);
  
    var System = new SystemLoader();
  
    // note we have to export before runing "init" below
    if (typeof exports === 'object')
      module.exports = System;
  
    __global.System = System;
  
    // <script type="module"> support
    // allow a data-init function callback once loaded
    if (isBrowser && typeof document.getElementsByTagName != 'undefined') {
      var curScript = document.getElementsByTagName('script');
      curScript = curScript[curScript.length - 1];
  
      function completed() {
        document.removeEventListener( "DOMContentLoaded", completed, false );
        window.removeEventListener( "load", completed, false );
        ready();
      }
  
      function ready() {
        var scripts = document.getElementsByTagName('script');
        for (var i = 0; i < scripts.length; i++) {
          var script = scripts[i];
          if (script.type == 'module') {
            var source = script.innerHTML.substr(1);
            // It is important to reference the global System, rather than the one
            // in our closure. We want to ensure that downstream users/libraries
            // can override System w/ custom behavior.
            __global.System.module(source)['catch'](function(err) { setTimeout(function() { throw err; }); });
          }
        }
      }
  
      // DOM ready, taken from https://github.com/jquery/jquery/blob/master/src/core/ready.js#L63
      if (document.readyState === 'complete') {
        setTimeout(ready);
      }
      else if (document.addEventListener) {
        document.addEventListener('DOMContentLoaded', completed, false);
        window.addEventListener('load', completed, false);
      }
  
      // run the data-init function on the script tag
      if (curScript.getAttribute('data-init'))
        window[curScript.getAttribute('data-init')]();
    }
  })();
  
  
  // Define our eval outside of the scope of any other reference defined in this
  // file to avoid adding those references to the evaluation scope.
  function __eval(__source, __global, __load) {
    try {
      eval('(function() { var __moduleName = "' + (__load.name || '').replace('"', '\"') + '"; ' + __source + ' \n }).call(__global);');
    }
    catch(e) {
      if (e.name == 'SyntaxError' || e.name == 'TypeError')
        e.message = 'Evaluating ' + (__load.name || load.address) + '\n\t' + e.message;
      throw e;
    }
  }
  
  })(typeof window != 'undefined' ? window : (typeof WorkerGlobalScope != 'undefined' ?
                                             self : global));
  
  /*
   * SystemJS v0.16.6
   */
  
  (function($__global) {
  
  $__global.upgradeSystemLoader = function() {
    $__global.upgradeSystemLoader = undefined;
  
    // indexOf polyfill for IE
    var indexOf = Array.prototype.indexOf || function(item) {
      for (var i = 0, l = this.length; i < l; i++)
        if (this[i] === item)
          return i;
      return -1;
    }
  
    var isWindows = typeof process != 'undefined' && !!process.platform.match(/^win/);
  
    // Absolute URL parsing, from https://gist.github.com/Yaffle/1088850
    function parseURI(url) {
      var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@\/?#]*(?::[^:@\/?#]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);
      // authority = '//' + user + ':' + pass '@' + hostname + ':' port
      return (m ? {
        href     : m[0] || '',
        protocol : m[1] || '',
        authority: m[2] || '',
        host     : m[3] || '',
        hostname : m[4] || '',
        port     : m[5] || '',
        pathname : m[6] || '',
        search   : m[7] || '',
        hash     : m[8] || ''
      } : null);
    }
    function toAbsoluteURL(base, href) {
      function removeDotSegments(input) {
        var output = [];
        input.replace(/^(\.\.?(\/|$))+/, '')
          .replace(/\/(\.(\/|$))+/g, '/')
          .replace(/\/\.\.$/, '/../')
          .replace(/\/?[^\/]*/g, function (p) {
            if (p === '/..')
              output.pop();
            else
              output.push(p);
        });
        return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : '');
      }
  
      if (isWindows)
        href = href.replace(/\\/g, '/');
  
      href = parseURI(href || '');
      base = parseURI(base || '');
  
      return !href || !base ? null : (href.protocol || base.protocol) +
        (href.protocol || href.authority ? href.authority : base.authority) +
        removeDotSegments(href.protocol || href.authority || href.pathname.charAt(0) === '/' ? href.pathname : (href.pathname ? ((base.authority && !base.pathname ? '/' : '') + base.pathname.slice(0, base.pathname.lastIndexOf('/') + 1) + href.pathname) : base.pathname)) +
        (href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) +
        href.hash;
    }
  
    // clone the original System loader
    var System;
    (function() {
      var originalSystem = $__global.System;
      System = $__global.System = new LoaderPolyfill(originalSystem);
      System.baseURL = originalSystem.baseURL;
      System.paths = { '*': '*.js' };
      System.originalSystem = originalSystem;
    })();
  
    System.noConflict = function() {
      $__global.SystemJS = System;
      $__global.System = System.originalSystem;
    }
  
    
  /*
   * SystemJS Core
   * Code should be vaguely readable
   * 
   */
  var originalSystem = $__global.System.originalSystem;
  function core(loader) {
    /*
      __useDefault
      
      When a module object looks like:
      newModule(
        __useDefault: true,
        default: 'some-module'
      })
  
      Then importing that module provides the 'some-module'
      result directly instead of the full module.
  
      Useful for eg module.exports = function() {}
    */
    var loaderImport = loader['import'];
    loader['import'] = function(name, options) {
      return loaderImport.call(this, name, options).then(function(module) {
        return module.__useDefault ? module['default'] : module;
      });
    };
  
    // support the empty module, as a concept
    loader.set('@empty', loader.newModule({}));
  
    // include the node require since we're overriding it
    if (typeof require != 'undefined')
      loader._nodeRequire = require;
  
    /*
      Config
      Extends config merging one deep only
  
      loader.config({
        some: 'random',
        config: 'here',
        deep: {
          config: { too: 'too' }
        }
      });
  
      <=>
  
      loader.some = 'random';
      loader.config = 'here'
      loader.deep = loader.deep || {};
      loader.deep.config = { too: 'too' };
    */
    loader.config = function(cfg) {
      for (var c in cfg) {
        var v = cfg[c];
        if (typeof v == 'object' && !(v instanceof Array)) {
          this[c] = this[c] || {};
          for (var p in v)
            this[c][p] = v[p];
        }
        else
          this[c] = v;
      }
    };
  
    // override locate to allow baseURL to be document-relative
    var baseURI;
    if (typeof window == 'undefined' &&
        typeof WorkerGlobalScope == 'undefined') {
      baseURI = 'file:' + process.cwd() + '/';
      if (isWindows)
        baseURI = baseURI.replace(/\\/g, '/');
    }
    // Inside of a Web Worker
    else if(typeof window == 'undefined') {
      baseURI = loader.global.location.href;
    }
    else {
      baseURI = document.baseURI;
      if (!baseURI) {
        var bases = document.getElementsByTagName('base');
        baseURI = bases[0] && bases[0].href || window.location.href;
      }
    }
  
    var loaderLocate = loader.locate;
    var normalizedBaseURL;
    loader.locate = function(load) {
      if (this.baseURL != normalizedBaseURL) {
        normalizedBaseURL = toAbsoluteURL(baseURI, this.baseURL);
  
        if (normalizedBaseURL.substr(normalizedBaseURL.length - 1, 1) != '/')
          normalizedBaseURL += '/';
        this.baseURL = normalizedBaseURL;
      }
  
      return Promise.resolve(loaderLocate.call(this, load));
    };
  
    function applyExtensions(extensions, loader) {
      loader._extensions = [];
      for(var i = 0, len = extensions.length; i < len; i++) {
        extensions[i](loader);
      }
    }
  
    loader._extensions = loader._extensions || [];
    loader._extensions.push(core);
  
    loader.clone = function() {
      var originalLoader = this;
      var loader = new LoaderPolyfill(originalSystem);
      loader.baseURL = originalLoader.baseURL;
      loader.paths = { '*': '*.js' };
      applyExtensions(originalLoader._extensions, loader);
      return loader;
    };
  }
  /*
   * Meta Extension
   *
   * Sets default metadata on a load record (load.metadata) from
   * loader.meta[moduleName].
   * Also provides an inline meta syntax for module meta in source.
   *
   * Eg:
   *
   * loader.meta['my/module'] = { some: 'meta' };
   *
   * load.metadata.some = 'meta' will now be set on the load record.
   *
   * The same meta could be set with a my/module.js file containing:
   * 
   * my/module.js
   *   "some meta"; 
   *   "another meta";
   *   console.log('this is my/module');
   *
   * The benefit of inline meta is that coniguration doesn't need
   * to be known in advance, which is useful for modularising
   * configuration and avoiding the need for configuration injection.
   *
   *
   * Example
   * -------
   *
   * The simplest meta example is setting the module format:
   *
   * System.meta['my/module'] = { format: 'amd' };
   *
   * or inside 'my/module.js':
   *
   * "format amd";
   * define(...);
   * 
   */
  
  function meta(loader) {
    var metaRegEx = /^(\s*\/\*.*\*\/|\s*\/\/[^\n]*|\s*"[^"]+"\s*;?|\s*'[^']+'\s*;?)+/;
    var metaPartRegEx = /\/\*.*\*\/|\/\/[^\n]*|"[^"]+"\s*;?|'[^']+'\s*;?/g;
  
    loader.meta = {};
    loader._extensions = loader._extensions || [];
    loader._extensions.push(meta);
  
    function setConfigMeta(loader, load) {
      var meta = loader.meta && loader.meta[load.name];
      if (meta) {
        for (var p in meta)
          load.metadata[p] = load.metadata[p] || meta[p];
      }
    }
  
    var loaderLocate = loader.locate;
    loader.locate = function(load) {
      setConfigMeta(this, load);
      return loaderLocate.call(this, load);
    }
  
    var loaderTranslate = loader.translate;
    loader.translate = function(load) {
      // detect any meta header syntax
      var meta = load.source.match(metaRegEx);
      if (meta) {
        var metaParts = meta[0].match(metaPartRegEx);
        for (var i = 0; i < metaParts.length; i++) {
          var len = metaParts[i].length;
  
          var firstChar = metaParts[i].substr(0, 1);
          if (metaParts[i].substr(len - 1, 1) == ';')
            len--;
        
          if (firstChar != '"' && firstChar != "'")
            continue;
  
          var metaString = metaParts[i].substr(1, metaParts[i].length - 3);
  
          var metaName = metaString.substr(0, metaString.indexOf(' '));
          if (metaName) {
            var metaValue = metaString.substr(metaName.length + 1, metaString.length - metaName.length - 1);
  
            if (load.metadata[metaName] instanceof Array)
              load.metadata[metaName].push(metaValue);
            else if (!load.metadata[metaName])
              load.metadata[metaName] = metaValue;
          }
        }
      }
      // config meta overrides
      setConfigMeta(this, load);
      
      return loaderTranslate.call(this, load);
    }
  }
  /*
   * Instantiate registry extension
   *
   * Supports Traceur System.register 'instantiate' output for loading ES6 as ES5.
   *
   * - Creates the loader.register function
   * - Also supports metadata.format = 'register' in instantiate for anonymous register modules
   * - Also supports metadata.deps, metadata.execute and metadata.executingRequire
   *     for handling dynamic modules alongside register-transformed ES6 modules
   *
   * Works as a standalone extension, but benefits from having a more 
   * advanced __eval defined like in SystemJS polyfill-wrapper-end.js
   *
   * The code here replicates the ES6 linking groups algorithm to ensure that
   * circular ES6 compiled into System.register can work alongside circular AMD 
   * and CommonJS, identically to the actual ES6 loader.
   *
   */
  function register(loader) {
    if (typeof indexOf == 'undefined')
      indexOf = Array.prototype.indexOf;
    if (typeof __eval == 'undefined' || typeof document != 'undefined' && !document.addEventListener)
      __eval = 0 || eval; // uglify breaks without the 0 ||
  
    loader._extensions = loader._extensions || [];
    loader._extensions.push(register);
  
    // define exec for easy evaluation of a load record (load.name, load.source, load.address)
    // main feature is source maps support handling
    var curSystem;
    function exec(load) {
      var loader = this;
      // support sourceMappingURL (efficiently)
      var sourceMappingURL;
      var lastLineIndex = load.source.lastIndexOf('\n');
      if (lastLineIndex != -1) {
        if (load.source.substr(lastLineIndex + 1, 21) == '//# sourceMappingURL=') {
          sourceMappingURL = load.source.substr(lastLineIndex + 22, load.source.length - lastLineIndex - 22);
          if (typeof toAbsoluteURL != 'undefined')
            sourceMappingURL = toAbsoluteURL(load.address, sourceMappingURL);
        }
      }
  
      __eval(load.source, load.address, sourceMappingURL);
    }
    loader.__exec = exec;
  
    function dedupe(deps) {
      var newDeps = [];
      for (var i = 0, l = deps.length; i < l; i++)
        if (indexOf.call(newDeps, deps[i]) == -1)
          newDeps.push(deps[i])
      return newDeps;
    }
  
    /*
     * There are two variations of System.register:
     * 1. System.register for ES6 conversion (2-3 params) - System.register([name, ]deps, declare)
     *    see https://github.com/ModuleLoader/es6-module-loader/wiki/System.register-Explained
     *
     * 2. System.register for dynamic modules (3-4 params) - System.register([name, ]deps, executingRequire, execute)
     * the true or false statement 
     *
     * this extension implements the linking algorithm for the two variations identical to the spec
     * allowing compiled ES6 circular references to work alongside AMD and CJS circular references.
     *
     */
    // loader.register sets loader.defined for declarative modules
    var anonRegister;
    var calledRegister;
    function registerModule(name, deps, declare, execute) {
      if (typeof name != 'string') {
        execute = declare;
        declare = deps;
        deps = name;
        name = null;
      }
  
      calledRegister = true;
      
      var register;
  
      // dynamic
      if (typeof declare == 'boolean') {
        register = {
          declarative: false,
          deps: deps,
          execute: execute,
          executingRequire: declare
        };
      }
      else {
        // ES6 declarative
        register = {
          declarative: true,
          deps: deps,
          declare: declare
        };
      }
      
      // named register
      if (name) {
        register.name = name;
        // we never overwrite an existing define
        if (!(name in loader.defined))
          loader.defined[name] = register; 
      }
      // anonymous register
      else if (register.declarative) {
        if (anonRegister)
          throw new TypeError('Multiple anonymous System.register calls in the same module file.');
        anonRegister = register;
      }
    }
    /*
     * Registry side table - loader.defined
     * Registry Entry Contains:
     *    - name
     *    - deps 
     *    - declare for declarative modules
     *    - execute for dynamic modules, different to declarative execute on module
     *    - executingRequire indicates require drives execution for circularity of dynamic modules
     *    - declarative optional boolean indicating which of the above
     *
     * Can preload modules directly on System.defined['my/module'] = { deps, execute, executingRequire }
     *
     * Then the entry gets populated with derived information during processing:
     *    - normalizedDeps derived from deps, created in instantiate
     *    - groupIndex used by group linking algorithm
     *    - evaluated indicating whether evaluation has happend
     *    - module the module record object, containing:
     *      - exports actual module exports
     *      
     *    Then for declarative only we track dynamic bindings with the records:
     *      - name
     *      - setters declarative setter functions
     *      - exports actual module values
     *      - dependencies, module records of dependencies
     *      - importers, module records of dependents
     *
     * After linked and evaluated, entries are removed, declarative module records remain in separate
     * module binding table
     *
     */
  
    function defineRegister(loader) {
      if (loader.register)
        return;
  
      loader.register = registerModule;
  
      if (!loader.defined)
        loader.defined = {};
      
      // script injection mode calls this function synchronously on load
      var onScriptLoad = loader.onScriptLoad;
      loader.onScriptLoad = function(load) {
        onScriptLoad(load);
        // anonymous define
        if (anonRegister)
          load.metadata.entry = anonRegister;
        
        if (calledRegister) {
          load.metadata.format = load.metadata.format || 'register';
          load.metadata.registered = true;
        }
      }
    }
  
    defineRegister(loader);
  
    function buildGroups(entry, loader, groups) {
      groups[entry.groupIndex] = groups[entry.groupIndex] || [];
  
      if (indexOf.call(groups[entry.groupIndex], entry) != -1)
        return;
  
      groups[entry.groupIndex].push(entry);
  
      for (var i = 0, l = entry.normalizedDeps.length; i < l; i++) {
        var depName = entry.normalizedDeps[i];
        var depEntry = loader.defined[depName];
        
        // not in the registry means already linked / ES6
        if (!depEntry || depEntry.evaluated)
          continue;
        
        // now we know the entry is in our unlinked linkage group
        var depGroupIndex = entry.groupIndex + (depEntry.declarative != entry.declarative);
  
        // the group index of an entry is always the maximum
        if (depEntry.groupIndex === undefined || depEntry.groupIndex < depGroupIndex) {
          
          // if already in a group, remove from the old group
          if (depEntry.groupIndex !== undefined) {
            groups[depEntry.groupIndex].splice(indexOf.call(groups[depEntry.groupIndex], depEntry), 1);
  
            // if the old group is empty, then we have a mixed depndency cycle
            if (groups[depEntry.groupIndex].length == 0)
              throw new TypeError("Mixed dependency cycle detected");
          }
  
          depEntry.groupIndex = depGroupIndex;
        }
  
        buildGroups(depEntry, loader, groups);
      }
    }
  
    function link(name, loader) {
      var startEntry = loader.defined[name];
  
      // skip if already linked
      if (startEntry.module)
        return;
  
      startEntry.groupIndex = 0;
  
      var groups = [];
  
      buildGroups(startEntry, loader, groups);
  
      var curGroupDeclarative = !!startEntry.declarative == groups.length % 2;
      for (var i = groups.length - 1; i >= 0; i--) {
        var group = groups[i];
        for (var j = 0; j < group.length; j++) {
          var entry = group[j];
  
          // link each group
          if (curGroupDeclarative)
            linkDeclarativeModule(entry, loader);
          else
            linkDynamicModule(entry, loader);
        }
        curGroupDeclarative = !curGroupDeclarative; 
      }
    }
  
    // module binding records
    var moduleRecords = {};
    function getOrCreateModuleRecord(name) {
      return moduleRecords[name] || (moduleRecords[name] = {
        name: name,
        dependencies: [],
        exports: {}, // start from an empty module and extend
        importers: []
      })
    }
  
    function linkDeclarativeModule(entry, loader) {
      // only link if already not already started linking (stops at circular)
      if (entry.module)
        return;
  
      var module = entry.module = getOrCreateModuleRecord(entry.name);
      var exports = entry.module.exports;
  
      var declaration = entry.declare.call(loader.global, function(name, value) {
        module.locked = true;
        exports[name] = value;
  
        for (var i = 0, l = module.importers.length; i < l; i++) {
          var importerModule = module.importers[i];
          if (!importerModule.locked) {
            var importerIndex = indexOf.call(importerModule.dependencies, module);
            importerModule.setters[importerIndex](exports);
          }
        }
  
        module.locked = false;
        return value;
      });
      
      module.setters = declaration.setters;
      module.execute = declaration.execute;
  
      if (!module.setters || !module.execute) {
        throw new TypeError('Invalid System.register form for ' + entry.name);
      }
  
      // now link all the module dependencies
      for (var i = 0, l = entry.normalizedDeps.length; i < l; i++) {
        var depName = entry.normalizedDeps[i];
        var depEntry = loader.defined[depName];
        var depModule = moduleRecords[depName];
  
        // work out how to set depExports based on scenarios...
        var depExports;
  
        if (depModule) {
          depExports = depModule.exports;
        }
        // dynamic, already linked in our registry
        else if (depEntry && !depEntry.declarative) {
          if (depEntry.module.exports && depEntry.module.exports.__esModule)
            depExports = depEntry.module.exports;
          else
            depExports = { 'default': depEntry.module.exports, '__useDefault': true };
        }
        // in the loader registry
        else if (!depEntry) {
          depExports = loader.get(depName);
        }
        // we have an entry -> link
        else {
          linkDeclarativeModule(depEntry, loader);
          depModule = depEntry.module;
          depExports = depModule.exports;
        }
  
        // only declarative modules have dynamic bindings
        if (depModule && depModule.importers) {
          depModule.importers.push(module);
          module.dependencies.push(depModule);
        }
        else {
          module.dependencies.push(null);
        }
  
        // run the setter for this dependency
        if (module.setters[i])
          module.setters[i](depExports);
      }
    }
  
    // An analog to loader.get covering execution of all three layers (real declarative, simulated declarative, simulated dynamic)
    function getModule(name, loader) {
      var exports;
      var entry = loader.defined[name];
  
      if (!entry) {
        exports = loader.get(name);
        if (!exports)
          throw new Error('Unable to load dependency ' + name + '.');
      }
  
      else {
        if (entry.declarative)
          ensureEvaluated(name, [], loader);
      
        else if (!entry.evaluated)
          linkDynamicModule(entry, loader);
  
        exports = entry.module.exports;
      }
  
      if ((!entry || entry.declarative) && exports && exports.__useDefault)
        return exports['default'];
      
      return exports;
    }
  
    function linkDynamicModule(entry, loader) {
      if (entry.module)
        return;
  
      var exports = {};
  
      var module = entry.module = { exports: exports, id: entry.name };
  
      // AMD requires execute the tree first
      if (!entry.executingRequire) {
        for (var i = 0, l = entry.normalizedDeps.length; i < l; i++) {
          var depName = entry.normalizedDeps[i];
          var depEntry = loader.defined[depName];
          if (depEntry)
            linkDynamicModule(depEntry, loader);
        }
      }
  
      // now execute
      entry.evaluated = true;
      var output = entry.execute.call(loader.global, function(name) {
        for (var i = 0, l = entry.deps.length; i < l; i++) {
          if (entry.deps[i] != name)
            continue;
          return getModule(entry.normalizedDeps[i], loader);
        }
        throw new TypeError('Module ' + name + ' not declared as a dependency.');
      }, exports, module);
      
      if (output)
        module.exports = output;
        
      /*if ( output && output.__esModule )
        entry.module = output;
      else if (output)
        entry.module['default'] = output;*/
    }
  
    /*
     * Given a module, and the list of modules for this current branch,
     *  ensure that each of the dependencies of this module is evaluated
     *  (unless one is a circular dependency already in the list of seen
     *  modules, in which case we execute it)
     *
     * Then we evaluate the module itself depth-first left to right 
     * execution to match ES6 modules
     */
    function ensureEvaluated(moduleName, seen, loader) {
      var entry = loader.defined[moduleName];
  
      // if already seen, that means it's an already-evaluated non circular dependency
      if (!entry || entry.evaluated || !entry.declarative)
        return;
  
      // this only applies to declarative modules which late-execute
  
      seen.push(moduleName);
  
      for (var i = 0, l = entry.normalizedDeps.length; i < l; i++) {
        var depName = entry.normalizedDeps[i];
        if (indexOf.call(seen, depName) == -1) {
          if (!loader.defined[depName])
            loader.get(depName);
          else
            ensureEvaluated(depName, seen, loader);
        }
      }
  
      if (entry.evaluated)
        return;
  
      entry.evaluated = true;
      entry.module.execute.call(loader.global);
    }
  
    var registerRegEx = /System\.register/;
  
    var loaderFetch = loader.fetch;
    loader.fetch = function(load) {
      var loader = this;
      defineRegister(loader);
      if (loader.defined[load.name]) {
        load.metadata.format = 'defined';
        return '';
      }
      anonRegister = null;
      calledRegister = false;
      // the above get picked up by onScriptLoad
      return loaderFetch.call(loader, load);
    }
  
    var loaderTranslate = loader.translate;
    loader.translate = function(load) {
      this.register = registerModule;
  
      this.__exec = exec;
  
      load.metadata.deps = load.metadata.deps || [];
  
      // we run the meta detection here (register is after meta)
      return Promise.resolve(loaderTranslate.call(this, load)).then(function(source) {
        
        // dont run format detection for globals shimmed
        // ideally this should be in the global extension, but there is
        // currently no neat way to separate it
        if (load.metadata.init || load.metadata.exports)
          load.metadata.format = load.metadata.format || 'global';
  
        // run detection for register format
        if (load.metadata.format == 'register' || !load.metadata.format && load.source.match(registerRegEx))
          load.metadata.format = 'register';
        return source;
      });
    }
  
  
    var loaderInstantiate = loader.instantiate;
    loader.instantiate = function(load) {
      var loader = this;
  
      var entry;
  
      // first we check if this module has already been defined in the registry
      if (loader.defined[load.name]) {
        entry = loader.defined[load.name];
        entry.deps = entry.deps.concat(load.metadata.deps);
      }
  
      // picked up already by a script injection
      else if (load.metadata.entry)
        entry = load.metadata.entry;
  
      // otherwise check if it is dynamic
      else if (load.metadata.execute) {
        entry = {
          declarative: false,
          deps: load.metadata.deps || [],
          execute: load.metadata.execute,
          executingRequire: load.metadata.executingRequire // NodeJS-style requires or not
        };
      }
  
      // Contains System.register calls
      else if (load.metadata.format == 'register') {
        anonRegister = null;
        calledRegister = false;
  
        var curSystem = loader.global.System;
  
        loader.global.System = loader;
  
        loader.__exec(load);
  
        loader.global.System = curSystem;
  
        if (anonRegister)
          entry = anonRegister;
  
        if (!entry && System.defined[load.name])
          entry = System.defined[load.name];
  
        if (!calledRegister && !load.metadata.registered)
          throw new TypeError(load.name + ' detected as System.register but didn\'t execute.');
      }
  
      // named bundles are just an empty module
      if (!entry && load.metadata.format != 'es6')
        return {
          deps: load.metadata.deps,
          execute: function() {
            return loader.newModule({});
          }
        };
  
      // place this module onto defined for circular references
      if (entry)
        loader.defined[load.name] = entry;
  
      // no entry -> treat as ES6
      else
        return loaderInstantiate.call(this, load);
  
      entry.deps = dedupe(entry.deps);
      entry.name = load.name;
  
      // first, normalize all dependencies
      var normalizePromises = [];
      for (var i = 0, l = entry.deps.length; i < l; i++)
        normalizePromises.push(Promise.resolve(loader.normalize(entry.deps[i], load.name)));
  
      return Promise.all(normalizePromises).then(function(normalizedDeps) {
  
        entry.normalizedDeps = normalizedDeps;
  
        return {
          deps: entry.deps,
          execute: function() {
            // recursively ensure that the module and all its 
            // dependencies are linked (with dependency group handling)
            link(load.name, loader);
  
            // now handle dependency execution in correct order
            ensureEvaluated(load.name, [], loader);
  
            // remove from the registry
            loader.defined[load.name] = undefined;
  
            var module = entry.module.exports;
  
            if (!module || !entry.declarative && module.__esModule !== true)
              module = { 'default': module, __useDefault: true };
  
            // return the defined module object
            return loader.newModule(module);
          }
        };
      });
    }
  }
  /*
   * Extension to detect ES6 and auto-load Traceur or Babel for processing
   */
  function es6(loader) {
    loader._extensions.push(es6);
  
    // good enough ES6 detection regex - format detections not designed to be accurate, but to handle the 99% use case
    var es6RegEx = /(^\s*|[}\);\n]\s*)(import\s+(['"]|(\*\s+as\s+)?[^"'\(\)\n;]+\s+from\s+['"]|\{)|export\s+\*\s+from\s+["']|export\s+(\{|default|function|class|var|const|let|async\s+function))/;
  
    var traceurRuntimeRegEx = /\$traceurRuntime\s*\./;
    var babelHelpersRegEx = /babelHelpers\s*\./;
  
    var transpilerNormalized, transpilerRuntimeNormalized;
  
    var firstLoad = true;
  
    var nodeResolver = typeof process != 'undefined' && typeof require != 'undefined' && require.resolve;
  
    function setConfig(loader, module, nodeModule) {
      loader.meta[module] = {format: 'global'};
      if (nodeResolver && !loader.paths[module]) {
        try {
          loader.paths[module] = require.resolve(nodeModule || module);
        }
        catch(e) {}
      }
    }
  
    var loaderLocate = loader.locate;
    loader.locate = function(load) {
      var self = this;
      if (firstLoad) {
        if (self.transpiler == 'traceur') {
          setConfig(self, 'traceur', 'traceur/bin/traceur.js');
          self.meta['traceur'].exports = 'traceur';
          setConfig(self, 'traceur-runtime', 'traceur/bin/traceur-runtime.js');
        }
        else if (self.transpiler == 'babel') {
          setConfig(self, 'babel', 'babel-core/browser.js');
          setConfig(self, 'babel-runtime', 'babel-core/external-helpers.js');
        }
        firstLoad = false;
      }
      return loaderLocate.call(self, load);
    };
  
    var loaderTranslate = loader.translate;
    loader.translate = function(load) {
      var loader = this;
  
      return loaderTranslate.call(loader, load)
      .then(function(source) {
  
        // detect ES6
        if (load.metadata.format == 'es6' || !load.metadata.format && source.match(es6RegEx)) {
          load.metadata.format = 'es6';
          return source;
        }
  
        if (load.metadata.format == 'register') {
          if (!loader.global.$traceurRuntime && load.source.match(traceurRuntimeRegEx)) {
            return loader['import']('traceur-runtime').then(function() {
              return source;
            });
          }
          if (!loader.global.babelHelpers && load.source.match(babelHelpersRegEx)) {
            return loader['import']('babel/external-helpers').then(function() {
              return source;
            });
          }
        }
  
        // ensure Traceur doesn't clobber the System global
        if (loader.transpiler == 'traceur')
          return Promise.all([
            transpilerNormalized || (transpilerNormalized = loader.normalize(loader.transpiler)),
            transpilerRuntimeNormalized || (transpilerRuntimeNormalized = loader.normalize(loader.transpiler + '-runtime'))
          ])
          .then(function(normalized) {
            if (load.name == normalized[0] || load.name == normalized[1])
              return '(function() { var curSystem = System; ' + source + '\nSystem = curSystem; })();';
  
            return source;
          });
  
        return source;
      });
  
    };
  
  }
  /*
    SystemJS Global Format
  
    Supports
      metadata.deps
      metadata.init
      metadata.exports
  
    Also detects writes to the global object avoiding global collisions.
    See the SystemJS readme global support section for further information.
  */
  function global(loader) {
  
    loader._extensions.push(global);
  
    function readGlobalProperty(p, value) {
      var pParts = p.split('.');
      while (pParts.length)
        value = value[pParts.shift()];
      return value;
    }
  
    function createHelpers(loader) {
      if (loader.has('@@global-helpers'))
        return;
  
      var hasOwnProperty = loader.global.hasOwnProperty;
      var moduleGlobals = {};
  
      var curGlobalObj;
      var ignoredGlobalProps;
  
      function makeLookupObject(arr) {
        var out = {};
        for(var i = 0, len = arr.length; i < len; i++) {
          out[arr[i]] = true;
        }
        return out;
      }
  
      loader.set('@@global-helpers', loader.newModule({
        prepareGlobal: function(moduleName, deps, exportName) {
          // first, we add all the dependency modules to the global
          for (var i = 0; i < deps.length; i++) {
            var moduleGlobal = moduleGlobals[deps[i]];
            if (moduleGlobal)
              for (var m in moduleGlobal)
                loader.global[m] = moduleGlobal[m];
          }
  
          // If an exportName is defined there is no need to perform the next
          // expensive operation.
          if(exportName || exportName === false || loader.inferGlobals === false) {
            return;
          }
  
          // now store a complete copy of the global object
          // in order to detect changes
          curGlobalObj = {};
          ignoredGlobalProps = makeLookupObject(['indexedDB', 'sessionStorage', 'localStorage',
            'clipboardData', 'frames', 'webkitStorageInfo', 'toolbar', 'statusbar',
            'scrollbars', 'personalbar', 'menubar', 'locationbar', 'webkitIndexedDB',
            'screenTop', 'screenLeft'
          ]);
          for (var g in loader.global) {
            if (ignoredGlobalProps[g]) { continue; }
            if (!hasOwnProperty || loader.global.hasOwnProperty(g)) {
              try {
                curGlobalObj[g] = loader.global[g];
              } catch (e) {
                ignoredGlobalProps[g] = true;
              }
            }
          }
        },
        retrieveGlobal: function(moduleName, exportName, init) {
          var singleGlobal;
          var multipleExports;
          var exports = {};
  
          // run init
          if (init)
            singleGlobal = init.call(loader.global);
  
          // check for global changes, creating the globalObject for the module
          // if many globals, then a module object for those is created
          // if one global, then that is the module directly
          else if (exportName) {
            var firstPart = exportName.split('.')[0];
            singleGlobal = readGlobalProperty(exportName, loader.global);
            exports[firstPart] = loader.global[firstPart];
          }
  
          else if(exportName !== false && loader.inferGlobals !== false) {
            for (var g in loader.global) {
              if (ignoredGlobalProps[g])
                continue;
              if ((!hasOwnProperty || loader.global.hasOwnProperty(g)) && g != loader.global && curGlobalObj[g] != loader.global[g]) {
                exports[g] = loader.global[g];
                if (singleGlobal) {
                  if (singleGlobal !== loader.global[g])
                    multipleExports = true;
                }
                else if (singleGlobal === undefined) {
                  singleGlobal = loader.global[g];
                }
              }
            }
          }
  
          moduleGlobals[moduleName] = exports;
  
          return multipleExports ? exports : singleGlobal;
        }
      }));
    }
  
    createHelpers(loader);
  
    var loaderInstantiate = loader.instantiate;
    loader.instantiate = function(load) {
      var loader = this;
  
      createHelpers(loader);
  
      var exportName = load.metadata.exports;
  
      if (!load.metadata.format)
        load.metadata.format = 'global';
  
      // global is a fallback module format
      if (load.metadata.format == 'global') {
        load.metadata.execute = function(require, exports, module) {
  
          loader.get('@@global-helpers').prepareGlobal(module.id, load.metadata.deps, exportName);
  
          if (exportName)
            load.source += '\nthis["' + exportName + '"] = ' + exportName + ';';
  
          // disable module detection
          var define = loader.global.define;
          var require = loader.global.require;
  
          loader.global.define = undefined;
          loader.global.module = undefined;
          loader.global.exports = undefined;
  
          loader.__exec(load);
  
          loader.global.require = require;
          loader.global.define = define;
  
          return loader.get('@@global-helpers').retrieveGlobal(module.id, exportName, load.metadata.init);
        }
      }
      return loaderInstantiate.call(loader, load);
    }
  }
  /*
    SystemJS CommonJS Format
  */
  function cjs(loader) {
    loader._extensions.push(cjs);
  
    // CJS Module Format
    // require('...') || exports[''] = ... || exports.asd = ... || module.exports = ...
    var cjsExportsRegEx = /(?:^\uFEFF?|[^$_a-zA-Z\xA0-\uFFFF.]|module\.)(exports\s*\[['"]|\exports\s*\.)|(?:^\uFEFF?|[^$_a-zA-Z\xA0-\uFFFF.])module\.exports\s*\=/;
    // RegEx adjusted from https://github.com/jbrantly/yabble/blob/master/lib/yabble.js#L339
    var cjsRequireRegEx = /(?:^\uFEFF?|[^$_a-zA-Z\xA0-\uFFFF."'])require\s*\(\s*("[^"\\]*(?:\\.[^"\\]*)*"|'[^'\\]*(?:\\.[^'\\]*)*')\s*\)/g;
    var commentRegEx = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg;
  
    function getCJSDeps(source) {
      cjsRequireRegEx.lastIndex = 0;
  
      var deps = [];
  
      // remove comments from the source first, if not minified
      if (source.length / source.split('\n').length < 200)
        source = source.replace(commentRegEx, '');
  
      var match;
  
      while (match = cjsRequireRegEx.exec(source))
        deps.push(match[1].substr(1, match[1].length - 2));
  
      return deps;
    }
  
    var loaderInstantiate = loader.instantiate;
    loader.instantiate = function(load) {
  
      if (!load.metadata.format) {
        cjsExportsRegEx.lastIndex = 0;
        cjsRequireRegEx.lastIndex = 0;
        if (cjsRequireRegEx.exec(load.source) || cjsExportsRegEx.exec(load.source))
          load.metadata.format = 'cjs';
      }
  
      if (load.metadata.format == 'cjs') {
        load.metadata.deps = load.metadata.deps ? load.metadata.deps.concat(getCJSDeps(load.source)) : getCJSDeps(load.source);
  
        load.metadata.executingRequire = true;
  
        load.metadata.execute = function(require, exports, module) {
          var dirname = (load.address || '').split('/');
          dirname.pop();
          dirname = dirname.join('/');
  
          // if on the server, remove the "file:" part from the dirname
          if (System._nodeRequire)
            dirname = dirname.substr(5);
  
          var globals = loader.global._g = {
            global: loader.global,
            exports: exports,
            module: module,
            require: require,
            __filename: System._nodeRequire ? load.address.substr(5) : load.address,
            __dirname: dirname
          };
  
  
          // disable AMD detection
          var define = loader.global.define;
          loader.global.define = undefined;
  
          var execLoad = {
            name: load.name,
            source: '(function() {\n(function(global, exports, module, require, __filename, __dirname){\n' + load.source + 
                                    '\n}).call(_g.exports, _g.global, _g.exports, _g.module, _g.require, _g.__filename, _g.__dirname);})();',
            address: load.address
          };
          loader.__exec(execLoad);
  
          loader.global.define = define;
  
          loader.global._g = undefined;
        }
      }
  
      return loaderInstantiate.call(this, load);
    };
  }
  /*
    SystemJS AMD Format
    Provides the AMD module format definition at System.format.amd
    as well as a RequireJS-style require on System.require
  */
  function amd(loader) {
    // by default we only enforce AMD noConflict mode in Node
    var isNode = typeof module != 'undefined' && module.exports;
  
    loader._extensions.push(amd);
  
    // AMD Module Format Detection RegEx
    // define([.., .., ..], ...)
    // define(varName); || define(function(require, exports) {}); || define({})
    var amdRegEx = /(?:^\uFEFF?|[^$_a-zA-Z\xA0-\uFFFF.])define\s*\(\s*("[^"]+"\s*,\s*|'[^']+'\s*,\s*)?\s*(\[(\s*(("[^"]+"|'[^']+')\s*,|\/\/.*\r?\n|\/\*(.|\s)*?\*\/))*(\s*("[^"]+"|'[^']+')\s*,?)?(\s*(\/\/.*\r?\n|\/\*(.|\s)*?\*\/))*\s*\]|function\s*|{|[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*\))/;
    var commentRegEx = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg;
  
    var cjsRequirePre = "(?:^|[^$_a-zA-Z\\xA0-\\uFFFF.])";
    var cjsRequirePost = "\\s*\\(\\s*(\"([^\"]+)\"|'([^']+)')\\s*\\)";
  
    var fnBracketRegEx = /\(([^\)]*)\)/;
  
    var wsRegEx = /^\s+|\s+$/g;
  
    var requireRegExs = {};
  
    function getCJSDeps(source, requireIndex) {
  
      // remove comments
      source = source.replace(commentRegEx, '');
  
      // determine the require alias
      var params = source.match(fnBracketRegEx);
      var requireAlias = (params[1].split(',')[requireIndex] || 'require').replace(wsRegEx, '');
  
      // find or generate the regex for this requireAlias
      var requireRegEx = requireRegExs[requireAlias] || (requireRegExs[requireAlias] = new RegExp(cjsRequirePre + requireAlias + cjsRequirePost, 'g'));
  
      requireRegEx.lastIndex = 0;
  
      var deps = [];
  
      var match;
      while (match = requireRegEx.exec(source))
        deps.push(match[2] || match[3]);
  
      return deps;
    }
  
    /*
      AMD-compatible require
      To copy RequireJS, set window.require = window.requirejs = loader.amdRequire
    */
    function require(names, callback, errback, referer) {
      // 'this' is bound to the loader
      var loader = this;
  
      // in amd, first arg can be a config object... we just ignore
      if (typeof names == 'object' && !(names instanceof Array))
        return require.apply(null, Array.prototype.splice.call(arguments, 1, arguments.length - 1));
  
      // amd require
      if (names instanceof Array)
        Promise.all(names.map(function(name) {
          return loader['import'](name, referer);
        })).then(function(modules) {
          if(callback) {
            callback.apply(null, modules);
          }
        }, errback);
  
      // commonjs require
      else if (typeof names == 'string') {
        var module = loader.get(names);
        return module.__useDefault ? module['default'] : module;
      }
  
      else
        throw new TypeError('Invalid require');
    };
    loader.amdRequire = function() {
      return require.apply(this, arguments);
    };
  
    function makeRequire(parentName, staticRequire, loader) {
      return function(names, callback, errback) {
        if (typeof names == 'string')
          return staticRequire(names);
        return require.call(loader, names, callback, errback, { name: parentName });
      }
    }
  
    // run once per loader
    function generateDefine(loader) {
      // script injection mode calls this function synchronously on load
      var onScriptLoad = loader.onScriptLoad;
      loader.onScriptLoad = function(load) {
        onScriptLoad(load);
        if (anonDefine || defineBundle) {
          load.metadata.format = 'defined';
          load.metadata.registered = true;
        }
  
        if (anonDefine) {
          load.metadata.deps = load.metadata.deps ? load.metadata.deps.concat(anonDefine.deps) : anonDefine.deps;
          load.metadata.execute = anonDefine.execute;
        }
      }
  
      function define(name, deps, factory) {
        if (typeof name != 'string') {
          factory = deps;
          deps = name;
          name = null;
        }
        if (!(deps instanceof Array)) {
          factory = deps;
          deps = ['require', 'exports', 'module'];
        }
  
        if (typeof factory != 'function')
          factory = (function(factory) {
            return function() { return factory; }
          })(factory);
  
        // in IE8, a trailing comma becomes a trailing undefined entry
        if (deps[deps.length - 1] === undefined)
          deps.pop();
  
        // remove system dependencies
        var requireIndex, exportsIndex, moduleIndex;
        
        if ((requireIndex = indexOf.call(deps, 'require')) != -1) {
          
          deps.splice(requireIndex, 1);
  
          var factoryText = factory.toString();
  
          deps = deps.concat(getCJSDeps(factoryText, requireIndex));
        }
          
  
        if ((exportsIndex = indexOf.call(deps, 'exports')) != -1)
          deps.splice(exportsIndex, 1);
        
        if ((moduleIndex = indexOf.call(deps, 'module')) != -1)
          deps.splice(moduleIndex, 1);
  
        var define = {
          deps: deps,
          execute: function(require, exports, module) {
  
            var depValues = [];
            for (var i = 0; i < deps.length; i++)
              depValues.push(require(deps[i]));
  
            module.uri = loader.baseURL + module.id;
  
            module.config = function() {};
  
            // add back in system dependencies
            if (moduleIndex != -1)
              depValues.splice(moduleIndex, 0, module);
            
            if (exportsIndex != -1)
              depValues.splice(exportsIndex, 0, exports);
            
            if (requireIndex != -1)
              depValues.splice(requireIndex, 0, makeRequire(module.id, require, loader));
  
            var output = factory.apply(global, depValues);
  
            if (typeof output == 'undefined' && module)
              output = module.exports;
  
            if (typeof output != 'undefined')
              return output;
          }
        };
  
        // anonymous define
        if (!name) {
          // already defined anonymously -> throw
          if (anonDefine)
            throw new TypeError('Multiple defines for anonymous module');
          anonDefine = define;
        }
        // named define
        else {
          // if it has no dependencies and we don't have any other
          // defines, then let this be an anonymous define
          if (deps.length == 0 && !anonDefine && !defineBundle)
            anonDefine = define;
  
          // otherwise its a bundle only
          else
            anonDefine = null;
  
          // the above is just to support single modules of the form:
          // define('jquery')
          // still loading anonymously
          // because it is done widely enough to be useful
  
          // note this is now a bundle
          defineBundle = true;
  
          // define the module through the register registry
          loader.register(name, define.deps, false, define.execute);
        }
      };
      define.amd = {};
      loader.amdDefine = define;
    }
  
    var anonDefine;
    // set to true if the current module turns out to be a named define bundle
    var defineBundle;
  
    var oldModule, oldExports, oldDefine;
  
    // adds define as a global (potentially just temporarily)
    function createDefine(loader) {
      if (!loader.amdDefine)
        generateDefine(loader);
  
      anonDefine = null;
      defineBundle = null;
  
      // ensure no NodeJS environment detection
      var global = loader.global;
  
      oldModule = global.module;
      oldExports = global.exports;
      oldDefine = global.define;
  
      global.module = undefined;
      global.exports = undefined;
  
      if (global.define && global.define === loader.amdDefine)
        return;
  
      global.define = loader.amdDefine;
    }
  
    function removeDefine(loader) {
      var global = loader.global;
      global.define = oldDefine;
      global.module = oldModule;
      global.exports = oldExports;
    }
  
    generateDefine(loader);
  
    if (loader.scriptLoader) {
      var loaderFetch = loader.fetch;
      loader.fetch = function(load) {
        createDefine(this);
        return loaderFetch.call(this, load);
      }
    }
  
    var loaderInstantiate = loader.instantiate;
    loader.instantiate = function(load) {
      var loader = this;
  
      if (load.metadata.format == 'amd' || !load.metadata.format && load.source.match(amdRegEx)) {
        load.metadata.format = 'amd';
  
        if (loader.execute !== false) {
          createDefine(loader);
  
          loader.__exec(load);
  
          removeDefine(loader);
  
          if (!anonDefine && !defineBundle && !isNode)
            throw new TypeError('AMD module ' + load.name + ' did not define');
        }
  
        if (anonDefine) {
          load.metadata.deps = load.metadata.deps ? load.metadata.deps.concat(anonDefine.deps) : anonDefine.deps;
          load.metadata.execute = anonDefine.execute;
        }
      }
  
      return loaderInstantiate.call(loader, load);
    }
  }
  /*
    SystemJS map support
    
    Provides map configuration through
      System.map['jquery'] = 'some/module/map'
  
    As well as contextual map config through
      System.map['bootstrap'] = {
        jquery: 'some/module/map2'
      }
  
    Note that this applies for subpaths, just like RequireJS
  
    jquery      -> 'some/module/map'
    jquery/path -> 'some/module/map/path'
    bootstrap   -> 'bootstrap'
  
    Inside any module name of the form 'bootstrap' or 'bootstrap/*'
      jquery    -> 'some/module/map2'
      jquery/p  -> 'some/module/map2/p'
  
    Maps are carefully applied from most specific contextual map, to least specific global map
  */
  function map(loader) {
    loader.map = loader.map || {};
  
    loader._extensions.push(map);
  
    // return if prefix parts (separated by '/') match the name
    // eg prefixMatch('jquery/some/thing', 'jquery') -> true
    //    prefixMatch('jqueryhere/', 'jquery') -> false
    function prefixMatch(name, prefix) {
      if (name.length < prefix.length)
        return false;
      if (name.substr(0, prefix.length) != prefix)
        return false;
      if (name[prefix.length] && name[prefix.length] != '/')
        return false;
      return true;
    }
  
    // get the depth of a given path
    // eg pathLen('some/name') -> 2
    function pathLen(name) {
      var len = 1;
      for (var i = 0, l = name.length; i < l; i++)
        if (name[i] === '/')
          len++;
      return len;
    }
  
    function doMap(name, matchLen, map) {
      return map + name.substr(matchLen);
    }
  
    // given a relative-resolved module name and normalized parent name,
    // apply the map configuration
    function applyMap(name, parentName, loader) {
      var curMatch, curMatchLength = 0;
      var curParent, curParentMatchLength = 0;
      var tmpParentLength, tmpPrefixLength;
      var subPath;
      var nameParts;
      
      // first find most specific contextual match
      if (parentName) {
        for (var p in loader.map) {
          var curMap = loader.map[p];
          if (typeof curMap != 'object')
            continue;
  
          // most specific parent match wins first
          if (!prefixMatch(parentName, p))
            continue;
  
          tmpParentLength = pathLen(p);
          if (tmpParentLength <= curParentMatchLength)
            continue;
  
          for (var q in curMap) {
            // most specific name match wins
            if (!prefixMatch(name, q))
              continue;
            tmpPrefixLength = pathLen(q);
            if (tmpPrefixLength <= curMatchLength)
              continue;
  
            curMatch = q;
            curMatchLength = tmpPrefixLength;
            curParent = p;
            curParentMatchLength = tmpParentLength;
          }
        }
      }
  
      // if we found a contextual match, apply it now
      if (curMatch)
        return doMap(name, curMatch.length, loader.map[curParent][curMatch]);
  
      // now do the global map
      for (var p in loader.map) {
        var curMap = loader.map[p];
        if (typeof curMap != 'string')
          continue;
  
        if (!prefixMatch(name, p))
          continue;
  
        var tmpPrefixLength = pathLen(p);
  
        if (tmpPrefixLength <= curMatchLength)
          continue;
  
        curMatch = p;
        curMatchLength = tmpPrefixLength;
      }
  
      if (curMatch)
        return doMap(name, curMatch.length, loader.map[curMatch]);
  
      return name;
    }
  
    var loaderNormalize = loader.normalize;
    loader.normalize = function(name, parentName, parentAddress) {
      var loader = this;
      if (!loader.map)
        loader.map = {};
  
      var isPackage = false;
      if (name.substr(name.length - 1, 1) == '/') {
        isPackage = true;
        name += '#';
      }
  
      return Promise.resolve(loaderNormalize.call(loader, name, parentName, parentAddress))
      .then(function(name) {
        name = applyMap(name, parentName, loader);
  
        // Normalize "module/" into "module/module"
        // Convenient for packages
        if (isPackage) {
          var nameParts = name.split('/');
          nameParts.pop();
          var pkgName = nameParts.pop();
          nameParts.push(pkgName);
          nameParts.push(pkgName);
          name = nameParts.join('/');
        }
  
        return name;
      });
    }
  }
  /*
    SystemJS Plugin Support
  
    Supports plugin syntax with "!"
  
    The plugin name is loaded as a module itself, and can override standard loader hooks
    for the plugin resource. See the plugin section of the systemjs readme.
  */
  function plugins(loader) {
    if (typeof indexOf == 'undefined')
      indexOf = Array.prototype.indexOf;
  
    loader._extensions.push(plugins);
  
    var loaderNormalize = loader.normalize;
    loader.normalize = function(name, parentName, parentAddress) {
      var loader = this;
      // if parent is a plugin, normalize against the parent plugin argument only
      var parentPluginIndex;
      if (parentName && (parentPluginIndex = parentName.indexOf('!')) != -1)
        parentName = parentName.substr(0, parentPluginIndex);
  
      return Promise.resolve(loaderNormalize.call(loader, name, parentName, parentAddress))
      .then(function(name) {
        // if this is a plugin, normalize the plugin name and the argument
        var pluginIndex = name.lastIndexOf('!');
        if (pluginIndex != -1) {
          var argumentName = name.substr(0, pluginIndex);
  
          // plugin name is part after "!" or the extension itself
          var pluginName = name.substr(pluginIndex + 1) || argumentName.substr(argumentName.lastIndexOf('.') + 1);
  
          // normalize the plugin name relative to the same parent
          return new Promise(function(resolve) {
            resolve(loader.normalize(pluginName, parentName, parentAddress));
          })
          // normalize the plugin argument
          .then(function(_pluginName) {
            pluginName = _pluginName;
            return loader.normalize(argumentName, parentName, parentAddress, true);
          })
          .then(function(argumentName) {
            return argumentName + '!' + pluginName;
          });
        }
  
        // standard normalization
        return name;
      });
    };
  
    var loaderLocate = loader.locate;
    loader.locate = function(load) {
      var loader = this;
  
      var name = load.name;
  
      // only fetch the plugin itself if this name isn't defined
      if (this.defined && this.defined[name])
        return loaderLocate.call(this, load);
  
      // plugin
      var pluginIndex = name.lastIndexOf('!');
      if (pluginIndex != -1) {
        var pluginName = name.substr(pluginIndex + 1);
  
        // the name to locate is the plugin argument only
        load.name = name.substr(0, pluginIndex);
  
        var pluginLoader = loader.pluginLoader || loader;
  
        // load the plugin module
        // NB ideally should use pluginLoader.load for normalized,
        //    but not currently working for some reason
        return pluginLoader['import'](pluginName)
        .then(function() {
          var plugin = pluginLoader.get(pluginName);
          plugin = plugin['default'] || plugin;
  
          // allow plugins to opt-out of build
          if (plugin.build === false && loader.pluginLoader)
            load.metadata.build = false;
  
          // store the plugin module itself on the metadata
          load.metadata.plugin = plugin;
          load.metadata.pluginName = pluginName;
          load.metadata.pluginArgument = load.name;
          load.metadata.buildType = plugin.buildType || "js";
  
          // run plugin locate if given
          if (plugin.locate)
            return plugin.locate.call(loader, load);
  
          // otherwise use standard locate without '.js' extension adding
          else
            return Promise.resolve(loader.locate(load))
            .then(function(address) {
              return address.replace(/\.js$/, '');
            });
        });
      }
  
      return loaderLocate.call(this, load);
    };
  
    var loaderFetch = loader.fetch;
    loader.fetch = function(load) {
      var loader = this;
      // ignore fetching build = false unless in a plugin loader
      if (load.metadata.build === false && loader.pluginLoader)
        return '';
      else if (load.metadata.plugin && load.metadata.plugin.fetch && !load.metadata.pluginFetchCalled) {
        load.metadata.pluginFetchCalled = true;
        return load.metadata.plugin.fetch.call(loader, load, loaderFetch);
      }
      else
        return loaderFetch.call(loader, load);
    };
  
    var loaderTranslate = loader.translate;
    loader.translate = function(load) {
      var loader = this;
      if (load.metadata.plugin && load.metadata.plugin.translate)
        return Promise.resolve(load.metadata.plugin.translate.call(loader, load)).then(function(result) {
          if (typeof result == 'string')
            load.source = result;
          return loaderTranslate.call(loader, load);
        });
      else
        return loaderTranslate.call(loader, load);
    };
  
    var loaderInstantiate = loader.instantiate;
    loader.instantiate = function(load) {
      var loader = this;
      if (load.metadata.plugin && load.metadata.plugin.instantiate)
         return Promise.resolve(load.metadata.plugin.instantiate.call(loader, load)).then(function(result) {
          if (result) {
            // load.metadata.format = 'defined';
            // load.metadata.execute = function() {
            //   return result;
            // };
            return result;
          }
          return loaderInstantiate.call(loader, load);
        });
      else if (load.metadata.plugin && load.metadata.plugin.build === false) {
        load.metadata.format = 'defined';
        load.metadata.deps.push(load.metadata.pluginName);
        load.metadata.execute = function() {
          return loader.newModule({});
        };
        return loaderInstantiate.call(loader, load);
      }
      else
        return loaderInstantiate.call(loader, load);
    }
  
  }
  /*
    System bundles
  
    Allows a bundle module to be specified which will be dynamically 
    loaded before trying to load a given module.
  
    For example:
    System.bundles['mybundle'] = ['jquery', 'bootstrap/js/bootstrap']
  
    Will result in a load to "mybundle" whenever a load to "jquery"
    or "bootstrap/js/bootstrap" is made.
  
    In this way, the bundle becomes the request that provides the module
  */
  
  function bundles(loader) {
    if (typeof indexOf == 'undefined')
      indexOf = Array.prototype.indexOf;
  
    loader._extensions.push(bundles);
  
    // bundles support (just like RequireJS)
    // bundle name is module name of bundle itself
    // bundle is array of modules defined by the bundle
    // when a module in the bundle is requested, the bundle is loaded instead
    // of the form System.bundles['mybundle'] = ['jquery', 'bootstrap/js/bootstrap']
    loader.bundles = loader.bundles || {};
  
    var loaderFetch = loader.fetch;
    loader.fetch = function(load) {
      var loader = this;
      if (loader.trace)
        return loaderFetch.call(this, load);
      if (!loader.bundles)
        loader.bundles = {};
  
      // if this module is in a bundle, load the bundle first then
      for (var b in loader.bundles) {
        if (indexOf.call(loader.bundles[b], load.name) == -1)
          continue;
        // we do manual normalization in case the bundle is mapped
        // this is so we can still know the normalized name is a bundle
        return Promise.resolve(loader.normalize(b))
        .then(function(normalized) {
          loader.bundles[normalized] = loader.bundles[normalized] || loader.bundles[b];
  
          // note this module is a bundle in the meta
          loader.meta = loader.meta || {};
          loader.meta[normalized] = loader.meta[normalized] || {};
          loader.meta[normalized].bundle = true;
  
          return loader.load(normalized);
        })
        .then(function() {
          return '';
        });
      }
      return loaderFetch.call(this, load);
    }
  }
  /*
   * Dependency Tree Cache
   * 
   * Allows a build to pre-populate a dependency trace tree on the loader of 
   * the expected dependency tree, to be loaded upfront when requesting the
   * module, avoinding the n round trips latency of module loading, where 
   * n is the dependency tree depth.
   *
   * eg:
   * System.depCache = {
   *  'app': ['normalized', 'deps'],
   *  'normalized': ['another'],
   *  'deps': ['tree']
   * };
   * 
   * System.import('app') 
   * // simultaneously starts loading all of:
   * // 'normalized', 'deps', 'another', 'tree'
   * // before "app" source is even loaded
   */
  
  function depCache(loader) {
    loader.depCache = loader.depCache || {};
  
    loader._extensions.push(depCache);
  
    var loaderLocate = loader.locate;
    loader.locate = function(load) {
      var loader = this;
  
      if (!loader.depCache)
        loader.depCache = {};
  
      // load direct deps, in turn will pick up their trace trees
      var deps = loader.depCache[load.name];
      if (deps)
        for (var i = 0; i < deps.length; i++)
          loader.load(deps[i]);
  
      return loaderLocate.call(loader, load);
    }
  }
    
  core(System);
  meta(System);
  register(System);
  es6(System);
  global(System);
  cjs(System);
  amd(System);
  map(System);
  plugins(System);
  bundles(System);
  depCache(System);
  
  };
  
  var $__curScript, __eval;
  
  (function() {
  
    var doEval;
  
    __eval = function(source, address, sourceMap) {
      source += '\n//# sourceURL=' + address + (sourceMap ? '\n//# sourceMappingURL=' + sourceMap : '');
  
      try {
        doEval(source);
      }
      catch(e) {
        var msg = 'Error evaluating ' + address + '\n';
        if (e instanceof Error)
          e.message = msg + e.message;
        else
          e = msg + e;
        throw e;
      }
    };
  
    if (typeof document != 'undefined') {
      var head;
  
      var scripts = document.getElementsByTagName('script');
      $__curScript = scripts[scripts.length - 1];
  
      // globally scoped eval for the browser
      doEval = function(source) {
        if (!head)
          head = document.head || document.body || document.documentElement;
  
        var script = document.createElement('script');
        script.text = source;
        var onerror = window.onerror;
        var e;
        window.onerror = function(_e) {
          e = _e;
        }
        head.appendChild(script);
        head.removeChild(script);
        window.onerror = onerror;
        if (e)
          throw e;
      }
  
      if (!$__global.System || !$__global.LoaderPolyfill) {
        // determine the current script path as the base path
        var curPath = $__curScript.src;
        var basePath = curPath.substr(0, curPath.lastIndexOf('/') + 1);
        document.write(
          '<' + 'script type="text/javascript" src="' + basePath + 'steal-es6-module-loader.js" data-init="upgradeSystemLoader">' + '<' + '/script>'
        );
      }
      else {
        $__global.upgradeSystemLoader();
      }
    }
    else if (typeof WorkerGlobalScope != 'undefined' && typeof importScripts != 'undefined') {
      doEval = function(source) {
        try {
          eval(source);
        } catch(e) {
          throw e;
        }
      };
  
      if (!$__global.System || !$__global.LoaderPolyfill) {
        var basePath = '';
        try {
          throw new Error('Get worker base path via error stack');
        } catch (e) {
          e.stack.replace(/(?:at|@).*(http.+):[\d]+:[\d]+/, function (m, url) {
            basePath = url.replace(/\/[^\/]*$/, '/');
          });
        }
        importScripts(basePath + 'steal-es6-module-loader.js');
        $__global.upgradeSystemLoader();
      } else {
        $__global.upgradeSystemLoader();
      }
    }
    else {
      var es6ModuleLoader = require('steal-es6-module-loader');
      $__global.System = es6ModuleLoader.System;
      $__global.Loader = es6ModuleLoader.Loader;
      $__global.upgradeSystemLoader();
      module.exports = $__global.System;
  
      // global scoped eval for node
      var vm = require('vm');
      doEval = function(source, address, sourceMap) {
        vm.runInThisContext(source);
      }
    }
  })();
  
  })(typeof window != 'undefined' ? window : (typeof WorkerGlobalScope != 'undefined' ? self : global));
  
  (function(global){
  
  	// helpers
  	var camelize = function(str){
  		return str.replace(/-+(.)?/g, function(match, chr){ 
  			return chr ? chr.toUpperCase() : '' 
  		});
  	},
  		each = function( o, cb){
  			var i, len;
  
  			// weak array detection, but we only use this internally so don't
  			// pass it weird stuff
  			if ( typeof o.length == 'number' && (o.length - 1) in o) {
  				for ( i = 0, len = o.length; i < len; i++ ) {
  					cb.call(o[i], o[i], i, o);
  				}
  			} else {
  				for ( i in o ) {
  					if(o.hasOwnProperty(i)){
  						cb.call(o[i], o[i], i, o);
  					}
  				}
  			}
  			return o;
  		},
  		map = function(o, cb) {
  			var arr = [];
  			each(o, function(item, i){
  				arr[i] = cb(item, i);
  			});
  			return arr;
  		},
  		isString = function(o) {
  			return typeof o == "string";
  		},
  		extend = function(d,s){
  			each(s, function(v, p){
  				d[p] = v;
  			});
  			return d;
  		},
  		dir = function(uri){
  			var lastSlash = uri.lastIndexOf("/");
  			//if no / slashes, check for \ slashes since it might be a windows path
  			if(lastSlash === -1)
  				lastSlash = uri.lastIndexOf("\\");
  			if(lastSlash !== -1) {
  				return uri.substr(0, lastSlash);
  			} else {
  				return uri;
  			}
  		},
  		last = function(arr){
  			return arr[arr.length - 1];
  		},
  		parseURI = function(url) {
  			var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);
  				// authority = '//' + user + ':' + pass '@' + hostname + ':' port
  				return (m ? {
  				href     : m[0] || '',
  				protocol : m[1] || '',
  				authority: m[2] || '',
  				host     : m[3] || '',
  				hostname : m[4] || '',
  				port     : m[5] || '',
  				pathname : m[6] || '',
  				search   : m[7] || '',
  				hash     : m[8] || ''
  			} : null);
  		},
  		joinURIs = function(base, href) {
  			function removeDotSegments(input) {
  				var output = [];
  				input.replace(/^(\.\.?(\/|$))+/, '')
  					.replace(/\/(\.(\/|$))+/g, '/')
  					.replace(/\/\.\.$/, '/../')
  					.replace(/\/?[^\/]*/g, function (p) {
  						if (p === '/..') {
  							output.pop();
  						} else {
  							output.push(p);
  						}
  					});
  				return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : '');
  			}
  
  			href = parseURI(href || '');
  			base = parseURI(base || '');
  
  			return !href || !base ? null : (href.protocol || base.protocol) +
  				(href.protocol || href.authority ? href.authority : base.authority) +
  				removeDotSegments(href.protocol || href.authority || href.pathname.charAt(0) === '/' ? href.pathname : (href.pathname ? ((base.authority && !base.pathname ? '/' : '') + base.pathname.slice(0, base.pathname.lastIndexOf('/') + 1) + href.pathname) : base.pathname)) +
  					(href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) +
  					href.hash;
  		},
  		isWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope,
  		isBrowserWithWindow = typeof window !== "undefined",
  		isNode = !isBrowserWithWindow && !isWebWorker && typeof require != 'undefined';
  
  	var filename = function(uri){
  		var lastSlash = uri.lastIndexOf("/");
  		//if no / slashes, check for \ slashes since it might be a windows path
  		if(lastSlash === -1)
  			lastSlash = uri.lastIndexOf("\\");
  		var matches = ( lastSlash == -1 ? uri : uri.substr(lastSlash+1) ).match(/^[\w-\s\.!]+/);
  		return matches ? matches[0] : "";
  	};
  	
  	var ext = function(uri){
  		var fn = filename(uri);
  		var dot = fn.lastIndexOf(".");
  		if(dot !== -1) {
  			return fn.substr(dot+1);
  		} else {
  			return "";
  		}
  	};
  
  	var pluginCache = {};
  	
  	var normalize = function(name, loader){
  
  		// Detech if this name contains a plugin part like: app.less!steal/less
  		// and catch the plugin name so that when it is normalized we do not perform
  		// Steal's normalization against it.
  		var pluginIndex = name.lastIndexOf('!');
  		var pluginPart = "";
  		if (pluginIndex != -1) {
  			// argumentName is the part before the !
  			var argumentName = name.substr(0, pluginIndex);
  			var pluginName = name.substr(pluginIndex + 1);
  			pluginPart = "!" + pluginName;
  
  			// Set the name to the argument name so that we can normalize it alone.
  			name = argumentName;
  		} 
  		
  		var last = filename(name),
  			extension = ext(name);
  		// if the name ends with /
  		if(	name[name.length -1] === "/" ) {
  			return name+filename( name.substr(0, name.length-1) ) + pluginPart;
  		} else if(	!/^(\w+(?:s)?:\/\/|\.|file|\/)/.test(name) &&
  			// and doesn't end with a dot
  			 last.indexOf(".") === -1 
  			) {
  			return name+"/"+last + pluginPart;
  		} else {
  			if(extension === "js") {
  				return name.substr(0, name.lastIndexOf(".")) + pluginPart;
  			} else {
  				return name + pluginPart;
  			}
  		}
  	};
  
  var cloneSteal = function(System){
  	var loader = System || this.System;
  	return makeSteal(this.addSteal(loader.clone()));
  };
  
  var makeSteal = function(System){
  
  	System.set('@loader', System.newModule({'default':System, __useDefault: true}));
  	System.config({
  		map: {
  			"@loader/@loader": "@loader",
  			"@steal/@steal": "@steal"
  		}
  	});
  
  	var configDeferred,
  		devDeferred,
  		appDeferred;
  
  	var steal = function(){
  		var args = arguments;
  		var afterConfig = function(){
  			var imports = [];
  			var factory;
  			each(args, function(arg){
  				if(isString(arg)) {
  					imports.push( steal.System['import']( normalize(arg) ) );
  				} else if(typeof arg === "function") {
  					factory = arg;
  				}
  			});
  
  			var modules = Promise.all(imports);
  			if(factory) {
  				return modules.then(function(modules) {
  			        return factory && factory.apply(null, modules);
  			   });
  			} else {
  				return modules;
  			}
  		};
  		if(System.isEnv("production")) {
  			return afterConfig();
  		} else {
  			// wait until the config has loaded
  			return configDeferred.then(afterConfig,afterConfig);
  		}
  
  	};
  
  	System.set("@steal", System.newModule({"default":steal, __useDefault:true}));
  
  	steal.System = System;
  	steal.parseURI = parseURI;
  	steal.joinURIs = joinURIs;
  	steal.normalize = normalize;
  
  	// System.ext = {bar: "path/to/bar"}
  	// foo.bar! -> foo.bar!path/to/bar
  	var addExt = function(loader) {
  
  		loader.ext = {};
  
  		var normalize = loader.normalize,
  			endingExtension = /\.(\w+)!?$/;
  
  		loader.normalize = function(name, parentName, parentAddress, pluginNormalize){
  			if(pluginNormalize) {
  				return normalize.apply(this, arguments);
  			}
  
  			var matches = name.match(endingExtension),
  				ext,
  				newName = name;
  
  			if(matches && loader.ext[ext = matches[1]]) {
  				var hasBang = name[name.length - 1] === "!";
  				newName = name + (hasBang ? "" : "!") + loader.ext[ext];
  			}
  			return normalize.call(this, newName, parentName, parentAddress);
  		};
  	};
  
  	if(typeof System){
  		addExt(System);
  	}
  
  
  
  	// "path/to/folder/" -> "path/to/folder/folder"
  	var addForwardSlash = function(loader) {
  		var normalize = loader.normalize;
  
  		var npmLike = /@.+#.+/;
  
  		loader.normalize = function(name, parentName, parentAddress, pluginNormalize) {
  			var lastPos = name.length - 1,
  				secondToLast,
  				folderName;
  
  			if (name[lastPos] === "/") {
  				secondToLast = name.substring(0, lastPos).lastIndexOf("/");
  				folderName = name.substring(secondToLast + 1, lastPos);
  				if(npmLike.test(folderName)) {
  					folderName = folderName.substr(folderName.lastIndexOf("#") + 1);
  				}
  
  				name += folderName;
  			}
  			return normalize.call(this, name, parentName, parentAddress, pluginNormalize);
  		};
  	};
  
  	if (typeof System) {
  		addForwardSlash(System);
  	}
  
  function applyTraceExtension(loader){
  	if(loader._extensions) {
  		loader._extensions.push(applyTraceExtension);
  	}
  
  	loader._traceData = {
  		loads: {},
  		parentMap: {}
  	};
  
  	loader.getDependencies = function(moduleName){
  		var load = this.getModuleLoad(moduleName);
  		return load ? load.metadata.dependencies : undefined;
  	};
  	loader.getDependants = function(moduleName){
  		var deps = [];
  		var pars = this._traceData.parentMap[moduleName] || {};
  		eachOf(pars, function(name) { deps.push(name); });
  		return deps;
  	};
  	loader.getModuleLoad = function(moduleName){
  		return this._traceData.loads[moduleName];
  	};
  	loader.getBundles = function(moduleName, visited){
  		visited = visited || {};
  		visited[moduleName] = true;
  		var loader = this;
  		var parentMap = loader._traceData.parentMap;
  		var parents = parentMap[moduleName];
  		if(!parents) return [moduleName];
  
  		var bundles = [];
  		eachOf(parents, function(parentName, value){
  			if(!visited[parentName])
  				bundles = bundles.concat(loader.getBundles(parentName, visited));
  		});
  		return bundles;
  	};
  	loader._allowModuleExecution = {};
  	loader.allowModuleExecution = function(name){
  		var loader = this;
  		return loader.normalize(name).then(function(name){
  			loader._allowModuleExecution[name] = true;
  		});
  	};
  
  	function eachOf(obj, callback){
  		var name, val;
  		for(name in obj) {
  			callback(name, obj[name]);
  		}
  	}
  
  	var normalize = loader.normalize;
  	loader.normalize = function(name, parentName){
  		var normalizePromise = normalize.apply(this, arguments);
  
  		if(parentName) {
  			var parentMap = this._traceData.parentMap;
  			return normalizePromise.then(function(name){
  				if(!parentMap[name]) {
  					parentMap[name] = {};
  				}
  				parentMap[name][parentName] = true;
  				return name;
  			});
  		}
  
  		return normalizePromise;
  	};
  
  	var emptyExecute = function(){
  		return loader.newModule({});
  	};
  
  
  	var passThroughModules = {
  		traceur: true,
  		babel: true
  	};
  	var isAllowedToExecute = function(load){
  		return passThroughModules[load.name] || this._allowModuleExecution[load.name];
  	};
  
  	var map = [].map || function(callback){
  		var res = [];
  		for(var i = 0, len = this.length; i < len; i++) {
  			res.push(callback(this[i]));
  		}
  		return res;
  	};
  
  	var transpiledDepsExp = /System\.register\((\[.+?\])\,/;
  	var singleQuoteExp = /'/g;
  	var instantiate = loader.instantiate;
  	loader.instantiate = function(load){
  		this._traceData.loads[load.name] = load;
  		var loader = this;
  		var instantiatePromise = Promise.resolve(instantiate.apply(this, arguments));
  
  		function finalizeResult(result){
  			var preventExecution = loader.preventModuleExecution &&
  				!isAllowedToExecute.call(loader, load);
  
  			// deps either comes from the instantiate result, or if an
  			// es6 module it was found in the transpile hook.
  			var deps = result ? result.deps : load.metadata.deps;
  
  			return Promise.all(map.call(deps, function(depName){
  				return loader.normalize(depName, load.name);
  			})).then(function(dependencies){
  				load.metadata.deps = deps;
  				load.metadata.dependencies = dependencies;
  
  				if(preventExecution) {
  					return {
  						deps: deps,
  						execute: emptyExecute
  					};
  				}
  
  				return result;
  
  			});
  		}
  
  		return instantiatePromise.then(function(result){
  			// This must be es6
  			if(!result) {
  				return loader.transpile(load).then(function(source){
  					load.metadata.transpiledSource = source;
  
  					var depsMatches = transpiledDepsExp.exec(source);
  					var depsSource = depsMatches ? depsMatches[1] : "[]";
  					var deps = JSON.parse(depsSource.replace(singleQuoteExp, '"'));
  					load.metadata.deps = deps;
  
  					return finalizeResult(result);
  				});
  			}
  			return finalizeResult(result);
  		});
  	};
  
  	var transpile = loader.transpile;
  	// Allow transpile to be memoized, but only once
  	loader.transpile = function(load){
  		var transpiled = load.metadata.transpiledSource;
  		if(transpiled) {
  			delete load.metadata.transpiledSource;
  			return Promise.resolve(transpiled);
  		}
  		return transpile.apply(this, arguments);
  	};
  }
  
  applyTraceExtension.name = "Trace";
  
  if(typeof System !== "undefined") {
  	applyTraceExtension(System);
  }
  
  /*
    SystemJS JSON Format
    Provides the JSON module format definition.
  */
  function _SYSTEM_addJSON(loader) {
  	var jsonTest = /^[\s\n\r]*[\{\[]/;
  	var jsonExt = /\.json$/i;
  	var jsExt = /\.js$/i;
  	var inNode = typeof window === "undefined";
  
  	// Add the extension to _extensions so that it can be cloned.
  	loader._extensions.push(_SYSTEM_addJSON);
  
  	// if someone has a moduleName that is .json, make sure it loads a json file
  	// no matter what paths might do
  	var loaderLocate = loader.locate;
  	loader.locate = function(load){
  	  return loaderLocate.apply(this, arguments).then(function(address){
  		if(jsonExt.test(load.name)) {
  			return address.replace(jsExt, "");
  		}
  
  	    return address;
  	  });
  	};
  
  	// If we are in a build we should convert to CommonJS instead.
  	if(inNode) {
  		var loaderTranslate = loader.translate;
  		loader.translate = function(load){
  			if(jsonExt.test(load.name)) {
  				var parsed = parse(load);
  				if(parsed) {
  					return "def" + "ine([], function(){\n" +
  						"\treturn " + load.source + "\n});";
  				}
  			}
  
  			return loaderTranslate.call(this, load);
  		};
  		return;
  	}
  
  	var loaderInstantiate = loader.instantiate;
  	loader.instantiate = function(load) {
  		var loader = this,
  			parsed;
  
  		parsed = parse(load);
  		if(parsed) {
  			load.metadata.format = 'json';
  
  			load.metadata.execute = function(){
  				return parsed;
  			};
  		}
  
  		return loaderInstantiate.call(loader, load);
  	};
  
  	return loader;
  
  	// Attempt to parse a load as json.
  	function parse(load){
  		if ( (load.metadata.format === 'json' || !load.metadata.format) && jsonTest.test(load.source)  ) {
  			try {
  				return JSON.parse(load.source);
  			} catch(e) {}
  		}
  
  	}
  }
  
  if (typeof System !== "undefined") {
  	_SYSTEM_addJSON(System);
  }
  
  	// Overwrites System.config with setter hooks
  	var setterConfig = function(loader, configSpecial){
  		var oldConfig = loader.config;
  
  		loader.config =  function(cfg){
  
  			var data = extend({},cfg);
  			// check each special
  			each(configSpecial, function(special, name){
  				// if there is a setter and a value
  				if(special.set && data[name]){
  					// call the setter
  					var res = special.set.call(loader,data[name], cfg);
  					// if the setter returns a value
  					if(res !== undefined) {
  						// set that on the loader
  						loader[name] = res;
  					}
  					// delete the property b/c setting is done
  					delete data[name];
  				}
  			});
  			oldConfig.call(this, data);
  		};
  	};
  
  	var setIfNotPresent = function(obj, prop, value){
  		if(!obj[prop]) {
  			obj[prop] = value;
  		}
  	};
  
  	// steal.js's default configuration values
  	System.configMain = "@config";
  	System.paths[System.configMain] = "stealconfig.js";
  	System.env = (isWebWorker ? "worker" : "window") + "-development";
  	System.ext = {
  		css: '$css',
  		less: '$less'
  	};
  	System.logLevel = 0;
  	var cssBundlesNameGlob = "bundles/*.css",
  		jsBundlesNameGlob = "bundles/*";
  	setIfNotPresent(System.paths,cssBundlesNameGlob, "dist/bundles/*css");
  	setIfNotPresent(System.paths,jsBundlesNameGlob, "dist/bundles/*.js");
  
  	var configSetter = {
  		set: function(val){
  			var name = filename(val),
  				root = dir(val);
  
  			if(!isNode) {
  				System.configPath = joinURIs( location.href, val);
  			}
  			System.configMain = name;
  			System.paths[name] = name;
  			addProductionBundles.call(this);
  			this.config({ baseURL: (root === val ? "." : root) + "/" });
  		}
  	},
  		mainSetter = {
  			set: function(val){
  				this.main = val;
  				addProductionBundles.call(this);
  			}
  		};
  
  	// checks if we're running in node, then prepends the "file:" protocol if we are
  	var envPath = function(val) {
  		if(isNode && !/^file:/.test(val)) {
  			// If relative join with the current working directory
  			if(val[0] === "." && (val[1] === "/" ||
  								 (val[1] === "." && val[2] === "/"))) {
  				val = require("path").join(process.cwd(), val);
  			}
  			if(!val) return val;
  
  			return "file:" + val;
  		}
  		return val;
  	};
  
  	var fileSetter = function(prop) {
  		return {
  			set: function(val) {
  				this[prop] = envPath(val);
  			}
  		};
  	};
  
  	var setToSystem = function(prop){
  		return {
  			set: function(val){
  				if(typeof val === "object" && typeof steal.System[prop] === "object") {
  					this[prop] = extend(this[prop] || {},val || {});
  				} else {
  					this[prop] = val;
  				}
  			}
  		};
  	};
  
  	var pluginPart = function(name) {
  		var bang = name.lastIndexOf("!");
  		if(bang !== -1) {
  			return name.substr(bang+1);
  		}
  	};
  	var pluginResource = function(name){
  		var bang = name.lastIndexOf("!");
  		if(bang !== -1) {
  			return name.substr(0, bang);
  		}
  	};
  
  	var addProductionBundles = function(){
  		if(this.loadBundles && this.main) {
  			var main = this.main,
  				bundlesDir = this.bundlesName || "bundles/",
  				mainBundleName = bundlesDir+main;
  
  			setIfNotPresent(this.meta, mainBundleName, {format:"amd"});
  
  			// If the configMain has a plugin like package.json!npm,
  			// plugin has to be defined prior to importing.
  			var plugin = pluginPart(System.configMain);
  			var bundle = [main, System.configMain];
  			if(plugin){
  				System.set(plugin, System.newModule({}));
  			}
  			plugin = pluginPart(main);
  			if(plugin) {
  				var resource = pluginResource(main);
  				bundle.push(plugin);
  				bundle.push(resource);
  
  				mainBundleName = bundlesDir+resource.substr(0, resource.indexOf("."));
  			}
  
  			this.bundles[mainBundleName] = bundle;
  		}
  	};
  
  	var setEnvsConfig = function(){
  		if(this.envs) {
  			var envConfig = this.envs[this.env];
  			if(envConfig) {
  				this.config(envConfig);
  			}
  		}
  	};
  
  	var LESS_ENGINE = "less-2.4.0";
  	var specialConfig;
  	var envsSpecial = { map: true, paths: true, meta: true };
  	setterConfig(System, specialConfig = {
  		env: {
  			set: function(val){
  				this.env = val;
  
  				if(this.isEnv("production")) {
  					this.loadBundles = true;
  				}
  
  				addProductionBundles.call(this);
  			}
  		},
  		envs: {
  			set: function(val){
  				// envs should be set, deep
  				var envs = this.envs;
  				if(!envs) envs = this.envs = {};
  				each(val, function(cfg, name){
  					var env = envs[name];
  					if(!env) env = envs[name] = {};
  
  					each(cfg, function(val, name){
  						if(envsSpecial[name] && env[name]) {
  							extend(env[name], val);
  						} else {
  							env[name] = val;
  						}
  					});
  
  					//extend(env, cfg);
  				});
  			}
  		},
  		baseUrl: fileSetter("baseURL"),
  		baseURL: fileSetter("baseURL"),
  		root: fileSetter("baseURL"),  //backwards comp
  		config: configSetter,
  		configPath: configSetter,
  		loadBundles: {
  			set: function(val){
  				this.loadBundles = val;
  				addProductionBundles.call(this);
  			}
  		},
  		startId: {
  			set: function(val){
  				mainSetter.set.call(this, normalize(val) );
  			}
  		},
  		main: mainSetter,
  		stealURL: {
  			// http://domain.com/steal/steal.js?moduleName,env&
  			set: function(url, cfg)	{
  				System.stealURL = url;
  				var urlParts = url.split("?");
  
  				var path = urlParts.shift(),
  					search = urlParts.join("?"),
  					searchParts = search.split("&"),
  					paths = path.split("/"),
  					lastPart = paths.pop(),
  					stealPath = paths.join("/");
  
  				specialConfig.stealPath.set.call(this,stealPath, cfg);
  
  				if (lastPart.indexOf("steal.production") > -1 && !cfg.env) {
  					var platform = this.getPlatform() || (isWebWorker ? "worker" : "window");
  					this.config({ env: platform+"-production" });
  					addProductionBundles.call(this);
  				}
  
  				if(searchParts.length && searchParts[0].length) {
  					var searchConfig = {},
  						searchPart;
  					for(var i =0; i < searchParts.length; i++) {
  						searchPart = searchParts[i];
  						var paramParts = searchPart.split("=");
  						if(paramParts.length > 1) {
  							searchConfig[paramParts[0]] = paramParts.slice(1).join("=");
  						} else {
  							if(steal.dev) {
  								steal.dev.warn("Please use search params like ?main=main&env=production");
  							}
  							var oldParamParts = searchPart.split(",");
  							if (oldParamParts[0]) {
  								searchConfig.startId = oldParamParts[0];
  							}
  							if (oldParamParts[1]) {
  								searchConfig.env = oldParamParts[1];
  							}
  						}
  					}
  					this.config(searchConfig);
  				}
  
  				// Split on / to get rootUrl
  
  
  
  
  			}
  		},
  		// this gets called with the __dirname steal is in
  		stealPath: {
  			set: function(dirname, cfg) {
  				dirname = envPath(dirname);
  				var parts = dirname.split("/");
  
  				// steal keeps this around to make things easy no matter how you are using it.
  				setIfNotPresent(this.paths,"@dev", dirname+"/ext/dev.js");
  				setIfNotPresent(this.paths,"$css", dirname+"/ext/css.js");
  				setIfNotPresent(this.paths,"$less", dirname+"/ext/less.js");
  				setIfNotPresent(this.paths,"npm", dirname+"/ext/npm.js");
  				setIfNotPresent(this.paths,"npm-extension", dirname+"/ext/npm-extension.js");
  				setIfNotPresent(this.paths,"npm-utils", dirname+"/ext/npm-utils.js");
  				setIfNotPresent(this.paths,"npm-crawl", dirname+"/ext/npm-crawl.js");
  				setIfNotPresent(this.paths,"semver", dirname+"/ext/semver.js");
  				setIfNotPresent(this.paths,"bower", dirname+"/ext/bower.js");
  				setIfNotPresent(this.paths,"live-reload", dirname+"/ext/live-reload.js");
  				this.paths["traceur"] = dirname+"/ext/traceur.js";
  				this.paths["traceur-runtime"] = dirname+"/ext/traceur-runtime.js";
  				this.paths["babel"] = dirname+"/ext/babel.js";
  				this.paths["babel-runtime"] = dirname+"/ext/babel-runtime.js";
  
  				if(isNode) {
  					System.register("less",[], false, function(){
  						var r = require;
  						return r('less');
  					});
  
  					if(this.configMain === "@config" && last(parts) === "steal") {
  						parts.pop();
  						if(last(parts) === "node_modules") {
  							this.configMain = "package.json!npm";
  							addProductionBundles.call(this);
  							parts.pop();
  						}
  					}
  
  				} else {
  					setIfNotPresent(this.paths, "less", dirname + "/ext/less-engine.js");
  
  					// make sure we don't set baseURL if something else is going to set it
  					if(!cfg.root && !cfg.baseUrl && !cfg.baseURL && !cfg.config && !cfg.configPath ) {
  						if ( last(parts) === "steal" ) {
  							parts.pop();
  							if ( last(parts) === "bower_components" ) {
  								System.configMain = "bower.json!bower";
  								addProductionBundles.call(this);
  								parts.pop();
  							}
  							if (last(parts) === "node_modules") {
  								System.configMain = "package.json!npm";
  								addProductionBundles.call(this);
  								parts.pop();
  							}
  						}
  						this.config({ baseURL: parts.join("/")+"/"});
  					}
  				}
  				System.stealPath = dirname;
  			}
  		},
  		// System.config does not like being passed arrays.
  		bundle: {
  			set: function(val){
  				System.bundle = val;
  			}
  		},
  		bundlesPath: {
  			set: function(val){
  				this.paths[cssBundlesNameGlob] = val+"/*css";
  				this.paths[jsBundlesNameGlob]  = val+"/*.js";
  				return val;
  			}
  		},
  		instantiated: {
  			set: function(val){
  				var loader = this;
  
  				each(val || {}, function(value, name){
  					loader.set(name,  loader.newModule(value));
  				});
  			}
  		}
  	});
  
  	steal.config = function(cfg){
  		if(typeof cfg === "string") {
  			return System[cfg];
  		} else {
  			System.config(cfg);
  		}
  	};
  
  
  if(typeof System !== "undefined") {
  	addEnv(System);
  }
  
  function addEnv(loader){
  	// Add the extension to _extensions so that it can be cloned.
  	loader._extensions.push(addEnv);
  
  	loader.getEnv = function(){
  		var envParts = (this.env || "").split("-");
  		// Fallback to this.env for legacy
  		return envParts[1] || this.env;
  	};
  	loader.getPlatform = function(){
  		var envParts = (this.env || "").split("-");
  		return envParts.length === 2 ? envParts[0] : undefined;
  	};
  
  	loader.isEnv = function(name){
  		return this.getEnv() === name;
  	};
  
  	loader.isPlatform = function(name){
  		return this.getPlatform() === name;
  	};
  }
  
  	var getScriptOptions = function () {
  
  		var options = {},
  			parts, src, query, startFile, env,
  			scripts = document.getElementsByTagName("script");
  
  		var script = scripts[scripts.length - 1];
  
  		if (script) {
  			options.stealURL = script.src;
  			// Split on question mark to get query
  
  			each(script.attributes, function(attr){
  				var optionName =
  					camelize( attr.nodeName.indexOf("data-") === 0 ?
  						attr.nodeName.replace("data-","") :
  						attr.nodeName );
  				options[optionName] = (attr.value === "") ? true : attr.value;
  			});
  
  			var source = script.innerHTML.substr(1);
  			if(/\S/.test(source)){
  				options.mainSource = source;
  			}
  		}
  
  		return options;
  	};
  
  	steal.startup = function(config){
  
  		// Get options from the script tag
  		if (isWebWorker) {
  			var urlOptions = {
  				stealURL: location.href
  			};
  		} else if(global.document) {
  			var urlOptions = getScriptOptions();
  		} else {
  			// or the only option is where steal is.
  			var urlOptions = {
  				stealPath: __dirname
  			};
  		}
  
  		// B: DO THINGS WITH OPTIONS
  		// CALCULATE CURRENT LOCATION OF THINGS ...
  		System.config(urlOptions);
  
  		if(config){
  			System.config(config);
  		}
  
  		setEnvsConfig.call(this.System);
  
  		// Read the env now because we can't overwrite everything yet
  
  		// immediate steals we do
  		var steals = [];
  
  		// we only load things with force = true
  		if ( System.loadBundles ) {
  
  			configDeferred = System["import"](System.configMain);
  
  			appDeferred = configDeferred.then(function(cfg){
  				setEnvsConfig.call(System);
  				return System.main ? System["import"](System.main) : cfg;
  			})["catch"](function(e){
  				console.log(e);
  			});
  
  		} else {
  			configDeferred = System["import"](System.configMain);
  
  			devDeferred = configDeferred.then(function(){
  				setEnvsConfig.call(System);
  
  				// If a configuration was passed to startup we'll use that to overwrite
  				// what was loaded in stealconfig.js
  				// This means we call it twice, but that's ok
  				if(config) {
  					System.config(config);
  				}
  
  				return System["import"]("@dev");
  			},function(e){
  				console.log("steal - error loading @config.",e);
  				return steal.System["import"]("@dev");
  			});
  
  			appDeferred = devDeferred.then(function(){
  				// if there's a main, get it, otherwise, we are just loading
  				// the config.
  				if(!System.main || System.env === "build") {
  					return configDeferred;
  				}
  				var main = System.main;
  				if(typeof main === "string") {
  					main = [main];
  				}
  				return Promise.all( map(main,function(main){
  					return System["import"](main);
  				}) );
  			});
  
  		}
  
  		if(System.mainSource) {
  			appDeferred = appDeferred.then(function(){
  				System.module(System.mainSource);
  			});
  		}
  		return appDeferred;
  	};
  	steal.done = function(){
  		return appDeferred;
  	};
  
  	steal["import"] = function(){
  		var names = arguments;
  		var loader = this.System;
  
  		function afterConfig(){
  			var imports = [];
  			each(names, function(name){
  				imports.push(loader["import"](name));
  			});
  			if(imports.length > 1) {
  				return Promise.all(imports);
  			} else {
  				return imports[0];
  			}
  		}
  
  		if(!configDeferred) {
  			steal.startup();
  		}
  
  		return configDeferred.then(afterConfig);
  	};
  	return steal;
  
  };
  /*
    SystemJS Steal Format
    Provides the Steal module format definition.
  */
  function addSteal(loader) {
  
    // Steal Module Format Detection RegEx
    // steal(module, ...)
    var stealRegEx = /(?:^\s*|[}{\(\);,\n\?\&]\s*)steal\s*\(\s*((?:"[^"]+"\s*,|'[^']+'\s*,\s*)*)/;
  
    // What we stole.
    var stealInstantiateResult;
    
    function createSteal(loader) {
      stealInstantiateResult = null;
  
      // ensure no NodeJS environment detection
      loader.global.module = undefined;
      loader.global.exports = undefined;
  
      function steal() {
        var deps = [];
        var factory;
        
        for( var i = 0; i < arguments.length; i++ ) {
          if (typeof arguments[i] === 'string') {
            deps.push( normalize(arguments[i]) );
          } else {
            factory = arguments[i];
          }
        }
  
        if (typeof factory !== 'function') {
          factory = (function(factory) {
            return function() { return factory; };
          })(factory);
        }
  
        stealInstantiateResult = {
          deps: deps,
          execute: function(require, exports, moduleName) {
  
            var depValues = [];
            for (var i = 0; i < deps.length; i++) {
              depValues.push(require(deps[i]));
            }
  
            var output = factory.apply(loader.global, depValues);
  
            if (typeof output !== 'undefined') {
              return output;
            }
          }
        };
      }
  
      loader.global.steal = steal;
    }
  
    var loaderInstantiate = loader.instantiate;
    loader.instantiate = function(load) {
      var loader = this;
  
      if (load.metadata.format === 'steal' || !load.metadata.format && load.source.match(stealRegEx)) {
        load.metadata.format = 'steal';
  
        var oldSteal = loader.global.steal;
  
        createSteal(loader);
  
        loader.__exec(load);
  
        loader.global.steal = oldSteal;
  
        if (!stealInstantiateResult) {
          throw "Steal module " + load.name + " did not call steal";
        }
  
        if (stealInstantiateResult) {
          load.metadata.deps = load.metadata.deps ? load.metadata.deps.concat(stealInstantiateResult.deps) : stealInstantiateResult.deps;
          load.metadata.execute = stealInstantiateResult.execute;
        }
      }
      return loaderInstantiate.call(loader, load);
    };
  
    return loader;
  }
  
  if (typeof System !== "undefined") {
    addSteal(System);
  }
  
  	if( isNode ) {
  		require('steal-systemjs');
  
  		global.steal = makeSteal(System);
  		global.steal.System = System;
  		global.steal.dev = require("./ext/dev.js");
  		steal.clone = cloneSteal;
  		module.exports = global.steal;
  		global.steal.addSteal = addSteal;
  		require("system-json");
  
  	} else {
  		var oldSteal = global.steal;
  		global.steal = makeSteal(System);
  		global.steal.startup(oldSteal && typeof oldSteal == 'object' && oldSteal)
  			.then(null, function(error){
  				console.log("error",error,  error.stack);
  				throw error;
  			});
  		global.steal.clone = cloneSteal;
  		global.steal.addSteal = addSteal;
  	}
  
  })(typeof window == "undefined" ? (typeof global === "undefined" ? this : global) : window);
  