docs: @Override
    protected Tree determineNonTrivialHead(Tree t, Tree parent) {
      String motherCat = tlp.basicCategory(t.label().value());
  
      if (DEBUG) {
        System.err.println("At " + motherCat + ", my parent is " + parent);
      }
  
      // do VPs with auxiliary as special case
      if ((motherCat.equals("VP") || motherCat.equals("SQ") || motherCat.equals("SINV"))) {
        Tree[] kids = t.children();
        // try to find if there is an auxiliary verb
  
        if (DEBUG) {
          System.err.println("Semantic head finder: at VP");
          System.err.println("Class is " + t.getClass().getName());
          t.pennPrint(System.err);
          //System.err.println("hasVerbalAuxiliary = " + hasVerbalAuxiliary(kids, verbalAuxiliaries));
        }
  
        // looks for auxiliaries
        if (hasVerbalAuxiliary(kids, verbalAuxiliaries) || hasPassiveProgressiveAuxiliary(kids, passiveAuxiliaries)) {
          // String[] how = new String[] {"left", "VP", "ADJP", "NP"};
          // Including NP etc seems okay for copular sentences but is
          // problematic for other auxiliaries, like 'he has an answer'
          // But maybe doing ADJP is fine!
          String[] how = { "left", "VP", "ADJP" };
          Tree pti = traverseLocate(kids, how, false);
          if (DEBUG) {
            System.err.println("Determined head (case 1) for " + t.value() + " is: " + pti);
          }
          if (pti != null) {
            return pti;
          } else {
            // System.err.println("------");
            // System.err.println("SemanticHeadFinder failed to reassign head for");
            // t.pennPrint(System.err);
            // System.err.println("------");
          }
        }
  
        // looks for copular verbs
        if (hasVerbalAuxiliary(kids, copulars) && ! isExistential(t, parent) && ! isWHQ(t, parent)) {
          String[] how;
          if (motherCat.equals("SQ")) {
            how = new String[]{"right", "VP", "ADJP", "NP", "WHADJP", "WHNP"};
          } else {
            how = new String[]{"left", "VP", "ADJP", "NP", "WHADJP", "WHNP"};
          }
          Tree pti = traverseLocate(kids, how, false);
          // don't allow a temporal to become head
          if (pti != null && pti.label() != null && pti.label().value().contains("-TMP")) {
            pti = null;
          }
          // In SQ, only allow an NP to become head if there is another one to the left (then it's probably predicative)
          if (motherCat.equals("SQ") && pti != null && pti.label() != null && pti.label().value().startsWith("NP")) {
              boolean foundAnotherNp = false;
              for (Tree kid : kids) {
                if (kid == pti) {
                  break;
                } else if (kid.label() != null && kid.label().value().startsWith("NP")) {
                  foundAnotherNp = true;
                  break;
                }
              }
            if ( ! foundAnotherNp) {
              pti = null;
            }
          }
  
          if (DEBUG) {
            System.err.println("Determined head (case 2) for " + t.value() + " is: " + pti);
          }
          if (pti != null) {
            return pti;
          } else {
            if (DEBUG) {
              System.err.println("------");
              System.err.println("SemanticHeadFinder failed to reassign head for");
              t.pennPrint(System.err);
              System.err.println("------");
            }
          }
        }
      }
  
      Tree hd = super.determineNonTrivialHead(t, parent);
      
      // Heuristically repair punctuation heads
      Tree[] hdChildren = hd.children();
      if (hdChildren != null && hdChildren.length > 0 &&
          hdChildren[0].isLeaf()) {
        if (tlp.isPunctuationWord(hdChildren[0].label().value())) {
           Tree[] tChildren = t.children();
           if (DEBUG) {
             System.err.printf("head is punct: %s\n", hdChildren[0].label());
           }
           for (int i = tChildren.length - 1; i >= 0; i--) {
             if (!tlp.isPunctuationWord(tChildren[i].children()[0].label().value())) {
               hd = tChildren[i];
               if (DEBUG) {
                 System.err.printf("New head: %s %s", hd.label(), hd.children()[0].label());
               }
               break;
             }
           }
        }
      }
      
      if (DEBUG) {
        System.err.println("Determined head (case 3) for " + t.value() + " is: " + hd);
      }
      return hd;
    }