/**
   * Compute the Levenshtein distance between Strings stringA and stringB, respecting supplementary
   * characters (i.e., surrogate pairs). The algorithm is the two-row technique from:
   *
   * <p>https://en.wikipedia.org/wiki/Levenshtein_distance
   *
   * <p>which is derived from Hjelmqvist, Sten (26 Mar 2012), Fast, memory efficient Levenshtein
   * algorithm:
   *
   * <p>http://www.codeproject.com/Articles/13525/Fast-memory-efficient-Levenshtein-algorithm
   *
   * @param stringA the first string, must be non-null
   * @param stringB the second string, must be non-null
   * @return the Levenshtein distance between the two strings
   * @throws NullPointerException if either string is null
   */
  static int lev(String stringA, String stringB) {
    Objects.requireNonNull(stringA);
    Objects.requireNonNull(stringB);

    // handle degenerate cases
    if (stringA.equals(stringB)) return 0;

    if (stringA.length() == 0) return stringB.length();

    if (stringB.length() == 0) return stringA.length();

    // convert strings to code points, represented as int[]
    int[] s = stringA.codePoints().toArray();
    int[] t = stringB.codePoints().toArray();

    // create work vectors
    int[] v0 = new int[t.length + 1];
    int[] v1 = new int[t.length + 1];
    Arrays.setAll(v0, i -> i);

    for (int i = 0; i < s.length; i++) {
      // calculate v1 (current row distances) from the previous row v0
      // first element of v1 is A[i+1][0]
      // edit distance is delete (i+1) chars from s to match empty t
      v1[0] = i + 1;

      // use formula to fill in the rest of the row
      for (int j = 0; j < t.length; j++) {
        int cost = (s[i] == t[j]) ? 0 : 1;
        v1[j + 1] = min3(v1[j] + 1, v0[j + 1] + 1, v0[j] + cost);
      }

      // copy v1 (current row) to v0 (previous row) for next iteration
      Arrays.setAll(v0, j -> v1[j]);
    }

    return v1[t.length];
  }
 public static Byte[] toObjects(byte[] bytesPrim) {
   Byte[] bytes = new Byte[bytesPrim.length];
   Arrays.setAll(bytes, n -> bytesPrim[n]);
   return bytes;
 }