Source: require.js

/*
    Based in part on Motorola Mobility’s Montage
    Copyright (c) 2012, Motorola Mobility LLC. All Rights Reserved.
    3-Clause BSD License
    https://github.com/motorola-mobility/montage/blob/master/LICENSE.md
*/

/*global bootstrap,define */
(function (definition) {

    // Boostrapping Browser
    if (typeof bootstrap !== "undefined") {

        // Window
        if (typeof window !== "undefined") {
            bootstrap("require", function (require, exports) {
                var Promise = require("promise");
                var URL = require("mini-url");
                definition(exports, Promise, URL);
                require("require/browser");
            });

        // Worker
        } else {
            bootstrap("require", function (require, exports) {
                var Promise = require("promise").Promise;
                var URL = require("mini-url");
                definition(exports, Promise, URL);
            });
        }

    // Node Server
    } else if (typeof process !== "undefined") {
        // the parens trick the heuristic scanner for static dependencies, so
        // they are not pre-loaded by the asynchronous browser loader
        var Promise = (require)("q");
        var URL = (require)("url");
        definition(exports, Promise, URL);
        (require)("./node");
    } else {
        throw new Error("Can't support require on this platform");
    }

})(function (Require, Promise, URL) {

    if (!this)
        throw new Error("Require does not work in strict mode.");

    var globalEval = eval; // reassigning causes eval to not use lexical scope.

    // Non-CommonJS speced extensions should be marked with an "// EXTENSION"
    // comment.

    Require.makeRequire = function (config) {
        var require;

        // Configuration defaults:
        config = config || {};
        config.location = URL.resolve(config.location || Require.getLocation(), "./");
        config.lib = URL.resolve(config.location, config.lib || "./");
        config.paths = config.paths || [config.lib];
        config.mappings = config.mappings || {}; // EXTENSION
        config.exposedConfigs = config.exposedConfigs || Require.exposedConfigs;
        config.makeLoader = config.makeLoader || Require.makeLoader;
        config.load = config.load || config.makeLoader(config);
        config.makeCompiler = config.makeCompiler || Require.makeCompiler;
        config.compile = config.compile || config.makeCompiler(config);
        config.parseDependencies = config.parseDependencies || Require.parseDependencies;
        config.read = config.read || Require.read;

        // Modules: { exports, id, location, directory, factory, dependencies,
        // dependees, text, type }
        var modules = config.modules = config.modules || {};

        // produces an entry in the module state table, which gets built
        // up through loading and execution, ultimately serving as the
        // ``module`` free variable inside the corresponding module.
        function getModuleDescriptor(id) {
            var lookupId = id.toLowerCase();
            if (!has(modules, lookupId)) {
                modules[lookupId] = {
                    id: id,
                    display: (config.name || config.location) + "#" + id, // EXTENSION
                    require: require
                };
            }
            return modules[lookupId];
        }

        // for preloading modules by their id and exports, useful to
        // prevent wasteful multiple instantiation if a module was loaded
        // in the bootstrapping process and can be trivially injected into
        // the system.
        function inject(id, exports) {
            var module = getModuleDescriptor(id);
            module.exports = exports;
            module.location = URL.resolve(config.location, id);
            module.directory = URL.resolve(module.location, "./");
            module.injected = true;
            delete module.redirect;
            delete module.mappingRedirect;
        }

        // Ensures a module definition is loaded, compiled, analyzed
        var load = memoize(function (topId, viaId) {
            var module = getModuleDescriptor(topId);
            return Promise.fcall(function () {
                // if not already loaded, already instantiated, or
                // configured as a redirection to another module
                if (
                    module.factory === void 0 &&
                    module.exports === void 0 &&
                    module.redirect === void 0
                ) {
                    return Promise.fcall(config.load, topId, module);
                }
            })
            .then(function () {
                // compile and analyze dependencies
                config.compile(module);
                var dependencies =
                    module.dependencies =
                        module.dependencies || [];
                if (module.redirect !== void 0) {
                    dependencies.push(module.redirect);
                }
                if (module.extraDependencies !== void 0) {
                    Array.prototype.push.apply(module.dependencies, module.extraDependencies);
                }
            });
        });

        // Load a module definition, and the definitions of its transitive
        // dependencies
        function deepLoad(topId, viaId, loading) {
            var module = getModuleDescriptor(topId);
            // this is a memo of modules already being loaded so we don’t
            // data-lock on a cycle of dependencies.
            loading = loading || {};
            // has this all happened before?  will it happen again?
            if (has(loading, topId))
                return; // break the cycle of violence.
            loading[topId] = true; // this has happened before
            return load(topId, viaId)
            .then(function () {
                // load the transitive dependencies using the magic of
                // recursion.
                return Promise.all(module.dependencies.map(function (depId) {
                    depId = resolve(depId, topId);
                    // create dependees set, purely for debug purposes
                    var module = getModuleDescriptor(depId);
                    var dependees = module.dependees = module.dependees || {};
                    dependees[topId] = true;
                    return deepLoad(depId, topId, loading);
                }));
            }, function (error) {
                module.error = error;
            });
        }

        // Initializes a module by executing the factory function with a new
        // module "exports" object.
        function getExports(topId, viaId) {
            var module = getModuleDescriptor(topId);

            // check for consistent case convention
            if (module.id !== topId) {
                throw new Error(
                    "Can't require module " + JSON.stringify(module.id) +
                    " by alternate spelling " + JSON.stringify(topId)
                );
            }

            // check for load error
            if (module.error) {
                var error = new Error(
                    "Can't require module " + JSON.stringify(module.id) +
                    " via " + JSON.stringify(viaId) +
                    " because " + module.error.message
                );
                error.cause = module.error;
                throw error;
            }

            // handle redirects
            if (module.redirect !== void 0) {
                return getExports(module.redirect, viaId);
            }

            // handle cross-package linkage
            if (module.mappingRedirect !== void 0) {
                return module.mappingRequire(module.mappingRedirect, viaId);
            }

            // do not reinitialize modules
            if (module.exports !== void 0) {
                return module.exports;
            }

            // do not initialize modules that do not define a factory function
            if (module.factory === void 0) {
                throw new Error(
                    "Can't require module " + JSON.stringify(topId) +
                    " via " + JSON.stringify(viaId)
                );
            }

            module.directory = URL.resolve(module.location, "./"); // EXTENSION
            module.exports = {};

            // Execute the factory function:
            var returnValue = module.factory.call(
                // in the context of the module:
                void 0, // this (defaults to global)
                makeRequire(topId), // require
                module.exports, // exports
                module // module
            );

            // EXTENSION
            if (returnValue !== void 0) {
                module.exports = returnValue;
            }

            return module.exports;
        }

        // Finds the internal identifier for a module in a subpackage
        // The ``internal`` boolean parameter causes the function to return
        // null instead of throwing an exception.  I’m guessing that
        // throwing exceptions *and* being recursive would be too much
        // performance evil for one function.
        function identify(id2, require2, internal) {
            if (require2.location === config.location)
                return id2;
            var locations = {};
            for (var name in config.mappings) {
                var mapping = config.mappings[name];
                var location = mapping.location;
                if (!config.hasPackage(location))
                    continue;
                var candidate = config.getPackage(location);
                var id1 = candidate.identify(id2, require2, true);
                if (id1 === null) {
                    continue;
                } else if (id1 === "") {
                    return name;
                } else {
                    return name + "/" + id1;
                }
            }
            if (internal) {
                return null;
            } else {
                throw new Error(
                    "Can't identify " + id2 + " from " + require2.location
                );
            }
        }

        // Creates a unique require function for each module that encapsulates
        // that module's id for resolving relative module IDs against.
        function makeRequire(viaId) {

            /**
             * The synchronously executing `require` function. Can only be
             * used for static dependencies, or dependencies that have already
             * been loaded. If you wish to require a module where the ID is
             * only known at runtime, use `require.async`.
             * @example
             * var URL = require("mini-url");
             * var other = URL.resolve("http://example.com/path", "../other");
             * //...
             * @param  {string} id The id of the module to require.
             * @return {*}         The exports of the module.
             * @constructor
             */
            var require = function(id) {
                var topId = resolve(id, viaId);
                return getExports(topId, viaId);
            };

            /**
             * Asynchronous `require` function. Can be used to dynamically
             * load a dependency at runtime.
             *
             * @example
             * require.async("mini-url")
             * .then(function (URL) {
             *     var other = URL.resolve("http://example.com/path", "../other");
             *     //...
             * })
             * .done();
             * @param  {string} id   The id of the module to require.
             * @return {Promise.<*>} A promise for the exports of the module.
             */
            require.async = function(id) {
                var topId = resolve(id, viaId);
                var module = getModuleDescriptor(id);
                return deepLoad(topId, viaId)
                .then(function () {
                    return require(topId);
                });
            };

            /**
             * Removes any "." and ".." parts from the given id, the ".js"
             * extension if it exists and, if relative, makes absolute from
             * the base ID of the require.
             * @example
             * // in my/sub/module
             * require.resolve("../other/./sub/module") // -> my/other/sub/module
             * @param  {string} id The id of the module to resolve.
             * @return {string}    The resolved module id.
             */
            require.resolve = function (id) {
                return normalizeId(resolve(id, viaId));
            };

            require.getModule = getModuleDescriptor; // XXX deprecated, use:
            /**
             * Gets the module descriptor for the given id.
             *
             * The module descriptor is the value of the `module` free
             * variable given inside the corresponding module.
             *
             * @param  {string} id The id to get the module descriptor for.
             * @return {Object}    The module descriptor.
             * @function
             */
            require.getModuleDescriptor = getModuleDescriptor;
            /**
             * Ensures a module definition is loaded, compiled, analyzed.
             *
             * Note: this just loads the module. To load its dependencies as
             * well use `require.deepLoad`.
             *
             * Uses the loader created by `config.makeLoader`.
             *
             * @param  {string} id The module id to load.
             * @return  {Promise}   A promise for the completion of the loading.
             * @function
             */
            require.load = load;
            /**
             * Loads a module definition and the definitions of its transitive
             * dependencies.
             * @param  {string}  id The module id to load.
             * @return {Promise}    A promise for the completion of the
             * loading of the module and its dependencies.
             * @function
             */
            require.deepLoad = deepLoad;

            /**
             * Loads a package.
             *
             * If givenConfig is not provided then the package is loaded as
             * a child of this package (which is probably what you want).
             * Otherwise the package is loaded with no parent, behaving the
             * same as `Require.loadPackage`.
             *
             * @example
             * require.loadPackage({ name: "q" })
             * .then(function (qRequire) {
             *     return qRequire.async("queue");
             * })
             * .then(function (queue) {
             *     //...
             * })
             * .done();
             * @param  {givenDependency} dependency The dependency to load.
             * @param  {Object} [givenConfig] The parent configuration to use.
             * @return {Promise.<require>}    A `require` function for the
             * root of the package.
             */
            require.loadPackage = function (dependency, givenConfig) {
                if (givenConfig) { // explicit configuration, fresh environment
                    return Require.loadPackage(dependency, givenConfig);
                } else { // inherited environment
                    return config.loadPackage(dependency, config);
                }
            };

            /**
             * Returns if this package has the given package dependency loaded.
             * @param  {givenDependency} dependency The package dependency to check.
             * @return {boolean}               `true` if the package has been
             * loaded, `false` if not.
             */
            require.hasPackage = function (dependency) {
                return config.hasPackage(dependency);
            };

            /**
             * Gets the `require` for the diven package dependency.
             *
             * The package must have been loaded (for example with
             * `require.loadPackage`) prior to calling this function.
             *
             * @param  {givenDependency} dependency The package dependency to get.
             * @return {require}               The package's `require`.
             */
            require.getPackage = function (dependency) {
                return config.getPackage(dependency);
            };

            /**
             * Returns if this is the top-most package of this `require`.
             * @return {boolean}
             */
            require.isMainPackage = function () {
                return require.location === config.mainPackageLocation;
            };

            /**
             * Injects a package description directly into this `require`.
             * @param  {string} location         The absolute path to the
             * package.
             * @param  {Description} description The package description, as
             * would usually be found in a `package.json`.
             */
            require.injectPackageDescription = function (location, description) {
                Require.injectPackageDescription(location, description, config);
            };

            /**
             * Injects the location of a package decription into this
             * `require`. TODO
             */
            require.injectPackageDescriptionLocation = function (location, descriptionLocation) {
                Require.injectPackageDescriptionLocation(location, descriptionLocation, config);
            };

            /**
             * Injects a mapping into this `require`.
             * @param  {givenDependency} dependency The dependency to use for
             * `name`.
             * @param  {string} name       The name of the mapping.
             */
            require.injectMapping = function (dependency, name) {
                dependency = normalizeDependency(dependency, config, name);
                name = name || dependency.name;
                config.mappings[name] = dependency;
            };

            /**
             * Inject a dependency, as if it was listed in the
             * `package.json`'s `dependency` block.
             * @param  {string} name The name of the dependency.
             */
            require.injectDependency = function (name) {
                require.injectMapping({name: name}, name);
            };

            require.identify = identify;

            /**
             * Directly inject the exports for the given module id.
             *
             * Useful to prevent wasteful multiple instantiation if a module
             * was loaded in the bootstrapping process and can be trivially
             * injected into the system.
             *
             * @param  {string} id      The module id to inject exports for.
             * @param  {*}      exports The exports of the module.
             * @function
             */
            require.inject = inject;

            config.exposedConfigs.forEach(function(name) {
                require[name] = config[name];
            });

            /**
             * The configuration for this package/require.
             * @type {Object}
             */
            require.config = config;

            /**
             * Low level function that reads a location.
             *
             * In the browser the location should be a url, and in node it
             * should be a path.
             *
             * @param  {string} location  The location to read.
             * @return {Promise.<string>} A promise for the string contents of
             * the file at `location`.
             * @function
             */
            require.read = Require.read;

            return require;
        }

        require = makeRequire("");
        return require;
    };

    /**
     * @see require.injectPackageDescription
     */
    Require.injectPackageDescription = function (location, description, config) {
        var descriptions =
            config.descriptions =
                config.descriptions || {};
        descriptions[location] = Promise.resolve(description);
    };

    /**
     * @see require.injectPackageDescriptionLocation
     */
    Require.injectPackageDescriptionLocation = function (location, descriptionLocation, config) {
        var descriptionLocations =
            config.descriptionLocations =
                config.descriptionLocations || {};
        descriptionLocations[location] = descriptionLocation;
    };

    Require.loadPackageDescription = function (dependency, config) {
        var location = dependency.location;
        var descriptions =
            config.descriptions =
                config.descriptions || {};
        if (descriptions[location] === void 0) {
            var descriptionLocations =
                config.descriptionLocations =
                    config.descriptionLocations || {};
            var descriptionLocation;
            if (descriptionLocations[location]) {
                descriptionLocation = descriptionLocations[location];
            } else {
                descriptionLocation = URL.resolve(location, "package.json");
            }
            descriptions[location] = Require.read(descriptionLocation)
            .then(function (json) {
                try {
                    return JSON.parse(json);
                } catch (error) {
                    error.message = error.message + " in " + JSON.stringify(descriptionLocation)
                    throw error;
                }
            });
        }
        return descriptions[location];
    };

    /**
     * @see require.loadPackage
     */
    Require.loadPackage = function (dependency, config) {
        dependency = normalizeDependency(dependency, config);
        if (!dependency.location) {
            throw new Error("Can't find dependency: " + JSON.stringify(dependency));
        }
        var location = dependency.location;
        config = Object.create(config || null);
        var loadingPackages = config.loadingPackages = config.loadingPackages || {};
        var loadedPackages = config.packages = {};
        var registry = config.registry = config.registry || Object.create(null);
        config.mainPackageLocation = location;

        config.hasPackage = function (dependency) {
            dependency = normalizeDependency(dependency, config);
            if (!dependency.location)
                return false;
            var location = dependency.location;
            return !!loadedPackages[location];
        };

        config.getPackage = function (dependency) {
            dependency = normalizeDependency(dependency, config);
            if (!dependency.location) {
                throw new Error("Can't find dependency: " + JSON.stringify(dependency) + " from " + config.location);
            }
            var location = dependency.location;
            if (!loadedPackages[location]) {
                if (loadingPackages[location]) {
                    throw new Error(
                        "Dependency has not finished loading: " + JSON.stringify(dependency)
                    );
                } else {
                    throw new Error(
                        "Dependency was not loaded: " + JSON.stringify(dependency)
                    );
                }
            }
            return loadedPackages[location];
        };

        config.loadPackage = function (dependency, viaConfig) {
            dependency = normalizeDependency(dependency, viaConfig);
            if (!dependency.location) {
                throw new Error("Can't find dependency: " + JSON.stringify(dependency) + " from " + config.location);
            }
            var location = dependency.location;
            if (!loadingPackages[location]) {
                loadingPackages[location] = Require.loadPackageDescription(dependency, config)
                .then(function (packageDescription) {
                    var subconfig = configurePackage(
                        location,
                        packageDescription,
                        config
                    );
                    var pkg = Require.makeRequire(subconfig);
                    loadedPackages[location] = pkg;
                    return pkg;
                });
            }
            return loadingPackages[location];
        };

        var pkg = config.loadPackage(dependency);
        pkg.location = location;
        pkg.async = function (id, callback) {
            return pkg.then(function (require) {
                return require.async(id, callback);
            });
        };

        return pkg;
    };

    /**
     * A number of functions accept a dependency as an argument.
     *
     * If the dependency is an object, at least one of the properties must be
     * given.
     *
     * If the dependency is a string, it is converted to an object with the
     * `location` property set to the value of the string.
     *
     * @typedef {Object|string} givenDependency
     * @property {string} [name] The name of the dependency.
     *
     * If only the name is given then the location is resolved relative to the
     * `packagesDirectory` of the package config (generally "node_modules").
     * @property {string} [location] The location of the dependency.
     *
     * If the location is relative it is resolved relative to the `location`
     * of the package config.
     */

    function normalizeDependency(dependency, config, name) {
        config = config || {};
        if (typeof dependency === "string") {
            dependency = {
                location: dependency
            };
        }
        if (dependency.main) {
            dependency.location = config.mainPackageLocation;
        }
        // if the named dependency has already been found at another
        // location, refer to the same eventual instance
        if (
            dependency.name &&
            config.registry &&
            config.registry[dependency.name]
        ) {
            dependency.location = config.registry[dependency.name];
        }
        // default location
        if (!dependency.location && config.packagesDirectory && dependency.name) {
            dependency.location = URL.resolve(
                config.packagesDirectory,
                dependency.name + "/"
            );
        }
        if (!dependency.location)
            return dependency; // partially completed
        // make sure the dependency location has a trailing slash so that
        // relative urls will resolve properly
        if (!/\/$/.test(dependency.location)) {
            dependency.location += "/";
        }
        // resolve the location relative to the current package
        if (!Require.isAbsolute(dependency.location)) {
            if (!config.location) {
                throw new Error(
                    "Dependency locations must be fully qualified: " +
                    JSON.stringify(dependency)
                );
            }
            dependency.location = URL.resolve(
                config.location,
                dependency.location
            );
        }
        // register the package name so the location can be reused
        if (dependency.name) {
            config.registry[dependency.name] = dependency.location;
        }
        return dependency;
    }

    function configurePackage(location, description, parent) {

        if (!/\/$/.test(location)) {
            location += "/";
        }

        var config = Object.create(parent);
        config.name = description.name;
        config.location = location || Require.getLocation();
        config.packageDescription = description;
        config.useScriptInjection = description.useScriptInjection;

        if (description.production !== void 0) {
            config.production = description.production;
        }

        // explicitly mask definitions and modules, which must
        // not apply to child packages
        var modules = config.modules = config.modules || {};

        var registry = config.registry;
        if (config.name !== void 0 && !registry[config.name]) {
            registry[config.name] = config.location;
        }

        // overlay
        var overlay = description.overlay || {};
        var layer;
        (config.overlays || Require.overlays).forEach(function (engine) {
            if (overlay[engine]) {
                var layer = overlay[engine];
                for (var name in layer) {
                    description[name] = layer[name];
                }
            }
        });
        delete description.overlay;

        // directories
        description.directories = description.directories || {};
        description.directories.lib =
            description.directories.lib === void 0 ? "./" : description.directories.lib;
        var lib = description.directories.lib;
        // lib
        config.lib = URL.resolve(location, "./" + lib);
        var packagesDirectory = description.directories.packages || "node_modules";
        packagesDirectory = URL.resolve(location, packagesDirectory + "/");
        config.packagesDirectory = packagesDirectory;

        // The default "main" module of a package has the same name as the
        // package.
        if (description.main !== void 0) {

            // main, injects a definition for the main module, with
            // only its path. makeRequire goes through special effort
            // in deepLoad to re-initialize this definition with the
            // loaded definition from the given path.
            modules[""] = {
                id: "",
                redirect: normalizeId(description.main),
                location: config.location
            };

            if (description.name !== modules[""].redirect) {
                modules[description.name] = {
                    id: description.name,
                    redirect: "",
                    location: URL.resolve(location, description.name)
                };
            }

        }

        //Deal with redirects
        var redirects = description.redirects;
        if (redirects !== void 0) {
            Object.keys(redirects).forEach(function (name) {
                modules[name] = {
                    id: name,
                    redirect: redirects[name],
                    location: URL.resolve(location, name)
                };
            });
        }

        // mappings, link this package to other packages.
        var mappings = description.mappings || {};
        // dependencies, devDependencies if not in production
        [description.dependencies, !config.production ? description.devDependencies : null]
        .forEach(function (dependencies) {
            if (!dependencies)
                return;
            Object.keys(dependencies).forEach(function (name) {
                if (!mappings[name]) {
                    // dependencies are equivalent to name and version mappings,
                    // though the version predicate string is presently ignored
                    // (TODO)
                    mappings[name] = {
                        name: name,
                        version: dependencies[name]
                    };
                }
            });
        });
        // mappings
        Object.keys(mappings).forEach(function (name) {
            var mapping = mappings[name] = normalizeDependency(
                mappings[name],
                config,
                name
            );
        });
        config.mappings = mappings;

        return config;
    }

    // Helper functions:

    function has(object, property) {
        return Object.prototype.hasOwnProperty.call(object, property);
    }

    // Resolves CommonJS module IDs (not paths)
    Require.resolve = resolve;
    function resolve(id, baseId) {
        id = String(id);
        var source = id.split("/");
        var target = [];
        // if the source is relative append it to the parent of baseId
        if (source.length && source[0] === "." || source[0] === "..") {
            var parts = baseId.split("/");
            parts.pop();
            source.unshift.apply(source, parts);
        }
        for (var i = 0, ii = source.length; i < ii; i++) {
            var part = source[i];
            if (part === "" || part === ".") {
            } else if (part === "..") {
                if (target.length) {
                    target.pop();
                }
            } else {
                target.push(part);
            }
        }
        return target.join("/");
    }

    Require.base = function (location) {
        // matches Unix basename
        return String(location)
            .replace(/(.+?)\/+$/, "$1")
            .match(/([^\/]+$|^\/$|^$)/)[1];
    };

    // Tests whether the location or URL is a absolute.
    Require.isAbsolute = function(location) {
        return (/^[\w\-]+:/).test(location);
    };

    // Extracts dependencies by parsing code and looking for "require" (currently using a simple regexp)
    Require.parseDependencies = function(factory) {
        var o = {};
        String(factory).replace(/(?:^|[^\w\$_.])require\s*\(\s*["']([^"']*)["']\s*\)/g, function(_, id) {
            o[id] = true;
        });
        return Object.keys(o);
    };

    // Built-in compiler/preprocessor "middleware":

    Require.DependenciesCompiler = function(config, compile) {
        return function(module) {
            if (!module.dependencies && module.text !== void 0) {
                module.dependencies = config.parseDependencies(module.text);
            }
            compile(module);
            if (module && !module.dependencies) {
                if (module.text || module.factory) {
                    module.dependencies = Require.parseDependencies(module.text || module.factory);
                } else {
                    module.dependencies = [];
                }
            }
            return module;
        };
    };

    // Support she-bang for shell scripts by commenting it out (it is never
    // valid JavaScript syntax anyway)
    Require.ShebangCompiler = function(config, compile) {
        return function (module) {
            if (module.text) {
                module.text = module.text.replace(/^#!/, "//#!");
            }
            compile(module);
        };
    };

    Require.LintCompiler = function(config, compile) {
        return function(module) {
            try {
                compile(module);
            } catch (error) {
                if (config.lint) {
                    Promise.nextTick(function () {
                        config.lint(module);
                    });
                }
                throw error;
            }
        };
    };

    Require.exposedConfigs = [
        "paths",
        "mappings",
        "location",
        "packageDescription",
        "packages",
        "modules"
    ];

    Require.makeCompiler = function(config) {
        return Require.JsonCompiler(
            config,
            Require.ShebangCompiler(
                config,
                Require.DependenciesCompiler(
                    config,
                    Require.LintCompiler(
                        config,
                        Require.Compiler(config)
                    )
                )
            )
        );
    };

    Require.JsonCompiler = function (config, compile) {
        return function (module) {
            var json = (module.location || "").match(/\.json$/);
            if (json) {
                module.exports = JSON.parse(module.text);
                return module;
            } else {
                return compile(module);
            }
        };
    };

    // Built-in loader "middleware":

    // Using mappings hash to load modules that match a mapping.
    Require.MappingsLoader = function(config, load) {
        config.mappings = config.mappings || {};
        config.name = config.name;

        // finds a mapping to follow, if any
        return function (id, module) {
            var mappings = config.mappings;
            var prefixes = Object.keys(mappings);
            var length = prefixes.length;

            if (Require.isAbsolute(id)) {
                return load(id, module);
            }
            // TODO: remove this when all code has been migrated off of the autonomous name-space problem
            if (
                config.name !== void 0 &&
                id.indexOf(config.name) === 0 &&
                id.charAt(config.name.length) === "/"
            ) {
                console.warn("Package reflexive module ignored:", id);
            }
            var i, prefix;
            for (i = 0; i < length; i++) {
                prefix = prefixes[i];
                if (
                    id === prefix ||
                    id.indexOf(prefix) === 0 &&
                    id.charAt(prefix.length) === "/"
                ) {
                    var mapping = mappings[prefix];
                    var rest = id.slice(prefix.length + 1);
                    return config.loadPackage(mapping, config)
                    .then(function (mappingRequire) {
                        module.mappingRedirect = rest;
                        module.mappingRequire = mappingRequire;
                        return mappingRequire.deepLoad(rest, config.location);
                    });
                }
            }
            return load(id, module);
        };
    };

    Require.ExtensionsLoader = function(config, load) {
        var extensions = config.extensions || ["js"];
        var loadWithExtension = extensions.reduceRight(function (next, extension) {
            return function (id, module) {
                return load(id + "." + extension, module)
                .fail(function (error) {
                    if (/^Can't find /.test(error.message)) {
                        return next(id, module);
                    } else {
                        throw error;
                    }
                });
            };
        }, function (id, module) {
            throw new Error(
                "Can't find " + JSON.stringify(id) + " with extensions " +
                JSON.stringify(extensions) + " in package at " +
                JSON.stringify(config.location)
            );
        });
        return function (id, module) {
            if (Require.base(id).indexOf(".") !== -1) {
                // already has an extension
                return load(id, module);
            } else {
                return loadWithExtension(id, module);
            }
        };
    };

    // Attempts to load using multiple base paths (or one absolute path) with a
    // single loader.
    Require.PathsLoader = function(config, load) {
        var loadFromPaths = config.paths.reduceRight(function (next, path) {
            return function (id, module) {
                var newId = URL.resolve(path, id);
                return load(newId, module)
                .fail(function (error) {
                    if (/^Can't find /.test(error.message)) {
                        return next(id, module);
                    } else {
                        throw error;
                    }
                });
            };
        }, function (id, module) {
            throw new Error(
                "Can't find " + JSON.stringify(id) + " from paths " +
                JSON.stringify(config.paths) + " in package at " +
                JSON.stringify(config.location)
            );
        });
        return function(id, module) {
            if (Require.isAbsolute(id)) {
                // already fully qualified
                return load(id, module);
            } else {
                return loadFromPaths(id, module);
            }
        };
    };

    Require.MemoizedLoader = function (config, load) {
        var cache = config.cache = config.cache || {};
        return memoize(load, cache);
    };

    var normalizeId = function (id) {
        var match = /^(.*)\.js$/.exec(id);
        if (match) {
            id = match[1];
        }
        return id;
    };

    var memoize = function (callback, cache) {
        cache = cache || {};
        return function (key, arg) {
            if (!has(cache, key)) {
                cache[key] = Promise.fcall(callback, key, arg);
            }
            return cache[key];
        };
    };

});