text: var JS = (typeof this.JS === 'undefined') ? {} : this.JS;
  JS.Date = Date;
  
  (function(factory) {
    var $ = (typeof this.global === 'object') ? this.global : this,
        E = (typeof exports === 'object');
  
    if (E) {
      exports.JS = exports;
      JS = exports;
    } else {
      $.JS = JS;
    }
    factory($, JS);
  
  })(function(global, exports) {
  'use strict';
  
  var Package = function(loader) {
    Package._index(this);
  
    this._loader    = loader;
    this._names     = new OrderedSet();
    this._deps      = new OrderedSet();
    this._uses      = new OrderedSet();
    this._styles    = new OrderedSet();
    this._observers = {};
    this._events    = {};
  };
  
  Package.displayName = 'Package';
  Package.toString = function() { return Package.displayName };
  
  Package.log = function(message) {
    if (!exports.debug) return;
    if (typeof window === 'undefined') return;
    if (typeof global.runtime === 'object') runtime.trace(message);
    if (global.console && console.info) console.info(message);
  };
  
  var resolve = function(filename) {
    if (/^https?:/.test(filename)) return filename;
    var root = exports.ROOT;
    if (root) filename = (root + '/' + filename).replace(/\/+/g, '/');
    return filename;
  };
  
  //================================================================
  // Ordered list of unique elements, for storing dependencies
  
  var OrderedSet = function(list) {
    this._members = this.list = [];
    this._index = {};
    if (!list) return;
  
    for (var i = 0, n = list.length; i < n; i++)
      this.push(list[i]);
  };
  
  OrderedSet.prototype.push = function(item) {
    var key   = (item.id !== undefined) ? item.id : item,
        index = this._index;
  
    if (index.hasOwnProperty(key)) return;
    index[key] = this._members.length;
    this._members.push(item);
  };
  
  //================================================================
  // Wrapper for deferred values
  
  var Deferred = Package.Deferred = function() {
    this._status    = 'deferred';
    this._value     = null;
    this._callbacks = [];
  };
  
  Deferred.prototype.callback = function(callback, context) {
    if (this._status === 'succeeded') callback.call(context, this._value);
    else this._callbacks.push([callback, context]);
  };
  
  Deferred.prototype.succeed = function(value) {
    this._status = 'succeeded';
    this._value  = value;
    var callback;
    while (callback = this._callbacks.shift())
      callback[0].call(callback[1], value);
  };
  
  //================================================================
  // Environment settings
  
  Package.ENV = exports.ENV = global;
  
  Package.onerror = function(e) { throw e };
  
  Package._throw = function(message) {
    Package.onerror(new Error(message));
  };
  
  
  //================================================================
  // Configuration methods, called by the DSL
  
  var instance = Package.prototype,
  
      methods = [['requires', '_deps'],
                 ['uses',     '_uses']],
  
      i = methods.length;
  
  while (i--)
    (function(pair) {
      var method = pair[0], list = pair[1];
      instance[method] = function() {
        var n = arguments.length, i;
        for (i = 0; i < n; i++) this[list].push(arguments[i]);
        return this;
      };
    })(methods[i]);
  
  instance.provides = function() {
    var n = arguments.length, i;
    for (i = 0; i < n; i++) {
      this._names.push(arguments[i]);
      Package._getFromCache(arguments[i]).pkg = this;
    }
    return this;
  };
  
  instance.styling = function() {
    for (var i = 0, n = arguments.length; i < n; i++)
      this._styles.push(resolve(arguments[i]));
  };
  
  instance.setup = function(block) {
    this._onload = block;
    return this;
  };
  
  //================================================================
  // Event dispatchers, for communication between packages
  
  instance._on = function(eventType, block, context) {
    if (this._events[eventType]) return block.call(context);
    var list = this._observers[eventType] = this._observers[eventType] || [];
    list.push([block, context]);
    this._load();
  };
  
  instance._fire = function(eventType) {
    if (this._events[eventType]) return false;
    this._events[eventType] = true;
  
    var list = this._observers[eventType];
    if (!list) return true;
    delete this._observers[eventType];
  
    for (var i = 0, n = list.length; i < n; i++)
      list[i][0].call(list[i][1]);
  
    return true;
  };
  
  //================================================================
  // Loading frontend and other miscellany
  
  instance._isLoaded = function(withExceptions) {
    if (!withExceptions && this.__isLoaded !== undefined) return this.__isLoaded;
  
    var names = this._names.list,
        i     = names.length,
        name, object;
  
    while (i--) { name = names[i];
      object = Package._getObject(name, this._exports);
      if (object !== undefined) continue;
      if (withExceptions)
        return Package._throw('Expected package at ' + this._loader + ' to define ' + name);
      else
        return this.__isLoaded = false;
    }
    return this.__isLoaded = true;
  };
  
  instance._load = function() {
    if (!this._fire('request')) return;
    if (!this._isLoaded()) this._prefetch();
  
    var allDeps = this._deps.list.concat(this._uses.list),
        source  = this._source || [],
        n       = (this._loader || {}).length,
        self    = this;
  
    Package.when({load: allDeps});
  
    Package.when({complete: this._deps.list}, function() {
      Package.when({complete: allDeps, load: [this]}, function() {
        this._fire('complete');
      }, this);
  
      var loadNext = function(exports) {
        if (n === 0) return fireOnLoad(exports);
        n -= 1;
        var index = self._loader.length - n - 1;
        Package.loader.loadFile(self._loader[index], loadNext, source[index]);
      };
  
      var fireOnLoad = function(exports) {
        self._exports = exports;
        if (self._onload) self._onload();
        self._isLoaded(true);
        self._fire('load');
      };
  
      if (this._isLoaded()) {
        this._fire('download');
        return this._fire('load');
      }
  
      if (this._loader === undefined)
        return Package._throw('No load path found for ' + this._names.list[0]);
  
      if (typeof this._loader === 'function')
        this._loader(fireOnLoad);
      else
        loadNext();
  
      if (!Package.loader.loadStyle) return;
  
      var styles = this._styles.list,
          i      = styles.length;
  
      while (i--) Package.loader.loadStyle(styles[i]);
  
      this._fire('download');
    }, this);
  };
  
  instance._prefetch = function() {
    if (this._source || !(this._loader instanceof Array) || !Package.loader.fetch)
      return;
  
    this._source = [];
  
    for (var i = 0, n = this._loader.length; i < n; i++)
      this._source[i] = Package.loader.fetch(this._loader[i]);
  };
  
  instance.toString = function() {
    return 'Package:' + this._names.list.join(',');
  };
  
  //================================================================
  // Class-level event API, handles group listeners
  
  Package.when = function(eventTable, block, context) {
    var eventList = [], objects = {}, event, packages, i;
    for (event in eventTable) {
      if (!eventTable.hasOwnProperty(event)) continue;
      objects[event] = [];
      packages = new OrderedSet(eventTable[event]);
      i = packages.list.length;
      while (i--) eventList.push([event, packages.list[i], i]);
    }
  
    var waiting = i = eventList.length;
    if (waiting === 0) return block && block.call(context, objects);
  
    while (i--)
      (function(event) {
        var pkg = Package._getByName(event[1]);
        pkg._on(event[0], function() {
          objects[event[0]][event[2]] = Package._getObject(event[1], pkg._exports);
          waiting -= 1;
          if (waiting === 0 && block) block.call(context, objects);
        });
      })(eventList[i]);
  };
  
  //================================================================
  // Indexes for fast lookup by path and name, and assigning IDs
  
  var globalPackage = (global.JS || {}).Package || {};
  
  Package._autoIncrement = globalPackage._autoIncrement || 1;
  Package._indexByPath   = globalPackage._indexByPath   || {};
  Package._indexByName   = globalPackage._indexByName   || {};
  Package._autoloaders   = globalPackage._autoloaders   || [];
  
  Package._index = function(pkg) {
    pkg.id = this._autoIncrement;
    this._autoIncrement += 1;
  };
  
  Package._getByPath = function(loader) {
    var path = loader.toString(),
        pkg  = this._indexByPath[path];
  
    if (pkg) return pkg;
  
    if (typeof loader === 'string')
      loader = [].slice.call(arguments);
  
    pkg = this._indexByPath[path] = new this(loader);
    return pkg;
  };
  
  Package._getByName = function(name) {
    if (typeof name !== 'string') return name;
    var cached = this._getFromCache(name);
    if (cached.pkg) return cached.pkg;
  
    var autoloaded = this._manufacture(name);
    if (autoloaded) return autoloaded;
  
    var placeholder = new this();
    placeholder.provides(name);
    return placeholder;
  };
  
  Package.remove = function(name) {
    var pkg = this._getByName(name);
    delete this._indexByName[name];
    delete this._indexByPath[pkg._loader];
  };
  
  //================================================================
  // Auotloading API, generates packages from naming patterns
  
  Package._autoload = function(pattern, options) {
    this._autoloaders.push([pattern, options]);
  };
  
  Package._manufacture = function(name) {
    var autoloaders = this._autoloaders,
        n = autoloaders.length,
        i, j, autoloader, path;
  
    for (i = 0; i < n; i++) {
      autoloader = autoloaders[i];
      if (!autoloader[0].test(name)) continue;
  
      path = autoloader[1].from;
      if (typeof path === 'string') path = this._convertNameToPath(path);
  
      var pkg = new this([path(name)]);
      pkg.provides(name);
  
      if (path = autoloader[1].require) {
        path = [].concat(path);
        j = path.length;
        while (j--) pkg.requires(name.replace(autoloader[0], path[j]));
      }
  
      return pkg;
    }
    return null;
  };
  
  Package._convertNameToPath = function(from) {
    return function(name) {
      return from.replace(/\/?$/, '/') +
             name.replace(/([a-z])([A-Z])/g, function(m,a,b) { return a + '_' + b })
                 .replace(/\./g, '/')
                 .toLowerCase() + '.js';
    };
  };
  
  //================================================================
  // Cache for named packages and runtime objects
  
  Package._getFromCache = function(name) {
    return this._indexByName[name] = this._indexByName[name] || {};
  };
  
  Package._getObject = function(name, rootObject) {
    if (typeof name !== 'string') return undefined;
  
    var cached = rootObject ? {} : this._getFromCache(name);
    if (cached.obj !== undefined) return cached.obj;
  
    var object = rootObject || this.ENV,
        parts  = name.split('.'), part;
  
    while (part = parts.shift()) object = object && object[part];
  
    if (rootObject && object === undefined)
      return this._getObject(name);
  
    return cached.obj = object;
  };
  
  Package.CommonJSLoader = {
    usable: function() {
      return typeof require === 'function' &&
             typeof exports === 'object';
    },
  
    __FILE__: function() {
      return this._currentPath;
    },
  
    loadFile: function(path, fireCallbacks) {
      var file, module;
  
      if (typeof process !== 'undefined') {
        module = path.replace(/\.[^\.]+$/g, '');
        file   = require('path').resolve(module);
      }
      else if (typeof phantom !== 'undefined') {
        file = phantom.libraryPath.replace(/\/$/, '') + '/' +
               path.replace(/^\//, '');
      }
  
      this._currentPath = file + '.js';
      var module = require(file);
      fireCallbacks(module);
  
      return module;
    }
  };
  
  Package.BrowserLoader = {
    HOST_REGEX: /^(https?\:)?\/\/[^\/]+/i,
  
    usable: function() {
      return !!Package._getObject('window.document.getElementsByTagName') &&
             typeof phantom === 'undefined';
    },
  
    __FILE__: function() {
      var scripts = document.getElementsByTagName('script'),
          src     = scripts[scripts.length - 1].src,
          url     = window.location.href;
  
      if (/^\w+\:\/+/.test(src)) return src;
      if (/^\//.test(src)) return window.location.origin + src;
      return url.replace(/[^\/]*$/g, '') + src;
    },
  
    cacheBust: function(path) {
      if (exports.cache !== false) return path;
      var token = new JS.Date().getTime();
      return path + (/\?/.test(path) ? '&' : '?') + token;
    },
  
    fetch: function(path) {
      var originalPath = path;
      path = this.cacheBust(path);
  
      this.HOST = this.HOST || this.HOST_REGEX.exec(window.location.href);
      var host = this.HOST_REGEX.exec(path);
  
      if (!this.HOST || (host && host[0] !== this.HOST[0])) return null;
      Package.log('[FETCH] ' + path);
  
      var source = new Package.Deferred(),
          self   = this,
          xhr    = window.ActiveXObject
                 ? new ActiveXObject('Microsoft.XMLHTTP')
                 : new XMLHttpRequest();
  
      xhr.open('GET', path, true);
      xhr.onreadystatechange = function() {
        if (xhr.readyState !== 4) return;
        xhr.onreadystatechange = self._K;
        source.succeed(xhr.responseText + '\n//@ sourceURL=' + originalPath);
        xhr = null;
      };
      xhr.send(null);
      return source;
    },
  
    loadFile: function(path, fireCallbacks, source) {
      if (!source) path = this.cacheBust(path);
  
      var self   = this,
          head   = document.getElementsByTagName('head')[0],
          script = document.createElement('script');
  
      script.type = 'text/javascript';
  
      if (source)
        return source.callback(function(code) {
          Package.log('[EXEC]  ' + path);
          var execute = new Function('code', 'eval(code)');
          execute(code);
          fireCallbacks();
        });
  
      Package.log('[LOAD] ' + path);
      script.src = path;
  
      script.onload = script.onreadystatechange = function() {
        var state = script.readyState, status = script.status;
        if ( !state || state === 'loaded' || state === 'complete' ||
             (state === 4 && status === 200) ) {
          fireCallbacks();
          script.onload = script.onreadystatechange = self._K;
          head   = null;
          script = null;
        }
      };
      head.appendChild(script);
    },
  
    loadStyle: function(path) {
      var link  = document.createElement('link');
      link.rel  = 'stylesheet';
      link.type = 'text/css';
      link.href = this.cacheBust(path);
  
      document.getElementsByTagName('head')[0].appendChild(link);
    },
  
    _K: function() {}
  };
  
  Package.RhinoLoader = {
    usable: function() {
      return typeof java === 'object' &&
             typeof require === 'function';
    },
  
    __FILE__: function() {
      return this._currentPath;
    },
  
    loadFile: function(path, fireCallbacks) {
      var cwd    = java.lang.System.getProperty('user.dir'),
          module = path.replace(/\.[^\.]+$/g, '');
  
      var requirePath = new java.io.File(cwd, module).toString();
      this._currentPath = requirePath + '.js';
      var module = require(requirePath);
      fireCallbacks(module);
  
      return module;
    }
  };
  
  Package.ServerLoader = {
    usable: function() {
      return typeof Package._getObject('load') === 'function' &&
             typeof Package._getObject('version') === 'function';
    },
  
    __FILE__: function() {
      return this._currentPath;
    },
  
    loadFile: function(path, fireCallbacks) {
      this._currentPath = path;
      load(path);
      fireCallbacks();
    }
  };
  
  Package.WshLoader = {
    usable: function() {
      return !!Package._getObject('ActiveXObject') &&
             !!Package._getObject('WScript');
    },
  
    __FILE__: function() {
      return this._currentPath;
    },
  
    loadFile: function(path, fireCallbacks) {
      this._currentPath = path;
      var fso = new ActiveXObject('Scripting.FileSystemObject'), file, runner;
      try {
        file   = fso.OpenTextFile(path);
        runner = function() { eval(file.ReadAll()) };
        runner();
        fireCallbacks();
      } finally {
        try { if (file) file.Close() } catch (e) {}
      }
    }
  };
  
  Package.XULRunnerLoader = {
    jsloader:   '@mozilla.org/moz/jssubscript-loader;1',
    cssservice: '@mozilla.org/content/style-sheet-service;1',
    ioservice:  '@mozilla.org/network/io-service;1',
  
    usable: function() {
      try {
        var CC = (Components || {}).classes;
        return !!(CC && CC[this.jsloader] && CC[this.jsloader].getService);
      } catch(e) {
        return false;
      }
    },
  
    setup: function() {
      var Cc = Components.classes, Ci = Components.interfaces;
      this.ssl = Cc[this.jsloader].getService(Ci.mozIJSSubScriptLoader);
      this.sss = Cc[this.cssservice].getService(Ci.nsIStyleSheetService);
      this.ios = Cc[this.ioservice].getService(Ci.nsIIOService);
    },
  
    loadFile: function(path, fireCallbacks) {
      Package.log('[LOAD] ' + path);
  
      this.ssl.loadSubScript(path);
      fireCallbacks();
    },
  
    loadStyle: function(path) {
      var uri = this.ios.newURI(path, null, null);
      this.sss.loadAndRegisterSheet(uri, this.sss.USER_SHEET);
    }
  };
  
  var candidates = [  Package.XULRunnerLoader,
                      Package.RhinoLoader,
                      Package.BrowserLoader,
                      Package.CommonJSLoader,
                      Package.ServerLoader,
                      Package.WshLoader ],
  
      n = candidates.length,
      i, candidate;
  
  for (i = 0; i < n; i++) {
    candidate = candidates[i];
    if (candidate.usable()) {
      Package.loader = candidate;
      if (candidate.setup) candidate.setup();
      break;
    }
  }
  
  var DSL = {
    __FILE__: function() {
      return Package.loader.__FILE__();
    },
  
    pkg: function(name, path) {
      var pkg = path
          ? Package._getByPath(path)
          : Package._getByName(name);
      pkg.provides(name);
      return pkg;
    },
  
    file: function(filename) {
      var files = [], i = arguments.length;
      while (i--) files[i] = resolve(arguments[i]);
      return Package._getByPath.apply(Package, files);
    },
  
    load: function(path, fireCallbacks) {
      Package.loader.loadFile(path, fireCallbacks);
    },
  
    autoload: function(pattern, options) {
      Package._autoload(pattern, options);
    }
  };
  
  DSL.files  = DSL.file;
  DSL.loader = DSL.file;
  
  var packages = function(declaration) {
    declaration.call(DSL);
  };
  
  var parseLoadArgs = function(args) {
   var files = [], i = 0;
  
    while (typeof args[i] === 'string'){
      files.push(args[i]);
      i += 1;
    }
  
    return {files: files, callback: args[i], context: args[i+1]};
  };
  
  exports.load = function(path, callback) {
    var args = parseLoadArgs(arguments),
        n    = args.files.length;
  
    var loadNext = function(index) {
      if (index === n) return args.callback.call(args.context);
      Package.loader.loadFile(args.files[index], function() {
        loadNext(index + 1);
      });
    };
    loadNext(0);
  };
  
  exports.require = function() {
    var args = parseLoadArgs(arguments);
  
    Package.when({complete: args.files}, function(objects) {
      if (!args.callback) return;
      args.callback.apply(args.context, objects && objects.complete);
    });
  
    return this;
  };
  
  exports.Package  = Package;
  exports.Packages = exports.packages = packages;
  exports.DSL      = DSL;
  });