def before_after_apply(self, before_fn, after_fn, leaf_fn=None):
        """Applies the functions to each node in a subtree using an traversal in which
        encountered twice: once right before its descendants, and once right
        after its last descendant
        """
        stack = [self]
        while stack:
            node = stack.pop()
            if node.is_leaf:
                if leaf_fn:
                    leaf_fn(node)
                while node.is_last_child_of_parent:
                    node = node._parent
                    if node:
                        after_fn(node)
                    else:
                        break
            else:
                before_fn(node)
                stack.extend([i for i in reversed(node._children)])