// 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;
  }
 public static boolean isValidPath(String path) {
   Path test = new Path(path);
   for (int i = 0, max = test.segmentCount(); i < max; i++) {
     if (!isValidSegment(test.segment(i))) {
       return false;
     }
   }
   return true;
 }
 public int matchingFirstSegments(Path anotherPath) {
   assert anotherPath != null;
   int anotherPathLen = anotherPath.segmentCount();
   int max = Math.min(segments.length, anotherPathLen);
   int count = 0;
   for (int i = 0; i < max; i++) {
     if (!segments[i].equals(anotherPath.segment(i))) {
       return count;
     }
     count++;
   }
   return count;
 }
 public Path makeAbsolute() {
   if (isAbsolute()) {
     return this;
   }
   Path result = new Path(segments, separators | HAS_LEADING);
   // may need canonicalizing if it has leading ".." or "." segments
   if (result.segmentCount() > 0) {
     String first = result.segment(0);
     if (first.equals("..") || first.equals(".")) { // $NON-NLS-1$ //$NON-NLS-2$
       result.canonicalize();
     }
   }
   return result;
 }
 public boolean isPrefixOf(Path anotherPath) {
   if (isEmpty() || (isRoot() && anotherPath.isAbsolute())) {
     return true;
   }
   int len = segments.length;
   if (len > anotherPath.segmentCount()) {
     return false;
   }
   for (int i = 0; i < len; i++) {
     if (!segments[i].equals(anotherPath.segment(i))) {
       return false;
     }
   }
   return true;
 }