//////////////////// MIXINS

// Minimal, well-documented, general-purpose CSS mixins.
// (Some are same as Bootstrap.)

////////// Box-Sizing: Border-Box

// Setting `box-sizing: border-box` on an element causes the CSS
// layout algorithm to interpret `width` and `height` declarations
// as referring to the size of the border box (outside the border),
// not the content box as usual (inside the padding).
//
// This is especially useful for stretching a form element to the
// width of its container even if the form element has arbitrary
// padding and borders, which can be done using `width: 100%`.
//
// Browser support is IE 8+ and all modern browsers, with the caveat
// that `-moz-box-sizing` in Firefox is considered to have some
// buggy or non-compliant behavior.  For example, min/max-width/height
// may not interact correctly. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=243412.
.box-sizing-by-border () {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

////////// Box-Shadow

.box-shadow (...) {
  box-shadow: @arguments;
  -webkit-box-shadow: @arguments; // For Android
}

////////// Unselectable

.unselectable () {
  -webkit-user-select: none; // Chrome/Safari
  -moz-user-select: none; // Firefox
  -ms-user-select: none; // IE10+

  // These delarations not implemented in browsers yet:
  -o-user-select: none;
  user-select: none;

  // In IE <= 9 and Opera, need unselectable="on" in the HTML.
}

//////////////////// LOGIN BUTTONS

@login-buttons-accounts-dialog-width: 250px;
@login-buttons-color: #596595;
@login-buttons-color-border: darken(@login-buttons-color, 10%);
@login-buttons-color-active: lighten(@login-buttons-color, 10%);
@login-buttons-color-active-border: darken(@login-buttons-color-active, 10%);

@login-buttons-config-color: darken(#f53, 10%);
@login-buttons-config-color-border: darken(@login-buttons-config-color, 10%);
@login-buttons-config-color-active: lighten(@login-buttons-config-color, 10%);
@login-buttons-config-color-active-border: darken(@login-buttons-config-color-active, 10%);

#login-buttons {

  display: inline-block;
  margin-right: 0.2px; // Fixes display on IE8: http://www.compsoft.co.uk/Blog/2009/11/inline-block-not-quite-inline-blocking.html

  // This seems to keep the height of the line from
  // being sensitive to the presence of the unicode down arrow,
  // which otherwise bumps the baseline down by 1px.
  line-height: 1;

  .login-button {
    position: relative; // so that we can position the image absolutely within the button
  }

  .login-buttons-with-only-one-button {
    display: inline-block;
    .login-button { display: inline-block; }
    .login-text-and-button {
      display: inline-block;
    }
  }

  .login-display-name {
    display: inline-block;
    padding-right: 2px;
    line-height: 1.5;
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
  }
  .loading {
    line-height: 1;
    background-image: url(data:image/gif;base64,R0lGODlhEAALAPQAAP///wAAANra2tDQ0Orq6gYGBgAAAC4uLoKCgmBgYLq6uiIiIkpKSoqKimRkZL6+viYmJgQEBE5OTubm5tjY2PT09Dg4ONzc3PLy8ra2tqCgoMrKyu7u7gAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCwAAACwAAAAAEAALAAAFLSAgjmRpnqSgCuLKAq5AEIM4zDVw03ve27ifDgfkEYe04kDIDC5zrtYKRa2WQgAh+QQJCwAAACwAAAAAEAALAAAFJGBhGAVgnqhpHIeRvsDawqns0qeN5+y967tYLyicBYE7EYkYAgAh+QQJCwAAACwAAAAAEAALAAAFNiAgjothLOOIJAkiGgxjpGKiKMkbz7SN6zIawJcDwIK9W/HISxGBzdHTuBNOmcJVCyoUlk7CEAAh+QQJCwAAACwAAAAAEAALAAAFNSAgjqQIRRFUAo3jNGIkSdHqPI8Tz3V55zuaDacDyIQ+YrBH+hWPzJFzOQQaeavWi7oqnVIhACH5BAkLAAAALAAAAAAQAAsAAAUyICCOZGme1rJY5kRRk7hI0mJSVUXJtF3iOl7tltsBZsNfUegjAY3I5sgFY55KqdX1GgIAIfkECQsAAAAsAAAAABAACwAABTcgII5kaZ4kcV2EqLJipmnZhWGXaOOitm2aXQ4g7P2Ct2ER4AMul00kj5g0Al8tADY2y6C+4FIIACH5BAkLAAAALAAAAAAQAAsAAAUvICCOZGme5ERRk6iy7qpyHCVStA3gNa/7txxwlwv2isSacYUc+l4tADQGQ1mvpBAAIfkECQsAAAAsAAAAABAACwAABS8gII5kaZ7kRFGTqLLuqnIcJVK0DeA1r/u3HHCXC/aKxJpxhRz6Xi0ANAZDWa+kEAA7AAAAAAAAAAAA);
    width: 16px;
    background-position: center center;
    background-repeat: no-repeat;
  }
}

#login-buttons .login-button, .accounts-dialog .login-button {
  cursor: pointer;
  .unselectable();
  padding: 4px 8px;

  font-size: 80%;
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
  line-height: 1.5;

  text-align: center;
  color: #fff;

  background: @login-buttons-color;
  border: 1px solid @login-buttons-color-border;

  border-radius: 4px;

  &:hover {
    background: @login-buttons-color-active;
  }
  &:active {
    background: @login-buttons-color-active;
    .box-shadow(0 2px 3px 0 rgba(0, 0, 0, 0.2) inset);
  }

  &.login-button-disabled, &.login-button-disabled:active {
    color: #ddd;
    background: #aaa;
    border: 1px solid lighten(#aaa, 10%);
    .box-shadow(none);
  }
}

// precendence of this selector is significant
.accounts-dialog * {
  // A base for our dialog CSS, to reset browser styles and protect against
  // the app's CSS.  Dialogs include the dropdown, config modals, and the
  // reset password modal.  We can't completely isolate the dialogs from
  // the app's CSS, and that isn't the goal because the app can style them.
  // This rule is a compromise that should take precedence over some very
  // broad rules but be overridden by more specific ones.

  // Add more declarations here if they help the dialogs look good
  // out-of-the-box in more apps.

  padding: 0;
  margin: 0;
  line-height: inherit;
  color: inherit;
  font: inherit;

  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

.accounts-dialog .login-button {
  width: auto;
  margin-bottom: 4px;
}

#login-buttons {
  .login-buttons-padding {
    display: inline-block;
    width: 30px;
  }

  .login-display-name { margin-right: 4px; }

  .configure-button {
    background: @login-buttons-config-color;
    border-color: @login-buttons-config-color-border;

    &:active, &:hover {
      background: @login-buttons-config-color-active;
      border-color: @login-buttons-config-color-active-border;
    }
  }

  .login-image {
    display: inline-block;
    position: absolute;
    left: 6px;
    top: 6px;
    width: 16px;
    height: 16px;
  }

  .text-besides-image {
    margin-left: 18px;
  }

  .no-services { color: red; }

  .login-link-and-dropdown-list {
    position: relative;
  }
  .login-close-text {
    float: left;
    position: relative;
    padding-bottom: 8px;
  }

  .login-text-and-button .loading, .login-link-and-dropdown-list .loading {
    display: inline-block;
  }
  &.login-buttons-dropdown-align-left #login-dropdown-list .loading {
    float: right;
  }
  &.login-buttons-dropdown-align-right #login-dropdown-list .loading {
    float: left;
  }

  .login-close-text-clear { clear: both; }

  .or { text-align: center; }
  .hline { text-decoration: line-through; color: lightgrey; }
  .or-text { font-weight: bold; }

  #signup-link { float: right; }
  #forgot-password-link { float: left; }
  #back-to-login-link { float: right; }
}

#login-buttons a, .accounts-dialog a {
    cursor: pointer;
    text-decoration: underline;
}

#login-buttons.login-buttons-dropdown-align-right .login-close-text {
    float: right;
}

@meteor-accounts-base-padding: 8px;
@meteor-accounts-dialog-border-width: 1px;

.accounts-dialog {
  border: @meteor-accounts-dialog-border-width solid #ccc;
  z-index: 1000;
  background: white;
  border-radius: 4px;

  padding: 8px 12px;
  margin: -8px -12px 0 -12px;

  width: @login-buttons-accounts-dialog-width;

  .box-shadow(0 0 3px 0 rgba(0, 0, 0, 0.2));

  // Labels and links inherit app's font with this line commented out:
  //font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-size: 16px;
  color: #333;

  // XXX Make the dropdown and dialogs look good without a top-level
  // line-height: 1.6.  For now, we apply it to everything except
  // the "Close" link, which we want to have the same line-height
  // as the "Sign in" link.
  & > * { line-height: 1.6; }
  & > .login-close-text {
    line-height: inherit;
    font-size: inherit;
    font-family: inherit;
  }

  label, .title {
    font-size: 80%;
    margin-top: 7px;
    margin-bottom: -2px;
  }
  input {
    // Be pixel-accurate in IE 8+ regardless of our borders and
    // paddings, at the expense of IE 7.
    // Any heights or widths applied to this element will set the
    // size of the border box (including padding and borders)
    // instead of the content box.  This makes it possible to
    // do width 100%.
    .box-sizing-by-border();
    width: 100%;
    // A fix purely for the "meteor add bootstrap" experience.
    // Bootstrap sets "height: 20px" on form fields, which is too
    // small when applied to the border box.  People have complained
    // that Bootstrap takes this approach for the sake of IE 7:
    // https://github.com/twitter/bootstrap/issues/2935
    // Our work-around is to override Bootstrap's rule (with higher
    // precedence).
    &[type] { height: auto; }
  }

  .login-button-form-submit { margin-top: 8px; }
  .message { font-size: 80%; margin-top: 8px; line-height: 1.3; }
  .error-message { color: red; }
  .info-message { color: green; }
  .additional-link { font-size: 75%; }

  .accounts-close {
    position: absolute;
    top: 0;
    right: 5px;

    font-size: 20px;
    font-weight: bold;
    line-height: 20px;
    text-decoration: none;
    color: #000;
    opacity: 0.4;

    &:hover {
      opacity: 0.8;
    }
  }

  #login-buttons-cancel-reset-password { float: right; }
  #login-buttons-cancel-enroll-account { float: right; }
}

#login-dropdown-list {
  position: absolute;
  // The top-left of the border-box of the dropdown is absolutely
  // positioned within its container, so we need to compensate
  // for the border.  The padding is already compensated for by
  // negative margins on the dropdown.
  // XXX We could use negative margins to compensate for the
  // border too.
  top: -@meteor-accounts-dialog-border-width;
  left: -@meteor-accounts-dialog-border-width;
}

#login-buttons.login-buttons-dropdown-align-right #login-dropdown-list {
  left: auto;
  right: -@meteor-accounts-dialog-border-width;
}

#login-buttons-message-dialog .message {
    /* we intentionally want it bigger on this dialog since it's the only thing displayed */
    font-size: 100%;
}

.accounts-centered-dialog {
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;

  z-index: 1001;
  position: fixed;

  left: 50%;
  margin-left: -(@login-buttons-accounts-dialog-width
               + @meteor-accounts-base-padding) / 2;

  top: 50%;
  margin-top: -40px; /* = approximately -height/2, though height can change */
}

@configure-login-service-dialog-width: 530px;

#configure-login-service-dialog {
  width: @configure-login-service-dialog-width;
  margin-left: -(@configure-login-service-dialog-width
               + @meteor-accounts-base-padding) / 2;
  margin-top: -220px; /* = approximately -height/2, though height can change */

  table { width: 100%; }
  input {
    width: 100%;
    font-family: "Courier New", Courier, monospace;
  }
  ol {
    margin-top: 10px;
    margin-bottom: 10px;

    li { margin-left: 30px; }
  }
  .configuration_labels { width: 30%; }
  .configuration_inputs { width: 70%; }
  .new-section { margin-top: 10px; }
  .url { font-family: "Courier New", Courier, monospace; }
}

#configure-login-service-dialog-save-configuration {
  float: right;
}

.configure-login-service-dismiss-button {
  float: left;
}

#just-verified-dismiss-button, #messages-dialog-dismiss-button {
  margin-top: 8px;
}

.hide-background {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  z-index: 999;

  /* XXX consider replacing with DXImageTransform */
  background-color: rgb(0.2, 0.2, 0.2); /* fallback for IE7-8 */

  background-color: rgba(0, 0, 0, 0.7);
}

#login-buttons, .accounts-dialog {
  input[type=text], input[type=email], input[type=password] {
    padding: 4px;
    border: 1px solid #aaa;
    border-radius: 3px;
    line-height: 1;
  }
}


var buildsToDownload = catalog.official.getBuildsForArches(

"No compatible build found for " + packageName + "@" + version);

<html {{htmlAttributes}}>
<head>
{{#each css}}  <link rel="stylesheet" type="text/css" class="__meteor-css__" href="{{../bundledJsCssPrefix}}{{url}}">{{/each}}

{{#if inlineScriptsAllowed}}
<script type='text/javascript'>__meteor_runtime_config__ = {{meteorRuntimeConfig}};</script>
{{else}}
<script type='text/javascript' src='{{rootUrlPathPrefix}}/meteor_runtime_config.js'></script>
{{/if}}
{{#each js}}  <script type="text/javascript" src="{{../bundledJsCssPrefix}}{{url}}"></script>
{{/each}}
{{#each additionalStaticJs}}
  {{#if ../inlineScriptsAllowed}}
    <script type='text/javascript'>
      {{contents}}
    </script>
  {{else}}
    <script type='text/javascript'
            src='{{rootUrlPathPrefix}}{{pathname}}'></script>
  {{/if}}
{{/each}}

{{{head}}}
</head>
<body>
{{{body}}}
</body>
</html>


// Source: http://code.google.com/p/google-code-prettify

// XXX this sucks. I would much rather do this processing at
// bundle-time on the server, not in the client. (though I'd like to
// support both..)

var path = Npm.require('path');

Package.describe({
  summary: "Syntax highlighting of code, from Google",
  version: "1.0.0"
});

// XXX this code dumps symbols into the global namespace (directly
// onto 'window'.) we need to fix that.
Package.on_use(function (api) {
  api.add_files([
    'prettify.js',
    'prettify.css',
    path.join('styles', 'sunburst.css')], "client");
});


e.noCompatibleBuildError = true;
throw e;

var path = require("path");
var fs = require("fs");
var os = require("os");
var Future = require("fibers/future");
var _ = require("underscore");
var files = require('./files.js');
var utils = require('./utils.js');
var updater = require('./updater.js');
var httpHelpers = require('./http-helpers.js');
var fiberHelpers = require('./fiber-helpers.js');
var release = require('./release.js');
var archinfo = require('./archinfo.js');
var catalog = require('./catalog.js');
var Unipackage = require('./unipackage.js').Unipackage;
var config = require('./config.js');
var buildmessage = require('./buildmessage.js');

exports.Tropohouse = function (root, catalog) {
  var self = this;
  self.root = root;
  self.catalog = catalog;
};

// Return the directory containing our loaded collection of tools, releases and
// packages. If we're running an installed version, found at $HOME/.meteor, if
// we are running form a checkout, probably at $CHECKOUT_DIR/.meteor.
var defaultWarehouseDir = function () {
  // a hook for tests, or i guess for users.
  if (process.env.METEOR_WAREHOUSE_DIR)
    return process.env.METEOR_WAREHOUSE_DIR;

  var warehouseBase = files.inCheckout()
     ? files.getCurrentToolsDir() : process.env.HOME;
  // XXX This will be `.meteor` soon, once we've written the code to make the
  // tropohouse and warehouse live together in harmony (eg, allowing tropohouse
  // tools to springboard to warehouse tools).
  return path.join(warehouseBase, ".meteor");
};

// The default tropohouse is on disk at defaultWarehouseDir() and knows not to
// download local packages; you can make your own Tropohouse to override these
// things.
exports.default = new exports.Tropohouse(
  defaultWarehouseDir(), catalog.complete);

_.extend(exports.Tropohouse.prototype, {
  // Returns the load path where one can expect to find the package, at a given
  // version, if we have already downloaded from the package server. Does not
  // check for contents.
  //
  // Returns null if the package name is lexographically invalid.
  packagePath: function (packageName, version, relative) {
    var self = this;
    if (! utils.isValidPackageName(packageName)) {
      return null;
    }

    var relativePath = path.join(config.getPackagesDirectoryName(),
                                 packageName, version);
    return relative ? relativePath : path.join(self.root, relativePath);
  },

  // Pretty extreme! We call this when we learn that something has changed on
  // the server in a way that our sync protocol doesn't understand well.
  wipeAllPackages: function () {
    var self = this;

    var packagesDirectoryName = config.getPackagesDirectoryName();

    var packageRootDir = path.join(self.root, packagesDirectoryName);
    try {
      var packages = fs.readdirSync(packageRootDir);
    } catch (e) {
      // No packages at all? We're done.
      if (e.code === 'ENOENT')
        return;
      throw e;
    }

    // We want to be careful not to break the 'meteor' symlink inside the
    // tropohouse. Hopefully nobody deleted that package!
    var latestToolPackage = null;
    var latestToolVersion = null;
    var currentToolPackage = null;
    var currentToolVersion = null;
    if (release.current.isProperRelease()) {
      currentToolPackage = release.current.getToolsPackage();
      currentToolVersion = release.current.getToolsVersion();
      var latestMeteorSymlink = self.latestMeteorSymlink();
      if (utils.startsWith(latestMeteorSymlink,
                           packagesDirectoryName + path.sep)) {
        var rest = latestMeteorSymlink.substr(packagesDirectoryName.length + path.sep.length);
        var pieces = rest.split(path.sep);
        latestToolPackage = pieces[0];
        latestToolVersion = pieces[1];
      }
    }

    _.each(packages, function (package) {
      var packageDir = path.join(packageRootDir, package);
      _.each(fs.readdirSync(packageDir), function (version) {
        // Is this a pre-0.9.0 "warehouse" version with a hash name?
        if (/^[a-f0-9]{3,}$/.test(version))
          return;

        // Skip the currently-latest tool (ie, don't break top-level meteor
        // symlink). This includes both the symlink with its name and the thing
        // it points to.
        if (package === latestToolPackage &&
            (version === latestToolVersion ||
             utils.startsWith(version, '.' + latestToolVersion + '.'))) {
          return;
        }

        // Skip the currently-executing tool (ie, don't break the current
        // operation).
        if (package === currentToolPackage &&
            (version === currentToolVersion ||
             utils.startsWith(version, '.' + currentToolVersion + '.'))) {
          return;
        }

        files.rm_recursive(path.join(packageDir, version));
      });
    });
  },

  // Contacts the package server, downloads and extracts a tarball for a given
  // buildRecord into a temporary directory, whose path is returned.
  //
  // XXX: Error handling.
  downloadBuildToTempDir: function (versionInfo, buildRecord) {
    var self = this;
    var targetDirectory = files.mkdtemp();
    var packageTarball = httpHelpers.getUrl({
      url: buildRecord.build.url,
      encoding: null
    });
    files.extractTarGz(packageTarball, targetDirectory);
    return targetDirectory;
  },

  // Given versionInfo for a package version and required architectures, checks
  // to make sure that we have the package at the requested arch. If we do not
  // have the package, contact the server and attempt to download and extract
  // the right build.
  //
  // XXX more precise error handling in offline case. maybe throw instead like
  // warehouse does.  actually, generally deal with error handling.
  maybeDownloadPackageForArchitectures: function (options) {
    var self = this;
    buildmessage.assertInCapture();
    if (!options.packageName)
      throw Error("Missing required argument: packageName");
    if (!options.version)
      throw Error("Missing required argument: version");
    if (!options.architectures)
      throw Error("Missing required argument: architectures");

    var packageName = options.packageName;
    var version = options.version;

    // If this package isn't coming from the package server (loaded from a
    // checkout, or from an app package directory), don't try to download it (we
    // already have it)
    // (In the special case of springboarding, we avoid using self.catalog
    // here because it is catalog.complete and is not yet initialized.)
    if (!options.definitelyNotLocal && self.catalog.isLocalPackage(packageName))
      return;

    // Figure out what arches (if any) we have loaded for this package version
    // already.
    var packageLinkFile = self.packagePath(packageName, version);
    var downloadedArches = [];
    var packageLinkTarget = null;
    try {
      packageLinkTarget = fs.readlinkSync(packageLinkFile);
    } catch (e) {
      // Complain about anything other than "we don't have it at all". This
      // includes "not a symlink": The main reason this would not be a symlink
      // is if it's a directory containing a pre-0.9.0 package (ie, this is a
      // warehouse package not a tropohouse package). But the versions should
      // not overlap: warehouse versions are truncated SHAs whereas tropohouse
      // versions should be semver.
      if (e.code !== 'ENOENT')
        throw e;
    }
    if (packageLinkTarget) {
      // The symlink will be of the form '.VERSION.RANDOMTOKEN++web.browser+os',
      // so this strips off the part before the '++'.
      // XXX maybe we should just read the unipackage.json instead of
      //     depending on the symlink?
      var archPart = packageLinkTarget.split('++')[1];
      if (!archPart)
        throw Error("unexpected symlink target for " + packageName + "@" +
                    version + ": " + packageLinkTarget);
      downloadedArches = archPart.split('+');
    }

    var archesToDownload = _.filter(options.architectures, function (requiredArch) {
      return !archinfo.mostSpecificMatch(requiredArch, downloadedArches);
    });

    // Have everything we need? Great.
    if (!archesToDownload.length) {
      return;
    }

    // Since we are downloading from the server (and we've already done the
    // local package check), we can use the official catalog here. (This is
    // important, since springboarding calls this function before the complete
    // catalog is ready!)
    var buildsToDownload = catalog.official.getBuildsForArches(
      packageName, version, archesToDownload);
    if (! buildsToDownload) {
      throw new Error(
        "No compatible build found for " + packageName + "@" + version);
    }

    // XXX replace with a real progress bar in downloadMissingPackages
    if (!options.silent) {
      process.stderr.write(
        "  downloading " + packageName + " at version " + version + " ... ");
    }

    var buildTempDirs = [];
    // If there's already a package in the tropohouse, start with it.
    if (packageLinkTarget) {
      buildTempDirs.push(path.resolve(path.dirname(packageLinkFile),
                                      packageLinkTarget));
    }
    // XXX how does concurrency work here?  we could just get errors if we try
    // to rename over the other thing?  but that's the same as in warehouse?
    _.each(buildsToDownload, function (build) {
      buildTempDirs.push(self.downloadBuildToTempDir(
        {packageName: packageName, version: version}, build));
    });

    // We need to turn our builds into a single unipackage.
    var unipackage = new Unipackage;
    _.each(buildTempDirs, function (buildTempDir, i) {
      unipackage._loadUnibuildsFromPath(
        packageName,
        buildTempDir,
        {firstUnipackage: i === 0});
    });
    // Note: wipeAllPackages depends on this filename structure, as does the
    // part above which readlinks.
    var newPackageLinkTarget = '.' + version + '.'
          + utils.randomToken() + '++' + unipackage.buildArchitectures();
    var combinedDirectory = self.packagePath(packageName, newPackageLinkTarget);
    unipackage.saveToPath(combinedDirectory, {
      // We got this from the server, so we can't rebuild it.
      elideBuildInfo: true
    });
    files.symlinkOverSync(newPackageLinkTarget, packageLinkFile);

    // Clean up old version.
    if (packageLinkTarget) {
      files.rm_recursive(self.packagePath(packageName, packageLinkTarget));
    }

    if (!options.silent) {
      process.stderr.write(" done\n");
    }

    return;
  },

  // Go through a list of packages and makes sure we have enough builds of the
  // package downloaded such that we can load a browser unibuild and a unibuild
  // that will run on this system (or the requested architecture). Return the
  // object with mapping packageName to version for the packages that we have
  // successfully downloaded.
  downloadMissingPackages: function (versionMap, options) {
    var self = this;
    buildmessage.assertInCapture();
    options = options || {};
    var serverArch = options.serverArch || archinfo.host();
    var downloadedPackages = {};
    _.each(versionMap, function (version, name) {
      try {
        self.maybeDownloadPackageForArchitectures({
          packageName: name,
          version: version,
          architectures: [serverArch]
        });
        downloadedPackages[name] = version;
      } catch (err) {
        // We have failed to download the right things and put them on disk!
        // This should not happen, and we aren't sure why it happened.
        // XXX plenty of reasons why this might happen!  eg, no network.
        //     better error handling here!
        console.log(err);
      }
    });
    return downloadedPackages;
  },

  latestMeteorSymlink: function () {
    var self = this;
    var linkPath = path.join(self.root, 'meteor');
    return fs.readlinkSync(linkPath);
  },

  replaceLatestMeteorSymlink: function (linkText) {
    var self = this;
    var linkPath = path.join(self.root, 'meteor');
    files.symlinkOverSync(linkText, linkPath);
  }
});


// The HTTP object used to be called Meteor.http.
// XXX COMPAT WITH 0.6.4
Meteor.http = HTTP;


// package downloaded such that we can load a browser unibuild and a unibuild

// that will run on this system (or the requested architecture). Return the

// object with mapping packageName to version for the packages that we have

downloadMissingPackages: function (versionMap, options) {

// XXX This function's error handling capabilities are poor. It's supposed to

// return a data structure that its callers check, but most of its callers

// don't check it. Bleah.  Should rewrite this and all of its callers.


<template name="pkg_appcache">
{{#markdown}}

## `appcache`

The `appcache` package stores the static parts of a Meteor application
(the client side Javascript, HTML, CSS, and images) in the browser's
[application cache](https://en.wikipedia.org/wiki/AppCache). To enable
caching simply add the `appcache` package to your project.

* Once a user has visited a Meteor application for the first time and
  the application has been cached, on subsequent visits the web page
  loads faster because the browser can load the application out of the
  cache without contacting the server first.

* Hot code pushes are loaded by the browser in the background while the
  app continues to run.  Once the new code has been fully loaded the
  browser is able to switch over to the new code quickly.

* The application cache allows the application to be loaded even when
  the browser doesn't have an Internet connection, and so enables using
  the app offline.

(Note however that the `appcache` package by itself doesn't make
*data* available offline: in an application loaded offline, a Meteor
Collection will appear to be empty in the client until the Internet
becomes available and the browser is able to establish a livedata
connection).

The application cache works transparently in all supported browsers
except for Firefox, which pops up a message saying "This website is
asking to store data on your computer for offline use" and asks the
user whether to allow or deny the request. To turn AppCache off for
Firefox or other specific browsers use:

    Meteor.AppCache.config({
      chrome: false,
      firefox: false
    });

The supported browsers that can be enabled or disabled include, but are
not limited to, `android`, `chrome`, `chromium`, `chromeMobileIOS`,
`firefox`, `ie`, `mobileSafari` and `safari`.

Browsers limit the amount of data they will put in the application
cache, which can vary due to factors such as how much disk space is
free.  Unfortunately if your application goes over the limit rather
than disabling the application cache altogether and running the
application online, the browser will instead fail that particular
*update* of the cache, leaving your users running old code.

Thus it's best to keep the size of the cache below 5MB.  The
`appcache` package will print a warning on the Meteor server console
if the total size of the resources being cached is over 5MB.

If you have files too large to fit in the cache you can disable
caching by URL prefix.  For example,

    Meteor.AppCache.config({onlineOnly: ['/online/']});

causes files in your `public/online` directory to not be cached, and
so they will only be available online.  You can then move your large
files into that directory and refer to them at the new URL:

    <img src="/online/bigimage.jpg">

If you'd prefer not to move your files, you can use the file names
themselves as the URL prefix:

    Meteor.AppCache.config({
      onlineOnly: [
        '/bigimage.jpg',
        '/largedata.json'
      ]
    });

though keep in mind that since the exclusion is by prefix (this is a
limitation of the application cache manifest), excluding
`/largedata.json` will also exclude such URLs as
`/largedata.json.orig` and `/largedata.json/file1`.

For more information about how Meteor interacts with the application
cache, see the
[AppCache page](https://github.com/meteor/meteor/wiki/AppCache)
in the Meteor wiki.

{{/markdown}}
</template>


// We have failed to download the right things and put them on disk!

// This should not happen, and we aren't sure why it happened.

// XXX plenty of reasons why this might happen!  eg, no network.

keep keep keep keep keep replace replace replace replace replace keep keep keep keep keep

// continue, which is weird, but we want to avoid a stack trace...

// the caller is supposed to check the size of the return value,


#room-list .room.selected {
    color: white;
    background-color: black;
}

.room .name {
    display: inline;
}

.room .delete {
    float: right;
    display: none;
}

.room:hover .delete {
    display: block;
}

.add-room {
    margin-top: 20px;
    font-style: italic;
}

.add-room:hover {
    text-decoration: underline;
}


Package.describe({
  summary: "Simulates local storage on IE 6,7 using userData",
  version: "1.0.0"
});

Package.on_use(function (api) {
  api.use('random', 'client');

  api.add_files('localstorage.js', 'client');
});

Package.on_test(function (api) {
  api.use('localstorage', 'client');
  api.use('tinytest');

  api.add_files('localstorage_tests.js', 'client');
});


#else
class NSMenu;
#endif  // __OBJC__
#elif defined(TOOLKIT_GTK)
struct GtkMenu;
#elif defined(OS_WIN)
#include <windows.h>
#endif  // defined(OS_MACOSX)
namespace content {

keep keep keep keep replace keep keep keep keep keep

// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "content/nw/src/api/menu/menu.h"

#include "base/values.h"
#include "content/nw/src/api/menuitem/menuitem.h"

namespace api {

using namespace v8;

void Menu::Create(const base::DictionaryValue& option) {
}

void Menu::Destroy() {
}

void Menu::SetTitle(const std::string& title) {
}

void Menu::Append(MenuItem* menu_item) {
}

void Menu::Insert(MenuItem* menu_item, int pos) {
}

void Menu::Remove(MenuItem* menu_item, int pos_hint) {
}

void Menu::RemoveAt(int pos) {
}

void Menu::Popup(int x, int y, content::Shell* shell) {
}

}  // namespace api


// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_SHELL_SHELL_CONTENT_CLIENT_H_
#define CONTENT_SHELL_SHELL_CONTENT_CLIENT_H_

#include <string>
#include <vector>

#include "base/compiler_specific.h"
#include "content/public/common/content_client.h"

namespace content {

class ShellContentClient : public ContentClient {
 public:
  virtual ~ShellContentClient();

  virtual std::string GetUserAgent() const OVERRIDE;
  virtual string16 GetLocalizedString(int message_id) const OVERRIDE;
  virtual base::StringPiece GetDataResource(
      int resource_id,
      ui::ScaleFactor scale_factor) const OVERRIDE;
};

}  // namespace content

#endif  // CONTENT_SHELL_SHELL_CONTENT_CLIENT_H_


// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "zip.h"

#include "base/bind.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/string16.h"
#include "base/string_util.h"
#include "net/base/file_stream.h"
#include "third_party/zlib/contrib/minizip/unzip.h"
#include "third_party/zlib/contrib/minizip/zip.h"
#include "zip_internal.h"
#include "zip_reader.h"

namespace {

bool AddFileToZip(zipFile zip_file, const FilePath& src_dir) {
  net::FileStream stream(NULL);
  int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
  if (stream.OpenSync(src_dir, flags) != 0) {
    DLOG(ERROR) << "Could not open stream for path "
                << src_dir.value();
    return false;
  }

  int num_bytes;
  char buf[zip::internal::kZipBufSize];
  do {
    num_bytes = stream.ReadSync(buf, zip::internal::kZipBufSize);
    if (num_bytes > 0) {
      if (ZIP_OK != zipWriteInFileInZip(zip_file, buf, num_bytes)) {
        DLOG(ERROR) << "Could not write data to zip for path "
                    << src_dir.value();
        return false;
      }
    }
  } while (num_bytes > 0);

  return true;
}

bool AddEntryToZip(zipFile zip_file, const FilePath& path,
                   const FilePath& root_path) {
  std::string str_path =
      path.AsUTF8Unsafe().substr(root_path.value().length() + 1);
#if defined(OS_WIN)
  ReplaceSubstringsAfterOffset(&str_path, 0u, "\\", "/");
#endif

  bool is_directory = file_util::DirectoryExists(path);
  if (is_directory)
    str_path += "/";

  if (ZIP_OK != zipOpenNewFileInZip(
      zip_file, str_path.c_str(),
      NULL, NULL, 0u, NULL, 0u, NULL,  // file info, extrafield local, length,
                                       // extrafield global, length, comment
      Z_DEFLATED, Z_DEFAULT_COMPRESSION)) {
    DLOG(ERROR) << "Could not open zip file entry " << str_path;
    return false;
  }

  bool success = true;
  if (!is_directory) {
    success = AddFileToZip(zip_file, path);
  }

  if (ZIP_OK != zipCloseFileInZip(zip_file)) {
    DLOG(ERROR) << "Could not close zip file entry " << str_path;
    return false;
  }

  return success;
}

bool ExcludeNoFilesFilter(const FilePath& file_path) {
  return true;
}

bool ExcludeHiddenFilesFilter(const FilePath& file_path) {
  return file_path.BaseName().value()[0] != '.';
}

}  // namespace

namespace zip {

bool Unzip(const FilePath& src_file, const FilePath& dest_dir) {
  ZipReader reader;
  if (!reader.Open(src_file)) {
    DLOG(WARNING) << "Failed to open " << src_file.value();
    return false;
  }
  while (reader.HasMore()) {
    if (!reader.OpenCurrentEntryInZip()) {
      DLOG(WARNING) << "Failed to open the current file in zip";
      return false;
    }
    if (reader.current_entry_info()->is_unsafe()) {
      DLOG(WARNING) << "Found an unsafe file in zip "
                    << reader.current_entry_info()->file_path().value();
      return false;
    }
    if (!reader.ExtractCurrentEntryIntoDirectory(dest_dir)) {
      DLOG(WARNING) << "Failed to extract "
                    << reader.current_entry_info()->file_path().value();
      return false;
    }
    if (!reader.AdvanceToNextEntry()) {
      DLOG(WARNING) << "Failed to advance to the next file";
      return false;
    }
  }
  return true;
}

bool ZipWithFilterCallback(const FilePath& src_dir, const FilePath& dest_file,
                           const FilterCallback& filter_cb) {
  DCHECK(file_util::DirectoryExists(src_dir));

  zipFile zip_file = internal::OpenForZipping(dest_file.AsUTF8Unsafe(),
                                              APPEND_STATUS_CREATE);

  if (!zip_file) {
    DLOG(WARNING) << "couldn't create file " << dest_file.value();
    return false;
  }

  bool success = true;
  file_util::FileEnumerator file_enumerator(
      src_dir, true,  // recursive
      static_cast<file_util::FileEnumerator::FileType>(
          file_util::FileEnumerator::FILES |
          file_util::FileEnumerator::DIRECTORIES));
  for (FilePath path = file_enumerator.Next(); !path.value().empty();
       path = file_enumerator.Next()) {
    if (!filter_cb.Run(path)) {
      continue;
    }

    if (!AddEntryToZip(zip_file, path, src_dir)) {
      success = false;
      return false;
    }
  }

  if (ZIP_OK != zipClose(zip_file, NULL)) {  // global comment
    DLOG(ERROR) << "Error closing zip file " << dest_file.value();
    return false;
  }

  return success;
}

bool Zip(const FilePath& src_dir, const FilePath& dest_file,
         bool include_hidden_files) {
  if (include_hidden_files) {
    return ZipWithFilterCallback(
        src_dir, dest_file, base::Bind(&ExcludeNoFilesFilter));
  } else {
    return ZipWithFilterCallback(
        src_dir, dest_file, base::Bind(&ExcludeHiddenFilesFilter));
  }
}

}  // namespace zip


// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "content/nw/src/api/menuitem/menuitem.h"

#include "content/nw/src/api/menu/menu.h"

namespace api {

void MenuItem::Create(const base::DictionaryValue& option) {
}

void MenuItem::Destroy() {
}

void MenuItem::SetLabel(const std::string& label) {
}

void MenuItem::SetIcon(const std::string& icon) {
}

void MenuItem::SetTooltip(const std::string& tooltip) {
}

void MenuItem::SetEnabled(bool enabled) {
}

void MenuItem::SetChecked(bool checked) {
}

void MenuItem::SetSubmenu(Menu* sub_menu) {
}

}  // namespace api


void Menu::Create(const base::DictionaryValue& option) {

keep keep keep replace replace keep keep keep keep keep

// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#ifndef CONTENT_NW_SRC_API_MENUITEM_MENUITEM_H_
#define CONTENT_NW_SRC_API_MENUITEM_MENUITEM_H_

#include "base/compiler_specific.h"
#include "content/nw/src/api/base/base.h"

#include <string>

#if defined(OS_MACOSX)
#if __OBJC__
@class NSMenuItem;
@class MenuItemDelegate;
#else
class NSMenuItem;
class MenuItemDelegate;
#endif  // __OBJC__
#elif defined(TOOLKIT_GTK)
class GtkMenuItem;
#elif defined(OS_WIN)
#include <windows.h>
#endif  // defined(OS_MACOSX)

namespace api {

class Menu;

class MenuItem : public Base {
 public:
  MenuItem(int id,
           DispatcherHost* dispatcher_host,
           const base::DictionaryValue& option);
  virtual ~MenuItem();

  virtual void Call(const std::string& method,
                    const base::ListValue& arguments) OVERRIDE;
  void OnClick();

 private:
  friend class Menu;

  // Platform-independent implementations
  void Create(const base::DictionaryValue& option);
  void Destroy();
  void SetLabel(const std::string& label);
  void SetIcon(const std::string& icon);
  void SetTooltip(const std::string& tooltip);
  void SetEnabled(bool enabled);
  void SetChecked(bool checked);
  void SetSubmenu(Menu* sub_menu);

#if defined(OS_MACOSX)
  __block NSMenuItem* menu_item_;
  __block MenuItemDelegate* delegate_;
#elif defined(TOOLKIT_GTK)
  GtkMenuItem* menu_item_;
#elif defined(OS_WIN)

#endif

  DISALLOW_COPY_AND_ASSIGN(MenuItem);
};

}  // namespace api

#endif  // CONTENT_NW_SRC_API_MENUITEM_MENUITEM_H_


// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "content/nw/src/net/shell_url_request_context_getter.h"

#include "base/logging.h"
#include "base/string_split.h"
#include "base/threading/worker_pool.h"
#include "content/public/browser/browser_thread.h"
#include "content/nw/src/net/shell_network_delegate.h"
#include "content/nw/src/nw_protocol_handler.h"
#include "net/base/cert_verifier.h"
#include "net/base/default_server_bound_cert_store.h"
#include "net/base/host_resolver.h"
#include "net/base/server_bound_cert_service.h"
#include "net/base/ssl_config_service_defaults.h"
#include "net/cookies/cookie_monster.h"
#include "net/http/http_auth_handler_factory.h"
#include "net/http/http_cache.h"
#include "net/http/http_server_properties_impl.h"
#include "net/proxy/proxy_service.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_storage.h"
#include "net/url_request/url_request_job_factory_impl.h"

namespace content {

ShellURLRequestContextGetter::ShellURLRequestContextGetter(
    const FilePath& base_path,
    MessageLoop* io_loop,
    MessageLoop* file_loop)
    : ignore_certificate_errors_(true),
      base_path_(base_path),
      io_loop_(io_loop),
      file_loop_(file_loop) {
  // Must first be created on the UI thread.
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  // We must create the proxy config service on the UI loop on Linux because it
  // must synchronously run on the glib message loop. This will be passed to
  // the URLRequestContextStorage on the IO thread in GetURLRequestContext().
  proxy_config_service_.reset(
      net::ProxyService::CreateSystemProxyConfigService(
          io_loop_->message_loop_proxy(), file_loop_));
}

ShellURLRequestContextGetter::~ShellURLRequestContextGetter() {
}

net::URLRequestContext* ShellURLRequestContextGetter::GetURLRequestContext() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  if (!url_request_context_.get()) {
    url_request_context_.reset(new net::URLRequestContext());
    network_delegate_.reset(new ShellNetworkDelegate);
    url_request_context_->set_network_delegate(network_delegate_.get());
    storage_.reset(
        new net::URLRequestContextStorage(url_request_context_.get()));
    storage_->set_cookie_store(new net::CookieMonster(NULL, NULL));
    storage_->set_server_bound_cert_service(new net::ServerBoundCertService(
        new net::DefaultServerBoundCertStore(NULL),
        base::WorkerPool::GetTaskRunner(true)));
    url_request_context_->set_accept_language("en-us,en");
    url_request_context_->set_accept_charset("iso-8859-1,*,utf-8");

    storage_->set_host_resolver(
        net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism,
                                      net::HostResolver::kDefaultRetryAttempts,
                                      NULL));
    storage_->set_cert_verifier(net::CertVerifier::CreateDefault());
    // TODO(jam): use v8 if possible, look at chrome code.
    storage_->set_proxy_service(
        net::ProxyService::CreateUsingSystemProxyResolver(
        proxy_config_service_.release(),
        0,
        NULL));
    storage_->set_ssl_config_service(new net::SSLConfigServiceDefaults);
    storage_->set_http_auth_handler_factory(
        net::HttpAuthHandlerFactory::CreateDefault(
            url_request_context_->host_resolver()));
    storage_->set_http_server_properties(new net::HttpServerPropertiesImpl);

    FilePath cache_path = base_path_.Append(FILE_PATH_LITERAL("Cache"));
    net::HttpCache::DefaultBackend* main_backend =
        new net::HttpCache::DefaultBackend(
            net::DISK_CACHE,
            cache_path,
            0,
            BrowserThread::GetMessageLoopProxyForThread(
                BrowserThread::CACHE));

    net::HttpNetworkSession::Params network_session_params;
    network_session_params.host_resolver =
        url_request_context_->host_resolver();
    network_session_params.cert_verifier =
        url_request_context_->cert_verifier();
    network_session_params.server_bound_cert_service =
        url_request_context_->server_bound_cert_service();
    network_session_params.proxy_service =
        url_request_context_->proxy_service();
    network_session_params.ssl_config_service =
        url_request_context_->ssl_config_service();
    network_session_params.http_auth_handler_factory =
        url_request_context_->http_auth_handler_factory();
    network_session_params.network_delegate =
        url_request_context_->network_delegate();
    network_session_params.http_server_properties =
        url_request_context_->http_server_properties();
    network_session_params.ignore_certificate_errors =
        ignore_certificate_errors_;

    net::HttpCache* main_cache = new net::HttpCache(
        network_session_params, main_backend);
    storage_->set_http_transaction_factory(main_cache);

    net::URLRequestJobFactoryImpl* job_factory =
      new net::URLRequestJobFactoryImpl();
    job_factory->SetProtocolHandler("nw", new nw::NwProtocolHandler());
    storage_->set_job_factory(job_factory);
  }

  return url_request_context_.get();
}

scoped_refptr<base::SingleThreadTaskRunner>
    ShellURLRequestContextGetter::GetNetworkTaskRunner() const {
  return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
}

net::HostResolver* ShellURLRequestContextGetter::host_resolver() {
  return url_request_context_->host_resolver();
}

}  // namespace content


// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "content/nw/src/api/menu/menu.h"

#include "base/values.h"
#include "content/nw/src/api/dispatcher_host.h"
#include "content/nw/src/api/menuitem/menuitem.h"
#include "content/nw/src/shell.h"

namespace api {

Menu::Menu(int id,
           DispatcherHost* dispatcher_host,
           const base::DictionaryValue& option)
    : Base(id, dispatcher_host, option) {
  Create(option);
}

Menu::~Menu() {
  Destroy();
}

void Menu::Call(const std::string& method,
                const base::ListValue& arguments) {
  if (method == "SetTitle") {
    std::string title;
    arguments.GetString(0, &title);
    SetTitle(title);
  } else if (method == "Append") {
    int object_id = 0;
    arguments.GetInteger(0, &object_id);
    Append(static_cast<MenuItem*>(dispatcher_host()->GetObject(object_id)));
  } else if (method == "Insert") {
    int object_id = 0;
    arguments.GetInteger(0, &object_id);
    int pos = 0;
    arguments.GetInteger(1, &pos);
    Insert(static_cast<MenuItem*>(dispatcher_host()->GetObject(object_id)),
           pos);
  } else if (method == "Remove") {
    int object_id = 0;
    arguments.GetInteger(0, &object_id);
    int pos_hint = 0;
    arguments.GetInteger(1, &pos_hint);
    Remove(static_cast<MenuItem*>(dispatcher_host()->GetObject(object_id)),
           pos_hint);
  } else if (method == "RemoveAt") {
    int pos = 0;
    arguments.GetInteger(0, &pos);
    RemoveAt(pos);
  } else if (method == "Popup") {
    int x = 0;
    arguments.GetInteger(0, &x);
    int y = 0;
    arguments.GetInteger(1, &y);
    Popup(x, y, content::Shell::FromRenderViewHost(
          dispatcher_host()->render_view_host()));
  } else {
    NOTREACHED() << "Invalid call to Menu method:" << method
                 << " arguments:" << arguments;
  }
}

}  // namespace api


// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#import "content/nw/src/api/menuitem/menuitem_delegate_mac.h"

#include "content/nw/src/api/menuitem/menuitem.h"

@implementation MenuItemDelegate

-(id)initWithMenuItem: (api::MenuItem*)item {
  if ([super init]) {
    menu_item_ = item;
  }

  return self;
}

-(void)invoke: (id)sender {
  menu_item_->OnClick();
}

@end


keep keep keep replace replace keep keep keep keep


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDevelopmentRegion</key>
	<string>en</string>
	<key>CFBundleDisplayName</key>
	<string>${EXECUTABLE_NAME}</string>
	<key>CFBundleExecutable</key>
	<string>${EXECUTABLE_NAME}</string>
	<key>CFBundleIdentifier</key>
	<string>com.intel.nw.helper</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>${PRODUCT_NAME}</string>
	<key>CFBundlePackageType</key>
	<string>APPL</string>
	<key>CFBundleSignature</key>
	<string>????</string>
	<key>LSFileQuarantineEnabled</key>
	<true/>
	<key>LSMinimumSystemVersion</key>
	<string>${MACOSX_DEPLOYMENT_TARGET}.0</string>
	<key>LSUIElement</key>
	<string>1</string>
	<key>NSSupportsAutomaticGraphicsSwitching</key>
	<true/>
</dict>
</plist>


<button onclick="win.focus()">Focus</button>

<button onclick="win.blur()">Blur</button>

<button onclick="win.show()">Show</button>

<button onclick="win.hide()">Hide</button>

<button onclick="win.maximize()">Maximize</button>

<button onclick="win.unmaximize()">Unmaximize</button>

<button onclick="win.minimize()">Minimize</button>

<button onclick="win.restore()">Restore</button>

<button onclick="win.enterFullscreen()">EnterFullscreen</button>

<button onclick="win.leaveFullscreen()">LeaveFullscreen</button>

<button onclick="win.close()">Close</button>

<button onclick="win.close(true)">Force Close</button>


// Copyright (c) 2012 Roger Wang <roger.wang@linux.intel.com>
//                    Zhao Cheng <zcbenz@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#ifndef NW_VERSION_H
#define NW_VERSION_H

#define NW_MAJOR_VERSION 0
#define NW_MINOR_VERSION 3
#define NW_PATCH_VERSION 0
#define NW_VERSION_IS_RELEASE 0

#ifndef NW_STRINGIFY
#define NW_STRINGIFY(n) NW_STRINGIFY_HELPER(n)
#define NW_STRINGIFY_HELPER(n) #n
#endif

#if NW_VERSION_IS_RELEASE
# define NW_VERSION_STRING  NW_STRINGIFY(NW_MAJOR_VERSION) "." \
                              NW_STRINGIFY(NW_MINOR_VERSION) "." \
                              NW_STRINGIFY(NW_PATCH_VERSION)
#else
# define NW_VERSION_STRING  NW_STRINGIFY(NW_MAJOR_VERSION) "." \
                              NW_STRINGIFY(NW_MINOR_VERSION) "." \
                              NW_STRINGIFY(NW_PATCH_VERSION) "-pre"
#endif

#define NW_VERSION "v" NW_VERSION_STRING

#define NW_VERSION_AT_LEAST(major, minor, patch) \
  (( (major) < NW_MAJOR_VERSION) \
  || ((major) == NW_MAJOR_VERSION && (minor) < NW_MINOR_VERSION) \
  || ((major) == NW_MAJOR_VERSION && (minor) == NW_MINOR_VERSION && (patch) <= NW_PATCH_VERSION))

#endif /* NW_VERSION_H */


#else
class NSMenuItem;
class MenuItemDelegate;
#endif  // __OBJC__
#elif defined(TOOLKIT_GTK)
class GtkMenuItem;
#elif defined(OS_WIN)
#include <windows.h>
#endif  // defined(OS_MACOSX)

keep keep keep keep keep replace keep keep keep

// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "content/nw/src/api/menu/menu.h"

#include "content/nw/src/api/menuitem/menuitem.h"

namespace api {

using namespace v8;

void Menu::Create(const base::DictionaryValue& option) {
}

void Menu::Destroy() {
}

void Menu::SetTitle(const std::string& title) {
}

void Menu::Append(MenuItem* menu_item) {
}

void Menu::Insert(MenuItem* menu_item, int pos) {
}

void Menu::Remove(MenuItem* menu_item, int pos_hint) {
}

void Menu::RemoveAt(int pos) {
}

void Menu::Popup(int x, int y, content::Shell* shell) {
}

}  // namespace api


// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "content/nw/src/api/base/base.h"

#include "base/logging.h"
#include "base/values.h"

namespace api {

Base::Base(int id,
           DispatcherHost* dispatcher_host,
           const base::DictionaryValue& option)
    : id_(id),
      dispatcher_host_(dispatcher_host) {
}

Base::~Base() {
}

void Base::Call(const std::string& method, const base::ListValue& arguments) {
  NOTREACHED() << "Uncatched call in Base"
               << " method:" << method
               << " arguments:" << arguments;
}

void Base::CallSync(const std::string& method,
                    const base::ListValue& arguments,
                    base::ListValue* result) {
  NOTREACHED() << "Uncatched callAsync in Base"
               << " method:" << method
               << " arguments:" << arguments;
}

}  // namespace api


#else
class NSStatusItem;
#endif  // __OBJC__
#elif defined(TOOLKIT_GTK)
class GtkStatusIcon;
#elif defined(OS_WIN)
#include <windows.h>
#endif  // defined(OS_MACOSX)

keep keep keep keep replace keep keep keep keep


// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "content/nw/src/api/clipboard/clipboard.h"

#include "base/values.h"
#include "base/utf_string_conversions.h"
#include "base/string16.h"
#include "content/nw/src/api/dispatcher_host.h"
#include "ui/base/clipboard/clipboard.h"

namespace api {

Clipboard::Clipboard(int id,
           DispatcherHost* dispatcher_host,
           const base::DictionaryValue& option)
    : Base(id, dispatcher_host, option) {
}

Clipboard::~Clipboard() {
}

void Clipboard::Call(const std::string& method,
                     const base::ListValue& arguments) {
  if (method == "Set") {
    std::string text, type;
    arguments.GetString(0, &text);
    arguments.GetString(1, &type);
    SetText(text);
  } else if (method == "Clear") {
    Clear();
  } else {
    NOTREACHED() << "Invalid call to Clipboard method:" << method
                 << " arguments:" << arguments;
  }
}

void Clipboard::CallSync(const std::string& method,
                         const base::ListValue& arguments,
                         base::ListValue* result) {
  if (method == "Get") {
    result->AppendString(GetText());
  } else {
    NOTREACHED() << "Invalid call to Clipboard method:" << method
                 << " arguments:" << arguments;
  }
}

void Clipboard::SetText(std::string& text) {
  ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
  ui::Clipboard::ObjectMap map;
  map[ui::Clipboard::CBF_TEXT].push_back(
      std::vector<char>(text.begin(), text.end()));
  clipboard->WriteObjects(ui::Clipboard::BUFFER_STANDARD, map);
}

std::string Clipboard::GetText() {
  ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
  string16 text;
  clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &text);
  return UTF16ToUTF8(text);
}

void Clipboard::Clear() {
  ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
  clipboard->Clear(ui::Clipboard::BUFFER_STANDARD);
}

}  // namespace api


// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#ifndef CONTENT_NW_SRC_API_DISPATCHER_HOST_H_
#define CONTENT_NW_SRC_API_DISPATCHER_HOST_H_

#include "base/basictypes.h"
#include "base/id_map.h"
#include "content/public/browser/render_view_host_observer.h"

#include <string>

namespace base {
class DictionaryValue;
class ListValue;
}

namespace WebKit {
class WebFrame;
}

namespace api {

class Base;

class DispatcherHost : public content::RenderViewHostObserver {
 public:
  explicit DispatcherHost(content::RenderViewHost* render_view_host);
  virtual ~DispatcherHost();

  Base* GetObject(int id);
  void SendEvent(Base* object,
                 const std::string& event,
                 const base::ListValue& arguments);

  virtual bool Send(IPC::Message* message) OVERRIDE;
  content::RenderViewHost* render_view_host() const {
    return content::RenderViewHostObserver::render_view_host();
  }

 private:
  IDMap<Base, IDMapOwnPointer> objects_registry_;

  // RenderViewHostObserver implementation.
  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;

  void OnAllocateObject(int object_id,
                        const std::string& type,
                        const base::DictionaryValue& option);
  void OnDeallocateObject(int object_id);
  void OnCallObjectMethod(int object_id,
                          const std::string& type,
                          const std::string& method,
                          const base::ListValue& arguments);
  void OnCallObjectMethodSync(int object_id,
                              const std::string& type,
                              const std::string& method,
                              const base::ListValue& arguments,
                              base::ListValue* result);

  DISALLOW_COPY_AND_ASSIGN(DispatcherHost);
};

}  // namespace api

#endif  // CONTENT_NW_SRC_API_DISPATCHER_HOST_H_


# Introduction

node-webkit is an app runtime based on `Chromium` and `node.js`. You can
write native apps in HTML and Javascript with node-webkit. It also lets you
to call Node.js modules directly from DOM and enables a new way of writing
native applications with all Web technologies.

It's created and developed in Intel Open Source Technology Center.

[Introduction to node-webkit (slides)](https://speakerdeck.com/u/zcbenz/p/node-webkit-app-runtime-based-on-chromium-and-node-dot-js)

# Features

* Apps written in modern HTML5, CSS3, JS and WebGL.
* Complete support for [Node.js APIs](http://nodejs.org/api/) and all its [third party modules](https://npmjs.org).
* No extra performance lose in calling Node.js APIs.
* Easy to package and distribute apps.

# Downloads

[v0.2.6 release note](https://groups.google.com/forum/?fromgroups=#!topic/node-webkit/dIYKeL6fPRM)

Prebuilt binaries (v0.2.6):

* Linux: [32bit](http://s3.amazonaws.com/node-webkit/nw_release_linux_x32.tar.gz) / [64bit](https://s3.amazonaws.com/node-webkit/nw_release_linux_x64.tar.gz)
* Windows: [win32](http://s3.amazonaws.com/node-webkit/nw_release_win32.zip)
* Mac: [32bit](http://s3.amazonaws.com/node-webkit/nw_release_mac.zip)

[Looking for older versions?](https://github.com/rogerwang/node-webkit/wiki/Downloads-of-old-versions)

Demos:

* [Hello World](http://s3.amazonaws.com/node-webkit/hello_world2.nw)
* [File Explorer](https://github.com/zcbenz/nw-file-explorer)

# Quick Start

Create `index.html`:

````html
<html>
<head>
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
We are using node.js <script>document.write(process.version)</script>
</body>
</html>
````

Create `package.json`:

````json
{
  "name": "nw-demo",
  "main": "index.html"
}
````

Compress `index.html` and `package.json` into a zip archive, and rename
it to `app.nw`:

    app.nw
    |-- package.json
    `-- index.html

Download the prebuilt binary for your platform and use it to open the
`app.nw` file:

````bash
$ ./nw app.nw
````

Note: on Windows, you can drag the `app.nw` to `nw.exe` to open it.

For more information on how to write/package/run apps, see:

* [How to run apps](https://github.com/rogerwang/node-webkit/wiki/How-to-run-apps)
* [How to package and distribute your apps](https://github.com/rogerwang/node-webkit/wiki/How-to-package-and-distribute-your-apps)

And our [Wiki](https://github.com/rogerwang/node-webkit/wiki) for much more.

# Community

We use [node-webkit | Google Groups](http://groups.google.com/group/node-webkit) as
our mailing list, subscribe via [node-webkit+subscribe@googlegroups.com](mailto:node-webkit+subscribe@googlegroups.com).

# License

`node-webkit`'s code uses the MIT license, see our `LICENSE` file.


Package.describe({
  summary: "Serves a Meteor app over HTTP",
  version: '1.12.0'
});

Npm.depends({"basic-auth-connect": "1.0.0",
             "cookie-parser": "1.4.5",
             connect: "3.7.0",
             compression: "1.7.4",
             errorhandler: "1.5.1",
             parseurl: "1.3.3",
             send: "0.17.1",
             "stream-to-string": "1.2.0",
             "qs": "6.10.1",
             useragent: "2.3.0",
             "@vlasky/whomst": "0.1.7"});

Npm.strip({
  multiparty: ["test/"],
  useragent: ["test/"]
});

// whitelist plugin is now included in the core
Cordova.depends({
  'cordova-plugin-meteor-webapp': '2.0.0-beta.0'
});

Package.onUse(function (api) {
  api.use('ecmascript');
  api.use([
    'logging',
    'underscore',
    'routepolicy',
    'modern-browsers',
    'boilerplate-generator',
    'webapp-hashing',
    'inter-process-messaging',
    'callback-hook'
  ], 'server');

  // At response serving time, webapp uses browser-policy if it is loaded. If
  // browser-policy is loaded, then it must be loaded after webapp
  // (browser-policy depends on webapp). So we don't explicitly depend in any
  // way on browser-policy here, but we use it when it is loaded, and it can be
  // loaded after webapp.
  api.mainModule('webapp_server.js', 'server');
  api.export('WebApp', 'server');
  api.export('WebAppInternals', 'server');
  api.export('main', 'server');

  api.mainModule('webapp_client.js', 'client');
  api.export('WebApp', 'client');

  api.mainModule('webapp_cordova.js', 'web.cordova');
});

Package.onTest(function (api) {
  api.use(['tinytest', 'ecmascript', 'webapp', 'http', 'underscore']);
  api.addFiles('webapp_tests.js', 'server');
  api.addFiles('webapp_client_tests.js', 'client');
  api.addFiles('socket_file_tests.js', 'server');

  api.addAssets('modern_test_asset.js', 'web.browser');
  api.addAssets('legacy_test_asset.js', 'legacy');
});


// Subscribe to the `meteor_autoupdate_clientVersions` collection,
// which contains the set of acceptable client versions.
//
// A "hard code push" occurs when the running client version is not in
// the set of acceptable client versions (or the server updates the
// collection, there is a published client version marked `current` and
// the running client version is no longer in the set).
//
// When the `reload` package is loaded, a hard code push causes
// the browser to reload, so that it will load the latest client
// version from the server.
//
// A "soft code push" represents the situation when the running client
// version is in the set of acceptable versions, but there is a newer
// version available on the server.
//
// `Autoupdate.newClientAvailable` is a reactive data source which
// becomes `true` if a new version of the client is available on
// the server.
//
// This package doesn't implement a soft code reload process itself,
// but `newClientAvailable` could be used for example to display a
// "click to reload" link to the user.

// The client version of the client code currently running in the
// browser.

import { ClientVersions } from "./client_versions.js";

const clientArch = Meteor.isCordova ? "web.cordova" :
  Meteor.isModern ? "web.browser" : "web.browser.legacy";

const autoupdateVersions =
  ((__meteor_runtime_config__.autoupdate || {}).versions || {})[clientArch] || {
    version: "unknown",
    versionRefreshable: "unknown",
    versionNonRefreshable: "unknown",
    assets: [],
  };

export const Autoupdate = {};

// Stores acceptable client versions.
const clientVersions =
  Autoupdate._clientVersions = // Used by a self-test.
  new ClientVersions();

Meteor.connection.registerStore(
  "meteor_autoupdate_clientVersions",
  clientVersions.createStore()
);

Autoupdate.newClientAvailable = function () {
  return clientVersions.newClientAvailable(
    clientArch,
    ["versionRefreshable", "versionNonRefreshable"],
    autoupdateVersions
  );
};

// Set to true if the link.onload callback ever fires for any <link> node.
let knownToSupportCssOnLoad = false;

const retry = new Retry({
  // Unlike the stream reconnect use of Retry, which we want to be instant
  // in normal operation, this is a wacky failure. We don't want to retry
  // right away, we can start slowly.
  //
  // A better way than timeconstants here might be to use the knowledge
  // of when we reconnect to help trigger these retries. Typically, the
  // server fixing code will result in a restart and reconnect, but
  // potentially the subscription could have a transient error.
  minCount: 0, // don't do any immediate retries
  baseTimeout: 30*1000 // start with 30s
});

let failures = 0;

Autoupdate._retrySubscription = () => {
  Meteor.subscribe("meteor_autoupdate_clientVersions", {
    onError(error) {
      Meteor._debug("autoupdate subscription failed", error);
      failures++;
      retry.retryLater(failures, function () {
        // Just retry making the subscription, don't reload the whole
        // page. While reloading would catch more cases (for example,
        // the server went back a version and is now doing old-style hot
        // code push), it would also be more prone to reload loops,
        // which look really bad to the user. Just retrying the
        // subscription over DDP means it is at least possible to fix by
        // updating the server.
        Autoupdate._retrySubscription();
      });
    },

    onReady() {
      // Call checkNewVersionDocument with a slight delay, so that the
      // const handle declaration is guaranteed to be initialized, even if
      // the added or changed callbacks are called synchronously.
      const resolved = Promise.resolve();
      function check(doc) {
        resolved.then(() => checkNewVersionDocument(doc));
      }

      const stop = clientVersions.watch(check);

      function checkNewVersionDocument(doc) {
        if (doc._id !== clientArch) {
          return;
        }

        if (doc.versionNonRefreshable !==
            autoupdateVersions.versionNonRefreshable) {
          // Non-refreshable assets have changed, so we have to reload the
          // whole page rather than just replacing <link> tags.
          if (stop) stop();
          if (Package.reload) {
            // The reload package should be provided by ddp-client, which
            // is provided by the ddp package that autoupdate depends on.
            Package.reload.Reload._reload();
          }
          return;
        }

        if (doc.versionRefreshable !== autoupdateVersions.versionRefreshable) {
          autoupdateVersions.versionRefreshable = doc.versionRefreshable;

          // Switch out old css links for the new css links. Inspired by:
          // https://github.com/guard/guard-livereload/blob/master/js/livereload.js#L710
          var newCss = doc.assets || [];
          var oldLinks = [];

          Array.prototype.forEach.call(
            document.getElementsByTagName('link'),
            function (link) {
              if (link.className === '__meteor-css__') {
                oldLinks.push(link);
              }
            }
          );

          function waitUntilCssLoads(link, callback) {
            var called;

            link.onload = function () {
              knownToSupportCssOnLoad = true;
              if (! called) {
                called = true;
                callback();
              }
            };

            if (! knownToSupportCssOnLoad) {
              var id = Meteor.setInterval(function () {
                if (link.sheet) {
                  if (! called) {
                    called = true;
                    callback();
                  }
                  Meteor.clearInterval(id);
                }
              }, 50);
            }
          }

          let newLinksLeftToLoad = newCss.length;
          function removeOldLinks() {
            if (oldLinks.length > 0 &&
                --newLinksLeftToLoad < 1) {
              oldLinks.splice(0).forEach(link => {
                link.parentNode.removeChild(link);
              });
            }
          }

          if (newCss.length > 0) {
            newCss.forEach(css => {
              const newLink = document.createElement("link");
              newLink.setAttribute("rel", "stylesheet");
              newLink.setAttribute("type", "text/css");
              newLink.setAttribute("class", "__meteor-css__");
              newLink.setAttribute("href", css.url);

              waitUntilCssLoads(newLink, function () {
                Meteor.setTimeout(removeOldLinks, 200);
              });

              const head = document.getElementsByTagName("head").item(0);
              head.appendChild(newLink);
            });
          } else {
            removeOldLinks();
          }
        }
      }
    }
  });
};

Autoupdate._retrySubscription();


const invariant = require('invariant');
const isMeteorProp = require('../ast/isMeteorProp');
const { union, intersection } = require('./sets');
const invert = require('./invert');

// Nodes -> Set
module.exports = function getExecutorsFromTest(test) {
  switch (test.type) {
    case 'MemberExpression':
      if (isMeteorProp(test, 'isClient')) {
        return new Set(['browser', 'cordova']);
      }
      if (isMeteorProp(test, 'isServer')) {
        return new Set(['server']);
      }
      if (isMeteorProp(test, 'isCordova')) {
        return new Set(['cordova']);
      }
      return invariant(false, 'Unkown Meteor prop should never be reached');
    case 'UnaryExpression':
      return invert(getExecutorsFromTest(test.argument));
    case 'LogicalExpression':
      if (test.operator === '&&') {
        return intersection(
          getExecutorsFromTest(test.left),
          getExecutorsFromTest(test.right)
        );
      }
      if (test.operator === '||') {
        return union(
          getExecutorsFromTest(test.left),
          getExecutorsFromTest(test.right)
        );
      }
      return invariant(false, 'Unkown operator should never be reached');
    default:
      return invariant(
        false,
        'Called getExecutorsFromTest on unkown node type'
      );
  }
};