text: /**
   * This code does _NOT_ support hot (session-restoring) reloads on
   * IE6,7. It only works on browsers with sessionStorage support.
   *
   * There are a couple approaches to add IE6,7 support:
   *
   * - use IE's "userData" mechanism in combination with window.name.
   * This mostly works, however the problem is that it can not get to the
   * data until after DOMReady. This is a problem for us since this API
   * relies on the data being ready before API users run. We could
   * refactor using Meteor.startup in all API users, but that might slow
   * page loads as we couldn't start the stream until after DOMReady.
   * Here are some resources on this approach:
   * https://github.com/hugeinc/USTORE.js
   * http://thudjs.tumblr.com/post/419577524/localstorage-userdata
   * http://www.javascriptkit.com/javatutors/domstorage2.shtml
   *
   * - POST the data to the server, and have the server send it back on
   * page load. This is nice because it sidesteps all the local storage
   * compatibility issues, however it is kinda tricky. We can use a unique
   * token in the URL, then get rid of it with HTML5 pushstate, but that
   * only works on pushstate browsers.
   *
   * This will all need to be reworked entirely when we add server-side
   * HTML rendering. In that case, the server will need to have access to
   * the client's session to render properly.
   */
  
  // XXX when making this API public, also expose a flag for the app
  // developer to know whether a hot code push is happening. This is
  // useful for apps using `window.onbeforeunload`. See
  // https://github.com/meteor/meteor/pull/657
  
  Reload = {};
  
  var KEY_NAME = 'Meteor_Reload';
  
  var old_data = {};
  // read in old data at startup.
  var old_json;
  
  // This logic for sessionStorage detection is based on browserstate/history.js
  var safeSessionStorage = null;
  try {
    // This throws a SecurityError on Chrome if cookies & localStorage are
    // explicitly disabled
    //
    // On Firefox with dom.storage.enabled set to false, sessionStorage is null
    //
    // We can't even do (typeof sessionStorage) on Chrome, it throws.  So we rely
    // on the throw if sessionStorage == null; the alternative is browser
    // detection, but this seems better.
    safeSessionStorage = window.sessionStorage;
  
    // Check we can actually use it
    if (safeSessionStorage) {
      safeSessionStorage.setItem('__dummy__', '1');
      safeSessionStorage.removeItem('__dummy__');
    } else {
      // Be consistently null, for safety
      safeSessionStorage = null;
    }
  } catch(e) {
    // Expected on chrome with strict security, or if sessionStorage not supported
    safeSessionStorage = null;
  }
  
  // Exported for test.
  Reload._getData = function () {
    return safeSessionStorage && safeSessionStorage.getItem(KEY_NAME);
  };
  
  if (safeSessionStorage) {
    old_json = Reload._getData();
    safeSessionStorage.removeItem(KEY_NAME);
  } else {
    // Unsupported browser (IE 6,7) or locked down security settings.
    // No session resumption.
    // Meteor._debug("XXX UNSUPPORTED BROWSER/SETTINGS");
  }
  
  if (!old_json) old_json = '{}';
  var old_parsed = {};
  try {
    old_parsed = JSON.parse(old_json);
    if (typeof old_parsed !== "object") {
      Meteor._debug("Got bad data on reload. Ignoring.");
      old_parsed = {};
    }
  } catch (err) {
    Meteor._debug("Got invalid JSON on reload. Ignoring.");
  }
  
  if (old_parsed.reload && typeof old_parsed.data === "object") {
    // Meteor._debug("Restoring reload data.");
    old_data = old_parsed.data;
  }
  
  
  var providers = [];
  
  ////////// External API //////////
  
  // Packages that support migration should register themselves by calling
  // this function. When it's time to migrate, callback will be called
  // with one argument, the "retry function," and an optional 'option'
  // argument (containing a key 'immediateMigration'). If the package
  // is ready to migrate, it should return [true, data], where data is
  // its migration data, an arbitrary JSON value (or [true] if it has
  // no migration data this time). If the package needs more time
  // before it is ready to migrate, it should return false. Then, once
  // it is ready to migrating again, it should call the retry
  // function. The retry function will return immediately, but will
  // schedule the migration to be retried, meaning that every package
  // will be polled once again for its migration data. If they are all
  // ready this time, then the migration will happen. name must be set if there
  // is migration data. If 'immediateMigration' is set in the options
  // argument, then it doesn't matter whether the package is ready to
  // migrate or not; the reload will happen immediately without waiting
  // (used for OAuth redirect login).
  //
  Reload._onMigrate = function (name, callback) {
    if (!callback) {
      // name not provided, so first arg is callback.
      callback = name;
      name = undefined;
    }
    providers.push({name: name, callback: callback});
  };
  
  // Called by packages when they start up.
  // Returns the object that was saved, or undefined if none saved.
  //
  Reload._migrationData = function (name) {
    return old_data[name];
  };
  
  // Options are the same as for `Reload._migrate`.
  var pollProviders = function (tryReload, options) {
    tryReload = tryReload || function () {};
    options = options || {};
  
    var migrationData = {};
    var remaining = _.clone(providers);
    var allReady = true;
    while (remaining.length) {
      var p = remaining.shift();
      var status = p.callback(tryReload, options);
      if (!status[0])
        allReady = false;
      if (status.length > 1 && p.name)
        migrationData[p.name] = status[1];
    };
    if (allReady || options.immediateMigration)
      return migrationData;
    else
      return null;
  };
  
  // Options are:
  //  - immediateMigration: true if the page will be reloaded immediately
  //    regardless of whether packages report that they are ready or not.
  Reload._migrate = function (tryReload, options) {
    // Make sure each package is ready to go, and collect their
    // migration data
    var migrationData = pollProviders(tryReload, options);
    if (migrationData === null)
      return false; // not ready yet..
  
    try {
      // Persist the migration data
      var json = JSON.stringify({
        data: migrationData, reload: true
      });
    } catch (err) {
      Meteor._debug("Couldn't serialize data for migration", migrationData);
      throw err;
    }
  
    if (safeSessionStorage) {
      try {
        safeSessionStorage.setItem(KEY_NAME, json);
      } catch (err) {
        // We should have already checked this, but just log - don't throw
        Meteor._debug("Couldn't save data for migration to sessionStorage", err);
      }
    } else {
      Meteor._debug("Browser does not support sessionStorage. Not saving migration state.");
    }
  
    return true;
  };
  
  // Allows tests to isolate the list of providers.
  Reload._withFreshProvidersForTest = function (f) {
    var originalProviders = _.clone(providers);
    providers = [];
    try {
      f();
    } finally {
      providers = originalProviders;
    }
  };
  
  // Migrating reload: reload this page (presumably to pick up a new
  // version of the code or assets), but save the program state and
  // migrate it over. This function returns immediately. The reload
  // will happen at some point in the future once all of the packages
  // are ready to migrate.
  //
  var reloading = false;
  Reload._reload = function (options) {
    options = options || {};
  
    if (reloading)
      return;
    reloading = true;
  
    var tryReload = function () { _.defer(function () {
      if (Reload._migrate(tryReload, options)) {
        // Tell the browser to shut down this VM and make a new one
        window.location.reload();
      }
    }); };
  
    tryReload();
  };
  