@Override
 void pushNotsDown() {
   if (!bool) { // ONLY push down if this is a "not"
     bool = true;
     switch (conjunction) {
       case AND:
         conjunction = Conjunction.OR;
         break;
       case OR:
         conjunction = Conjunction.AND;
         break;
     }
     for (Node node : nodes) {
       node.invert();
     }
   }
   for (Node node : nodes) {
     node.pushNotsDown();
   }
 }
      @Override
      Node simplify() {
        boolean simplifyAgain;
        do {
          simplifyAgain = false;
          // first, simplify our sub-ops...
          List<Node> simplified = new ArrayList<Node>();
          for (Node node : nodes) {
            simplified.add(node.simplify());
          }
          nodes = simplified;

          // now, see if any of our subops can be trivially combined with us
          List<Node> combined = new ArrayList<Node>();
          for (Node node : nodes) {
            if (node instanceof OperatorNode) {
              OperatorNode opnode = (OperatorNode) node;
              if (opnode.conjunction == conjunction && opnode.bool) {
                simplifyAgain = true;
                for (Node child : opnode.nodes) {
                  combined.add(child);
                }
                continue;
              }
            }
            combined.add(node);
          }
          nodes = combined;
        } while (simplifyAgain);

        if (nodes.isEmpty()) {
          return null;
        } else if (nodes.size() == 1) {
          Node node = nodes.get(0);
          if (!bool) {
            node.invert();
          }
          return node;
        }
        return this;
      }