/// [new] Blaze.View([name], renderMethod)
///
/// Blaze.View is the building block of reactive DOM.  Views have
/// the following features:
///
/// * lifecycle callbacks - Views are created, rendered, and destroyed,
///   and callbacks can be registered to fire when these things happen.
///
/// * parent pointer - A View points to its parentView, which is the
///   View that caused it to be rendered.  These pointers form a
///   hierarchy or tree of Views.
///
/// * render() method - A View's render() method specifies the DOM
///   (or HTML) content of the View.  If the method establishes
///   reactive dependencies, it may be re-run.
///
/// * a DOMRange - If a View is rendered to DOM, its position and
///   extent in the DOM are tracked using a DOMRange object.
///
/// When a View is constructed by calling Blaze.View, the View is
/// not yet considered "created."  It doesn't have a parentView yet,
/// and no logic has been run to initialize the View.  All real
/// work is deferred until at least creation time, when the onViewCreated
/// callbacks are fired, which happens when the View is "used" in
/// some way that requires it to be rendered.
///
/// ...more lifecycle stuff
///
/// `name` is an optional string tag identifying the View.  The only
/// time it's used is when looking in the View tree for a View of a
/// particular name; for example, data contexts are stored on Views
/// of name "with".  Names are also useful when debugging, so in
/// general it's good for functions that create Views to set the name.
/// Views associated with templates have names of the form "Template.foo".

/**
 * @class
 * @summary Constructor for a View, which represents a reactive region of DOM.
 * @locus Client
 * @param {String} [name] Optional.  A name for this type of View.  See [`view.name`](#view_name).
 * @param {Function} renderFunction A function that returns [*renderable content*](#renderable_content).  In this function, `this` is bound to the View.
 */
Blaze.View = function (name, render) {
  if (! (this instanceof Blaze.View))
    // called without `new`
    return new Blaze.View(name, render);

  if (typeof name === 'function') {
    // omitted "name" argument
    render = name;
    name = '';
  }
  this.name = name;
  this._render = render;

  this._callbacks = {
    created: null,
    rendered: null,
    destroyed: null
  };

  // Setting all properties here is good for readability,
  // and also may help Chrome optimize the code by keeping
  // the View object from changing shape too much.
  this.isCreated = false;
  this._isCreatedForExpansion = false;
  this.isRendered = false;
  this._isAttached = false;
  this.isDestroyed = false;
  this._isInRender = false;
  this.parentView = null;
  this._domrange = null;
  // This flag is normally set to false except for the cases when view's parent
  // was generated as part of expanding some syntactic sugar expressions or
  // methods.
  // Ex.: Blaze.renderWithData is an equivalent to creating a view with regular
  // Blaze.render and wrapping it into {{#with data}}{{/with}} view. Since the
  // users don't know anything about these generated parent views, Blaze needs
  // this information to be available on views to make smarter decisions. For
  // example: removing the generated parent view with the view on Blaze.remove.
  this._hasGeneratedParent = false;

  this.renderCount = 0;
};

Blaze.View.prototype._render = function () { return null; };

Blaze.View.prototype.onViewCreated = function (cb) {
  this._callbacks.created = this._callbacks.created || [];
  this._callbacks.created.push(cb);
};

Blaze.View.prototype._onViewRendered = function (cb) {
  this._callbacks.rendered = this._callbacks.rendered || [];
  this._callbacks.rendered.push(cb);
};

Blaze.View.prototype.onViewReady = function (cb) {
  var self = this;
  var fire = function () {
    Tracker.afterFlush(function () {
      if (! self.isDestroyed) {
        Blaze._withCurrentView(self, function () {
          cb.call(self);
        });
      }
    });
  };
  self._onViewRendered(function onViewRendered() {
    if (self.isDestroyed)
      return;
    if (! self._domrange.attached)
      self._domrange.onAttached(fire);
    else
      fire();
  });
};

Blaze.View.prototype.onViewDestroyed = function (cb) {
  this._callbacks.destroyed = this._callbacks.destroyed || [];
  this._callbacks.destroyed.push(cb);
};

/// View#autorun(func)
///
/// Sets up a Tracker autorun that is "scoped" to this View in two
/// important ways: 1) Blaze.currentView is automatically set
/// on every re-run, and 2) the autorun is stopped when the
/// View is destroyed.  As with Tracker.autorun, the first run of
/// the function is immediate, and a Computation object that can
/// be used to stop the autorun is returned.
///
/// View#autorun is meant to be called from View callbacks like
/// onViewCreated, or from outside the rendering process.  It may not
/// be called before the onViewCreated callbacks are fired (too early),
/// or from a render() method (too confusing).
///
/// Typically, autoruns that update the state
/// of the View (as in Blaze.With) should be started from an onViewCreated
/// callback.  Autoruns that update the DOM should be started
/// from either onViewCreated (guarded against the absence of
/// view._domrange), or onViewReady.
Blaze.View.prototype.autorun = function (f, _inViewScope, displayName) {
  var self = this;

  // The restrictions on when View#autorun can be called are in order
  // to avoid bad patterns, like creating a Blaze.View and immediately
  // calling autorun on it.  A freshly created View is not ready to
  // have logic run on it; it doesn't have a parentView, for example.
  // It's when the View is materialized or expanded that the onViewCreated
  // handlers are fired and the View starts up.
  //
  // Letting the render() method call `this.autorun()` is problematic
  // because of re-render.  The best we can do is to stop the old
  // autorun and start a new one for each render, but that's a pattern
  // we try to avoid internally because it leads to helpers being
  // called extra times, in the case where the autorun causes the
  // view to re-render (and thus the autorun to be torn down and a
  // new one established).
  //
  // We could lift these restrictions in various ways.  One interesting
  // idea is to allow you to call `view.autorun` after instantiating
  // `view`, and automatically wrap it in `view.onViewCreated`, deferring
  // the autorun so that it starts at an appropriate time.  However,
  // then we can't return the Computation object to the caller, because
  // it doesn't exist yet.
  if (! self.isCreated) {
    throw new Error("View#autorun must be called from the created callback at the earliest");
  }
  if (this._isInRender) {
    throw new Error("Can't call View#autorun from inside render(); try calling it from the created or rendered callback");
  }
  if (Tracker.active) {
    throw new Error("Can't call View#autorun from a Tracker Computation; try calling it from the created or rendered callback");
  }

  // Each local variable allocate additional space on each frame of the
  // execution stack. When too many variables are allocated on stack, you can
  // run out of memory on stack running a deep recursion (which is typical for
  // Blaze functions) and get stackoverlow error. (The size of the stack varies
  // between browsers).
  // The trick we use here is to allocate only one variable on stack `locals`
  // that keeps references to all the rest. Since locals is allocated on heap,
  // we don't take up any space on the stack.
  var locals = {};
  locals.templateInstanceFunc = Blaze.Template._currentTemplateInstanceFunc;

  locals.f = function viewAutorun(c) {
    return Blaze._withCurrentView(_inViewScope || self, function () {
      return Blaze.Template._withTemplateInstanceFunc(locals.templateInstanceFunc, function () {
        return f.call(self, c);
      });
    });
  };

  // Give the autorun function a better name for debugging and profiling.
  // The `displayName` property is not part of the spec but browsers like Chrome
  // and Firefox prefer it in debuggers over the name function was declared by.
  locals.f.displayName =
    (self.name || 'anonymous') + ':' + (displayName || 'anonymous');
  locals.c = Tracker.autorun(locals.f);

  self.onViewDestroyed(function () { locals.c.stop(); });

  return locals.c;
};

Blaze.View.prototype._errorIfShouldntCallSubscribe = function () {
  var self = this;

  if (! self.isCreated) {
    throw new Error("View#subscribe must be called from the created callback at the earliest");
  }
  if (self._isInRender) {
    throw new Error("Can't call View#subscribe from inside render(); try calling it from the created or rendered callback");
  }
  if (self.isDestroyed) {
    throw new Error("Can't call View#subscribe from inside the destroyed callback, try calling it inside created or rendered.");
  }
};

/**
 * Just like Blaze.View#autorun, but with Meteor.subscribe instead of
 * Tracker.autorun. Stop the subscription when the view is destroyed.
 * @return {SubscriptionHandle} A handle to the subscription so that you can
 * see if it is ready, or stop it manually
 */
Blaze.View.prototype.subscribe = function (args, options) {
  var self = this;
  options = options || {};

  self._errorIfShouldntCallSubscribe();

  var subHandle;
  if (options.connection) {
    subHandle = options.connection.subscribe.apply(options.connection, args);
  } else {
    subHandle = Meteor.subscribe.apply(Meteor, args);
  }

  self.onViewDestroyed(function () {
    subHandle.stop();
  });

  return subHandle;
};

Blaze.View.prototype.firstNode = function () {
  if (! this._isAttached)
    throw new Error("View must be attached before accessing its DOM");

  return this._domrange.firstNode();
};

Blaze.View.prototype.lastNode = function () {
  if (! this._isAttached)
    throw new Error("View must be attached before accessing its DOM");

  return this._domrange.lastNode();
};

Blaze._fireCallbacks = function (view, which) {
  Blaze._withCurrentView(view, function () {
    Tracker.nonreactive(function fireCallbacks() {
      var cbs = view._callbacks[which];
      for (var i = 0, N = (cbs && cbs.length); i < N; i++)
        cbs[i].call(view);
    });
  });
};

Blaze._createView = function (view, parentView, forExpansion) {
  if (view.isCreated)
    throw new Error("Can't render the same View twice");

  view.parentView = (parentView || null);
  view.isCreated = true;
  if (forExpansion)
    view._isCreatedForExpansion = true;

  Blaze._fireCallbacks(view, 'created');
};

var doFirstRender = function (view, initialContent) {
  var domrange = new Blaze._DOMRange(initialContent);
  view._domrange = domrange;
  domrange.view = view;
  view.isRendered = true;
  Blaze._fireCallbacks(view, 'rendered');

  var teardownHook = null;

  domrange.onAttached(function attached(range, element) {
    view._isAttached = true;

    teardownHook = Blaze._DOMBackend.Teardown.onElementTeardown(
      element, function teardown() {
        Blaze._destroyView(view, true /* _skipNodes */);
      });
  });

  // tear down the teardown hook
  view.onViewDestroyed(function () {
    teardownHook && teardownHook.stop();
    teardownHook = null;
  });

  return domrange;
};

// Take an uncreated View `view` and create and render it to DOM,
// setting up the autorun that updates the View.  Returns a new
// DOMRange, which has been associated with the View.
//
// The private arguments `_workStack` and `_intoArray` are passed in
// by Blaze._materializeDOM and are only present for recursive calls
// (when there is some other _materializeView on the stack).  If
// provided, then we avoid the mutual recursion of calling back into
// Blaze._materializeDOM so that deep View hierarchies don't blow the
// stack.  Instead, we push tasks onto workStack for the initial
// rendering and subsequent setup of the View, and they are done after
// we return.  When there is a _workStack, we do not return the new
// DOMRange, but instead push it into _intoArray from a _workStack
// task.
Blaze._materializeView = function (view, parentView, _workStack, _intoArray) {
  Blaze._createView(view, parentView);

  var domrange;
  var lastHtmljs;
  // We don't expect to be called in a Computation, but just in case,
  // wrap in Tracker.nonreactive.
  Tracker.nonreactive(function () {
    view.autorun(function doRender(c) {
      // `view.autorun` sets the current view.
      view.renderCount++;
      view._isInRender = true;
      // Any dependencies that should invalidate this Computation come
      // from this line:
      var htmljs = view._render();
      view._isInRender = false;

      if (! c.firstRun) {
        Tracker.nonreactive(function doMaterialize() {
          // re-render
          var rangesAndNodes = Blaze._materializeDOM(htmljs, [], view);
          if (! Blaze._isContentEqual(lastHtmljs, htmljs)) {
            domrange.setMembers(rangesAndNodes);
            Blaze._fireCallbacks(view, 'rendered');
          }
        });
      }
      lastHtmljs = htmljs;

      // Causes any nested views to stop immediately, not when we call
      // `setMembers` the next time around the autorun.  Otherwise,
      // helpers in the DOM tree to be replaced might be scheduled
      // to re-run before we have a chance to stop them.
      Tracker.onInvalidate(function () {
        if (domrange) {
          domrange.destroyMembers();
        }
      });
    }, undefined, 'materialize');

    // first render.  lastHtmljs is the first htmljs.
    var initialContents;
    if (! _workStack) {
      initialContents = Blaze._materializeDOM(lastHtmljs, [], view);
      domrange = doFirstRender(view, initialContents);
      initialContents = null; // help GC because we close over this scope a lot
    } else {
      // We're being called from Blaze._materializeDOM, so to avoid
      // recursion and save stack space, provide a description of the
      // work to be done instead of doing it.  Tasks pushed onto
      // _workStack will be done in LIFO order after we return.
      // The work will still be done within a Tracker.nonreactive,
      // because it will be done by some call to Blaze._materializeDOM
      // (which is always called in a Tracker.nonreactive).
      initialContents = [];
      // push this function first so that it happens last
      _workStack.push(function () {
        domrange = doFirstRender(view, initialContents);
        initialContents = null; // help GC because of all the closures here
        _intoArray.push(domrange);
      });
      // now push the task that calculates initialContents
      _workStack.push(_.bind(Blaze._materializeDOM, null,
                             lastHtmljs, initialContents, view, _workStack));
    }
  });

  if (! _workStack) {
    return domrange;
  } else {
    return null;
  }
};

// Expands a View to HTMLjs, calling `render` recursively on all
// Views and evaluating any dynamic attributes.  Calls the `created`
// callback, but not the `materialized` or `rendered` callbacks.
// Destroys the view immediately, unless called in a Tracker Computation,
// in which case the view will be destroyed when the Computation is
// invalidated.  If called in a Tracker Computation, the result is a
// reactive string; that is, the Computation will be invalidated
// if any changes are made to the view or subviews that might affect
// the HTML.
Blaze._expandView = function (view, parentView) {
  Blaze._createView(view, parentView, true /*forExpansion*/);

  view._isInRender = true;
  var htmljs = Blaze._withCurrentView(view, function () {
    return view._render();
  });
  view._isInRender = false;

  var result = Blaze._expand(htmljs, view);

  if (Tracker.active) {
    Tracker.onInvalidate(function () {
      Blaze._destroyView(view);
    });
  } else {
    Blaze._destroyView(view);
  }

  return result;
};

// Options: `parentView`
Blaze._HTMLJSExpander = HTML.TransformingVisitor.extend();
Blaze._HTMLJSExpander.def({
  visitObject: function (x) {
    if (x instanceof Blaze.Template)
      x = x.constructView();
    if (x instanceof Blaze.View)
      return Blaze._expandView(x, this.parentView);

    // this will throw an error; other objects are not allowed!
    return HTML.TransformingVisitor.prototype.visitObject.call(this, x);
  },
  visitAttributes: function (attrs) {
    // expand dynamic attributes
    if (typeof attrs === 'function')
      attrs = Blaze._withCurrentView(this.parentView, attrs);

    // call super (e.g. for case where `attrs` is an array)
    return HTML.TransformingVisitor.prototype.visitAttributes.call(this, attrs);
  },
  visitAttribute: function (name, value, tag) {
    // expand attribute values that are functions.  Any attribute value
    // that contains Views must be wrapped in a function.
    if (typeof value === 'function')
      value = Blaze._withCurrentView(this.parentView, value);

    return HTML.TransformingVisitor.prototype.visitAttribute.call(
      this, name, value, tag);
  }
});

// Return Blaze.currentView, but only if it is being rendered
// (i.e. we are in its render() method).
var currentViewIfRendering = function () {
  var view = Blaze.currentView;
  return (view && view._isInRender) ? view : null;
};

Blaze._expand = function (htmljs, parentView) {
  parentView = parentView || currentViewIfRendering();
  return (new Blaze._HTMLJSExpander(
    {parentView: parentView})).visit(htmljs);
};

Blaze._expandAttributes = function (attrs, parentView) {
  parentView = parentView || currentViewIfRendering();
  return (new Blaze._HTMLJSExpander(
    {parentView: parentView})).visitAttributes(attrs);
};

Blaze._destroyView = function (view, _skipNodes) {
  if (view.isDestroyed)
    return;
  view.isDestroyed = true;

  Blaze._fireCallbacks(view, 'destroyed');

  // Destroy views and elements recursively.  If _skipNodes,
  // only recurse up to views, not elements, for the case where
  // the backend (jQuery) is recursing over the elements already.

  if (view._domrange)
    view._domrange.destroyMembers(_skipNodes);
};

Blaze._destroyNode = function (node) {
  if (node.nodeType === 1)
    Blaze._DOMBackend.Teardown.tearDownElement(node);
};

// Are the HTMLjs entities `a` and `b` the same?  We could be
// more elaborate here but the point is to catch the most basic
// cases.
Blaze._isContentEqual = function (a, b) {
  if (a instanceof HTML.Raw) {
    return (b instanceof HTML.Raw) && (a.value === b.value);
  } else if (a == null) {
    return (b == null);
  } else {
    return (a === b) &&
      ((typeof a === 'number') || (typeof a === 'boolean') ||
       (typeof a === 'string'));
  }
};

/**
 * @summary The View corresponding to the current template helper, event handler, callback, or autorun.  If there isn't one, `null`.
 * @locus Client
 * @type {Blaze.View}
 */
Blaze.currentView = null;

Blaze._withCurrentView = function (view, func) {
  var oldView = Blaze.currentView;
  try {
    Blaze.currentView = view;
    return func();
  } finally {
    Blaze.currentView = oldView;
  }
};

// Blaze.render publicly takes a View or a Template.
// Privately, it takes any HTMLJS (extended with Views and Templates)
// except null or undefined, or a function that returns any extended
// HTMLJS.
var checkRenderContent = function (content) {
  if (content === null)
    throw new Error("Can't render null");
  if (typeof content === 'undefined')
    throw new Error("Can't render undefined");

  if ((content instanceof Blaze.View) ||
      (content instanceof Blaze.Template) ||
      (typeof content === 'function'))
    return;

  try {
    // Throw if content doesn't look like HTMLJS at the top level
    // (i.e. verify that this is an HTML.Tag, or an array,
    // or a primitive, etc.)
    (new HTML.Visitor).visit(content);
  } catch (e) {
    // Make error message suitable for public API
    throw new Error("Expected Template or View");
  }
};

// For Blaze.render and Blaze.toHTML, take content and
// wrap it in a View, unless it's a single View or
// Template already.
var contentAsView = function (content) {
  checkRenderContent(content);

  if (content instanceof Blaze.Template) {
    return content.constructView();
  } else if (content instanceof Blaze.View) {
    return content;
  } else {
    var func = content;
    if (typeof func !== 'function') {
      func = function () {
        return content;
      };
    }
    return Blaze.View('render', func);
  }
};

// For Blaze.renderWithData and Blaze.toHTMLWithData, wrap content
// in a function, if necessary, so it can be a content arg to
// a Blaze.With.
var contentAsFunc = function (content) {
  checkRenderContent(content);

  if (typeof content !== 'function') {
    return function () {
      return content;
    };
  } else {
    return content;
  }
};

/**
 * @summary Renders a template or View to DOM nodes and inserts it into the DOM, returning a rendered [View](#blaze_view) which can be passed to [`Blaze.remove`](#blaze_remove).
 * @locus Client
 * @param {Template|Blaze.View} templateOrView The template (e.g. `Template.myTemplate`) or View object to render.  If a template, a View object is [constructed](#template_constructview).  If a View, it must be an unrendered View, which becomes a rendered View and is returned.
 * @param {DOMNode} parentNode The node that will be the parent of the rendered template.  It must be an Element node.
 * @param {DOMNode} [nextNode] Optional. If provided, must be a child of <em>parentNode</em>; the template will be inserted before this node. If not provided, the template will be inserted as the last child of parentNode.
 * @param {Blaze.View} [parentView] Optional. If provided, it will be set as the rendered View's [`parentView`](#view_parentview).
 */
Blaze.render = function (content, parentElement, nextNode, parentView) {
  if (! parentElement) {
    Blaze._warn("Blaze.render without a parent element is deprecated. " +
                "You must specify where to insert the rendered content.");
  }

  if (nextNode instanceof Blaze.View) {
    // handle omitted nextNode
    parentView = nextNode;
    nextNode = null;
  }

  // parentElement must be a DOM node. in particular, can't be the
  // result of a call to `$`. Can't check if `parentElement instanceof
  // Node` since 'Node' is undefined in IE8.
  if (parentElement && typeof parentElement.nodeType !== 'number')
    throw new Error("'parentElement' must be a DOM node");
  if (nextNode && typeof nextNode.nodeType !== 'number') // 'nextNode' is optional
    throw new Error("'nextNode' must be a DOM node");

  parentView = parentView || currentViewIfRendering();

  var view = contentAsView(content);
  Blaze._materializeView(view, parentView);

  if (parentElement) {
    view._domrange.attach(parentElement, nextNode);
  }

  return view;
};

Blaze.insert = function (view, parentElement, nextNode) {
  Blaze._warn("Blaze.insert has been deprecated.  Specify where to insert the " +
              "rendered content in the call to Blaze.render.");

  if (! (view && (view._domrange instanceof Blaze._DOMRange)))
    throw new Error("Expected template rendered with Blaze.render");

  view._domrange.attach(parentElement, nextNode);
};

/**
 * @summary Renders a template or View to DOM nodes with a data context.  Otherwise identical to `Blaze.render`.
 * @locus Client
 * @param {Template|Blaze.View} templateOrView The template (e.g. `Template.myTemplate`) or View object to render.
 * @param {Object|Function} data The data context to use, or a function returning a data context.  If a function is provided, it will be reactively re-run.
 * @param {DOMNode} parentNode The node that will be the parent of the rendered template.  It must be an Element node.
 * @param {DOMNode} [nextNode] Optional. If provided, must be a child of <em>parentNode</em>; the template will be inserted before this node. If not provided, the template will be inserted as the last child of parentNode.
 * @param {Blaze.View} [parentView] Optional. If provided, it will be set as the rendered View's [`parentView`](#view_parentview).
 */
Blaze.renderWithData = function (content, data, parentElement, nextNode, parentView) {
  // We defer the handling of optional arguments to Blaze.render.  At this point,
  // `nextNode` may actually be `parentView`.
  return Blaze.render(Blaze._TemplateWith(data, contentAsFunc(content)),
                          parentElement, nextNode, parentView);
};

/**
 * @summary Removes a rendered View from the DOM, stopping all reactive updates and event listeners on it.
 * @locus Client
 * @param {Blaze.View} renderedView The return value from `Blaze.render` or `Blaze.renderWithData`.
 */
Blaze.remove = function (view) {
  if (! (view && (view._domrange instanceof Blaze._DOMRange)))
    throw new Error("Expected template rendered with Blaze.render");

  while (view) {
    if (! view.isDestroyed) {
      var range = view._domrange;
      if (range.attached && ! range.parentRange)
        range.detach();
      range.destroy();
    }

    view = view._hasGeneratedParent && view.parentView;
  }
};

/**
 * @summary Renders a template or View to a string of HTML.
 * @locus Client
 * @param {Template|Blaze.View} templateOrView The template (e.g. `Template.myTemplate`) or View object from which to generate HTML.
 */
Blaze.toHTML = function (content, parentView) {
  parentView = parentView || currentViewIfRendering();

  return HTML.toHTML(Blaze._expandView(contentAsView(content), parentView));
};

/**
 * @summary Renders a template or View to HTML with a data context.  Otherwise identical to `Blaze.toHTML`.
 * @locus Client
 * @param {Template|Blaze.View} templateOrView The template (e.g. `Template.myTemplate`) or View object from which to generate HTML.
 * @param {Object|Function} data The data context to use, or a function returning a data context.
 */
Blaze.toHTMLWithData = function (content, data, parentView) {
  parentView = parentView || currentViewIfRendering();

  return HTML.toHTML(Blaze._expandView(Blaze._TemplateWith(
    data, contentAsFunc(content)), parentView));
};

Blaze._toText = function (htmljs, parentView, textMode) {
  if (typeof htmljs === 'function')
    throw new Error("Blaze._toText doesn't take a function, just HTMLjs");

  if ((parentView != null) && ! (parentView instanceof Blaze.View)) {
    // omitted parentView argument
    textMode = parentView;
    parentView = null;
  }
  parentView = parentView || currentViewIfRendering();

  if (! textMode)
    throw new Error("textMode required");
  if (! (textMode === HTML.TEXTMODE.STRING ||
         textMode === HTML.TEXTMODE.RCDATA ||
         textMode === HTML.TEXTMODE.ATTRIBUTE))
    throw new Error("Unknown textMode: " + textMode);

  return HTML.toText(Blaze._expand(htmljs, parentView), textMode);
};

/**
 * @summary Returns the current data context, or the data context that was used when rendering a particular DOM element or View from a Meteor template.
 * @locus Client
 * @param {DOMElement|Blaze.View} [elementOrView] Optional.  An element that was rendered by a Meteor, or a View.
 */
Blaze.getData = function (elementOrView) {
  var theWith;

  if (! elementOrView) {
    theWith = Blaze.getView('with');
  } else if (elementOrView instanceof Blaze.View) {
    var view = elementOrView;
    theWith = (view.name === 'with' ? view :
               Blaze.getView(view, 'with'));
  } else if (typeof elementOrView.nodeType === 'number') {
    if (elementOrView.nodeType !== 1)
      throw new Error("Expected DOM element");
    theWith = Blaze.getView(elementOrView, 'with');
  } else {
    throw new Error("Expected DOM element or View");
  }

  return theWith ? theWith.dataVar.get() : null;
};

// For back-compat
Blaze.getElementData = function (element) {
  Blaze._warn("Blaze.getElementData has been deprecated.  Use " +
              "Blaze.getData(element) instead.");

  if (element.nodeType !== 1)
    throw new Error("Expected DOM element");

  return Blaze.getData(element);
};

// Both arguments are optional.

/**
 * @summary Gets either the current View, or the View enclosing the given DOM element.
 * @locus Client
 * @param {DOMElement} [element] Optional.  If specified, the View enclosing `element` is returned.
 */
Blaze.getView = function (elementOrView, _viewName) {
  var viewName = _viewName;

  if ((typeof elementOrView) === 'string') {
    // omitted elementOrView; viewName present
    viewName = elementOrView;
    elementOrView = null;
  }

  // We could eventually shorten the code by folding the logic
  // from the other methods into this method.
  if (! elementOrView) {
    return Blaze._getCurrentView(viewName);
  } else if (elementOrView instanceof Blaze.View) {
    return Blaze._getParentView(elementOrView, viewName);
  } else if (typeof elementOrView.nodeType === 'number') {
    return Blaze._getElementView(elementOrView, viewName);
  } else {
    throw new Error("Expected DOM element or View");
  }
};

// Gets the current view or its nearest ancestor of name
// `name`.
Blaze._getCurrentView = function (name) {
  var view = Blaze.currentView;
  // Better to fail in cases where it doesn't make sense
  // to use Blaze._getCurrentView().  There will be a current
  // view anywhere it does.  You can check Blaze.currentView
  // if you want to know whether there is one or not.
  if (! view)
    throw new Error("There is no current view");

  if (name) {
    while (view && view.name !== name)
      view = view.parentView;
    return view || null;
  } else {
    // Blaze._getCurrentView() with no arguments just returns
    // Blaze.currentView.
    return view;
  }
};

Blaze._getParentView = function (view, name) {
  var v = view.parentView;

  if (name) {
    while (v && v.name !== name)
      v = v.parentView;
  }

  return v || null;
};

Blaze._getElementView = function (elem, name) {
  var range = Blaze._DOMRange.forElement(elem);
  var view = null;
  while (range && ! view) {
    view = (range.view || null);
    if (! view) {
      if (range.parentRange)
        range = range.parentRange;
      else
        range = Blaze._DOMRange.forElement(range.parentElement);
    }
  }

  if (name) {
    while (view && view.name !== name)
      view = view.parentView;
    return view || null;
  } else {
    return view;
  }
};

Blaze._addEventMap = function (view, eventMap, thisInHandler) {
  thisInHandler = (thisInHandler || null);
  var handles = [];

  if (! view._domrange)
    throw new Error("View must have a DOMRange");

  view._domrange.onAttached(function attached_eventMaps(range, element) {
    _.each(eventMap, function (handler, spec) {
      var clauses = spec.split(/,\s+/);
      // iterate over clauses of spec, e.g. ['click .foo', 'click .bar']
      _.each(clauses, function (clause) {
        var parts = clause.split(/\s+/);
        if (parts.length === 0)
          return;

        var newEvents = parts.shift();
        var selector = parts.join(' ');
        handles.push(Blaze._EventSupport.listen(
          element, newEvents, selector,
          function (evt) {
            if (! range.containsElement(evt.currentTarget))
              return null;
            var handlerThis = thisInHandler || this;
            var handlerArgs = arguments;
            return Blaze._withCurrentView(view, function () {
              return handler.apply(handlerThis, handlerArgs);
            });
          },
          range, function (r) {
            return r.parentRange;
          }));
      });
    });
  });

  view.onViewDestroyed(function () {
    _.each(handles, function (h) {
      h.stop();
    });
    handles.length = 0;
  });
};


var optimized = groupMutuallyExclusiveTerms(costTerms, costWeights);

self.solution, optimized.costTerms, optimized.costWeights, {

keep keep keep keep replace keep keep keep keep keep

<template name="basicIntroduction">

{{#markdown}}

_**Meteor is an ultra-simple environment for building modern websites.
What once took weeks, even with the best tools, now takes hours with
Meteor.**_

The web was originally designed to work in the same way that mainframes
worked in the 70s.  The application server rendered a screen and sent it
over the network to a dumb terminal. Whenever the user did anything,
that server rerendered a whole new screen. This model served the Web
well for over a decade. It gave rise to LAMP, Rails, Django, PHP.

But the best teams, with the biggest budgets and the longest schedules,
now build applications in JavaScript that run on the client.  These apps
have stellar interfaces.  They don't reload pages.  They are reactive:
changes from any client immediately appear on everyone's screen.

They've built them the hard way.  Meteor makes it an order of
magnitude simpler, and a lot more fun.  You can build a complete
application in a weekend, or a sufficiently caffeinated hackathon.  No
longer do you need to provision server resources, or deploy API
endpoints in the cloud, or manage a database, or wrangle an ORM layer,
or swap back and forth between JavaScript and Ruby, or broadcast data
invalidations to clients.

{{> quickStart}}

{{> principles}}

Learning Resources

There are many community resources for getting help with your app. If Meteor
catches your interest, we hope you'll get involved with the project!

Tutorial

Get started fast with the official Meteor tutorial!

Stack Overflow

The best place to ask (and answer!) technical questions is on Stack
  Overflow.  Be sure to add
  the meteor tag to your question.

Forums

Visit the Meteor discussion
    forums to announce projects, get help, talk about the community,
  or discuss changes to core.

GitHub

The core code is on GitHub.  If you're able to write code or file issues, we'd love to have your help.  Please read Contributing to Meteor for how to get started.

{{/markdown}}

{{> commandLine}}
{{> basicFileStructure}}
{{> basicMobile}}

</template>


for (var i = 0; i < vectorLength; i++) {

var weights = _.pluck(weightVectors, i);

solution = solver.minimize(solution, terms, weights);

keep keep keep keep keep replace keep keep keep

solution = solver.minimizeWeightedSum(solution, terms, weights);

var CS = ConstraintSolver;
var PV = PackageVersion;

var pvVar = function (p, v) {
  return p + ' ' + v;
};

// The "inner solver".  You construct it with a ConstraintSolver.Input object
// (which specifies the problem) and then call .getAnswer() on it.

CS.Solver = function (input, options) {
  var self = this;
  check(input, CS.Input);

  self.input = input;
  self.errors = []; // [String]

  self.pricer = new CS.VersionPricer();
  self.getConstraintFormula = _.memoize(_getConstraintFormula,
                                         function (p, vConstraint) {
                                           return p + "@" + vConstraint.raw;
                                         });

  self.options = options || {};
  self.Profile = (self.options.Profile || CS.DummyProfile);

  self.steps = [];
  self.stepsByName = {};

  self.analysis = {};

  self.Profile.time("Solver#analyze", function () {
    self.analyze();
  });

  self.logic = null; // Logic.Solver, initialized later
};

CS.Solver.prototype.throwAnyErrors = function () {
  if (this.errors.length) {
    var multiline = _.any(this.errors, function (e) {
      return /\n/.test(e);
    });
    CS.throwConstraintSolverError(this.errors.join(
      multiline ? '\n\n' : '\n'));
  }
};

CS.Solver.prototype.getVersions = function (package) {
  var self = this;
  if (_.has(self.analysis.allowedVersions, package)) {
    return self.analysis.allowedVersions[package];
  } else {
    return self.input.catalogCache.getPackageVersions(package);
  }
};

// Populates `self.analysis` with various data structures derived from the
// input.  May also throw errors, and may call methods that rely on
// analysis once that particular analysis is done (e.g. `self.getVersions`
// which relies on `self.analysis.allowedVersions`.
CS.Solver.prototype.analyze = function () {
  var self = this;
  var analysis = self.analysis;
  var input = self.input;
  var cache = input.catalogCache;
  var Profile = self.Profile;

  ////////// ANALYZE ALLOWED VERSIONS
  // (An "allowed version" is one that isn't ruled out by a top-level
  // constraint.)

  // package -> array of version strings.  If a package has an entry in
  // this map, then only the versions in the array are allowed for
  // consideration.
  analysis.allowedVersions = {};
  analysis.packagesWithNoAllowedVersions = {}; // package -> [constraints]

  // Process top-level constraints, applying them right now by
  // limiting what package versions we even consider.  This speeds up
  // solving, especially given the equality constraints on core
  // packages.  For versions we don't allow, we get to avoid generating
  // Constraint objects for their constraints, which saves us both
  // clause generation time and solver work up through the point where we
  // determine there are no conflicts between constraints.
  //
  // we can't throw any errors yet, because `input.constraints`
  // doesn't establish any dependencies (so we don't know if it's a
  // problem that some package has no legal versions), but we can
  // track such packages in packagesWithNoAllowedVersions so that we
  // throw a good error later.
  Profile.time("analyze allowed versions", function () {
    _.each(_.groupBy(input.constraints, 'package'), function (cs, p) {
      var versions = cache.getPackageVersions(p);
      if (! versions.length) {
        // deal with wholly unknown packages later
        return;
      }
      _.each(cs, function (constr) {
        versions = _.filter(versions, function (v) {
          return CS.isConstraintSatisfied(p, constr.versionConstraint, v);
        });
      });
      if (! versions.length) {
        analysis.packagesWithNoAllowedVersions[p] = _.filter(cs, function (c) {
          return !! c.constraintString;
        });
      }
      analysis.allowedVersions[p] = versions;
    });
  });

  ////////// ANALYZE ROOT DEPENDENCIES

  // Collect root dependencies that we've never heard of.
  analysis.unknownRootDeps = [];
  // Collect "previous solution" versions of root dependencies.
  analysis.previousRootDepVersions = [];

  Profile.time("analyze root dependencies", function () {
    _.each(input.dependencies, function (p) {
      if (! input.isKnownPackage(p)) {
        analysis.unknownRootDeps.push(p);
      } else if (input.isInPreviousSolution(p) &&
                 ! input.isUpgrading(p)) {
        analysis.previousRootDepVersions.push(new CS.PackageAndVersion(
          p, input.previousSolution[p]));
      }
    });

    // throw if there are unknown packages in root deps
    if (analysis.unknownRootDeps.length) {
      _.each(analysis.unknownRootDeps, function (p) {
        self.errors.push('unknown package in top-level dependencies: ' + p);
      });
      self.throwAnyErrors();
    }
  });

  ////////// ANALYZE REACHABILITY

  // A "reachable" package is one that is either a root dependency or
  // a strong dependency of any "allowed" version of a reachable package.
  // In other words, we walk all strong dependencies starting
  // with the root dependencies, and visiting all allowed versions of each
  // package.
  //
  // This analysis is mainly done for performance, because if there are
  // extraneous packages in the CatalogCache (for whatever reason) we
  // want to spend as little time on them as possible.  It also establishes
  // the universe of possible "known" and "unknown" packages we might
  // come across.
  //
  // A more nuanced reachability analysis that takes versions into account
  // is probably possible.

  // package name -> true
  analysis.reachablePackages = {};
  // package name -> package versions asking for it (in pvVar form)
  analysis.unknownPackages = {};

  var markReachable = function (p) {
    analysis.reachablePackages[p] = true;

    _.each(self.getVersions(p), function (v) {
      _.each(cache.getDependencyMap(p, v), function (dep) {
        // `dep` is a CS.Dependency
        var p2 = dep.packageConstraint.package;
        if (! input.isKnownPackage(p2)) {
          // record this package so we will generate a variable
          // for it.  we'll try not to select it, and ultimately
          // throw an error if we are forced to.
          if (! _.has(analysis.unknownPackages, p2)) {
            analysis.unknownPackages[p2] = [];
          }
          analysis.unknownPackages[p2].push(pvVar(p, v));
        } else {
          if (! dep.isWeak) {
            if (! _.has(analysis.reachablePackages, p2)) {
              markReachable(p2);
            }
          }
        }
      });
    });
  };

  Profile.time("analyze reachability", function () {
    _.each(input.dependencies, markReachable);
  });

  ////////// ANALYZE CONSTRAINTS

  // Array of CS.Solver.Constraint
  analysis.constraints = [];
  // packages `foo` such that there's a simple top-level equality
  // constraint about `foo`.  package name -> true.
  analysis.topLevelEqualityConstrainedPackages = {};

  Profile.time("analyze constraints", function () {
    // top-level constraints
    _.each(input.constraints, function (c) {
      if (c.constraintString) {
        analysis.constraints.push(new CS.Solver.Constraint(
          null, c.package, c.versionConstraint,
          "constraint#" + analysis.constraints.length));

        if (c.versionConstraint.alternatives.length === 1 &&
            c.versionConstraint.alternatives[0].type === 'exactly') {
          analysis.topLevelEqualityConstrainedPackages[c.package] = true;
        }
      }
    });

    // constraints specified in package dependencies
    _.each(_.keys(analysis.reachablePackages), function (p) {
      _.each(self.getVersions(p), function (v) {
        var pv = pvVar(p, v);
        _.each(cache.getDependencyMap(p, v), function (dep) {
          // `dep` is a CS.Dependency
          var p2 = dep.packageConstraint.package;
          if (input.isKnownPackage(p2) &&
              dep.packageConstraint.constraintString) {
            analysis.constraints.push(new CS.Solver.Constraint(
              pv, p2, dep.packageConstraint.versionConstraint,
              "constraint#" + analysis.constraints.length));
          }
        });
      });
    });
  });

  ////////// ANALYZE PRE-RELEASES

  Profile.time("analyze pre-releases", function () {
    var unanticipatedPrereleases = [];
    _.each(_.keys(analysis.reachablePackages), function (p) {
      var anticipatedPrereleases = input.anticipatedPrereleases[p];
      _.each(self.getVersions(p), function (v) {
        if (/-/.test(v) && ! (anticipatedPrereleases &&
                              _.has(anticipatedPrereleases, v))) {
          unanticipatedPrereleases.push(pvVar(p, v));
        }
      });
    });
    analysis.unanticipatedPrereleases = unanticipatedPrereleases;
  });
};

var WholeNumber = Match.Where(Logic.isWholeNumber);

// A Step consists of a name, an array of terms, and an array of weights.
// Steps are optimized one by one.  Optimizing a Step means to find
// the minimum whole number value for the weighted sum of the terms,
// and then to enforce in the solver that the weighted sum be that number.
// Thus, when the Steps are optimized in sequence, earlier Steps take
// precedence and will stay minimized while later Steps are optimized.
//
// A term can be a package name, a package version, or any other variable
// name or Logic formula.
//
// A weight is a non-negative integer.  The weights array can be a single
// weight (which is used for all terms).
//
// The terms and weights arguments each default to [].  You can add terms
// with weights using addTerm.
//
// options is optional.
CS.Solver.Step = function (name, terms, weights) {
  check(name, String);
  terms = terms || [];
  check(terms, [String]);
  weights = (weights == null ? [] : weights);
  check(weights, Match.OneOf([WholeNumber], WholeNumber));

  this.name = name;

  // mutable:
  this.terms = terms;
  this.weights = weights;
  this.optimum = null; // set when optimized
};

// If weights is a single number, you can omit the weight argument.
// Adds a term.  If weight is 0, addTerm may skip it.
CS.Solver.Step.prototype.addTerm = function (term, weight) {
  if (weight == null) {
    if (typeof this.weights !== 'number') {
      throw new Error("Must specify a weight");
    }
    weight = this.weights;
  }
  check(weight, WholeNumber);
  if (weight !== 0) {
    this.terms.push(term);
    if (typeof this.weights === 'number') {
      if (weight !== this.weights) {
        throw new Error("Can't specify a different weight now: " +
                        weight + " != " + this.weights);
      }
    } else {
      this.weights.push(weight);
    }
  }
};

var DEBUG = false;

// Call as one of:
// * minimize(step, options)
// * minimize([step1, step2, ...], options)
// * minimize(stepName, costTerms, costWeights, options)
CS.Solver.prototype.minimize = function (step, options) {
  var self = this;

  if (_.isArray(step)) {
    // minimize([steps...], options)
    _.each(step, function (st) {
      self.minimize(st, options);
    });
    return;
  }

  if (typeof step === 'string') {
    // minimize(stepName, costTerms, costWeights, options)
    var stepName_ = arguments[0];
    var costTerms_ = arguments[1];
    var costWeights_ = arguments[2];
    var options_ = arguments[3];
    if (costWeights_ && typeof costWeights_ === 'object' &&
        ! _.isArray(costWeights_)) {
      options_ = costWeights_;
      costWeights_ = null;
    }
    var theStep = new CS.Solver.Step(
      stepName_, costTerms_, (costWeights_ == null ? 1 : costWeights_));
    self.minimize(theStep, options_);
    return;
  }

  // minimize(step, options);

  self.Profile.time("minimize " + step.name, function () {

    var logic = self.logic;

    self.steps.push(step);
    self.stepsByName[step.name] = step;

    if (DEBUG) {
      console.log("--- MINIMIZING " + step.name);
    }

    var costWeights = step.weights;
    var costTerms = step.terms;

    var optimized = groupMutuallyExclusiveTerms(costTerms, costWeights);

    self.setSolution(logic.minimize(
      self.solution, optimized.costTerms, optimized.costWeights, {
        progress: function (status, cost) {
          if (self.options.nudge) {
            self.options.nudge();
          }
          if (DEBUG) {
            if (status === 'improving') {
              console.log(cost + " ... trying to improve ...");
            } else if (status === 'trying') {
              console.log("... trying " + cost + " ... ");
            }
          }
        },
        strategy: (options && options.strategy)
      }));

    step.optimum = self.solution.getWeightedSum(costTerms, costWeights);
    if (DEBUG) {
      console.log(step.optimum + " is optimal");

      if (step.optimum) {
        _.each(costTerms, function (t, i) {
          var w = (typeof costWeights === 'number' ? costWeights :
                   costWeights[i]);
          if (w && self.solution.evaluate(t)) {
            console.log("    " + w + ": " + t);
          }
        });
      }
    }
  });
};

// This is a correctness-preserving performance optimization.
//
// Cost functions often have many terms where both the package name
// and the weight are the same.  For example, when optimizing major
// version, we might have `(foo 3.0.0)*2 + (foo 3.0.1)*2 ...`.  It's
// more efficient to give the solver `((foo 3.0.0) OR (foo 3.0.1) OR
// ...)*2 + ...`, because it separates the question of whether to use
// ANY `foo 3.x.x` variable from the question of which one.  Other
// constraints already enforce the fact that `foo 3.0.0` and `foo 3.0.1`
// are mutually exclusive variables.  We can use that fact to "relax"
// that relationship for the purposes of the weighted sum.
//
// Note that shuffling up the order of terms unnecessarily seems to
// impact performance, so it's significant that we group by package
// first, then weight, rather than vice versa.
var groupMutuallyExclusiveTerms = function (costTerms, costWeights) {
  // Return a key for a term, such that terms with the same key are
  // guaranteed to be mutually exclusive.  We assume each term is
  // a variable representing either a package or a package version.
  // We take a prefix of the variable name up to and including the
  // first space.  So "foo 1.0.0" becomes "foo " and "foo" stays "foo".
  var getTermKey = function (t) {
    var firstSpace = t.indexOf(' ');
    return firstSpace < 0 ? t : t.slice(0, firstSpace+1);
  };

  // costWeights, as usual, may be a number or an array
  if (typeof costWeights === 'number') {
    return {
      costTerms: _.map(_.groupBy(costTerms, getTermKey), function (group) {
        return Logic.or(group);
      }),
      costWeights: costWeights
    };
  } else if (! costTerms.length) {
    return { costTerms: costTerms, costWeights: costWeights };
  } else {
    var weightedTerms = _.zip(costWeights, costTerms);
    var newWeightedTerms = _.map(_.groupBy(weightedTerms, function (wt) {
      // construct a string from the weight and term key, for grouping
      // purposes.  since the weight comes first, there's no ambiguity
      // and the separator char could be pretty much anything.
      return wt[0] + ' ' + getTermKey(wt[1]);
    }), function (wts) {
      return [wts[0][0], Logic.or(_.pluck(wts, 1))];
    });
    return {
      costTerms: _.pluck(newWeightedTerms, 1),
      costWeights: _.pluck(newWeightedTerms, 0)
    };
  }

};

// Determine the non-zero contributions to the cost function in `step`
// based on the current solution, returning a map from term (usually
// the name of a package or package version) to positive integer cost.
CS.Solver.prototype.getStepContributions = function (step) {
  var self = this;
  var solution = self.solution;
  var contributions = {};
  var weights = step.weights;
  _.each(step.terms, function (t, i) {
    var w = (typeof weights === 'number' ? weights : weights[i]);
    if (w && self.solution.evaluate(t)) {
      contributions[t] = w;
    }
  });
  return contributions;
};

var addCostsToSteps = function (package, versions, costs, steps) {
  var pvs = _.map(versions, function (v) {
    return pvVar(package, v);
  });
  for (var j = 0; j < steps.length; j++) {
    var step = steps[j];
    var costList = costs[j];
    if (costList.length !== versions.length) {
      throw new Error("Assertion failure: Bad lengths in addCostsToSteps");
    }
    for (var i = 0; i < versions.length; i++) {
      step.addTerm(pvs[i], costList[i]);
    }
  }
};

// Get an array of "Steps" that, when minimized in order, optimizes
// the package version costs of `packages` (an array of String package
// names) according to `pricerMode`, which may be
// `CS.VersionPricer.MODE_UPDATE` or a similar mode constant.
// Wraps `VersionPricer#priceVersions`, which is tasked with calculating
// the cost of every version of every package.  This function iterates
// over `packages` and puts the result into `Step` objects.
CS.Solver.prototype.getVersionCostSteps = function (stepBaseName, packages,
                                                    pricerMode) {
  var self = this;
  var major = new CS.Solver.Step(stepBaseName + '_major');
  var minor = new CS.Solver.Step(stepBaseName + '_minor');
  var patch = new CS.Solver.Step(stepBaseName + '_patch');
  var rest = new CS.Solver.Step(stepBaseName + '_rest');

  self.Profile.time(
    "calculate " + stepBaseName + " version costs",
    function () {
      _.each(packages, function (p) {
        var versions = self.getVersions(p);
        var costs = self.pricer.priceVersions(versions, pricerMode);
        addCostsToSteps(p, versions, costs, [major, minor, patch, rest]);
      });
    });

  return [major, minor, patch, rest];
};

// Like `getVersionCostSteps`, but wraps
// `VersionPricer#priceVersionsWithPrevious` instead of `#priceVersions`.
// The cost function is "distance" from the previous versions passed in
// as `packageAndVersion`.  (Actually it's a complicated function of the
// previous and new version.)
CS.Solver.prototype.getVersionDistanceSteps = function (stepBaseName,
                                                        packageAndVersions,
                                                        takePatches) {
  var self = this;

  var incompat = new CS.Solver.Step(stepBaseName + '_incompat');
  var major = new CS.Solver.Step(stepBaseName + '_major');
  var minor = new CS.Solver.Step(stepBaseName + '_minor');
  var patch = new CS.Solver.Step(stepBaseName + '_patch');
  var rest = new CS.Solver.Step(stepBaseName + '_rest');

  self.Profile.time(
    "calculate " + stepBaseName + " distance costs",
    function () {
      _.each(packageAndVersions, function (pvArg) {
        var package = pvArg.package;
        var previousVersion = pvArg.version;
        var versions = self.getVersions(package);
        var costs = self.pricer.priceVersionsWithPrevious(
          versions, previousVersion, takePatches);
        addCostsToSteps(package, versions, costs,
                        [incompat, major, minor, patch, rest]);
      });
    });

  return [incompat, major, minor, patch, rest];
};

CS.Solver.prototype.currentVersionMap = function () {
  var self = this;
  var pvs = [];
  _.each(self.solution.getTrueVars(), function (x) {
    if (x.indexOf(' ') >= 0) {
      // all variables with spaces in them are PackageAndVersions
      var pv = CS.PackageAndVersion.fromString(x);
      pvs.push(pv);
    }
  });

  var versionMap = {};
  _.each(pvs, function (pv) {
    if (_.has(versionMap, pv.package)) {
      throw new Error("Assertion failure: Selected two versions of " +
                      pv.package + ", " +versionMap[pv.package] +
                      " and " + pv.version);
    }
    versionMap[pv.package] = pv.version;
  });

  return versionMap;
};

// Called to re-assign `self.solution` after a call to `self.logic.solve()`,
// `solveAssuming`, or `minimize`.
CS.Solver.prototype.setSolution = function (solution) {
  var self = this;
  self.solution = solution;
  if (! self.solution) {
    throw new Error("Unexpected unsatisfiability");
  }
  self.solution.ignoreUnknownVariables();
};

CS.Solver.prototype.getAnswer = function (options) {
  var self = this;
  return self.Profile.time("Solver#getAnswer", function () {
    return self._getAnswer(options);
  });
};

CS.Solver.prototype._getAnswer = function (options) {
  var self = this;
  var input = self.input;
  var analysis = self.analysis;
  var cache = input.catalogCache;
  var allAnswers = (options && options.allAnswers); // for tests
  var Profile = self.Profile;

  var logic;
  Profile.time("new Logic.Solver (MiniSat start-up)", function () {
    logic = self.logic = new Logic.Solver();
  });

  // require root dependencies
  Profile.time("require root dependencies", function () {
    _.each(input.dependencies, function (p) {
      logic.require(p);
    });
  });

  // generate package version variables for known, reachable packages
  Profile.time("generate package variables", function () {
    _.each(_.keys(analysis.reachablePackages), function (p) {
      if (! _.has(analysis.packagesWithNoAllowedVersions, p)) {
        var versionVars = _.map(self.getVersions(p),
                                function (v) {
                                  return pvVar(p, v);
                                });
        // At most one of ["foo 1.0.0", "foo 1.0.1", ...] is true.
        logic.require(Logic.atMostOne(versionVars));
        // The variable "foo" is true if and only if at least one of the
        // variables ["foo 1.0.0", "foo 1.0.1", ...] is true.
        logic.require(Logic.equiv(p, Logic.or(versionVars)));
      }
    });
  });

  // generate strong dependency requirements
  Profile.time("generate dependency requirements", function () {
    _.each(_.keys(analysis.reachablePackages), function (p) {
      _.each(self.getVersions(p), function (v) {
        _.each(cache.getDependencyMap(p, v), function (dep) {
          // `dep` is a CS.Dependency
          if (! dep.isWeak) {
            var p2 = dep.packageConstraint.package;
            logic.require(Logic.implies(pvVar(p, v), p2));
          }
        });
      });
    });
  });

  // generate constraints -- but technically don't enforce them, because
  // we haven't forced the conflictVars to be false
  Profile.time("generate constraints", function () {
    _.each(analysis.constraints, function (c) {
      // We logically require that EITHER a constraint is marked as a
      // conflict OR it comes from a package version that is not selected
      // OR its constraint formula must be true.
      // (The constraint formula says that if toPackage is selected,
      // then a version of it that satisfies our constraint must be true.)
      logic.require(
        Logic.or(c.conflictVar,
                 c.fromVar ? Logic.not(c.fromVar) : [],
                 self.getConstraintFormula(c.toPackage, c.vConstraint)));
    });
  });

  // Establish the invariant of self.solution being a valid solution.
  // From now on, if we add some new logical requirement to the solver
  // that isn't necessarily true of `self.solution`, we must
  // recalculate `self.solution` and pass the new value to
  // self.setSolution.  It is our job to obtain the new solution in a
  // way that ensures the solution exists and doesn't put the solver
  // in an unsatisfiable state.  There are several ways to do this:
  //
  // * Calling `logic.solve()` and immediately throwing a fatal error
  //   if there's no solution (not calling `setSolution` at all)
  // * Calling `logic.solve()` in a situation where we know we have
  //   not made the problem unsatisfiable
  // * Calling `logic.solveAssuming(...)` and checking the result, only
  //   using the solution if it exists
  // * Calling `minimize()`, which always maintains satisfiability

  Profile.time("pre-solve", function () {
    self.setSolution(logic.solve());
  });
  // There is always a solution at this point, namely,
  // select all packages (including unknown packages), select
  // any version of each known package (excluding packages with
  // "no allowed versions"), and set all conflictVars
  // to true.

  // Forbid packages with no versions allowed by top-level constraints,
  // which we didn't do earlier because we needed to establish an
  // initial solution before asking the solver if it's possible to
  // not use these packages.
  Profile.time("forbid packages with no matching versions", function () {
    _.each(analysis.packagesWithNoAllowedVersions, function (constrs, p) {
      var newSolution = logic.solveAssuming(Logic.not(p));
      if (newSolution) {
        self.setSolution(newSolution);
        logic.forbid(p);
      } else {
        self.errors.push(
          'No version of ' + p + ' satisfies all constraints: ' +
            _.map(constrs, function (constr) {
              return '@' + constr.constraintString;
            }).join(', '));
      }
    });
    self.throwAnyErrors();
  });

  // try not to use any unknown packages.  If the minimum is greater
  // than 0, we'll throw an error later, after we apply the constraints
  // and the cost function, so that we can explain the problem to the
  // user in a convincing way.
  self.minimize('unknown_packages', _.keys(analysis.unknownPackages));

  // try not to set the conflictVar on any constraint.  If the minimum
  // is greater than 0, we'll throw an error later, after we've run the
  // cost function, so we can show a better error.
  // If there are conflicts, this minimization can be time-consuming
  // (several seconds or more).  The strategy 'bottom-up' helps by
  // looking for solutions with few conflicts first.
  self.minimize('conflicts', _.pluck(analysis.constraints, 'conflictVar'),
                { strategy: 'bottom-up' });

  // Try not to use "unanticipated" prerelease versions
  self.minimize('unanticipated_prereleases',
                analysis.unanticipatedPrereleases);

  var previousRootSteps = self.getVersionDistanceSteps(
    'previous_root', analysis.previousRootDepVersions);
  // the "previous_root_incompat" step
  var previousRootIncompat = previousRootSteps[0];
  // the "previous_root_major", "previous_root_minor", etc. steps
  var previousRootVersionParts = previousRootSteps.slice(1);

  var toUpdate = _.filter(input.upgrade, function (p) {
    return analysis.reachablePackages[p] === true;
  });

  // make sure packages that are being updated can still count as
  // a previous_root for the purposes of previous_root_incompat
  Profile.time("add terms to previous_root_incompat", function () {
    _.each(toUpdate, function (p) {
      if (input.isRootDependency(p) && input.isInPreviousSolution(p)) {
        var parts = self.pricer.partitionVersions(
          self.getVersions(p), input.previousSolution[p]);
        _.each(parts.older.concat(parts.higherMajor), function (v) {
          previousRootIncompat.addTerm(pvVar(p, v), 1);
        });
      }
    });
  });

  if (! input.allowIncompatibleUpdate) {
    // Enforce that we don't make breaking changes to your root dependencies,
    // unless you pass --allow-incompatible-update.  It will actually be enforced
    // farther down, but for now, we want to apply this constraint before handling
    // updates.
    self.minimize(previousRootIncompat);
  }

  self.minimize(self.getVersionCostSteps(
    'update', toUpdate, CS.VersionPricer.MODE_UPDATE));

  if (input.allowIncompatibleUpdate) {
    // If you pass `--allow-incompatible-update`, we will still try to minimize
    // version changes to root deps that break compatibility, but with a lower
    // priority than taking as-new-as-possible versions for `meteor update`.
    self.minimize(previousRootIncompat);
  }

  self.minimize(previousRootVersionParts);

  var otherPrevious = _.filter(_.map(input.previousSolution, function (v, p) {
    return new CS.PackageAndVersion(p, v);
  }), function (pv) {
    var p = pv.package;
    return analysis.reachablePackages[p] === true &&
      ! input.isRootDependency(p);
  });

  self.minimize(self.getVersionDistanceSteps(
    'previous_indirect', otherPrevious,
    input.upgradeIndirectDepPatchVersions));

  var newRootDeps = _.filter(input.dependencies, function (p) {
    return ! input.isInPreviousSolution(p);
  });

  self.minimize(self.getVersionCostSteps(
    'new_root', newRootDeps, CS.VersionPricer.MODE_UPDATE));

  // Lock down versions of all root, previous, and updating packages that
  // are currently selected.  The reason to do this is to save the solver
  // a bunch of work (i.e. improve performance) by not asking it to
  // optimize the "unimportant" packages while also twiddling the versions
  // of the "important" packages, which would just multiply the search space.
  //
  // The important packages are root deps, packages in the previous solution,
  // and packages being upgraded.  At this point, we either have unique
  // versions for them, or else there is some kind of trade-off, like a
  // situation where raising the version of one package and lowering the
  // version of another produces the same cost -- a tie between two solutions.
  // If we have a tie, it probably won't be broken by the unimportant
  // packages, so we'll end up going with whatever we picked anyway.  (Note
  // that we have already taken the unimportant packages into account in that
  // we are only considering solutions where SOME versions can be chosen for
  // them.)  Even if optimizing the unimportant packages (coming up next)
  // was able to break a tie in the important packages, we care so little
  // about the versions of the unimportant packages that it's a very weak
  // signal.  In other words, the user might be better off with some tie-breaker
  // that looks only at the important packages anyway.
  Profile.time("lock down important versions", function () {
    _.each(self.currentVersionMap(), function (v, package) {
      if (input.isRootDependency(package) ||
          input.isInPreviousSolution(package) ||
          input.isUpgrading(package)) {
        logic.require(Logic.implies(package, pvVar(package, v)));
      }
    });
  });

  // new, indirect packages are the lowest priority
  var otherPackages = [];
  _.each(_.keys(analysis.reachablePackages), function (p) {
    if (! (input.isRootDependency(p) ||
           input.isInPreviousSolution(p) ||
           input.isUpgrading(p))) {
      otherPackages.push(p);
    }
  });

  self.minimize(self.getVersionCostSteps(
    'new_indirect', otherPackages,
    CS.VersionPricer.MODE_GRAVITY_WITH_PATCHES));

  self.minimize('total_packages', _.keys(analysis.reachablePackages));

  // throw errors about unknown packages
  if (self.stepsByName['unknown_packages'].optimum > 0) {
    Profile.time("generate error for unknown packages", function () {
      var unknownPackages = _.keys(analysis.unknownPackages);
      var unknownPackagesNeeded = _.filter(unknownPackages, function (p) {
        return self.solution.evaluate(p);
      });
      _.each(unknownPackagesNeeded, function (p) {
        var requirers = _.filter(analysis.unknownPackages[p], function (pv) {
          return self.solution.evaluate(pv);
        });
        var errorStr = 'unknown package: ' + p;
        _.each(requirers, function (pv) {
          errorStr += '\nRequired by: ' + pv;
        });
        self.errors.push(errorStr);
      });
    });
    self.throwAnyErrors();
  }

  // throw errors about conflicts
  if (self.stepsByName['conflicts'].optimum > 0) {
    self.throwConflicts();
  }

  if ((! input.allowIncompatibleUpdate) &&
      self.stepsByName['previous_root_incompat'].optimum > 0) {
    // we have some "incompatible root changes", where we needed to change a
    // version of a root dependency to a new version incompatible with the
    // original, but --allow-incompatible-update hasn't been passed in.
    // these are in the form of PackageAndVersion strings that we need.
    var incompatRootChanges = _.keys(self.getStepContributions(
      self.stepsByName['previous_root_incompat']));

    Profile.time("generate errors for incompatible root change", function () {
      var numActualErrors = 0;
      _.each(incompatRootChanges, function (pvStr) {
        var pv = CS.PackageAndVersion.fromString(pvStr);
        // exclude packages with top-level equality constraints (added by user
        // or by the tool pinning a version)
        if (! _.has(analysis.topLevelEqualityConstrainedPackages, pv.package)) {
          var prevVersion = input.previousSolution[pv.package];
          self.errors.push(
            'Potentially incompatible change required to ' +
              'top-level dependency: ' +
              pvStr + ', was ' + prevVersion + '.\n' +
              self.listConstraintsOnPackage(pv.package));
          numActualErrors++;
        }
      });
      if (numActualErrors) {
        self.errors.push(
          'To allow potentially incompatible changes to top-level ' +
            'dependencies, you must pass --allow-incompatible-update ' +
            'on the command line.');
      }
    });
    self.throwAnyErrors();
  }

  var result = {
    neededToUseUnanticipatedPrereleases: (
      self.stepsByName['unanticipated_prereleases'].optimum > 0),
    answer: Profile.time("generate version map", function () {
      return self.currentVersionMap();
    })
  };

  if (allAnswers) {
    Profile.time("generate all answers", function () {
      var allAnswersList = [result.answer];
      var nextAnswer = function () {
        var formula = self.solution.getFormula();
        var newSolution = logic.solveAssuming(Logic.not(formula));
        if (newSolution) {
          self.setSolution(newSolution);
          logic.forbid(formula);
        }
        return newSolution;
      };
      while (nextAnswer()) {
        allAnswersList.push(self.currentVersionMap());
      }
      result.allAnswers = allAnswersList;
    });
  };

  return result;
};

// Get a list of package-version variables that satisfy a given constraint.
var getOkVersions = function (toPackage, vConstraint, targetVersions) {
  return _.compact(_.map(targetVersions, function (v) {
    if (CS.isConstraintSatisfied(toPackage, vConstraint, v)) {
      return pvVar(toPackage, v);
    } else {
      return null;
    }
  }));
};

// The CS.Solver constructor turns this into a memoized method.
// Memoizing the Formula object reduces clause generation a lot.
var _getConstraintFormula = function (toPackage, vConstraint) {
  var self = this;

  var targetVersions = self.getVersions(toPackage);
  var okVersions = getOkVersions(toPackage, vConstraint, targetVersions);

  if (okVersions.length === targetVersions.length) {
    return Logic.TRUE;
  } else {
    return Logic.or(Logic.not(toPackage), okVersions);
  }
};

CS.Solver.prototype.listConstraintsOnPackage = function (package) {
  var self = this;
  var constraints = self.analysis.constraints;

  var result = 'Constraints on package "' + package + '":';

  _.each(constraints, function (c) {
    if (c.toPackage === package) {
      var paths;
      if (c.fromVar) {
        paths = self.getPathsToPackageVersion(
          CS.PackageAndVersion.fromString(c.fromVar));
      } else {
        paths = [['top level']];
      }
      _.each(paths, function (path) {
        result += '\n* ' + (new PV.PackageConstraint(
          package, c.vConstraint.raw)) + ' <- ' + path.join(' <- ');
      });
    }
  });

  return result;
};

CS.Solver.prototype.throwConflicts = function () {
  var self = this;

  var solution = self.solution;
  var constraints = self.analysis.constraints;

  self.Profile.time("generate error about conflicts", function () {
    _.each(constraints, function (c) {
      // c is a CS.Solver.Constraint
      if (solution.evaluate(c.conflictVar)) {
        // skipped this constraint
        var possibleVersions = self.getVersions(c.toPackage);
        var chosenVersion = _.find(possibleVersions, function (v) {
          return solution.evaluate(pvVar(c.toPackage, v));
        });
        if (! chosenVersion) {
          // this can't happen, because for a constraint to be a problem,
          // we must have chosen some version of the package it applies to!
          throw new Error("Internal error: Version not found");
        }
        var error = (
          'Conflict: Constraint ' + (new PV.PackageConstraint(
            c.toPackage, c.vConstraint)) +
            ' is not satisfied by ' + c.toPackage + ' ' + chosenVersion + '.');

        error += '\n' + self.listConstraintsOnPackage(c.toPackage);

        self.errors.push(error);
      }
    });
  });

  // always throws, never returns
  self.throwAnyErrors();

  throw new Error("Internal error: conflicts could not be explained");
};

// Takes a PackageVersion and returns an array of arrays of PackageVersions.
// If the `packageVersion` is not selected in `self.solution`, returns
// an empty array.  Otherwise, returns an array of all paths from
// root dependencies to the package, in reverse order.  In other words,
// the first element of each path is `packageVersion`,
// and the last element is the selected version of a root dependency.
//
// Ok, it isn't all paths.  Because that would be crazy (combinatorial
// explosion).  It stops at root dependencies and tries to filter out
// ones that are definitely longer than another.
CS.Solver.prototype.getPathsToPackageVersion = function (packageAndVersion) {
  check(packageAndVersion, CS.PackageAndVersion);
  var self = this;
  var input = self.input;
  var cache = input.catalogCache;
  var solution = self.solution;

  var versionMap = self.currentVersionMap();
  var hasDep = function (p1, p2) {
    // Include weak dependencies, because their constraints matter.
    return _.has(cache.getDependencyMap(p1, versionMap[p1]), p2);
  };
  var allPackages = _.keys(versionMap);

  var getPaths = function (pv, _ignorePackageSet) {
    if (! solution.evaluate(pv.toString())) {
      return [];
    }
    var package = pv.package;

    if (input.isRootDependency(package)) {
      return [[pv]];
    }

    var newIgnorePackageSet = _.clone(_ignorePackageSet);
    newIgnorePackageSet[package] = true;

    var paths = [];
    var shortestLength = null;

    _.each(allPackages, function (p) {
      if ((! _.has(newIgnorePackageSet, p)) &&
          solution.evaluate(p) &&
          hasDep(p, package)) {
        var newPV = new CS.PackageAndVersion(p, versionMap[p]);
        _.each(getPaths(newPV, newIgnorePackageSet), function (path) {
          var newPath = [pv].concat(path);
          if ((! paths.length) || newPath.length < shortestLength) {
            paths.push(newPath);
            shortestLength = newPath.length;
          }
        });
      }
    });

    return paths;
  };

  return getPaths(packageAndVersion, {});
};

CS.Solver.Constraint = function (fromVar, toPackage, vConstraint, conflictVar) {
  this.fromVar = fromVar;
  this.toPackage = toPackage;
  this.vConstraint = vConstraint;
  this.conflictVar = conflictVar;

  // this.fromVar is a return value of pvVar(p, v), or null for a
  // top-level constraint
  check(this.fromVar, Match.OneOf(String, null));
  check(this.toPackage, String); // package name
  check(this.vConstraint, PV.VersionConstraint);
  check(this.conflictVar, String);
};


root = exports ? this # export Presses globally.
root.Presses = new Mongo.Collection 'presses'

Meteor.publish 'presses'


var PV = PackageVersion;
var CS = ConstraintSolver;

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 = {
    getSortedVersionRecords: function (name) {
      var records = Versions.find({packageName: name}).fetch();
      records.sort(function (a, b) {
        return PV.compare(a.version, b.version);
      });
      return records;
    }
  };
  return new CS.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(PV.parsePackageConstraint(dep + "@" + constr));
    }
  });
  return {dependencies: dependencies, constraints: constraints};
};

var testWithResolver = function (test, resolver, f) {
  var answerToString = function (answer) {
    var pvs = _.map(answer, function (v, p) { return p + ' ' + v; });
    return pvs.sort().join('\n');
  };
  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(answerToString(resolvedDeps.answer),
               answerToString(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);
    }, 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.2",
      "jquery": "1.8.2"
    });

    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.2",
      "jquery": "1.8.2",
      "awesome-dropdown": "1.5.0",
      "dropdown": "1.2.2"
    });
  });
});

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.2",
      "jquery": "1.8.2",
      "awesome-dropdown": "1.5.0",
      "dropdown": "1.2.2"
    });
  });
});

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"],
    ["mytoplevel", "1.0.0", {"bad-1": "1.0.0", "bad-2": ""}]
  ]);
  testWithResolver(test, resolver, function (t, FAIL) {
    FAIL({ "mytoplevel": "" }, function (error) {
      return error.message.match(/indirect@2\.0\.0 is not satisfied by indirect 1\.0\.0/)
        && error.message.match(/^\* indirect@1\.0\.0 <- bad-1 1\.0\.0 <- mytoplevel 1.0.0$/m)
        && error.message.match(/^\* indirect@2\.0\.0 <- bad-2 1\.0\.0 <- mytoplevel 1.0.0$/m)
      // Lines should be unique.
        && ! error.message.match(/bad-1[^]+bad-1/)
      // only two constraints listed
        && ! error.message.match(/onstraints on package "foo":[^]+@[^]+@[^]+@/);
    });
  });

  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"}, function (error) {
      return error.message.match(/Constraints on package "foo":[^]+top level/) &&
        error.message.match(/Constraints on package "foo":[^]+bar 1.0.0/);
    });
  });

  testWithResolver(test, makeResolver([]), function (t, FAIL) {
    FAIL({foo: "1.0.0"}, /unknown package in top-level dependencies: 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"},
         /No version of foo satisfies all constraints: @1.0.0/);
  });
});

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"
    });
  });

  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"
    });

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

    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"
    });

    FAIL({"one-of-equal": "1.0.0",
          "one-of": "1.0.0",
          "indirect" : "=2.0.0"}, function (error) {
            return error.message.match(/Constraints on package "indirect":[^]+top level/) &&
              error.message.match(/Constraints on package "indirect":[^]+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.2",
      "jquery": "1.8.2",
      "sparkle": "2.1.1"
    });

    // 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.2",
      "jquery": "1.8.2"
    });

    // 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.2",
      "jquery": "1.8.2",
      "sparkle": "2.1.1"
    }, { 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.2",
      "jquery": "1.8.2"
    }, { previousSolution: {
      "sparky-forms": "1.0.0"
    }});
  });
});

Tinytest.add("constraint solver - no constraint dependency - anything", function (test) {
  var versions = defaultResolver.resolve(["sparkle"], []).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"],
    [PV.parsePackageConstraint("sparky-forms@1.1.2")]).answer;
  test.equal(versions.sparkle, "2.1.1");
});

Tinytest.add("constraint solver - input serialization", function (test) {
  var json = '{"dependencies":["sparky-forms"],"constraints":["sparky-forms@1.0.0"],"catalogCache":{"data":{"sparky-forms 1.0.0":["awesome-dropdown@=1.4.0"],"sparky-forms 1.1.2":["forms@=1.0.1","sparkle@=2.1.1"],"sparkle 1.0.0":[],"sparkle 2.1.0":["jquery@1.8.2"],"sparkle 2.1.1":["jquery@1.8.2"],"jquery 1.8.0":[],"jquery 1.8.2":[],"forms 1.0.1":["sparkle@2.1.0","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"],"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"]}}}';

  var input1 = CS.Input.fromJSONable(JSON.parse(json));

  test.equal(input1.dependencies, ["sparky-forms"]);
  test.isTrue(input1.constraints[0] instanceof PV.PackageConstraint);
  test.equal(input1.constraints.toString(), "sparky-forms@1.0.0");
  test.isTrue(input1.catalogCache instanceof CS.CatalogCache);
  test.equal(input1.upgrade, []);
  test.equal(input1.anticipatedPrereleases, {});
  test.equal(input1.previousSolution, null);
  test.equal(input1.allowIncompatibleUpdate, false);
  test.equal(input1.upgradeIndirectDepPatchVersions, false);

  var obj1 = input1.toJSONable();
  test.isFalse(_.has(obj1, 'upgrade'));
  test.isFalse(_.has(obj1, 'anticipatedPrereleases'));
  test.isFalse(_.has(obj1, 'previousSolution'));
  var input2 = CS.Input.fromJSONable(obj1);
  var obj2 = input2.toJSONable();

  test.equal(JSON.stringify(obj1), json);
  test.equal(JSON.stringify(obj2), json);

  ///// Now a different case:

  var input2 = new CS.Input(
    ['foo'], [PV.parsePackageConstraint('foo@1.0.0')],
    new CS.CatalogCache(), {
      upgrade: ['foo'],
      anticipatedPrereleases: { foo: { '1.0.0-rc.0': true } },
      previousSolution: { foo: '1.0.0' },
      allowIncompatibleUpdate: true,
      upgradeIndirectDepPatchVersions: true
    });

  var json2 = JSON.stringify(input2.toJSONable());
  var input2prime = CS.Input.fromJSONable(JSON.parse(json2));
  test.equal(input2prime.toJSONable(), {
    dependencies: ["foo"],
    constraints: ["foo@1.0.0"],
    catalogCache: { data: {} },
    upgrade: ['foo'],
    anticipatedPrereleases: { foo: { '1.0.0-rc.0': true } },
    previousSolution: { foo: '1.0.0' },
    allowIncompatibleUpdate: true,
    upgradeIndirectDepPatchVersions: true
  });
});

Tinytest.add("constraint solver - non-existent indirect package", function (test) {
  var resolver = makeResolver([
    ["foo", "1.0.0", {bar: "1.0.0"}]
  ]);
  testWithResolver(test, resolver, function (t, FAIL) {
    FAIL({ "foo": "1.0.0" }, function (error) {
      return error.message.match(/unknown package: bar/);
    });
  });
});


#!/bin/bash

# import all the environment
source $(dirname $0)/common_env.sh

adb shell sqlite3 /data/data/com.android.providers.telephony/databases/telephony.db \
    "update carriers set proxy='10.0.2.2', port='3002' where current=1"
adb shell stop
adb shell start


// nothing forces the cost (= the number of false variables)

// to be greater than 0, but MiniSat will always discover

// a sparser solution than (1,1,1,1) first.

test.isTrue(solution1.getWeightedSum(costTerms, costWeights) > 0);

var solution2 = s.minimize(solution1, costTerms, costWeights);

test.equal(solution2.getTrueVars(), ["A", "B", "C", "D"]);

var solution2 = s.minimizeWeightedSum(solution1, costTerms, costWeights);

Package.describe({
  summary: "General satisfiability solver for logic problems",
  version: '1.0.2'
});

Package.on_use(function (api) {
  api.export('Logic');
  api.use('underscore');
  api.add_files(['minisat.js',
                 'minisat_wrapper.js',
                 'types.js',
                 'logic.js',
                 'optimize.js']);
});

Package.on_test(function (api) {
  api.use('tinytest');
  api.use('logic-solver');

  // logic-solver is totally meant for the client too, but not old
  // ones like IE 8, so we have to exclude it from our automated
  // testing.  It needs a browser released in the last year (say) so
  // that Emscripten-compiled code runs reasonably.
  api.add_files('logic_tests.js', 'server');
});


# Meteor packages used by this project, one per line.
#
# 'meteor add' and 'meteor remove' will edit this file for you,
# but you can also edit it by hand.

less
coffeescript
standard-app-packages


====================================================================
For the license for Meteor itself, see LICENSE.txt in the root of
the repository.  This file contains the licenses for externally
maintained libraries.
====================================================================

----------
libuv: https://github.com/joyent/libuv
----------

libuv is part of the Node project: http://nodejs.org/
libuv may be distributed alone under Node's license:

====

Copyright Joyent, Inc. and other Node contributors. All rights reserved.
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 copies 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
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER 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.

====

This license applies to all parts of libuv that are not externally
maintained libraries.

The externally maintained libraries used by libuv are:

  - tree.h (from FreeBSD), copyright Niels Provos. Two clause BSD license.

  - ngx_queue.h (from Nginx), copyright Igor Sysoev. Two clause BSD license.

  - c-ares, copyright Daniel Stenberg and others. MIT licensed.

  - libev, located at ev/ is copyright Marc Alexander Lehmann, and
    dual-licensed under the MIT license and GPL2.

  - libeio, located at eio/ is copyright Marc Alexander Lehmann, and
    dual-licensed under the MIT license and GPL2.


var ws = Logic.weightedSum(costTerms, costWeights);

var sol2 = s.maximize(sol, costTerms, costWeights, ws);

Tinytest.add("logic-solver - weightedSum", function (test) {

keep keep keep keep keep replace keep keep keep keep keep

var sol2 = s.maximizeWeightedSum(sol, costTerms, costWeights, ws);


// A hacky way to extract the phantom runner script from the package.
if (process.env.WRITE_RUNNER_JS) {
  Npm.require('fs').writeFileSync(
    process.env.WRITE_RUNNER_JS, new Buffer(Assets.getBinary('runner.js')));
}

var url =  null;
if (Meteor.settings &&
    Meteor.settings.public &&
    Meteor.settings.public.runId &&
    Meteor.settings.public.reportTo) {
  url = Meteor.settings.public.reportTo +
      "/report/" +
      Meteor.settings.public.runId;
}

Meteor.methods({
  report: function (reports) {
    // XXX Could do a more precise validation here; reports are complex!
    check(reports, [Object]);
    if (url) {
      HTTP.post(url, {
        data: reports
      });
    }
    return null;
  }
});

// provide some notification we're started. This is to allow use
// in automated scripts with `meteor run --once` which does not
// print when the proxy is listening.
Meteor.startup(function () {
  Meteor._debug("test-in-console listening");
});


/**
 * @summary Generate an absolute URL pointing to the application. The server reads from the `ROOT_URL` environment variable to determine where it is running. This is taken care of automatically for apps deployed with `meteor deploy`, but must be provided when using `meteor build`.
 * @locus Anywhere
 * @param {String} [path] A path to append to the root URL. Do not include a leading "`/`".
 * @param {Object} [options]
 * @param {Boolean} options.secure Create an HTTPS URL.
 * @param {Boolean} options.replaceLocalhost Replace localhost with 127.0.0.1. Useful for services that don't recognize localhost as a domain name.
 * @param {String} options.rootUrl Override the default ROOT_URL from the server environment. For example: "`http://foo.example.com`"
 */
Meteor.absoluteUrl = function (path, options) {
  // path is optional
  if (!options && typeof path === 'object') {
    options = path;
    path = undefined;
  }
  // merge options with defaults
  options = _.extend({}, Meteor.absoluteUrl.defaultOptions, options || {});

  var url = options.rootUrl;
  if (!url)
    throw new Error("Must pass options.rootUrl or set ROOT_URL in the server environment");

  if (!/^http[s]?:\/\//i.test(url)) // url starts with 'http://' or 'https://'
    url = 'http://' + url; // we will later fix to https if options.secure is set

  if (!/\/$/.test(url)) // url ends with '/'
    url += '/';

  if (path)
    url += path;

  // turn http to https if secure option is set, and we're not talking
  // to localhost.
  if (options.secure &&
      /^http:/.test(url) && // url starts with 'http:'
      !/http:\/\/localhost[:\/]/.test(url) && // doesn't match localhost
      !/http:\/\/127\.0\.0\.1[:\/]/.test(url)) // or 127.0.0.1
    url = url.replace(/^http:/, 'https:');

  if (options.replaceLocalhost)
    url = url.replace(/^http:\/\/localhost([:\/].*)/, 'http://127.0.0.1$1');

  return url;
};

// allow later packages to override default options
Meteor.absoluteUrl.defaultOptions = { };
if (typeof __meteor_runtime_config__ === "object" &&
    __meteor_runtime_config__.ROOT_URL)
  Meteor.absoluteUrl.defaultOptions.rootUrl = __meteor_runtime_config__.ROOT_URL;

Meteor._relativeToSiteRootUrl = function (link) {
  if (typeof __meteor_runtime_config__ === "object" &&
      link.substr(0, 1) === "/")
    link = (__meteor_runtime_config__.ROOT_URL_PATH_PREFIX || "") + link;
  return link;
};


// All Tomorrow's Parties -- server

Meteor.publish("directory", function () {
  return Meteor.users.find({}, {fields: {emails: 1, profile: 1}});
});

Meteor.publish("parties", function () {
  return Parties.find(
    {$or: [{"public": true}, {invited: this.userId}, {owner: this.userId}]});
});


keep keep keep keep replace replace keep keep keep keep keep

// See comments on minimizeWeightedSum and maximizeWeightedSum.

var minMaxWS = function (solver, solution, costTerms, costWeights, options,

var getNonZeroWeightedTerms = function (costTerms, costWeights) {
  if (typeof costWeights === 'number') {
    return costWeights ? costTerms : [];
  } else {
    var terms = [];
    for (var i = 0; i < costTerms.length; i++) {
      if (costWeights[i]) {
        terms.push(costTerms[i]);
      }
    }
    return terms;
  }
};

// See comments on minimize and maximize.
var minMax = function (solver, solution, costTerms, costWeights, options, isMin) {
  var curSolution = solution;
  var curCost = curSolution.getWeightedSum(costTerms, costWeights);

  var optFormula = options && options.formula;
  var weightedSum = (optFormula || Logic.weightedSum(costTerms, costWeights));

  var progress = options && options.progress;
  var strategy = options && options.strategy;

  // array of terms with non-zero weights, populated on demand
  var nonZeroTerms = null;

  if (isMin && curCost > 0) {
    // try to skip straight to 0 cost, because if it works, it could
    // save us some time
    if (progress) {
      progress('trying', 0);
    }
    var zeroSolution = null;
    nonZeroTerms = getNonZeroWeightedTerms(costTerms, costWeights);
    var zeroSolution = solver.solveAssuming(Logic.not(Logic.or(nonZeroTerms)));
    if (zeroSolution) {
      curSolution = zeroSolution;
      curCost = 0;
    }
  }

  if (isMin && strategy === 'bottom-up') {
    for (var trialCost = 1; trialCost < curCost; trialCost++) {
      if (progress) {
        progress('trying', trialCost);
      }
      var costIsTrialCost = Logic.equalBits(
        weightedSum, Logic.constantBits(trialCost));
      var newSolution = solver.solveAssuming(costIsTrialCost);
      if (newSolution) {
        curSolution = newSolution;
        curCost = trialCost;
        break;
      }
    }
  } else if (strategy && strategy !== 'default') {
    throw new Error("Bad strategy: " + strategy);
  } else {
    strategy = 'default';
  }

  if (strategy === 'default') {
    // for minimization, count down from current cost. for maximization,
    // count up.
    while (isMin ? curCost > 0 : true) {
      if (progress) {
        progress('improving', curCost);
      }
      var improvement = (isMin ? Logic.lessThan : Logic.greaterThan)(
        weightedSum, Logic.constantBits(curCost));
      var newSolution = solver.solveAssuming(improvement);
      if (! newSolution) {
        break;
      }
      solver.require(improvement);
      curSolution = newSolution;
      curCost = curSolution.getWeightedSum(costTerms, costWeights);
    }
  }

  if (isMin && curCost === 0) {
    // express the requirement that the weighted sum be 0 in an efficient
    // way for the solver (all terms with non-zero weights must be 0)
    if (! nonZeroTerms) {
      nonZeroTerms = getNonZeroWeightedTerms(costTerms, costWeights);
    }
    solver.forbid(nonZeroTerms);
  } else {
    solver.require(Logic.equalBits(weightedSum, Logic.constantBits(curCost)));
  }

  if (progress) {
    progress('finished', curCost);
  }

  return curSolution;
};

// Minimize (or maximize) the dot product of costTerms and
// costWeights, and further, require (as in solver.require) that the
// value of the dot product be equal to the optimum found.  Returns a
// valid solution where this optimum is achieved.
//
// `solution` must be a current valid solution as returned from
// `solve` or `solveAssuming`.  It is used as a starting point (to
// evaluate the current cost).
//
// costWeights is an array (of same length as costTerms) or a single
// WholeNumber.
//
// if the caller passes options.formula, it should be the formula
// Logic.weightedSum(costTerms, costWeights).  The optimizer will use
// this existing formula rather than generating a new one (for
// efficiency).  The optimizer still wants to know the terms and
// weights, because it is more efficient for it to evaluate the
// current cost using them directly rather than the formula.
//
// options.progress: a function that takes two arguments, to call at
// particular times during optimization.  Called with arguments
// ('improving', cost) when about to search for a way to improve on
// `cost`, and called with arguments ('finished', cost) when the
// optimum is reached.  There's also ('trying', cost) when a cost
// is tried directly (which is usually done with 0 right off the bat).
//
// options.strategy: a string hinting how to go about the optimization.
// the default strategy (option absent or 'default') is to work down
// from the current cost for minimization or up from the current cost
// for maximization, and iteratively insist that the cost be made lower
// if possible.  For minimization, the alternate strategy 'bottom-up' is
// available, which starts at 0 and tries ever higher costs until one
// works.  All strategies first try and see if a cost of 0 is possible.

Logic.Solver.prototype.minimize = function (solution, costTerms, costWeights,
                                            options) {
  return minMax(this, solution, costTerms, costWeights, options, true);
};

Logic.Solver.prototype.maximize = function (solution, costTerms, costWeights,
                                            options) {
  return minMax(this, solution, costTerms, costWeights, options, false);
};