gt:                 if (tailLength == 0 || ".".equals(path)) {
context: /*******************************************************************************
   * Copyright (c) 2012-2016 Codenvy, S.A.
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of the Eclipse Public License v1.0
   * which accompanies this distribution, and is available at
   * http://www.eclipse.org/legal/epl-v10.html
   *
   * Contributors:
   *   Codenvy, S.A. - initial API and implementation
   *******************************************************************************/
  package org.eclipse.che.ide.resource;
  
  import com.google.common.annotations.Beta;
  import com.google.common.base.Objects;
  
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Collections;
  import java.util.List;
  
  import static com.google.common.base.Preconditions.checkArgument;
  import static com.google.common.base.Preconditions.checkNotNull;
  
  /**
   * Client side implementation for the resource path.
   * <p/>
   * A path is an ordered collection of string segments, separated by a
   * standard separator character, "/". A path may also have a leading
   * and/or a trailing separator.
   * <p/>
   * Note that paths are value objects; all operations on paths return
   * a new path; the path that is operated on is unscathed.
   * <p/>
   * This class is not intended to be extended by clients.
   *
   * @author Vlad Zhukovskyi
   * @since 4.0.0-RC7
   */
  @Beta
  public final class Path {
  
      /**
       * Path separator character constant "/" used in paths.
       */
      public static char SEPARATOR = '/';
  
      /**
       * Device separator character constant ":" used in paths.
       */
      public static char DEVICE_SEPARATOR = ':';
  
      /** masks for separator values */
      private static final int HAS_LEADING  = 1;
      private static final int IS_UNC       = 2;
      private static final int HAS_TRAILING = 4;
  
      private static final int ALL_SEPARATORS = HAS_LEADING | IS_UNC | HAS_TRAILING;
  
      /** Constant empty string value. */
      private static final String EMPTY_STRING = "";
  
      /** Constant value indicating no segments */
      private static final String[] NO_SEGMENTS = new String[0];
  
      /** Constant value containing the empty path with no device. */
      public static final Path EMPTY = new Path(EMPTY_STRING);
  
      /** Mask for all bits that are involved in the hash code */
      private static final int HASH_MASK = ~HAS_TRAILING;
  
      /** Constant root path string (<code>"/"</code>). */
      private static final String ROOT_STRING = "/";
  
      /** Constant value containing the root path with no device. */
      public static final Path ROOT = new Path(ROOT_STRING);
  
      /** The device id string. May be null if there is no device. */
      private String device = null;
  
      /** The path segments */
      private String[] segments;
  
      /** flags indicating separators (has leading, is UNC, has trailing) */
      private int separators;
  
      /**
       * Constructs a new path from the given string path.
       * The string path must represent a valid file system path
       * on the local file system.
       * The path is canonicalized and double slashes are removed
       * except at the beginning. (to handle UNC paths). All forward
       * slashes ('/') are treated as segment delimiters, and any
       * segment and device delimiters for the local file system are
       * also respected.
       *
       * @param pathString
       *         the portable string path
       * @since 4.0.0-RC5
       */
      public static Path valueOf(String pathString) {
          return new Path(pathString);
      }
  
      /* (Intentionally not included in javadoc)
       * Private constructor.
       */
      private Path() {
          // not allowed
      }
  
      /**
       * Constructs a new path from the given string path.
       * The string path must represent a valid file system path
       * on the local file system.
       * The path is canonicalized and double slashes are removed
       * except at the beginning. (to handle UNC paths). All forward
       * slashes ('/') are treated as segment delimiters, and any
       * segment and device delimiters for the local file system are
       * also respected (such as colon (':') and backslash ('\') on some file systems).
       *
       * @param fullPath
       *         the string path
       * @see #isValidPath(String)
       * @since 4.0.0-RC5
       */
      public Path(String fullPath) {
          initialize(null, fullPath);
      }
  
      /**
       * Constructs a new path from the given device id and string path.
       * The given string path must be valid.
       * The path is canonicalized and double slashes are removed except
       * at the beginning (to handle UNC paths). All forward
       * slashes ('/') are treated as segment delimiters, and any
       * segment delimiters for the local file system are
       * also respected (such as backslash ('\') on some file systems).
       *
       * @param device
       *         the device id
       * @param path
       *         the string path
       * @see #isValidPath(String)
       * @see #setDevice(String)
       * @since 4.0.0-RC5
       */
      public Path(String device, String path) {
          initialize(device, path);
      }
  
      /* (Intentionally not included in javadoc)
       * Private constructor.
       */
      private Path(String device, String[] segments, int _separators) {
          // no segment validations are done for performance reasons
          this.segments = segments;
          this.device = device;
          //hash code is cached in all but the bottom three bits of the separators field
          this.separators = (computeHashCode() << 3) | (_separators & ALL_SEPARATORS);
      }
  
      /**
       * Returns a new path which is the same as this path but with
       * the given file extension added.  If this path is empty, root or has a
       * trailing separator, this path is returned.  If this path already
       * has an extension, the existing extension is left and the given
       * extension simply appended. Clients wishing to replace
       * the current extension should first remove the extension and
       * then add the desired one.
       * <p>
       * The file extension portion is defined as the string
       * following the last period (".") character in the last segment.
       * The given extension should not include a leading ".".
       * </p>
       *
       * @param extension
       *         the file extension to append
       * @return the new path
       * @see #getFileExtension()
       * @since 4.0.0-RC5
       */
      public Path addFileExtension(String extension) {
          if (isRoot() || isEmpty() || hasTrailingSeparator())
              return this;
          int len = segments.length;
          String[] newSegments = new String[len];
          System.arraycopy(segments, 0, newSegments, 0, len - 1);
          newSegments[len - 1] = segments[len - 1] + '.' + extension;
          return new Path(device, newSegments, separators);
      }
  
      /**
       * Returns a path with the same segments as this path
       * but with a trailing separator added.
       * This path must have at least one segment.
       * <p>
       * If this path already has a trailing separator,
       * this path is returned.
       * </p>
       *
       * @return the new path
       * @see #hasTrailingSeparator()
       * @see #removeTrailingSeparator()
       * @since 4.0.0-RC5
       */
      public Path addTrailingSeparator() {
          if (hasTrailingSeparator() || isRoot()) {
              return this;
          }
          if (isEmpty()) {
              return new Path(device, segments, HAS_LEADING);
          }
          return new Path(device, segments, separators | HAS_TRAILING);
      }
  
      /**
       * Returns the canonicalized path obtained from the
       * concatenation of the given path's segments to the
       * end of this path.  If the given path has a trailing
       * separator, the result will have a trailing separator.
       * The device id of this path is preserved (the one
       * of the given path is ignored). Duplicate slashes
       * are removed from the path except at the beginning
       * where the path is considered to be UNC.
       *
       * @param path
       *         the path to concatenate
       * @return the new path
       * @since 4.0.0-RC5
       */
      public Path append(Path path) {
          //optimize some easy cases
          if (path == null || path.segmentCount() == 0)
              return this;
          //these call chains look expensive, but in most cases they are no-ops
          if (this.isEmpty())
              return path.setDevice(device).makeRelative().makeUNC(isUNC());
          if (this.isRoot())
              return path.setDevice(device).makeAbsolute().makeUNC(isUNC());
  
          //concatenate the two segment arrays
          int myLen = segments.length;
          int tailLen = path.segmentCount();
          String[] newSegments = new String[myLen + tailLen];
          System.arraycopy(segments, 0, newSegments, 0, myLen);
          for (int i = 0; i < tailLen; i++) {
              newSegments[myLen + i] = path.segment(i);
          }
          //use my leading separators and the tail's trailing separator
          Path result = new Path(device, newSegments,
                                 (separators & (HAS_LEADING | IS_UNC)) | (path.hasTrailingSeparator() ? HAS_TRAILING : 0));
          String tailFirstSegment = newSegments[myLen];
          if (tailFirstSegment.equals("..") || tailFirstSegment.equals(".")) {
              result.canonicalize();
          }
          return result;
      }
  
      /**
       * Returns the canonicalized path obtained from the
       * concatenation of the given string path to the
       * end of this path. The given string path must be a valid
       * path. If it has a trailing separator,
       * the result will have a trailing separator.
       * The device id of this path is preserved (the one
       * of the given string is ignored). Duplicate slashes
       * are removed from the path except at the beginning
       * where the path is considered to be UNC.
       *
       * @param path
       *         the string path to concatenate
       * @return the new path
       * @see #isValidPath(String)
       * @since 4.0.0-RC5
       */
      public Path append(String path) {
          //optimize addition of a single segment
          if (path.indexOf(SEPARATOR) == -1 && path.indexOf("\\") == -1 && path.indexOf(DEVICE_SEPARATOR) == -1) {
              int tailLength = path.length();
              if (tailLength < 3) {
                  //some special cases
  