getLatestMainlineVersion: function (name) {

// Just getVersion mapped over getSortedVersions, but only makes one round

var versionRecords = this._contentQuery(

"SELECT content FROM versions WHERE packageName=?", [name]);

ConstraintSolver = {};

// `catalog` has the following methods:
//
// * getSortedVersions(packageName) -> [String]
// * getVersion(packageName, version) -> {
//     packageName, version, dependencies }
//
// Where `dependencies` is a map from packageName to
// an object of the form `{ constraint: String,
// references: [{arch: String, optional "weak": true}] }`.
//
// TODO: Abstract away the catalog by pulling out the code that
// interfaces with it.  We shouldn't have to stub the catalog in
// tests or conform to its format anywhere in order to, say,
// run the solver with a real cost function.
ConstraintSolver.PackagesResolver = function (catalog, options) {
  var self = this;

  options = options || {};

  self.catalog = catalog;

  // The main resolver
  self.resolver = new ConstraintSolver.Resolver({
    nudge: options.nudge
  });

  self._packageInfoLoadQueue = [];
  self._packagesEverEnqueued = {};
  self._loadingPackageInfo = false;
};

ConstraintSolver.PackagesResolver.prototype._ensurePackageInfoLoaded = function (
    packageName) {
  var self = this;
  if (_.has(self._packagesEverEnqueued, packageName))
    return;
  self._packagesEverEnqueued[packageName] = true;
  self._packageInfoLoadQueue.push(packageName);

  // Is there already an instance of _ensurePackageInfoLoaded up the stack?
  // Great, it'll get this.
  // XXX does this work correctly with multiple fibers?
  if (self._loadingPackageInfo)
    return;

  self._loadingPackageInfo = true;
  try {
    while (self._packageInfoLoadQueue.length) {
      var nextPackageName = self._packageInfoLoadQueue.shift();
      self._loadPackageInfo(nextPackageName);
    }
  } finally {
    self._loadingPackageInfo = false;
  }
};

ConstraintSolver.PackagesResolver.prototype._loadPackageInfo = function (
    packageName) {
  var self = this;

  // We rely on sortedness in the constraint solver, since one of the cost
  // functions wants to be able to quickly find the earliest or latest version.
  var sortedVersions = self.catalog.getSortedVersions(packageName);
  _.each(sortedVersions, function (version) {
    var versionDef = self.catalog.getVersion(packageName, version);

    var unitVersion = new ConstraintSolver.UnitVersion(packageName, version);
    self.resolver.addUnitVersion(unitVersion);

    _.each(versionDef.dependencies, function (dep, depName) {
      self._ensurePackageInfoLoaded(depName);

      // "dep" contains a list of references, which describes which unibuilds of
      // this unitVersion depend on depName, as well as a constraint, which
      // constraints the versions it depends on.

      // The package->package dependency is weak if ALL of the underlying
      // unibuild->unibuild dependencies are weak.  ie,
      //     api.use('dep', 'server', { weak: true });
      //     api.use('dep', 'client');
      // is not weak at the package->package level.
      var createsDependency = _.any(dep.references, function (ref) {
        return !ref.weak;
      });

      // Add the dependency if needed.
      if (createsDependency)
        unitVersion.addDependency(depName);

      // Add a constraint if needed.
      if (dep.constraint && dep.constraint !== "none") {
        var constraint = self.resolver.getConstraint(depName, dep.constraint);
        unitVersion.addConstraint(constraint);
      }
    });
  });
};

// dependencies - an array of string names of packages (not slices)
// constraints - an array of objects:
//  (almost, but not quite, what PackageVersion.parseConstraint returns)
//  - packageName - string name
//  - version - string constraint
//  - type - constraint type
// options:
//  - upgrade - list of dependencies for which upgrade is prioritized higher
//    than keeping the old version
//  - previousSolution - mapping from package name to a version that was used in
//    the previous constraint solver run
//  - anticipatedPrereleases: mapping from package name to version to true;
//    included versions are the only pre-releases that are allowed to match
//    constraints that don't specifically name them during the "try not to
//    use unanticipated pre-releases" pass
ConstraintSolver.PackagesResolver.prototype.resolve = function (
    dependencies, constraints, options) {
  var self = this;
  // clone because we mutate options
  options = _.extend({
    _testing: false,
    upgrade: [],
    anticipatedPrereleases: {}
  }, options || {});

  check(dependencies, [String]);

  check(constraints, [{
    name: String,
    constraintString: Match.Optional(Match.OneOf(String, undefined)),
    constraints: [{
      version: Match.OneOf(String, null),
      type: String }]
  }]);

  check(options, {
    _testing: Match.Optional(Boolean),
    upgrade: [String],
    previousSolution: Match.Optional(Object),
    anticipatedPrereleases: Match.Optional(
      Match.ObjectWithValues(Match.ObjectWithValues(Boolean)))
  });

  _.each(dependencies, function (packageName) {
    self._ensurePackageInfoLoaded(packageName);
  });
  _.each(constraints, function (constraint) {
    self._ensurePackageInfoLoaded(constraint.name);
  });
  _.each(options.previousSolution, function (version, packageName) {
    self._ensurePackageInfoLoaded(packageName);
  });

  if (options.previousSolution) {
    // Replace previousSolution map with a list of the UnitVersions that we know
    // about that were mentioned.  (_.compact drops unknown UnitVersions.)
    options.previousSolution = _.compact(
      _.map(options.previousSolution, function (version, packageName) {
        return self.resolver.getUnitVersion(packageName, version);
      }));
  }

  // Convert options.upgrade to a map for O(1) access.
  // XXX we should probably just change the API so it's passed in this way
  var upgradePackages = {};
  _.each(options.upgrade, function (packageName) {
    upgradePackages[packageName] = true;
  });
  options.upgrade = upgradePackages;

  constraints = self._makeConstraintObjects(constraints);

  options.rootDependencies = dependencies;
  var resolverOptions = self._getResolverOptions(options);
  var res = null;
  var neededToUseUnanticipatedPrereleases = false;

  // If a previous solution existed, try resolving with additional (weak)
  // equality constraints on all the versions from the previous solution (except
  // those we've explicitly been asked to update). If it's possible to solve the
  // constraints without changing any of the previous versions (though we may
  // add more choices in addition, or remove some now-unnecessary choices) then
  // that's our first try.
  //
  // If we're intentionally trying to upgrade some or all packages, we just skip
  // this step. We used to try to do this step but just leaving off pins from
  // the packages we're trying to upgrade, but this tended to not lead to actual
  // upgrades since we were still pinning things that the to-upgrade package
  // depended on.  (We still use the specific contents of options.upgrade to
  // guide which things are encouraged to be upgraded vs stay the same in the
  // heuristic.)
  if (!_.isEmpty(options.previousSolution) && _.isEmpty(options.upgrade)) {
    var constraintsWithPreviousSolutionLock = _.clone(constraints);
    _.each(options.previousSolution, function (uv) {
      constraintsWithPreviousSolutionLock.push(
        self.resolver.getConstraint(uv.name, '=' + uv.version));
    });
    try {
      // Try running the resolver. If it fails to resolve, that's OK, we'll keep
      // working.
      res = self.resolver.resolve(
        dependencies, constraintsWithPreviousSolutionLock, resolverOptions);
    } catch (e) {
      if (!(e.constraintSolverError))
        throw e;
    }
  }

  // Either we didn't have a previous solution, or it doesn't work. Try again
  // without locking in the previous solution as strict equality.
  if (!res) {
    try {
      res = self.resolver.resolve(dependencies, constraints, resolverOptions);
    } catch (e) {
      if (!(e.constraintSolverError))
        throw e;
    }
  }

  // As a last-ditch effort, let's allow ANY pre-release version found in the
  // catalog, not only those that are asked for at some level.
  if (!res) {
    resolverOptions.anticipatedPrereleases = true;
    neededToUseUnanticipatedPrereleases = true;
    // Unlike the previous calls, this one throws a constraintSolverError on
    // failure.
    res = self.resolver.resolve(dependencies, constraints, resolverOptions);
  }
  return {
    answer:  resolverResultToPackageMap(res),
    neededToUseUnanticipatedPrereleases: neededToUseUnanticipatedPrereleases
  };
};

var resolverResultToPackageMap = function (choices) {
  var packageMap = {};
  mori.each(choices, function (nameAndUv) {
    var name = mori.first(nameAndUv);
    var uv = mori.last(nameAndUv);
    packageMap[name] = uv.version;
  });
  return packageMap;
};

ConstraintSolver.PackagesResolver.prototype._makeConstraintObjects = function (
    inputConstraints) {
  var self = this;
  return _.map(inputConstraints, function (constraint) {
    return self.resolver.getConstraint(
      constraint.name, constraint.constraintString);
  });
};

ConstraintSolver.PackagesResolver.prototype._getResolverOptions =
  function (options) {
  var self = this;

  var resolverOptions = {
    anticipatedPrereleases: options.anticipatedPrereleases
  };

  if (options._testing) {
    resolverOptions.costFunction = function (state) {
      return mori.reduce(mori.sum, 0, mori.map(function (nameAndUv) {
        return PackageVersion.versionMagnitude(mori.last(nameAndUv).version);
      }, state.choices));
    };
  } else {
    // Poorman's enum
    var VMAJOR = 0, MAJOR = 1, MEDIUM = 2, MINOR = 3;
    var rootDeps = options.rootDependencies || [];
    var prevSol = options.previousSolution || [];

    var isRootDep = {};
    var prevSolMapping = {};

    _.each(rootDeps, function (dep) { isRootDep[dep] = true; });

    // if the upgrade is preferred over preserving previous solution, pretend
    // there are no previous solution
    _.each(prevSol, function (uv) {
      if (! _.has(options.upgrade, uv.name))
        prevSolMapping[uv.name] = uv;
    });

    resolverOptions.costFunction = function (state, options) {
      options = options || {};
      // very major, major, medium, minor costs
      // XXX maybe these can be calculated lazily?
      var cost = [0, 0, 0, 0];

      mori.each(state.choices, function (nameAndUv) {
        var uv = mori.last(nameAndUv);
        if (_.has(prevSolMapping, uv.name)) {
          // The package was present in the previous solution
          var prev = prevSolMapping[uv.name];
          var versionsDistance =
            PackageVersion.versionMagnitude(uv.version) -
            PackageVersion.versionMagnitude(prev.version);

          var isCompatible = prev.majorVersion === uv.majorVersion;

          if (isRootDep[uv.name]) {
            // root dependency
            if (versionsDistance < 0 || ! isCompatible) {
              // the new pick is older or is incompatible with the prev. solution
              // i.e. can have breaking changes, prefer not to do this
              // XXX in fact we want to avoid downgrades to the direct
              // dependencies at all cost.
              cost[VMAJOR]++;
              options.debug && console.log("root & *not* compatible: ", uv.name, prev.version, "=>", uv.version)
            } else {
              // compatible but possibly newer
              // prefer the version closest to the older solution
              cost[MAJOR] += versionsDistance;
              options.debug && console.log("root & compatible: ", uv.name, prev.version, "=>", uv.version)
            }
          } else {
            // transitive dependency
            // prefer to have less changed transitive dependencies
            cost[MINOR] += versionsDistance === 0 ? 0 : 1;
            options.debug && console.log("transitive: ", uv.name, prev.version, "=>", uv.version)
          }
        } else {
          var latestDistance =
            PackageVersion.versionMagnitude(_.last(self.resolver.unitsVersions[uv.name]).version) -
            PackageVersion.versionMagnitude(uv.version);

          if (isRootDep[uv.name]) {
            // root dependency
            // preferably latest
            cost[MEDIUM] += latestDistance;
            options.debug && console.log("root: ", uv.name, "=>", uv.version)
          } else {
            // transitive dependency
            // prefarable earliest possible to be conservative
            // How far is our choice from the most conservative version that
            // also matches our constraints?
            var minimal = state.constraints.getMinimalVersion(uv.name) || '0.0.0';
            cost[MINOR] += PackageVersion.versionMagnitude(uv.version) - PackageVersion.versionMagnitude(minimal);
            options.debug && console.log("transitive: ", uv.name, "=>", uv.version)
          }
        }
      });

      return cost;
    };

    resolverOptions.estimateCostFunction = function (state, options) {
      options = options || {};

      var cost = [0, 0, 0, 0];

      state.eachDependency(function (dep, alternatives) {
        // XXX don't try to estimate transitive dependencies
        if (! isRootDep[dep]) {
          cost[MINOR] += 10000000;
          return;
        }

        if (_.has(prevSolMapping, dep)) {
          var prev = prevSolMapping[dep];
          var prevVersionMatches = state.isSatisfied(prev);

          // if it matches, assume we would pick it and the cost doesn't
          // increase
          if (prevVersionMatches)
            return;

          // Get earliest matching version.
          var earliestMatching = mori.first(alternatives);

          var isCompatible =
                prev.majorVersion === earliestMatching.majorVersion;
          if (! isCompatible) {
            cost[VMAJOR]++;
            return;
          }

          var versionsDistance =
            PackageVersion.versionMagnitude(earliestMatching.version) -
            PackageVersion.versionMagnitude(prev.version);
          if (versionsDistance < 0) {
            cost[VMAJOR]++;
            return;
          }

          cost[MAJOR] += versionsDistance;
        } else {
          var versions = self.resolver.unitsVersions[dep];
          var latestMatching = mori.last(alternatives);

          var latestDistance =
            PackageVersion.versionMagnitude(
              _.last(self.resolver.unitsVersions[dep]).version) -
            PackageVersion.versionMagnitude(latestMatching.version);

          cost[MEDIUM] += latestDistance;
        }
      });

      return cost;
    };

    resolverOptions.combineCostFunction = function (costA, costB) {
      if (costA.length !== costB.length)
        throw new Error("Different cost types");

      var arr = [];
      _.each(costA, function (l, i) {
        arr.push(l + costB[i]);
      });

      return arr;
    };
  }

  return resolverOptions;
};


var versions = self.getSortedVersions(name);

getSortedVersionRecords: function (name) {

Plugin.registerSourceHandler('txt', function (compileStep) {
  compileStep.addAsset({
    path: compileStep.inputPath,
    data: compileStep.read()
  });
});


@font-face {
	font-family: 'todos';
	src:url('icon/todos.eot?-5w3um4');
	src:url('icon/todos.eot?#iefix5w3um4') format('embedded-opentype'),
		url('icon/todos.woff?5w3um4') format('woff'),
		url('icon/todos.ttf?5w3um4') format('truetype'),
		url('icon/todos.svg?5w3um4#todos') format('svg');
	font-weight: normal;
	font-style: normal;
}

[class^="icon-"], [class*=" icon-"] {
	font-family: 'todos';
	speak: none;
	font-style: normal;
	font-weight: normal;
	font-variant: normal;
	text-transform: none;
	line-height: 1;

	// Better Font Rendering
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

.icon-unlock:before {
	content: "\e600";
}
.icon-user-add:before {
	content: "\e604";
}
.icon-cog:before {
	content: "\e606";
}
.icon-trash:before {
	content: "\e607";
}
.icon-edit:before {
	content: "\e608";
}
.icon-add:before {
	content: "\e60a";
}
.icon-plus:before {
	content: "\e60b";
}
.icon-close:before {
	content: "\e60c";
}
.icon-cross:before {
	content: "\e60d";
}
.icon-sync:before {
	content: "\e60e";
}
.icon-lock:before {
	content: "\e610";
}
.icon-check:before {
	content: "\e612";
}
.icon-share:before {
	content: "\e617";
}
.icon-email:before {
	content: "\e619";
}
.icon-arrow-up:before {
	content: "\e623";
}
.icon-arrow-down:before {
	content: "\e626";
}
.icon-list-unordered:before {
	content: "\e634";
}


coffee.runCompilerOutputTests = (run) ->
  run "abc",
  """
  function () {
    var view = this;
    return "abc";
  }
  """

  run "{{foo}}",
  """
  function() {
    var view = this;
    return Blaze.View(function() {
      return Spacebars.mustache(view.lookup("foo"));
    });
  }
  """

  run "{{foo bar}}",
  """
  function() {
    var view = this;
    return Blaze.View(function() {
      return Spacebars.mustache(view.lookup("foo"),
                                view.lookup("bar"));
    });
  }
  """

  run "{{foo x=bar}}",
  """
  function() {
    var view = this;
    return Blaze.View(function() {
      return Spacebars.mustache(view.lookup("foo"), Spacebars.kw({
        x: view.lookup("bar")
      }));
    });
  }
  """

  run "{{foo.bar baz}}",
  """
  function() {
    var view = this;
    return Blaze.View(function() {
      return Spacebars.mustache(Spacebars.dot(
               view.lookup("foo"), "bar"),
               view.lookup("baz"));
    });
  }
  """

  run "{{foo bar.baz}}",
  """
  function() {
    var view = this;
    return Blaze.View(function() {
      return Spacebars.mustache(view.lookup("foo"),
             Spacebars.dot(view.lookup("bar"), "baz"));
    });
  }
  """

  run "{{foo x=bar.baz}}",
  """
  function() {
    var view = this;
    return Blaze.View(function() {
      return Spacebars.mustache(view.lookup("foo"), Spacebars.kw({
        x: Spacebars.dot(view.lookup("bar"), "baz")
      }));
    });
  }
  """

  run "{{#foo}}abc{{/foo}}",
  """
  function() {
    var view = this;
    return Spacebars.include(view.lookupTemplate("foo"), (function() {
      return "abc";
    }));
  }
  """

  run "{{#if cond}}aaa{{else}}bbb{{/if}}",
  """
  function() {
    var view = this;
    return Blaze.If(function () {
      return Spacebars.call(view.lookup("cond"));
    }, (function() {
      return "aaa";
    }), (function() {
      return "bbb";
    }));
  }
  """

  run "{{!-- --}}{{#if cond}}aaa{{!\n}}{{else}}{{!}}bbb{{!-- --}}{{/if}}{{!}}",
  """
function() {
  var view = this;
  return Blaze.If(function () {
    return Spacebars.call(view.lookup("cond"));
  }, (function() {
    return "aaa";
  }), (function() {
    return "bbb";
  }));
}
  """

  run "{{> foo bar}}",
  """
  function() {
    var view = this;
    return Blaze._TemplateWith(function() {
      return Spacebars.call(view.lookup("bar"));
    }, function() {
      return Spacebars.include(view.lookupTemplate("foo"));
    });
  }
  """

  run "{{> foo x=bar}}",
  """
  function() {
    var view = this;
    return Blaze._TemplateWith(function() {
      return {
        x: Spacebars.call(view.lookup("bar"))
      };
    }, function() {
      return Spacebars.include(view.lookupTemplate("foo"));
    });
  }

  """

  run "{{> foo bar.baz}}",
  """
  function() {
    var view = this;
    return Blaze._TemplateWith(function() {
      return Spacebars.call(Spacebars.dot(view.lookup("bar"), "baz"));
    }, function() {
      return Spacebars.include(view.lookupTemplate("foo"));
    });
  }
  """

  run "{{> foo x=bar.baz}}",
  """
  function() {
    var view = this;
    return Blaze._TemplateWith(function() {
      return {
        x: Spacebars.call(Spacebars.dot(view.lookup("bar"), "baz"))
      };
    }, function() {
      return Spacebars.include(view.lookupTemplate("foo"));
    });
  }
  """

  run "{{> foo bar baz}}",
  """
  function() {
    var view = this;
    return Blaze._TemplateWith(function() {
      return Spacebars.dataMustache(view.lookup("bar"), view.lookup("baz"));
    }, function() {
      return Spacebars.include(view.lookupTemplate("foo"));
    });
  }

  """

  run "{{#foo bar baz}}aaa{{/foo}}",
  """
  function() {
    var view = this;
    return Blaze._TemplateWith(function() {
      return Spacebars.dataMustache(view.lookup("bar"), view.lookup("baz"));
    }, function() {
      return Spacebars.include(view.lookupTemplate("foo"), (function() {
        return "aaa";
      }));
    });
  }
  """

  run "{{#foo p.q r.s}}aaa{{/foo}}",
  """
  function() {
    var view = this;
    return Blaze._TemplateWith(function() {
      return Spacebars.dataMustache(Spacebars.dot(view.lookup("p"), "q"), Spacebars.dot(view.lookup("r"), "s"));
    }, function() {
      return Spacebars.include(view.lookupTemplate("foo"), (function() {
        return "aaa";
      }));
    });
  }
  """

  run "",
  """
  function() {
    var view = this;
    return HTML.A(HTML.Attrs(function() {
      return Spacebars.attrMustache(view.lookup("b"));
    }));
  }
  """

  run "",
  """
  function() {
    var view = this;
    return HTML.A(HTML.Attrs({
      c: (function() { return [
        "d",
        Spacebars.mustache(view.lookup("e")),
        "f" ]; })
    }, function() {
      return Spacebars.attrMustache(view.lookup("b"));
    }));
  }
  """

  run "<asdf>{{foo}}</asdf>",
  """
  function() {
    var view = this;
    return HTML.getTag("asdf")(Blaze.View(function() {
      return Spacebars.mustache(view.lookup("foo"));
    }));
  }
  """

  run "<textarea>{{foo}}</textarea>",
  """
  function() {
    var view = this;
    return HTML.TEXTAREA({value: (function () {
      return Spacebars.mustache(view.lookup("foo"));
    }) });
  }
  """

  run "<textarea>{{{{|{{|foo}}</textarea>",
  """
  function() {
    var view = this;
    return HTML.TEXTAREA({value: (function () {
      return [ "{{{{", "{{", "foo}}" ];
    }) });
  }
  """

  run "{{|foo}}",
  """
  function() {
    var view = this;
    return [ "{{", "foo}}" ];
  }
  """

  run "",
  """
  function() {
    var view = this;
    return HTML.A({
      b: (function () {
        return "{{{";
      })
    });
  }
  """


return this._returnFirst("getSortedVersions", arguments, ACCEPT_NON_EMPTY);

var result = self.localCatalog.getVersion(name, version);

var makeResolver = function (data) {
  var Versions = new LocalCollection;

  _.each(data, function (versionDescription) {
    var packageName = versionDescription.shift();
    var version = versionDescription.shift();
    var deps = versionDescription.shift();

    var constructedDeps = {};
    _.each(deps, function (constraint, name) {
      constructedDeps[name] = {
        constraint: constraint,
        references: [
          { arch: "os" },
          { arch: "web.browser"},
          { arch: "web.cordova"}
        ]
      };
    });
    Versions.insert({ packageName: packageName, version: version,
                      dependencies: constructedDeps });
  });

  var catalogStub = {
    getSortedVersions: function (name) {
      return _.pluck(
        Versions.find({
          packageName: name
        }, { fields: { version: 1 } }).fetch(),
        'version'
      ).sort(PackageVersion.compare);
    },
    getVersion: function (name, version) {
      return Versions.findOne({
        packageName: name,
        version: version
      });
    }
  };
  return new ConstraintSolver.PackagesResolver(catalogStub);
};

var defaultResolver = makeResolver([
  ["sparky-forms", "1.1.2", {"forms": "=1.0.1", "sparkle": "=2.1.1"}],
  ["sparky-forms", "1.0.0", {"awesome-dropdown": "=1.4.0"}],
  ["forms", "1.0.1", {"sparkle": "2.1.0", "jquery-widgets": "1.0.0"}],
  ["sparkle", "2.1.0", {"jquery": "1.8.2"}],
  ["sparkle", "2.1.1", {"jquery": "1.8.2"}],
  ["sparkle", "1.0.0"],
  ["awesome-dropdown", "1.4.0", {"dropdown": "=1.2.2"}],
  ["awesome-dropdown", "1.5.0", {"dropdown": "=1.2.2"}],
  ["dropdown", "1.2.2", {"jquery-widgets": "1.0.0"}],
  ["jquery-widgets", "1.0.0", {"jquery": "1.8.0", "sparkle": "2.1.1"}],
  ["jquery-widgets", "1.0.2", {"jquery": "1.8.0", "sparkle": "2.1.1"}],
  ["jquery", "1.8.0"],
  ["jquery", "1.8.2"]
]);

// Take a map of `{ dependency: constraint }`, where `dependency`
// is a package name string and `constraint` is a constraint string,
// and return an array of dependencies (package name strings)
// and an array of constraint objects.
//
// If a constraint is prefixed with 'w', the dependency is a weak
// dependency, so it will generate a constraint but not a dependency
// in the returned arrays.
splitArgs = function (deps) {
  var dependencies = [], constraints = [];

  _.each(deps, function (constr, dep) {
    if (constr && constr.charAt(0) === 'w') {
      constr = constr.slice(1);
    } else {
      dependencies.push(dep);
    }
    if (constr) {
      constraints.push(PackageVersion.parseConstraint(dep + "@" + constr));
    }
  });
  return {dependencies: dependencies, constraints: constraints};
};

var testWithResolver = function (test, resolver, f) {
  var t = function (deps, expected, options) {
    var dependencies = splitArgs(deps).dependencies;
    var constraints = splitArgs(deps).constraints;

    var resolvedDeps = resolver.resolve(dependencies, constraints, options);
    test.equal(resolvedDeps.answer, expected);
  };

  var FAIL = function (deps, regexp) {
    test.throws(function () {
      var dependencies = splitArgs(deps).dependencies;
      var constraints = splitArgs(deps).constraints;

      var resolvedDeps = resolver.resolve(dependencies, constraints,
                                          {_testing: true});
    }, regexp);
  };
  f(t, FAIL);
};

Tinytest.add("constraint solver - simple exact + regular deps", function (test) {
  testWithResolver(test, defaultResolver, function (t) {
    t({ "sparky-forms": "=1.1.2" }, {
      "sparky-forms": "1.1.2",
      "forms": "1.0.1",
      "sparkle": "2.1.1",
      "jquery-widgets": "1.0.0",
      "jquery": "1.8.2"
    }, { _testing: true });

    t({ "sparky-forms": "=1.1.2", "awesome-dropdown": "=1.5.0" }, {
      "sparky-forms": "1.1.2",
      "forms": "1.0.1",
      "sparkle": "2.1.1",
      "jquery-widgets": "1.0.0",
      "jquery": "1.8.2",
      "awesome-dropdown": "1.5.0",
      "dropdown": "1.2.2"
    }, { _testing: true });
  });
});

Tinytest.add("constraint solver - non-exact direct dependency", function (test) {
  testWithResolver(test, defaultResolver, function (t) {
    // sparky-forms 1.0.0 won't be chosen because it depends on a very old
    // jquery, which is not compatible with the jquery that
    // awesome-dropdown uses.
    t({ "sparky-forms": "1.0.0", "awesome-dropdown": "=1.5.0" }, {
      "sparky-forms": "1.1.2",
      "forms": "1.0.1",
      "sparkle": "2.1.1",
      "jquery-widgets": "1.0.0",
      "jquery": "1.8.2",
      "awesome-dropdown": "1.5.0",
      "dropdown": "1.2.2"
    }, { _testing: true });
  });
});

Tinytest.add("constraint solver - no results", function (test) {
  var resolver = makeResolver([
    ["bad-1", "1.0.0", {indirect: "1.0.0"}],
    ["bad-2", "1.0.0", {indirect: "2.0.0"}],
    ["indirect", "1.0.0"],
    ["indirect", "2.0.0"]
  ]);
  testWithResolver(test, resolver, function (t, FAIL) {
    FAIL({ "bad-1": "1.0.0", "bad-2": "" }, function (error) {
      return error.message.match(/indirect@2\.0\.0 is not satisfied by 1\.0\.0/)
        && error.message.match(/bad-1@1\.0\.0/)
        && error.message.match(/bad-2@1\.0\.0/)
        // We shouldn't get shown indirect itself in a pathway: that would just
        // be an artifact of there being a path that passes through another
        // package.  (Note: we might change our mind and decide that all these
        // lines should end in the relevant constraint, which would probably be
        // nice! But in that case, we should test that no line ends with TWO
        // mentions of indirect.)
        && ! error.message.match(/-> indirect/)
        // Lines should be unique.
        && ! error.message.match(/bad-1[^]+bad-1/);
    });
  });

  resolver = makeResolver([
    ["foo", "1.0.0"],
    ["foo", "1.1.0"],
    ["foo", "2.0.0"],
    ["foo", "2.1.0"],
    ["bar", "1.0.0", {foo: "1.0.0"}]
  ]);
  testWithResolver(test, resolver, function (t, FAIL) {
    FAIL({foo: "2.0.0", bar: "1.0.0"},
         /constraints on foo[^]+top level[^]+bar@1.0.0/);
  });

  testWithResolver(test, makeResolver([]), function (t, FAIL) {
    FAIL({foo: "1.0.0"}, /unknown package: foo/);
  });

  resolver = makeResolver([
    ["foo", "2.0.0"],
    ["bar", "1.0.0", {foo: ""}]
  ]);
  testWithResolver(test, resolver, function (t, FAIL) {
    FAIL({foo: "w1.0.0", bar: "1.0.0"},
         /constraints on foo[^]+top level/);
  });
});

Tinytest.add("constraint solver - any-of constraint", function (test) {
  var resolver = makeResolver([
    ["one-of", "1.0.0", {indirect: "1.0.0 || 2.0.0"}],
    ["important", "1.0.0", {indirect: "2.0.0"}],
    ["indirect", "1.0.0"],
    ["indirect", "2.0.0"]
  ]);

  testWithResolver(test, resolver, function (t, FAIL) {
    t({ "one-of": "=1.0.0", "important": "1.0.0" }, {
      "one-of": "1.0.0",
      "important": "1.0.0",
      "indirect": "2.0.0"
    }, { _testing: true });
  });

  resolver = makeResolver([
    ["one-of", "1.0.0", {indirect: "1.0.0 || 2.0.0"}],
    ["one-of-equal", "1.0.0", {indirect: "1.0.0 || =2.0.1"}],
    ["important", "1.0.0", {indirect: "1.0.0"}],
    ["indirect", "1.0.0"],
    ["indirect", "2.0.0"],
    ["indirect", "2.0.1"]
  ]);

  testWithResolver(test, resolver, function (t, FAIL) {
    t({ "one-of": "=1.0.0", "important": "1.0.0" }, {
      "one-of": "1.0.0",
      "important": "1.0.0",
      "indirect": "1.0.0"
    }, { _testing: true });

    t({ "one-of-equal": "1.0.0", "indirect": "2.0.0" }, {
      "one-of-equal": "1.0.0",
      "indirect": "2.0.1"
    }, { _testing: true });

    t({ "one-of-equal": "1.0.0", "one-of": "1.0.0" }, {
      "one-of-equal": "1.0.0",
      "one-of": "1.0.0",
      "indirect": "1.0.0"
    }, { _testing: true });

    FAIL({"one-of-equal": "1.0.0",
          "one-of": "1.0.0",
          "indirect" : "=2.0.0"},
         /constraints on indirect[^]+top level[^]+one-of-equal@1.0.0/
    );
  });
});

Tinytest.add("constraint solver - previousSolution", function (test) {
  testWithResolver(test, defaultResolver, function (t, FAIL) {
    // This is what you get if you lock sparky-forms to 1.0.0.
    t({ "sparky-forms": "=1.0.0" }, {
      "sparky-forms": "1.0.0",
      "awesome-dropdown": "1.4.0",
      "dropdown": "1.2.2",
      "jquery-widgets": "1.0.0",
      "jquery": "1.8.2",
      "sparkle": "2.1.1"
    }, { _testing: true });

    // If you just requires something compatible with 1.0.0, we end up choosing
    // 1.1.2.
    t({ "sparky-forms": "1.0.0" }, {
      "sparky-forms": "1.1.2",
      "forms": "1.0.1",
      "sparkle": "2.1.1",
      "jquery-widgets": "1.0.0",
      "jquery": "1.8.2"
    }, { _testing: true });

    // But if you ask for something compatible with 1.0.0 and have a previous
    // solution with 1.0.0, the previous solution works (since it is achievable).
    t({ "sparky-forms": "1.0.0" }, {
      "sparky-forms": "1.0.0",
      "awesome-dropdown": "1.4.0",
      "dropdown": "1.2.2",
      "jquery-widgets": "1.0.0",
      "jquery": "1.8.2",
      "sparkle": "2.1.1"
    }, { _testing: true, previousSolution: {
      "sparky-forms": "1.0.0"
    }});

    // On the other hand, if the previous solution is incompatible with the
    // constraints, it's not an error: we can try something that isn't the
    // previous solution in this case!
    t({ "sparky-forms": "1.1.2" }, {
      "sparky-forms": "1.1.2",
      "forms": "1.0.1",
      "sparkle": "2.1.1",
      "jquery-widgets": "1.0.0",
      "jquery": "1.8.2"
    }, { _testing: true, previousSolution: {
      "sparky-forms": "1.0.0"
    }});
  });
});

Tinytest.add("constraint solver - no constraint dependency - anything", function (test) {
  var versions = defaultResolver.resolve(["sparkle"], [], { _testing: true }).answer;
  test.isTrue(_.isString(versions.sparkle));
});

Tinytest.add("constraint solver - no constraint dependency - transitive dep still picked right", function (test) {
  var versions = defaultResolver.resolve(
    ["sparkle", "sparky-forms"],
    [PackageVersion.parseConstraint("sparky-forms@1.1.2")],
    { _testing: true }).answer;
  test.equal(versions.sparkle, "2.1.1");
});

Tinytest.add("constraint solver - build IDs", function (test) {
  // build IDs in suffixes like "+local" don't show up in output
  testWithResolver(test, makeResolver([
    ["foo", "1.0.1+local"]
  ]), function (t) {
    t({ "foo": "1.0.0" }, {
      "foo": "1.0.1"
    }, { _testing: false });
  });
});


#! /bin/bash
echo "Please run this script from the docs app folder."
echo "Make sure you have phantomjs installed!"

DOCS_FOLDER=$(pwd);
METEOR_FOLDER=$(dirname ${DOCS_FOLDER});

# make temporary folder
mkdir /tmp/docsdiff
cd /tmp/docsdiff

# trigger phantomjs to give us actual HTML
curl "localhost:3000/?_escaped_fragment_=key1=value1" > new
curl "docs.meteor.com/?_escaped_fragment_=key1=value1" > old

# use our handy canonicalize script copy-pasted from the test-helpers package
# maybe there is a way to use the actual package?
${METEOR_FOLDER}/scripts/node.sh "${DOCS_FOLDER}/private/canonicalize.js" new > new1
${METEOR_FOLDER}/scripts/node.sh "${DOCS_FOLDER}/private/canonicalize.js" old > old1

# remove some of the things we want to ignore, you might want to change these
cat new1 | sed "s/new-api-box//g" | sed "s/ class=\"api-title\"//g" > new2
cat new2  | sed "s/
<\/p>//g" > new3
cat new3  | sed "s/i>/em>/g" > new4

cat old1 | sed "s/new-api-box//g" | sed "s/ class=\"api-title\"//g" > old2
cat old2  | sed "s/
<\/p>//g" > old3
cat old3  | sed "s/i>/em>/g" > old4

# git diff is more colorful than regular diff
/usr/bin/git diff -U10 --no-index --ignore-blank-lines -w old4 new4


# OS Check. Put here because here is where we download the precompiled

// This file contains a package.json for the dependencies of the command-line
// tool.

// We put this in a JS file so that it can contain comments. It is processed
// into a package.json file by generate-dev-bundle.sh.

var fibersVersion;
if (process.platform === "win32") {
  // We have a fork of fibers off of version 1.0.5 that searches farther for
  // the isolate thread. This problem is a result of antivirus programs messing
  // with the thread counts on Windows.
  // Duplicated in dev-bundle-server-package.js
  fibersVersion = "https://github.com/meteor/node-fibers/tarball/d519f0c5971c33d99c902dad346b817e84bab001";
} else {
  fibersVersion = "1.0.5";
}

var packageJson = {
  name: "meteor-dev-bundle-tool",
  // Version is not important but is needed to prevent warnings.
  version: "0.0.0",
  dependencies: {
    fibers: fibersVersion,
    "meteor-babel": "0.3.4",
    "meteor-promise": "0.2.4",
    // Not yet upgrading Underscore from 1.5.2 to 1.7.0 (which should be done
    // in the package too) because we should consider using lodash instead
    // (and there are backwards-incompatible changes either way).
    underscore: "1.5.2",
    "source-map-support": "https://github.com/meteor/node-source-map-support/tarball/1912478769d76e5df4c365e147f25896aee6375e",
    semver: "4.1.0",
    request: "2.47.0",
    fstream: "https://github.com/meteor/fstream/tarball/d11b9ec4a13918447c8af7559c243c190744dd1c",
    tar: "1.0.2",
    kexec: "0.2.0",
    "source-map": "0.1.40",
    "browserstack-webdriver": "2.41.1",
    "node-inspector": "0.7.4",
    chalk: "0.5.1",
    sqlite3: "3.0.2",
    netroute: "0.2.5",
    phantomjs: "1.9.12",
    "http-proxy": "1.11.1",
    "wordwrap": "0.0.2",
    "moment": "2.8.4",
    "rimraf": "2.2.8",
    // XXX: When we update this, see if it fixes this Github issue:
    // https://github.com/jgm/CommonMark/issues/276 . If it does, remove the
    // workaround from the tool.
    "commonmark": "0.15.0",
    // XXX We ought to be able to get this from the copy in js-analyze rather
    // than in the dev bundle.)
    esprima: "1.2.2",
    // 2.4.0 (more or less, the package.json change isn't committed) plus our PR
    // https://github.com/williamwicks/node-eachline/pull/4
    eachline: "https://github.com/meteor/node-eachline/tarball/ff89722ff94e6b6a08652bf5f44c8fffea8a21da",
    cordova: "5.0.0",
    pathwatcher: "4.1.0",
    'lru-cache': '2.6.4'
  }
};

if (process.platform === 'win32') {
  // Cordova is not supported on Windows
  delete packageJson.dependencies.cordova;
  // netroute is only needed for Cordova support
  delete packageJson.dependencies.netroute;
  // kexec doesn't work on Windows
  delete packageJson.dependencies.kexec;
}

process.stdout.write(JSON.stringify(packageJson, null, 2) + '\n');


var DEBUG_TAG = 'METEOR CORDOVA DEBUG (autoupdate_cordova.js) ';
var log = function (msg) {
  console.log(DEBUG_TAG + msg);
};

// This constant was picked by testing on iOS 7.1
// We limit the number of concurrent downloads because iOS gets angry on the
// application when a certain limit is exceeded and starts timing-out the
// connections in 1-2 minutes which makes the whole HCP really slow.
var MAX_NUM_CONCURRENT_DOWNLOADS = 30;
var MAX_RETRY_COUNT = 5;

var autoupdateVersionCordova = __meteor_runtime_config__.autoupdateVersionCordova || "unknown";

// The collection of acceptable client versions.
ClientVersions = new Mongo.Collection("meteor_autoupdate_clientVersions");

Autoupdate = {};

Autoupdate.newClientAvailable = function () {
  return !! ClientVersions.findOne({
    _id: 'version-cordova',
    version: {$ne: autoupdateVersionCordova}
  });
};

var writeFile = function (directoryPath, fileName, content, cb) {
  var fail = function (err) {
    cb(new Error("Failed to write file: ", err), null);
  };

  window.resolveLocalFileSystemURL(directoryPath, function (dirEntry) {
    var success = function (fileEntry) {
      fileEntry.createWriter(function (writer) {
        writer.onwrite = function (evt) {
          var result = evt.target.result;
          cb(null, result);
        };
        writer.onerror = fail;
        writer.write(content);
      }, fail);
    };

    dirEntry.getFile(fileName, {
      create: true,
      exclusive: false
    }, success, fail);
  }, fail);
};

var restartServer = function (location) {
  log('restartServer with location ' + location);
  var fail = function (err) { log("Unexpected error in restartServer: " + err.message) };
  var httpd = cordova && cordova.plugins && cordova.plugins.CordovaUpdate;

  if (! httpd) {
    fail(new Error('no httpd'));
    return;
  }

  var startServer = function (cordovajsRoot) {
    httpd.startServer({
      'www_root' : location,
      'cordovajs_root': cordovajsRoot
    }, function (url) {
      Package.reload.Reload._reload();
    }, fail);
  };

  httpd.getCordovajsRoot(function (cordovajsRoot) {
    startServer(cordovajsRoot);
  }, fail);
};

var hasCalledReload = false;
var updating = false;
var localPathPrefix = null;

var onNewVersion = function () {
  var ft = new FileTransfer();
  var urlPrefix = Meteor.absoluteUrl() + '__cordova';
  HTTP.get(urlPrefix + '/manifest.json', function (err, res) {
    if (err || ! res.data) {
      log('Failed to download the manifest ' + (err && err.message) + ' ' + (res && res.content));
      return;
    }

    updating = true;
    ensureLocalPathPrefix(_.bind(downloadNewVersion, null, res.data));
  });
};

var downloadNewVersion = function (program) {
  var urlPrefix = Meteor.absoluteUrl() + '__cordova';
  var manifest = _.clone(program.manifest);
  var version = program.version;
  var ft = new FileTransfer();

  manifest.push({ url: '/index.html?' + Random.id() });

  var versionPrefix = localPathPrefix + version;

  var queue = [];
  _.each(manifest, function (item) {
    if (! item.url) return;

    var url = item.url;
    url = url.replace(/\?.+$/, '');

    queue.push(url);
  });

  var afterAllFilesDownloaded = _.after(queue.length, function () {
    var wroteManifest = function (err) {
      if (err) {
        log("Failed to write manifest.json: " + err);
        // XXX do something smarter?
        return;
      }

      // success! downloaded all sources and saved the manifest
      // save the version string for atomicity
      writeFile(localPathPrefix, 'version', version, function (err) {
        if (err) {
          log("Failed to write version: " + err);
          return;
        }

        // don't call reload twice!
        if (! hasCalledReload) {
          var location = uriToPath(localPathPrefix + version);
          restartServer(location);
        }
      });
    };

    writeFile(versionPrefix, 'manifest.json',
              JSON.stringify(program, undefined, 2), wroteManifest);
  });

  var downloadUrl = function (url) {
    console.log(DEBUG_TAG + "start downloading " + url);
    // Add a cache buster to ensure that we don't cache an old asset.
    var uri = encodeURI(urlPrefix + url + '?' + Random.id());

    // Try to download the file a few times.
    var tries = 0;
    var tryDownload = function () {
      ft.download(uri, versionPrefix + encodeURI(url), function (entry) {
        if (entry) {
          console.log(DEBUG_TAG + "done downloading " + url);
          // start downloading next queued url
          if (queue.length)
            downloadUrl(queue.shift());
          afterAllFilesDownloaded();
        }
      }, function (err) {
        // It failed, try again if we have tried less than 5 times.
        if (tries++ < MAX_RETRY_COUNT) {
          log("Download error, will retry (#" + tries + "): " + uri);
          tryDownload();
        } else {
          log('Download failed: ' + JSON.stringify(err) + ", source=" + err.source + ", target=" + err.target);
        }
      });
    };

    tryDownload();
  };

  _.times(Math.min(MAX_NUM_CONCURRENT_DOWNLOADS, queue.length), function () {
    var nextUrl = queue.shift();
    // XXX defer the next download so iOS doesn't rate limit us on concurrent
    // downloads
    Meteor.setTimeout(downloadUrl.bind(null, nextUrl), 50);
  });
};

var retry = new Retry({
  minCount: 0, // don't do any immediate retries
  baseTimeout: 30*1000 // start with 30s
});
var failures = 0;

Autoupdate._retrySubscription = function () {
  var appId = __meteor_runtime_config__.appId;
  Meteor.subscribe("meteor_autoupdate_clientVersions", appId, {
    onError: function (err) {
      Meteor._debug("autoupdate subscription failed:", err);
      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();
      });
    }
  });
  if (Package.reload) {
    var checkNewVersionDocument = function (doc) {
      var self = this;
      if (doc.version !== autoupdateVersionCordova) {
        onNewVersion();
      }
    };

    var handle = ClientVersions.find({
      _id: 'version-cordova'
    }).observe({
      added: checkNewVersionDocument,
      changed: checkNewVersionDocument
    });
  }
};

Meteor.startup(function () {
  clearAutoupdateCache(autoupdateVersionCordova);
});
Meteor.startup(Autoupdate._retrySubscription);

// A helper that removes old directories left from previous autoupdates
var clearAutoupdateCache = function (currentVersion) {
  ensureLocalPathPrefix(function () {
    // Try to clean up our cache directory, make sure to scan the directory
    // *before* loading the actual app. This ordering will prevent race
    // conditions when the app code tries to download a new version before
    // the old-cache removal has scanned the cache folder.
    listDirectory(localPathPrefix, {dirsOnly: true}, function (err, names) {
      // Couldn't get the list of dirs or risking to get into a race with an
      // on-going update to disk.
      if (err || updating) {
        return;
      }

      _.each(names, function (name) {
        // Skip the folder with the latest version
        if (name === currentVersion)
          return;

        // remove everything else, as we don't want to keep too much cache
        // around on disk
        removeDirectory(localPathPrefix + name + '/', function (err) {
          if (err) {
            log('Failed to remove an old cache folder '
                + name + ':' + err.message);
          } else {
            log('Successfully removed an old cache folder ' + name);
          }
        });
      });
    });
  })
};

// Cordova File plugin helpers
var listDirectory = function (url, options, cb) {
  if (typeof options === 'function')
    cb = options, options = {};

  var fail = function (err) { cb(err); };
  window.resolveLocalFileSystemURL(url, function (entry) {
    var reader = entry.createReader();
    reader.readEntries(function (entries) {
      var names = [];
      _.each(entries, function (entry) {
        if (! options.dirsOnly || entry.isDirectory)
          names.push(entry.name);
      });
      cb(null, names);
    }, fail);
  }, fail);
};

var removeDirectory = function (url, cb) {
  var fail = function (err) {
    cb(err);
  };
  window.resolveLocalFileSystemURL(url, function (entry) {
    entry.removeRecursively(function () { cb(); }, fail);
  }, fail);
};

var uriToPath = function (uri) {
  return decodeURI(uri).replace(/^file:\/\//g, '');
};

var ensureLocalPathPrefix = function (cb) {
  if (! localPathPrefix) {
    if (! cordova.file.dataDirectory) {
      // Since ensureLocalPathPrefix function is always called on
      // Meteor.startup, all Cordova plugins should be ready.
      // XXX Experiments have shown that it is not always the case, even when
      // the cordova.file symbol is attached, properties like dataDirectory
      // still can be null. Poll until we are sure the property is attached.
      console.log(DEBUG_TAG + 'cordova.file.dataDirectory is null, retrying in 20ms');
      Meteor.setTimeout(_.bind(ensureLocalPathPrefix, null, cb), 20);
    } else {
      localPathPrefix = cordova.file.dataDirectory + 'meteor/';
      cb();
    }
  } else {
    cb();
  }
};


<template name="about">

    {{> nav title='About' black=true}}

Be a local wherever you go. Connect to Local Market’s community to get the latest news, hand-picked recipes, and share with other locals. This season's recipes were chosen by San Francisco chefs Colin Kull of Range, Laurie Ellen Pellicano of Tartine Bakery, and Ren Rossini of Fatted Calf.

Local Market was made by Percolate Studio as an example of a cross platform mobile app built in Meteor. The entire app is less than 1,000 lines of JavaScript. View the source on GitHub.

    Learn More

</template>


makeErrorByStatus = function(statusCode, content) {
  var MAX_LENGTH = 500; // if you change this, also change the appropriate test

  var truncate = function(str, length) {
    return str.length > length ? str.slice(0, length) + '...' : str;
  };

  var message = "failed [" + statusCode + "]";
  if (content)
    message += " " + truncate(content.replace(/\n/g, " "), MAX_LENGTH);

  return new Error(message);
};

// Fill in `response.data` if the content-type is JSON.
populateData = function(response) {
  // Read Content-Type header, up to a ';' if there is one.
  // A typical header might be "application/json; charset=utf-8"
  // or just "application/json".
  var contentType = (response.headers['content-type'] || ';').split(';')[0];

  // Only try to parse data as JSON if server sets correct content type.
  if (_.include(['application/json', 'text/javascript',
      'application/javascript', 'application/x-javascript'], contentType)) {
    try {
      response.data = JSON.parse(response.content);
    } catch (err) {
      response.data = null;
    }
  } else {
    response.data = null;
  }
};

HTTP = {};

/**
 * @summary Send an HTTP `GET` request. Equivalent to calling [`HTTP.call`](#http_call) with "GET" as the first argument.
 * @param {String} url The URL to which the request should be sent.
 * @param {Object} [callOptions] Options passed on to [`HTTP.call`](#http_call).
 * @param {Function} [asyncCallback] Callback that is called when the request is completed. Required on the client.
 * @locus Anywhere
 */
HTTP.get = function (/* varargs */) {
  return HTTP.call.apply(this, ["GET"].concat(_.toArray(arguments)));
};

/**
 * @summary Send an HTTP `POST` request. Equivalent to calling [`HTTP.call`](#http_call) with "POST" as the first argument.
 * @param {String} url The URL to which the request should be sent.
 * @param {Object} [callOptions] Options passed on to [`HTTP.call`](#http_call).
 * @param {Function} [asyncCallback] Callback that is called when the request is completed. Required on the client.
 * @locus Anywhere
 */
HTTP.post = function (/* varargs */) {
  return HTTP.call.apply(this, ["POST"].concat(_.toArray(arguments)));
};

/**
 * @summary Send an HTTP `PUT` request. Equivalent to calling [`HTTP.call`](#http_call) with "PUT" as the first argument.
 * @param {String} url The URL to which the request should be sent.
 * @param {Object} [callOptions] Options passed on to [`HTTP.call`](#http_call).
 * @param {Function} [asyncCallback] Callback that is called when the request is completed. Required on the client.
 * @locus Anywhere
 */
HTTP.put = function (/* varargs */) {
  return HTTP.call.apply(this, ["PUT"].concat(_.toArray(arguments)));
};

/**
 * @summary Send an HTTP `DELETE` request. Equivalent to calling [`HTTP.call`](#http_call) with "DELETE" as the first argument. (Named `del` to avoid conflic with the Javascript keyword `delete`)
 * @param {String} url The URL to which the request should be sent.
 * @param {Object} [callOptions] Options passed on to [`HTTP.call`](#http_call).
 * @param {Function} [asyncCallback] Callback that is called when the request is completed. Required on the client.
 * @locus Anywhere
 */
HTTP.del = function (/* varargs */) {
  return HTTP.call.apply(this, ["DELETE"].concat(_.toArray(arguments)));
};


// XXX: When we update this, see if it fixes this Github issue:

// https://github.com/jgm/CommonMark/issues/276 . If it does, remove the

// XXX We ought to be able to get this from the copy in js-analyze rather

keep keep keep keep replace replace keep