public static SliceNode filterTree(SliceNode oldRoot,
                                     NullableFunction<? super SliceNode, ? extends SliceNode> filter,
                                     PairProcessor<? super SliceNode, ? super List<SliceNode>> postProcessor) {
    SliceNode filtered = filter.fun(oldRoot);
    if (filtered == null) return null;

    List<SliceNode> childrenFiltered = new ArrayList<>();
    if (oldRoot.myCachedChildren != null) {
      for (SliceNode child : oldRoot.myCachedChildren) {
        SliceNode childFiltered = filterTree(child, filter,postProcessor);
        if (childFiltered != null) {
          childrenFiltered.add(childFiltered);
        }
      }
    }
    boolean success = postProcessor == null || postProcessor.process(filtered, childrenFiltered);
    if (!success) return null;
    filtered.myCachedChildren = new ArrayList<>(childrenFiltered);
    return filtered;
  }
public static SliceNode filterTree(SliceNode oldRoot,
                                     NullableFunction<? super SliceNode, ? extends SliceNode> filter,
                                     PairProcessor<? super SliceNode, ? super List<SliceNode>> postProcessor)