code: private static <T> Optional<T> lowestCommonAncestor(TreeDef.Parented<T> treeDef, T nodeA, T nodeB) {
  		class TreeSearcher {
  			private T tip;
  			private final Set<T> visited;
  
  			public TreeSearcher(T start) {
  				this.tip = start;
  				this.visited = new HashSet<>();
  			}
  
  			public boolean hasMore() {
  				return tip != null;
  			}
  
  			public Optional<T> march(TreeSearcher other) {
  				if (other.visited.contains(tip)) {
  					return Optional.of(tip);
  				} else {
  					visited.add(tip);
  					tip = treeDef.parentOf(tip);
  					return Optional.empty();
  				}
  			}
  		}
  
  		// make a list of a's parents (bottom of stack is 'a' itself, top of is root)
  		TreeSearcher searchA = new TreeSearcher(nodeA);
  		TreeSearcher searchB = new TreeSearcher(nodeB);
  
  		Optional<T> commonAncestor = searchB.march(searchA);
  		// so long as both searches
  		while (searchA.hasMore() && searchB.hasMore()) {
  			commonAncestor = searchA.march(searchB);
  			if (commonAncestor.isPresent()) {
  				return commonAncestor;
  			}
  			commonAncestor = searchB.march(searchA);
  			if (commonAncestor.isPresent()) {
  				return commonAncestor;
  			}
  		}
  		while (searchA.hasMore() && !commonAncestor.isPresent()) {
  			commonAncestor = searchA.march(searchB);
  		}
  		while (searchB.hasMore() && !commonAncestor.isPresent()) {
  			commonAncestor = searchB.march(searchA);
  		}
  		return commonAncestor;
  	}
docs: Returns the common parent of the two given elements.