prioritizeAndRun = (conditions, operator) => {
      if (conditions.length === 0) {
        return Promise.resolve(true)
      }
      if (conditions.length === 1) {
        // no prioritizing is necessary, just evaluate the single condition
        // 'all' and 'any' will give the same results with a single condition so no method is necessary
        // this also covers the 'not' case which should only ever have a single condition
        return evaluateCondition(conditions[0])
      }
      const orderedSets = this.prioritizeConditions(conditions)
      let cursor = Promise.resolve(operator === 'all')
      // use for() loop over Array.forEach to support IE8 without polyfill
      for (let i = 0; i < orderedSets.length; i++) {
        const set = orderedSets[i]
        cursor = cursor.then((setResult) => {
          // rely on the short-circuiting behavior of || and && to avoid evaluating subsequent conditions
          return operator === 'any'
            ? (setResult || evaluateConditions(set, Array.prototype.some))
            : (setResult && evaluateConditions(set, Array.prototype.every))
        })
      }
      return cursor
    }
Evaluates a set of conditions based on an 'all', 'any', or 'not' operator.
  First, orders the top level conditions based on priority
  Iterates over each priority set, evaluating each condition
  If any condition results in the rule to be guaranteed truthy or falsey,
  it will short-circuit and not bother evaluating any additional rules
@param  {Condition[]} conditions - conditions to be evaluated
@param  {string('all'|'any'|'not')} operator
@return {Promise(boolean)} rule evaluation result