code: @Override
    public void percolateHeads(HeadFinder hf) {
      if (isLeaf()) {
        TreeGraphNode hwn = headWordNode();
        if (hwn == null) {
          setHeadWordNode(this);
        }
      } else {
        for (Tree child : children()) {
          child.percolateHeads(hf);
        }
        TreeGraphNode head = safeCast(hf.determineHead(this,parent));
        if (head != null) {
  
          TreeGraphNode hwn = head.headWordNode();
          if (hwn == null && head.isLeaf()) { // below us is a leaf
            setHeadWordNode(head);
          } else {
            setHeadWordNode(hwn);
          }
  
          TreeGraphNode htn = head.headTagNode();
          if (htn == null && head.isLeaf()) { // below us is a leaf
            setHeadTagNode(this);
          } else {
            setHeadTagNode(htn);
          }
  
        } else {
          System.err.println("Head is null: " + this);
        }
      }
    }
docs: Uses the specified {@link HeadFinder <code>HeadFinder</code>}
  to determine the heads for this node and all its descendants,
  and to store references to the head word node and head tag node
  in this node's {@link CyclicCoreLabel <code>CyclicCoreLabel</code>} and the
  <code>CyclicCoreLabel</code>s of all its descendants.<p>
  <p/>
  Note that, in contrast to {@link Tree#percolateHeads
  <code>Tree.percolateHeads()</code>}, which assumes {@link
  edu.stanford.nlp.ling.CategoryWordTag
  <code>CategoryWordTag</code>} labels and therefore stores head
  words and head tags merely as <code>String</code>s, this
  method stores references to the actual nodes.  This mitigates
  potential problems in sentences which contain the same word
  more than once.
  
  @param hf The headfinding algorithm to use