text: (function (scope) {
  var ephox = scope.ephox = scope.ephox || {};
  var bolt = ephox.bolt = ephox.bolt || {};
  
  var def = function (deps, factory) {
      return factory.apply(null, deps);
  };
  var kernel = bolt.kernel = bolt.kernel || {};
  kernel.api = kernel.api || {};
  kernel.async = kernel.api || {};
  kernel.fp = kernel.fp || {};
  kernel.modulator = kernel.modulator || {};
  kernel.module = kernel.module || {};
  kernel.fp.array = def(
    [
    ],
  
    function () {
      var equals = function (a1, a2) {
        if (a1.length !== a2.length)
          return false;
        for (var i = 0; i < a1.length; ++i)
          if (a1[i] !== a2[i])
            return false;
        return true;
      };
  
      var forall = function (a, f) {
        var fn = f || function (x) {
          return x === true;
        };
        for (var i = 0; i < a.length; ++i)
          if (fn(a[i]) !== true)
            return false;
        return true;
      };
  
      var map = function (a, f) {
        var r = [];
        for (var i = 0; i < a.length; ++i)
          r.push(f(a[i], i));
        return r;
      };
  
      var flatten = function (a) {
        var r = [];
        for (var i = 0; i < a.length; ++i)
          r = r.concat(a[i]);
        return r;
      };
  
      var flatmap = function (a, f) {
        return flatten(map(a, f));
      };
  
      var filter = function (a, f) {
        var r = [];
        for (var i = 0; i < a.length; ++i)
          if (f(a[i]))
            r.push(a[i]);
        return r;
      };
  
      var each = map;
  
      var contains = function (a, x) {
        return !forall(a, function (v) {
          return v !== x;
        });
      };
  
      var indexof = function (a, x) {
        for (var i = 0; i < a.length; ++i)
          if (a[i] === x)
            return i;
        return -1;
      };
  
      return {
        equals: equals,
        forall: forall,
        map: map,
        flatten: flatten,
        flatmap: flatmap,
        filter: filter,
        each: each,
        contains: contains,
        indexof: indexof
      };
    }
  );
  kernel.fp.object = def(
    [
    ],
  
    function () {
      var map = function (o, f) {
        var r = {};
        for (var i in o)
          if (o.hasOwnProperty(i))
            r[i] = f(i, o[i]);
        return r;
      };
  
      var each = map;
  
      var merge = function (d, s) {
        each(s, function (k, v) {
          d[k] = v;
        });
      };
  
      var keys = function (o) {
        var r = [];
        each(o, function (k) {
          r.push(k);
        });
        return r;
      };
  
      return {
        each: each,
        keys: keys,
        map: map,
        merge: merge
      };
    }
  );
  kernel.fp.functions = def(
    [
    ],
  
    function () {
      var curry = function (f) {
        var slice = Array.prototype.slice;
        var args = slice.call(arguments, 1);
        return function () {
          var all = args.concat(slice.call(arguments, 0));
          return f.apply(null, all);
        };
      };
  
      var not = function (z) {
        return function () {
          var slice = Array.prototype.slice;
          return !z.apply(null, slice.call(arguments, 0));
        };
      };
  
      var apply = function (f) {
        var slice = Array.prototype.slice;
        return f.apply(null, slice.call(arguments, 0));
      };
  
      return {
        curry: curry,
        not: not,
        apply: apply
      };
    }
  );kernel.async.map = def(
    [
      kernel.fp.array
    ],
  
    function (ar) {
      var amap = function (data, f, oncomplete) {
        var total = data.length;
        var count = 0;
        var results = [];
  
        ar.each(data, function (datum, i) {
          f(datum, function (result) {
            ++count;
            results[i] = result;
            if (count === total)
              oncomplete(results);
          });
        });
      };
  
      return {
        amap: amap
      };
    }
  );
  /**
   * This module has a dual responsibility:
   *  1. Ensures that asynchronous function calls, 'f', that share the same
   *     'key' are not executed in parallel.
   *  2. In the case where an attempt to call in parallel is prevented,
   *     the 'action' callbacks are executed when the asynchronous call is
   *     completed.
   *
   * Example:
   *  When we async-map to remotely fetch module definition, it is
   *  important that only a single define is evaluated, but the
   *  notification that the definition has completed is propagated
   *  to all interested parties.
   *
   *    1. we require dependencies 'x' and 'y'
   *
   *    2. both x and y are defined in the same file  (i.e. compiled together), 'a.js'.
   *
   *    3. we resolve x and y, to their load spec using a modulator
   *        x_spec = {load: function () { -- load a.js -- }, url: a.js, serial: false};
   *        y_spec = {load: function () { -- load a.js -- }, url: a.js, serial: false};
   *
   *    4. we make the piggyback call for x:
   *        piggybacker.piggyback(x_spec.url, x_spec.load, xdone);
   *
   *       this will register the 'xdone' action, and actually
   *       trigger the load call, with a synthetic callback
   *       responsible for triggering all registered actions.
   *
   *    5. we make the piggyback call for y:
   *        piggybacker.piggyback(y_spec.url, y_spec.load, ydone);
   *
   *       this will register the 'ydone' action, but NOT trigger
   *       the load call.
   *
   *    6. the load call completes, and calls the synthetic callback,
   *       which is responsible for triggering both 'xdone' and 'ydone'.
   *
   *    7. something else happens that means we have to load 'a.js' again,
   *       the piggybacker DOES NOT prevent this call, and will follow
   *       the above process.
   */
  kernel.async.piggybacker = def(
    [
      kernel.fp.array,
      kernel.fp.functions
    ],
  
    function (ar, fn) {
      var create = function () {
        var queue = {};  // key -> [actions]
  
        var process = function (key) {
          var actions = queue[key];
          delete queue[key];
          ar.each(actions, fn.apply);
        };
  
        var piggyback = function (key, f, action) {
          if (queue[key] === undefined) {
            queue[key] = [ action ];
            f(fn.curry(process, key));
          } else {
            queue[key].push(action);
          }
        };
  
        return {
          piggyback: piggyback
        };
      };
  
      return {
        create: create
      };
    }
  );
  kernel.modulator.globalator = def(
    [
    ],
  
    function () {
      var create = function () {
        // FIX pull out
        var resolve = function (name, scope) {
          var parts = name.split('.');
          var r = scope;
          for (var i = 0; i < parts.length && r !== undefined; ++i)
            r = r[parts[i]];
          return r;
        };
  
        var global = Function('return this')();
  
        var can = function (id) {
          return id.indexOf('global!') === 0;
        };
  
        var get = function (id, define, require) {
          var name = id.substring('global!'.length);
  
          var load = function (onsuccess, onfailure) {
            var instance = resolve(name, global);
            if (instance !== undefined) {
              define(id, [], function () { return instance; });
              onsuccess();
            } else {
              onfailure('Modulator error: could not resolve global [' + name + ']');
            }
          };
  
          return {
            url: id, // this just needs to be unique, no download required.
            load: load,
            serial: true
          };
        };
  
        return {
          can: can,
          get: get
        }
      };
      return {
        create: create
      };
    }
  );
  kernel.modulator.bolt = def(
    [
      kernel.fp.functions
    ],
  
    function (fn) {
      var create = function (loader, pather, namespace, path, idTransformer, options) {
        var can = function (id) {
          return id === namespace || id.indexOf(namespace + '.') === 0 || id.indexOf(namespace + '/') === 0;
        };
  
        var get = function (id) {
          var before = options !== undefined && options.absolute === true ? path : pather(path);
          var after = options !== undefined && options.fresh === true ? '?cachebuster=' + new Date().getTime() : '';
          var url = before + "/" + idTransformer(id) + '.js' + after;
          var load = fn.curry(loader.load, url);
  
          return {
            url: url,
            load: load,
            serial: false
          };
        };
  
        return {
          can: can,
          get: get
        };
      };
  
      return {
        create: create
      };
    }
  );kernel.module.stratifier = def(
    [
      kernel.fp.array
    ],
  
    function (ar) {
      var stratify = function (specs) {
        var parallels = ar.filter(specs, function (spec) {
          return !spec.serial;
        });
        return parallels.length > 0 ? parallels : specs.slice(0, 1);
      };
  
      return {
        stratify: stratify
      };
    }
  );
  /**
   * This module performs dependency analysis of strings that depend on sets of
   * strings.
   *
   * The input is an array of root strings to start analysis from, and an object
   * that contains a mapping of each string to the strings it depends on.
   *
   * Performing an analysis results in either:
   *   1. an empty array, indicating that all dependencies are satisfied,
   *   2. an array of strings that are, at the minimum, still needed in order to
   *      satisfy the given dependency trees, or
   *   3. an array of strings that form a dependency cycle.
   */
  kernel.module.analyser = def(
    [
      kernel.fp.array
    ],
  
    function (array) {
      var collect = function (path, name) {
        var i = array.indexof(path, name);
        var p = path.slice(i);
        return p.concat([name]);
      };
  
      /**
       * @param {array} roots Contains a list of root ids
       * @param {object} modules Contains dependency information in format: { id: [ 'id1', 'id2' ] }
       */
      var analyse = function (roots, modules) {
        var done = {};
        var path = [];
        var missing = [];
        var cycle;
  
        var children = function (name) {
          array.each(modules[name], attempt);
        };
  
        var examine = function (name) {
          if (modules[name])
            children(name);
          else
            missing.push(name);
        };
  
        var descend = function (name) {
          path.push(name);
          examine(name);
          path.pop();
        };
  
        var decycle = function (name) {
          if (array.contains(path, name))
            cycle = collect(path, name);
          else
            descend(name);
        };
  
        var attempt = function (name) {
          if (!done[name]) {
            decycle(name);
            done[name] = true;
          }
        };
  
        array.each(roots, attempt);
  
        return cycle ? { cycle: cycle } : { load: missing };
      };
  
      return {
        analyse: analyse
      };
    }
  );
  kernel.module.fetcher = def(
    [
      kernel.fp.array,
      kernel.fp.functions,
      kernel.async.map,
      kernel.async.piggybacker,
      kernel.module.stratifier
    ],
  
    function (ar, fn, map, piggybacker, stratifier) {
      var create = function (regulator, validator, onerror, define, require, demand) {
        var piggyback = piggybacker.create();
  
        var validate = function (onsuccess, results) {
          var failed = ar.filter(results, fn.not(validator));
          if (failed.length > 0)
            onerror('Fetcher error: modules were not defined: ' + failed.join(', '));
          else
            onsuccess();
        };
  
        var mapper = function (spec, onresult) {
          var action = fn.curry(onresult, spec.id);
          var load = function (callback) {
            spec.load(callback, onerror);
          };
          piggyback.piggyback(spec.url, load, action);
        };
  
        var asyncfetch = function (specs, onsuccess) {
          var oncomplete = fn.curry(validate, onsuccess);
          var strata = stratifier.stratify(specs);
          map.amap(strata, mapper, oncomplete);
        };
  
        var fetch = function (ids, onsuccess) {
          regulator.regulate(ids, define, require, demand, function (specs) {
            asyncfetch(specs, onsuccess);
          }, onerror);
        };
  
        return {
          fetch: fetch
        };
      };
  
      return {
        create: create
      };
    }
  );
  kernel.module.loader = def(
    [
      kernel.module.analyser
    ],
  
    function (analyser) {
      var load = function (roots, deps, fetcher, oncontinue, onsuccess, onerror) {
        var result = analyser.analyse(roots, deps);
  
        if (result.cycle)
          onerror('Dependency error: a circular module dependency exists from ' + result.cycle.join(' ~> '));
        else if (result.load.length === 0)
          onsuccess();
        else
          fetcher.fetch(result.load, oncontinue);
      };
  
      return {
        load: load
      };
    }
  );
  kernel.module.manager = def(
    [
      kernel.fp.array,
      kernel.fp.object,
      kernel.module.loader,
      kernel.module.fetcher
    ],
  
    function (ar, obj, loader, fetcher) {
      var create = function (regulator, onerror) {
        var blueprints = {};  // id -> { id: string, dependencies: [ string ], definition: function }
        var modules = {};     // id -> module
  
        // Adds a module to the system.
        var define = function (id, dependencies, definition) {
          if (id === undefined)
            onerror("Define error: module id can not be undefined");
          else if (blueprints[id] !== undefined)
            onerror("Define error: module '" + id + "' is already defined");
          else
            blueprints[id] = { id: id, dependencies: dependencies, definition: definition };
        };
  
        // Loads a set of modules asynchronously.
        var require = function (ids, callback) {
          var onsuccess = function () {
            var instances = ar.map(ids, demand);
            callback.apply(null, instances);
          };
  
          var oncontinue = function () {
            var deps = obj.map(blueprints, function (k, v) {
              return v.dependencies;
            });
            loader.load(ids, deps, fetch, oncontinue, onsuccess, onerror);
          };
  
          oncontinue();
        };
  
        // Instantiates a module and all of its dependencies.
        var demand = function (id) {
          if (modules[id] !== undefined)
            return modules[id];
          if (blueprints[id] === undefined)
            throw "module '" + id + "' is not defined";
          var result = instantiate(id);
          if (result === undefined)
            throw "module '" + id + "' returned undefined from definition function";
          modules[id] = result;
          return result;
        };
  
        var instantiate = function (id) {
          var blueprint = blueprints[id];
          var args = ar.map(blueprint.dependencies, demand);  // Instantiate dependencies
          return blueprint.definition.apply(null, args);  // Instantiate self
        };
  
        var validator = function (id) { return blueprints[id] !== undefined; };
        var fetch = fetcher.create(regulator, validator, onerror, define, require, demand);
  
        return {
          define: define,
          require: require,
          demand: demand
        };
      };
  
      return {
        create: create
      };
    }
  );
  kernel.api.sources = def(
    [
      kernel.fp.array,
      kernel.fp.object,
      kernel.modulator.globalator
    ],
  
    function (ar, obj, globalator) {
      var create = function (builtins, configuration) {
        var data = {
          'global': { instance: globalator }
        };
        obj.each(builtins, function (key, value) {
          data[key] = { instance: value };
        });
        ar.each(configuration.types, function (spec) {
          data[spec.type] = { id: spec.modulator };
        });
        var sourcespecs = configuration.sources.slice(0);
        var sources = [ globalator.create() ];
  
        var guard = function (type) {
          if (data[type] === undefined)
            throw 'Unknown modulator type [' + type + '].';
        };
  
        var isResolved = function (type) {
          guard(type);
          return data[type].instance !== undefined;
        };
  
        var idOf = function (type) {
          guard(type);
          return data[type].id;
        };
  
        var instanceOf = function (type) {
          guard(type);
          return data[type].instance;
        };
  
        var register = function (type, instance) {
          guard(type);
          data[type].instance = instance;
        };
  
        var find = function (id) {
          for (var i = 0; i < sources.length; ++i)
            if (sources[i].can(id))
              return { found: sources[i] };
          return { notfound: true };
        };
  
        var crank = function () {
          var left = [];
          ar.each(sourcespecs, function (spec) {
            if (isResolved(spec.type)) {
              var instance = instanceOf(spec.type);
              var source = instance.create.apply(null, spec.args);
              sources.push(source);
            } else
              left.push(spec);
          });
          sourcespecs = left;
        };
  
        return {
          isResolved: isResolved,
          idOf: idOf,
          instanceOf: instanceOf,
          register: register,
          find: find,
          crank: crank
        };
      };
  
      return {
        create: create
      };
    }
  );
  kernel.api.regulator = def(
    [
      kernel.fp.array,
      kernel.fp.functions
    ],
  
    function (ar, fn) {
      var create = function (sources) {
        /*
         * 1. Resolve configuration as much as possible
         * 2. Check for unresolved modulator types that are required to continue.
         *   a) Go ahead and resolve, if we have everything we need.
         *   b) Delay, requiring the modulators, then retry.
         */
        var regulate = function (ids, define, require, demand, onsuccess, onerror) {
          sources.crank();
          var required = ar.map(ids, determinetype);
          var unresolved = ar.filter(required, fn.not(sources.isResolved));
          if (unresolved.length === 0)
            resolve(ids,  define, require, demand, onsuccess, onerror);
          else
            delay(unresolved, ids, define, require, demand, onsuccess, onerror);
        };
  
        var resolve = function (ids,  define, require, demand, onsuccess, onerror) {
          var r = [];
          for (var i = 0; i < ids.length; ++i) {
            var id = ids[i];
            var source = sources.find(id);
            if (source.notfound) {
              onerror('Could not find source for module [' +  id + ']');
              return;
            }
            var spec = source.found.get(id, define, require, demand);
            r[i] = build(id, spec);
          }
          onsuccess(r);
        };
  
        var build = function (id, spec) {
          return {
            id: id,
            url: spec.url,
            load: spec.load,
            serial: spec.serial
          };
        };
  
        var delay = function (types, ids, define, require, demand, onsuccess, onerror) {
          var modulatorids = ar.map(types, sources.idOf);
          require(modulatorids, function (/* modulators */) {
            var modulators = arguments;
            ar.each(types, function (type, i) {
               sources.register(type, modulators[i]);
            });
            regulate(ids, define, require, demand, onsuccess, onerror);
          });
        };
  
        var determinetype = function (id) {
          var index = id.indexOf('!');
          return index === -1 ? 'bolt' : id.substring(0, index);
        };
  
        return {
          regulate: regulate
        };
      };
  
      return {
        create: create
      };
    }
  );
  kernel.api.config = def(
    [
      kernel.module.manager,
      kernel.api.regulator,
      kernel.api.sources
    ],
  
    function (manager, regulator, sources) {
      var configure = function (configuration, builtins, onerror) {
        var s = sources.create(builtins, configuration);
        var r = regulator.create(s);
        var engine = manager.create(r, onerror);
  
        return {
          define: engine.define,
          require: engine.require,
          demand: engine.demand
        };
      };
  
      return {
        configure: configure
      };
    }
  );
  })(Function('return this')());
  
  (function (scope) {
  var ephox = scope.ephox = scope.ephox || {};
  var bolt = ephox.bolt = ephox.bolt || {};
  
  var def = function (deps, factory) {
      return factory.apply(null, deps);
  };
  var loader = bolt.loader = bolt.loader || {};
  loader.executor = loader.executor || {};
  loader.api = loader.api || {};
  loader.transporter = loader.transporter || {};
  loader.tag = loader.tag || {};
  loader.tag.script = def(
    [
    ],
  
    function () {
      var guard = function (callback) {
        return function (evt) {
          if (evt.srcElement.readyState === "loaded" || evt.srcElement.readyState === "complete")
            callback();
        };
      };
  
      var ie = function (el) {
        return el.attachEvent && !window.opera;
      };
  
      var onload = function (el, callback) {
        if (ie(el))
          el.attachEvent("onreadystatechange", guard(callback));
        else
          el.addEventListener("load", callback, false);
      };
  
      var createtag = function (callback) {
        var el = document.createElement("script");
        el.type = "text/javascript";
        onload(el, callback);
        return el;
      };
  
      var insert = function (decorator, callback) {
        var el = createtag(callback);
        decorator(el);
        var head = document.getElementsByTagName("head")[0];
        head.appendChild(el);
      };
  
      return {
        insert: insert
      };
    }
  );
  loader.transporter.commonjs = def(
    [
    ],
  
    function () {
      var read = function (url, success, error) {
        var fs = require('fs');
        fs.exists(url, function (exists) {
          if (exists)
            fs.readFile(url, 'UTF-8', function (err, data) {
              if (err)
                error('Error reading file [' + url + '], error [' + err + ']');
              else
                success(data);
            });
          else
            error('File does not exist [' + url + ']');
        });
      };
  
      return {
        read: read
      };
    }
  );
  loader.transporter.xhr = def(
    [
    ],
  
    function () {
      var requestObject = function () {
        // Correct way to use XMLHttpRequest in IE:
        // http://blogs.msdn.com/b/ie/archive/2006/01/23/516393.aspx
        var factories = [
          function () { return new XMLHttpRequest() },
          function () { return new ActiveXObject("Microsoft.XMLHTTP") }
        ];
  
        return fallback(factories);
      };
  
      var fallback = function (items) {
        for (var i = 0; i < items.length; ++i) {
          try {
            return items[i]();
          } catch (e) {
          }
        }
      };
  
      var handler = function (req, url, success, error) {
        return function () {
          if (req.readyState === 4)
            done(req, url, success, error);
        };
      };
  
      var done = function (req, url, success, error) {
        if (req.status === 200 || req.status === 304)
          success(req.responseText);
        else
          error('Transport error: ' + req.status + ' ' + req.statusText + ' for resource: "' + url + '"');
      };
  
      var getUrl = function (req, url, success, error) {
        req.open('GET', url, true);
        req.onreadystatechange = handler(req, url, success, error);
        req.send();
      };
  
      var request = function (url, success, error) {
        var req = requestObject();
        if (req)
          getUrl(req, url, success, error);
        else
          error('Transport error: browser does not support XMLHttpRequest.');
      };
  
      return {
        request: request
      };
    }
  );
  loader.executor.evaller = def(
    [
    ],
  
    function () {
      var execute = function (data, onsuccess, onfailure) {
        try {
          eval(data);
        } catch(e) {
          onfailure(e);
          return;
        }
  
        onsuccess();
      };
  
      return {
        execute: execute
      };
    }
  );
  loader.executor.injector = def(
    [
      loader.tag.script
    ],
  
    function (script) {
      var execute = function (data, onsuccess, onfailure) {
        var inject = function (tag) {
          tag.text = data;
        };
  
        var noop = function () {};
  
        // Injection does not fire events, but execution happens synchronously,
        // so we just make an explicit callback
        script.insert(inject, noop);
        onsuccess(); 
      };
  
      return {
        execute: execute
      };
    }
  );
  loader.api.commonjsevaller = def(
    [
      loader.transporter.commonjs,
      loader.executor.evaller
    ],
  
    function (commonjs, evaller) {
      var load = function (url, onsuccess, onfailure) {
        var inject = function (data) {
          evaller.execute(data, onsuccess, onfailure);
        };
  
        commonjs.read(url, inject, onfailure);
      };
  
      return {
        load: load
      };
    }
  );
  loader.api.scripttag = def(
    [
      loader.tag.script
    ],
  
    function (script) {
      var load = function (url, onsuccess, onfailure) {
        var sourcer = function (tag) {
          tag.src = url;
        };
  
        script.insert(sourcer, onsuccess);
      };
  
      return {
        load: load
      };
    }
  );
  loader.api.xhrevaller = def(
    [
      loader.transporter.xhr,
      loader.executor.evaller
    ],
  
    function (xhr, evaller) {
      var load = function (url, onsuccess, onfailure) {
        var inject = function (data) {
          evaller.execute(data, onsuccess, onfailure);
        };
  
        xhr.request(url, inject, onfailure);
      };
  
      return {
        load: load
      };
    }
  );
  loader.api.xhrinjector = def(
    [
      loader.transporter.xhr,
      loader.executor.injector
    ],
  
    function (xhr, injector) {
      var load = function (url, onsuccess, onfailure) {
        var inject = function (data) {
          injector.execute(data, onsuccess);
        };
  
        xhr.request(url, inject, onfailure);
      };
  
      return {
        load: load
      };
    }
  );
  })(Function('return this')());
  
  (function (scope) {
  var ephox = scope.ephox = scope.ephox || {};
  var bolt = ephox.bolt = ephox.bolt || {};
  
  var def = function (deps, factory) {
      return factory.apply(null, deps);
  };
  var module = bolt.module = bolt.module || {};
  module.bootstrap = module.bootstrap || {};
  module.config = module.config || {};
  module.error = module.error || {};
  module.modulator = module.modulator || {};
  module.reader = module.reader || {};
  module.runtime = module.runtime || {};
  module.util = module.util || {};
  module.error.error = def(
    [
    ],
  
    function () {
      var die = function (msg) {
        throw msg || new Error('unknown error');
      };
  
      return {
        die: die
      };
    }
  );
  module.config.mapper = def(
    [
    ],
  
    function () {
      var flat = function (id) {
        return id;
      };
  
      var hierarchical = function (id) {
        return id.replace(/\./g, '/');
      };
  
      var constant = function (name) {
        return function () {
          return name;
        };
      };
  
      return {
        flat: flat,
        hierarchical: hierarchical,
        constant: constant
      };
    }
  );
  module.api = def(
    [
      module.runtime
    ],
  
    function (runtime) {
      var delegate = function (method) {
        return function () {
          return runtime[method].apply(null, arguments);
        };
      };
  
      return {
        define: delegate('define'),
        require: delegate('require'),
        demand: delegate('demand'),
        main: delegate('main'),
        load: delegate('load'),
        loadscript: delegate('loadscript')
      };
    }
  );
  module.util.path = def(
    [
    ],
  
    function () {
      var dirname = function (file) {
        var normalized = file.replace(/\\/g, '/');
        var end = normalized.lastIndexOf('/');
        return normalized.substring(0, end);
      };
  
      var basename = function (file) {
        var normalized = file.replace(/\\/g, '/');
        var end = normalized.lastIndexOf('/');
        return normalized.substring(end + 1);
      };
  
      return {
        basename: basename,
        dirname: dirname
      };
    }
  );
  module.util.locator = def(
    [
    ],
  
    function () {
      var browser = function () {
        var scripts = document.getElementsByTagName("script");
        return scripts[scripts.length - 1].src;
      };
  
      var runtime = module.runtime.locate;
  
      var locate = function () {
        var f = runtime || browser;
        return f();
      };
  
      return {
        locate: locate
      };
    }
  );
  module.util.pather = def(
    [
      module.util.path
    ],
  
    function (path) {
      var create = function (relativeto) {
        var base = path.dirname(relativeto);
        return function (path) {
          return base + '/' + path;
        };
      };
  
      return {
        create: create
      };
    }
  );module.modulator.modulators = def(
    [
      ephox.bolt.kernel.fp.functions,
      ephox.bolt.kernel.modulator.bolt,
      ephox.bolt.loader.api.commonjsevaller,
      ephox.bolt.loader.api.scripttag,
      ephox.bolt.loader.api.xhrevaller,
      ephox.bolt.loader.api.xhrinjector
    ],
  
    function (fn, bolt, commonjsevaller, scripttag, xhrevaller, xhrinjector) {
      var wrap = function (modulator, loader) {
        var create = fn.curry(modulator.create, loader);
  
        return {
          create: create
        }
      };
  
      return {
        boltcommonjs: wrap(bolt, commonjsevaller),
        boltscripttag: wrap(bolt, scripttag),
        boltxhreval: wrap(bolt, xhrevaller),
        boltxhrinjector: wrap(bolt, xhrinjector)
      };
    }
  );
  module.config.builtins = def(
    [
      ephox.bolt.module.modulator.modulators.boltscripttag,
      ephox.bolt.module.modulator.modulators.boltcommonjs
    ],
  
    function (boltscripttag, boltcommonjs) {
      return {
        // TODO: 'amd' is maintained for backwards compatibility, will be removed
        // at some point.
        browser: { bolt: boltscripttag, amd: boltscripttag },
        commonjs: { bolt: boltcommonjs, amd: boltcommonjs }
      };
    }
  );
  module.config.specs = def(
    [
      module.util.pather
    ],
  
    function (pather) {
      var type = function (type, implementation) {
        return {
          type: type,
          implementation: implementation,
          modulator: implementation + '.Modulator',
          compiler: implementation + '.Compiler'
        };
      };
  
      var source = function (relativeto) {
        return function (type /*, args */) {
          return {
            type: type,
            relativeto: relativeto,
            args: [ pather.create(relativeto) ].concat(Array.prototype.slice.call(arguments, 1))
          };
        }
      };
  
      return {
        type: type,
        source: source
      };
    }
  );
  module.reader.bouncing = def(
    [
      ephox.bolt.kernel.fp.array,
      module.error.error,
      module.config.specs
    ],
  
    function (ar, error, specs) {
      var bounce = function (done, read, acc) {
        var next = acc.configs.shift();
        read(next.relativeto, next.config, done, acc);
      };
  
      var tick = function (file, cfg, done, read, acc) {
        var munged = ar.map(cfg.configs || [], function (config) {
          return { relativeto: file, config: config };
        });
        var accumulated = {
          sources: acc.sources.concat(cfg.sources || []),
          types: acc.types.concat(cfg.types || []),
          configs: munged.concat(acc.configs)
        };
        if (accumulated.configs.length > 0)
          bounce(done, read, accumulated);
        else
          done({ sources: accumulated.sources, types: accumulated.types });
      };
  
      /*
       * All precedence is depth-first, pre-order. Example:
       *
       *        A
       *       /-\
       *      B   C
       *     /|   |\
       *    D E   F G
       *
       * Configs are read in A, B, D, E, C, F, G.
       *
       * If configs mixed delegation and sources, the
       * sources would be ordered the same: A, B, D, E, C, F, G.
       */
  
      var evaluate = function (file, payload, done, read, acc) {
        var result = {};
        /* eval scope */
        var mapper = module.config.mapper;
        var type = specs.type;
        var source = specs.source(file);
        var configure = function (configuration) {
          result = configuration;
        };
        try {
          eval(payload);
        } catch (e) {
          throw 'Could not load configuration [' + file + '], with: ' + e;
        }
        tick(file, result, done, read, acc);
      };
  
      return {
        evaluate: evaluate
      };
    }
  );
  module.reader.browser = def(
    [
      module.error.error,
      module.reader.bouncing,
      module.util.path,
      ephox.bolt.loader.transporter.xhr
    ],
  
    function (error, bouncing, path, xhr) {
      var read = function (relativeto, file, done, acc) {
        var accumulated = acc || { sources: [], types: [],  configs: [] };
        var base = path.dirname(relativeto);
        var absolute = base + '/' + file;
        xhr.request(absolute, function (payload) {
          bouncing.evaluate(absolute, payload, done, read, accumulated);
        }, error.die);
      };
  
      return {
        read: read
      };
    }
  );
  module.reader.node = def(
    [
      module.reader.bouncing
    ],
  
    function (bouncing, path, fs) {
      var read = function (relativeto, file, done, acc) {
        var fs = require('fs');
        var path = require('path');
        var accumulated = acc || { sources: [], types: [],  configs: [] };
        var base = path.dirname(relativeto);
        var absolute = path.resolve(base, file);
        var payload = fs.readFileSync(absolute, 'UTF-8');
        bouncing.evaluate(absolute, payload, done, read, accumulated);
      };
  
      return {
        read: read
      };
    }
  );
  module.reader.direct = def(
    [
    ],
  
    function () {
      var create = function (configuration) {
        return function (done) {
          done({
            sources: configuration.sources || [],
            types: configuration.types || [],
            configs: configuration.configs || []
          });
        };
      };
  
      return {
        create: create
      };
    }
  );
  module.bootstrap.configloader = def(
    [
      module.util.locator,
      module.reader.browser
    ],
  
    function (locator, browser) {
      var create = function (file) {
        var script = locator.locate();
        return function (done) {
          browser.read(script, file, done);
        };
      };
  
      return {
        create: create
      };
    }
  );module.bootstrap.deferred = def(
    [
      ephox.bolt.kernel.fp.array
    ],
  
    function (ar) {
      var deferred = [];
  
      var require = function (ids, fn) {
        var r = function (real) {
          real(ids, fn);
        };
        deferred.push(r);
      };
  
      var configured = function (require) {
        ar.each(deferred, function (action) {
          action(require);
        });
        deferred = [];
      };
  
      return {
        require: require,
        configured: configured
      };
    }
  );
  module.bootstrap.main = def(
    [
      ephox.bolt.kernel.api.config,
      module.bootstrap.deferred,
      module.runtime
    ],
  
    function (config, deferred, runtime) {
      var main = function (id, args, configids, callback) {
        runtime.require(configids || [], function () {
          callback && callback.apply(null, arguments);
          runtime.require([ id ], function (module) {
            module.apply(null, args || []);
          });
        });
      };
  
      return {
        main: main
      };
    }
  );
  module.bootstrap.install = def(
    [
      ephox.bolt.kernel.api.config,
      module.bootstrap.deferred,
      module.bootstrap.main,
      module.runtime,
      module.error.error
    ],
  
    function (config, deferred, main, runtime, error) {
      var notready = function () { throw 'bolt not initialised, can not call define or demand, did you mean to use require or main?'; };
  
      var install = function (reader, builtins, load, loadscript) {
        runtime.define = notready;
        runtime.demand = notready;
        runtime.require = deferred.require;
        runtime.main = main.main;
        runtime.load = load;
        runtime.loadscript = loadscript;
  
        reader(function (configuration) {
          var bolt = config.configure(configuration, builtins, error.die);
          runtime.define = bolt.define;
          runtime.require = bolt.require;
          runtime.demand = bolt.demand;
  
          deferred.configured(runtime.require);
        });
      };
  
      return {
        install: install
      };
    }
  );
  
  })(Function('return this')());
  (function (global) {
    var obj = ephox.bolt.kernel.fp.object;
    var api = ephox.bolt.module.api;
    var builtins = ephox.bolt.module.config.builtins.browser;
    var install = ephox.bolt.module.bootstrap.install;
    var reader = ephox.bolt.module.bootstrap.configloader.create("browser.js");
    var transport = ephox.bolt.loader.transporter.xhr.request;
    var script = ephox.bolt.loader.api.scripttag.load;
    install.install(reader, builtins, transport, script);
    obj.merge(global, api);
  })(Function("return this;")());