private void evaluateAll(
     String pluginName,
     Features features,
     Set<String> discovered,
     BooleanTerm term,
     ModuleDeps results,
     String comment) {
   if (feature != null && discovered != null) {
     discovered.add(feature);
   }
   if (feature == null) {
     if (nodeName != null && nodeName.length() > 0) {
       results.add(nodeName, new ModuleDepInfo(pluginName, term, comment, true));
     }
   } else if (!features.contains(feature)) {
     BooleanTerm newTerm = term.andWith(new BooleanTerm(new BooleanVar(feature, true)));
     trueNode.evaluateAll(pluginName, features, discovered, newTerm, results, comment);
     newTerm = term.andWith(new BooleanTerm(new BooleanVar(feature, false)));
     falseNode.evaluateAll(pluginName, features, discovered, newTerm, results, comment);
   } else {
     if (features.isFeature(feature)) {
       trueNode.evaluateAll(pluginName, features, discovered, term, results, comment);
     } else {
       falseNode.evaluateAll(pluginName, features, discovered, term, results, comment);
     }
   }
 }
 /**
  * Evaluate the has plugin for the given set of features.
  *
  * @param features The features passed to the aggregator.
  * @param discovered A map in which all features encountered in the evaluation will be placed.
  *     This will not necessarily contain all features in the dependency expression. Only the ones
  *     in the evaluation chain will be included.
  * @param coerceUndefinedToFalse If true, then a feature not being defined will be treated the
  *     same as if the feature were defined with a value of false.
  * @return The evaluated resource based on provided features. If a lack of features prevents us
  *     from being able to determine the resource, then null is returned. If the required features
  *     are provided but the evaluation results in no module name, then the empty string is
  *     returned.
  */
 public String evaluate(
     Features features, Set<String> discovered, boolean coerceUndefinedToFalse) {
   if (feature != null && discovered != null) {
     discovered.add(feature);
   }
   if (feature == null) {
     return nodeName;
   } else if (!coerceUndefinedToFalse && !features.contains(feature)) {
     return null;
   } else {
     if (features.isFeature(feature)) {
       return trueNode.evaluate(features, discovered, coerceUndefinedToFalse);
     } else {
       return falseNode.evaluate(features, discovered, coerceUndefinedToFalse);
     }
   }
 }
 /**
  * Recursively resolves the current node with the specified features. Any conditionals for
  * features contained in <code>features</code> will be replaced with the result of the evaluation.
  *
  * @param features The features passed to the aggregator.
  * @param discovered A map in which all features encountered in the evaluation will be placed.
  *     This will not necessarily contain all features in the dependency expression. Only the ones
  *     in the evaluation chain will be included.
  * @param coerceUndefinedToFalse If true, then a feature not being defined will be treated the
  *     same as if the feature were defined with a value of false.
  * @return this node
  */
 public HasNode resolve(
     Features features, Set<String> discovered, boolean coerceUndefinedToFalse) {
   if (feature != null && discovered != null) {
     discovered.add(feature);
   }
   if (feature != null && (features.contains(feature) || coerceUndefinedToFalse)) {
     replaceWith(features.isFeature(feature) ? trueNode : falseNode);
     resolve(features, discovered, coerceUndefinedToFalse);
   }
   if (trueNode != null) {
     trueNode.resolve(features, discovered, coerceUndefinedToFalse);
   }
   if (falseNode != null) {
     falseNode.resolve(features, discovered, coerceUndefinedToFalse);
   }
   return this;
 }