The recursion step according to the optimal strategy.

@param it1
@param it2
@return
774632
private double computeDistUsingStrArray(InfoTree it1, InfoTree it2) {

		int postorder1 = it1.getCurrentNode();
		int postorder2 = it2.getCurrentNode();

		int stepStrategy = str[postorder1][postorder2];

		int tmpPostorder;

		int[] stepPath;
		int[] stepRelSubtrees;
		ArrayList<Integer> heavyPath;
		switch (stepStrategy) {
		case LEFT:
			tmpPostorder = postorder1;
			stepPath = it1.getPath(LEFT);
			// go along the path
			while (stepPath[postorder1] > -1) {
				stepRelSubtrees = it1.getNodeRelSubtrees(LEFT, postorder1);
				if (stepRelSubtrees != null) {
					// iterate over rel subtrees for a specific node on the path
					for (int rs : stepRelSubtrees) {
						it1.setCurrentNode(rs);
						// make the recursion
						computeDistUsingStrArray(it1, it2);
					}
				}
				postorder1 = stepPath[postorder1];
			}
			// set current node
			it1.setCurrentNode(tmpPostorder);
			it1.setSwitched(false);
			it2.setSwitched(false);
			// count the distance using a single-path function
			strStat[3]++;
			strStat[LEFT]++;
			return spfL(it1, it2);
		case RIGHT:
			tmpPostorder = postorder1;
			stepPath = it1.getPath(RIGHT);
			while (stepPath[postorder1] > -1) {
				stepRelSubtrees = it1.getNodeRelSubtrees(RIGHT, postorder1);
				if (stepRelSubtrees != null) {
					for (int rs : stepRelSubtrees) {
						it1.setCurrentNode(rs);
						computeDistUsingStrArray(it1, it2);
					}
				}
				postorder1 = stepPath[postorder1];
			}
			it1.setCurrentNode(tmpPostorder);
			it1.setSwitched(false);
			it2.setSwitched(false);
			strStat[3]++;
			strStat[RIGHT]++;
			return spfR(it1, it2);
		case HEAVY:
			tmpPostorder = postorder1;
			stepPath = it1.getPath(HEAVY);
			heavyPath = new ArrayList<Integer>();
			heavyPath.add(postorder1);
			while (stepPath[postorder1] > -1) {
				stepRelSubtrees = it1.getNodeRelSubtrees(HEAVY, postorder1);
				if (stepRelSubtrees != null) {
					for (int rs : stepRelSubtrees) {
						it1.setCurrentNode(rs);
						computeDistUsingStrArray(it1, it2);
					}
				}
				postorder1 = stepPath[postorder1];
				heavyPath.add(postorder1);
			}
			it1.setCurrentNode(tmpPostorder);
			it1.setSwitched(false);
			it2.setSwitched(false);
			strStat[3]++;
			strStat[HEAVY]++;
			return spfH(it1, it2, InfoTree.toIntArray(heavyPath));
		case REVLEFT:
			tmpPostorder = postorder2;
			stepPath = it2.getPath(LEFT);
			while (stepPath[postorder2] > -1) {
				stepRelSubtrees = it2.getNodeRelSubtrees(LEFT, postorder2);
				if (stepRelSubtrees != null) {
					for (int rs : stepRelSubtrees) {
						it2.setCurrentNode(rs);
						computeDistUsingStrArray(it1, it2);
					}
				}
				postorder2 = stepPath[postorder2];
			}
			it2.setCurrentNode(tmpPostorder);
			it1.setSwitched(true);
			it2.setSwitched(true);
			strStat[3]++;
			strStat[LEFT]++;
			return spfL(it2, it1);
		case REVRIGHT:
			tmpPostorder = postorder2;
			stepPath = it2.getPath(RIGHT);
			while (stepPath[postorder2] > -1) {
				stepRelSubtrees = it2.getNodeRelSubtrees(RIGHT, postorder2);
				if (stepRelSubtrees != null) {
					for (int rs : stepRelSubtrees) {
						it2.setCurrentNode(rs);
						computeDistUsingStrArray(it1, it2);
					}
				}
				postorder2 = stepPath[postorder2];
			}
			it2.setCurrentNode(tmpPostorder);
			it1.setSwitched(true);
			it2.setSwitched(true);
			strStat[3]++;
			strStat[RIGHT]++;
			return spfR(it2, it1);
		case REVHEAVY:
			tmpPostorder = postorder2;
			stepPath = it2.getPath(HEAVY);
			heavyPath = new ArrayList<Integer>();
			heavyPath.add(postorder2);
			while (stepPath[postorder2] > -1) {
				stepRelSubtrees = it2.getNodeRelSubtrees(HEAVY, postorder2);
				if (stepRelSubtrees != null) {
					for (int rs : stepRelSubtrees) {
						it2.setCurrentNode(rs);
						computeDistUsingStrArray(it1, it2);
					}
				}
				postorder2 = stepPath[postorder2];
				heavyPath.add(postorder2);
			}
			it2.setCurrentNode(tmpPostorder);
			it1.setSwitched(true);
			it2.setSwitched(true);
			strStat[3]++;
			strStat[HEAVY]++;
			return spfH(it2, it1, InfoTree.toIntArray(heavyPath));
		default:
			return -1;
		}
	}
1014291
public Iterator<T> iterator() {

        if (input == null)
            return null;

        if (outputIterator == null)
            outputIterator = new SinkIterator<T>(input.iterator());

        return outputIterator;
    }
1235511
public Object findFirst(Iterator it, Constraint constraint) {
		return new IteratorTemplate(it).findFirst(constraint);
	}
422910
public static <F, S> Pair<F, S> of(F first, S second) {
        if (first == null || second == null) {
            throw new IllegalArgumentException("Pair.of requires non null values.");
        }
        return new Pair<F, S>(first, second);
    }
1275261
public static function DeepEqual( $context, $iter1, $iter2 )
	{
		/**
		 * @var TreeComparer $comparer
		 */
		$comparer = new TreeComparer( $context );
		return $comparer->DeepEqualByIterator( $iter1, $iter2 );
	}
807546
private static boolean groupTogether(Object key1, Object key2, int groupLevel) {
        if (groupLevel == 0 || !(key1 instanceof List) || !(key2 instanceof List)) {
            return key1.equals(key2);
        }
        @SuppressWarnings("unchecked")
        List<Object> key1List = (List<Object>) key1;
        @SuppressWarnings("unchecked")
        List<Object> key2List = (List<Object>) key2;

        // if either key list is smaller than groupLevel and the key lists are different
        // sizes, they cannot be equal.
        if ((key1List.size() < groupLevel || key2List.size() < groupLevel) &&
                key1List.size() != key2List.size()) {
            return false;
        }

        int end = Math.min(groupLevel, Math.min(key1List.size(), key2List.size()));
        for (int i = 0; i < end; ++i) {
            if (key1List.get(i) != null && !key1List.get(i).equals(key2List.get(i)))
                return false;
            else if (key1List.get(i) == null && key2List.get(i) != null)
                return false;
        }
        return true;
    }
574608
private T nextWrapper(Iterator<T> it) {
        try {
            if (trace != null) {
                trace.add(new TraceEntry(System.nanoTime(), System.currentTimeMillis(),
                        NextOrHasNext.NEXT, debugLabels.get(it)));
            }
            return it.next();
        } catch (RuntimeException e) {
            logTrace();
            throw e;
        }
    }
338073
def first(n, it, constructor=list):
    
    return constructor(itertools.islice(it,n))
266141
public function DeepEqualByIterator( $iter1, $iter2, $elementsOnly = false )
	{
		$iter1 = $iter1->CloneInstance();
		$iter2 = $iter2->CloneInstance();

		$flag1 = $iter1->MoveNext();

		while ( $flag1 )
		{

			// Find the element in $iter2 with the same name
			$iter1Current = $iter1->getCurrent();
			$localName1 = $iter1Current->getLocalName();
			$namespace1 = $iter1Current->getNamespaceURI();
			$found = false;

			$iter2->Reset();
			$flag2 = $iter2->MoveNext();

			while ( $flag2 )
			{
				$iter2Current = $iter2->getCurrent();
				$localName2 = $iter2Current->getLocalName();
				$namespace2 = $iter2Current->getNamespaceURI();

				if ( $localName1 == $localName2 && $namespace1 == $namespace2 )
				{
					// If one of the iterators is a ForIterator and it returns an ExprIterator handle it
					if ( $iter1Current instanceof ExprIterator || $iter2Current instanceof ExprIterator )
					{
						if ( ! $iter1Current instanceof ExprIterator ) $iter1Current = $iter1;
						if ( ! $iter2Current instanceof ExprIterator ) $iter2Current = $iter2;
						$found = $this->DeepEqualByIterator( $iter1Current->CloneInstance(), $iter2Current->CloneInstance() );
					}
					else if ( $iter1Current->getIsNode() == $iter2Current->getIsNode() )
					{
						if ( $iter1Current->getIsNode() && $iter2Current->getIsNode() )
						{
							$found = $this->NodeEqual( $iter1Current, $iter2Current );
						}
						else
						{
							$found = $this->ItemEqual( $iter1Current, $iter2Current );
						}
					}
				}

				if ( $found ) break;
				$flag2 = $iter2->MoveNext();
			}

			if ( ! $found )
			{
				return false;
			}

			$flag1 = $iter1->MoveNext();

		}

		return true;
	}
540499
private double spfH(InfoTree it1, InfoTree it2, int[] heavyPath) {

		int fSize = it1.info[POST2_SIZE][it1.getCurrentNode()];
		int gSize = it2.info[POST2_SIZE][it2.getCurrentNode()];

		int gRevPre = it2.getSize() - 1 - it2.getCurrentNode();
		int gPre = it2.info[POST2_PRE][it2.getCurrentNode()];

		int gTreeSize = it2.getSize();

		int strategy;

		int jOfi;

		// Initialize arrays to their maximal possible size for current pairs of
		// subtrees.
		t = new double[gSize][gSize];
		tCOPY = new double[gSize][gSize];
		s = new double[fSize][gSize];
		q = new double[fSize];

		int vp = -1;
		int nextVp = -1;

		for (int it = heavyPath.length - 1; it >= 0; it--) {
			vp = heavyPath[it];
			strategy = it1.info[POST2_STRATEGY][vp];
			if (strategy != BOTH) {
				if (it1.info[POST2_SIZE][vp] == 1) {
					for (int i = gSize - 1; i >= 0; i--) {
						jOfi = jOfI(it2, i, gSize, gRevPre, gPre, strategy,
								gTreeSize);
						for (int j = jOfi; j >= 0; j--) {
							t[i][j] = (gSize - (i + j)) * costIns;
						}
					}
					previousStrategy = strategy;
				}
				computePeriod(it1, vp, nextVp, it2, strategy);
			} else {
				if (it1.info[POST2_SIZE][vp] == 1) {
					for (int i = gSize - 1; i >= 0; i--) {
						jOfi = jOfI(it2, i, gSize, gRevPre, gPre, LEFT,
								gTreeSize);
						for (int j = jOfi; j >= 0; j--) {
							t[i][j] = (gSize - (i + j)) * costIns;
						}
					}
					previousStrategy = LEFT;
				}
				computePeriod(it1, vp, nextVp, it2, LEFT);
				if (it1.info[POST2_SIZE][vp] == 1) {
					for (int i = gSize - 1; i >= 0; i--) {
						jOfi = jOfI(it2, i, gSize, gRevPre, gPre, RIGHT,
								gTreeSize);
						for (int j = jOfi; j >= 0; j--) {
							t[i][j] = (gSize - (i + j)) * costIns;
						}
					}
					previousStrategy = RIGHT;
				}
				computePeriod(it1, vp, nextVp, it2, RIGHT);
			}
			nextVp = vp;
		}
		return t[0][0];
	}
629067
public static final <T> T getSingle( Iterable<T> it ) {
        if( ! it.iterator().hasNext() )
            return null;

        final Iterator<T> iterator = it.iterator();
        T o = iterator.next();
        if(iterator.hasNext())
            throw new IllegalStateException("Found multiple items in iterator over " + o.getClass().getName() );

        return o;
    }
397025
public Iterator<Pair<F, S>> getIterator() {
        return new Iterator<Pair<F, S>>() {

            Iterator<F> outerIt;
            Iterator<S> innerIt;
            F curKey;

            {
                outerIt = keySet().iterator();
            }

            private boolean hasInside() {
                if (innerIt == null || !innerIt.hasNext()) {
                    if (!outerIt.hasNext()) {
                        return false;
                    }
                    curKey = outerIt.next();
                    innerIt = getCounter(curKey).keySet().iterator();
                }
                return true;
            }

            public boolean hasNext() {
                return hasInside();
            }

            public Pair<F, S> next() {
                hasInside();
                if (curKey == null)
                    throw new RuntimeException("Outer element can't be null");

                return Pair.makePair(curKey, innerIt.next());
            }

            public void remove() {
                //
            }
        };
    }
63063
public static <X, Y> Iterable<ZipPair<X, Y>> zip(final Iterable<X> iter1,
      final Iterable<Y> iter2) {
    return new ZipIterable<X, Y>(iter1, iter2);
  }
738910
public static <T> int compare(Stream<T> s1, Stream<T> s2, Comparator<T> comp)
    {
        Iterator<T> os1 = s1.iterator();
        Iterator<T> os2 = s2.iterator();
        Comparable<T> comparable = null;
        while (os1.hasNext() && os2.hasNext())
        {
            T n1 = os1.next();
            T n2 = os2.next();
            int c;
            if (comp == null)
            {
                comparable = (Comparable<T>) n1;
                c = comparable.compareTo(n2);
            }
            else
            {
                c = comp.compare(n1, n2);
            }
            if (c != 0)
            {
                return c;
            }
        }
        boolean hn1 = os1.hasNext();
        boolean hn2 = os2.hasNext();
        if (hn1 == hn2)
        {
            return 0;
        }
        if (hn1)
        {
            return 1;
        }
        else
        {
            return -1;
        }
    }
792791
public V get(K1 key1, K2 key2) {
        return JMOptional.getOptional(nestedMap, key1).map(map -> map.get(key2))
                .orElse(null);
    }
103355
public static <A, B> B reduce(final Iterable<A> iterable,
      final B initial, final Function2<A, B> func) {
    B b = initial;
    for (final A item : iterable) {
      b = func.apply(b, item);
    }
    return b;
  }
846660
public static <U> Stream<U> stream(final Iterator<U> it) {
        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.ORDERED), false);
    }