text: /** vim: et:ts=4:sw=4:sts=4
   * @license amdefine 1.0.0 Copyright (c) 2011-2015, The Dojo Foundation All Rights Reserved.
   * Available via the MIT or new BSD license.
   * see: http://github.com/jrburke/amdefine for details
   */
  
  /*jslint node: true */
  /*global module, process */
  'use strict';
  
  /**
   * Creates a define for node.
   * @param {Object} module the "module" object that is defined by Node for the
   * current module.
   * @param {Function} [requireFn]. Node's require function for the current module.
   * It only needs to be passed in Node versions before 0.5, when module.require
   * did not exist.
   * @returns {Function} a define function that is usable for the current node
   * module.
   */
  function amdefine(module, requireFn) {
      'use strict';
      var defineCache = {},
          loaderCache = {},
          alreadyCalled = false,
          path = require('path'),
          makeRequire, stringRequire;
  
      /**
       * Trims the . and .. from an array of path segments.
       * It will keep a leading path segment if a .. will become
       * the first path segment, to help with module name lookups,
       * which act like paths, but can be remapped. But the end result,
       * all paths that use this function should look normalized.
       * NOTE: this method MODIFIES the input array.
       * @param {Array} ary the array of path segments.
       */
      function trimDots(ary) {
          var i, part;
          for (i = 0; ary[i]; i+= 1) {
              part = ary[i];
              if (part === '.') {
                  ary.splice(i, 1);
                  i -= 1;
              } else if (part === '..') {
                  if (i === 1 && (ary[2] === '..' || ary[0] === '..')) {
                      //End of the line. Keep at least one non-dot
                      //path segment at the front so it can be mapped
                      //correctly to disk. Otherwise, there is likely
                      //no path mapping for a path starting with '..'.
                      //This can still fail, but catches the most reasonable
                      //uses of ..
                      break;
                  } else if (i > 0) {
                      ary.splice(i - 1, 2);
                      i -= 2;
                  }
              }
          }
      }
  
      function normalize(name, baseName) {
          var baseParts;
  
          //Adjust any relative paths.
          if (name && name.charAt(0) === '.') {
              //If have a base name, try to normalize against it,
              //otherwise, assume it is a top-level require that will
              //be relative to baseUrl in the end.
              if (baseName) {
                  baseParts = baseName.split('/');
                  baseParts = baseParts.slice(0, baseParts.length - 1);
                  baseParts = baseParts.concat(name.split('/'));
                  trimDots(baseParts);
                  name = baseParts.join('/');
              }
          }
  
          return name;
      }
  
      /**
       * Create the normalize() function passed to a loader plugin's
       * normalize method.
       */
      function makeNormalize(relName) {
          return function (name) {
              return normalize(name, relName);
          };
      }
  
      function makeLoad(id) {
          function load(value) {
              loaderCache[id] = value;
          }
  
          load.fromText = function (id, text) {
              //This one is difficult because the text can/probably uses
              //define, and any relative paths and requires should be relative
              //to that id was it would be found on disk. But this would require
              //bootstrapping a module/require fairly deeply from node core.
              //Not sure how best to go about that yet.
              throw new Error('amdefine does not implement load.fromText');
          };
  
          return load;
      }
  
      makeRequire = function (systemRequire, exports, module, relId) {
          function amdRequire(deps, callback) {
              if (typeof deps === 'string') {
                  //Synchronous, single module require('')
                  return stringRequire(systemRequire, exports, module, deps, relId);
              } else {
                  //Array of dependencies with a callback.
  
                  //Convert the dependencies to modules.
                  deps = deps.map(function (depName) {
                      return stringRequire(systemRequire, exports, module, depName, relId);
                  });
  
                  //Wait for next tick to call back the require call.
                  if (callback) {
                      process.nextTick(function () {
                          callback.apply(null, deps);
                      });
                  }
              }
          }
  
          amdRequire.toUrl = function (filePath) {
              if (filePath.indexOf('.') === 0) {
                  return normalize(filePath, path.dirname(module.filename));
              } else {
                  return filePath;
              }
          };
  
          return amdRequire;
      };
  
      //Favor explicit value, passed in if the module wants to support Node 0.4.
      requireFn = requireFn || function req() {
          return module.require.apply(module, arguments);
      };
  
      function runFactory(id, deps, factory) {
          var r, e, m, result;
  
          if (id) {
              e = loaderCache[id] = {};
              m = {
                  id: id,
                  uri: __filename,
                  exports: e
              };
              r = makeRequire(requireFn, e, m, id);
          } else {
              //Only support one define call per file
              if (alreadyCalled) {
                  throw new Error('amdefine with no module ID cannot be called more than once per file.');
              }
              alreadyCalled = true;
  
              //Use the real variables from node
              //Use module.exports for exports, since
              //the exports in here is amdefine exports.
              e = module.exports;
              m = module;
              r = makeRequire(requireFn, e, m, module.id);
          }
  
          //If there are dependencies, they are strings, so need
          //to convert them to dependency values.
          if (deps) {
              deps = deps.map(function (depName) {
                  return r(depName);
              });
          }
  
          //Call the factory with the right dependencies.
          if (typeof factory === 'function') {
              result = factory.apply(m.exports, deps);
          } else {
              result = factory;
          }
  
          if (result !== undefined) {
              m.exports = result;
              if (id) {
                  loaderCache[id] = m.exports;
              }
          }
      }
  
      stringRequire = function (systemRequire, exports, module, id, relId) {
          //Split the ID by a ! so that
          var index = id.indexOf('!'),
              originalId = id,
              prefix, plugin;
  
          if (index === -1) {
              id = normalize(id, relId);
  
              //Straight module lookup. If it is one of the special dependencies,
              //deal with it, otherwise, delegate to node.
              if (id === 'require') {
                  return makeRequire(systemRequire, exports, module, relId);
              } else if (id === 'exports') {
                  return exports;
              } else if (id === 'module') {
                  return module;
              } else if (loaderCache.hasOwnProperty(id)) {
                  return loaderCache[id];
              } else if (defineCache[id]) {
                  runFactory.apply(null, defineCache[id]);
                  return loaderCache[id];
              } else {
                  if(systemRequire) {
                      return systemRequire(originalId);
                  } else {
                      throw new Error('No module with ID: ' + id);
                  }
              }
          } else {
              //There is a plugin in play.
              prefix = id.substring(0, index);
              id = id.substring(index + 1, id.length);
  
              plugin = stringRequire(systemRequire, exports, module, prefix, relId);
  
              if (plugin.normalize) {
                  id = plugin.normalize(id, makeNormalize(relId));
              } else {
                  //Normalize the ID normally.
                  id = normalize(id, relId);
              }
  
              if (loaderCache[id]) {
                  return loaderCache[id];
              } else {
                  plugin.load(id, makeRequire(systemRequire, exports, module, relId), makeLoad(id), {});
  
                  return loaderCache[id];
              }
          }
      };
  
      //Create a define function specific to the module asking for amdefine.
      function define(id, deps, factory) {
          if (Array.isArray(id)) {
              factory = deps;
              deps = id;
              id = undefined;
          } else if (typeof id !== 'string') {
              factory = id;
              id = deps = undefined;
          }
  
          if (deps && !Array.isArray(deps)) {
              factory = deps;
              deps = undefined;
          }
  
          if (!deps) {
              deps = ['require', 'exports', 'module'];
          }
  
          //Set up properties for this module. If an ID, then use
          //internal cache. If no ID, then use the external variables
          //for this node module.
          if (id) {
              //Put the module in deep freeze until there is a
              //require call for it.
              defineCache[id] = [id, deps, factory];
          } else {
              runFactory(id, deps, factory);
          }
      }
  
      //define.require, which has access to all the values in the
      //cache. Useful for AMD modules that all have IDs in the file,
      //but need to finally export a value to node based on one of those
      //IDs.
      define.require = function (id) {
          if (loaderCache[id]) {
              return loaderCache[id];
          }
  
          if (defineCache[id]) {
              runFactory.apply(null, defineCache[id]);
              return loaderCache[id];
          }
      };
  
      define.amd = {};
  
      return define;
  }
  
  module.exports = amdefine;
  