// XXX: confusing, one may think that this modifies the path
  // being appended to (like Python's list.append()).
  public Path append(Path tail) {
    // optimize some easy cases
    if (tail == null || tail.segmentCount() == 0) {
      return this;
    }
    if (isEmpty()) {
      return tail.makeRelative();
    }
    if (isRoot()) {
      return tail.makeAbsolute();
    }

    // concatenate the two segment arrays
    int myLen = segments.length;
    int tailLen = tail.segmentCount();
    String[] newSegments = new String[myLen + tailLen];
    System.arraycopy(segments, 0, newSegments, 0, myLen);
    for (int i = 0; i < tailLen; i++) {
      newSegments[myLen + i] = tail.segment(i);
    }
    // use my leading separators and the tail's trailing separator
    Path result =
        new Path(
            newSegments,
            (separators & HAS_LEADING) | (tail.hasTrailingSeparator() ? HAS_TRAILING : 0));
    String tailFirstSegment = newSegments[myLen];
    if (tailFirstSegment.equals("..")
        || tailFirstSegment.equals(".")) { // $NON-NLS-1$ //$NON-NLS-2$
      result.canonicalize();
    }
    return result;
  }