public EventPair treeReduce(EventPair lhs, EventPair rhs) {
    EventPair result;

    if (lhs.left == null) {
      result = rhs;
    } else if (rhs.left == null) {
      result = lhs;
    } else if (lhs.right == null) {
      if (rhs.right == null) {
        if (canBeMerged(lhs.left, rhs.left))
          result =
              new EventPair(mergeEvents(lhs.left, rhs.left), null, lhs.intervals, rhs.intervals);
        else result = new EventPair(lhs.left, rhs.left, lhs.intervals, rhs.intervals);
      } else {
        if (canBeMerged(lhs.left, rhs.left))
          result =
              new EventPair(
                  mergeEvents(lhs.left, rhs.left), rhs.right, lhs.intervals, rhs.intervals);
        else {
          if (rhs.left.isReportableEvent()) rhs.intervals.add(rhs.left.getLoc());
          result = new EventPair(lhs.left, rhs.right, lhs.intervals, rhs.intervals);
        }
      }
    } else if (rhs.right == null) {
      if (canBeMerged(lhs.right, rhs.left))
        result =
            new EventPair(lhs.left, mergeEvents(lhs.right, rhs.left), lhs.intervals, rhs.intervals);
      else {
        if (lhs.right.isReportableEvent()) lhs.intervals.add(lhs.right.getLoc());
        result = new EventPair(lhs.left, rhs.left, lhs.intervals, rhs.intervals);
      }
    } else {
      if (canBeMerged(lhs.right, rhs.left)) {
        Event merge = mergeEvents(lhs.right, rhs.left);
        if (merge.isReportableEvent()) lhs.intervals.add(merge.getLoc());
      } else {
        if (lhs.right.isReportableEvent()) lhs.intervals.add(lhs.right.getLoc());
        if (rhs.left.isReportableEvent()) rhs.intervals.add(rhs.left.getLoc());
      }

      result = new EventPair(lhs.left, rhs.right, lhs.intervals, rhs.intervals);
    }

    return result;
  }
 @com.google.java.contract.Requires({"left != null", "right != null"})
 private static Event mergeEvents(Event left, Event right) {
   left.merge(right);
   return left;
 }