merge in ub-support-test-release history after reset to ub-support-test
diff --git a/AUTHORS b/AUTHORS
index 40401b7..324fd82 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -4,3 +4,4 @@
 Louis Wasserman
 Maginatics
 Roman Leventov
+David E. Wheeler
diff --git a/README b/README
index 089d02d..f6b5992 100644
--- a/README
+++ b/README
@@ -27,20 +27,20 @@
 used on the CLASSPATH of users outside your own control), you should
 not use beta APIs, unless you repackage them (e.g. using ProGuard).
 
-2. Deprecated non-beta APIs will be removed eighteen months after the
+2. Deprecated non-beta APIs will be removed two years after the
 release in which they are first deprecated. You must fix your
 references before this time. If you don't, any manner of breakage
 could result (you are not guaranteed a compilation error).
 
-3. Serialized forms of ALL objects are subject to change. Do not
-persist these and assume they can be read by a future version of the
-library.
+3. Serialized forms of ALL objects are subject to change unless noted
+otherwise. Do not persist these and assume they can be read by a
+future version of the library.
 
 4. Our classes are not designed to protect against a malicious caller.
 You should not use them for communication between trusted and
 untrusted code.
 
-5. We unit-test and benchmark the libraries using only OpenJDK 1.6 on
+5. We unit-test and benchmark the libraries using only OpenJDK 1.7 on
 Linux. Some features, especially in com.google.common.io, may not work
 correctly in other environments.
 
diff --git a/README.android b/README.android
index ed30e5d..3464386 100644
--- a/README.android
+++ b/README.android
@@ -1,12 +1,12 @@
 URL: http://code.google.com/p/guava-libraries/source/checkout
-Version: v11.0.2
+Version: v18.0
 License: Apache 2
-Description: "Guava: Google Core Libraries for Java 1.5"
+Description: "Guava: Google Core Libraries for Java 1.7"
 
-Local Modifications: 
-   Commented out use of the non-public sun.misc.Unsafe
-   from guava/src/com/google/common/primitives/UnsignedBytes.java
-   Look for "BEGIN/END android-changed" markers.
+Local Modifications:
+   Replace usages of Unsafe.compareAndSwap(Int|Long) in Striped64.java with Atomic(Integer|Long)FieldUpdater classes
+   Remove usages of Unsafe in UnsignedBytes.java and use standard Java
+   Add Closeables.closeQuietly(Closeable) back in temporarily until all usages are removed
 
 Guava-libraries are a grab bag of utility libraries published by Google as
 open source, including among other things the Google collections libraries.
diff --git a/guava-gwt/pom.xml b/guava-gwt/pom.xml
index 065909a..f98a731 100644
--- a/guava-gwt/pom.xml
+++ b/guava-gwt/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <groupId>com.google.guava</groupId>
     <artifactId>guava-parent</artifactId>
-    <version>17.0-SNAPSHOT</version>
+    <version>18.0</version>
   </parent>
   <artifactId>guava-gwt</artifactId>
   <name>Guava GWT compatible libs</name>
@@ -17,7 +17,8 @@
     This project includes GWT-friendly sources.
   </description>
   <properties>
-    <gwt.version>2.5.0-rc1</gwt.version>
+    <gwt.test.include>**/GwtTestSuite.java</gwt.test.include>
+    <gwt.version>2.6.1</gwt.version>
   </properties>
   <dependencies>
     <!-- GWT requires a library's transitive dependencies to be present when
@@ -66,7 +67,7 @@
       <scope>provided</scope>
     </dependency>
     <dependency>
-      <groupId>org.truth0</groupId>
+      <groupId>com.google.truth</groupId>
       <artifactId>truth</artifactId>
       <version>${truth.version}</version>
       <classifier>gwt</classifier>
@@ -240,7 +241,7 @@
             <configuration>
               <module>com.google.common.GuavaTests</module>
               <strict>true</strict>
-              <includes>**/GwtTestSuite.java</includes>
+              <includes>${gwt.test.include}</includes>
               <mode>htmlunit</mode>
               <testTimeOut>600</testTimeOut>
               <extraJvmArgs>-Xms3500m -Xmx3500m -Xss1024k</extraJvmArgs>
diff --git a/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Charsets.java b/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Charsets.java
index 27e6bf5..10d83ce 100644
--- a/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Charsets.java
+++ b/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Charsets.java
@@ -40,6 +40,9 @@
   /**
    * UTF-8: eight-bit UCS Transformation Format.
    *
+   * <p><b>Note for Java 7 and later:</b> this constant should be treated as deprecated; use
+   * {@link java.nio.charset.StandardCharsets#UTF_8} instead.
+   *
    */
   public static final Charset UTF_8 = Charset.forName("UTF-8");
 
diff --git a/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Enums.java b/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Enums.java
index 4927e21..f4aa4a8 100644
--- a/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Enums.java
+++ b/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Enums.java
@@ -39,61 +39,6 @@
   private Enums() {}
 
   /**
-   * Returns a {@link Function} that maps an {@link Enum} name to the associated {@code Enum}
-   * constant. The {@code Function} will return {@code null} if the {@code Enum} constant
-   * does not exist.
-   *
-   * @param enumClass the {@link Class} of the {@code Enum} declaring the constant values
-   * @deprecated Use {@link Enums#stringConverter} instead. Note that the string converter has
-   *     slightly different behavior: it throws {@link IllegalArgumentException} if the enum
-   *     constant does not exist rather than returning {@code null}. It also converts {@code null}
-   *     to {@code null} rather than throwing {@link NullPointerException}. This method is
-   *     scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static <T extends Enum<T>> Function<String, T> valueOfFunction(
-      Class<T> enumClass) {
-    return new ValueOfFunction<T>(enumClass);
-  }
-
-  /**
-   * A {@link Function} that maps an {@link Enum} name to the associated constant, or {@code null}
-   * if the constant does not exist.
-   */
-  private static final class ValueOfFunction<T extends Enum<T>>
-      implements Function<String, T>, Serializable {
-
-    private final Class<T> enumClass;
-
-    private ValueOfFunction(Class<T> enumClass) {
-      this.enumClass = checkNotNull(enumClass);
-    }
-
-    @Override
-    public T apply(String value) {
-      try {
-        return Enum.valueOf(enumClass, value);
-      } catch (IllegalArgumentException e) {
-        return null;
-      }
-    }
-
-    @Override public boolean equals(@Nullable Object obj) {
-      return obj instanceof ValueOfFunction && enumClass.equals(((ValueOfFunction) obj).enumClass);
-    }
-
-    @Override public int hashCode() {
-      return enumClass.hashCode();
-    }
-
-    @Override public String toString() {
-      return "Enums.valueOf(" + enumClass + ")";
-    }
-
-    private static final long serialVersionUID = 0;
-  }
-
-  /**
    * Returns an optional enum constant for the given type, using {@link Enum#valueOf}. If the
    * constant does not exist, {@link Optional#absent} is returned. A common use case is for parsing
    * user input or falling back to a default enum constant. For example,
@@ -161,3 +106,4 @@
     private static final long serialVersionUID = 0L;
   }
 }
+
diff --git a/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Stopwatch.java b/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Stopwatch.java
index 931a2df..07f674e 100644
--- a/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Stopwatch.java
+++ b/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Stopwatch.java
@@ -122,11 +122,10 @@
    * Creates (but does not start) a new stopwatch using {@link System#nanoTime}
    * as its time source.
    *
-   * @deprecated Use {@link Stopwatch#createUnstarted()} instead. This
-   *     constructor is scheduled to be removed in Guava release 17.0.
+   * @deprecated Use {@link Stopwatch#createUnstarted()} instead.
    */
   @Deprecated
-  public Stopwatch() {
+  Stopwatch() {
     this(Ticker.systemTicker());
   }
 
@@ -134,11 +133,10 @@
    * Creates (but does not start) a new stopwatch, using the specified time
    * source.
    *
-   * @deprecated Use {@link Stopwatch#createUnstarted(Ticker)} instead. This
-   *     constructor is scheduled to be removed in Guava release 17.0.
+   * @deprecated Use {@link Stopwatch#createUnstarted(Ticker)} instead.
    */
   @Deprecated
-  public Stopwatch(Ticker ticker) {
+  Stopwatch(Ticker ticker) {
     this.ticker = checkNotNull(ticker, "ticker");
   }
 
@@ -252,4 +250,3 @@
     }
   }
 }
-
diff --git a/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/CacheBuilder.java b/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/CacheBuilder.java
index 40753be..8e50152 100644
--- a/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/CacheBuilder.java
+++ b/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/CacheBuilder.java
@@ -16,7 +16,6 @@
 
 package com.google.common.cache;
 
-import static com.google.common.base.Objects.firstNonNull;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
@@ -24,7 +23,7 @@
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Ascii;
 import com.google.common.base.Equivalence;
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Supplier;
 import com.google.common.base.Suppliers;
 import com.google.common.base.Ticker;
@@ -244,11 +243,11 @@
   }
 
   Equivalence<Object> getKeyEquivalence() {
-    return firstNonNull(keyEquivalence, getKeyStrength().defaultEquivalence());
+    return MoreObjects.firstNonNull(keyEquivalence, getKeyStrength().defaultEquivalence());
   }
 
   Equivalence<Object> getValueEquivalence() {
-    return firstNonNull(valueEquivalence, getValueStrength().defaultEquivalence());
+    return MoreObjects.firstNonNull(valueEquivalence, getValueStrength().defaultEquivalence());
   }
 
   /**
@@ -351,7 +350,7 @@
   // Make a safe contravariant cast now so we don't have to do it over and over.
   @SuppressWarnings("unchecked")
   <K1 extends K, V1 extends V> Weigher<K1, V1> getWeigher() {
-    return (Weigher<K1, V1>) Objects.firstNonNull(weigher, OneWeigher.INSTANCE);
+    return (Weigher<K1, V1>) MoreObjects.firstNonNull(weigher, OneWeigher.INSTANCE);
   }
 
   CacheBuilder<K, V> setKeyStrength(Strength strength) {
@@ -361,7 +360,7 @@
   }
 
   Strength getKeyStrength() {
-    return firstNonNull(keyStrength, Strength.STRONG);
+    return MoreObjects.firstNonNull(keyStrength, Strength.STRONG);
   }
 
   CacheBuilder<K, V> setValueStrength(Strength strength) {
@@ -371,7 +370,7 @@
   }
 
   Strength getValueStrength() {
-    return firstNonNull(valueStrength, Strength.STRONG);
+    return MoreObjects.firstNonNull(valueStrength, Strength.STRONG);
   }
 
   /**
@@ -502,7 +501,8 @@
   // Make a safe contravariant cast now so we don't have to do it over and over.
   @SuppressWarnings("unchecked")
   <K1 extends K, V1 extends V> RemovalListener<K1, V1> getRemovalListener() {
-    return (RemovalListener<K1, V1>) Objects.firstNonNull(removalListener, NullListener.INSTANCE);
+    return (RemovalListener<K1, V1>)
+        MoreObjects.firstNonNull(removalListener, NullListener.INSTANCE);
   }
 
   /**
@@ -586,7 +586,7 @@
    */
   @Override
   public String toString() {
-    Objects.ToStringHelper s = Objects.toStringHelper(this);
+    MoreObjects.ToStringHelper s = MoreObjects.toStringHelper(this);
     if (initialCapacity != UNSET_INT) {
       s.add("initialCapacity", initialCapacity);
     }
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/FluentIterable.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/FluentIterable.java
index 7cf2a0a..641b052 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/FluentIterable.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/FluentIterable.java
@@ -21,9 +21,11 @@
 import com.google.common.annotations.Beta;
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Function;
+import com.google.common.base.Joiner;
 import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.Iterator;
@@ -109,6 +111,16 @@
   }
 
   /**
+   * Returns a fluent iterable containing {@code elements} in the specified order.
+   *
+   * @since 18.0
+   */
+  @Beta
+  public static <E> FluentIterable<E> of(E[] elements) {
+    return from(Lists.newArrayList(elements));
+  }
+
+  /**
    * Returns a string representation of this fluent iterable, with the format
    * {@code [e1, e2, ..., en]}.
    */
@@ -151,6 +163,33 @@
   }
 
   /**
+   * Returns a fluent iterable whose iterators traverse first the elements of this fluent iterable,
+   * followed by those of {@code other}. The iterators are not polled until necessary.
+   *
+   * <p>The returned iterable's {@code Iterator} supports {@code remove()} when the corresponding
+   * {@code Iterator} supports it.
+   *
+   * @since 18.0
+   */
+  @Beta
+  @CheckReturnValue
+  public final FluentIterable<E> append(Iterable<? extends E> other) {
+    return from(Iterables.concat(iterable, other));
+  }
+
+  /**
+   * Returns a fluent iterable whose iterators traverse first the elements of this fluent iterable,
+   * followed by {@code elements}.
+   *
+   * @since 18.0
+   */
+  @Beta
+  @CheckReturnValue
+  public final FluentIterable<E> append(E... elements) {
+    return from(Iterables.concat(iterable, Arrays.asList(elements)));
+  }
+
+  /**
    * Returns the elements from this fluent iterable that satisfy a predicate. The
    * resulting fluent iterable's iterator does not support {@code remove()}.
    */
@@ -331,7 +370,6 @@
    * @throws NullPointerException if any element is null
    * @since 14.0 (since 13.0 as {@code toSortedImmutableList()}).
    */
-  @Beta
   public final ImmutableList<E> toSortedList(Comparator<? super E> comparator) {
     return Ordering.from(comparator).immutableSortedCopy(iterable);
   }
@@ -413,64 +451,6 @@
   }
 
   /**
-   * Returns an {@code ImmutableList} containing all of the elements from this
-   * fluent iterable in proper sequence.
-   *
-   * @deprecated Use {@link #toList()} instead. This method is scheduled for removal in Guava 15.0.
-   */
-  @Deprecated
-  public final ImmutableList<E> toImmutableList() {
-    return toList();
-  }
-
-  /**
-   * Returns an {@code ImmutableList} containing all of the elements from this
-   * {@code FluentIterable} in the order specified by {@code comparator}.  To produce an
-   * {@code ImmutableList} sorted by its natural ordering, use
-   * {@code toSortedImmutableList(Ordering.natural())}.
-   *
-   * @param comparator the function by which to sort list elements
-   * @throws NullPointerException if any element is null
-   * @since 13.0
-   * @deprecated Use {@link #toSortedList(Comparator)} instead. This method is scheduled for removal
-   *     in Guava 15.0.
-   */
-  @Deprecated
-  public final ImmutableList<E> toSortedImmutableList(
-      Comparator<? super E> comparator) {
-    return toSortedList(comparator);
-  }
-
-  /**
-   * Returns an {@code ImmutableSet} containing all of the elements from this
-   * fluent iterable with duplicates removed.
-   *
-   * @deprecated Use {@link #toSet()} instead. This method is scheduled for removal in Guava 15.0.
-   */
-  @Deprecated
-  public final ImmutableSet<E> toImmutableSet() {
-    return toSet();
-  }
-
-  /**
-   * Returns an {@code ImmutableSortedSet} containing all of the elements from this
-   * {@code FluentIterable} in the order specified by {@code comparator}, with duplicates
-   * (determined by {@code comparator.compare(x, y) == 0}) removed. To produce an
-   * {@code ImmutableSortedSet} sorted by its natural ordering, use
-   * {@code toImmutableSortedSet(Ordering.natural())}.
-   *
-   * @param comparator the function by which to sort set elements
-   * @throws NullPointerException if any element is null
-   * @deprecated Use {@link #toSortedSet(Comparator)} instead. This method is scheduled for removal
-   *     in Guava 15.0.
-   */
-  @Deprecated
-  public final ImmutableSortedSet<E> toImmutableSortedSet(
-      Comparator<? super E> comparator) {
-    return toSortedSet(comparator);
-  }
-
-  /**
    * Copies all the elements from this fluent iterable to {@code collection}. This is equivalent to
    * calling {@code Iterables.addAll(collection, this)}.
    *
@@ -491,6 +471,17 @@
   }
 
   /**
+   * Returns a {@link String} containing all of the elements of this fluent iterable joined with
+   * {@code joiner}.
+   *
+   * @since 18.0
+   */
+  @Beta
+  public final String join(Joiner joiner) {
+    return joiner.join(this);
+  }
+
+  /**
    * Returns the element at the specified position in this fluent iterable.
    *
    * @param position position of the element to return
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/GenericMapMaker.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/GenericMapMaker.java
index 03ba0c0..6240625 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/GenericMapMaker.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/GenericMapMaker.java
@@ -37,12 +37,12 @@
  *     "Generic" equivalent; simple use {@code CacheBuilder} naturally. For general migration
  *     instructions, see the <a
  *     href="http://code.google.com/p/guava-libraries/wiki/MapMakerMigration">MapMaker Migration
- *     Guide</a>. This class is scheduled for removal in Guava 16.0.
+ *     Guide</a>.
  */
 @Beta
 @Deprecated
 @GwtCompatible(emulated = true)
-public abstract class GenericMapMaker<K0, V0> {
+abstract class GenericMapMaker<K0, V0> {
 
   // Set by MapMaker, but sits in this class to preserve the type relationship
 
@@ -83,6 +83,6 @@
    * See {@link MapMaker#makeComputingMap}.
    */
   @Deprecated
-  public abstract <K extends K0, V extends V0> ConcurrentMap<K, V> makeComputingMap(
+  abstract <K extends K0, V extends V0> ConcurrentMap<K, V> makeComputingMap(
       Function<? super K, ? extends V> computingFunction);
 }
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableCollection.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableCollection.java
index 0a5a804..d32c834 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableCollection.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableCollection.java
@@ -95,7 +95,12 @@
     return false;
   }
 
-  abstract static class Builder<E> {
+  /**
+   * GWT emulated version of {@link ImmutableCollection.Builder}.
+   */
+  public abstract static class Builder<E> {
+
+    Builder() {}
 
     public abstract Builder<E> add(E element);
 
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSetMultimap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSetMultimap.java
index fca8b2c..1a4b392 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSetMultimap.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSetMultimap.java
@@ -16,10 +16,10 @@
 
 package com.google.common.collect;
 
-import static com.google.common.base.Objects.firstNonNull;
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.MoreObjects;
 
 import java.util.Arrays;
 import java.util.Collection;
@@ -351,7 +351,7 @@
   @Override public ImmutableSet<V> get(@Nullable K key) {
     // This cast is safe as its type is known in constructor.
     ImmutableSet<V> set = (ImmutableSet<V>) map.get(key);
-    return firstNonNull(set, emptySet);
+    return MoreObjects.firstNonNull(set, emptySet);
   }
 
   private transient ImmutableSetMultimap<V, K> inverse;
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Iterators.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Iterators.java
index 15b1de0..e63a460 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Iterators.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Iterators.java
@@ -100,7 +100,12 @@
    *
    * <p>The {@link Iterable} equivalent of this method is {@link
    * ImmutableSet#of()}.
+   *
+   * @deprecated Use {@code ImmutableSet.<T>of().iterator()} instead; or for
+   *     Java 7 or later, {@link Collections#emptyIterator}. This method is
+   *     scheduled for removal in May 2016.
    */
+  @Deprecated
   public static <T> UnmodifiableIterator<T> emptyIterator() {
     return emptyListIterator();
   }
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Lists.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Lists.java
index a817fd4..74e9606 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Lists.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Lists.java
@@ -70,12 +70,16 @@
   // ArrayList
 
   /**
-   * Creates a <i>mutable</i>, empty {@code ArrayList} instance.
+   * Creates a <i>mutable</i>, empty {@code ArrayList} instance (for Java 6 and
+   * earlier).
    *
    * <p><b>Note:</b> if mutability is not required, use {@link
    * ImmutableList#of()} instead.
    *
-   * @return a new, empty {@code ArrayList}
+   * <p><b>Note for Java 7 and later:</b> this method is now unnecessary and
+   * should be treated as deprecated. Instead, use the {@code ArrayList}
+   * {@linkplain ArrayList#ArrayList() constructor} directly, taking advantage
+   * of the new <a href="http://goo.gl/iz2Wi">"diamond" syntax</a>.
    */
   @GwtCompatible(serializable = true)
   public static <E> ArrayList<E> newArrayList() {
@@ -86,12 +90,18 @@
    * Creates a <i>mutable</i> {@code ArrayList} instance containing the given
    * elements.
    *
-   * <p><b>Note:</b> if mutability is not required and the elements are
-   * non-null, use an overload of {@link ImmutableList#of()} (for varargs) or
-   * {@link ImmutableList#copyOf(Object[])} (for an array) instead.
+   * <p><b>Note:</b> essentially the only reason to use this method is when you
+   * will need to add or remove elements later. Otherwise, for non-null elements
+   * use {@link ImmutableList#of()} (for varargs) or {@link
+   * ImmutableList#copyOf(Object[])} (for an array) instead. If any elements
+   * might be null, or you need support for {@link List#set(int, Object)}, use
+   * {@link Arrays#asList}.
    *
-   * @param elements the elements that the list should contain, in order
-   * @return a new {@code ArrayList} containing those elements
+   * <p>Note that even when you do need the ability to add or remove, this method
+   * provides only a tiny bit of syntactic sugar for {@code newArrayList(}{@link
+   * Arrays#asList asList}{@code (...))}, or for creating an empty list then
+   * calling {@link Collections#addAll}. This method is not actually very useful
+   * and will likely be deprecated in the future.
    */
   @GwtCompatible(serializable = true)
   public static <E> ArrayList<E> newArrayList(E... elements) {
@@ -112,13 +122,18 @@
 
   /**
    * Creates a <i>mutable</i> {@code ArrayList} instance containing the given
-   * elements.
+   * elements; a very thin shortcut for creating an empty list then calling
+   * {@link Iterables#addAll}.
    *
    * <p><b>Note:</b> if mutability is not required and the elements are
-   * non-null, use {@link ImmutableList#copyOf(Iterator)} instead.
+   * non-null, use {@link ImmutableList#copyOf(Iterable)} instead. (Or, change
+   * {@code elements} to be a {@link FluentIterable} and call
+   * {@code elements.toList()}.)
    *
-   * @param elements the elements that the list should contain, in order
-   * @return a new {@code ArrayList} containing those elements
+   * <p><b>Note for Java 7 and later:</b> if {@code elements} is a {@link
+   * Collection}, you don't need this method. Use the {@code ArrayList}
+   * {@linkplain ArrayList#ArrayList(Collection) constructor} directly, taking
+   * advantage of the new <a href="http://goo.gl/iz2Wi">"diamond" syntax</a>.
    */
   @GwtCompatible(serializable = true)
   public static <E> ArrayList<E> newArrayList(Iterable<? extends E> elements) {
@@ -131,13 +146,11 @@
 
   /**
    * Creates a <i>mutable</i> {@code ArrayList} instance containing the given
-   * elements.
+   * elements; a very thin shortcut for creating an empty list and then calling
+   * {@link Iterators#addAll}.
    *
    * <p><b>Note:</b> if mutability is not required and the elements are
    * non-null, use {@link ImmutableList#copyOf(Iterator)} instead.
-   *
-   * @param elements the elements that the list should contain, in order
-   * @return a new {@code ArrayList} containing those elements
    */
   @GwtCompatible(serializable = true)
   public static <E> ArrayList<E> newArrayList(Iterator<? extends E> elements) {
@@ -147,17 +160,15 @@
   }
 
   /**
-   * Creates an {@code ArrayList} instance backed by an array of the
-   * <i>exact</i> size specified; equivalent to
-   * {@link ArrayList#ArrayList(int)}.
+   * Creates an {@code ArrayList} instance backed by an array with the specified
+   * initial size; simply delegates to {@link ArrayList#ArrayList(int)}.
    *
-   * <p><b>Note:</b> if you know the exact size your list will be, consider
-   * using a fixed-size list ({@link Arrays#asList(Object[])}) or an {@link
-   * ImmutableList} instead of a growable {@link ArrayList}.
-   *
-   * <p><b>Note:</b> If you have only an <i>estimate</i> of the eventual size of
-   * the list, consider padding this estimate by a suitable amount, or simply
-   * use {@link #newArrayListWithExpectedSize(int)} instead.
+   * <p><b>Note for Java 7 and later:</b> this method is now unnecessary and
+   * should be treated as deprecated. Instead, use {@code new }{@link
+   * ArrayList#ArrayList(int) ArrayList}{@code <>(int)} directly, taking
+   * advantage of the new <a href="http://goo.gl/iz2Wi">"diamond" syntax</a>.
+   * (Unlike here, there is no risk of overload ambiguity, since the {@code
+   * ArrayList} constructors very wisely did not accept varargs.)
    *
    * @param initialArraySize the exact size of the initial backing array for
    *     the returned array list ({@code ArrayList} documentation calls this
@@ -174,13 +185,14 @@
   }
 
   /**
-   * Creates an {@code ArrayList} instance sized appropriately to hold an
-   * <i>estimated</i> number of elements without resizing. A small amount of
-   * padding is added in case the estimate is low.
+   * Creates an {@code ArrayList} instance to hold {@code estimatedSize}
+   * elements, <i>plus</i> an unspecified amount of padding; you almost
+   * certainly mean to call {@link #newArrayListWithCapacity} (see that method
+   * for further advice on usage).
    *
-   * <p><b>Note:</b> If you know the <i>exact</i> number of elements the list
-   * will hold, or prefer to calculate your own amount of padding, refer to
-   * {@link #newArrayListWithCapacity(int)}.
+   * <p><b>Note:</b> This method will soon be deprecated. Even in the rare case
+   * that you do want some amount of padding, it's best if you choose your
+   * desired amount explicitly.
    *
    * @param estimatedSize an estimate of the eventual {@link List#size()} of
    *     the new list
@@ -197,12 +209,21 @@
   // LinkedList
 
   /**
-   * Creates an empty {@code LinkedList} instance.
+   * Creates a <i>mutable</i>, empty {@code LinkedList} instance (for Java 6 and
+   * earlier).
    *
-   * <p><b>Note:</b> if you need an immutable empty {@link List}, use
-   * {@link ImmutableList#of()} instead.
+   * <p><b>Note:</b> if you won't be adding any elements to the list, use {@link
+   * ImmutableList#of()} instead.
    *
-   * @return a new, empty {@code LinkedList}
+   * <p><b>Performance note:</b> {@link ArrayList} and {@link
+   * java.util.ArrayDeque} consistently outperform {@code LinkedList} except in
+   * certain rare and specific situations. Unless you have spent a lot of time
+   * benchmarking your specific needs, use one of those instead.
+   *
+   * <p><b>Note for Java 7 and later:</b> this method is now unnecessary and
+   * should be treated as deprecated. Instead, use the {@code LinkedList}
+   * {@linkplain LinkedList#LinkedList() constructor} directly, taking advantage
+   * of the new <a href="http://goo.gl/iz2Wi">"diamond" syntax</a>.
    */
   @GwtCompatible(serializable = true)
   public static <E> LinkedList<E> newLinkedList() {
@@ -210,10 +231,24 @@
   }
 
   /**
-   * Creates a {@code LinkedList} instance containing the given elements.
+   * Creates a <i>mutable</i> {@code LinkedList} instance containing the given
+   * elements; a very thin shortcut for creating an empty list then calling
+   * {@link Iterables#addAll}.
    *
-   * @param elements the elements that the list should contain, in order
-   * @return a new {@code LinkedList} containing those elements
+   * <p><b>Note:</b> if mutability is not required and the elements are
+   * non-null, use {@link ImmutableList#copyOf(Iterable)} instead. (Or, change
+   * {@code elements} to be a {@link FluentIterable} and call
+   * {@code elements.toList()}.)
+   *
+   * <p><b>Performance note:</b> {@link ArrayList} and {@link
+   * java.util.ArrayDeque} consistently outperform {@code LinkedList} except in
+   * certain rare and specific situations. Unless you have spent a lot of time
+   * benchmarking your specific needs, use one of those instead.
+   *
+   * <p><b>Note for Java 7 and later:</b> if {@code elements} is a {@link
+   * Collection}, you don't need this method. Use the {@code LinkedList}
+   * {@linkplain LinkedList#LinkedList(Collection) constructor} directly, taking
+   * advantage of the new <a href="http://goo.gl/iz2Wi">"diamond" syntax</a>.
    */
   @GwtCompatible(serializable = true)
   public static <E> LinkedList<E> newLinkedList(
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Maps.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Maps.java
index 01a0741..f5d84ae 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Maps.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Maps.java
@@ -654,7 +654,7 @@
    * Removal operations write through to the backing set.  The returned map
    * does not support put operations.
    *
-   * <p><b>Warning</b>: If the function rejects {@code null}, caution is
+   * <p><b>Warning:</b> If the function rejects {@code null}, caution is
    * required to make sure the set does not contain {@code null}, because the
    * view cannot stop {@code null} from being added to the set.
    *
@@ -690,7 +690,7 @@
    * Removal operations write through to the backing set.  The returned map does
    * not support put operations.
    *
-   * <p><b>Warning</b>: If the function rejects {@code null}, caution is
+   * <p><b>Warning:</b> If the function rejects {@code null}, caution is
    * required to make sure the set does not contain {@code null}, because the
    * view cannot stop {@code null} from being added to the set.
    *
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/TreeMultiset.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/TreeMultiset.java
index 3f6aab2..b9be3d3 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/TreeMultiset.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/TreeMultiset.java
@@ -22,7 +22,7 @@
 import static com.google.common.collect.CollectPreconditions.checkRemove;
 
 import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
 import com.google.common.primitives.Ints;
 
 import java.io.Serializable;
@@ -895,7 +895,7 @@
     @Nullable private AvlNode<E> ceiling(Comparator<? super E> comparator, E e) {
       int cmp = comparator.compare(e, elem);
       if (cmp < 0) {
-        return (left == null) ? this : Objects.firstNonNull(left.ceiling(comparator, e), this);
+        return (left == null) ? this : MoreObjects.firstNonNull(left.ceiling(comparator, e), this);
       } else if (cmp == 0) {
         return this;
       } else {
@@ -906,7 +906,7 @@
     @Nullable private AvlNode<E> floor(Comparator<? super E> comparator, E e) {
       int cmp = comparator.compare(e, elem);
       if (cmp > 0) {
-        return (right == null) ? this : Objects.firstNonNull(right.floor(comparator, e), this);
+        return (right == null) ? this : MoreObjects.firstNonNull(right.floor(comparator, e), this);
       } else if (cmp == 0) {
         return this;
       } else {
diff --git a/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/BigIntegerMath.java b/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/BigIntegerMath.java
index 75f19be..b81f76d 100644
--- a/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/BigIntegerMath.java
+++ b/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/BigIntegerMath.java
@@ -122,7 +122,7 @@
    * Returns {@code n!}, that is, the product of the first {@code n} positive
    * integers, or {@code 1} if {@code n == 0}.
    *
-   * <p><b>Warning</b>: the result takes <i>O(n log n)</i> space, so use cautiously.
+   * <p><b>Warning:</b> the result takes <i>O(n log n)</i> space, so use cautiously.
    *
    * <p>This uses an efficient binary recursive algorithm to compute the factorial
    * with balanced multiplies.  It also removes all the 2s from the intermediate
@@ -210,7 +210,7 @@
    * Returns {@code n} choose {@code k}, also known as the binomial coefficient of {@code n} and
    * {@code k}, that is, {@code n! / (k! (n - k)!)}.
    *
-   * <p><b>Warning</b>: the result can take as much as <i>O(k log n)</i> space.
+   * <p><b>Warning:</b> the result can take as much as <i>O(k log n)</i> space.
    *
    * @throws IllegalArgumentException if {@code n < 0}, {@code k < 0}, or {@code k > n}
    */
diff --git a/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/DoubleMath.java b/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/DoubleMath.java
index 9bffdff..2574322 100644
--- a/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/DoubleMath.java
+++ b/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/DoubleMath.java
@@ -69,7 +69,7 @@
 
   /**
    * Returns {@code n!}, that is, the product of the first {@code n} positive
-   * integers, {@code 1} if {@code n == 0}, or e n!}, or
+   * integers, {@code 1} if {@code n == 0}, or {@code n!}, or
    * {@link Double#POSITIVE_INFINITY} if {@code n! > Double.MAX_VALUE}.
    *
    * <p>The result is within 1 ulp of the true value.
diff --git a/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/LongMath.java b/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/LongMath.java
index 1a5be4f..a210627 100644
--- a/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/LongMath.java
+++ b/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/LongMath.java
@@ -56,7 +56,7 @@
   public static boolean isPowerOfTwo(long x) {
     return x > 0 & (x & (x - 1)) == 0;
   }
-  
+
   /**
    * Returns 1 if {@code x < y} as unsigned longs, and 0 otherwise.  Assumes that x - y fits into a
    * signed long.  The implementation is branch-free, and benchmarks suggest it is measurably
@@ -227,14 +227,14 @@
           return result;
         } else {
           int nBits = LongMath.log2(n, RoundingMode.CEILING);
-          
+
           long result = 1;
           long numerator = n--;
           long denominator = 1;
-          
+
           int numeratorBits = nBits;
           // This is an upper bound on log2(numerator, ceiling).
-          
+
           /*
            * We want to do this in long math for speed, but want to avoid overflow. We adapt the
            * technique previously used by BigIntegerMath: maintain separate numerator and
@@ -259,7 +259,7 @@
         }
     }
   }
-  
+
   /**
    * Returns (x * numerator / denominator), which is assumed to come out to an integral value.
    */
@@ -314,4 +314,3 @@
 
   private LongMath() {}
 }
-
diff --git a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Chars.java b/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Chars.java
index b4e00cf..c167373 100644
--- a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Chars.java
+++ b/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Chars.java
@@ -105,8 +105,8 @@
    * Compares the two specified {@code char} values. The sign of the value
    * returned is the same as that of {@code ((Character) a).compareTo(b)}.
    *
-   * <p><b>Note:</b> projects using JDK 7 or later should use the equivalent
-   * {@link Character#compare} method instead.
+   * <p><b>Note for Java 7 and later:</b> this method should be treated as
+   * deprecated; use the equivalent {@link Character#compare} method instead.
    *
    * @param a the first {@code char} to compare
    * @param b the second {@code char} to compare
diff --git a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Doubles.java b/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Doubles.java
index 9161389..0b7bb63 100644
--- a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Doubles.java
+++ b/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Doubles.java
@@ -387,7 +387,7 @@
     public int compare(double[] left, double[] right) {
       int minLength = Math.min(left.length, right.length);
       for (int i = 0; i < minLength; i++) {
-        int result = Doubles.compare(left[i], right[i]);
+        int result = Double.compare(left[i], right[i]);
         if (result != 0) {
           return result;
         }
diff --git a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Floats.java b/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Floats.java
index 3743d11..d669e50 100644
--- a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Floats.java
+++ b/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Floats.java
@@ -384,7 +384,7 @@
     public int compare(float[] left, float[] right) {
       int minLength = Math.min(left.length, right.length);
       for (int i = 0; i < minLength; i++) {
-        int result = Floats.compare(left[i], right[i]);
+        int result = Float.compare(left[i], right[i]);
         if (result != 0) {
           return result;
         }
diff --git a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Ints.java b/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Ints.java
index d924d09..eb14ea5 100644
--- a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Ints.java
+++ b/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Ints.java
@@ -34,6 +34,8 @@
 import java.util.List;
 import java.util.RandomAccess;
 
+import javax.annotation.CheckForNull;
+
 /**
  * Static utility methods pertaining to {@code int} primitives, that are not
  * already found in either {@link Integer} or {@link Arrays}.
@@ -112,8 +114,8 @@
    * Compares the two specified {@code int} values. The sign of the value
    * returned is the same as that of {@code ((Integer) a).compareTo(b)}.
    *
-   * <p><b>Note:</b> projects using JDK 7 or later should use the equivalent
-   * {@link Integer#compare} method instead.
+   * <p><b>Note for Java 7 and later:</b> this method should be treated as
+   * deprecated; use the equivalent {@link Integer#compare} method instead.
    *
    * @param a the first {@code int} to compare
    * @param b the second {@code int} to compare
@@ -598,4 +600,95 @@
   private static int digit(char c) {
     return (c < 128) ? asciiDigits[c] : -1;
   }
+
+  /**
+   * Parses the specified string as a signed decimal integer value. The ASCII
+   * character {@code '-'} (<code>'&#92;u002D'</code>) is recognized as the
+   * minus sign.
+   *
+   * <p>Unlike {@link Integer#parseInt(String)}, this method returns
+   * {@code null} instead of throwing an exception if parsing fails.
+   * Additionally, this method only accepts ASCII digits, and returns
+   * {@code null} if non-ASCII digits are present in the string.
+   *
+   * <p>Note that strings prefixed with ASCII {@code '+'} are rejected, even
+   * under JDK 7, despite the change to {@link Integer#parseInt(String)} for
+   * that version.
+   *
+   * @param string the string representation of an integer value
+   * @return the integer value represented by {@code string}, or {@code null} if
+   *     {@code string} has a length of zero or cannot be parsed as an integer
+   *     value
+   * @since 11.0
+   */
+  @Beta
+  @CheckForNull
+  public static Integer tryParse(String string) {
+    return tryParse(string, 10);
+  }
+
+  /**
+   * Parses the specified string as a signed integer value using the specified
+   * radix. The ASCII character {@code '-'} (<code>'&#92;u002D'</code>) is
+   * recognized as the minus sign.
+   *
+   * <p>Unlike {@link Integer#parseInt(String, int)}, this method returns
+   * {@code null} instead of throwing an exception if parsing fails.
+   * Additionally, this method only accepts ASCII digits, and returns
+   * {@code null} if non-ASCII digits are present in the string.
+   *
+   * <p>Note that strings prefixed with ASCII {@code '+'} are rejected, even
+   * under JDK 7, despite the change to {@link Integer#parseInt(String, int)}
+   * for that version.
+   *
+   * @param string the string representation of an integer value
+   * @param radix the radix to use when parsing
+   * @return the integer value represented by {@code string} using
+   *     {@code radix}, or {@code null} if {@code string} has a length of zero
+   *     or cannot be parsed as an integer value
+   * @throws IllegalArgumentException if {@code radix < Character.MIN_RADIX} or
+   *     {@code radix > Character.MAX_RADIX}
+   */
+  @CheckForNull static Integer tryParse(
+      String string, int radix) {
+    if (checkNotNull(string).isEmpty()) {
+      return null;
+    }
+    if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
+      throw new IllegalArgumentException(
+          "radix must be between MIN_RADIX and MAX_RADIX but was " + radix);
+    }
+    boolean negative = string.charAt(0) == '-';
+    int index = negative ? 1 : 0;
+    if (index == string.length()) {
+      return null;
+    }
+    int digit = digit(string.charAt(index++));
+    if (digit < 0 || digit >= radix) {
+      return null;
+    }
+    int accum = -digit;
+
+    int cap = Integer.MIN_VALUE / radix;
+
+    while (index < string.length()) {
+      digit = digit(string.charAt(index++));
+      if (digit < 0 || digit >= radix || accum < cap) {
+        return null;
+      }
+      accum *= radix;
+      if (accum < Integer.MIN_VALUE + digit) {
+        return null;
+      }
+      accum -= digit;
+    }
+
+    if (negative) {
+      return accum;
+    } else if (accum == Integer.MIN_VALUE) {
+      return null;
+    } else {
+      return -accum;
+    }
+  }
 }
diff --git a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Shorts.java b/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Shorts.java
index 1b7aafc..221255b 100644
--- a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Shorts.java
+++ b/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Shorts.java
@@ -112,8 +112,8 @@
    * Compares the two specified {@code short} values. The sign of the value
    * returned is the same as that of {@code ((Short) a).compareTo(b)}.
    *
-   * <p><b>Note:</b> projects using JDK 7 or later should use the equivalent
-   * {@link Short#compare} method instead.
+   * <p><b>Note for Java 7 and later:</b> this method should be treated as
+   * deprecated; use the equivalent {@link Short#compare} method instead.
    *
    * @param a the first {@code short} to compare
    * @param b the second {@code short} to compare
diff --git a/guava-gwt/test-super/com/google/common/base/super/com/google/common/base/EnumsTest.java b/guava-gwt/test-super/com/google/common/base/super/com/google/common/base/EnumsTest.java
index ef7ac46..c61855a 100644
--- a/guava-gwt/test-super/com/google/common/base/super/com/google/common/base/EnumsTest.java
+++ b/guava-gwt/test-super/com/google/common/base/super/com/google/common/base/EnumsTest.java
@@ -17,7 +17,6 @@
 package com.google.common.base;
 
 import com.google.common.annotations.GwtCompatible;
-import com.google.common.testing.EqualsTester;
 import com.google.common.testing.SerializableTester;
 
 import junit.framework.TestCase;
@@ -41,33 +40,6 @@
 
   private enum OtherEnum {}
 
-  public void testValueOfFunction() {
-    Function<String, TestEnum> function = Enums.valueOfFunction(TestEnum.class);
-    assertEquals(TestEnum.CHEETO, function.apply("CHEETO"));
-    assertEquals(TestEnum.HONDA, function.apply("HONDA"));
-    assertEquals(TestEnum.POODLE, function.apply("POODLE"));
-  }
-
-  public void testValueOfFunction_caseSensitive() {
-    Function<String, TestEnum> function = Enums.valueOfFunction(TestEnum.class);
-    assertNull(function.apply("cHEETO"));
-    assertNull(function.apply("Honda"));
-    assertNull(function.apply("poodlE"));
-  }
-
-  public void testValueOfFunction_nullWhenNoMatchingConstant() {
-    Function<String, TestEnum> function = Enums.valueOfFunction(TestEnum.class);
-    assertNull(function.apply("WOMBAT"));
-  }
-
-  public void testValueOfFunction_equals() {
-    new EqualsTester()
-        .addEqualityGroup(
-            Enums.valueOfFunction(TestEnum.class), Enums.valueOfFunction(TestEnum.class))
-        .addEqualityGroup(Enums.valueOfFunction(OtherEnum.class))
-        .testEquals();
-  }
-
   public void testGetIfPresent() {
     assertEquals(Optional.of(TestEnum.CHEETO), Enums.getIfPresent(TestEnum.class, "CHEETO"));
     assertEquals(Optional.of(TestEnum.HONDA), Enums.getIfPresent(TestEnum.class, "HONDA"));
diff --git a/guava-gwt/test-super/com/google/common/base/super/com/google/common/base/OptionalTest.java b/guava-gwt/test-super/com/google/common/base/super/com/google/common/base/OptionalTest.java
index 6b33a0c..6d78535 100644
--- a/guava-gwt/test-super/com/google/common/base/super/com/google/common/base/OptionalTest.java
+++ b/guava-gwt/test-super/com/google/common/base/super/com/google/common/base/OptionalTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.base;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.FluentIterable;
@@ -218,34 +218,34 @@
   public void testPresentInstances_allPresent() {
     List<Optional<String>> optionals =
         ImmutableList.of(Optional.of("a"), Optional.of("b"), Optional.of("c"));
-    ASSERT.that(Optional.presentInstances(optionals)).iteratesOverSequence("a", "b", "c");
+    assertThat(Optional.presentInstances(optionals)).iteratesAs("a", "b", "c");
   }
 
   public void testPresentInstances_allAbsent() {
     List<Optional<Object>> optionals =
         ImmutableList.of(Optional.absent(), Optional.absent());
-    ASSERT.that(Optional.presentInstances(optionals)).isEmpty();
+    assertThat(Optional.presentInstances(optionals)).isEmpty();
   }
 
   public void testPresentInstances_somePresent() {
     List<Optional<String>> optionals =
         ImmutableList.of(Optional.of("a"), Optional.<String>absent(), Optional.of("c"));
-    ASSERT.that(Optional.presentInstances(optionals)).iteratesOverSequence("a", "c");
+    assertThat(Optional.presentInstances(optionals)).iteratesAs("a", "c");
   }
 
   public void testPresentInstances_callingIteratorTwice() {
     List<Optional<String>> optionals =
         ImmutableList.of(Optional.of("a"), Optional.<String>absent(), Optional.of("c"));
     Iterable<String> onlyPresent = Optional.presentInstances(optionals);
-    ASSERT.that(onlyPresent).iteratesOverSequence("a", "c");
-    ASSERT.that(onlyPresent).iteratesOverSequence("a", "c");
+    assertThat(onlyPresent).iteratesAs("a", "c");
+    assertThat(onlyPresent).iteratesAs("a", "c");
   }
 
   public void testPresentInstances_wildcards() {
     List<Optional<? extends Number>> optionals =
         ImmutableList.<Optional<? extends Number>>of(Optional.<Double>absent(), Optional.of(2));
     Iterable<Number> onlyPresent = Optional.presentInstances(optionals);
-    ASSERT.that(onlyPresent).iteratesOverSequence(2);
+    assertThat(onlyPresent).iteratesAs(2);
   }
 
   private static Optional<Integer> getSomeOptionalInt() {
diff --git a/guava-gwt/test-super/com/google/common/base/super/com/google/common/base/SplitterTest.java b/guava-gwt/test-super/com/google/common/base/super/com/google/common/base/SplitterTest.java
index 829ce4b..aabd88d 100644
--- a/guava-gwt/test-super/com/google/common/base/super/com/google/common/base/SplitterTest.java
+++ b/guava-gwt/test-super/com/google/common/base/super/com/google/common/base/SplitterTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.base;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.ImmutableList;
@@ -48,7 +48,7 @@
   public void testCharacterSimpleSplit() {
     String simple = "a,b,c";
     Iterable<String> letters = COMMA_SPLITTER.split(simple);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c");
+    assertThat(letters).iteratesAs("a", "b", "c");
   }
 
   /**
@@ -62,7 +62,7 @@
   public void testCharacterSimpleSplitToList() {
     String simple = "a,b,c";
     List<String> letters = COMMA_SPLITTER.splitToList(simple);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c");
+    assertThat(letters).iteratesAs("a", "b", "c");
   }
 
   public void testToString() {
@@ -74,37 +74,37 @@
   public void testCharacterSimpleSplitWithNoDelimiter() {
     String simple = "a,b,c";
     Iterable<String> letters = Splitter.on('.').split(simple);
-    ASSERT.that(letters).iteratesOverSequence("a,b,c");
+    assertThat(letters).iteratesAs("a,b,c");
   }
 
   public void testCharacterSplitWithDoubleDelimiter() {
     String doubled = "a,,b,c";
     Iterable<String> letters = COMMA_SPLITTER.split(doubled);
-    ASSERT.that(letters).iteratesOverSequence("a", "", "b", "c");
+    assertThat(letters).iteratesAs("a", "", "b", "c");
   }
 
   public void testCharacterSplitWithDoubleDelimiterAndSpace() {
     String doubled = "a,, b,c";
     Iterable<String> letters = COMMA_SPLITTER.split(doubled);
-    ASSERT.that(letters).iteratesOverSequence("a", "", " b", "c");
+    assertThat(letters).iteratesAs("a", "", " b", "c");
   }
 
   public void testCharacterSplitWithTrailingDelimiter() {
     String trailing = "a,b,c,";
     Iterable<String> letters = COMMA_SPLITTER.split(trailing);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c", "");
+    assertThat(letters).iteratesAs("a", "b", "c", "");
   }
 
   public void testCharacterSplitWithLeadingDelimiter() {
     String leading = ",a,b,c";
     Iterable<String> letters = COMMA_SPLITTER.split(leading);
-    ASSERT.that(letters).iteratesOverSequence("", "a", "b", "c");
+    assertThat(letters).iteratesAs("", "a", "b", "c");
   }
 
   public void testCharacterSplitWithMulitpleLetters() {
     Iterable<String> testCharacteringMotto = Splitter.on('-').split(
         "Testing-rocks-Debugging-sucks");
-    ASSERT.that(testCharacteringMotto).iteratesOverSequence(
+    assertThat(testCharacteringMotto).iteratesAs(
         "Testing", "rocks", "Debugging", "sucks");
   }
 
@@ -112,7 +112,7 @@
     Iterable<String> testCharacteringMotto = Splitter
         .on(CharMatcher.WHITESPACE)
         .split("Testing\nrocks\tDebugging sucks");
-    ASSERT.that(testCharacteringMotto).iteratesOverSequence(
+    assertThat(testCharacteringMotto).iteratesAs(
         "Testing", "rocks", "Debugging", "sucks");
   }
 
@@ -120,40 +120,40 @@
     String doubled = "a..b.c";
     Iterable<String> letters = Splitter.on('.')
         .omitEmptyStrings().split(doubled);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c");
+    assertThat(letters).iteratesAs("a", "b", "c");
   }
 
   public void testCharacterSplitEmptyToken() {
     String emptyToken = "a. .c";
     Iterable<String> letters = Splitter.on('.').trimResults()
         .split(emptyToken);
-    ASSERT.that(letters).iteratesOverSequence("a", "", "c");
+    assertThat(letters).iteratesAs("a", "", "c");
   }
 
   public void testCharacterSplitEmptyTokenOmitEmptyStrings() {
     String emptyToken = "a. .c";
     Iterable<String> letters = Splitter.on('.')
         .omitEmptyStrings().trimResults().split(emptyToken);
-    ASSERT.that(letters).iteratesOverSequence("a", "c");
+    assertThat(letters).iteratesAs("a", "c");
   }
 
   public void testCharacterSplitOnEmptyString() {
     Iterable<String> nothing = Splitter.on('.').split("");
-    ASSERT.that(nothing).iteratesOverSequence("");
+    assertThat(nothing).iteratesAs("");
   }
 
   public void testCharacterSplitOnEmptyStringOmitEmptyStrings() {
-    ASSERT.that(Splitter.on('.').omitEmptyStrings().split("")).isEmpty();
+    assertThat(Splitter.on('.').omitEmptyStrings().split("")).isEmpty();
   }
 
   public void testCharacterSplitOnOnlyDelimiter() {
     Iterable<String> blankblank = Splitter.on('.').split(".");
-    ASSERT.that(blankblank).iteratesOverSequence("", "");
+    assertThat(blankblank).iteratesAs("", "");
   }
 
   public void testCharacterSplitOnOnlyDelimitersOmitEmptyStrings() {
     Iterable<String> empty = Splitter.on('.').omitEmptyStrings().split("...");
-    ASSERT.that(empty).isEmpty();
+    assertThat(empty).isEmpty();
   }
 
   public void testCharacterSplitWithTrim() {
@@ -162,50 +162,50 @@
     Iterable<String> family = COMMA_SPLITTER
         .trimResults(CharMatcher.anyOf("afro").or(CharMatcher.WHITESPACE))
         .split(jacksons);
-    ASSERT.that(family).iteratesOverSequence(
+    assertThat(family).iteratesAs(
         "(Marlon)", "(Michael)", "(Jackie)", "(Jemaine)", "(Tito)");
   }
 
   public void testStringSimpleSplit() {
     String simple = "a,b,c";
     Iterable<String> letters = Splitter.on(',').split(simple);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c");
+    assertThat(letters).iteratesAs("a", "b", "c");
   }
 
   public void testStringSimpleSplitWithNoDelimiter() {
     String simple = "a,b,c";
     Iterable<String> letters = Splitter.on('.').split(simple);
-    ASSERT.that(letters).iteratesOverSequence("a,b,c");
+    assertThat(letters).iteratesAs("a,b,c");
   }
 
   public void testStringSplitWithDoubleDelimiter() {
     String doubled = "a,,b,c";
     Iterable<String> letters = Splitter.on(',').split(doubled);
-    ASSERT.that(letters).iteratesOverSequence("a", "", "b", "c");
+    assertThat(letters).iteratesAs("a", "", "b", "c");
   }
 
   public void testStringSplitWithDoubleDelimiterAndSpace() {
     String doubled = "a,, b,c";
     Iterable<String> letters = Splitter.on(',').split(doubled);
-    ASSERT.that(letters).iteratesOverSequence("a", "", " b", "c");
+    assertThat(letters).iteratesAs("a", "", " b", "c");
   }
 
   public void testStringSplitWithTrailingDelimiter() {
     String trailing = "a,b,c,";
     Iterable<String> letters = Splitter.on(',').split(trailing);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c", "");
+    assertThat(letters).iteratesAs("a", "b", "c", "");
   }
 
   public void testStringSplitWithLeadingDelimiter() {
     String leading = ",a,b,c";
     Iterable<String> letters = Splitter.on(',').split(leading);
-    ASSERT.that(letters).iteratesOverSequence("", "a", "b", "c");
+    assertThat(letters).iteratesAs("", "a", "b", "c");
   }
 
   public void testStringSplitWithMultipleLetters() {
     Iterable<String> testStringingMotto = Splitter.on('-').split(
         "Testing-rocks-Debugging-sucks");
-    ASSERT.that(testStringingMotto).iteratesOverSequence(
+    assertThat(testStringingMotto).iteratesAs(
         "Testing", "rocks", "Debugging", "sucks");
   }
 
@@ -213,46 +213,46 @@
     String doubled = "a..b.c";
     Iterable<String> letters = Splitter.on('.')
         .omitEmptyStrings().split(doubled);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c");
+    assertThat(letters).iteratesAs("a", "b", "c");
   }
 
   public void testStringSplitEmptyToken() {
     String emptyToken = "a. .c";
     Iterable<String> letters = Splitter.on('.').trimResults()
         .split(emptyToken);
-    ASSERT.that(letters).iteratesOverSequence("a", "", "c");
+    assertThat(letters).iteratesAs("a", "", "c");
   }
 
   public void testStringSplitEmptyTokenOmitEmptyStrings() {
     String emptyToken = "a. .c";
     Iterable<String> letters = Splitter.on('.')
         .omitEmptyStrings().trimResults().split(emptyToken);
-    ASSERT.that(letters).iteratesOverSequence("a", "c");
+    assertThat(letters).iteratesAs("a", "c");
   }
 
   public void testStringSplitWithLongDelimiter() {
     String longDelimiter = "a, b, c";
     Iterable<String> letters = Splitter.on(", ").split(longDelimiter);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c");
+    assertThat(letters).iteratesAs("a", "b", "c");
   }
 
   public void testStringSplitWithLongLeadingDelimiter() {
     String longDelimiter = ", a, b, c";
     Iterable<String> letters = Splitter.on(", ").split(longDelimiter);
-    ASSERT.that(letters).iteratesOverSequence("", "a", "b", "c");
+    assertThat(letters).iteratesAs("", "a", "b", "c");
   }
 
   public void testStringSplitWithLongTrailingDelimiter() {
     String longDelimiter = "a, b, c, ";
     Iterable<String> letters = Splitter.on(", ").split(longDelimiter);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c", "");
+    assertThat(letters).iteratesAs("a", "b", "c", "");
   }
 
   public void testStringSplitWithDelimiterSubstringInValue() {
     String fourCommasAndFourSpaces = ",,,,    ";
     Iterable<String> threeCommasThenThreeSpaces = Splitter.on(", ").split(
         fourCommasAndFourSpaces);
-    ASSERT.that(threeCommasThenThreeSpaces).iteratesOverSequence(",,,", "   ");
+    assertThat(threeCommasThenThreeSpaces).iteratesAs(",,,", "   ");
   }
 
   public void testStringSplitWithEmptyString() {
@@ -265,21 +265,21 @@
 
   public void testStringSplitOnEmptyString() {
     Iterable<String> notMuch = Splitter.on('.').split("");
-    ASSERT.that(notMuch).iteratesOverSequence("");
+    assertThat(notMuch).iteratesAs("");
   }
 
   public void testStringSplitOnEmptyStringOmitEmptyString() {
-    ASSERT.that(Splitter.on('.').omitEmptyStrings().split("")).isEmpty();
+    assertThat(Splitter.on('.').omitEmptyStrings().split("")).isEmpty();
   }
 
   public void testStringSplitOnOnlyDelimiter() {
     Iterable<String> blankblank = Splitter.on('.').split(".");
-    ASSERT.that(blankblank).iteratesOverSequence("", "");
+    assertThat(blankblank).iteratesAs("", "");
   }
 
   public void testStringSplitOnOnlyDelimitersOmitEmptyStrings() {
     Iterable<String> empty = Splitter.on('.').omitEmptyStrings().split("...");
-    ASSERT.that(empty).isEmpty();
+    assertThat(empty).isEmpty();
   }
 
   public void testStringSplitWithTrim() {
@@ -288,7 +288,7 @@
     Iterable<String> family = Splitter.on(',')
         .trimResults(CharMatcher.anyOf("afro").or(CharMatcher.WHITESPACE))
         .split(jacksons);
-    ASSERT.that(family).iteratesOverSequence(
+    assertThat(family).iteratesAs(
         "(Marlon)", "(Michael)", "(Jackie)", "(Jemaine)", "(Tito)");
   }
 
@@ -341,41 +341,41 @@
   public void testFixedLengthSimpleSplit() {
     String simple = "abcde";
     Iterable<String> letters = Splitter.fixedLength(2).split(simple);
-    ASSERT.that(letters).iteratesOverSequence("ab", "cd", "e");
+    assertThat(letters).iteratesAs("ab", "cd", "e");
   }
 
   public void testFixedLengthSplitEqualChunkLength() {
     String simple = "abcdef";
     Iterable<String> letters = Splitter.fixedLength(2).split(simple);
-    ASSERT.that(letters).iteratesOverSequence("ab", "cd", "ef");
+    assertThat(letters).iteratesAs("ab", "cd", "ef");
   }
 
   public void testFixedLengthSplitOnlyOneChunk() {
     String simple = "abc";
     Iterable<String> letters = Splitter.fixedLength(3).split(simple);
-    ASSERT.that(letters).iteratesOverSequence("abc");
+    assertThat(letters).iteratesAs("abc");
   }
 
   public void testFixedLengthSplitSmallerString() {
     String simple = "ab";
     Iterable<String> letters = Splitter.fixedLength(3).split(simple);
-    ASSERT.that(letters).iteratesOverSequence("ab");
+    assertThat(letters).iteratesAs("ab");
   }
 
   public void testFixedLengthSplitEmptyString() {
     String simple = "";
     Iterable<String> letters = Splitter.fixedLength(3).split(simple);
-    ASSERT.that(letters).iteratesOverSequence("");
+    assertThat(letters).iteratesAs("");
   }
 
   public void testFixedLengthSplitEmptyStringWithOmitEmptyStrings() {
-    ASSERT.that(Splitter.fixedLength(3).omitEmptyStrings().split("")).isEmpty();
+    assertThat(Splitter.fixedLength(3).omitEmptyStrings().split("")).isEmpty();
   }
 
   public void testFixedLengthSplitIntoChars() {
     String simple = "abcd";
     Iterable<String> letters = Splitter.fixedLength(1).split(simple);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c", "d");
+    assertThat(letters).iteratesAs("a", "b", "c", "d");
   }
 
   public void testFixedLengthSplitZeroChunkLen() {
@@ -397,79 +397,79 @@
   public void testLimitLarge() {
     String simple = "abcd";
     Iterable<String> letters = Splitter.fixedLength(1).limit(100).split(simple);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c", "d");
+    assertThat(letters).iteratesAs("a", "b", "c", "d");
   }
 
   public void testLimitOne() {
     String simple = "abcd";
     Iterable<String> letters = Splitter.fixedLength(1).limit(1).split(simple);
-    ASSERT.that(letters).iteratesOverSequence("abcd");
+    assertThat(letters).iteratesAs("abcd");
   }
 
   public void testLimitFixedLength() {
     String simple = "abcd";
     Iterable<String> letters = Splitter.fixedLength(1).limit(2).split(simple);
-    ASSERT.that(letters).iteratesOverSequence("a", "bcd");
+    assertThat(letters).iteratesAs("a", "bcd");
   }
 
   public void testLimitSeparator() {
     String simple = "a,b,c,d";
     Iterable<String> items = COMMA_SPLITTER.limit(2).split(simple);
-    ASSERT.that(items).iteratesOverSequence("a", "b,c,d");
+    assertThat(items).iteratesAs("a", "b,c,d");
   }
 
   public void testLimitExtraSeparators() {
     String text = "a,,,b,,c,d";
     Iterable<String> items = COMMA_SPLITTER.limit(2).split(text);
-    ASSERT.that(items).iteratesOverSequence("a", ",,b,,c,d");
+    assertThat(items).iteratesAs("a", ",,b,,c,d");
   }
 
   public void testLimitExtraSeparatorsOmitEmpty() {
     String text = "a,,,b,,c,d";
     Iterable<String> items = COMMA_SPLITTER.limit(2).omitEmptyStrings().split(text);
-    ASSERT.that(items).iteratesOverSequence("a", "b,,c,d");
+    assertThat(items).iteratesAs("a", "b,,c,d");
   }
 
   public void testLimitExtraSeparatorsOmitEmpty3() {
     String text = "a,,,b,,c,d";
     Iterable<String> items = COMMA_SPLITTER.limit(3).omitEmptyStrings().split(text);
-    ASSERT.that(items).iteratesOverSequence("a", "b", "c,d");
+    assertThat(items).iteratesAs("a", "b", "c,d");
   }
 
   public void testLimitExtraSeparatorsTrim() {
     String text = ",,a,,  , b ,, c,d ";
     Iterable<String> items = COMMA_SPLITTER.limit(2).omitEmptyStrings().trimResults().split(text);
-    ASSERT.that(items).iteratesOverSequence("a", "b ,, c,d");
+    assertThat(items).iteratesAs("a", "b ,, c,d");
   }
 
   public void testLimitExtraSeparatorsTrim3() {
     String text = ",,a,,  , b ,, c,d ";
     Iterable<String> items = COMMA_SPLITTER.limit(3).omitEmptyStrings().trimResults().split(text);
-    ASSERT.that(items).iteratesOverSequence("a", "b", "c,d");
+    assertThat(items).iteratesAs("a", "b", "c,d");
   }
 
   public void testLimitExtraSeparatorsTrim1() {
     String text = ",,a,,  , b ,, c,d ";
     Iterable<String> items = COMMA_SPLITTER.limit(1).omitEmptyStrings().trimResults().split(text);
-    ASSERT.that(items).iteratesOverSequence("a,,  , b ,, c,d");
+    assertThat(items).iteratesAs("a,,  , b ,, c,d");
   }
 
   public void testLimitExtraSeparatorsTrim1NoOmit() {
     String text = ",,a,,  , b ,, c,d ";
     Iterable<String> items = COMMA_SPLITTER.limit(1).trimResults().split(text);
-    ASSERT.that(items).iteratesOverSequence(",,a,,  , b ,, c,d");
+    assertThat(items).iteratesAs(",,a,,  , b ,, c,d");
   }
 
   public void testLimitExtraSeparatorsTrim1Empty() {
     String text = "";
     Iterable<String> items = COMMA_SPLITTER.limit(1).split(text);
-    ASSERT.that(items).iteratesOverSequence("");
+    assertThat(items).iteratesAs("");
   }
 
   public void testLimitExtraSeparatorsTrim1EmptyOmit() {
     String text = "";
     Iterable<String> items = COMMA_SPLITTER.omitEmptyStrings().limit(1).split(text);
-    ASSERT.that(items).isEmpty();
+    assertThat(items).isEmpty();
   }
 
   @SuppressWarnings("ReturnValueIgnored") // testing for exception
@@ -492,8 +492,8 @@
         .split("boy  : tom , girl: tina , cat  : kitty , dog: tommy ");
     ImmutableMap<String, String> expected =
           ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy");
-    ASSERT.that(m).isEqualTo(expected);
-    ASSERT.that(asList(m.entrySet())).is(asList(expected.entrySet()));
+    assertThat(m).isEqualTo(expected);
+    assertThat(asList(m.entrySet())).isEqualTo(asList(expected.entrySet()));
   }
 
   public void testMapSplitter_trimmedEntries() {
@@ -504,8 +504,8 @@
     ImmutableMap<String, String> expected =
         ImmutableMap.of("boy  ", " tom", "girl", " tina", "cat  ", " kitty", "dog", " tommy");
 
-    ASSERT.that(m).isEqualTo(expected);
-    ASSERT.that(asList(m.entrySet())).is(asList(expected.entrySet()));
+    assertThat(m).isEqualTo(expected);
+    assertThat(asList(m.entrySet())).isEqualTo(asList(expected.entrySet()));
   }
 
   public void testMapSplitter_trimmedKeyValue() {
@@ -514,8 +514,8 @@
             "boy  : tom , girl: tina , cat  : kitty , dog: tommy ");
     ImmutableMap<String, String> expected =
         ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy");
-    ASSERT.that(m).isEqualTo(expected);
-    ASSERT.that(asList(m.entrySet())).is(asList(expected.entrySet()));
+    assertThat(m).isEqualTo(expected);
+    assertThat(asList(m.entrySet())).isEqualTo(asList(expected.entrySet()));
   }
 
   public void testMapSplitter_notTrimmed() {
@@ -523,8 +523,8 @@
         " boy:tom , girl: tina , cat :kitty , dog:  tommy ");
     ImmutableMap<String, String> expected =
         ImmutableMap.of(" boy", "tom ", " girl", " tina ", " cat ", "kitty ", " dog", "  tommy ");
-    ASSERT.that(m).isEqualTo(expected);
-    ASSERT.that(asList(m.entrySet())).is(asList(expected.entrySet()));
+    assertThat(m).isEqualTo(expected);
+    assertThat(asList(m.entrySet())).isEqualTo(asList(expected.entrySet()));
   }
 
   public void testMapSplitter_CharacterSeparator() {
@@ -536,8 +536,8 @@
     ImmutableMap<String, String> expected =
         ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy");
 
-    ASSERT.that(m).isEqualTo(expected);
-    ASSERT.that(asList(m.entrySet())).is(asList(expected.entrySet()));
+    assertThat(m).isEqualTo(expected);
+    assertThat(asList(m.entrySet())).isEqualTo(asList(expected.entrySet()));
   }
 
   public void testMapSplitter_multiCharacterSeparator() {
@@ -549,8 +549,8 @@
     ImmutableMap<String, String> expected =
         ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy");
 
-    ASSERT.that(m).isEqualTo(expected);
-    ASSERT.that(asList(m.entrySet())).is(asList(expected.entrySet()));
+    assertThat(m).isEqualTo(expected);
+    assertThat(asList(m.entrySet())).isEqualTo(asList(expected.entrySet()));
   }
 
   @SuppressWarnings("ReturnValueIgnored") // testing for exception
@@ -575,8 +575,8 @@
         .withKeyValueSeparator(":")
         .split("boy:tom,girl:tina,cat:kitty,dog:tommy");
 
-    ASSERT.that(m.keySet()).iteratesOverSequence("boy", "girl", "cat", "dog");
-    ASSERT.that(m).isEqualTo(
+    assertThat(m.keySet()).iteratesAs("boy", "girl", "cat", "dog");
+    assertThat(m).isEqualTo(
         ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy"));
 
     // try in a different order
@@ -584,8 +584,8 @@
         .withKeyValueSeparator(":")
         .split("girl:tina,boy:tom,dog:tommy,cat:kitty");
 
-    ASSERT.that(m.keySet()).iteratesOverSequence("girl", "boy", "dog", "cat");
-    ASSERT.that(m).isEqualTo(
+    assertThat(m.keySet()).iteratesAs("girl", "boy", "dog", "cat");
+    assertThat(m).isEqualTo(
         ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy"));
   }
 
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/AbstractImmutableSetTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/AbstractImmutableSetTest.java
index 1826fb6..b16137a 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/AbstractImmutableSetTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/AbstractImmutableSetTest.java
@@ -16,8 +16,8 @@
 
 package com.google.common.collect;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.testing.MinimalCollection;
@@ -271,7 +271,7 @@
         .add("d", "e", "f")
         .add("g", "h", "i", "j")
         .build();
-    ASSERT.that(set).has().exactly(
+    assertThat(set).has().exactly(
         "a", "b", "c", "d", "e", "f", "g", "h", "i", "j").inOrder();
   }
 
@@ -279,9 +279,9 @@
     ImmutableSet.Builder<String> builder = this.<String>builder()
         .add("a")
         .add("b");
-    ASSERT.that(builder.build()).has().exactly("a", "b").inOrder();
+    assertThat(builder.build()).has().exactly("a", "b").inOrder();
     builder.add("c", "d");
-    ASSERT.that(builder.build()).has().exactly("a", "b", "c", "d").inOrder();
+    assertThat(builder.build()).has().exactly("a", "b", "c", "d").inOrder();
   }
 
   public void testBuilderWithDuplicateElements() {
@@ -301,9 +301,9 @@
         .add("a")
         .add("a", "a")
         .add("b");
-    ASSERT.that(builder.build()).has().exactly("a", "b").inOrder();
+    assertThat(builder.build()).has().exactly("a", "b").inOrder();
     builder.add("a", "b", "c", "c");
-    ASSERT.that(builder.build()).has().exactly("a", "b", "c").inOrder();
+    assertThat(builder.build()).has().exactly("a", "b", "c").inOrder();
   }
 
   public void testBuilderAddAll() {
@@ -313,7 +313,7 @@
         .addAll(a)
         .addAll(b)
         .build();
-    ASSERT.that(set).has().exactly("a", "b", "c", "d", "e").inOrder();
+    assertThat(set).has().exactly("a", "b", "c", "d", "e").inOrder();
   }
 
   static final int LAST_COLOR_ADDED = 0x00BFFF;
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/AbstractSequentialIteratorTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/AbstractSequentialIteratorTest.java
index 85d641e..81b9b85 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/AbstractSequentialIteratorTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/AbstractSequentialIteratorTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 
@@ -37,7 +37,7 @@
         return newDoubler(2, 32);
       }
     };
-    ASSERT.that(doubled).iteratesOverSequence(2, 4, 8, 16, 32);
+    assertThat(doubled).iteratesAs(2, 4, 8, 16, 32);
   }
 
   public void testSampleCode() {
@@ -52,7 +52,7 @@
         return powersOfTwo;
       }
     };
-    ASSERT.that(actual).iteratesOverSequence(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
+    assertThat(actual).iteratesAs(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
         4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304,
         8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824);
   }
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/AbstractTableReadTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/AbstractTableReadTest.java
index 11581ba..342b112 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/AbstractTableReadTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/AbstractTableReadTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Objects;
@@ -181,7 +181,7 @@
   public void testColumnSetPartialOverlap() {
     table = create(
         "foo", 1, 'a', "bar", 1, 'b', "foo", 2, 'c', "bar", 3, 'd');
-    ASSERT.that(table.columnKeySet()).has().exactly(1, 2, 3);
+    assertThat(table.columnKeySet()).has().exactly(1, 2, 3);
   }
 }
 
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ArrayListMultimapTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ArrayListMultimapTest.java
index 9c8aba4..18339cc 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ArrayListMultimapTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ArrayListMultimapTest.java
@@ -16,8 +16,8 @@
 
 package com.google.common.collect;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 
@@ -82,9 +82,9 @@
     ListMultimap<String, Integer> multimap = create();
     multimap.putAll("foo", asList(1, 2, 3, 4, 5));
     List<Integer> list = multimap.get("foo");
-    ASSERT.that(multimap.get("foo")).has().exactly(1, 2, 3, 4, 5).inOrder();
+    assertThat(multimap.get("foo")).has().exactly(1, 2, 3, 4, 5).inOrder();
     List<Integer> sublist = list.subList(0, 5);
-    ASSERT.that(sublist).has().exactly(1, 2, 3, 4, 5).inOrder();
+    assertThat(sublist).has().exactly(1, 2, 3, 4, 5).inOrder();
 
     sublist.clear();
     assertTrue(sublist.isEmpty());
@@ -153,8 +153,8 @@
     multimap.put("bar", 3);
     multimap.trimToSize();
     assertEquals(3, multimap.size());
-    ASSERT.that(multimap.get("foo")).has().exactly(1, 2).inOrder();
-    ASSERT.that(multimap.get("bar")).has().item(3);
+    assertThat(multimap.get("foo")).has().exactly(1, 2).inOrder();
+    assertThat(multimap.get("bar")).has().item(3);
   }
 }
 
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ArrayTableTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ArrayTableTest.java
index 9f3af8f..76cc870 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ArrayTableTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ArrayTableTest.java
@@ -16,8 +16,8 @@
 
 package com.google.common.collect;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Objects;
@@ -279,13 +279,13 @@
   public void testRowKeyList() {
     ArrayTable<String, Integer, Character> table
         = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
-    ASSERT.that(table.rowKeyList()).has().exactly("foo", "bar", "cat").inOrder();
+    assertThat(table.rowKeyList()).has().exactly("foo", "bar", "cat").inOrder();
   }
 
   public void testColumnKeyList() {
     ArrayTable<String, Integer, Character> table
         = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
-    ASSERT.that(table.columnKeyList()).has().exactly(1, 2, 3).inOrder();
+    assertThat(table.columnKeyList()).has().exactly(1, 2, 3).inOrder();
   }
 
   public void testGetMissingKeys() {
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/Collections2Test.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/Collections2Test.java
index 3529efd..31e19a4 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/Collections2Test.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/Collections2Test.java
@@ -18,9 +18,9 @@
 
 import static com.google.common.collect.Iterables.concat;
 import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
 import static java.util.Collections.nCopies;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Function;
@@ -79,7 +79,7 @@
         Collections2.orderedPermutations(list);
 
     assertEquals(1, permutationSet.size());
-    ASSERT.that(permutationSet).has().item(list);
+    assertThat(permutationSet).has().item(list);
 
     Iterator<List<Integer>> permutations = permutationSet.iterator();
 
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ConstraintsTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ConstraintsTest.java
deleted file mode 100644
index 9dda41f..0000000
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ConstraintsTest.java
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * Copyright (C) 2007 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
-
-import com.google.common.annotations.GwtCompatible;
-
-import junit.framework.TestCase;
-
-import java.util.AbstractCollection;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.RandomAccess;
-import java.util.Set;
-import java.util.SortedSet;
-
-/**
- * Tests for {@code Constraints}.
- *
- * @author Mike Bostock
- * @author Jared Levy
- */
-@GwtCompatible(emulated = true)
-public class ConstraintsTest extends TestCase {
-
-  private static final String TEST_ELEMENT = "test";
-
-  private static final class TestElementException
-      extends IllegalArgumentException {
-    private static final long serialVersionUID = 0;
-  }
-
-  private static final Constraint<String> TEST_CONSTRAINT
-      = new Constraint<String>() {
-          @Override
-          public String checkElement(String element) {
-            if (TEST_ELEMENT.equals(element)) {
-              throw new TestElementException();
-            }
-            return element;
-          }
-        };
-
-  public void testNotNull() {
-    Constraint<? super String> constraint = Constraints.notNull();
-    assertSame(TEST_ELEMENT, constraint.checkElement(TEST_ELEMENT));
-    try {
-      constraint.checkElement(null);
-      fail("NullPointerException expected");
-    } catch (NullPointerException expected) {}
-    assertEquals("Not null", constraint.toString());
-  }
-
-  public void testConstrainedCollectionLegal() {
-    Collection<String> collection = Lists.newArrayList("foo", "bar");
-    Collection<String> constrained = Constraints.constrainedCollection(
-        collection, TEST_CONSTRAINT);
-    collection.add(TEST_ELEMENT);
-    constrained.add("qux");
-    constrained.addAll(asList("cat", "dog"));
-    /* equals and hashCode aren't defined for Collection */
-    ASSERT.that(collection).has()
-        .exactly("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder();
-    ASSERT.that(constrained).has()
-        .exactly("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder();
-  }
-
-  public void testConstrainedCollectionIllegal() {
-    Collection<String> collection = Lists.newArrayList("foo", "bar");
-    Collection<String> constrained = Constraints.constrainedCollection(
-        collection, TEST_CONSTRAINT);
-    try {
-      constrained.add(TEST_ELEMENT);
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    try {
-      constrained.addAll(asList("baz", TEST_ELEMENT));
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    ASSERT.that(constrained).has().exactly("foo", "bar").inOrder();
-    ASSERT.that(collection).has().exactly("foo", "bar").inOrder();
-  }
-
-  public void testConstrainedSetLegal() {
-    Set<String> set = Sets.newLinkedHashSet(asList("foo", "bar"));
-    Set<String> constrained = Constraints.constrainedSet(set, TEST_CONSTRAINT);
-    set.add(TEST_ELEMENT);
-    constrained.add("qux");
-    constrained.addAll(asList("cat", "dog"));
-    assertTrue(set.equals(constrained));
-    assertTrue(constrained.equals(set));
-    assertEquals(set.toString(), constrained.toString());
-    assertEquals(set.hashCode(), constrained.hashCode());
-    ASSERT.that(set).has().exactly("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder();
-    ASSERT.that(constrained).has()
-        .exactly("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder();
-  }
-
-  public void testConstrainedSetIllegal() {
-    Set<String> set = Sets.newLinkedHashSet(asList("foo", "bar"));
-    Set<String> constrained = Constraints.constrainedSet(set, TEST_CONSTRAINT);
-    try {
-      constrained.add(TEST_ELEMENT);
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    try {
-      constrained.addAll(asList("baz", TEST_ELEMENT));
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    ASSERT.that(constrained).has().exactly("foo", "bar").inOrder();
-    ASSERT.that(set).has().exactly("foo", "bar").inOrder();
-  }
-
-  public void testConstrainedSortedSetLegal() {
-    SortedSet<String> sortedSet = Sets.newTreeSet(asList("foo", "bar"));
-    SortedSet<String> constrained = Constraints.constrainedSortedSet(
-        sortedSet, TEST_CONSTRAINT);
-    sortedSet.add(TEST_ELEMENT);
-    constrained.add("qux");
-    constrained.addAll(asList("cat", "dog"));
-    assertTrue(sortedSet.equals(constrained));
-    assertTrue(constrained.equals(sortedSet));
-    assertEquals(sortedSet.toString(), constrained.toString());
-    assertEquals(sortedSet.hashCode(), constrained.hashCode());
-    ASSERT.that(sortedSet).has().exactly("bar", "cat", "dog", "foo", "qux", TEST_ELEMENT).inOrder();
-    ASSERT.that(constrained).has()
-        .exactly("bar", "cat", "dog", "foo", "qux", TEST_ELEMENT).inOrder();
-    assertNull(constrained.comparator());
-    assertEquals("bar", constrained.first());
-    assertEquals(TEST_ELEMENT, constrained.last());
-  }
-
-  public void testConstrainedSortedSetIllegal() {
-    SortedSet<String> sortedSet = Sets.newTreeSet(asList("foo", "bar"));
-    SortedSet<String> constrained = Constraints.constrainedSortedSet(
-        sortedSet, TEST_CONSTRAINT);
-    try {
-      constrained.add(TEST_ELEMENT);
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    try {
-      constrained.subSet("bar", "foo").add(TEST_ELEMENT);
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    try {
-      constrained.headSet("bar").add(TEST_ELEMENT);
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    try {
-      constrained.tailSet("foo").add(TEST_ELEMENT);
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    try {
-      constrained.addAll(asList("baz", TEST_ELEMENT));
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    ASSERT.that(constrained).has().exactly("bar", "foo").inOrder();
-    ASSERT.that(sortedSet).has().exactly("bar", "foo").inOrder();
-  }
-
-  public void testConstrainedListLegal() {
-    List<String> list = Lists.newArrayList("foo", "bar");
-    List<String> constrained = Constraints.constrainedList(
-        list, TEST_CONSTRAINT);
-    list.add(TEST_ELEMENT);
-    constrained.add("qux");
-    constrained.addAll(asList("cat", "dog"));
-    constrained.add(1, "cow");
-    constrained.addAll(4, asList("box", "fan"));
-    constrained.set(2, "baz");
-    assertTrue(list.equals(constrained));
-    assertTrue(constrained.equals(list));
-    assertEquals(list.toString(), constrained.toString());
-    assertEquals(list.hashCode(), constrained.hashCode());
-    ASSERT.that(list).has().exactly(
-        "foo", "cow", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog").inOrder();
-    ASSERT.that(constrained).has().exactly(
-        "foo", "cow", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog").inOrder();
-    ListIterator<String> iterator = constrained.listIterator();
-    iterator.next();
-    iterator.set("sun");
-    constrained.listIterator(2).add("sky");
-    ASSERT.that(list).has().exactly(
-        "sun", "cow", "sky", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog").inOrder();
-    ASSERT.that(constrained).has().exactly(
-        "sun", "cow", "sky", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog").inOrder();
-    assertTrue(constrained instanceof RandomAccess);
-  }
-
-  public void testConstrainedListRandomAccessFalse() {
-    List<String> list = Lists.newLinkedList(asList("foo", "bar"));
-    List<String> constrained = Constraints.constrainedList(
-        list, TEST_CONSTRAINT);
-    list.add(TEST_ELEMENT);
-    constrained.add("qux");
-    assertFalse(constrained instanceof RandomAccess);
-  }
-
-  public void testConstrainedListIllegal() {
-    List<String> list = Lists.newArrayList("foo", "bar");
-    List<String> constrained = Constraints.constrainedList(
-        list, TEST_CONSTRAINT);
-    try {
-      constrained.add(TEST_ELEMENT);
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    try {
-      constrained.listIterator().add(TEST_ELEMENT);
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    try {
-      constrained.listIterator(1).add(TEST_ELEMENT);
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    try {
-      constrained.listIterator().set(TEST_ELEMENT);
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    try {
-      constrained.listIterator(1).set(TEST_ELEMENT);
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    try {
-      constrained.subList(0, 1).add(TEST_ELEMENT);
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    try {
-      constrained.add(1, TEST_ELEMENT);
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    try {
-      constrained.set(1, TEST_ELEMENT);
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    try {
-      constrained.addAll(asList("baz", TEST_ELEMENT));
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    try {
-      constrained.addAll(1, asList("baz", TEST_ELEMENT));
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    ASSERT.that(constrained).has().exactly("foo", "bar").inOrder();
-    ASSERT.that(list).has().exactly("foo", "bar").inOrder();
-  }
-
-  public void testConstrainedMultisetLegal() {
-    Multiset<String> multiset = HashMultiset.create(asList("foo", "bar"));
-    Multiset<String> constrained = Constraints.constrainedMultiset(
-        multiset, TEST_CONSTRAINT);
-    multiset.add(TEST_ELEMENT);
-    constrained.add("qux");
-    constrained.addAll(asList("cat", "dog"));
-    constrained.add("cow", 2);
-    assertTrue(multiset.equals(constrained));
-    assertTrue(constrained.equals(multiset));
-    assertEquals(multiset.toString(), constrained.toString());
-    assertEquals(multiset.hashCode(), constrained.hashCode());
-    ASSERT.that(multiset).has().exactly(
-        "foo", "bar", TEST_ELEMENT, "qux", "cat", "dog", "cow", "cow");
-    ASSERT.that(constrained).has().exactly(
-        "foo", "bar", TEST_ELEMENT, "qux", "cat", "dog", "cow", "cow");
-    assertEquals(1, constrained.count("foo"));
-    assertEquals(1, constrained.remove("foo", 3));
-    assertEquals(2, constrained.setCount("cow", 0));
-    ASSERT.that(multiset).has().exactly("bar", TEST_ELEMENT, "qux", "cat", "dog");
-    ASSERT.that(constrained).has().exactly("bar", TEST_ELEMENT, "qux", "cat", "dog");
-  }
-
-  public void testConstrainedMultisetIllegal() {
-    Multiset<String> multiset = HashMultiset.create(asList("foo", "bar"));
-    Multiset<String> constrained = Constraints.constrainedMultiset(
-        multiset, TEST_CONSTRAINT);
-    try {
-      constrained.add(TEST_ELEMENT);
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    try {
-      constrained.add(TEST_ELEMENT, 2);
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    try {
-      constrained.addAll(asList("baz", TEST_ELEMENT));
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    ASSERT.that(constrained).has().exactly("foo", "bar");
-    ASSERT.that(multiset).has().exactly("foo", "bar");
-  }
-
-  public void testNefariousAddAll() {
-    List<String> list = Lists.newArrayList("foo", "bar");
-    List<String> constrained = Constraints.constrainedList(
-        list, TEST_CONSTRAINT);
-    Collection<String> onceIterable = onceIterableCollection("baz");
-    constrained.addAll(onceIterable);
-    ASSERT.that(constrained).has().exactly("foo", "bar", "baz").inOrder();
-    ASSERT.that(list).has().exactly("foo", "bar", "baz").inOrder();
-  }
-
-  /**
-   * Returns a "nefarious" collection, which permits only one call to
-   * iterator(). This verifies that the constrained collection uses a defensive
-   * copy instead of potentially checking the elements in one snapshot and
-   * adding the elements from another.
-   *
-   * @param element the element to be contained in the collection
-   */
-  static <E> Collection<E> onceIterableCollection(final E element) {
-    return new AbstractCollection<E>() {
-      boolean iteratorCalled;
-      @Override public int size() {
-        /*
-         * We could make the collection empty, but that seems more likely to
-         * trigger special cases (so maybe we should test both empty and
-         * nonempty...).
-         */
-        return 1;
-      }
-      @Override public Iterator<E> iterator() {
-        assertFalse("Expected only one call to iterator()", iteratorCalled);
-        iteratorCalled = true;
-        return Collections.singleton(element).iterator();
-      }
-    };
-  }
-}
-
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ContiguousSetTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ContiguousSetTest.java
index fcbb944..ea7efe1 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ContiguousSetTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ContiguousSetTest.java
@@ -19,7 +19,7 @@
 import static com.google.common.collect.BoundType.CLOSED;
 import static com.google.common.collect.BoundType.OPEN;
 import static com.google.common.collect.DiscreteDomain.integers;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.testing.EqualsTester;
@@ -107,53 +107,53 @@
 
   public void testHeadSet() {
     ImmutableSortedSet<Integer> set = ContiguousSet.create(Range.closed(1, 3), integers());
-    ASSERT.that(set.headSet(1)).isEmpty();
-    ASSERT.that(set.headSet(2)).has().item(1);
-    ASSERT.that(set.headSet(3)).has().exactly(1, 2).inOrder();
-    ASSERT.that(set.headSet(4)).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(set.headSet(Integer.MAX_VALUE)).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(set.headSet(1, true)).has().item(1);
-    ASSERT.that(set.headSet(2, true)).has().exactly(1, 2).inOrder();
-    ASSERT.that(set.headSet(3, true)).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(set.headSet(4, true)).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(set.headSet(Integer.MAX_VALUE, true)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.headSet(1)).isEmpty();
+    assertThat(set.headSet(2)).has().item(1);
+    assertThat(set.headSet(3)).has().exactly(1, 2).inOrder();
+    assertThat(set.headSet(4)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.headSet(Integer.MAX_VALUE)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.headSet(1, true)).has().item(1);
+    assertThat(set.headSet(2, true)).has().exactly(1, 2).inOrder();
+    assertThat(set.headSet(3, true)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.headSet(4, true)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.headSet(Integer.MAX_VALUE, true)).has().exactly(1, 2, 3).inOrder();
   }
 
   public void testHeadSet_tooSmall() {
-    ASSERT.that(ContiguousSet.create(Range.closed(1, 3), integers()).headSet(0)).isEmpty();
+    assertThat(ContiguousSet.create(Range.closed(1, 3), integers()).headSet(0)).isEmpty();
   }
 
   public void testTailSet() {
     ImmutableSortedSet<Integer> set = ContiguousSet.create(Range.closed(1, 3), integers());
-    ASSERT.that(set.tailSet(Integer.MIN_VALUE)).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(set.tailSet(1)).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(set.tailSet(2)).has().exactly(2, 3).inOrder();
-    ASSERT.that(set.tailSet(3)).has().item(3);
-    ASSERT.that(set.tailSet(Integer.MIN_VALUE, false)).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(set.tailSet(1, false)).has().exactly(2, 3).inOrder();
-    ASSERT.that(set.tailSet(2, false)).has().item(3);
-    ASSERT.that(set.tailSet(3, false)).isEmpty();
+    assertThat(set.tailSet(Integer.MIN_VALUE)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.tailSet(1)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.tailSet(2)).has().exactly(2, 3).inOrder();
+    assertThat(set.tailSet(3)).has().item(3);
+    assertThat(set.tailSet(Integer.MIN_VALUE, false)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.tailSet(1, false)).has().exactly(2, 3).inOrder();
+    assertThat(set.tailSet(2, false)).has().item(3);
+    assertThat(set.tailSet(3, false)).isEmpty();
   }
 
   public void testTailSet_tooLarge() {
-    ASSERT.that(ContiguousSet.create(Range.closed(1, 3), integers()).tailSet(4)).isEmpty();
+    assertThat(ContiguousSet.create(Range.closed(1, 3), integers()).tailSet(4)).isEmpty();
   }
 
   public void testSubSet() {
     ImmutableSortedSet<Integer> set = ContiguousSet.create(Range.closed(1, 3), integers());
-    ASSERT.that(set.subSet(1, 4)).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(set.subSet(2, 4)).has().exactly(2, 3).inOrder();
-    ASSERT.that(set.subSet(3, 4)).has().item(3);
-    ASSERT.that(set.subSet(3, 3)).isEmpty();
-    ASSERT.that(set.subSet(2, 3)).has().item(2);
-    ASSERT.that(set.subSet(1, 3)).has().exactly(1, 2).inOrder();
-    ASSERT.that(set.subSet(1, 2)).has().item(1);
-    ASSERT.that(set.subSet(2, 2)).isEmpty();
-    ASSERT.that(set.subSet(Integer.MIN_VALUE, Integer.MAX_VALUE)).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(set.subSet(1, true, 3, true)).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(set.subSet(1, false, 3, true)).has().exactly(2, 3).inOrder();
-    ASSERT.that(set.subSet(1, true, 3, false)).has().exactly(1, 2).inOrder();
-    ASSERT.that(set.subSet(1, false, 3, false)).has().item(2);
+    assertThat(set.subSet(1, 4)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.subSet(2, 4)).has().exactly(2, 3).inOrder();
+    assertThat(set.subSet(3, 4)).has().item(3);
+    assertThat(set.subSet(3, 3)).isEmpty();
+    assertThat(set.subSet(2, 3)).has().item(2);
+    assertThat(set.subSet(1, 3)).has().exactly(1, 2).inOrder();
+    assertThat(set.subSet(1, 2)).has().item(1);
+    assertThat(set.subSet(2, 2)).isEmpty();
+    assertThat(set.subSet(Integer.MIN_VALUE, Integer.MAX_VALUE)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.subSet(1, true, 3, true)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.subSet(1, false, 3, true)).has().exactly(2, 3).inOrder();
+    assertThat(set.subSet(1, true, 3, false)).has().exactly(1, 2).inOrder();
+    assertThat(set.subSet(1, false, 3, false)).has().item(2);
   }
 
   public void testSubSet_outOfOrder() {
@@ -165,11 +165,11 @@
   }
 
   public void testSubSet_tooLarge() {
-    ASSERT.that(ContiguousSet.create(Range.closed(1, 3), integers()).subSet(4, 6)).isEmpty();
+    assertThat(ContiguousSet.create(Range.closed(1, 3), integers()).subSet(4, 6)).isEmpty();
   }
 
   public void testSubSet_tooSmall() {
-    ASSERT.that(ContiguousSet.create(Range.closed(1, 3), integers()).subSet(-1, 0)).isEmpty();
+    assertThat(ContiguousSet.create(Range.closed(1, 3), integers()).subSet(-1, 0)).isEmpty();
   }
 
   public void testFirst() {
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/EnumBiMapTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/EnumBiMapTest.java
index 7cfc706..bed6626 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/EnumBiMapTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/EnumBiMapTest.java
@@ -17,7 +17,7 @@
 package com.google.common.collect;
 
 import static com.google.common.collect.testing.Helpers.orderEntriesByKey;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.testing.Helpers;
@@ -172,16 +172,16 @@
     EnumBiMap<Currency, Country> bimap = EnumBiMap.create(map);
 
     // forward map ordered by currency
-    ASSERT.that(bimap.keySet())
+    assertThat(bimap.keySet())
         .has().exactly(Currency.DOLLAR, Currency.FRANC, Currency.PESO).inOrder();
     // forward map ordered by currency (even for country values)
-    ASSERT.that(bimap.values())
+    assertThat(bimap.values())
         .has().exactly(Country.CANADA, Country.SWITZERLAND, Country.CHILE).inOrder();
     // backward map ordered by country
-    ASSERT.that(bimap.inverse().keySet())
+    assertThat(bimap.inverse().keySet())
         .has().exactly(Country.CANADA, Country.CHILE, Country.SWITZERLAND).inOrder();
     // backward map ordered by country (even for currency values)
-    ASSERT.that(bimap.inverse().values())
+    assertThat(bimap.inverse().values())
         .has().exactly(Currency.DOLLAR, Currency.PESO, Currency.FRANC).inOrder();
   }
 
@@ -199,16 +199,16 @@
     iter.remove();
 
     // forward map ordered by currency
-    ASSERT.that(bimap.keySet())
+    assertThat(bimap.keySet())
         .has().exactly(Currency.FRANC, Currency.PESO).inOrder();
     // forward map ordered by currency (even for country values)
-    ASSERT.that(bimap.values())
+    assertThat(bimap.values())
         .has().exactly(Country.SWITZERLAND, Country.CHILE).inOrder();
     // backward map ordered by country
-    ASSERT.that(bimap.inverse().keySet())
+    assertThat(bimap.inverse().keySet())
         .has().exactly(Country.CHILE, Country.SWITZERLAND).inOrder();
     // backward map ordered by country (even for currency values)
-    ASSERT.that(bimap.inverse().values())
+    assertThat(bimap.inverse().values())
         .has().exactly(Currency.PESO, Currency.FRANC).inOrder();
   }
 
@@ -227,16 +227,16 @@
     iter.remove();
 
     // forward map ordered by currency
-    ASSERT.that(bimap.keySet())
+    assertThat(bimap.keySet())
         .has().exactly(Currency.DOLLAR, Currency.PESO).inOrder();
     // forward map ordered by currency (even for country values)
-    ASSERT.that(bimap.values())
+    assertThat(bimap.values())
         .has().exactly(Country.CANADA, Country.CHILE).inOrder();
     // backward map ordered by country
-    ASSERT.that(bimap.inverse().keySet())
+    assertThat(bimap.inverse().keySet())
         .has().exactly(Country.CANADA, Country.CHILE).inOrder();
     // backward map ordered by country (even for currency values)
-    ASSERT.that(bimap.inverse().values())
+    assertThat(bimap.inverse().values())
         .has().exactly(Currency.DOLLAR, Currency.PESO).inOrder();
   }
 
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableBiMapTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableBiMapTest.java
index 30ede60..514effe 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableBiMapTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableBiMapTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Joiner;
@@ -404,7 +404,7 @@
           ImmutableMap.of("one", 1, "two", 2, "three", 3, "four", 4));
       Set<String> keys = bimap.keySet();
       assertEquals(Sets.newHashSet("one", "two", "three", "four"), keys);
-      ASSERT.that(keys).has().exactly("one", "two", "three", "four").inOrder();
+      assertThat(keys).has().exactly("one", "two", "three", "four").inOrder();
     }
 
     public void testValues() {
@@ -412,7 +412,7 @@
           ImmutableMap.of("one", 1, "two", 2, "three", 3, "four", 4));
       Set<Integer> values = bimap.values();
       assertEquals(Sets.newHashSet(1, 2, 3, 4), values);
-      ASSERT.that(values).has().exactly(1, 2, 3, 4).inOrder();
+      assertThat(values).has().exactly(1, 2, 3, 4).inOrder();
     }
 
     public void testDoubleInverse() {
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableEnumMapTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableEnumMapTest.java
index 2fc26fd..1233a93 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableEnumMapTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableEnumMapTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.testing.AnEnum;
@@ -55,7 +55,7 @@
     ImmutableMap<AnEnum, String> map = Maps.immutableEnumMap(
         ImmutableMap.of(AnEnum.C, "c", AnEnum.A, "a", AnEnum.E, "e"));
 
-    ASSERT.that(map.entrySet()).has().exactly(
+    assertThat(map.entrySet()).has().exactly(
         Helpers.mapEntry(AnEnum.A, "a"),
         Helpers.mapEntry(AnEnum.C, "c"),
         Helpers.mapEntry(AnEnum.E, "e")).inOrder();
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableListMultimapTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableListMultimapTest.java
index f6c0657..b71caa8 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableListMultimapTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableListMultimapTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.ImmutableListMultimap.Builder;
@@ -239,10 +239,10 @@
     builder.put("a", 2);
     builder.put("b", 6);
     ImmutableListMultimap<String, Integer> multimap = builder.build();
-    ASSERT.that(multimap.keySet()).has().exactly("d", "c", "b", "a").inOrder();
-    ASSERT.that(multimap.values()).has().exactly(2, 4, 3, 6, 5, 2).inOrder();
-    ASSERT.that(multimap.get("a")).has().exactly(5, 2).inOrder();
-    ASSERT.that(multimap.get("b")).has().exactly(3, 6).inOrder();
+    assertThat(multimap.keySet()).has().exactly("d", "c", "b", "a").inOrder();
+    assertThat(multimap.values()).has().exactly(2, 4, 3, 6, 5, 2).inOrder();
+    assertThat(multimap.get("a")).has().exactly(5, 2).inOrder();
+    assertThat(multimap.get("b")).has().exactly(3, 6).inOrder();
   }
 
   public void testBuilderOrderKeysByDuplicates() {
@@ -261,10 +261,10 @@
     builder.put("a", 2);
     builder.put("bb", 6);
     ImmutableListMultimap<String, Integer> multimap = builder.build();
-    ASSERT.that(multimap.keySet()).has().exactly("d", "a", "bb", "cc").inOrder();
-    ASSERT.that(multimap.values()).has().exactly(2, 5, 2, 3, 6, 4).inOrder();
-    ASSERT.that(multimap.get("a")).has().exactly(5, 2).inOrder();
-    ASSERT.that(multimap.get("bb")).has().exactly(3, 6).inOrder();
+    assertThat(multimap.keySet()).has().exactly("d", "a", "bb", "cc").inOrder();
+    assertThat(multimap.values()).has().exactly(2, 5, 2, 3, 6, 4).inOrder();
+    assertThat(multimap.get("a")).has().exactly(5, 2).inOrder();
+    assertThat(multimap.get("bb")).has().exactly(3, 6).inOrder();
   }
 
   public void testBuilderOrderValuesBy() {
@@ -278,10 +278,10 @@
     builder.put("a", 2);
     builder.put("b", 6);
     ImmutableListMultimap<String, Integer> multimap = builder.build();
-    ASSERT.that(multimap.keySet()).has().exactly("b", "d", "a", "c").inOrder();
-    ASSERT.that(multimap.values()).has().exactly(6, 3, 2, 5, 2, 4).inOrder();
-    ASSERT.that(multimap.get("a")).has().exactly(5, 2).inOrder();
-    ASSERT.that(multimap.get("b")).has().exactly(6, 3).inOrder();
+    assertThat(multimap.keySet()).has().exactly("b", "d", "a", "c").inOrder();
+    assertThat(multimap.values()).has().exactly(6, 3, 2, 5, 2, 4).inOrder();
+    assertThat(multimap.get("a")).has().exactly(5, 2).inOrder();
+    assertThat(multimap.get("b")).has().exactly(6, 3).inOrder();
   }
 
   public void testBuilderOrderKeysAndValuesBy() {
@@ -296,10 +296,10 @@
     builder.put("a", 2);
     builder.put("b", 6);
     ImmutableListMultimap<String, Integer> multimap = builder.build();
-    ASSERT.that(multimap.keySet()).has().exactly("d", "c", "b", "a").inOrder();
-    ASSERT.that(multimap.values()).has().exactly(2, 4, 6, 3, 5, 2).inOrder();
-    ASSERT.that(multimap.get("a")).has().exactly(5, 2).inOrder();
-    ASSERT.that(multimap.get("b")).has().exactly(6, 3).inOrder();
+    assertThat(multimap.keySet()).has().exactly("d", "c", "b", "a").inOrder();
+    assertThat(multimap.values()).has().exactly(2, 4, 6, 3, 5, 2).inOrder();
+    assertThat(multimap.get("a")).has().exactly(5, 2).inOrder();
+    assertThat(multimap.get("b")).has().exactly(6, 3).inOrder();
   }
 
   public void testCopyOf() {
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableMultisetTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableMultisetTest.java
index f1092a3..5396ef2 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableMultisetTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableMultisetTest.java
@@ -16,8 +16,8 @@
 
 package com.google.common.collect;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.testing.MinimalCollection;
@@ -348,13 +348,13 @@
     Collection<String> c = ImmutableMultiset.of("a", "b", "a");
     assertEquals(c, ImmutableMultiset.of("a", "b", "a"));
     assertEquals(c, ImmutableMultiset.of("a", "a", "b"));
-    ASSERT.that(c).isNotEqualTo(ImmutableMultiset.of("a", "b"));
-    ASSERT.that(c).isNotEqualTo(ImmutableMultiset.of("a", "b", "c", "d"));
+    assertThat(c).isNotEqualTo(ImmutableMultiset.of("a", "b"));
+    assertThat(c).isNotEqualTo(ImmutableMultiset.of("a", "b", "c", "d"));
   }
 
   public void testIterationOrder() {
     Collection<String> c = ImmutableMultiset.of("a", "b", "a");
-    ASSERT.that(c).has().exactly("a", "a", "b").inOrder();
+    assertThat(c).has().exactly("a", "a", "b").inOrder();
   }
 
   public void testMultisetWrites() {
@@ -380,3 +380,4 @@
         .testEquals();
   }
 }
+
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableSetMultimapTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableSetMultimapTest.java
index 497a67f..1b1b586 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableSetMultimapTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableSetMultimapTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.ImmutableSetMultimap.Builder;
@@ -216,10 +216,10 @@
     builder.put("a", 2);
     builder.put("b", 6);
     ImmutableSetMultimap<String, Integer> multimap = builder.build();
-    ASSERT.that(multimap.keySet()).has().exactly("d", "c", "b", "a").inOrder();
-    ASSERT.that(multimap.values()).has().exactly(2, 4, 3, 6, 5, 2).inOrder();
-    ASSERT.that(multimap.get("a")).has().exactly(5, 2).inOrder();
-    ASSERT.that(multimap.get("b")).has().exactly(3, 6).inOrder();
+    assertThat(multimap.keySet()).has().exactly("d", "c", "b", "a").inOrder();
+    assertThat(multimap.values()).has().exactly(2, 4, 3, 6, 5, 2).inOrder();
+    assertThat(multimap.get("a")).has().exactly(5, 2).inOrder();
+    assertThat(multimap.get("b")).has().exactly(3, 6).inOrder();
     assertFalse(multimap.get("a") instanceof ImmutableSortedSet);
     assertFalse(multimap.get("x") instanceof ImmutableSortedSet);
     assertFalse(multimap.asMap().get("a") instanceof ImmutableSortedSet);
@@ -241,10 +241,10 @@
     builder.put("a", 2);
     builder.put("bb", 6);
     ImmutableSetMultimap<String, Integer> multimap = builder.build();
-    ASSERT.that(multimap.keySet()).has().exactly("d", "a", "bb", "cc").inOrder();
-    ASSERT.that(multimap.values()).has().exactly(2, 5, 2, 3, 6, 4).inOrder();
-    ASSERT.that(multimap.get("a")).has().exactly(5, 2).inOrder();
-    ASSERT.that(multimap.get("bb")).has().exactly(3, 6).inOrder();
+    assertThat(multimap.keySet()).has().exactly("d", "a", "bb", "cc").inOrder();
+    assertThat(multimap.values()).has().exactly(2, 5, 2, 3, 6, 4).inOrder();
+    assertThat(multimap.get("a")).has().exactly(5, 2).inOrder();
+    assertThat(multimap.get("bb")).has().exactly(3, 6).inOrder();
     assertFalse(multimap.get("a") instanceof ImmutableSortedSet);
     assertFalse(multimap.get("x") instanceof ImmutableSortedSet);
     assertFalse(multimap.asMap().get("a") instanceof ImmutableSortedSet);
@@ -261,10 +261,10 @@
     builder.put("a", 2);
     builder.put("b", 6);
     ImmutableSetMultimap<String, Integer> multimap = builder.build();
-    ASSERT.that(multimap.keySet()).has().exactly("b", "d", "a", "c").inOrder();
-    ASSERT.that(multimap.values()).has().exactly(6, 3, 2, 5, 2, 4).inOrder();
-    ASSERT.that(multimap.get("a")).has().exactly(5, 2).inOrder();
-    ASSERT.that(multimap.get("b")).has().exactly(6, 3).inOrder();
+    assertThat(multimap.keySet()).has().exactly("b", "d", "a", "c").inOrder();
+    assertThat(multimap.values()).has().exactly(6, 3, 2, 5, 2, 4).inOrder();
+    assertThat(multimap.get("a")).has().exactly(5, 2).inOrder();
+    assertThat(multimap.get("b")).has().exactly(6, 3).inOrder();
     assertTrue(multimap.get("a") instanceof ImmutableSortedSet);
     assertEquals(Collections.reverseOrder(),
         ((ImmutableSortedSet<Integer>) multimap.get("a")).comparator());
@@ -288,10 +288,10 @@
     builder.put("a", 2);
     builder.put("b", 6);
     ImmutableSetMultimap<String, Integer> multimap = builder.build();
-    ASSERT.that(multimap.keySet()).has().exactly("d", "c", "b", "a").inOrder();
-    ASSERT.that(multimap.values()).has().exactly(2, 4, 6, 3, 5, 2).inOrder();
-    ASSERT.that(multimap.get("a")).has().exactly(5, 2).inOrder();
-    ASSERT.that(multimap.get("b")).has().exactly(6, 3).inOrder();
+    assertThat(multimap.keySet()).has().exactly("d", "c", "b", "a").inOrder();
+    assertThat(multimap.values()).has().exactly(2, 4, 6, 3, 5, 2).inOrder();
+    assertThat(multimap.get("a")).has().exactly(5, 2).inOrder();
+    assertThat(multimap.get("b")).has().exactly(6, 3).inOrder();
     assertTrue(multimap.get("a") instanceof ImmutableSortedSet);
     assertEquals(Collections.reverseOrder(),
         ((ImmutableSortedSet<Integer>) multimap.get("a")).comparator());
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableSetTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableSetTest.java
index bb71022..15cf351 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableSetTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableSetTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.ImmutableSet.Builder;
@@ -103,7 +103,7 @@
     // now we'll get the varargs overload
     ImmutableSet<String> set = ImmutableSet.of(
         "a", "b", "c", "c", "c", "c", "b", "b", "a", "a", "c", "c", "c", "a");
-    ASSERT.that(set).has().exactly("a", "b", "c").inOrder();
+    assertThat(set).has().exactly("a", "b", "c").inOrder();
   }
 
   public void testCreation_arrayOfArray() {
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedMapTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedMapTest.java
index bb65aaf..1b76d45 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedMapTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedMapTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Joiner;
@@ -611,7 +611,7 @@
   public void testHeadMapInclusive() {
     Map<String, Integer> map =
         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).headMap("three", true);
-    ASSERT.that(map.entrySet()).has().exactly(
+    assertThat(map.entrySet()).has().exactly(
         Maps.immutableEntry("one", 1),
         Maps.immutableEntry("three", 3)).inOrder();
   }
@@ -620,14 +620,14 @@
   public void testHeadMapExclusive() {
     Map<String, Integer> map =
         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).headMap("three", false);
-    ASSERT.that(map.entrySet()).has().exactly(Maps.immutableEntry("one", 1)).inOrder();
+    assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("one", 1)).inOrder();
   }
 
   @SuppressWarnings("unchecked") // varargs
   public void testTailMapInclusive() {
     Map<String, Integer> map =
         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).tailMap("three", true);
-    ASSERT.that(map.entrySet()).has().exactly(Maps.immutableEntry("three", 3),
+    assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("three", 3),
         Maps.immutableEntry("two", 2)).inOrder();
   }
 
@@ -635,21 +635,21 @@
   public void testTailMapExclusive() {
     Map<String, Integer> map =
         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).tailMap("three", false);
-    ASSERT.that(map.entrySet()).has().exactly(Maps.immutableEntry("two", 2)).inOrder();
+    assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("two", 2)).inOrder();
   }
 
   @SuppressWarnings("unchecked") // varargs
   public void testSubMapExclusiveExclusive() {
     Map<String, Integer> map =
         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).subMap("one", false, "two", false);
-    ASSERT.that(map.entrySet()).has().exactly(Maps.immutableEntry("three", 3)).inOrder();
+    assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("three", 3)).inOrder();
   }
 
   @SuppressWarnings("unchecked") // varargs
   public void testSubMapInclusiveExclusive() {
     Map<String, Integer> map =
         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).subMap("one", true, "two", false);
-    ASSERT.that(map.entrySet()).has().exactly(Maps.immutableEntry("one", 1),
+    assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("one", 1),
         Maps.immutableEntry("three", 3)).inOrder();
   }
 
@@ -657,7 +657,7 @@
   public void testSubMapExclusiveInclusive() {
     Map<String, Integer> map =
         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).subMap("one", false, "two", true);
-    ASSERT.that(map.entrySet()).has().exactly(Maps.immutableEntry("three", 3),
+    assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("three", 3),
         Maps.immutableEntry("two", 2)).inOrder();
   }
 
@@ -665,7 +665,7 @@
   public void testSubMapInclusiveInclusive() {
     Map<String, Integer> map =
         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).subMap("one", true, "two", true);
-    ASSERT.that(map.entrySet()).has().exactly(Maps.immutableEntry("one", 1),
+    assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("one", 1),
         Maps.immutableEntry("three", 3), Maps.immutableEntry("two", 2)).inOrder();
   }
 
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedSetTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedSetTest.java
index aeb3fc0..89d5448 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedSetTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedSetTest.java
@@ -16,8 +16,8 @@
 
 package com.google.common.collect;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 
@@ -145,7 +145,7 @@
   public void testSingle_headSet() {
     SortedSet<String> set = of("e");
     assertTrue(set.headSet("g") instanceof ImmutableSortedSet);
-    ASSERT.that(set.headSet("g")).has().item("e");
+    assertThat(set.headSet("g")).has().item("e");
     assertSame(of(), set.headSet("c"));
     assertSame(of(), set.headSet("e"));
   }
@@ -153,16 +153,16 @@
   public void testSingle_tailSet() {
     SortedSet<String> set = of("e");
     assertTrue(set.tailSet("c") instanceof ImmutableSortedSet);
-    ASSERT.that(set.tailSet("c")).has().item("e");
-    ASSERT.that(set.tailSet("e")).has().item("e");
+    assertThat(set.tailSet("c")).has().item("e");
+    assertThat(set.tailSet("e")).has().item("e");
     assertSame(of(), set.tailSet("g"));
   }
 
   public void testSingle_subSet() {
     SortedSet<String> set = of("e");
     assertTrue(set.subSet("c", "g") instanceof ImmutableSortedSet);
-    ASSERT.that(set.subSet("c", "g")).has().item("e");
-    ASSERT.that(set.subSet("e", "g")).has().item("e");
+    assertThat(set.subSet("c", "g")).has().item("e");
+    assertThat(set.subSet("e", "g")).has().item("e");
     assertSame(of(), set.subSet("f", "g"));
     assertSame(of(), set.subSet("c", "e"));
     assertSame(of(), set.subSet("c", "d"));
@@ -180,7 +180,7 @@
 
   public void testOf_ordering() {
     SortedSet<String> set = of("e", "a", "f", "b", "d", "c");
-    ASSERT.that(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
   }
 
   /*
@@ -229,7 +229,7 @@
 
   public void testOf_ordering_dupes() {
     SortedSet<String> set = of("e", "a", "e", "f", "b", "b", "d", "a", "c");
-    ASSERT.that(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
   }
 
   public void testOf_comparator() {
@@ -240,8 +240,8 @@
   public void testOf_headSet() {
     SortedSet<String> set = of("e", "f", "b", "d", "c");
     assertTrue(set.headSet("e") instanceof ImmutableSortedSet);
-    ASSERT.that(set.headSet("e")).has().exactly("b", "c", "d").inOrder();
-    ASSERT.that(set.headSet("g")).has().exactly("b", "c", "d", "e", "f").inOrder();
+    assertThat(set.headSet("e")).has().exactly("b", "c", "d").inOrder();
+    assertThat(set.headSet("g")).has().exactly("b", "c", "d", "e", "f").inOrder();
     assertSame(of(), set.headSet("a"));
     assertSame(of(), set.headSet("b"));
   }
@@ -249,16 +249,16 @@
   public void testOf_tailSet() {
     SortedSet<String> set = of("e", "f", "b", "d", "c");
     assertTrue(set.tailSet("e") instanceof ImmutableSortedSet);
-    ASSERT.that(set.tailSet("e")).has().exactly("e", "f").inOrder();
-    ASSERT.that(set.tailSet("a")).has().exactly("b", "c", "d", "e", "f").inOrder();
+    assertThat(set.tailSet("e")).has().exactly("e", "f").inOrder();
+    assertThat(set.tailSet("a")).has().exactly("b", "c", "d", "e", "f").inOrder();
     assertSame(of(), set.tailSet("g"));
   }
 
   public void testOf_subSet() {
     SortedSet<String> set = of("e", "f", "b", "d", "c");
     assertTrue(set.subSet("c", "e") instanceof ImmutableSortedSet);
-    ASSERT.that(set.subSet("c", "e")).has().exactly("c", "d").inOrder();
-    ASSERT.that(set.subSet("a", "g")).has().exactly("b", "c", "d", "e", "f").inOrder();
+    assertThat(set.subSet("c", "e")).has().exactly("c", "d").inOrder();
+    assertThat(set.subSet("a", "g")).has().exactly("b", "c", "d", "e", "f").inOrder();
     assertSame(of(), set.subSet("a", "b"));
     assertSame(of(), set.subSet("g", "h"));
     assertSame(of(), set.subSet("c", "c"));
@@ -284,14 +284,14 @@
   public void testExplicit_ordering() {
     SortedSet<String> set = ImmutableSortedSet.orderedBy(STRING_LENGTH).add(
         "in", "the", "quick", "jumped", "over", "a").build();
-    ASSERT.that(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
+    assertThat(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
   }
 
   public void testExplicit_ordering_dupes() {
     SortedSet<String> set = ImmutableSortedSet.orderedBy(STRING_LENGTH).add(
         "in", "the", "quick", "brown", "fox", "jumped",
         "over", "a", "lazy", "dog").build();
-    ASSERT.that(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
+    assertThat(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
   }
 
   public void testExplicit_contains() {
@@ -321,8 +321,8 @@
         "in", "the", "quick", "jumped", "over", "a").build();
     assertTrue(set.headSet("a") instanceof ImmutableSortedSet);
     assertTrue(set.headSet("fish") instanceof ImmutableSortedSet);
-    ASSERT.that(set.headSet("fish")).has().exactly("a", "in", "the").inOrder();
-    ASSERT.that(set.headSet("california")).has()
+    assertThat(set.headSet("fish")).has().exactly("a", "in", "the").inOrder();
+    assertThat(set.headSet("california")).has()
         .exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
     assertTrue(set.headSet("a").isEmpty());
     assertTrue(set.headSet("").isEmpty());
@@ -333,8 +333,8 @@
         "in", "the", "quick", "jumped", "over", "a").build();
     assertTrue(set.tailSet("california") instanceof ImmutableSortedSet);
     assertTrue(set.tailSet("fish") instanceof ImmutableSortedSet);
-    ASSERT.that(set.tailSet("fish")).has().exactly("over", "quick", "jumped").inOrder();
-    ASSERT.that(
+    assertThat(set.tailSet("fish")).has().exactly("over", "quick", "jumped").inOrder();
+    assertThat(
         set.tailSet("a")).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
     assertTrue(set.tailSet("california").isEmpty());
   }
@@ -344,8 +344,8 @@
         "in", "the", "quick", "jumped", "over", "a").build();
     assertTrue(set.subSet("the", "quick") instanceof ImmutableSortedSet);
     assertTrue(set.subSet("", "b") instanceof ImmutableSortedSet);
-    ASSERT.that(set.subSet("the", "quick")).has().exactly("the", "over").inOrder();
-    ASSERT.that(set.subSet("a", "california"))
+    assertThat(set.subSet("the", "quick")).has().exactly("the", "over").inOrder();
+    assertThat(set.subSet("a", "california"))
         .has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
     assertTrue(set.subSet("", "b").isEmpty());
     assertTrue(set.subSet("vermont", "california").isEmpty());
@@ -372,13 +372,13 @@
   public void testCopyOf_ordering() {
     SortedSet<String> set =
         copyOf(asList("e", "a", "f", "b", "d", "c"));
-    ASSERT.that(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
   }
 
   public void testCopyOf_ordering_dupes() {
     SortedSet<String> set =
         copyOf(asList("e", "a", "e", "f", "b", "b", "d", "a", "c"));
-    ASSERT.that(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
   }
 
   public void testCopyOf_subSet() {
@@ -409,13 +409,13 @@
 
   public void testCopyOf_iterator_ordering() {
     SortedSet<String> set = copyOf(asIterator("e", "a", "f", "b", "d", "c"));
-    ASSERT.that(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
   }
 
   public void testCopyOf_iterator_ordering_dupes() {
     SortedSet<String> set =
         copyOf(asIterator("e", "a", "e", "f", "b", "b", "d", "a", "c"));
-    ASSERT.that(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
   }
 
   public void testCopyOf_iterator_comparator() {
@@ -426,7 +426,7 @@
   public void testCopyOf_sortedSet_ordering() {
     SortedSet<String> set =
         copyOf(Sets.newTreeSet(asList("e", "a", "f", "b", "d", "c")));
-    ASSERT.that(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
   }
 
   public void testCopyOf_sortedSet_comparator() {
@@ -438,7 +438,7 @@
     SortedSet<String> set =
         ImmutableSortedSet.copyOf(STRING_LENGTH, asList(
             "in", "the", "quick", "jumped", "over", "a"));
-    ASSERT.that(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
+    assertThat(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
   }
 
   public void testCopyOfExplicit_ordering_dupes() {
@@ -446,7 +446,7 @@
         ImmutableSortedSet.copyOf(STRING_LENGTH, asList(
             "in", "the", "quick", "brown", "fox", "jumped", "over", "a",
             "lazy", "dog"));
-    ASSERT.that(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
+    assertThat(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
   }
 
   public void testCopyOfExplicit_comparator() {
@@ -460,7 +460,7 @@
     SortedSet<String> set =
         ImmutableSortedSet.copyOf(STRING_LENGTH, asIterator(
             "in", "the", "quick", "jumped", "over", "a"));
-    ASSERT.that(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
+    assertThat(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
   }
 
   public void testCopyOfExplicit_iterator_ordering_dupes() {
@@ -468,7 +468,7 @@
         ImmutableSortedSet.copyOf(STRING_LENGTH, asIterator(
             "in", "the", "quick", "brown", "fox", "jumped", "over", "a",
             "lazy", "dog"));
-    ASSERT.that(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
+    assertThat(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
   }
 
   public void testCopyOfExplicit_iterator_comparator() {
@@ -482,14 +482,14 @@
     SortedSet<String> input = Sets.newTreeSet(STRING_LENGTH);
     Collections.addAll(input, "in", "the", "quick", "jumped", "over", "a");
     SortedSet<String> set = copyOf(input);
-    ASSERT.that(set).has().exactly("a", "in", "jumped", "over", "quick", "the").inOrder();
+    assertThat(set).has().exactly("a", "in", "jumped", "over", "quick", "the").inOrder();
   }
 
   public void testCopyOfSorted_natural_ordering() {
     SortedSet<String> input = Sets.newTreeSet(
         asList("in", "the", "quick", "jumped", "over", "a"));
     SortedSet<String> set = ImmutableSortedSet.copyOfSorted(input);
-    ASSERT.that(set).has().exactly("a", "in", "jumped", "over", "quick", "the").inOrder();
+    assertThat(set).has().exactly("a", "in", "jumped", "over", "quick", "the").inOrder();
   }
 
   public void testCopyOfSorted_natural_comparator() {
@@ -503,7 +503,7 @@
     SortedSet<String> input = Sets.newTreeSet(STRING_LENGTH);
     Collections.addAll(input, "in", "the", "quick", "jumped", "over", "a");
     SortedSet<String> set = ImmutableSortedSet.copyOfSorted(input);
-    ASSERT.that(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
+    assertThat(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
     assertSame(STRING_LENGTH, set.comparator());
   }
 
@@ -591,7 +591,7 @@
   public void testReverseOrder() {
     SortedSet<String> set = ImmutableSortedSet.<String>reverseOrder()
         .add("a", "b", "c").build();
-    ASSERT.that(set).has().exactly("c", "b", "a").inOrder();
+    assertThat(set).has().exactly("c", "b", "a").inOrder();
     assertEquals(Ordering.natural().reverse(), set.comparator());
   }
 
@@ -606,13 +606,13 @@
   public void testSupertypeComparator() {
     SortedSet<Integer> set = new ImmutableSortedSet.Builder<Integer>(TO_STRING)
         .add(3, 12, 101, 44).build();
-    ASSERT.that(set).has().exactly(101, 12, 3, 44).inOrder();
+    assertThat(set).has().exactly(101, 12, 3, 44).inOrder();
   }
 
   public void testSupertypeComparatorSubtypeElements() {
     SortedSet<Number> set = new ImmutableSortedSet.Builder<Number>(TO_STRING)
         .add(3, 12, 101, 44).build();
-    ASSERT.that(set).has().exactly(101, 12, 3, 44).inOrder();
+    assertThat(set).has().exactly(101, 12, 3, 44).inOrder();
   }
 
   @Override <E extends Comparable<E>> ImmutableSortedSet.Builder<E> builder() {
@@ -724,7 +724,7 @@
   private static void assertNotEqualLenient(
       TreeSet<?> unexpected, SortedSet<?> actual) {
     try {
-      ASSERT.that(actual).isNotEqualTo(unexpected);
+      assertThat(actual).isNotEqualTo(unexpected);
     } catch (ClassCastException accepted) {
     }
   }
@@ -734,7 +734,7 @@
     ImmutableSortedSet<String> set = ImmutableSortedSet.copyOf(strings);
     Arrays.sort(strings);
     for (int i = 0; i < strings.length; i++) {
-      ASSERT.that(set.headSet(strings[i], true))
+      assertThat(set.headSet(strings[i], true))
           .has().exactlyAs(sortedNumberNames(0, i + 1)).inOrder();
     }
   }
@@ -744,7 +744,7 @@
     ImmutableSortedSet<String> set = ImmutableSortedSet.copyOf(strings);
     Arrays.sort(strings);
     for (int i = 0; i < strings.length; i++) {
-      ASSERT.that(set.headSet(strings[i], false)).has().exactlyAs(
+      assertThat(set.headSet(strings[i], false)).has().exactlyAs(
           sortedNumberNames(0, i)).inOrder();
     }
   }
@@ -754,7 +754,7 @@
     ImmutableSortedSet<String> set = ImmutableSortedSet.copyOf(strings);
     Arrays.sort(strings);
     for (int i = 0; i < strings.length; i++) {
-      ASSERT.that(set.tailSet(strings[i], true)).has().exactlyAs(
+      assertThat(set.tailSet(strings[i], true)).has().exactlyAs(
           sortedNumberNames(i, strings.length)).inOrder();
     }
   }
@@ -764,7 +764,7 @@
     ImmutableSortedSet<String> set = ImmutableSortedSet.copyOf(strings);
     Arrays.sort(strings);
     for (int i = 0; i < strings.length; i++) {
-      ASSERT.that(set.tailSet(strings[i], false)).has().exactlyAs(
+      assertThat(set.tailSet(strings[i], false)).has().exactlyAs(
           sortedNumberNames(i + 1, strings.length)).inOrder();
     }
   }
@@ -775,7 +775,7 @@
     Arrays.sort(strings);
     for (int i = 0; i < strings.length; i++) {
       for (int j = i; j < strings.length; j++) {
-        ASSERT.that(set.subSet(strings[i], false, strings[j], false))
+        assertThat(set.subSet(strings[i], false, strings[j], false))
             .has().exactlyAs(sortedNumberNames(Math.min(i + 1, j), j)).inOrder();
       }
     }
@@ -787,7 +787,7 @@
     Arrays.sort(strings);
     for (int i = 0; i < strings.length; i++) {
       for (int j = i; j < strings.length; j++) {
-        ASSERT.that(set.subSet(strings[i], true, strings[j], false))
+        assertThat(set.subSet(strings[i], true, strings[j], false))
             .has().exactlyAs(sortedNumberNames(i, j)).inOrder();
       }
     }
@@ -799,7 +799,7 @@
     Arrays.sort(strings);
     for (int i = 0; i < strings.length; i++) {
       for (int j = i; j < strings.length; j++) {
-        ASSERT.that(set.subSet(strings[i], false, strings[j], true))
+        assertThat(set.subSet(strings[i], false, strings[j], true))
             .has().exactlyAs(sortedNumberNames(i + 1, j + 1)).inOrder();
       }
     }
@@ -811,7 +811,7 @@
     Arrays.sort(strings);
     for (int i = 0; i < strings.length; i++) {
       for (int j = i; j < strings.length; j++) {
-        ASSERT.that(set.subSet(strings[i], true, strings[j], true))
+        assertThat(set.subSet(strings[i], true, strings[j], true))
             .has().exactlyAs(sortedNumberNames(i, j + 1)).inOrder();
       }
     }
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableTableTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableTableTest.java
index e067e7e..c602d65 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableTableTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ImmutableTableTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 
@@ -184,8 +184,8 @@
     validateTableCopies(table);
     // Even though rowKeySet, columnKeySet, and cellSet have the same
     // iteration ordering, row has an inconsistent ordering.
-    ASSERT.that(table.row('b').keySet()).has().exactly(1, 2).inOrder();
-    ASSERT.that(ImmutableTable.copyOf(table).row('b').keySet())
+    assertThat(table.row('b').keySet()).has().exactly(1, 2).inOrder();
+    assertThat(ImmutableTable.copyOf(table).row('b').keySet())
         .has().exactly(2, 1).inOrder();
   }
 
@@ -227,10 +227,10 @@
         = builder.orderRowsBy(Ordering.natural())
             .orderColumnsBy(Ordering.natural())
             .putAll(table).build();
-    ASSERT.that(copy.rowKeySet()).has().exactly('a', 'b').inOrder();
-    ASSERT.that(copy.columnKeySet()).has().exactly(1, 2).inOrder();
-    ASSERT.that(copy.values()).has().exactly("baz", "bar", "foo").inOrder();
-    ASSERT.that(copy.row('b').keySet()).has().exactly(1, 2).inOrder();
+    assertThat(copy.rowKeySet()).has().exactly('a', 'b').inOrder();
+    assertThat(copy.columnKeySet()).has().exactly(1, 2).inOrder();
+    assertThat(copy.values()).has().exactly("baz", "bar", "foo").inOrder();
+    assertThat(copy.row('b').keySet()).has().exactly(1, 2).inOrder();
   }
 
   public void testBuilder_orderRowsAndColumnsBy_sparse() {
@@ -248,12 +248,12 @@
     builder.put('r', 4, "foo");
     builder.put('x', 5, "bar");
     Table<Character, Integer, String> table = builder.build();
-    ASSERT.that(table.rowKeySet()).has().exactly('b', 'c', 'e', 'r', 'x').inOrder();
-    ASSERT.that(table.columnKeySet()).has().exactly(0, 1, 2, 3, 4, 5, 7).inOrder();
-    ASSERT.that(table.values()).has().exactly("cat", "axe", "baz", "tub",
+    assertThat(table.rowKeySet()).has().exactly('b', 'c', 'e', 'r', 'x').inOrder();
+    assertThat(table.columnKeySet()).has().exactly(0, 1, 2, 3, 4, 5, 7).inOrder();
+    assertThat(table.values()).has().exactly("cat", "axe", "baz", "tub",
         "dog", "bar", "foo", "foo", "bar").inOrder();
-    ASSERT.that(table.row('c').keySet()).has().exactly(0, 3).inOrder();
-    ASSERT.that(table.column(5).keySet()).has().exactly('e', 'x').inOrder();
+    assertThat(table.row('c').keySet()).has().exactly(0, 3).inOrder();
+    assertThat(table.column(5).keySet()).has().exactly('e', 'x').inOrder();
   }
 
   public void testBuilder_orderRowsAndColumnsBy_dense() {
@@ -270,12 +270,12 @@
     builder.put('a', 2, "bar");
     builder.put('a', 1, "baz");
     Table<Character, Integer, String> table = builder.build();
-    ASSERT.that(table.rowKeySet()).has().exactly('a', 'b', 'c').inOrder();
-    ASSERT.that(table.columnKeySet()).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(table.values()).has().exactly("baz", "bar", "foo", "dog",
+    assertThat(table.rowKeySet()).has().exactly('a', 'b', 'c').inOrder();
+    assertThat(table.columnKeySet()).has().exactly(1, 2, 3).inOrder();
+    assertThat(table.values()).has().exactly("baz", "bar", "foo", "dog",
         "cat", "baz", "bar", "foo").inOrder();
-    ASSERT.that(table.row('c').keySet()).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(table.column(1).keySet()).has().exactly('a', 'b', 'c').inOrder();
+    assertThat(table.row('c').keySet()).has().exactly(1, 2, 3).inOrder();
+    assertThat(table.column(1).keySet()).has().exactly('a', 'b', 'c').inOrder();
   }
 
   public void testBuilder_orderRowsBy_sparse() {
@@ -292,8 +292,8 @@
     builder.put('r', 4, "foo");
     builder.put('x', 5, "bar");
     Table<Character, Integer, String> table = builder.build();
-    ASSERT.that(table.rowKeySet()).has().exactly('b', 'c', 'e', 'r', 'x').inOrder();
-    ASSERT.that(table.column(5).keySet()).has().exactly('e', 'x').inOrder();
+    assertThat(table.rowKeySet()).has().exactly('b', 'c', 'e', 'r', 'x').inOrder();
+    assertThat(table.column(5).keySet()).has().exactly('e', 'x').inOrder();
   }
 
   public void testBuilder_orderRowsBy_dense() {
@@ -309,8 +309,8 @@
     builder.put('a', 2, "bar");
     builder.put('a', 1, "baz");
     Table<Character, Integer, String> table = builder.build();
-    ASSERT.that(table.rowKeySet()).has().exactly('a', 'b', 'c').inOrder();
-    ASSERT.that(table.column(1).keySet()).has().exactly('a', 'b', 'c').inOrder();
+    assertThat(table.rowKeySet()).has().exactly('a', 'b', 'c').inOrder();
+    assertThat(table.column(1).keySet()).has().exactly('a', 'b', 'c').inOrder();
   }
 
   public void testBuilder_orderColumnsBy_sparse() {
@@ -327,8 +327,8 @@
     builder.put('r', 4, "foo");
     builder.put('x', 5, "bar");
     Table<Character, Integer, String> table = builder.build();
-    ASSERT.that(table.columnKeySet()).has().exactly(0, 1, 2, 3, 4, 5, 7).inOrder();
-    ASSERT.that(table.row('c').keySet()).has().exactly(0, 3).inOrder();
+    assertThat(table.columnKeySet()).has().exactly(0, 1, 2, 3, 4, 5, 7).inOrder();
+    assertThat(table.row('c').keySet()).has().exactly(0, 3).inOrder();
   }
 
   public void testBuilder_orderColumnsBy_dense() {
@@ -344,8 +344,8 @@
     builder.put('a', 2, "bar");
     builder.put('a', 1, "baz");
     Table<Character, Integer, String> table = builder.build();
-    ASSERT.that(table.columnKeySet()).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(table.row('c').keySet()).has().exactly(1, 2, 3).inOrder();
+    assertThat(table.columnKeySet()).has().exactly(1, 2, 3).inOrder();
+    assertThat(table.row('c').keySet()).has().exactly(1, 2, 3).inOrder();
   }
 }
 
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/IterablesTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/IterablesTest.java
index 8ee393e..5d0b304 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/IterablesTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/IterablesTest.java
@@ -20,9 +20,9 @@
 import static com.google.common.collect.Lists.newArrayList;
 import static com.google.common.collect.Sets.newLinkedHashSet;
 import static com.google.common.collect.testing.IteratorFeature.UNMODIFIABLE;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
 import static java.util.Collections.emptyList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Function;
@@ -374,7 +374,7 @@
     int n = 4;
     Iterable<Integer> repeated
         = Iterables.concat(Collections.nCopies(n, iterable));
-    ASSERT.that(repeated).iteratesOverSequence(
+    assertThat(repeated).iteratesAs(
         1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3);
   }
 
@@ -451,7 +451,7 @@
     List<String> freshlyAdded = newArrayList("freshly", "added");
 
     boolean changed = Iterables.addAll(alreadyThere, freshlyAdded);
-    ASSERT.that(alreadyThere).has().exactly(
+    assertThat(alreadyThere).has().exactly(
         "already", "there", "freshly", "added").inOrder();
     assertTrue(changed);
   }
@@ -603,7 +603,7 @@
     Iterable<String> tail = skip(set, 1);
     set.remove("b");
     set.addAll(newArrayList("A", "B", "C"));
-    ASSERT.that(tail).iteratesOverSequence("c", "A", "B", "C");
+    assertThat(tail).iteratesAs("c", "A", "B", "C");
   }
 
   public void testSkip_structurallyModifiedSkipSomeList() throws Exception {
@@ -611,7 +611,7 @@
     Iterable<String> tail = skip(list, 1);
     list.subList(1, 3).clear();
     list.addAll(0, newArrayList("A", "B", "C"));
-    ASSERT.that(tail).iteratesOverSequence("B", "C", "a");
+    assertThat(tail).iteratesAs("B", "C", "a");
   }
 
   public void testSkip_structurallyModifiedSkipAll() throws Exception {
@@ -1042,16 +1042,16 @@
     assertEquals("Iterables.consumingIterable(...)", consumingIterable.toString());
     Iterator<String> consumingIterator = consumingIterable.iterator();
 
-    ASSERT.that(list).has().exactly("a", "b").inOrder();
+    assertThat(list).has().exactly("a", "b").inOrder();
 
     assertTrue(consumingIterator.hasNext());
-    ASSERT.that(list).has().exactly("a", "b").inOrder();
+    assertThat(list).has().exactly("a", "b").inOrder();
     assertEquals("a", consumingIterator.next());
-    ASSERT.that(list).has().item("b");
+    assertThat(list).has().item("b");
 
     assertTrue(consumingIterator.hasNext());
     assertEquals("b", consumingIterator.next());
-    ASSERT.that(list).isEmpty();
+    assertThat(list).isEmpty();
 
     assertFalse(consumingIterator.hasNext());
   }
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/IteratorsTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/IteratorsTest.java
index d515fba..38bb635 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/IteratorsTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/IteratorsTest.java
@@ -20,8 +20,8 @@
 import static com.google.common.collect.Iterators.get;
 import static com.google.common.collect.Iterators.getLast;
 import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Function;
@@ -613,7 +613,7 @@
 
     boolean changed = Iterators.addAll(alreadyThere,
                                        Iterators.<String>emptyIterator());
-    ASSERT.that(alreadyThere).has().exactly("already", "there").inOrder();
+    assertThat(alreadyThere).has().exactly("already", "there").inOrder();
     assertFalse(changed);
   }
 
@@ -623,7 +623,7 @@
 
     boolean changed = Iterators.addAll(alreadyThere, freshlyAdded.iterator());
 
-    ASSERT.that(alreadyThere).has().exactly("already", "there", "freshly", "added");
+    assertThat(alreadyThere).has().exactly("already", "there", "freshly", "added");
     assertTrue(changed);
   }
 
@@ -633,7 +633,7 @@
     List<String> oneMore = Lists.newArrayList("there");
 
     boolean changed = Iterators.addAll(alreadyThere, oneMore.iterator());
-    ASSERT.that(alreadyThere).has().exactly("already", "there").inOrder();
+    assertThat(alreadyThere).has().exactly("already", "there").inOrder();
     assertFalse(changed);
   }
 
@@ -1229,16 +1229,16 @@
 
     assertEquals("Iterators.consumingIterator(...)", consumingIterator.toString());
 
-    ASSERT.that(list).has().exactly("a", "b").inOrder();
+    assertThat(list).has().exactly("a", "b").inOrder();
 
     assertTrue(consumingIterator.hasNext());
-    ASSERT.that(list).has().exactly("a", "b").inOrder();
+    assertThat(list).has().exactly("a", "b").inOrder();
     assertEquals("a", consumingIterator.next());
-    ASSERT.that(list).has().item("b");
+    assertThat(list).has().item("b");
 
     assertTrue(consumingIterator.hasNext());
     assertEquals("b", consumingIterator.next());
-    ASSERT.that(list).isEmpty();
+    assertThat(list).isEmpty();
 
     assertFalse(consumingIterator.hasNext());
   }
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/LinkedHashMultimapTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/LinkedHashMultimapTest.java
index 81e68c0..05d6650 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/LinkedHashMultimapTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/LinkedHashMultimapTest.java
@@ -16,8 +16,8 @@
 
 package com.google.common.collect;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.testing.EqualsTester;
@@ -88,12 +88,12 @@
   }
 
   private void assertOrderingReadOnly(Multimap<String, Integer> multimap) {
-    ASSERT.that(multimap.get("foo")).has().exactly(5, 3).inOrder();
-    ASSERT.that(multimap.get("bar")).has().exactly(4, 1).inOrder();
-    ASSERT.that(multimap.get("cow")).has().item(2);
+    assertThat(multimap.get("foo")).has().exactly(5, 3).inOrder();
+    assertThat(multimap.get("bar")).has().exactly(4, 1).inOrder();
+    assertThat(multimap.get("cow")).has().item(2);
 
-    ASSERT.that(multimap.keySet()).has().exactly("foo", "bar", "cow").inOrder();
-    ASSERT.that(multimap.values()).has().exactly(5, 4, 3, 2, 1).inOrder();
+    assertThat(multimap.keySet()).has().exactly("foo", "bar", "cow").inOrder();
+    assertThat(multimap.values()).has().exactly(5, 4, 3, 2, 1).inOrder();
 
     Iterator<Map.Entry<String, Integer>> entryIterator =
         multimap.entries().iterator();
@@ -107,28 +107,28 @@
         multimap.asMap().entrySet().iterator();
     Map.Entry<String, Collection<Integer>> entry = collectionIterator.next();
     assertEquals("foo", entry.getKey());
-    ASSERT.that(entry.getValue()).has().exactly(5, 3).inOrder();
+    assertThat(entry.getValue()).has().exactly(5, 3).inOrder();
     entry = collectionIterator.next();
     assertEquals("bar", entry.getKey());
-    ASSERT.that(entry.getValue()).has().exactly(4, 1).inOrder();
+    assertThat(entry.getValue()).has().exactly(4, 1).inOrder();
     entry = collectionIterator.next();
     assertEquals("cow", entry.getKey());
-    ASSERT.that(entry.getValue()).has().item(2);
+    assertThat(entry.getValue()).has().item(2);
   }
 
   public void testOrderingUpdates() {
     Multimap<String, Integer> multimap = initializeMultimap5();
 
-    ASSERT.that(multimap.replaceValues("foo", asList(6, 7))).has().exactly(5, 3).inOrder();
-    ASSERT.that(multimap.keySet()).has().exactly("foo", "bar", "cow").inOrder();
-    ASSERT.that(multimap.removeAll("foo")).has().exactly(6, 7).inOrder();
-    ASSERT.that(multimap.keySet()).has().exactly("bar", "cow").inOrder();
+    assertThat(multimap.replaceValues("foo", asList(6, 7))).has().exactly(5, 3).inOrder();
+    assertThat(multimap.keySet()).has().exactly("foo", "bar", "cow").inOrder();
+    assertThat(multimap.removeAll("foo")).has().exactly(6, 7).inOrder();
+    assertThat(multimap.keySet()).has().exactly("bar", "cow").inOrder();
     assertTrue(multimap.remove("bar", 4));
-    ASSERT.that(multimap.keySet()).has().exactly("bar", "cow").inOrder();
+    assertThat(multimap.keySet()).has().exactly("bar", "cow").inOrder();
     assertTrue(multimap.remove("bar", 1));
-    ASSERT.that(multimap.keySet()).has().item("cow");
+    assertThat(multimap.keySet()).has().item("cow");
     multimap.put("bar", 9);
-    ASSERT.that(multimap.keySet()).has().exactly("cow", "bar").inOrder();
+    assertThat(multimap.keySet()).has().exactly("cow", "bar").inOrder();
   }
 
   public void testToStringNullExact() {
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/LinkedHashMultisetTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/LinkedHashMultisetTest.java
index 4dc51a6..bfab499 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/LinkedHashMultisetTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/LinkedHashMultisetTest.java
@@ -16,8 +16,8 @@
 
 package com.google.common.collect;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.testing.google.TestStringMultisetGenerator;
@@ -97,14 +97,14 @@
     ms.add("a");
     ms.add("b", 2);
     ms.add("c");
-    ASSERT.that(ms.elementSet()).has().exactly("a", "b", "c").inOrder();
+    assertThat(ms.elementSet()).has().exactly("a", "b", "c").inOrder();
     ms.remove("b");
-    ASSERT.that(ms.elementSet()).has().exactly("a", "b", "c").inOrder();
+    assertThat(ms.elementSet()).has().exactly("a", "b", "c").inOrder();
     ms.add("b");
-    ASSERT.that(ms.elementSet()).has().exactly("a", "b", "c").inOrder();
+    assertThat(ms.elementSet()).has().exactly("a", "b", "c").inOrder();
     ms.remove("b", 2);
     ms.add("b");
-    ASSERT.that(ms.elementSet()).has().exactly("a", "c", "b").inOrder();
+    assertThat(ms.elementSet()).has().exactly("a", "c", "b").inOrder();
   }
 }
 
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/LinkedListMultimapTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/LinkedListMultimapTest.java
index 27a4c66..469b1b6 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/LinkedListMultimapTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/LinkedListMultimapTest.java
@@ -16,8 +16,8 @@
 
 package com.google.common.collect;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.testing.EqualsTester;
@@ -89,7 +89,7 @@
     LinkedListMultimap<String, Integer> copy =
         LinkedListMultimap.create(multimap);
     assertEquals(multimap, copy);
-    ASSERT.that(copy.entries()).has().exactlyAs(multimap.entries()).inOrder();
+    assertThat(copy.entries()).has().exactlyAs(multimap.entries()).inOrder();
   }
 
   public void testCreateFromSize() {
@@ -183,10 +183,10 @@
     List<Integer> foos = map.get("foo");
     Collection<Integer> values = map.values();
     assertEquals(asList(1, 2), foos);
-    ASSERT.that(values).has().exactly(1, 2, 3).inOrder();
+    assertThat(values).has().exactly(1, 2, 3).inOrder();
     map.clear();
     assertEquals(Collections.emptyList(), foos);
-    ASSERT.that(values).isEmpty();
+    assertThat(values).isEmpty();
     assertEquals("[]", map.entries().toString());
     assertEquals("{}", map.toString());
   }
@@ -210,7 +210,7 @@
     map.put("bar", 4);
     assertEquals("[bar=1, foo=2, bar=3, bar=4]",
         map.entries().toString());
-    ASSERT.that(map.keys()).has().exactly("bar", "foo", "bar", "bar").inOrder();
+    assertThat(map.keys()).has().exactly("bar", "foo", "bar", "bar").inOrder();
     map.keys().remove("bar"); // bar is no longer the first key!
     assertEquals("{foo=[2], bar=[3, 4]}", map.toString());
   }
@@ -256,7 +256,7 @@
         = map.asMap().entrySet().iterator();
     Map.Entry<String, Collection<Integer>> entry = entries.next();
     assertEquals("bar", entry.getKey());
-    ASSERT.that(entry.getValue()).has().exactly(1, 3).inOrder();
+    assertThat(entry.getValue()).has().exactly(1, 3).inOrder();
     try {
       entry.setValue(Arrays.<Integer>asList());
       fail("UnsupportedOperationException expected");
@@ -264,7 +264,7 @@
     entries.remove(); // clear
     entry = entries.next();
     assertEquals("foo", entry.getKey());
-    ASSERT.that(entry.getValue()).has().item(2);
+    assertThat(entry.getValue()).has().item(2);
     assertFalse(entries.hasNext());
     assertEquals("{foo=[2]}", map.toString());
   }
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ListsTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ListsTest.java
index 2ec35ce..dcd52d5 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ListsTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ListsTest.java
@@ -17,9 +17,9 @@
 package com.google.common.collect;
 
 import static com.google.common.collect.testing.IteratorFeature.UNMODIFIABLE;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
 import static java.util.Collections.singletonList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Function;
@@ -214,7 +214,7 @@
   }
 
   private void checkFooBarBazList(List<String> list) {
-    ASSERT.that(list).has().exactly("foo", "bar", "baz").inOrder();
+    assertThat(list).has().exactly("foo", "bar", "baz").inOrder();
     assertEquals(3, list.size());
     assertIndexIsOutOfBounds(list, -1);
     assertEquals("foo", list.get(0));
@@ -225,7 +225,7 @@
 
   public void testAsList1Small() {
     List<String> list = Lists.asList("foo", new String[0]);
-    ASSERT.that(list).has().item("foo");
+    assertThat(list).has().item("foo");
     assertEquals(1, list.size());
     assertIndexIsOutOfBounds(list, -1);
     assertEquals("foo", list.get(0));
@@ -308,24 +308,24 @@
 
   @SuppressWarnings("unchecked") // varargs!
   public void testCartesianProduct_binary1x1() {
-    ASSERT.that(Lists.cartesianProduct(list(1), list(2))).has().item(list(1, 2));
+    assertThat(Lists.cartesianProduct(list(1), list(2))).has().item(list(1, 2));
   }
 
   @SuppressWarnings("unchecked") // varargs!
   public void testCartesianProduct_binary1x2() {
-    ASSERT.that(Lists.cartesianProduct(list(1), list(2, 3)))
+    assertThat(Lists.cartesianProduct(list(1), list(2, 3)))
         .has().exactly(list(1, 2), list(1, 3)).inOrder();
   }
 
   @SuppressWarnings("unchecked") // varargs!
   public void testCartesianProduct_binary2x2() {
-    ASSERT.that(Lists.cartesianProduct(list(1, 2), list(3, 4)))
+    assertThat(Lists.cartesianProduct(list(1, 2), list(3, 4)))
         .has().exactly(list(1, 3), list(1, 4), list(2, 3), list(2, 4)).inOrder();
   }
 
   @SuppressWarnings("unchecked") // varargs!
   public void testCartesianProduct_2x2x2() {
-    ASSERT.that(Lists.cartesianProduct(list(0, 1), list(0, 1), list(0, 1))).has().exactly(
+    assertThat(Lists.cartesianProduct(list(0, 1), list(0, 1), list(0, 1))).has().exactly(
         list(0, 0, 0), list(0, 0, 1), list(0, 1, 0), list(0, 1, 1),
         list(1, 0, 0), list(1, 0, 1), list(1, 1, 0), list(1, 1, 1)).inOrder();
   }
@@ -350,7 +350,7 @@
     List<Object> exp3 = list((Object) 2, "3");
     List<Object> exp4 = list((Object) 2, "4");
 
-    ASSERT.that(Lists.<Object>cartesianProduct(x, y))
+    assertThat(Lists.<Object>cartesianProduct(x, y))
         .has().exactly(exp1, exp2, exp3, exp4).inOrder();
   }
 
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/MapConstraintsTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/MapConstraintsTest.java
index c199fdd..928f809 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/MapConstraintsTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/MapConstraintsTest.java
@@ -17,7 +17,7 @@
 package com.google.common.collect;
 
 import static com.google.common.collect.testing.Helpers.nefariousMapEntry;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Supplier;
@@ -113,7 +113,7 @@
     assertFalse(map.values() instanceof Serializable);
     assertEquals(map.toString(), constrained.toString());
     assertEquals(map.hashCode(), constrained.hashCode());
-    ASSERT.that(map.entrySet()).has().exactly(
+    assertThat(map.entrySet()).has().exactly(
         Maps.immutableEntry(TEST_KEY, TEST_VALUE),
         Maps.immutableEntry("foo", 1),
         Maps.immutableEntry("bar", 2),
@@ -161,7 +161,7 @@
     assertEquals(map.values(), constrained.values());
     assertEquals(map.toString(), constrained.toString());
     assertEquals(map.hashCode(), constrained.hashCode());
-    ASSERT.that(map.entrySet()).has().exactly(
+    assertThat(map.entrySet()).has().exactly(
         Maps.immutableEntry(TEST_KEY, TEST_VALUE),
         Maps.immutableEntry("foo", 1),
         Maps.immutableEntry("bar", 2),
@@ -228,9 +228,9 @@
         .put("dag", 11).build());
     assertTrue(multimap.equals(constrained));
     assertTrue(constrained.equals(multimap));
-    ASSERT.that(ImmutableList.copyOf(multimap.entries()))
-        .is(ImmutableList.copyOf(constrained.entries()));
-    ASSERT.that(constrained.asMap().get("foo")).has().item(1);
+    assertThat(ImmutableList.copyOf(multimap.entries())).isEqualTo(
+        ImmutableList.copyOf(constrained.entries()));
+    assertThat(constrained.asMap().get("foo")).has().item(1);
     assertNull(constrained.asMap().get("missing"));
     assertEquals(multimap.asMap(), constrained.asMap());
     assertEquals(multimap.values(), constrained.values());
@@ -238,7 +238,7 @@
     assertEquals(multimap.keySet(), constrained.keySet());
     assertEquals(multimap.toString(), constrained.toString());
     assertEquals(multimap.hashCode(), constrained.hashCode());
-    ASSERT.that(multimap.entries()).has().exactly(
+    assertThat(multimap.entries()).has().exactly(
         Maps.immutableEntry(TEST_KEY, TEST_VALUE),
         Maps.immutableEntry("foo", 1),
         Maps.immutableEntry("bar", 2),
@@ -405,8 +405,8 @@
           .add(TEST_VALUE);
       fail("TestValueException expected");
     } catch (TestValueException expected) {}
-    ASSERT.that(ImmutableList.copyOf(multimap.entries()))
-        .is(ImmutableList.copyOf(constrained.entries()));
+    assertThat(ImmutableList.copyOf(multimap.entries())).isEqualTo(
+        ImmutableList.copyOf(constrained.entries()));
     assertEquals(multimap.asMap(), constrained.asMap());
     assertEquals(multimap.values(), constrained.values());
     assertEquals(multimap.keys(), constrained.keys());
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/MapsTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/MapsTest.java
index 63e62fc..f2b3538 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/MapsTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/MapsTest.java
@@ -19,7 +19,7 @@
 import static com.google.common.collect.Maps.transformEntries;
 import static com.google.common.collect.Maps.transformValues;
 import static com.google.common.collect.testing.Helpers.mapEntry;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Converter;
@@ -183,9 +183,9 @@
     assertEquals(Collections.emptyMap(), map);
     map.put(new Derived("foo"), 1);
     map.put(new Derived("bar"), 2);
-    ASSERT.that(map.keySet()).has().exactly(
+    assertThat(map.keySet()).has().exactly(
         new Derived("bar"), new Derived("foo")).inOrder();
-    ASSERT.that(map.values()).has().exactly(2, 1).inOrder();
+    assertThat(map.values()).has().exactly(2, 1).inOrder();
     assertNull(map.comparator());
   }
 
@@ -194,9 +194,9 @@
     assertEquals(Collections.emptyMap(), map);
     map.put(new LegacyComparable("foo"), 1);
     map.put(new LegacyComparable("bar"), 2);
-    ASSERT.that(map.keySet()).has().exactly(
+    assertThat(map.keySet()).has().exactly(
         new LegacyComparable("bar"), new LegacyComparable("foo")).inOrder();
-    ASSERT.that(map.values()).has().exactly(2, 1).inOrder();
+    assertThat(map.values()).has().exactly(2, 1).inOrder();
     assertNull(map.comparator());
   }
 
@@ -460,13 +460,13 @@
     SortedMapDifference<Integer, String> diff1 =
         Maps.difference(left, right);
     assertFalse(diff1.areEqual());
-    ASSERT.that(diff1.entriesOnlyOnLeft().entrySet()).has().exactly(
+    assertThat(diff1.entriesOnlyOnLeft().entrySet()).has().exactly(
         Maps.immutableEntry(4, "d"), Maps.immutableEntry(2, "b")).inOrder();
-    ASSERT.that(diff1.entriesOnlyOnRight().entrySet()).has().item(
+    assertThat(diff1.entriesOnlyOnRight().entrySet()).has().item(
         Maps.immutableEntry(6, "z"));
-    ASSERT.that(diff1.entriesInCommon().entrySet()).has().item(
+    assertThat(diff1.entriesInCommon().entrySet()).has().item(
         Maps.immutableEntry(1, "a"));
-    ASSERT.that(diff1.entriesDiffering().entrySet()).has().exactly(
+    assertThat(diff1.entriesDiffering().entrySet()).has().exactly(
         Maps.immutableEntry(5, ValueDifferenceImpl.create("e", "g")),
         Maps.immutableEntry(3, ValueDifferenceImpl.create("c", "f"))).inOrder();
     assertEquals("not equal: only on left={4=d, 2=b}: only on right={6=z}: "
@@ -475,11 +475,11 @@
     SortedMapDifference<Integer, String> diff2 =
         Maps.difference(right, left);
     assertFalse(diff2.areEqual());
-    ASSERT.that(diff2.entriesOnlyOnLeft().entrySet()).has().item(
+    assertThat(diff2.entriesOnlyOnLeft().entrySet()).has().item(
         Maps.immutableEntry(6, "z"));
-    ASSERT.that(diff2.entriesOnlyOnRight().entrySet()).has().exactly(
+    assertThat(diff2.entriesOnlyOnRight().entrySet()).has().exactly(
         Maps.immutableEntry(2, "b"), Maps.immutableEntry(4, "d")).inOrder();
-    ASSERT.that(diff1.entriesInCommon().entrySet()).has().item(
+    assertThat(diff1.entriesInCommon().entrySet()).has().item(
         Maps.immutableEntry(1, "a"));
     assertEquals(ImmutableMap.of(
             3, ValueDifferenceImpl.create("f", "c"),
@@ -499,13 +499,13 @@
         Maps.difference(left, right);
     left.put(6, "z");
     assertFalse(diff1.areEqual());
-    ASSERT.that(diff1.entriesOnlyOnLeft().entrySet()).has().exactly(
+    assertThat(diff1.entriesOnlyOnLeft().entrySet()).has().exactly(
         Maps.immutableEntry(2, "b"), Maps.immutableEntry(4, "d")).inOrder();
-    ASSERT.that(diff1.entriesOnlyOnRight().entrySet()).has().item(
+    assertThat(diff1.entriesOnlyOnRight().entrySet()).has().item(
         Maps.immutableEntry(6, "z"));
-    ASSERT.that(diff1.entriesInCommon().entrySet()).has().item(
+    assertThat(diff1.entriesInCommon().entrySet()).has().item(
         Maps.immutableEntry(1, "a"));
-    ASSERT.that(diff1.entriesDiffering().entrySet()).has().exactly(
+    assertThat(diff1.entriesDiffering().entrySet()).has().exactly(
         Maps.immutableEntry(3, ValueDifferenceImpl.create("c", "f")),
         Maps.immutableEntry(5, ValueDifferenceImpl.create("e", "g"))).inOrder();
     try {
@@ -562,7 +562,7 @@
     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
     assertEquals(Integer.valueOf(5), map.get("three"));
     assertNull(map.get("five"));
-    ASSERT.that(map.entrySet()).has().exactly(
+    assertThat(map.entrySet()).has().exactly(
         mapEntry("one", 3),
         mapEntry("two", 3),
         mapEntry("three", 5)).inOrder();
@@ -585,13 +585,13 @@
     Map<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION);
     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
     assertEquals(Integer.valueOf(3), map.remove("two"));
-    ASSERT.that(strings).has().exactly("one", "three").inOrder();
+    assertThat(strings).has().exactly("one", "three").inOrder();
   }
 
   public void testAsMapEmpty() {
     Set<String> strings = ImmutableSet.of();
     Map<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION);
-    ASSERT.that(map.entrySet()).isEmpty();
+    assertThat(map.entrySet()).isEmpty();
     assertTrue(map.isEmpty());
     assertNull(map.get("five"));
   }
@@ -618,14 +618,14 @@
     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
     assertEquals(Integer.valueOf(5), map.get("three"));
     assertNull(map.get("five"));
-    ASSERT.that(map.entrySet()).has().exactly(
+    assertThat(map.entrySet()).has().exactly(
         mapEntry("one", 3),
         mapEntry("three", 5),
         mapEntry("two", 3)).inOrder();
-    ASSERT.that(map.tailMap("onea").entrySet()).has().exactly(
+    assertThat(map.tailMap("onea").entrySet()).has().exactly(
         mapEntry("three", 5),
         mapEntry("two", 3)).inOrder();
-    ASSERT.that(map.subMap("one", "two").entrySet()).has().exactly(
+    assertThat(map.subMap("one", "two").entrySet()).has().exactly(
         mapEntry("one", 3),
         mapEntry("three", 5)).inOrder();
   }
@@ -651,7 +651,7 @@
     assertEquals(
         ImmutableSortedMap.of("five", 4, "four", 4, "three", 5),
         headMap);
-    ASSERT.that(map.entrySet()).has().exactly(
+    assertThat(map.entrySet()).has().exactly(
         mapEntry("five", 4),
         mapEntry("four", 4),
         mapEntry("three", 5),
@@ -664,7 +664,7 @@
     SortedMap<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION);
     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
     assertEquals(Integer.valueOf(3), map.remove("two"));
-    ASSERT.that(strings).has().exactly("one", "three").inOrder();
+    assertThat(strings).has().exactly("one", "three").inOrder();
   }
 
   public void testAsMapSortedSubViewKeySetsDoNotSupportAdd() {
@@ -695,7 +695,7 @@
   public void testAsMapSortedEmpty() {
     SortedSet<String> strings = new NonNavigableSortedSet();
     SortedMap<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION);
-    ASSERT.that(map.entrySet()).isEmpty();
+    assertThat(map.entrySet()).isEmpty();
     assertTrue(map.isEmpty());
     assertNull(map.get("five"));
   }
@@ -704,7 +704,7 @@
     Iterable<String> strings = ImmutableList.of("one", "two", "three");
     ImmutableMap<String, Integer> map = Maps.toMap(strings, LENGTH_FUNCTION);
     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
-    ASSERT.that(map.entrySet()).has().exactly(
+    assertThat(map.entrySet()).has().exactly(
         mapEntry("one", 3),
         mapEntry("two", 3),
         mapEntry("three", 5)).inOrder();
@@ -714,7 +714,7 @@
     Iterator<String> strings = ImmutableList.of("one", "two", "three").iterator();
     ImmutableMap<String, Integer> map = Maps.toMap(strings, LENGTH_FUNCTION);
     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
-    ASSERT.that(map.entrySet()).has().exactly(
+    assertThat(map.entrySet()).has().exactly(
         mapEntry("one", 3),
         mapEntry("two", 3),
         mapEntry("three", 5)).inOrder();
@@ -724,7 +724,7 @@
     Iterable<String> strings = ImmutableList.of("one", "two", "three", "two", "one");
     ImmutableMap<String, Integer> map = Maps.toMap(strings, LENGTH_FUNCTION);
     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
-    ASSERT.that(map.entrySet()).has().exactly(
+    assertThat(map.entrySet()).has().exactly(
         mapEntry("one", 3),
         mapEntry("two", 3),
         mapEntry("three", 5)).inOrder();
@@ -810,37 +810,6 @@
     }
   }
 
-  /**
-   * Constructs a "nefarious" map entry with the specified key and value,
-   * meaning an entry that is suitable for testing that map entries cannot be
-   * modified via a nefarious implementation of equals. This is used for testing
-   * unmodifiable collections of map entries; for example, it should not be
-   * possible to access the raw (modifiable) map entry via a nefarious equals
-   * method.
-   */
-  public static <K, V> Map.Entry<K, V> nefariousEntry(
-      final K key, final V value) {
-    return new AbstractMapEntry<K, V>() {
-        @Override public K getKey() {
-          return key;
-        }
-        @Override public V getValue() {
-          return value;
-        }
-        @Override public V setValue(V value) {
-          throw new UnsupportedOperationException();
-        }
-        @SuppressWarnings("unchecked")
-        @Override public boolean equals(Object o) {
-          if (o instanceof Map.Entry) {
-            Map.Entry<K, V> e = (Map.Entry<K, V>) o;
-            e.setValue(value); // muhahaha!
-          }
-          return super.equals(o);
-        }
-      };
-  }
-
   public void testAsConverter_nominal() throws Exception {
     ImmutableBiMap<String, Integer> biMap = ImmutableBiMap.of(
         "one", 1,
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/MultimapBuilderTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/MultimapBuilderTest.java
index 5536a72..727101e 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/MultimapBuilderTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/MultimapBuilderTest.java
@@ -17,12 +17,9 @@
 package com.google.common.collect;
 
 import com.google.common.annotations.GwtCompatible;
-import com.google.common.collect.MultimapBuilder.MultimapBuilderWithKeys;
-import com.google.common.testing.SerializableTester;
 
 import junit.framework.TestCase;
 
-import java.math.RoundingMode;
 import java.util.SortedMap;
 import java.util.SortedSet;
 
@@ -49,21 +46,5 @@
     assertTrue(multimap.keySet() instanceof SortedSet);
     assertTrue(multimap.asMap() instanceof SortedMap);
   }
-
-  public void testSerialization() {
-    for (MultimapBuilderWithKeys<?> builderWithKeys : ImmutableList.of(
-        MultimapBuilder.hashKeys(), MultimapBuilder.linkedHashKeys(), MultimapBuilder.treeKeys(),
-        MultimapBuilder.enumKeys(RoundingMode.class))) {
-      for (MultimapBuilder<?, ?> builder : ImmutableList.of(
-          builderWithKeys.arrayListValues(),
-          builderWithKeys.linkedListValues(),
-          builderWithKeys.hashSetValues(),
-          builderWithKeys.linkedHashSetValues(),
-          builderWithKeys.treeSetValues(),
-          builderWithKeys.enumSetValues(RoundingMode.class))) {
-        SerializableTester.reserializeAndAssert(builder.build());
-      }
-    }
-  }
 }
 
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/MultimapsTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/MultimapsTest.java
index e6da7ce..43b9831 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/MultimapsTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/MultimapsTest.java
@@ -20,8 +20,8 @@
 import static com.google.common.collect.Sets.newHashSet;
 import static com.google.common.collect.testing.Helpers.nefariousMapEntry;
 import static com.google.common.collect.testing.IteratorFeature.MODIFIABLE;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Function;
@@ -205,7 +205,7 @@
     assertEquals(multimap.hashCode(), unmodifiable.hashCode());
     assertEquals(multimap, unmodifiable);
 
-    ASSERT.that(unmodifiable.asMap().get("bar")).has().exactly(5, -1);
+    assertThat(unmodifiable.asMap().get("bar")).has().exactly(5, -1);
     assertNull(unmodifiable.asMap().get("missing"));
 
     assertFalse(unmodifiable.entries() instanceof Serializable);
@@ -362,11 +362,11 @@
     assertFalse(map.containsKey("bar"));
     assertEquals(map.keySet(), multimapView.keySet());
     assertEquals(map.keySet(), multimapView.keys().elementSet());
-    ASSERT.that(multimapView.keys()).has().item("foo");
-    ASSERT.that(multimapView.values()).has().item(1);
-    ASSERT.that(multimapView.entries()).has().item(
+    assertThat(multimapView.keys()).has().item("foo");
+    assertThat(multimapView.values()).has().item(1);
+    assertThat(multimapView.entries()).has().item(
         Maps.immutableEntry("foo", 1));
-    ASSERT.that(multimapView.asMap().entrySet()).has().item(
+    assertThat(multimapView.asMap().entrySet()).has().item(
         Maps.immutableEntry(
             "foo", (Collection<Integer>) Collections.singleton(1)));
     multimapView.clear();
@@ -514,7 +514,7 @@
     } catch (IllegalArgumentException expected) {
       // expected
     }
-    ASSERT.that(multimap.entries()).has().exactly(
+    assertThat(multimap.entries()).has().exactly(
         Maps.immutableEntry(Color.RED, 1),
         Maps.immutableEntry(Color.BLUE, 2));
   }
@@ -732,7 +732,7 @@
     SetMultimap<String, Integer> filtered = Multimaps.filterKeys(
         multimap, Predicates.in(ImmutableSet.of("foo", "bar")));
     Set<Integer> bazSet = filtered.get("baz");
-    ASSERT.that(bazSet).isEmpty();
+    assertThat(bazSet).isEmpty();
     try {
       bazSet.add(5);
       fail("Expected IllegalArgumentException");
@@ -755,7 +755,7 @@
     ListMultimap<String, Integer> filtered = Multimaps.filterKeys(
         multimap, Predicates.in(ImmutableSet.of("foo", "bar")));
     List<Integer> bazList = filtered.get("baz");
-    ASSERT.that(bazList).isEmpty();
+    assertThat(bazList).isEmpty();
     try {
       bazList.add(5);
       fail("Expected IllegalArgumentException");
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/MultisetsTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/MultisetsTest.java
index 8fa4842..5394626 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/MultisetsTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/MultisetsTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.testing.DerivedComparable;
@@ -25,6 +25,7 @@
 
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.List;
 
 /**
  * Tests for {@link Multisets}.
@@ -43,7 +44,7 @@
     assertTrue(set.isEmpty());
     set.add(new DerivedComparable("foo"), 2);
     set.add(new DerivedComparable("bar"), 3);
-    ASSERT.that(set).has().exactly(
+    assertThat(set).has().exactly(
         new DerivedComparable("bar"), new DerivedComparable("bar"), new DerivedComparable("bar"),
         new DerivedComparable("foo"), new DerivedComparable("foo")).inOrder();
   }
@@ -53,7 +54,7 @@
     assertTrue(set.isEmpty());
     set.add(new LegacyComparable("foo"), 2);
     set.add(new LegacyComparable("bar"), 3);
-    ASSERT.that(set).has().exactly(new LegacyComparable("bar"),
+    assertThat(set).has().exactly(new LegacyComparable("bar"),
         new LegacyComparable("bar"), new LegacyComparable("bar"),
         new LegacyComparable("foo"), new LegacyComparable("foo")).inOrder();
   }
@@ -63,7 +64,7 @@
         = TreeMultiset.create(Collections.reverseOrder());
     multiset.add("bar", 3);
     multiset.add("foo", 2);
-    ASSERT.that(multiset).has().exactly("foo", "foo", "bar", "bar", "bar").inOrder();
+    assertThat(multiset).has().exactly("foo", "foo", "bar", "bar", "bar").inOrder();
   }
 
   public void testRetainOccurrencesEmpty() {
@@ -71,10 +72,17 @@
     Multiset<String> toRetain =
         HashMultiset.create(Arrays.asList("a", "b", "a"));
     assertFalse(Multisets.retainOccurrences(multiset, toRetain));
-    ASSERT.that(multiset).isEmpty();
+    assertThat(multiset).isEmpty();
   }
 
-  public void testRemoveOccurrencesEmpty() {
+  public void testRemoveOccurrencesIterableEmpty() {
+    Multiset<String> multiset = HashMultiset.create();
+    Iterable<String> toRemove = Arrays.asList("a", "b", "a");
+    assertFalse(Multisets.removeOccurrences(multiset, toRemove));
+    assertTrue(multiset.isEmpty());
+  }
+
+  public void testRemoveOccurrencesMultisetEmpty() {
     Multiset<String> multiset = HashMultiset.create();
     Multiset<String> toRemove =
         HashMultiset.create(Arrays.asList("a", "b", "a"));
@@ -86,7 +94,7 @@
     Multiset<String> ms1 = HashMultiset.create(Arrays.asList("a", "b", "a"));
     Multiset<String> ms2 = HashMultiset.create(
         Arrays.asList("a", "b", "b", "c"));
-    ASSERT.that(Multisets.union(ms1, ms2)).has().exactly("a", "a", "b", "b", "c");
+    assertThat(Multisets.union(ms1, ms2)).has().exactly("a", "a", "b", "b", "c");
   }
 
   public void testUnionEqualMultisets() {
@@ -110,50 +118,50 @@
   public void testIntersectEmptyNonempty() {
     Multiset<String> ms1 = HashMultiset.create();
     Multiset<String> ms2 = HashMultiset.create(Arrays.asList("a", "b", "a"));
-    ASSERT.that(Multisets.intersection(ms1, ms2)).isEmpty();
+    assertThat(Multisets.intersection(ms1, ms2)).isEmpty();
   }
 
   public void testIntersectNonemptyEmpty() {
     Multiset<String> ms1 = HashMultiset.create(Arrays.asList("a", "b", "a"));
     Multiset<String> ms2 = HashMultiset.create();
-    ASSERT.that(Multisets.intersection(ms1, ms2)).isEmpty();
+    assertThat(Multisets.intersection(ms1, ms2)).isEmpty();
   }
 
   public void testSum() {
     Multiset<String> ms1 = HashMultiset.create(Arrays.asList("a", "b", "a"));
     Multiset<String> ms2 = HashMultiset.create(Arrays.asList("b", "c"));
-    ASSERT.that(Multisets.sum(ms1, ms2)).has().exactly("a", "a", "b", "b", "c");
+    assertThat(Multisets.sum(ms1, ms2)).has().exactly("a", "a", "b", "b", "c");
   }
 
   public void testSumEmptyNonempty() {
     Multiset<String> ms1 = HashMultiset.create();
     Multiset<String> ms2 = HashMultiset.create(Arrays.asList("a", "b", "a"));
-    ASSERT.that(Multisets.sum(ms1, ms2)).has().exactly("a", "b", "a");
+    assertThat(Multisets.sum(ms1, ms2)).has().exactly("a", "b", "a");
   }
 
   public void testSumNonemptyEmpty() {
     Multiset<String> ms1 = HashMultiset.create(Arrays.asList("a", "b", "a"));
     Multiset<String> ms2 = HashMultiset.create();
-    ASSERT.that(Multisets.sum(ms1, ms2)).has().exactly("a", "b", "a");
+    assertThat(Multisets.sum(ms1, ms2)).has().exactly("a", "b", "a");
   }
 
   public void testDifferenceWithNoRemovedElements() {
     Multiset<String> ms1 = HashMultiset.create(Arrays.asList("a", "b", "a"));
     Multiset<String> ms2 = HashMultiset.create(Arrays.asList("a"));
-    ASSERT.that(Multisets.difference(ms1, ms2)).has().exactly("a", "b");
+    assertThat(Multisets.difference(ms1, ms2)).has().exactly("a", "b");
   }
 
   public void testDifferenceWithRemovedElement() {
     Multiset<String> ms1 = HashMultiset.create(Arrays.asList("a", "b", "a"));
     Multiset<String> ms2 = HashMultiset.create(Arrays.asList("b"));
-    ASSERT.that(Multisets.difference(ms1, ms2)).has().exactly("a", "a");
+    assertThat(Multisets.difference(ms1, ms2)).has().exactly("a", "a");
   }
 
   public void testDifferenceWithMoreElementsInSecondMultiset() {
     Multiset<String> ms1 = HashMultiset.create(Arrays.asList("a", "b", "a"));
     Multiset<String> ms2 = HashMultiset.create(Arrays.asList("a", "b", "b", "b"));
     Multiset<String> diff = Multisets.difference(ms1, ms2);
-    ASSERT.that(diff).has().item("a");
+    assertThat(diff).has().item("a");
     assertEquals(0, diff.count("b"));
     assertEquals(1, diff.count("a"));
     assertFalse(diff.contains("b"));
@@ -203,24 +211,40 @@
     Multiset<String> toRetain =
         HashMultiset.create(Arrays.asList("a", "b", "b"));
     assertTrue(Multisets.retainOccurrences(multiset, toRetain));
-    ASSERT.that(multiset).has().exactly("a", "b").inOrder();
+    assertThat(multiset).has().exactly("a", "b").inOrder();
   }
 
-  public void testRemoveEmptyOccurrences() {
+  public void testRemoveEmptyOccurrencesMultiset() {
     Multiset<String> multiset =
         TreeMultiset.create(Arrays.asList("a", "b", "a"));
     Multiset<String> toRemove = HashMultiset.create();
     assertFalse(Multisets.removeOccurrences(multiset, toRemove));
-    ASSERT.that(multiset).has().exactly("a", "a", "b").inOrder();
+    assertThat(multiset).has().exactly("a", "a", "b").inOrder();
   }
 
-  public void testRemoveOccurrences() {
+  public void testRemoveOccurrencesMultiset() {
     Multiset<String> multiset =
         TreeMultiset.create(Arrays.asList("a", "b", "a", "c"));
     Multiset<String> toRemove =
         HashMultiset.create(Arrays.asList("a", "b", "b"));
     assertTrue(Multisets.removeOccurrences(multiset, toRemove));
-    ASSERT.that(multiset).has().exactly("a", "c").inOrder();
+    assertThat(multiset).has().exactly("a", "c").inOrder();
+  }
+
+  public void testRemoveEmptyOccurrencesIterable() {
+    Multiset<String> multiset =
+        TreeMultiset.create(Arrays.asList("a", "b", "a"));
+    Iterable<String> toRemove = ImmutableList.of();
+    assertFalse(Multisets.removeOccurrences(multiset, toRemove));
+    assertThat(multiset).has().exactly("a", "a", "b").inOrder();
+  }
+
+  public void testRemoveOccurrencesMultisetIterable() {
+    Multiset<String> multiset =
+        TreeMultiset.create(Arrays.asList("a", "b", "a", "c"));
+    List<String> toRemove = Arrays.asList("a", "b", "b");
+    assertTrue(Multisets.removeOccurrences(multiset, toRemove));
+    assertThat(multiset).has().exactly("a", "c").inOrder();
   }
 
   @SuppressWarnings("deprecation")
@@ -240,11 +264,11 @@
     ImmutableMultiset<String> sortedMultiset =
         Multisets.copyHighestCountFirst(multiset);
 
-    ASSERT.that(sortedMultiset.entrySet()).has().exactly(
+    assertThat(sortedMultiset.entrySet()).has().exactly(
         Multisets.immutableEntry("a", 3), Multisets.immutableEntry("c", 2),
         Multisets.immutableEntry("b", 1)).inOrder();
 
-    ASSERT.that(sortedMultiset).has().exactly(
+    assertThat(sortedMultiset).has().exactly(
         "a",
         "a",
         "a",
@@ -252,7 +276,7 @@
         "c",
         "b").inOrder();
 
-    ASSERT.that(Multisets.copyHighestCountFirst(ImmutableMultiset.of())).isEmpty();
+    assertThat(Multisets.copyHighestCountFirst(ImmutableMultiset.of())).isEmpty();
   }
 }
 
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ObjectArraysTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ObjectArraysTest.java
index f43d446..b9342da 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ObjectArraysTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/ObjectArraysTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 
@@ -99,32 +99,32 @@
 
   public void testPrependZeroElements() {
     String[] result = ObjectArrays.concat("foo", new String[] {});
-    ASSERT.that(result).has().item("foo");
+    assertThat(result).asList().has().item("foo");
   }
 
   public void testPrependOneElement() {
     String[] result = ObjectArrays.concat("foo", new String[] { "bar" });
-    ASSERT.that(result).has().exactly("foo", "bar").inOrder();
+    assertThat(result).asList().has().exactly("foo", "bar").inOrder();
   }
 
   public void testPrependTwoElements() {
     String[] result = ObjectArrays.concat("foo", new String[] { "bar", "baz" });
-    ASSERT.that(result).has().exactly("foo", "bar", "baz").inOrder();
+    assertThat(result).asList().has().exactly("foo", "bar", "baz").inOrder();
   }
 
   public void testAppendZeroElements() {
     String[] result = ObjectArrays.concat(new String[] {}, "foo");
-    ASSERT.that(result).has().item("foo");
+    assertThat(result).asList().has().item("foo");
   }
 
   public void testAppendOneElement() {
     String[] result = ObjectArrays.concat(new String[] { "foo" }, "bar");
-    ASSERT.that(result).has().exactly("foo", "bar").inOrder();
+    assertThat(result).asList().has().exactly("foo", "bar").inOrder();
   }
 
   public void testAppendTwoElements() {
     String[] result = ObjectArrays.concat(new String[] { "foo", "bar" }, "baz");
-    ASSERT.that(result).has().exactly("foo", "bar", "baz").inOrder();
+    assertThat(result).asList().has().exactly("foo", "bar", "baz").inOrder();
   }
 
   public void testEmptyArrayToEmpty() {
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/OrderingTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/OrderingTest.java
index e797881..579842c 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/OrderingTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/OrderingTest.java
@@ -20,8 +20,8 @@
 import static com.google.common.collect.Lists.newArrayList;
 import static com.google.common.testing.SerializableTester.reserialize;
 import static com.google.common.testing.SerializableTester.reserializeAndAssert;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Function;
@@ -155,7 +155,7 @@
         = Ordering.explicit(2, 8, 6, 1, 7, 5, 3, 4, 0, 9);
     List<Integer> list = Arrays.asList(0, 3, 5, 6, 7, 8, 9);
     Collections.sort(list, c);
-    ASSERT.that(list).has().exactly(8, 6, 7, 5, 3, 0, 9).inOrder();
+    assertThat(list).has().exactly(8, 6, 7, 5, 3, 0, 9).inOrder();
     reserializeAndAssert(c);
   }
 
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/SetsTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/SetsTest.java
index 7173bc6..6242ee2 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/SetsTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/SetsTest.java
@@ -22,9 +22,9 @@
 import static com.google.common.collect.Sets.newLinkedHashSet;
 import static com.google.common.collect.Sets.powerSet;
 import static com.google.common.collect.testing.IteratorFeature.UNMODIFIABLE;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Collections.emptySet;
 import static java.util.Collections.singleton;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.testing.IteratorTester;
@@ -91,7 +91,7 @@
   public void testImmutableEnumSet() {
     Set<SomeEnum> units = Sets.immutableEnumSet(SomeEnum.D, SomeEnum.B);
 
-    ASSERT.that(units).has().exactly(SomeEnum.B, SomeEnum.D).inOrder();
+    assertThat(units).has().exactly(SomeEnum.B, SomeEnum.D).inOrder();
     try {
       units.remove(SomeEnum.B);
       fail("ImmutableEnumSet should throw an exception on remove()");
@@ -105,15 +105,15 @@
   public void testImmutableEnumSet_fromIterable() {
     ImmutableSet<SomeEnum> none
         = Sets.immutableEnumSet(MinimalIterable.<SomeEnum>of());
-    ASSERT.that(none).isEmpty();
+    assertThat(none).isEmpty();
 
     ImmutableSet<SomeEnum> one
         = Sets.immutableEnumSet(MinimalIterable.of(SomeEnum.B));
-    ASSERT.that(one).has().item(SomeEnum.B);
+    assertThat(one).has().item(SomeEnum.B);
 
     ImmutableSet<SomeEnum> two
         = Sets.immutableEnumSet(MinimalIterable.of(SomeEnum.D, SomeEnum.B));
-    ASSERT.that(two).has().exactly(SomeEnum.B, SomeEnum.D).inOrder();
+    assertThat(two).has().exactly(SomeEnum.B, SomeEnum.D).inOrder();
   }
 
   private static byte[] prepended(byte b, byte[] array) {
@@ -230,7 +230,7 @@
     assertTrue(set.isEmpty());
     set.add(new Derived("foo"));
     set.add(new Derived("bar"));
-    ASSERT.that(set).has().exactly(new Derived("bar"), new Derived("foo")).inOrder();
+    assertThat(set).has().exactly(new Derived("bar"), new Derived("foo")).inOrder();
   }
 
   public void testNewTreeSetEmptyNonGeneric() {
@@ -238,7 +238,7 @@
     assertTrue(set.isEmpty());
     set.add(new LegacyComparable("foo"));
     set.add(new LegacyComparable("bar"));
-    ASSERT.that(set).has()
+    assertThat(set).has()
         .exactly(new LegacyComparable("bar"), new LegacyComparable("foo")).inOrder();
   }
 
@@ -256,7 +256,7 @@
     Iterable<Derived> iterable =
         Arrays.asList(new Derived("foo"), new Derived("bar"));
     TreeSet<Derived> set = Sets.newTreeSet(iterable);
-    ASSERT.that(set).has().exactly(
+    assertThat(set).has().exactly(
         new Derived("bar"), new Derived("foo")).inOrder();
   }
 
@@ -264,7 +264,7 @@
     Iterable<LegacyComparable> iterable =
         Arrays.asList(new LegacyComparable("foo"), new LegacyComparable("bar"));
     TreeSet<LegacyComparable> set = Sets.newTreeSet(iterable);
-    ASSERT.that(set).has().exactly(
+    assertThat(set).has().exactly(
         new LegacyComparable("bar"), new LegacyComparable("foo")).inOrder();
   }
 
@@ -357,7 +357,7 @@
    */
   @SuppressWarnings("unchecked") // varargs!
   public void testCartesianProduct_zeroary() {
-    ASSERT.that(Sets.cartesianProduct()).has().exactly(list());
+    assertThat(Sets.cartesianProduct()).has().exactly(list());
   }
 
   /**
@@ -366,7 +366,7 @@
    */
   @SuppressWarnings("unchecked") // varargs!
   public void testCartesianProduct_unary() {
-    ASSERT.that(Sets.cartesianProduct(set(1, 2))).has().exactly(list(1), list(2));
+    assertThat(Sets.cartesianProduct(set(1, 2))).has().exactly(list(1), list(2));
   }
 
   @SuppressWarnings("unchecked") // varargs!
@@ -395,24 +395,24 @@
 
   @SuppressWarnings("unchecked") // varargs!
   public void testCartesianProduct_binary1x1() {
-    ASSERT.that(Sets.cartesianProduct(set(1), set(2))).has().item(list(1, 2));
+    assertThat(Sets.cartesianProduct(set(1), set(2))).has().item(list(1, 2));
   }
 
   @SuppressWarnings("unchecked") // varargs!
   public void testCartesianProduct_binary1x2() {
-    ASSERT.that(Sets.cartesianProduct(set(1), set(2, 3)))
+    assertThat(Sets.cartesianProduct(set(1), set(2, 3)))
         .has().exactly(list(1, 2), list(1, 3)).inOrder();
   }
 
   @SuppressWarnings("unchecked") // varargs!
   public void testCartesianProduct_binary2x2() {
-    ASSERT.that(Sets.cartesianProduct(set(1, 2), set(3, 4)))
+    assertThat(Sets.cartesianProduct(set(1, 2), set(3, 4)))
         .has().exactly(list(1, 3), list(1, 4), list(2, 3), list(2, 4)).inOrder();
   }
 
   @SuppressWarnings("unchecked") // varargs!
   public void testCartesianProduct_2x2x2() {
-    ASSERT.that(Sets.cartesianProduct(set(0, 1), set(0, 1), set(0, 1))).has().exactly(
+    assertThat(Sets.cartesianProduct(set(0, 1), set(0, 1), set(0, 1))).has().exactly(
         list(0, 0, 0), list(0, 0, 1), list(0, 1, 0), list(0, 1, 1),
         list(1, 0, 0), list(1, 0, 1), list(1, 1, 0), list(1, 1, 1)).inOrder();
   }
@@ -437,7 +437,7 @@
     List<Object> exp3 = list((Object) 2, "3");
     List<Object> exp4 = list((Object) 2, "4");
 
-    ASSERT.that(Sets.<Object>cartesianProduct(x, y))
+    assertThat(Sets.<Object>cartesianProduct(x, y))
         .has().exactly(exp1, exp2, exp3, exp4).inOrder();
   }
 
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/SingletonImmutableTableTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/SingletonImmutableTableTest.java
index 36c107f..c21fdc0 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/SingletonImmutableTableTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/SingletonImmutableTableTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Objects;
@@ -117,7 +117,7 @@
   }
 
   public void testValues() {
-    ASSERT.that(testTable.values()).has().item("blah");
+    assertThat(testTable.values()).has().item("blah");
   }
 
   @Override Iterable<ImmutableTable<Character, Integer, String>> getTestInstances() {
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/TreeBasedTableTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/TreeBasedTableTest.java
index 126152e..7977f8d 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/TreeBasedTableTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/TreeBasedTableTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.testing.SortedMapInterfaceTest;
@@ -117,8 +117,8 @@
     table.put("foo", 12, 'b');
     table.put("bar", 5, 'c');
     table.put("cat", 8, 'd');
-    ASSERT.that(table.rowKeySet()).has().exactly("foo", "cat", "bar").inOrder();
-    ASSERT.that(table.row("foo").keySet()).has().exactly(12, 3).inOrder();
+    assertThat(table.rowKeySet()).has().exactly("foo", "cat", "bar").inOrder();
+    assertThat(table.row("foo").keySet()).has().exactly(12, 3).inOrder();
   }
 
   public void testCreateCopy() {
@@ -129,8 +129,8 @@
     original.put("bar", 5, 'c');
     original.put("cat", 8, 'd');
     table = TreeBasedTable.create(original);
-    ASSERT.that(table.rowKeySet()).has().exactly("foo", "cat", "bar").inOrder();
-    ASSERT.that(table.row("foo").keySet()).has().exactly(12, 3).inOrder();
+    assertThat(table.rowKeySet()).has().exactly("foo", "cat", "bar").inOrder();
+    assertThat(table.row("foo").keySet()).has().exactly(12, 3).inOrder();
     assertEquals(original, table);
   }
 
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/TreeMultimapExplicitTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/TreeMultimapExplicitTest.java
index 3d0fcf2..e0b1ec4 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/TreeMultimapExplicitTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/TreeMultimapExplicitTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 
@@ -97,13 +97,13 @@
     tree.put("google", 6);
     tree.put("tree", 0);
     tree.put("tree", 3);
-    ASSERT.that(tree.keySet()).has().exactly("tree", "google").inOrder();
-    ASSERT.that(tree.get("google")).has().exactly(6, 2).inOrder();
+    assertThat(tree.keySet()).has().exactly("tree", "google").inOrder();
+    assertThat(tree.get("google")).has().exactly(6, 2).inOrder();
 
     TreeMultimap<String, Integer> copy = TreeMultimap.create(tree);
     assertEquals(tree, copy);
-    ASSERT.that(copy.keySet()).has().exactly("google", "tree").inOrder();
-    ASSERT.that(copy.get("google")).has().exactly(2, 6).inOrder();
+    assertThat(copy.keySet()).has().exactly("google", "tree").inOrder();
+    assertThat(copy.get("google")).has().exactly(2, 6).inOrder();
     assertEquals(Ordering.natural(), copy.keyComparator());
     assertEquals(Ordering.natural(), copy.valueComparator());
     assertEquals(Ordering.natural(), copy.get("google").comparator());
@@ -128,14 +128,14 @@
 
   public void testOrderedGet() {
     TreeMultimap<String, Integer> multimap = createPopulate();
-    ASSERT.that(multimap.get(null)).has().exactly(7, 3, 1).inOrder();
-    ASSERT.that(multimap.get("google")).has().exactly(6, 2).inOrder();
-    ASSERT.that(multimap.get("tree")).has().exactly(null, 0).inOrder();
+    assertThat(multimap.get(null)).has().exactly(7, 3, 1).inOrder();
+    assertThat(multimap.get("google")).has().exactly(6, 2).inOrder();
+    assertThat(multimap.get("tree")).has().exactly(null, 0).inOrder();
   }
 
   public void testOrderedKeySet() {
     TreeMultimap<String, Integer> multimap = createPopulate();
-    ASSERT.that(multimap.keySet()).has().exactly(null, "tree", "google").inOrder();
+    assertThat(multimap.keySet()).has().exactly(null, "tree", "google").inOrder();
   }
 
   public void testOrderedAsMapEntries() {
@@ -144,18 +144,18 @@
         multimap.asMap().entrySet().iterator();
     Map.Entry<String, Collection<Integer>> entry = iterator.next();
     assertEquals(null, entry.getKey());
-    ASSERT.that(entry.getValue()).has().exactly(7, 3, 1);
+    assertThat(entry.getValue()).has().exactly(7, 3, 1);
     entry = iterator.next();
     assertEquals("tree", entry.getKey());
-    ASSERT.that(entry.getValue()).has().exactly(null, 0);
+    assertThat(entry.getValue()).has().exactly(null, 0);
     entry = iterator.next();
     assertEquals("google", entry.getKey());
-    ASSERT.that(entry.getValue()).has().exactly(6, 2);
+    assertThat(entry.getValue()).has().exactly(6, 2);
   }
 
   public void testOrderedEntries() {
     TreeMultimap<String, Integer> multimap = createPopulate();
-    ASSERT.that(multimap.entries()).has().exactly(
+    assertThat(multimap.entries()).has().exactly(
         Maps.immutableEntry((String) null, 7),
         Maps.immutableEntry((String) null, 3),
         Maps.immutableEntry((String) null, 1),
@@ -167,7 +167,7 @@
 
   public void testOrderedValues() {
     TreeMultimap<String, Integer> multimap = createPopulate();
-    ASSERT.that(multimap.values()).has().exactly(7, 3, 1, null, 0, 6, 2).inOrder();
+    assertThat(multimap.values()).has().exactly(7, 3, 1, null, 0, 6, 2).inOrder();
   }
 
   public void testComparator() {
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/TreeMultimapNaturalTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/TreeMultimapNaturalTest.java
index f29ee18..3882958 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/TreeMultimapNaturalTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/TreeMultimapNaturalTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 
@@ -68,14 +68,14 @@
 
   public void testOrderedGet() {
     TreeMultimap<String, Integer> multimap = createPopulate();
-    ASSERT.that(multimap.get("foo")).has().exactly(1, 3, 7).inOrder();
-    ASSERT.that(multimap.get("google")).has().exactly(2, 6).inOrder();
-    ASSERT.that(multimap.get("tree")).has().exactly(0, 4).inOrder();
+    assertThat(multimap.get("foo")).has().exactly(1, 3, 7).inOrder();
+    assertThat(multimap.get("google")).has().exactly(2, 6).inOrder();
+    assertThat(multimap.get("tree")).has().exactly(0, 4).inOrder();
   }
 
   public void testOrderedKeySet() {
     TreeMultimap<String, Integer> multimap = createPopulate();
-    ASSERT.that(multimap.keySet()).has().exactly("foo", "google", "tree").inOrder();
+    assertThat(multimap.keySet()).has().exactly("foo", "google", "tree").inOrder();
   }
 
   public void testOrderedAsMapEntries() {
@@ -84,18 +84,18 @@
         multimap.asMap().entrySet().iterator();
     Map.Entry<String, Collection<Integer>> entry = iterator.next();
     assertEquals("foo", entry.getKey());
-    ASSERT.that(entry.getValue()).has().exactly(1, 3, 7);
+    assertThat(entry.getValue()).has().exactly(1, 3, 7);
     entry = iterator.next();
     assertEquals("google", entry.getKey());
-    ASSERT.that(entry.getValue()).has().exactly(2, 6);
+    assertThat(entry.getValue()).has().exactly(2, 6);
     entry = iterator.next();
     assertEquals("tree", entry.getKey());
-    ASSERT.that(entry.getValue()).has().exactly(0, 4);
+    assertThat(entry.getValue()).has().exactly(0, 4);
   }
 
   public void testOrderedEntries() {
     TreeMultimap<String, Integer> multimap = createPopulate();
-    ASSERT.that(multimap.entries()).has().exactly(
+    assertThat(multimap.entries()).has().exactly(
         Maps.immutableEntry("foo", 1),
         Maps.immutableEntry("foo", 3),
         Maps.immutableEntry("foo", 7),
@@ -107,7 +107,7 @@
 
   public void testOrderedValues() {
     TreeMultimap<String, Integer> multimap = createPopulate();
-    ASSERT.that(multimap.values()).has().exactly(
+    assertThat(multimap.values()).has().exactly(
         1, 3, 7, 2, 6, 0, 4).inOrder();
   }
 
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/TreeMultisetTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/TreeMultisetTest.java
index 7a0be3b..65f1a95 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/TreeMultisetTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/TreeMultisetTest.java
@@ -17,7 +17,7 @@
 package com.google.common.collect;
 
 import static com.google.common.collect.BoundType.CLOSED;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 
@@ -83,9 +83,9 @@
     assertEquals("c", elementSet.last());
     assertEquals(Ordering.natural(), elementSet.comparator());
 
-    ASSERT.that(elementSet.headSet("b")).has().exactly("a").inOrder();
-    ASSERT.that(elementSet.tailSet("b")).has().exactly("b", "c").inOrder();
-    ASSERT.that(elementSet.subSet("a", "c")).has().exactly("a", "b").inOrder();
+    assertThat(elementSet.headSet("b")).has().exactly("a").inOrder();
+    assertThat(elementSet.tailSet("b")).has().exactly("b", "c").inOrder();
+    assertThat(elementSet.subSet("a", "c")).has().exactly("a", "b").inOrder();
   }
 
   public void testElementSetSubsetRemove() {
@@ -98,18 +98,18 @@
     ms.add("f", 2);
 
     SortedSet<String> elementSet = ms.elementSet();
-    ASSERT.that(elementSet).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(elementSet).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
     SortedSet<String> subset = elementSet.subSet("b", "f");
-    ASSERT.that(subset).has().exactly("b", "c", "d", "e").inOrder();
+    assertThat(subset).has().exactly("b", "c", "d", "e").inOrder();
 
     assertTrue(subset.remove("c"));
-    ASSERT.that(elementSet).has().exactly("a", "b", "d", "e", "f").inOrder();
-    ASSERT.that(subset).has().exactly("b", "d", "e").inOrder();
+    assertThat(elementSet).has().exactly("a", "b", "d", "e", "f").inOrder();
+    assertThat(subset).has().exactly("b", "d", "e").inOrder();
     assertEquals(10, ms.size());
 
     assertFalse(subset.remove("a"));
-    ASSERT.that(elementSet).has().exactly("a", "b", "d", "e", "f").inOrder();
-    ASSERT.that(subset).has().exactly("b", "d", "e").inOrder();
+    assertThat(elementSet).has().exactly("a", "b", "d", "e", "f").inOrder();
+    assertThat(subset).has().exactly("b", "d", "e").inOrder();
     assertEquals(10, ms.size());
   }
 
@@ -123,13 +123,13 @@
     ms.add("f", 2);
 
     SortedSet<String> elementSet = ms.elementSet();
-    ASSERT.that(elementSet).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(elementSet).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
     SortedSet<String> subset = elementSet.subSet("b", "f");
-    ASSERT.that(subset).has().exactly("b", "c", "d", "e").inOrder();
+    assertThat(subset).has().exactly("b", "c", "d", "e").inOrder();
 
     assertTrue(subset.removeAll(Arrays.asList("a", "c")));
-    ASSERT.that(elementSet).has().exactly("a", "b", "d", "e", "f").inOrder();
-    ASSERT.that(subset).has().exactly("b", "d", "e").inOrder();
+    assertThat(elementSet).has().exactly("a", "b", "d", "e", "f").inOrder();
+    assertThat(subset).has().exactly("b", "d", "e").inOrder();
     assertEquals(10, ms.size());
   }
 
@@ -143,13 +143,13 @@
     ms.add("f", 2);
 
     SortedSet<String> elementSet = ms.elementSet();
-    ASSERT.that(elementSet).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(elementSet).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
     SortedSet<String> subset = elementSet.subSet("b", "f");
-    ASSERT.that(subset).has().exactly("b", "c", "d", "e").inOrder();
+    assertThat(subset).has().exactly("b", "c", "d", "e").inOrder();
 
     assertTrue(subset.retainAll(Arrays.asList("a", "c")));
-    ASSERT.that(elementSet).has().exactly("a", "c", "f").inOrder();
-    ASSERT.that(subset).has().exactly("c").inOrder();
+    assertThat(elementSet).has().exactly("a", "c", "f").inOrder();
+    assertThat(subset).has().exactly("c").inOrder();
     assertEquals(5, ms.size());
   }
 
@@ -163,13 +163,13 @@
     ms.add("f", 2);
 
     SortedSet<String> elementSet = ms.elementSet();
-    ASSERT.that(elementSet).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(elementSet).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
     SortedSet<String> subset = elementSet.subSet("b", "f");
-    ASSERT.that(subset).has().exactly("b", "c", "d", "e").inOrder();
+    assertThat(subset).has().exactly("b", "c", "d", "e").inOrder();
 
     subset.clear();
-    ASSERT.that(elementSet).has().exactly("a", "f").inOrder();
-    ASSERT.that(subset).isEmpty();
+    assertThat(elementSet).has().exactly("a", "f").inOrder();
+    assertThat(subset).isEmpty();
     assertEquals(3, ms.size());
   }
 
@@ -188,7 +188,7 @@
     ms.add("b");
     ms.add("d");
 
-    ASSERT.that(ms).has().exactly("d", "c", "b", "b", "a").inOrder();
+    assertThat(ms).has().exactly("d", "c", "b", "b", "a").inOrder();
 
     SortedSet<String> elementSet = ms.elementSet();
     assertEquals("d", elementSet.first());
@@ -206,7 +206,7 @@
     ms.add("b");
     ms.add(null, 2);
 
-    ASSERT.that(ms).has().exactly(null, null, null, "a", "b", "b").inOrder();
+    assertThat(ms).has().exactly(null, null, null, "a", "b", "b").inOrder();
     assertEquals(3, ms.count(null));
 
     SortedSet<String> elementSet = ms.elementSet();
diff --git a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/TreeTraverserTest.java b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/TreeTraverserTest.java
index 7ae9672..76f0a0c 100644
--- a/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/TreeTraverserTest.java
+++ b/guava-gwt/test-super/com/google/common/collect/super/com/google/common/collect/TreeTraverserTest.java
@@ -14,7 +14,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Optional;
@@ -126,22 +126,22 @@
   }
 
   public void testPreOrder() {
-    ASSERT.that(iterationOrder(ADAPTER.preOrderTraversal(h))).is("hdabcegf");
-    ASSERT.that(binaryIterationOrder(BIN_ADAPTER.preOrderTraversal(bd))).is("dbacefg");
+    assertThat(iterationOrder(ADAPTER.preOrderTraversal(h))).isEqualTo("hdabcegf");
+    assertThat(binaryIterationOrder(BIN_ADAPTER.preOrderTraversal(bd))).isEqualTo("dbacefg");
   }
 
   public void testPostOrder() {
-    ASSERT.that(iterationOrder(ADAPTER.postOrderTraversal(h))).is("abcdefgh");
-    ASSERT.that(binaryIterationOrder(BIN_ADAPTER.postOrderTraversal(bd))).is("acbgfed");
+    assertThat(iterationOrder(ADAPTER.postOrderTraversal(h))).isEqualTo("abcdefgh");
+    assertThat(binaryIterationOrder(BIN_ADAPTER.postOrderTraversal(bd))).isEqualTo("acbgfed");
   }
 
   public void testBreadthOrder() {
-    ASSERT.that(iterationOrder(ADAPTER.breadthFirstTraversal(h))).is("hdegabcf");
-    ASSERT.that(binaryIterationOrder(BIN_ADAPTER.breadthFirstTraversal(bd))).is("dbeacfg");
+    assertThat(iterationOrder(ADAPTER.breadthFirstTraversal(h))).isEqualTo("hdegabcf");
+    assertThat(binaryIterationOrder(BIN_ADAPTER.breadthFirstTraversal(bd))).isEqualTo("dbeacfg");
   }
 
   public void testInOrder() {
-    ASSERT.that(binaryIterationOrder(BIN_ADAPTER.inOrderTraversal(bd))).is("abcdegf");
+    assertThat(binaryIterationOrder(BIN_ADAPTER.inOrderTraversal(bd))).isEqualTo("abcdegf");
   }
 }
 
diff --git a/guava-gwt/test-super/com/google/common/collect/testing/google/super/com/google/common/collect/testing/google/MultisetRemoveTester.java b/guava-gwt/test-super/com/google/common/collect/testing/google/super/com/google/common/collect/testing/google/MultisetRemoveTester.java
index 26fedfa..46148b9 100644
--- a/guava-gwt/test-super/com/google/common/collect/testing/google/super/com/google/common/collect/testing/google/MultisetRemoveTester.java
+++ b/guava-gwt/test-super/com/google/common/collect/testing/google/super/com/google/common/collect/testing/google/MultisetRemoveTester.java
@@ -21,7 +21,7 @@
 import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_REMOVE;
 import static com.google.common.collect.testing.features.CollectionSize.SEVERAL;
 import static com.google.common.collect.testing.features.CollectionSize.ZERO;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.testing.Helpers;
@@ -150,7 +150,7 @@
   public void testRemoveAllIgnoresCount() {
     initThreeCopies();
     assertTrue(getMultiset().removeAll(Collections.singleton(samples.e0)));
-    ASSERT.that(getMultiset()).isEmpty();
+    assertThat(getMultiset()).isEmpty();
   }
   
   @CollectionSize.Require(SEVERAL)
diff --git a/guava-gwt/test-super/com/google/common/collect/testing/super/com/google/common/collect/testing/Platform.java b/guava-gwt/test-super/com/google/common/collect/testing/super/com/google/common/collect/testing/Platform.java
index a98e026..8dbda2f 100644
--- a/guava-gwt/test-super/com/google/common/collect/testing/super/com/google/common/collect/testing/Platform.java
+++ b/guava-gwt/test-super/com/google/common/collect/testing/super/com/google/common/collect/testing/Platform.java
@@ -74,9 +74,5 @@
     return builder.toString();
   }
   
-  static String classGetSimpleName(Class<?> clazz) {
-    throw new UnsupportedOperationException("Shouldn't be called in GWT.");
-  }
-
   private Platform() {}
 }
diff --git a/guava-gwt/test-super/com/google/common/net/super/com/google/common/net/InternetDomainNameTest.java b/guava-gwt/test-super/com/google/common/net/super/com/google/common/net/InternetDomainNameTest.java
index 655e409..8dda0c5 100644
--- a/guava-gwt/test-super/com/google/common/net/super/com/google/common/net/InternetDomainNameTest.java
+++ b/guava-gwt/test-super/com/google/common/net/super/com/google/common/net/InternetDomainNameTest.java
@@ -365,9 +365,9 @@
   }
 
   public void testExclusion() {
-    InternetDomainName domain = InternetDomainName.from("foo.nic.uk");
+    InternetDomainName domain = InternetDomainName.from("foo.teledata.mz");
     assertTrue(domain.hasPublicSuffix());
-    assertEquals("uk", domain.publicSuffix().toString());
+    assertEquals("mz", domain.publicSuffix().toString());
 
     // Behold the weirdness!
     assertFalse(domain.publicSuffix().isPublicSuffix());
diff --git a/guava-gwt/test-super/com/google/common/primitives/super/com/google/common/primitives/DoublesTest.java b/guava-gwt/test-super/com/google/common/primitives/super/com/google/common/primitives/DoublesTest.java
index 7713fd6..84717f3 100644
--- a/guava-gwt/test-super/com/google/common/primitives/super/com/google/common/primitives/DoublesTest.java
+++ b/guava-gwt/test-super/com/google/common/primitives/super/com/google/common/primitives/DoublesTest.java
@@ -16,8 +16,8 @@
 
 package com.google.common.primitives;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.lang.Double.NaN;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Converter;
@@ -345,7 +345,7 @@
     list.set(0, (double) 2);
     assertTrue(Arrays.equals(new double[] {(double) 2, (double) 1}, array));
     array[1] = (double) 3;
-    ASSERT.that(list).has().exactly((double) 2, (double) 3).inOrder();
+    assertThat(list).has().exactly((double) 2, (double) 3).inOrder();
   }
 
   public void testAsList_toArray_roundTrip() {
diff --git a/guava-gwt/test-super/com/google/common/primitives/super/com/google/common/primitives/FloatsTest.java b/guava-gwt/test-super/com/google/common/primitives/super/com/google/common/primitives/FloatsTest.java
index 1f6543e..d136719 100644
--- a/guava-gwt/test-super/com/google/common/primitives/super/com/google/common/primitives/FloatsTest.java
+++ b/guava-gwt/test-super/com/google/common/primitives/super/com/google/common/primitives/FloatsTest.java
@@ -16,8 +16,8 @@
 
 package com.google.common.primitives;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.lang.Float.NaN;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.testing.Helpers;
@@ -335,7 +335,7 @@
     list.set(0, (float) 2);
     assertTrue(Arrays.equals(new float[] {(float) 2, (float) 1}, array));
     array[1] = (float) 3;
-    ASSERT.that(list).has().exactly((float) 2, (float) 3).inOrder();
+    assertThat(list).has().exactly((float) 2, (float) 3).inOrder();
   }
 
   public void testAsList_toArray_roundTrip() {
diff --git a/guava-gwt/test-super/com/google/common/primitives/super/com/google/common/primitives/IntsTest.java b/guava-gwt/test-super/com/google/common/primitives/super/com/google/common/primitives/IntsTest.java
index 37e4e22..f1e7ed1 100644
--- a/guava-gwt/test-super/com/google/common/primitives/super/com/google/common/primitives/IntsTest.java
+++ b/guava-gwt/test-super/com/google/common/primitives/super/com/google/common/primitives/IntsTest.java
@@ -390,5 +390,38 @@
     assertEquals("-255", converter.reverse().convert(-0xFF));
     assertEquals("438", converter.reverse().convert(0666));
   }
-}
 
+  public void testTryParse() {
+    tryParseAndAssertEquals(0, "0");
+    tryParseAndAssertEquals(0, "-0");
+    tryParseAndAssertEquals(1, "1");
+    tryParseAndAssertEquals(-1, "-1");
+    tryParseAndAssertEquals(8900, "8900");
+    tryParseAndAssertEquals(-8900, "-8900");
+    tryParseAndAssertEquals(GREATEST, Integer.toString(GREATEST));
+    tryParseAndAssertEquals(LEAST, Integer.toString(LEAST));
+    assertNull(Ints.tryParse(""));
+    assertNull(Ints.tryParse("-"));
+    assertNull(Ints.tryParse("+1"));
+    assertNull(Ints.tryParse("9999999999999999"));
+    assertNull("Max integer + 1",
+        Ints.tryParse(Long.toString(((long) GREATEST) + 1)));
+    assertNull("Max integer * 10",
+        Ints.tryParse(Long.toString(((long) GREATEST) * 10)));
+    assertNull("Min integer - 1",
+        Ints.tryParse(Long.toString(((long) LEAST) - 1)));
+    assertNull("Min integer * 10",
+        Ints.tryParse(Long.toString(((long) LEAST) * 10)));
+    assertNull("Max long", Ints.tryParse(Long.toString(Long.MAX_VALUE)));
+    assertNull("Min long", Ints.tryParse(Long.toString(Long.MIN_VALUE)));
+    assertNull(Ints.tryParse("\u0662\u06f3"));
+  }
+
+  /**
+   * Applies {@link Ints#tryParse(String)} to the given string and asserts that
+   * the result is as expected.
+   */
+  private static void tryParseAndAssertEquals(Integer expected, String value) {
+    assertEquals(expected, Ints.tryParse(value));
+  }
+}
diff --git a/guava-gwt/test-super/com/google/common/primitives/super/com/google/common/primitives/LongsTest.java b/guava-gwt/test-super/com/google/common/primitives/super/com/google/common/primitives/LongsTest.java
index 833779e..c1556cc 100644
--- a/guava-gwt/test-super/com/google/common/primitives/super/com/google/common/primitives/LongsTest.java
+++ b/guava-gwt/test-super/com/google/common/primitives/super/com/google/common/primitives/LongsTest.java
@@ -25,6 +25,7 @@
 
 import junit.framework.TestCase;
 
+import java.math.BigInteger;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -412,6 +413,30 @@
     assertEquals("438", converter.reverse().convert(0666L));
   }
 
+  public void testTryParse() {
+    tryParseAndAssertEquals(0L, "0");
+    tryParseAndAssertEquals(0L, "-0");
+    tryParseAndAssertEquals(1L, "1");
+    tryParseAndAssertEquals(-1L, "-1");
+    tryParseAndAssertEquals(8900L, "8900");
+    tryParseAndAssertEquals(-8900L, "-8900");
+    tryParseAndAssertEquals(MAX_VALUE, Long.toString(MAX_VALUE));
+    tryParseAndAssertEquals(MIN_VALUE, Long.toString(MIN_VALUE));
+    assertNull(Longs.tryParse(""));
+    assertNull(Longs.tryParse("-"));
+    assertNull(Longs.tryParse("+1"));
+    assertNull(Longs.tryParse("999999999999999999999999"));
+    assertNull("Max long + 1",
+        Longs.tryParse(BigInteger.valueOf(MAX_VALUE).add(BigInteger.ONE).toString()));
+    assertNull("Max long * 10",
+        Longs.tryParse(BigInteger.valueOf(MAX_VALUE).multiply(BigInteger.TEN).toString()));
+    assertNull("Min long - 1",
+        Longs.tryParse(BigInteger.valueOf(MIN_VALUE).subtract(BigInteger.ONE).toString()));
+    assertNull("Min long * 10",
+        Longs.tryParse(BigInteger.valueOf(MIN_VALUE).multiply(BigInteger.TEN).toString()));
+    assertNull(Longs.tryParse("\u0662\u06f3"));
+  }
+
   /**
    * Applies {@link Longs#tryParse(String)} to the given string and asserts that
    * the result is as expected.
diff --git a/guava-gwt/test/com/google/common/base/AsciiTest_gwt.java b/guava-gwt/test/com/google/common/base/AsciiTest_gwt.java
index 518bd1a..e33c6c7 100644
--- a/guava-gwt/test/com/google/common/base/AsciiTest_gwt.java
+++ b/guava-gwt/test/com/google/common/base/AsciiTest_gwt.java
@@ -38,11 +38,6 @@
   testCase.testEqualsIgnoreCase();
 }
 
-public void testEqualsIgnoreCaseUnicodeEquivalence() throws Exception {
-  com.google.common.base.AsciiTest testCase = new com.google.common.base.AsciiTest();
-  testCase.testEqualsIgnoreCaseUnicodeEquivalence();
-}
-
 public void testToLowerCase() throws Exception {
   com.google.common.base.AsciiTest testCase = new com.google.common.base.AsciiTest();
   testCase.testToLowerCase();
diff --git a/guava-gwt/test/com/google/common/base/EnumsTest_gwt.java b/guava-gwt/test/com/google/common/base/EnumsTest_gwt.java
index bf5486b..40d81a5 100644
--- a/guava-gwt/test/com/google/common/base/EnumsTest_gwt.java
+++ b/guava-gwt/test/com/google/common/base/EnumsTest_gwt.java
@@ -57,24 +57,4 @@
   com.google.common.base.EnumsTest testCase = new com.google.common.base.EnumsTest();
   testCase.testStringConverter_serialization();
 }
-
-public void testValueOfFunction() throws Exception {
-  com.google.common.base.EnumsTest testCase = new com.google.common.base.EnumsTest();
-  testCase.testValueOfFunction();
-}
-
-public void testValueOfFunction_caseSensitive() throws Exception {
-  com.google.common.base.EnumsTest testCase = new com.google.common.base.EnumsTest();
-  testCase.testValueOfFunction_caseSensitive();
-}
-
-public void testValueOfFunction_equals() throws Exception {
-  com.google.common.base.EnumsTest testCase = new com.google.common.base.EnumsTest();
-  testCase.testValueOfFunction_equals();
-}
-
-public void testValueOfFunction_nullWhenNoMatchingConstant() throws Exception {
-  com.google.common.base.EnumsTest testCase = new com.google.common.base.EnumsTest();
-  testCase.testValueOfFunction_nullWhenNoMatchingConstant();
-}
 }
diff --git a/guava-gwt/test/com/google/common/base/testModule.gwt.xml b/guava-gwt/test/com/google/common/base/testModule.gwt.xml
index 9a72550..6dcc754 100644
--- a/guava-gwt/test/com/google/common/base/testModule.gwt.xml
+++ b/guava-gwt/test/com/google/common/base/testModule.gwt.xml
@@ -6,7 +6,7 @@
   <inherits name="com.google.common.collect.Collect"/>
   <inherits name="com.google.common.testing.Testing"/>
   <inherits name="com.google.common.annotations.Annotations"/>
-  <inherits name="org.truth0.Truth"/>
+  <inherits name="com.google.common.truth.Truth"/>
   <entry-point class="com.google.common.base.TestModuleEntryPoint"/>
    
   <source path=""/>
diff --git a/guava-gwt/test/com/google/common/cache/testModule.gwt.xml b/guava-gwt/test/com/google/common/cache/testModule.gwt.xml
index 51e2bdc..874969f 100644
--- a/guava-gwt/test/com/google/common/cache/testModule.gwt.xml
+++ b/guava-gwt/test/com/google/common/cache/testModule.gwt.xml
@@ -8,7 +8,7 @@
   <inherits name="com.google.common.collect.Collect"/>
   <inherits name="com.google.common.testing.Testing"/>
   <inherits name="com.google.common.util.concurrent.Concurrent"/>
-  <inherits name="org.truth0.Truth"/>
+  <inherits name="com.google.common.truth.Truth"/>
   <entry-point class="com.google.common.cache.TestModuleEntryPoint"/>
    
   <source path=""/>
diff --git a/guava-gwt/test/com/google/common/collect/ConstraintsTest_gwt.java b/guava-gwt/test/com/google/common/collect/ConstraintsTest_gwt.java
index 36300ec..6c091b2 100644
--- a/guava-gwt/test/com/google/common/collect/ConstraintsTest_gwt.java
+++ b/guava-gwt/test/com/google/common/collect/ConstraintsTest_gwt.java
@@ -43,16 +43,6 @@
   testCase.testConstrainedListRandomAccessFalse();
 }
 
-public void testConstrainedMultisetIllegal() throws Exception {
-  com.google.common.collect.ConstraintsTest testCase = new com.google.common.collect.ConstraintsTest();
-  testCase.testConstrainedMultisetIllegal();
-}
-
-public void testConstrainedMultisetLegal() throws Exception {
-  com.google.common.collect.ConstraintsTest testCase = new com.google.common.collect.ConstraintsTest();
-  testCase.testConstrainedMultisetLegal();
-}
-
 public void testConstrainedSetIllegal() throws Exception {
   com.google.common.collect.ConstraintsTest testCase = new com.google.common.collect.ConstraintsTest();
   testCase.testConstrainedSetIllegal();
@@ -77,9 +67,4 @@
   com.google.common.collect.ConstraintsTest testCase = new com.google.common.collect.ConstraintsTest();
   testCase.testNefariousAddAll();
 }
-
-public void testNotNull() throws Exception {
-  com.google.common.collect.ConstraintsTest testCase = new com.google.common.collect.ConstraintsTest();
-  testCase.testNotNull();
-}
 }
diff --git a/guava-gwt/test/com/google/common/collect/MultimapBuilderTest_gwt.java b/guava-gwt/test/com/google/common/collect/MultimapBuilderTest_gwt.java
index 7efaa5e..d1e18cc 100644
--- a/guava-gwt/test/com/google/common/collect/MultimapBuilderTest_gwt.java
+++ b/guava-gwt/test/com/google/common/collect/MultimapBuilderTest_gwt.java
@@ -23,11 +23,6 @@
   testCase.testGenerics_gwtCompatible();
 }
 
-public void testSerialization() throws Exception {
-  com.google.common.collect.MultimapBuilderTest testCase = new com.google.common.collect.MultimapBuilderTest();
-  testCase.testSerialization();
-}
-
 public void testTreeKeys_gwtCompatible() throws Exception {
   com.google.common.collect.MultimapBuilderTest testCase = new com.google.common.collect.MultimapBuilderTest();
   testCase.testTreeKeys_gwtCompatible();
diff --git a/guava-gwt/test/com/google/common/collect/MultisetsTest_gwt.java b/guava-gwt/test/com/google/common/collect/MultisetsTest_gwt.java
index 409cac0..f758c48 100644
--- a/guava-gwt/test/com/google/common/collect/MultisetsTest_gwt.java
+++ b/guava-gwt/test/com/google/common/collect/MultisetsTest_gwt.java
@@ -83,19 +83,34 @@
   testCase.testNewTreeMultisetNonGeneric();
 }
 
-public void testRemoveEmptyOccurrences() throws Exception {
+public void testRemoveEmptyOccurrencesIterable() throws Exception {
   com.google.common.collect.MultisetsTest testCase = new com.google.common.collect.MultisetsTest();
-  testCase.testRemoveEmptyOccurrences();
+  testCase.testRemoveEmptyOccurrencesIterable();
 }
 
-public void testRemoveOccurrences() throws Exception {
+public void testRemoveEmptyOccurrencesMultiset() throws Exception {
   com.google.common.collect.MultisetsTest testCase = new com.google.common.collect.MultisetsTest();
-  testCase.testRemoveOccurrences();
+  testCase.testRemoveEmptyOccurrencesMultiset();
 }
 
-public void testRemoveOccurrencesEmpty() throws Exception {
+public void testRemoveOccurrencesIterableEmpty() throws Exception {
   com.google.common.collect.MultisetsTest testCase = new com.google.common.collect.MultisetsTest();
-  testCase.testRemoveOccurrencesEmpty();
+  testCase.testRemoveOccurrencesIterableEmpty();
+}
+
+public void testRemoveOccurrencesMultiset() throws Exception {
+  com.google.common.collect.MultisetsTest testCase = new com.google.common.collect.MultisetsTest();
+  testCase.testRemoveOccurrencesMultiset();
+}
+
+public void testRemoveOccurrencesMultisetEmpty() throws Exception {
+  com.google.common.collect.MultisetsTest testCase = new com.google.common.collect.MultisetsTest();
+  testCase.testRemoveOccurrencesMultisetEmpty();
+}
+
+public void testRemoveOccurrencesMultisetIterable() throws Exception {
+  com.google.common.collect.MultisetsTest testCase = new com.google.common.collect.MultisetsTest();
+  testCase.testRemoveOccurrencesMultisetIterable();
 }
 
 public void testRetainEmptyOccurrences() throws Exception {
diff --git a/guava-gwt/test/com/google/common/collect/testModule.gwt.xml b/guava-gwt/test/com/google/common/collect/testModule.gwt.xml
index e21b7ba..888b81a 100644
--- a/guava-gwt/test/com/google/common/collect/testModule.gwt.xml
+++ b/guava-gwt/test/com/google/common/collect/testModule.gwt.xml
@@ -9,7 +9,7 @@
   <inherits name="com.google.common.collect.testing.google.Google"/>
   <inherits name="com.google.common.io.Io"/>
   <inherits name="com.google.common.testing.Testing"/>
-  <inherits name="org.truth0.Truth"/>
+  <inherits name="com.google.common.truth.Truth"/>
   <entry-point class="com.google.common.collect.TestModuleEntryPoint"/>
    
   <source path=""/>
diff --git a/guava-gwt/test/com/google/common/collect/testing/Testing.gwt.xml b/guava-gwt/test/com/google/common/collect/testing/Testing.gwt.xml
index 116b69f..184e212 100644
--- a/guava-gwt/test/com/google/common/collect/testing/Testing.gwt.xml
+++ b/guava-gwt/test/com/google/common/collect/testing/Testing.gwt.xml
@@ -20,7 +20,7 @@
    
   <inherits name="com.google.common.testing.Testing"/>
      
-  <inherits name="org.truth0.Truth"/>
+  <inherits name="com.google.common.truth.Truth"/>
    
   <inherits name="com.google.gwt.core.Core"/>
    
diff --git a/guava-gwt/test/com/google/common/collect/testing/google/Google.gwt.xml b/guava-gwt/test/com/google/common/collect/testing/google/Google.gwt.xml
index 2eccaf1..6f4c380 100644
--- a/guava-gwt/test/com/google/common/collect/testing/google/Google.gwt.xml
+++ b/guava-gwt/test/com/google/common/collect/testing/google/Google.gwt.xml
@@ -28,6 +28,6 @@
 <inherits name="com.google.common.collect.testing.Testing"/>
 <inherits name="com.google.common.primitives.Primitives"/>
 <inherits name="com.google.common.testing.Testing"/>
-<inherits name="org.truth0.Truth"/>
+<inherits name="com.google.common.truth.Truth"/>
 <inherits name="com.google.gwt.core.Core"/>
 </module>
diff --git a/guava-gwt/test/com/google/common/escape/testModule.gwt.xml b/guava-gwt/test/com/google/common/escape/testModule.gwt.xml
index 72a3676..9eb2464 100644
--- a/guava-gwt/test/com/google/common/escape/testModule.gwt.xml
+++ b/guava-gwt/test/com/google/common/escape/testModule.gwt.xml
@@ -8,7 +8,6 @@
   <inherits name="com.google.common.escape.testing.Testing"/>
   <inherits name="com.google.common.html.Html"/>
   <inherits name="com.google.common.testing.Testing"/>
-  <inherits name="com.google.common.annotations.Annotations"/>
   <entry-point class="com.google.common.escape.TestModuleEntryPoint"/>
    
   <source path=""/>
diff --git a/guava-gwt/test/com/google/common/html/testModule.gwt.xml b/guava-gwt/test/com/google/common/html/testModule.gwt.xml
index 45f8473..0346ed1 100644
--- a/guava-gwt/test/com/google/common/html/testModule.gwt.xml
+++ b/guava-gwt/test/com/google/common/html/testModule.gwt.xml
@@ -5,6 +5,7 @@
   <inherits name="com.google.common.base.Base"/>
   <inherits name="com.google.common.escape.testing.Testing"/>
   <inherits name="com.google.common.html.Html"/>
+  <inherits name="com.google.common.truth.Truth"/>
   <entry-point class="com.google.common.html.TestModuleEntryPoint"/>
    
   <source path=""/>
diff --git a/guava-gwt/test/com/google/common/math/testModule.gwt.xml b/guava-gwt/test/com/google/common/math/testModule.gwt.xml
index 53c22b0..91255e3 100644
--- a/guava-gwt/test/com/google/common/math/testModule.gwt.xml
+++ b/guava-gwt/test/com/google/common/math/testModule.gwt.xml
@@ -2,12 +2,12 @@
 <module>
   <inherits name="com.google.gwt.user.User"/>
   <inherits name="com.google.gwt.junit.JUnit"/>
+  <inherits name="com.google.common.annotations.Annotations"/>
   <inherits name="com.google.common.base.Base"/>
   <inherits name="com.google.common.collect.Collect"/>
   <inherits name="com.google.common.math.Math"/>
   <inherits name="com.google.common.testing.Testing"/>
-  <inherits name="org.truth0.Truth"/>
-  <inherits name="com.google.common.annotations.Annotations"/>
+  <inherits name="com.google.common.truth.Truth"/>
   <entry-point class="com.google.common.math.TestModuleEntryPoint"/>
    
   <source path=""/>
diff --git a/guava-gwt/test/com/google/common/net/testModule.gwt.xml b/guava-gwt/test/com/google/common/net/testModule.gwt.xml
index e9bd0a2..bc826a6 100644
--- a/guava-gwt/test/com/google/common/net/testModule.gwt.xml
+++ b/guava-gwt/test/com/google/common/net/testModule.gwt.xml
@@ -9,7 +9,7 @@
   <inherits name="com.google.common.escape.testing.Testing"/>
   <inherits name="com.google.common.net.Net"/>
   <inherits name="com.google.common.testing.Testing"/>
-  <inherits name="org.truth0.Truth"/>
+  <inherits name="com.google.common.truth.Truth"/>
   <entry-point class="com.google.common.net.TestModuleEntryPoint"/>
    
   <source path=""/>
diff --git a/guava-gwt/test/com/google/common/primitives/IntsTest_gwt.java b/guava-gwt/test/com/google/common/primitives/IntsTest_gwt.java
index 550dd5c..7021487 100644
--- a/guava-gwt/test/com/google/common/primitives/IntsTest_gwt.java
+++ b/guava-gwt/test/com/google/common/primitives/IntsTest_gwt.java
@@ -162,4 +162,9 @@
   com.google.common.primitives.IntsTest testCase = new com.google.common.primitives.IntsTest();
   testCase.testToArray_withNull();
 }
+
+public void testTryParse() throws Exception {
+  com.google.common.primitives.IntsTest testCase = new com.google.common.primitives.IntsTest();
+  testCase.testTryParse();
+}
 }
diff --git a/guava-gwt/test/com/google/common/primitives/LongsTest_gwt.java b/guava-gwt/test/com/google/common/primitives/LongsTest_gwt.java
index 5052512..b865b9e 100644
--- a/guava-gwt/test/com/google/common/primitives/LongsTest_gwt.java
+++ b/guava-gwt/test/com/google/common/primitives/LongsTest_gwt.java
@@ -167,4 +167,9 @@
   com.google.common.primitives.LongsTest testCase = new com.google.common.primitives.LongsTest();
   testCase.testToByteArray();
 }
+
+public void testTryParse() throws Exception {
+  com.google.common.primitives.LongsTest testCase = new com.google.common.primitives.LongsTest();
+  testCase.testTryParse();
+}
 }
diff --git a/guava-gwt/test/com/google/common/primitives/testModule.gwt.xml b/guava-gwt/test/com/google/common/primitives/testModule.gwt.xml
index 8e7f7e3..4bec900 100644
--- a/guava-gwt/test/com/google/common/primitives/testModule.gwt.xml
+++ b/guava-gwt/test/com/google/common/primitives/testModule.gwt.xml
@@ -5,7 +5,7 @@
   <inherits name="com.google.common.collect.testing.Testing"/>
   <inherits name="com.google.common.primitives.Primitives"/>
   <inherits name="com.google.common.testing.Testing"/>
-  <inherits name="org.truth0.Truth"/>
+  <inherits name="com.google.common.truth.Truth"/>
   <entry-point class="com.google.common.primitives.TestModuleEntryPoint"/>
    
   <source path=""/>
diff --git a/guava-gwt/test/com/google/common/testing/testModule.gwt.xml b/guava-gwt/test/com/google/common/testing/testModule.gwt.xml
index 0ef66da..cab3664 100644
--- a/guava-gwt/test/com/google/common/testing/testModule.gwt.xml
+++ b/guava-gwt/test/com/google/common/testing/testModule.gwt.xml
@@ -4,7 +4,7 @@
   <inherits name="com.google.gwt.junit.JUnit"/>
   <inherits name="com.google.common.collect.Collect"/>
   <inherits name="com.google.common.testing.Testing"/>
-  <inherits name="org.truth0.Truth"/>
+  <inherits name="com.google.common.truth.Truth"/>
   <entry-point class="com.google.common.testing.TestModuleEntryPoint"/>
    
   <source path=""/>
diff --git a/guava-testlib/pom.xml b/guava-testlib/pom.xml
index 3b7f330..5fe40f1 100644
--- a/guava-testlib/pom.xml
+++ b/guava-testlib/pom.xml
@@ -4,11 +4,11 @@
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>com.google.guava</groupId>
-    <artifactId>guava-parent-jdk5</artifactId>
-    <version>17.0</version>
+    <artifactId>guava-parent</artifactId>
+    <version>18.0</version>
   </parent>
-  <artifactId>guava-testlib-jdk5</artifactId>
-  <name>Guava Testing Library (JDK5 Backport)</name>
+  <artifactId>guava-testlib</artifactId>
+  <name>Guava Testing Library</name>
   <description>
     Guava testlib is a set of java classes used for more convenient
     unit testing - particularly to assist the tests for Guava itself.
@@ -20,22 +20,16 @@
     </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>guava-jdk5</artifactId>
+      <artifactId>guava</artifactId>
       <version>${project.version}</version>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>guava-bootstrap-jdk5</artifactId>
-      <version>${project.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
       <scope>compile</scope><!-- testlib must carry these transitively -->
     </dependency>
     <dependency>
-      <groupId>org.truth0</groupId>
+      <groupId>com.google.truth</groupId>
       <artifactId>truth</artifactId>
       <scope>compile</scope><!-- testlib must carry these transitively -->
     </dependency>
@@ -44,23 +38,6 @@
     <plugins>
       <plugin>
         <artifactId>maven-compiler-plugin</artifactId>
-        <configuration>
-          <!-- Prepend guava-bootstrap to avoid an API incompatibility between JDK5 and JDK6 -->
-          <compilerArgument>-Xbootclasspath/p:${project.build.directory}/dependency/guava-bootstrap-jdk5-${project.version}.jar</compilerArgument>
-        </configuration>
-      </plugin>
-      <plugin>
-        <artifactId>maven-dependency-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>prep-guava-bootstrap</id>
-            <phase>process-sources</phase>
-            <goals><goal>copy-dependencies</goal></goals>
-            <configuration>
-              <includeArtifactIds>guava-bootstrap-jdk5</includeArtifactIds>
-            </configuration>
-          </execution>
-        </executions>
       </plugin>
       <plugin>
         <artifactId>maven-source-plugin</artifactId>
diff --git a/guava-testlib/src/com/google/common/collect/testing/FeatureSpecificTestSuiteBuilder.java b/guava-testlib/src/com/google/common/collect/testing/FeatureSpecificTestSuiteBuilder.java
index 8163bb5..92c7bf2 100644
--- a/guava-testlib/src/com/google/common/collect/testing/FeatureSpecificTestSuiteBuilder.java
+++ b/guava-testlib/src/com/google/common/collect/testing/FeatureSpecificTestSuiteBuilder.java
@@ -320,8 +320,7 @@
       Object featureAsObject = feature; // to work around bogus JDK warning
       if (featureAsObject instanceof Enum) {
         Enum<?> f = (Enum<?>) featureAsObject;
-        temp.add(Platform.classGetSimpleName(
-            f.getDeclaringClass()) + "." + feature);
+        temp.add(f.getDeclaringClass().getSimpleName() + "." + feature);
       } else {
         temp.add(feature.toString());
       }
diff --git a/guava-testlib/src/com/google/common/collect/testing/MapTestSuiteBuilder.java b/guava-testlib/src/com/google/common/collect/testing/MapTestSuiteBuilder.java
index f54596a..c8390f0 100644
--- a/guava-testlib/src/com/google/common/collect/testing/MapTestSuiteBuilder.java
+++ b/guava-testlib/src/com/google/common/collect/testing/MapTestSuiteBuilder.java
@@ -106,7 +106,7 @@
           .createTestSuite());
     }
 
-    derivedSuites.add(SetTestSuiteBuilder.using(
+    derivedSuites.add(createDerivedEntrySetSuite(
             new MapEntrySetGenerator<K, V>(parentBuilder.getSubjectGenerator()))
         .withFeatures(computeEntrySetFeatures(parentBuilder.getFeatures()))
         .named(parentBuilder.getName() + " entrySet")
@@ -120,7 +120,7 @@
         .suppressing(parentBuilder.getSuppressedTests())
         .createTestSuite());
 
-    derivedSuites.add(CollectionTestSuiteBuilder.using(
+    derivedSuites.add(createDerivedValueCollectionSuite(
             new MapValueCollectionGenerator<K, V>(
                 parentBuilder.getSubjectGenerator()))
         .named(parentBuilder.getName() + " values")
@@ -132,10 +132,20 @@
     return derivedSuites;
   }
 
+  protected SetTestSuiteBuilder<Map.Entry<K, V>> createDerivedEntrySetSuite(
+      TestSetGenerator<Map.Entry<K, V>> entrySetGenerator) {
+    return SetTestSuiteBuilder.using(entrySetGenerator);
+  }
+
   protected SetTestSuiteBuilder<K> createDerivedKeySetSuite(TestSetGenerator<K> keySetGenerator) {
     return SetTestSuiteBuilder.using(keySetGenerator);
   }
 
+  protected CollectionTestSuiteBuilder<V> createDerivedValueCollectionSuite(
+      TestCollectionGenerator<V> valueCollectionGenerator) {
+    return CollectionTestSuiteBuilder.using(valueCollectionGenerator);
+  }
+
   private static Set<Feature<?>> computeReserializedMapFeatures(
       Set<Feature<?>> mapFeatures) {
     Set<Feature<?>> derivedFeatures = Helpers.copyToSet(mapFeatures);
diff --git a/guava-testlib/src/com/google/common/collect/testing/NavigableMapTestSuiteBuilder.java b/guava-testlib/src/com/google/common/collect/testing/NavigableMapTestSuiteBuilder.java
new file mode 100644
index 0000000..c31cc61
--- /dev/null
+++ b/guava-testlib/src/com/google/common/collect/testing/NavigableMapTestSuiteBuilder.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2010 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect.testing;
+
+import static com.google.common.collect.testing.Helpers.castOrCopyToList;
+import static java.util.Collections.reverse;
+
+import com.google.common.collect.testing.DerivedCollectionGenerators.Bound;
+import com.google.common.collect.testing.DerivedCollectionGenerators.SortedMapSubmapTestMapGenerator;
+import com.google.common.collect.testing.features.Feature;
+import com.google.common.collect.testing.testers.NavigableMapNavigationTester;
+
+import junit.framework.TestSuite;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NavigableMap;
+import java.util.SortedMap;
+
+/**
+ * Creates, based on your criteria, a JUnit test suite that exhaustively tests
+ * a NavigableMap implementation.
+ */
+public class NavigableMapTestSuiteBuilder<K, V> extends SortedMapTestSuiteBuilder<K, V> {
+  public static <K, V> NavigableMapTestSuiteBuilder<K, V> using(
+      TestSortedMapGenerator<K, V> generator) {
+    NavigableMapTestSuiteBuilder<K, V> result = new NavigableMapTestSuiteBuilder<K, V>();
+    result.usingGenerator(generator);
+    return result;
+  }
+
+  @Override protected List<Class<? extends AbstractTester>> getTesters() {
+    List<Class<? extends AbstractTester>> testers = Helpers.copyToList(super.getTesters());
+    testers.add(NavigableMapNavigationTester.class);
+    return testers;
+  }
+
+  @Override
+  protected List<TestSuite> createDerivedSuites(FeatureSpecificTestSuiteBuilder<?,
+      ? extends OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>>> parentBuilder) {
+    List<TestSuite> derivedSuites = super.createDerivedSuites(parentBuilder);
+
+    if (!parentBuilder.getFeatures().contains(NoRecurse.DESCENDING)) {
+      derivedSuites.add(createDescendingSuite(parentBuilder));
+    }
+
+    if (!parentBuilder.getFeatures().contains(NoRecurse.SUBMAP)) {
+      // Other combinations are inherited from SortedMapTestSuiteBuilder.
+      derivedSuites.add(createSubmapSuite(parentBuilder, Bound.NO_BOUND, Bound.INCLUSIVE));
+      derivedSuites.add(createSubmapSuite(parentBuilder, Bound.EXCLUSIVE, Bound.NO_BOUND));
+      derivedSuites.add(createSubmapSuite(parentBuilder, Bound.EXCLUSIVE, Bound.EXCLUSIVE));
+      derivedSuites.add(createSubmapSuite(parentBuilder, Bound.EXCLUSIVE, Bound.INCLUSIVE));
+      derivedSuites.add(createSubmapSuite(parentBuilder, Bound.INCLUSIVE, Bound.INCLUSIVE));
+    }
+
+    return derivedSuites;
+  }
+
+  @Override protected NavigableSetTestSuiteBuilder<K> createDerivedKeySetSuite(
+      TestSetGenerator<K> keySetGenerator) {
+    return NavigableSetTestSuiteBuilder.using((TestSortedSetGenerator<K>) keySetGenerator);
+  }
+
+  public static final class NavigableMapSubmapTestMapGenerator<K, V>
+      extends SortedMapSubmapTestMapGenerator<K, V> {
+    public NavigableMapSubmapTestMapGenerator(
+        TestSortedMapGenerator<K, V> delegate, Bound to, Bound from) {
+      super(delegate, to, from);
+    }
+
+    @Override NavigableMap<K, V> createSubMap(SortedMap<K, V> sortedMap, K firstExclusive,
+        K lastExclusive) {
+      NavigableMap<K, V> map = (NavigableMap<K, V>) sortedMap;
+      if (from == Bound.NO_BOUND && to == Bound.INCLUSIVE) {
+        return map.headMap(lastInclusive, true);
+      } else if (from == Bound.EXCLUSIVE && to == Bound.NO_BOUND) {
+        return map.tailMap(firstExclusive, false);
+      } else if (from == Bound.EXCLUSIVE && to == Bound.EXCLUSIVE) {
+        return map.subMap(firstExclusive, false, lastExclusive, false);
+      } else if (from == Bound.EXCLUSIVE && to == Bound.INCLUSIVE) {
+        return map.subMap(firstExclusive, false, lastInclusive, true);
+      } else if (from == Bound.INCLUSIVE && to == Bound.INCLUSIVE) {
+        return map.subMap(firstInclusive, true, lastInclusive, true);
+      } else {
+        return (NavigableMap<K, V>) super.createSubMap(map, firstExclusive, lastExclusive);
+      }
+    }
+  }
+
+  @Override
+  public NavigableMapTestSuiteBuilder<K, V> newBuilderUsing(
+      TestSortedMapGenerator<K, V> delegate, Bound to, Bound from) {
+    return using(new NavigableMapSubmapTestMapGenerator<K, V>(delegate, to, from));
+  }
+
+  /**
+   * Create a suite whose maps are descending views of other maps.
+   */
+  private TestSuite createDescendingSuite(final FeatureSpecificTestSuiteBuilder<?,
+          ? extends OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>>> parentBuilder) {
+    final TestMapGenerator<K, V> delegate
+        = (TestMapGenerator<K, V>) parentBuilder.getSubjectGenerator().getInnerGenerator();
+
+    List<Feature<?>> features = new ArrayList<Feature<?>>();
+    features.add(NoRecurse.DESCENDING);
+    features.addAll(parentBuilder.getFeatures());
+
+    return NavigableMapTestSuiteBuilder
+        .using(new ForwardingTestMapGenerator<K, V>(delegate) {
+          @Override public Map<K, V> create(Object... entries) {
+            NavigableMap<K, V> map = (NavigableMap<K, V>) delegate.create(entries);
+            return map.descendingMap();
+          }
+
+          @Override
+          public Iterable<Entry<K, V>> order(List<Entry<K, V>> insertionOrder) {
+            insertionOrder = castOrCopyToList(delegate.order(insertionOrder));
+            reverse(insertionOrder);
+            return insertionOrder;
+          }
+        })
+        .named(parentBuilder.getName() + " descending")
+        .withFeatures(features)
+        .suppressing(parentBuilder.getSuppressedTests())
+        .createTestSuite();
+  }
+
+  static class ForwardingTestMapGenerator<K, V> implements TestMapGenerator<K, V> {
+    private TestMapGenerator<K, V> delegate;
+
+    ForwardingTestMapGenerator(TestMapGenerator<K, V> delegate) {
+      this.delegate = delegate;
+    }
+
+    @Override
+    public Iterable<Entry<K, V>> order(List<Entry<K, V>> insertionOrder) {
+      return delegate.order(insertionOrder);
+    }
+
+    @Override
+    public K[] createKeyArray(int length) {
+      return delegate.createKeyArray(length);
+    }
+
+    @Override
+    public V[] createValueArray(int length) {
+      return delegate.createValueArray(length);
+    }
+
+    @Override
+    public SampleElements<Entry<K, V>> samples() {
+      return delegate.samples();
+    }
+
+    @Override
+    public Map<K, V> create(Object... elements) {
+      return delegate.create(elements);
+    }
+
+    @Override
+    public Entry<K, V>[] createArray(int length) {
+      return delegate.createArray(length);
+    }
+  }
+}
diff --git a/guava-testlib/src/com/google/common/collect/testing/NavigableSetTestSuiteBuilder.java b/guava-testlib/src/com/google/common/collect/testing/NavigableSetTestSuiteBuilder.java
new file mode 100644
index 0000000..4642147
--- /dev/null
+++ b/guava-testlib/src/com/google/common/collect/testing/NavigableSetTestSuiteBuilder.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2010 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect.testing;
+
+import com.google.common.collect.testing.DerivedCollectionGenerators.Bound;
+import com.google.common.collect.testing.DerivedCollectionGenerators.SortedSetSubsetTestSetGenerator;
+import com.google.common.collect.testing.features.CollectionFeature;
+import com.google.common.collect.testing.features.Feature;
+import com.google.common.collect.testing.testers.NavigableSetNavigationTester;
+
+import junit.framework.TestSuite;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.NavigableSet;
+import java.util.Set;
+import java.util.SortedSet;
+
+/**
+ * Creates, based on your criteria, a JUnit test suite that exhaustively tests
+ * a NavigableSet implementation.
+ */
+public final class NavigableSetTestSuiteBuilder<E>
+    extends SortedSetTestSuiteBuilder<E> {
+  public static <E> NavigableSetTestSuiteBuilder<E> using(
+      TestSortedSetGenerator<E> generator) {
+    NavigableSetTestSuiteBuilder<E> builder =
+        new NavigableSetTestSuiteBuilder<E>();
+    builder.usingGenerator(generator);
+    return builder;
+  }
+
+  @Override
+  protected List<TestSuite> createDerivedSuites(FeatureSpecificTestSuiteBuilder<
+      ?, ? extends OneSizeTestContainerGenerator<Collection<E>, E>> parentBuilder) {
+    List<TestSuite> derivedSuites = new ArrayList<TestSuite>(
+        super.createDerivedSuites(parentBuilder));
+
+    if (!parentBuilder.getFeatures().contains(CollectionFeature.SUBSET_VIEW)) {
+      // Other combinations are inherited from SortedSetTestSuiteBuilder.
+      derivedSuites.add(createSubsetSuite(parentBuilder, Bound.NO_BOUND, Bound.INCLUSIVE));
+      derivedSuites.add(createSubsetSuite(parentBuilder, Bound.EXCLUSIVE, Bound.NO_BOUND));
+      derivedSuites.add(createSubsetSuite(parentBuilder, Bound.EXCLUSIVE, Bound.EXCLUSIVE));
+      derivedSuites.add(createSubsetSuite(parentBuilder, Bound.EXCLUSIVE, Bound.INCLUSIVE));
+      derivedSuites.add(createSubsetSuite(parentBuilder, Bound.INCLUSIVE, Bound.INCLUSIVE));
+    }
+    if (!parentBuilder.getFeatures().contains(CollectionFeature.DESCENDING_VIEW)) {
+      derivedSuites.add(createDescendingSuite(parentBuilder));
+    }
+    return derivedSuites;
+  }
+
+  public static final class NavigableSetSubsetTestSetGenerator<E>
+      extends SortedSetSubsetTestSetGenerator<E> {
+    public NavigableSetSubsetTestSetGenerator(
+        TestSortedSetGenerator<E> delegate, Bound to, Bound from) {
+      super(delegate, to, from);
+    }
+
+    @Override NavigableSet<E> createSubSet(SortedSet<E> sortedSet, E firstExclusive,
+        E lastExclusive) {
+      NavigableSet<E> set = (NavigableSet<E>) sortedSet;
+      if (from == Bound.NO_BOUND && to == Bound.INCLUSIVE) {
+        return set.headSet(lastInclusive, true);
+      } else if (from == Bound.EXCLUSIVE && to == Bound.NO_BOUND) {
+        return set.tailSet(firstExclusive, false);
+      } else if (from == Bound.EXCLUSIVE && to == Bound.EXCLUSIVE) {
+        return set.subSet(firstExclusive, false, lastExclusive, false);
+      } else if (from == Bound.EXCLUSIVE && to == Bound.INCLUSIVE) {
+        return set.subSet(firstExclusive, false, lastInclusive, true);
+      } else if (from == Bound.INCLUSIVE && to == Bound.INCLUSIVE) {
+        return set.subSet(firstInclusive, true, lastInclusive, true);
+      } else {
+        return (NavigableSet<E>) super.createSubSet(set, firstExclusive, lastExclusive);
+      }
+    }
+  }
+
+  @Override
+  public NavigableSetTestSuiteBuilder<E> newBuilderUsing(
+      TestSortedSetGenerator<E> delegate, Bound to, Bound from) {
+    return using(new NavigableSetSubsetTestSetGenerator<E>(delegate, to, from));
+  }
+
+  /**
+   * Create a suite whose maps are descending views of other maps.
+   */
+  private TestSuite createDescendingSuite(final FeatureSpecificTestSuiteBuilder<?,
+          ? extends OneSizeTestContainerGenerator<Collection<E>, E>> parentBuilder) {
+    final TestSetGenerator<E> delegate = 
+        (TestSetGenerator<E>) parentBuilder.getSubjectGenerator().getInnerGenerator();
+
+    List<Feature<?>> features = new ArrayList<Feature<?>>();
+    features.add(CollectionFeature.DESCENDING_VIEW);
+    features.addAll(parentBuilder.getFeatures());
+
+    return NavigableSetTestSuiteBuilder.using(new TestSetGenerator<E>() {
+
+          @Override
+          public SampleElements<E> samples() {
+            return delegate.samples();
+          }
+
+          @Override
+          public E[] createArray(int length) {
+            return delegate.createArray(length);
+          }
+
+          @Override
+          public Iterable<E> order(List<E> insertionOrder) {
+            List<E> list = new ArrayList<E>();
+            for (E e : delegate.order(insertionOrder)) {
+              list.add(e);
+            }
+            Collections.reverse(list);
+            return list;
+          }
+
+          @Override
+          public Set<E> create(Object... elements) {
+            NavigableSet<E> navigableSet = (NavigableSet<E>) delegate.create(elements);
+            return navigableSet.descendingSet();
+          }
+        })
+        .named(parentBuilder.getName() + " descending")
+        .withFeatures(features)
+        .suppressing(parentBuilder.getSuppressedTests())
+        .createTestSuite();
+  }
+
+  @Override protected List<Class<? extends AbstractTester>> getTesters() {
+    List<Class<? extends AbstractTester>> testers =
+        Helpers.copyToList(super.getTesters());
+    testers.add(NavigableSetNavigationTester.class);
+    return testers;
+  }
+}
diff --git a/guava-testlib/src/com/google/common/collect/testing/Platform.java b/guava-testlib/src/com/google/common/collect/testing/Platform.java
index a81b9be..99eeb06 100644
--- a/guava-testlib/src/com/google/common/collect/testing/Platform.java
+++ b/guava-testlib/src/com/google/common/collect/testing/Platform.java
@@ -51,9 +51,5 @@
     return String.format(template, args);
   }
 
-  static String classGetSimpleName(Class<?> clazz) {
-    return clazz.getSimpleName();
-  }
-
   private Platform() {}
 }
diff --git a/guava-testlib/src/com/google/common/collect/testing/SafeTreeMap.java b/guava-testlib/src/com/google/common/collect/testing/SafeTreeMap.java
index 59f9608..d120610 100644
--- a/guava-testlib/src/com/google/common/collect/testing/SafeTreeMap.java
+++ b/guava-testlib/src/com/google/common/collect/testing/SafeTreeMap.java
@@ -22,6 +22,8 @@
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
@@ -33,14 +35,15 @@
  *
  * @author Louis Wasserman
  */
-public final class SafeTreeMap<K, V> implements Serializable, SortedMap<K, V> {
+public final class SafeTreeMap<K, V>
+    implements Serializable, NavigableMap<K, V> {
   @SuppressWarnings("unchecked")
   private static final Comparator<Object> NATURAL_ORDER = new Comparator<Object>() {
     @Override public int compare(Object o1, Object o2) {
       return ((Comparable<Object>) o1).compareTo(o2);
     }
   };
-  private final SortedMap<K, V> delegate;
+  private final NavigableMap<K, V> delegate;
 
   public SafeTreeMap() {
     this(new TreeMap<K, V>());
@@ -54,7 +57,11 @@
     this(new TreeMap<K, V>(map));
   }
 
-  private SafeTreeMap(SortedMap<K, V> delegate) {
+  public SafeTreeMap(SortedMap<K, ? extends V> map) {
+    this(new TreeMap<K, V>(map));
+  }
+
+  private SafeTreeMap(NavigableMap<K, V> delegate) {
     this.delegate = delegate;
     if (delegate == null) {
       throw new NullPointerException();
@@ -64,6 +71,14 @@
     }
   }
 
+  @Override public Entry<K, V> ceilingEntry(K key) {
+    return delegate.ceilingEntry(checkValid(key));
+  }
+
+  @Override public K ceilingKey(K key) {
+    return delegate.ceilingKey(checkValid(key));
+  }
+
   @Override public void clear() {
     delegate.clear();
   }
@@ -91,6 +106,14 @@
     return delegate.containsValue(value);
   }
 
+  @Override public NavigableSet<K> descendingKeySet() {
+    return delegate.descendingKeySet();
+  }
+
+  @Override public NavigableMap<K, V> descendingMap() {
+    return new SafeTreeMap<K, V>(delegate.descendingMap());
+  }
+
   @Override public Set<Entry<K, V>> entrySet() {
     return new AbstractSet<Entry<K, V>>() {
       private Set<Entry<K, V>> delegate() {
@@ -130,30 +153,79 @@
     };
   }
 
+  @Override public Entry<K, V> firstEntry() {
+    return delegate.firstEntry();
+  }
+
   @Override public K firstKey() {
     return delegate.firstKey();
   }
 
+  @Override public Entry<K, V> floorEntry(K key) {
+    return delegate.floorEntry(checkValid(key));
+  }
+
+  @Override public K floorKey(K key) {
+    return delegate.floorKey(checkValid(key));
+  }
+
   @Override public V get(Object key) {
     return delegate.get(checkValid(key));
   }
 
   @Override public SortedMap<K, V> headMap(K toKey) {
-    return new SafeTreeMap<K, V>(delegate.headMap(checkValid(toKey)));
+    return headMap(toKey, false);
+  }
+
+  @Override public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
+    return new SafeTreeMap<K, V>(
+        delegate.headMap(checkValid(toKey), inclusive));
+  }
+
+  @Override public Entry<K, V> higherEntry(K key) {
+    return delegate.higherEntry(checkValid(key));
+  }
+
+  @Override public K higherKey(K key) {
+    return delegate.higherKey(checkValid(key));
   }
 
   @Override public boolean isEmpty() {
     return delegate.isEmpty();
   }
 
-  @Override public Set<K> keySet() {
-    return delegate.keySet();
+  @Override public NavigableSet<K> keySet() {
+    return navigableKeySet();
+  }
+
+  @Override public Entry<K, V> lastEntry() {
+    return delegate.lastEntry();
   }
 
   @Override public K lastKey() {
     return delegate.lastKey();
   }
 
+  @Override public Entry<K, V> lowerEntry(K key) {
+    return delegate.lowerEntry(checkValid(key));
+  }
+
+  @Override public K lowerKey(K key) {
+    return delegate.lowerKey(checkValid(key));
+  }
+
+  @Override public NavigableSet<K> navigableKeySet() {
+    return delegate.navigableKeySet();
+  }
+
+  @Override public Entry<K, V> pollFirstEntry() {
+    return delegate.pollFirstEntry();
+  }
+
+  @Override public Entry<K, V> pollLastEntry() {
+    return delegate.pollLastEntry();
+  }
+
   @Override public V put(K key, V value) {
     return delegate.put(checkValid(key), value);
   }
@@ -173,12 +245,23 @@
     return delegate.size();
   }
 
+  @Override public NavigableMap<K, V> subMap(
+      K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+    return new SafeTreeMap<K, V>(delegate.subMap(
+        checkValid(fromKey), fromInclusive, checkValid(toKey), toInclusive));
+  }
+
   @Override public SortedMap<K, V> subMap(K fromKey, K toKey) {
-    return new SafeTreeMap<K, V>(delegate.subMap(checkValid(fromKey), checkValid(toKey)));
+    return subMap(fromKey, true, toKey, false);
   }
 
   @Override public SortedMap<K, V> tailMap(K fromKey) {
-    return new SafeTreeMap<K, V>(delegate.tailMap(checkValid(fromKey)));
+    return tailMap(fromKey, true);
+  }
+
+  @Override public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
+    return new SafeTreeMap<K, V>(
+        delegate.tailMap(checkValid(fromKey), inclusive));
   }
 
   @Override public Collection<V> values() {
@@ -206,5 +289,4 @@
   }
 
   private static final long serialVersionUID = 0L;
-
 }
diff --git a/guava-testlib/src/com/google/common/collect/testing/SafeTreeSet.java b/guava-testlib/src/com/google/common/collect/testing/SafeTreeSet.java
index e19dffa..eb2a45b 100644
--- a/guava-testlib/src/com/google/common/collect/testing/SafeTreeSet.java
+++ b/guava-testlib/src/com/google/common/collect/testing/SafeTreeSet.java
@@ -20,6 +20,7 @@
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.Iterator;
+import java.util.NavigableSet;
 import java.util.SortedSet;
 import java.util.TreeSet;
 
@@ -30,14 +31,14 @@
  *
  * @author Louis Wasserman
  */
-public final class SafeTreeSet<E> implements Serializable, SortedSet<E> {
+public final class SafeTreeSet<E> implements Serializable, NavigableSet<E> {
   @SuppressWarnings("unchecked")
   private static final Comparator<Object> NATURAL_ORDER = new Comparator<Object>() {
     @Override public int compare(Object o1, Object o2) {
       return ((Comparable<Object>) o1).compareTo(o2);
     }
   };
-  private final SortedSet<E> delegate;
+  private final NavigableSet<E> delegate;
 
   public SafeTreeSet() {
     this(new TreeSet<E>());
@@ -51,7 +52,11 @@
     this(new TreeSet<E>(comparator));
   }
 
-  private SafeTreeSet(SortedSet<E> delegate) {
+  public SafeTreeSet(SortedSet<E> set) {
+    this(new TreeSet<E>(set));
+  }
+
+  private SafeTreeSet(NavigableSet<E> delegate) {
     this.delegate = delegate;
     for (E e : this) {
       checkValid(e);
@@ -69,6 +74,10 @@
     return delegate.addAll(collection);
   }
 
+  @Override public E ceiling(E e) {
+    return delegate.ceiling(checkValid(e));
+  }
+
   @Override public void clear() {
     delegate.clear();
   }
@@ -90,12 +99,33 @@
     return delegate.containsAll(c);
   }
 
+  @Override public Iterator<E> descendingIterator() {
+    return delegate.descendingIterator();
+  }
+
+  @Override public NavigableSet<E> descendingSet() {
+    return new SafeTreeSet<E>(delegate.descendingSet());
+  }
+
   @Override public E first() {
     return delegate.first();
   }
 
+  @Override public E floor(E e) {
+    return delegate.floor(checkValid(e));
+  }
+
   @Override public SortedSet<E> headSet(E toElement) {
-    return new SafeTreeSet<E>(delegate.headSet(checkValid(toElement)));
+    return headSet(toElement, false);
+  }
+
+  @Override public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+    return new SafeTreeSet<E>(
+        delegate.headSet(checkValid(toElement), inclusive));
+  }
+
+  @Override public E higher(E e) {
+    return delegate.higher(checkValid(e));
   }
 
   @Override public boolean isEmpty() {
@@ -110,6 +140,18 @@
     return delegate.last();
   }
 
+  @Override public E lower(E e) {
+    return delegate.lower(checkValid(e));
+  }
+
+  @Override public E pollFirst() {
+    return delegate.pollFirst();
+  }
+
+  @Override public E pollLast() {
+    return delegate.pollLast();
+  }
+
   @Override public boolean remove(Object object) {
     return delegate.remove(checkValid(object));
   }
@@ -126,13 +168,23 @@
     return delegate.size();
   }
 
+  @Override public NavigableSet<E> subSet(
+      E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+    return new SafeTreeSet<E>(
+        delegate.subSet(checkValid(fromElement), fromInclusive,
+            checkValid(toElement), toInclusive));
+  }
 
   @Override public SortedSet<E> subSet(E fromElement, E toElement) {
-    return new SafeTreeSet<E>(delegate.subSet(checkValid(fromElement), checkValid(toElement)));
+    return subSet(fromElement, true, toElement, false);
   }
 
   @Override public SortedSet<E> tailSet(E fromElement) {
-    return new SafeTreeSet<E>(delegate.tailSet(checkValid(fromElement)));
+    return tailSet(fromElement, true);
+  }
+
+  @Override public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+    return new SafeTreeSet<E>(delegate.tailSet(checkValid(fromElement), inclusive));
   }
 
   @Override public Object[] toArray() {
diff --git a/guava-testlib/src/com/google/common/collect/testing/TestsForMapsInJavaUtil.java b/guava-testlib/src/com/google/common/collect/testing/TestsForMapsInJavaUtil.java
index 2cd055f..72db7f6 100644
--- a/guava-testlib/src/com/google/common/collect/testing/TestsForMapsInJavaUtil.java
+++ b/guava-testlib/src/com/google/common/collect/testing/TestsForMapsInJavaUtil.java
@@ -33,7 +33,10 @@
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.SortedMap;
+import java.util.TreeMap;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListMap;
 
 /**
  * Generates a test suite covering the {@link Map} implementations in the
@@ -54,8 +57,12 @@
     suite.addTest(testsForSingletonMap());
     suite.addTest(testsForHashMap());
     suite.addTest(testsForLinkedHashMap());
+    suite.addTest(testsForTreeMapNatural());
+    suite.addTest(testsForTreeMapWithComparator());
     suite.addTest(testsForEnumMap());
     suite.addTest(testsForConcurrentHashMap());
+    suite.addTest(testsForConcurrentSkipListMapNatural());
+    suite.addTest(testsForConcurrentSkipListMapWithComparator());
     return suite;
   }
 
@@ -168,6 +175,55 @@
         .createTestSuite();
   }
 
+  public Test testsForTreeMapNatural() {
+    return NavigableMapTestSuiteBuilder
+        .using(new TestStringSortedMapGenerator() {
+            @Override protected SortedMap<String, String> create(
+                Entry<String, String>[] entries) {
+              /*
+               * TODO(cpovirk): it would be nice to create an input Map and use
+               * the copy constructor here and in the other tests
+               */
+              return populate(new TreeMap<String, String>(), entries);
+            }
+          })
+        .named("TreeMap, natural")
+        .withFeatures(
+            MapFeature.GENERAL_PURPOSE,
+            MapFeature.ALLOWS_NULL_VALUES,
+            MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION,
+            CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
+            CollectionFeature.KNOWN_ORDER,
+            CollectionFeature.SERIALIZABLE,
+            CollectionSize.ANY)
+        .suppressing(suppressForTreeMapNatural())
+        .createTestSuite();
+  }
+
+  public Test testsForTreeMapWithComparator() {
+    return NavigableMapTestSuiteBuilder
+        .using(new TestStringSortedMapGenerator() {
+            @Override protected SortedMap<String, String> create(
+                Entry<String, String>[] entries) {
+              return populate(new TreeMap<String, String>(
+                  arbitraryNullFriendlyComparator()), entries);
+            }
+          })
+        .named("TreeMap, with comparator")
+        .withFeatures(
+            MapFeature.GENERAL_PURPOSE,
+            MapFeature.ALLOWS_NULL_KEYS,
+            MapFeature.ALLOWS_NULL_VALUES,
+            MapFeature.ALLOWS_ANY_NULL_QUERIES,
+            MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION,
+            CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
+            CollectionFeature.KNOWN_ORDER,
+            CollectionFeature.SERIALIZABLE,
+            CollectionSize.ANY)
+        .suppressing(suppressForTreeMapWithComparator())
+        .createTestSuite();
+  }
+
   public Test testsForEnumMap() {
     return MapTestSuiteBuilder
         .using(new TestEnumMapGenerator() {
@@ -208,6 +264,45 @@
         .createTestSuite();
   }
 
+  public Test testsForConcurrentSkipListMapNatural() {
+    return NavigableMapTestSuiteBuilder
+        .using(new TestStringSortedMapGenerator() {
+          @Override protected SortedMap<String, String> create(
+              Entry<String, String>[] entries) {
+            return populate(new ConcurrentSkipListMap<String, String>(), entries);
+          }
+        })
+        .named("ConcurrentSkipListMap, natural")
+        .withFeatures(
+            MapFeature.GENERAL_PURPOSE,
+            CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
+            CollectionFeature.KNOWN_ORDER,
+            CollectionFeature.SERIALIZABLE,
+            CollectionSize.ANY)
+        .suppressing(suppressForConcurrentSkipListMap())
+        .createTestSuite();
+  }
+
+  public Test testsForConcurrentSkipListMapWithComparator() {
+    return NavigableMapTestSuiteBuilder
+        .using(new TestStringSortedMapGenerator() {
+          @Override protected SortedMap<String, String> create(
+              Entry<String, String>[] entries) {
+            return populate(new ConcurrentSkipListMap<String, String>(
+                arbitraryNullFriendlyComparator()), entries);
+          }
+        })
+        .named("ConcurrentSkipListMap, with comparator")
+        .withFeatures(
+            MapFeature.GENERAL_PURPOSE,
+            CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
+            CollectionFeature.KNOWN_ORDER,
+            CollectionFeature.SERIALIZABLE,
+            CollectionSize.ANY)
+        .suppressing(suppressForConcurrentSkipListMap())
+        .createTestSuite();
+  }
+
   // TODO: IdentityHashMap, AbstractMap
 
   private static Map<String, String> toHashMap(
diff --git a/guava-testlib/src/com/google/common/collect/testing/TestsForSetsInJavaUtil.java b/guava-testlib/src/com/google/common/collect/testing/TestsForSetsInJavaUtil.java
index ee726bd..480499e 100644
--- a/guava-testlib/src/com/google/common/collect/testing/TestsForSetsInJavaUtil.java
+++ b/guava-testlib/src/com/google/common/collect/testing/TestsForSetsInJavaUtil.java
@@ -36,6 +36,7 @@
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
+import java.util.concurrent.ConcurrentSkipListSet;
 import java.util.concurrent.CopyOnWriteArraySet;
 
 /**
@@ -64,6 +65,8 @@
     suite.addTest(testsForCheckedSet());
     suite.addTest(testsForAbstractSet());
     suite.addTest(testsForBadlyCollidingHashSet());
+    suite.addTest(testsForConcurrentSkipListSetNatural());
+    suite.addTest(testsForConcurrentSkipListSetWithComparator());
 
     return suite;
   }
@@ -197,7 +200,7 @@
   }
 
   public Test testsForTreeSetNatural() {
-    return SortedSetTestSuiteBuilder
+    return NavigableSetTestSuiteBuilder
         .using(new TestStringSortedSetGenerator() {
             @Override public SortedSet<String> create(String[] elements) {
               return new TreeSet<String>(MinimalCollection.of(elements));
@@ -215,7 +218,7 @@
   }
 
   public Test testsForTreeSetWithComparator() {
-    return SortedSetTestSuiteBuilder
+    return NavigableSetTestSuiteBuilder
         .using(new TestStringSortedSetGenerator() {
             @Override public SortedSet<String> create(String[] elements) {
               SortedSet<String> set
@@ -337,6 +340,43 @@
         .createTestSuite();
   }
 
+  public Test testsForConcurrentSkipListSetNatural() {
+    return SetTestSuiteBuilder
+        .using(new TestStringSortedSetGenerator() {
+            @Override public SortedSet<String> create(String[] elements) {
+              return new ConcurrentSkipListSet<String>(MinimalCollection.of(elements));
+            }
+          })
+        .named("ConcurrentSkipListSet, natural")
+        .withFeatures(
+            SetFeature.GENERAL_PURPOSE,
+            CollectionFeature.SERIALIZABLE,
+            CollectionFeature.KNOWN_ORDER,
+            CollectionSize.ANY)
+        .suppressing(suppressForConcurrentSkipListSetNatural())
+        .createTestSuite();
+  }
+
+  public Test testsForConcurrentSkipListSetWithComparator() {
+    return SetTestSuiteBuilder
+        .using(new TestStringSortedSetGenerator() {
+            @Override public SortedSet<String> create(String[] elements) {
+              SortedSet<String> set
+                  = new ConcurrentSkipListSet<String>(arbitraryNullFriendlyComparator());
+              Collections.addAll(set, elements);
+              return set;
+            }
+          })
+        .named("ConcurrentSkipListSet, with comparator")
+        .withFeatures(
+            SetFeature.GENERAL_PURPOSE,
+            CollectionFeature.SERIALIZABLE,
+            CollectionFeature.KNOWN_ORDER,
+            CollectionSize.ANY)
+        .suppressing(suppressForConcurrentSkipListSetWithComparator())
+        .createTestSuite();
+  }
+
   private static String[] dedupe(String[] elements) {
     Set<String> tmp = new LinkedHashSet<String>();
     Collections.addAll(tmp, elements);
@@ -346,7 +386,7 @@
   static <T> Comparator<T> arbitraryNullFriendlyComparator() {
     return new NullFriendlyComparator<T>();
   }
-
+  
   private static final class NullFriendlyComparator<T>
       implements Comparator<T>, Serializable {
     @Override
diff --git a/guava-testlib/src/com/google/common/collect/testing/features/FeatureUtil.java b/guava-testlib/src/com/google/common/collect/testing/features/FeatureUtil.java
index 344e374..491fe08 100644
--- a/guava-testlib/src/com/google/common/collect/testing/features/FeatureUtil.java
+++ b/guava-testlib/src/com/google/common/collect/testing/features/FeatureUtil.java
@@ -214,7 +214,7 @@
   private static TesterRequirements buildTesterRequirements(
       Annotation testerAnnotation)
       throws ConflictingRequirementsException {
-    Class<? extends Annotation> annotationClass = testerAnnotation.getClass();
+    Class<? extends Annotation> annotationClass = testerAnnotation.annotationType();
     final Feature<?>[] presentFeatures;
     final Feature<?>[] absentFeatures;
     try {
diff --git a/guava-testlib/src/com/google/common/collect/testing/google/AbstractListMultimapTester.java b/guava-testlib/src/com/google/common/collect/testing/google/AbstractListMultimapTester.java
index 2f63606..acf973c 100644
--- a/guava-testlib/src/com/google/common/collect/testing/google/AbstractListMultimapTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/google/AbstractListMultimapTester.java
@@ -14,7 +14,7 @@
 
 package com.google.common.collect.testing.google;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.ListMultimap;
@@ -36,13 +36,13 @@
   }
 
   protected void assertGet(K key, Collection<V> values) {
-    ASSERT.that(multimap().get(key)).has().exactlyAs(values).inOrder();
+    assertThat(multimap().get(key)).has().exactlyAs(values).inOrder();
 
     if (!values.isEmpty()) {
-      ASSERT.that(multimap().asMap().get(key)).has().exactlyAs(values).inOrder();
+      assertThat(multimap().asMap().get(key)).has().exactlyAs(values).inOrder();
       assertFalse(multimap().isEmpty());
     } else {
-      ASSERT.that(multimap().asMap().get(key)).isNull();
+      assertThat(multimap().asMap().get(key)).isNull();
     }
 
     assertEquals(values.size(), multimap().get(key).size());
diff --git a/guava-testlib/src/com/google/common/collect/testing/google/AbstractMultimapTester.java b/guava-testlib/src/com/google/common/collect/testing/google/AbstractMultimapTester.java
index 5e84314..f307c36 100644
--- a/guava-testlib/src/com/google/common/collect/testing/google/AbstractMultimapTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/google/AbstractMultimapTester.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect.testing.google;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.Multimap;
@@ -145,18 +145,18 @@
   }
 
   protected void assertGet(K key, Collection<V> values) {
-    ASSERT.that(multimap().get(key)).has().exactlyAs(values);
+    assertThat(multimap().get(key)).has().exactlyAs(values);
 
     if (!values.isEmpty()) {
-      ASSERT.that(multimap().asMap().get(key)).has().exactlyAs(values);
+      assertThat(multimap().asMap().get(key)).has().exactlyAs(values);
       assertFalse(multimap().isEmpty());
     } else {
-      ASSERT.that(multimap().asMap().get(key)).isNull();
+      assertThat(multimap().asMap().get(key)).isNull();
     }
 
     // TODO(user): Add proper overrides to prevent autoboxing.
     // Truth+autoboxing == compile error. Cast int to long to fix:
-    ASSERT.that(multimap().get(key).size()).is((long) values.size());
+    assertThat(multimap().get(key).size()).isEqualTo((long) values.size());
 
     assertEquals(values.size() > 0, multimap().containsKey(key));
     assertEquals(values.size() > 0, multimap().keySet().contains(key));
diff --git a/guava-testlib/src/com/google/common/collect/testing/google/ListMultimapRemoveTester.java b/guava-testlib/src/com/google/common/collect/testing/google/ListMultimapRemoveTester.java
index 9cab13e..e84e4bb 100644
--- a/guava-testlib/src/com/google/common/collect/testing/google/ListMultimapRemoveTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/google/ListMultimapRemoveTester.java
@@ -18,7 +18,7 @@
 import static com.google.common.collect.testing.Helpers.mapEntry;
 import static com.google.common.collect.testing.features.CollectionSize.SEVERAL;
 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_REMOVE;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.ListMultimap;
@@ -48,7 +48,7 @@
 
     List<V> list = multimap().get(k);
     multimap().remove(k, v0);
-    ASSERT.that(list).has().exactly(v1, v0).inOrder();
+    assertThat(list).has().exactly(v1, v0).inOrder();
   }
 
   @SuppressWarnings("unchecked")
diff --git a/guava-testlib/src/com/google/common/collect/testing/google/MultimapAsMapGetTester.java b/guava-testlib/src/com/google/common/collect/testing/google/MultimapAsMapGetTester.java
index d43b1ee..88e576e 100644
--- a/guava-testlib/src/com/google/common/collect/testing/google/MultimapAsMapGetTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/google/MultimapAsMapGetTester.java
@@ -22,7 +22,7 @@
 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_VALUE_QUERIES;
 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_PUT;
 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_REMOVE;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.Multimap;
@@ -67,7 +67,7 @@
     Collection<V> result = multimap().asMap().get(sampleKeys().e0);
     result.clear();
     assertGet(sampleKeys().e0);
-    ASSERT.that(result).isEmpty();
+    assertThat(result).isEmpty();
   }
   
   @CollectionSize.Require(absent = ZERO)
@@ -100,7 +100,7 @@
   public void testPropagatesAddToMultimap() {
     Collection<V> result = multimap().asMap().get(sampleKeys().e0);
     result.add(sampleValues().e3);
-    ASSERT.that(multimap().get(sampleKeys().e0))
+    assertThat(multimap().get(sampleKeys().e0))
         .has().exactly(sampleValues().e0, sampleValues().e3);
   }
 
@@ -117,7 +117,7 @@
 
     assertFalse(multimap().containsKey(k0));
     assertFalse(multimap().containsEntry(k0, v0));
-    ASSERT.that(result).isEmpty();
+    assertThat(result).isEmpty();
 
     V v1 = sampleValues().e1;
     V v2 = sampleValues().e2;
@@ -125,8 +125,8 @@
     assertTrue(result.add(v1));
     assertTrue(result.add(v2));
 
-    ASSERT.that(result).has().exactly(v1, v2);
-    ASSERT.that(multimap().get(k0)).has().exactly(v1, v2);
+    assertThat(result).has().exactly(v1, v2);
+    assertThat(multimap().get(k0)).has().exactly(v1, v2);
     assertTrue(multimap().containsKey(k0));
     assertFalse(multimap().containsEntry(k0, v0));
     assertTrue(multimap().containsEntry(k0, v2));
@@ -138,6 +138,6 @@
   public void testReflectsMultimapRemove() {
     Collection<V> result = multimap().asMap().get(sampleKeys().e0);
     multimap().removeAll(sampleKeys().e0);
-    ASSERT.that(result).isEmpty();
+    assertThat(result).isEmpty();
   }
 }
diff --git a/guava-testlib/src/com/google/common/collect/testing/google/MultimapAsMapTester.java b/guava-testlib/src/com/google/common/collect/testing/google/MultimapAsMapTester.java
index 8e75055..b18f35b 100644
--- a/guava-testlib/src/com/google/common/collect/testing/google/MultimapAsMapTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/google/MultimapAsMapTester.java
@@ -21,7 +21,7 @@
 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_KEY_QUERIES;
 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_PUT;
 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_REMOVE;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.Iterables;
@@ -56,9 +56,9 @@
 
       Collection<V> collection = multimap().asMap().get(key);
       if (expectedValues.isEmpty()) {
-        ASSERT.that(collection).isNull();
+        assertThat(collection).isNull();
       } else {
-        ASSERT.that(collection).has().exactlyAs(expectedValues);
+        assertThat(collection).has().exactlyAs(expectedValues);
       }
     }
   }
@@ -67,12 +67,12 @@
   @MapFeature.Require(ALLOWS_NULL_KEYS)
   public void testAsMapGetNullKeyPresent() {
     initMultimapWithNullKey();
-    ASSERT.that(multimap().asMap().get(null)).has().exactly(getValueForNullKey());
+    assertThat(multimap().asMap().get(null)).has().exactly(getValueForNullKey());
   }
  
   @MapFeature.Require(ALLOWS_NULL_KEY_QUERIES)
   public void testAsMapGetNullKeyAbsent() {
-    ASSERT.that(multimap().asMap().get(null)).isNull();
+    assertThat(multimap().asMap().get(null)).isNull();
   }
  
   @MapFeature.Require(absent = ALLOWS_NULL_KEY_QUERIES)
@@ -86,7 +86,7 @@
   @CollectionSize.Require(absent = ZERO)
   @MapFeature.Require(SUPPORTS_REMOVE)
   public void testAsMapRemove() {
-    ASSERT.that(multimap().asMap().remove(sampleKeys().e0)).iteratesAs(sampleValues().e0);
+    assertThat(multimap().asMap().remove(sampleKeys().e0)).iteratesAs(sampleValues().e0);
     assertGet(sampleKeys().e0);
     assertEquals(getNumElements() - 1, multimap().size());
   }
@@ -100,10 +100,10 @@
     
     Set<Entry<K, Collection<V>>> asMapEntrySet = multimap().asMap().entrySet();
     Collection<V> valueCollection = Iterables.getOnlyElement(asMapEntrySet).getValue();
-    ASSERT.that(valueCollection)
+    assertThat(valueCollection)
         .has().exactly(sampleValues().e0, sampleValues().e3);
     assertTrue(multimap().put(sampleKeys().e0, sampleValues().e4));
-    ASSERT.that(valueCollection)
+    assertThat(valueCollection)
         .has().exactly(sampleValues().e0, sampleValues().e3, sampleValues().e4);
   }
 
@@ -130,7 +130,7 @@
     assertTrue(multimap().put(sampleKeys().e1, sampleValues().e4));
     assertTrue(asMapEntrySet.remove(asMapEntry0));
     assertEquals(1, multimap().size());
-    ASSERT.that(multimap().keySet()).iteratesAs(sampleKeys().e1);
+    assertThat(multimap().keySet()).iteratesAs(sampleKeys().e1);
   }
 
   @CollectionSize.Require(SEVERAL)
diff --git a/guava-testlib/src/com/google/common/collect/testing/google/MultimapClearTester.java b/guava-testlib/src/com/google/common/collect/testing/google/MultimapClearTester.java
index 9bdcdae..5c25fe4 100644
--- a/guava-testlib/src/com/google/common/collect/testing/google/MultimapClearTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/google/MultimapClearTester.java
@@ -18,7 +18,7 @@
 
 import static com.google.common.collect.testing.features.CollectionSize.ZERO;
 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_REMOVE;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.Multimap;
@@ -49,11 +49,11 @@
     assertEquals(0, multimap().size());
     assertTrue(multimap().isEmpty());
     assertEquals(multimap(), getSubjectGenerator().create());
-    ASSERT.that(multimap().entries()).isEmpty();
-    ASSERT.that(multimap().asMap()).isEmpty();
-    ASSERT.that(multimap().keySet()).isEmpty();
-    ASSERT.that(multimap().keys()).isEmpty();
-    ASSERT.that(multimap().values()).isEmpty();
+    assertThat(multimap().entries()).isEmpty();
+    assertThat(multimap().asMap()).isEmpty();
+    assertThat(multimap().keySet()).isEmpty();
+    assertThat(multimap().keys()).isEmpty();
+    assertThat(multimap().values()).isEmpty();
     for (K key : sampleKeys()) {
       assertGet(key);
     }
@@ -102,7 +102,7 @@
       resetContainer();
       Collection<V> collection = multimap().get(key);
       multimap().clear();
-      ASSERT.that(collection).isEmpty();
+      assertThat(collection).isEmpty();
     }
   }
 
@@ -114,7 +114,7 @@
       Collection<V> collection = multimap().asMap().get(key);
       if (collection != null) {
         multimap().clear();
-        ASSERT.that(collection).isEmpty();
+        assertThat(collection).isEmpty();
       }
     }
   }
@@ -123,13 +123,13 @@
   public void testClearPropagatesToAsMap() {
     Map<K, Collection<V>> asMap = multimap().asMap();
     multimap().clear();
-    ASSERT.that(asMap).isEmpty();
+    assertThat(asMap).isEmpty();
   }
 
   @MapFeature.Require(SUPPORTS_REMOVE)
   public void testClearPropagatesToEntries() {
     Collection<Entry<K, V>> entries = multimap().entries();
     multimap().clear();
-    ASSERT.that(entries).isEmpty();
+    assertThat(entries).isEmpty();
   }
 }
diff --git a/guava-testlib/src/com/google/common/collect/testing/google/MultimapEntriesTester.java b/guava-testlib/src/com/google/common/collect/testing/google/MultimapEntriesTester.java
index d939cad..c815631 100644
--- a/guava-testlib/src/com/google/common/collect/testing/google/MultimapEntriesTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/google/MultimapEntriesTester.java
@@ -22,7 +22,7 @@
 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_VALUES;
 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_VALUE_QUERIES;
 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_REMOVE;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.Multimap;
@@ -43,14 +43,14 @@
 @GwtCompatible
 public class MultimapEntriesTester<K, V> extends AbstractMultimapTester<K, V, Multimap<K, V>> {
   public void testEntries() {
-    ASSERT.that(multimap().entries()).has().exactlyAs(getSampleElements());
+    assertThat(multimap().entries()).has().exactlyAs(getSampleElements());
   }
   
   @CollectionSize.Require(absent = ZERO)
   @MapFeature.Require(ALLOWS_NULL_KEYS)
   public void testContainsEntryWithNullKeyPresent() {
     initMultimapWithNullKey();
-    ASSERT.that(multimap().entries()).has().allOf(
+    assertThat(multimap().entries()).has().allOf(
         Helpers.mapEntry((K) null, getValueForNullKey()));
   }
   
@@ -63,7 +63,7 @@
   @MapFeature.Require(ALLOWS_NULL_VALUES)
   public void testContainsEntryWithNullValuePresent() {
     initMultimapWithNullValue();
-    ASSERT.that(multimap().entries()).has().allOf(
+    assertThat(multimap().entries()).has().allOf(
         Helpers.mapEntry(getKeyForNullValue(), (V) null));
   }
   
diff --git a/guava-testlib/src/com/google/common/collect/testing/google/MultimapGetTester.java b/guava-testlib/src/com/google/common/collect/testing/google/MultimapGetTester.java
index 5f84a86..1dc82d6 100644
--- a/guava-testlib/src/com/google/common/collect/testing/google/MultimapGetTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/google/MultimapGetTester.java
@@ -23,7 +23,7 @@
 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_VALUES;
 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_PUT;
 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_REMOVE;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.Multimap;
@@ -122,7 +122,7 @@
 
     assertFalse(multimap().containsKey(k0));
     assertFalse(multimap().containsEntry(k0, v0));
-    ASSERT.that(result).isEmpty();
+    assertThat(result).isEmpty();
 
     V v1 = sampleValues().e1;
     V v2 = sampleValues().e2;
@@ -130,8 +130,8 @@
     assertTrue(result.add(v1));
     assertTrue(result.add(v2));
 
-    ASSERT.that(result).has().exactly(v1, v2);
-    ASSERT.that(multimap().get(k0)).has().exactly(v1, v2);
+    assertThat(result).has().exactly(v1, v2);
+    assertThat(multimap().get(k0)).has().exactly(v1, v2);
     assertTrue(multimap().containsKey(k0));
     assertFalse(multimap().containsEntry(k0, v0));
     assertTrue(multimap().containsEntry(k0, v2));
@@ -142,12 +142,12 @@
   @CollectionSize.Require(absent = ZERO)
   public void testGetNullPresent() {
     initMultimapWithNullKey();
-    ASSERT.that(multimap().get(null)).has().item(getValueForNullKey());
+    assertThat(multimap().get(null)).has().item(getValueForNullKey());
   }
 
   @MapFeature.Require(ALLOWS_NULL_KEY_QUERIES)
   public void testGetNullAbsent() {
-    ASSERT.that(multimap().get(null)).isEmpty();
+    assertThat(multimap().get(null)).isEmpty();
   }
 
   @MapFeature.Require(absent = ALLOWS_NULL_KEY_QUERIES)
@@ -164,7 +164,7 @@
   @CollectionSize.Require(absent = ZERO)
   public void testGetWithNullValue() {
     initMultimapWithNullValue();
-    ASSERT.that(multimap().get(getKeyForNullValue()))
+    assertThat(multimap().get(getKeyForNullValue()))
         .has().item(null);
   }
 }
diff --git a/guava-testlib/src/com/google/common/collect/testing/google/MultimapKeysTester.java b/guava-testlib/src/com/google/common/collect/testing/google/MultimapKeysTester.java
index e0d4310..b331030 100644
--- a/guava-testlib/src/com/google/common/collect/testing/google/MultimapKeysTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/google/MultimapKeysTester.java
@@ -20,7 +20,7 @@
 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_KEYS;
 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_KEY_QUERIES;
 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_REMOVE;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.Multimap;
@@ -50,8 +50,8 @@
     assertEquals(2, keys.count(sampleKeys().e0));
     assertEquals(1, keys.count(sampleKeys().e1));
     assertEquals(3, keys.size());
-    ASSERT.that(keys).has().allOf(sampleKeys().e0, sampleKeys().e1);
-    ASSERT.that(keys.entrySet()).has().allOf(
+    assertThat(keys).has().allOf(sampleKeys().e0, sampleKeys().e1);
+    assertThat(keys.entrySet()).has().allOf(
         Multisets.immutableEntry(sampleKeys().e0, 2),
         Multisets.immutableEntry(sampleKeys().e1, 1));
   }
@@ -72,8 +72,8 @@
     assertEquals(2, keys.count(null));
     assertEquals(1, keys.count(sampleKeys().e1));
     assertEquals(3, keys.size());
-    ASSERT.that(keys).has().allOf(null, sampleKeys().e1);
-    ASSERT.that(keys.entrySet()).has().allOf(
+    assertThat(keys).has().allOf(null, sampleKeys().e1);
+    assertThat(keys.entrySet()).has().allOf(
         Multisets.immutableEntry((K) null, 2),
         Multisets.immutableEntry(sampleKeys().e1, 1));
   }
diff --git a/guava-testlib/src/com/google/common/collect/testing/google/MultimapPutAllMultimapTester.java b/guava-testlib/src/com/google/common/collect/testing/google/MultimapPutAllMultimapTester.java
index a07b565..fc65e5c 100644
--- a/guava-testlib/src/com/google/common/collect/testing/google/MultimapPutAllMultimapTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/google/MultimapPutAllMultimapTester.java
@@ -19,7 +19,7 @@
 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_KEYS;
 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_VALUES;
 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_PUT;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.Multimap;
@@ -109,6 +109,6 @@
     int getCollectionSize = getCollection.size();
     assertTrue(multimap().putAll(source));
     assertEquals(getCollectionSize + 1, getCollection.size());
-    ASSERT.that(getCollection).has().allOf(sampleValues().e3);
+    assertThat(getCollection).has().allOf(sampleValues().e3);
   }
 }
diff --git a/guava-testlib/src/com/google/common/collect/testing/google/MultimapPutIterableTester.java b/guava-testlib/src/com/google/common/collect/testing/google/MultimapPutIterableTester.java
index cce6800..5e2768c 100644
--- a/guava-testlib/src/com/google/common/collect/testing/google/MultimapPutIterableTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/google/MultimapPutIterableTester.java
@@ -20,7 +20,7 @@
 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_KEYS;
 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_VALUES;
 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_PUT;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.Iterators;
@@ -209,6 +209,6 @@
     assertTrue(multimap().putAll(
         sampleKeys().e0, Lists.newArrayList(sampleValues().e3, sampleValues().e4)));
     assertEquals(getCollectionSize + 2, getCollection.size());
-    ASSERT.that(getCollection).has().allOf(sampleValues().e3, sampleValues().e4);
+    assertThat(getCollection).has().allOf(sampleValues().e3, sampleValues().e4);
   }
 }
diff --git a/guava-testlib/src/com/google/common/collect/testing/google/MultimapPutTester.java b/guava-testlib/src/com/google/common/collect/testing/google/MultimapPutTester.java
index 636f2b3..5ac36a4 100644
--- a/guava-testlib/src/com/google/common/collect/testing/google/MultimapPutTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/google/MultimapPutTester.java
@@ -20,7 +20,7 @@
 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_KEYS;
 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_VALUES;
 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_PUT;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.ImmutableList;
@@ -137,9 +137,9 @@
   public void testPutNotPresentKeyPropagatesToGet() {
     int size = getNumElements();
     Collection<V> collection = multimap().get(sampleKeys().e3);
-    ASSERT.that(collection).isEmpty();
+    assertThat(collection).isEmpty();
     multimap().put(sampleKeys().e3, sampleValues().e3);
-    ASSERT.that(collection).has().item(sampleValues().e3);
+    assertThat(collection).has().item(sampleValues().e3);
     assertEquals(size + 1, multimap().size());
   }
 
@@ -148,7 +148,7 @@
     Collection<Entry<K, V>> entries = multimap().entries();
     assertFalse(entries.contains(Helpers.mapEntry(sampleKeys().e3, sampleValues().e3)));
     multimap().put(sampleKeys().e3, sampleValues().e3);
-    ASSERT.that(entries).has().allOf(Helpers.mapEntry(sampleKeys().e3, sampleValues().e3));
+    assertThat(entries).has().allOf(Helpers.mapEntry(sampleKeys().e3, sampleValues().e3));
   }
 
   @CollectionSize.Require(absent = ZERO)
@@ -157,7 +157,7 @@
     Collection<Entry<K, V>> entries = multimap().entries();
     assertFalse(entries.contains(Helpers.mapEntry(sampleKeys().e0, sampleValues().e3)));
     multimap().put(sampleKeys().e0, sampleValues().e3);
-    ASSERT.that(entries).has().allOf(Helpers.mapEntry(sampleKeys().e0, sampleValues().e3));
+    assertThat(entries).has().allOf(Helpers.mapEntry(sampleKeys().e0, sampleValues().e3));
   }
 
   @MapFeature.Require(SUPPORTS_PUT)
@@ -174,7 +174,7 @@
 
       multimap().put(key, sampleValues().e3);
       expectedCollection.add(sampleValues().e3);
-      ASSERT.that(collection).has().exactlyAs(expectedCollection);
+      assertThat(collection).has().exactlyAs(expectedCollection);
       assertEquals(size + 1, multimap().size());
     }
   }
@@ -194,7 +194,7 @@
 
       multimap().put(key, sampleValues().e3);
       expectedCollection.add(sampleValues().e3);
-      ASSERT.that(collection).has().exactlyAs(expectedCollection);
+      assertThat(collection).has().exactlyAs(expectedCollection);
       assertEquals(size + 1, multimap().size());
     }
   }
@@ -222,7 +222,7 @@
 
       multimap().put(key, sampleValues().e3);
       expectedCollection.add(sampleValues().e3);
-      ASSERT.that(collection).has().exactlyAs(expectedCollection);
+      assertThat(collection).has().exactlyAs(expectedCollection);
       assertEquals(size + 1, multimap().size());
     }
   }
diff --git a/guava-testlib/src/com/google/common/collect/testing/google/MultimapRemoveAllTester.java b/guava-testlib/src/com/google/common/collect/testing/google/MultimapRemoveAllTester.java
index bf5e653..cbd84c9 100644
--- a/guava-testlib/src/com/google/common/collect/testing/google/MultimapRemoveAllTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/google/MultimapRemoveAllTester.java
@@ -21,7 +21,7 @@
 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_ANY_NULL_QUERIES;
 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_KEYS;
 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_REMOVE;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.Multimap;
@@ -40,14 +40,14 @@
 public class MultimapRemoveAllTester<K, V> extends AbstractMultimapTester<K, V, Multimap<K, V>> {
   @MapFeature.Require(SUPPORTS_REMOVE)
   public void testRemoveAllAbsentKey() {
-    ASSERT.that(multimap().removeAll(sampleKeys().e3)).isEmpty();
+    assertThat(multimap().removeAll(sampleKeys().e3)).isEmpty();
     expectUnchanged();
   }
 
   @CollectionSize.Require(absent = ZERO)
   @MapFeature.Require(SUPPORTS_REMOVE)
   public void testRemoveAllPresentKey() {
-    ASSERT.that(multimap().removeAll(sampleKeys().e0))
+    assertThat(multimap().removeAll(sampleKeys().e0))
         .has().exactly(sampleValues().e0).inOrder();
     expectMissing(samples.e0);
   }
@@ -59,7 +59,7 @@
 
     multimap().removeAll(sampleKeys().e0);
 
-    ASSERT.that(getResult).isEmpty();
+    assertThat(getResult).isEmpty();
     expectMissing(samples.e0);
   }
 
@@ -71,7 +71,7 @@
         Helpers.mapEntry(sampleKeys().e0, sampleValues().e1),
         Helpers.mapEntry(sampleKeys().e0, sampleValues().e2));
 
-    ASSERT.that(multimap().removeAll(sampleKeys().e0))
+    assertThat(multimap().removeAll(sampleKeys().e0))
         .has().exactly(sampleValues().e0, sampleValues().e1, sampleValues().e2);
     assertTrue(multimap().isEmpty());
   }
@@ -81,14 +81,14 @@
   public void testRemoveAllNullKeyPresent() {
     initMultimapWithNullKey();
 
-    ASSERT.that(multimap().removeAll(null)).has().exactly(getValueForNullKey()).inOrder();
+    assertThat(multimap().removeAll(null)).has().exactly(getValueForNullKey()).inOrder();
 
     expectMissing(Helpers.mapEntry((K) null, getValueForNullKey()));
   }
 
   @MapFeature.Require({ SUPPORTS_REMOVE, ALLOWS_ANY_NULL_QUERIES})
   public void testRemoveAllNullKeyAbsent() {
-    ASSERT.that(multimap().removeAll(null)).isEmpty();
+    assertThat(multimap().removeAll(null)).isEmpty();
     expectUnchanged();
   }
 }
diff --git a/guava-testlib/src/com/google/common/collect/testing/google/MultimapRemoveEntryTester.java b/guava-testlib/src/com/google/common/collect/testing/google/MultimapRemoveEntryTester.java
index 820c702..c1d6783 100644
--- a/guava-testlib/src/com/google/common/collect/testing/google/MultimapRemoveEntryTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/google/MultimapRemoveEntryTester.java
@@ -22,7 +22,7 @@
 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_VALUES;
 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_VALUE_QUERIES;
 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_REMOVE;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.ImmutableList;
@@ -132,7 +132,7 @@
       multimap().remove(key, value);
       expectedCollection.remove(value);
 
-      ASSERT.that(collection).has().exactlyAs(expectedCollection);
+      assertThat(collection).has().exactlyAs(expectedCollection);
       assertEquals(!expectedCollection.isEmpty(), multimap().containsKey(key));
     }
   }
@@ -153,7 +153,7 @@
       multimap().remove(key, value);
       expectedCollection.remove(value);
 
-      ASSERT.that(collection).has().exactlyAs(expectedCollection);
+      assertThat(collection).has().exactlyAs(expectedCollection);
       assertEquals(!expectedCollection.isEmpty(), multimap().containsKey(key));
     }
   }
@@ -183,7 +183,7 @@
       multimap().remove(key, value);
       expectedCollection.remove(value);
 
-      ASSERT.that(collection).has().exactlyAs(expectedCollection);
+      assertThat(collection).has().exactlyAs(expectedCollection);
       assertEquals(!expectedCollection.isEmpty(), multimap().containsKey(key));
     }
   }
diff --git a/guava-testlib/src/com/google/common/collect/testing/google/MultimapReplaceValuesTester.java b/guava-testlib/src/com/google/common/collect/testing/google/MultimapReplaceValuesTester.java
index 3a613b9..930d16f 100644
--- a/guava-testlib/src/com/google/common/collect/testing/google/MultimapReplaceValuesTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/google/MultimapReplaceValuesTester.java
@@ -21,7 +21,7 @@
 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_VALUES;
 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_PUT;
 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_REMOVE;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.Multimap;
@@ -128,7 +128,7 @@
     @SuppressWarnings("unchecked")
     List<V> values = Arrays.asList(sampleValues().e0, sampleValues().e2, sampleValues().e3);
     multimap().replaceValues(key, values);
-    ASSERT.that(getCollection).has().exactly(
+    assertThat(getCollection).has().exactly(
         sampleValues().e0, sampleValues().e2, sampleValues().e3);
   }
 
diff --git a/guava-testlib/src/com/google/common/collect/testing/google/MultimapValuesTester.java b/guava-testlib/src/com/google/common/collect/testing/google/MultimapValuesTester.java
index d89aac3..e7da59e 100644
--- a/guava-testlib/src/com/google/common/collect/testing/google/MultimapValuesTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/google/MultimapValuesTester.java
@@ -17,7 +17,7 @@
 import static com.google.common.collect.testing.features.CollectionFeature.KNOWN_ORDER;
 import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_ITERATOR_REMOVE;
 import static com.google.common.collect.testing.features.CollectionSize.ONE;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.Lists;
@@ -41,7 +41,7 @@
     for (Map.Entry<K, V> entry : getSampleElements()) {
       expected.add(entry.getValue());
     }
-    ASSERT.that(multimap().values()).has().exactlyAs(expected);
+    assertThat(multimap().values()).has().exactlyAs(expected);
   }
   
   @CollectionFeature.Require(KNOWN_ORDER)
@@ -50,7 +50,7 @@
     for (Map.Entry<K, V> entry : getOrderedElements()) {
       expected.add(entry.getValue());
     }
-    ASSERT.that(multimap().values()).has().exactlyAs(expected).inOrder();
+    assertThat(multimap().values()).has().exactlyAs(expected).inOrder();
   }
   
   
diff --git a/guava-testlib/src/com/google/common/collect/testing/google/MultisetElementSetTester.java b/guava-testlib/src/com/google/common/collect/testing/google/MultisetElementSetTester.java
index db66594..0ad79cc 100644
--- a/guava-testlib/src/com/google/common/collect/testing/google/MultisetElementSetTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/google/MultisetElementSetTester.java
@@ -20,7 +20,7 @@
 import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_REMOVE;
 import static com.google.common.collect.testing.features.CollectionSize.SEVERAL;
 import static com.google.common.collect.testing.features.CollectionSize.ZERO;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.testing.features.CollectionFeature;
@@ -67,7 +67,7 @@
     initThreeCopies();
     Set<E> elementSet = getMultiset().elementSet();
     assertTrue(elementSet.remove(samples.e0));
-    ASSERT.that(getMultiset()).isEmpty();
+    assertThat(getMultiset()).isEmpty();
   }
 
   @CollectionFeature.Require(SUPPORTS_REMOVE)
@@ -80,6 +80,6 @@
   @CollectionFeature.Require(SUPPORTS_REMOVE)
   public void testElementSetClear() {
     getMultiset().elementSet().clear();
-    ASSERT.that(getMultiset()).isEmpty();    
+    assertThat(getMultiset()).isEmpty();    
   }
 }
diff --git a/guava-testlib/src/com/google/common/collect/testing/google/MultisetRemoveTester.java b/guava-testlib/src/com/google/common/collect/testing/google/MultisetRemoveTester.java
index e8e09bb..7a76116 100644
--- a/guava-testlib/src/com/google/common/collect/testing/google/MultisetRemoveTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/google/MultisetRemoveTester.java
@@ -21,7 +21,7 @@
 import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_REMOVE;
 import static com.google.common.collect.testing.features.CollectionSize.SEVERAL;
 import static com.google.common.collect.testing.features.CollectionSize.ZERO;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -153,7 +153,7 @@
   public void testRemoveAllIgnoresCount() {
     initThreeCopies();
     assertTrue(getMultiset().removeAll(Collections.singleton(samples.e0)));
-    ASSERT.that(getMultiset()).isEmpty();
+    assertThat(getMultiset()).isEmpty();
   }
   
   @CollectionSize.Require(SEVERAL)
diff --git a/guava-testlib/src/com/google/common/collect/testing/google/SortedMultisetTestSuiteBuilder.java b/guava-testlib/src/com/google/common/collect/testing/google/SortedMultisetTestSuiteBuilder.java
index 6a72260..1b1abbd 100644
--- a/guava-testlib/src/com/google/common/collect/testing/google/SortedMultisetTestSuiteBuilder.java
+++ b/guava-testlib/src/com/google/common/collect/testing/google/SortedMultisetTestSuiteBuilder.java
@@ -46,7 +46,7 @@
  * Creates, based on your criteria, a JUnit test suite that exhaustively tests a
  * {@code SortedMultiset} implementation.
  *
- * <p><b>Warning</b>: expects that {@code E} is a String.
+ * <p><b>Warning:</b> expects that {@code E} is a String.
  *
  * @author Louis Wasserman
  */
diff --git a/guava-testlib/src/com/google/common/collect/testing/testers/CollectionAddAllTester.java b/guava-testlib/src/com/google/common/collect/testing/testers/CollectionAddAllTester.java
index 84a0d54..4add759 100644
--- a/guava-testlib/src/com/google/common/collect/testing/testers/CollectionAddAllTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/testers/CollectionAddAllTester.java
@@ -174,4 +174,28 @@
   public static Method getAddAllNullUnsupportedMethod() {
     return Helpers.getMethod(CollectionAddAllTester.class, "testAddAll_nullUnsupported");
   }
+
+  /**
+   * Returns the {@link Method} instance for {@link
+   * #testAddAll_unsupportedNonePresent()} so that tests can suppress it with
+   * {@code FeatureSpecificTestSuiteBuilder.suppressing()} while we figure out
+   * what to do with <a href="http://goo.gl/qJBruX">{@code ConcurrentHashMap}
+   * support for {@code entrySet().add()}</a>.
+   */
+  @GwtIncompatible("reflection")
+  public static Method getAddAllUnsupportedNonePresentMethod() {
+    return Helpers.getMethod(CollectionAddAllTester.class, "testAddAll_unsupportedNonePresent");
+  }
+
+  /**
+   * Returns the {@link Method} instance for {@link
+   * #testAddAll_unsupportedSomePresent()} so that tests can suppress it with
+   * {@code FeatureSpecificTestSuiteBuilder.suppressing()} while we figure out
+   * what to do with <a href="http://goo.gl/qJBruX">{@code ConcurrentHashMap}
+   * support for {@code entrySet().add()}</a>.
+   */
+  @GwtIncompatible("reflection")
+  public static Method getAddAllUnsupportedSomePresentMethod() {
+    return Helpers.getMethod(CollectionAddAllTester.class, "testAddAll_unsupportedSomePresent");
+  }
 }
diff --git a/guava-testlib/src/com/google/common/collect/testing/testers/CollectionAddTester.java b/guava-testlib/src/com/google/common/collect/testing/testers/CollectionAddTester.java
index e6ec2fb..1d1b84b 100644
--- a/guava-testlib/src/com/google/common/collect/testing/testers/CollectionAddTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/testers/CollectionAddTester.java
@@ -136,4 +136,16 @@
   public static Method getAddNullUnsupportedMethod() {
     return Helpers.getMethod(CollectionAddTester.class, "testAdd_nullUnsupported");
   }
+
+  /**
+   * Returns the {@link Method} instance for {@link
+   * #testAdd_unsupportedNotPresent()} so that tests can suppress it with
+   * {@code FeatureSpecificTestSuiteBuilder.suppressing()} while we figure out
+   * what to do with <a href="http://goo.gl/qJBruX">{@code ConcurrentHashMap}
+   * support for {@code entrySet().add()}</a>.
+   */
+  @GwtIncompatible("reflection")
+  public static Method getAddUnsupportedNotPresentMethod() {
+    return Helpers.getMethod(CollectionAddTester.class, "testAdd_unsupportedNotPresent");
+  }
 }
diff --git a/guava-testlib/src/com/google/common/collect/testing/testers/CollectionIteratorTester.java b/guava-testlib/src/com/google/common/collect/testing/testers/CollectionIteratorTester.java
index e505c58..0977180 100644
--- a/guava-testlib/src/com/google/common/collect/testing/testers/CollectionIteratorTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/testers/CollectionIteratorTester.java
@@ -131,15 +131,4 @@
     return Helpers.getMethod(
         CollectionIteratorTester.class, "testIterator_knownOrderRemoveUnsupported");
   }
-
-  /**
-   * Returns the {@link Method} instance for
-   * {@link #testIterator_knownOrderRemoveSupported()} so that tests of
-   * {@code Sets.filter} can suppress it under JDK5.
-   */
-  @GwtIncompatible("reflection")
-  public static Method getIteratorKnownOrderRemoveSupportedMethod() {
-    return Helpers.getMethod(
-        CollectionIteratorTester.class, "testIterator_knownOrderRemoveSupported");
-  }
 }
diff --git a/guava-testlib/src/com/google/common/collect/testing/testers/ListRetainAllTester.java b/guava-testlib/src/com/google/common/collect/testing/testers/ListRetainAllTester.java
index 3f84807..96a005d 100644
--- a/guava-testlib/src/com/google/common/collect/testing/testers/ListRetainAllTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/testers/ListRetainAllTester.java
@@ -20,7 +20,7 @@
 import static com.google.common.collect.testing.features.CollectionSize.ONE;
 import static com.google.common.collect.testing.features.CollectionSize.SEVERAL;
 import static com.google.common.collect.testing.features.CollectionSize.ZERO;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.testing.MinimalCollection;
@@ -67,6 +67,6 @@
   public void testRetainAll_countIgnored() {
     resetContainer(getSubjectGenerator().create(samples.e0, samples.e2, samples.e1, samples.e0));
     assertTrue(getList().retainAll(Arrays.asList(samples.e0, samples.e1)));
-    ASSERT.that(getList()).has().exactly(samples.e0, samples.e1, samples.e0).inOrder();
+    assertThat(getList()).has().exactly(samples.e0, samples.e1, samples.e0).inOrder();
   }
 }
diff --git a/guava-testlib/src/com/google/common/collect/testing/testers/MapGetTester.java b/guava-testlib/src/com/google/common/collect/testing/testers/MapGetTester.java
index 4670ea4..f5e0ba7 100644
--- a/guava-testlib/src/com/google/common/collect/testing/testers/MapGetTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/testers/MapGetTester.java
@@ -16,14 +16,13 @@
 
 package com.google.common.collect.testing.testers;
 
-import static com.google.common.collect.testing.features.CollectionFeature.ALLOWS_NULL_QUERIES;
 import static com.google.common.collect.testing.features.CollectionSize.ZERO;
 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_KEYS;
+import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_KEY_QUERIES;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.testing.AbstractMapTester;
 import com.google.common.collect.testing.WrongType;
-import com.google.common.collect.testing.features.CollectionFeature;
 import com.google.common.collect.testing.features.CollectionSize;
 import com.google.common.collect.testing.features.MapFeature;
 
@@ -47,12 +46,12 @@
     assertNull("get(notPresent) should return null", get(samples.e3.getKey()));
   }
 
-  @CollectionFeature.Require(ALLOWS_NULL_QUERIES)
+  @MapFeature.Require(ALLOWS_NULL_KEY_QUERIES)
   public void testGet_nullNotContainedButAllowed() {
     assertNull("get(null) should return null", get(null));
   }
 
-  @CollectionFeature.Require(absent = ALLOWS_NULL_QUERIES)
+  @MapFeature.Require(absent = ALLOWS_NULL_KEY_QUERIES)
   public void testGet_nullNotContainedAndUnsupported() {
     try {
       assertNull("get(null) should return null or throw", get(null));
diff --git a/guava-testlib/src/com/google/common/collect/testing/testers/NavigableMapNavigationTester.java b/guava-testlib/src/com/google/common/collect/testing/testers/NavigableMapNavigationTester.java
new file mode 100644
index 0000000..daf46ff
--- /dev/null
+++ b/guava-testlib/src/com/google/common/collect/testing/testers/NavigableMapNavigationTester.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2010 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect.testing.testers;
+
+import static com.google.common.collect.testing.features.CollectionSize.ONE;
+import static com.google.common.collect.testing.features.CollectionSize.SEVERAL;
+import static com.google.common.collect.testing.features.CollectionSize.ZERO;
+import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_REMOVE;
+
+import com.google.common.collect.testing.AbstractMapTester;
+import com.google.common.collect.testing.Helpers;
+import com.google.common.collect.testing.features.CollectionSize;
+import com.google.common.collect.testing.features.MapFeature;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.NavigableMap;
+
+/**
+ * A generic JUnit test which tests operations on a NavigableMap. Can't be
+ * invoked directly; please see {@code NavigableMapTestSuiteBuilder}.
+ *
+ * @author Jesse Wilson
+ * @author Louis Wasserman
+ */
+public class NavigableMapNavigationTester<K, V> extends AbstractMapTester<K, V> {
+
+  private NavigableMap<K, V> navigableMap;
+  private List<Entry<K, V>> entries;
+  private Entry<K, V> a;
+  private Entry<K, V> b;
+  private Entry<K, V> c;
+
+  @Override public void setUp() throws Exception {
+    super.setUp();
+    navigableMap = (NavigableMap<K, V>) getMap();
+    entries = Helpers.copyToList(getSubjectGenerator().getSampleElements(
+        getSubjectGenerator().getCollectionSize().getNumElements()));
+    Collections.sort(entries, Helpers.<K, V>entryComparator(navigableMap.comparator()));
+
+    // some tests assume SEVERAL == 3
+    if (entries.size() >= 1) {
+      a = entries.get(0);
+      if (entries.size() >= 3) {
+        b = entries.get(1);
+        c = entries.get(2);
+      }
+    }
+  }
+
+  /**
+   * Resets the contents of navigableMap to have entries a, c, for the
+   * navigation tests.
+   */
+  @SuppressWarnings("unchecked") // Needed to stop Eclipse whining
+  private void resetWithHole() {
+    Entry<K, V>[] entries = new Entry[] {a, c};
+    super.resetMap(entries);
+    navigableMap = (NavigableMap<K, V>) getMap();
+  }
+
+  @CollectionSize.Require(ZERO)
+  public void testEmptyMapFirst() {
+    assertNull(navigableMap.firstEntry());
+  }
+
+  @MapFeature.Require(SUPPORTS_REMOVE)
+  @CollectionSize.Require(ZERO)
+  public void testEmptyMapPollFirst() {
+    assertNull(navigableMap.pollFirstEntry());
+  }
+
+  @CollectionSize.Require(ZERO)
+  public void testEmptyMapNearby() {
+    assertNull(navigableMap.lowerEntry(samples.e0.getKey()));
+    assertNull(navigableMap.lowerKey(samples.e0.getKey()));
+    assertNull(navigableMap.floorEntry(samples.e0.getKey()));
+    assertNull(navigableMap.floorKey(samples.e0.getKey()));
+    assertNull(navigableMap.ceilingEntry(samples.e0.getKey()));
+    assertNull(navigableMap.ceilingKey(samples.e0.getKey()));
+    assertNull(navigableMap.higherEntry(samples.e0.getKey()));
+    assertNull(navigableMap.higherKey(samples.e0.getKey()));
+  }
+
+  @CollectionSize.Require(ZERO)
+  public void testEmptyMapLast() {
+    assertNull(navigableMap.lastEntry());
+  }
+
+  @MapFeature.Require(SUPPORTS_REMOVE)
+  @CollectionSize.Require(ZERO)
+  public void testEmptyMapPollLast() {
+    assertNull(navigableMap.pollLastEntry());
+  }
+
+  @CollectionSize.Require(ONE)
+  public void testSingletonMapFirst() {
+    assertEquals(a, navigableMap.firstEntry());
+  }
+
+  @MapFeature.Require(SUPPORTS_REMOVE)
+  @CollectionSize.Require(ONE)
+  public void testSingletonMapPollFirst() {
+    assertEquals(a, navigableMap.pollFirstEntry());
+    assertTrue(navigableMap.isEmpty());
+  }
+
+  @CollectionSize.Require(ONE)
+  public void testSingletonMapNearby() {
+    assertNull(navigableMap.lowerEntry(samples.e0.getKey()));
+    assertNull(navigableMap.lowerKey(samples.e0.getKey()));
+    assertEquals(a, navigableMap.floorEntry(samples.e0.getKey()));
+    assertEquals(a.getKey(), navigableMap.floorKey(samples.e0.getKey()));
+    assertEquals(a, navigableMap.ceilingEntry(samples.e0.getKey()));
+    assertEquals(a.getKey(), navigableMap.ceilingKey(samples.e0.getKey()));
+    assertNull(navigableMap.higherEntry(samples.e0.getKey()));
+    assertNull(navigableMap.higherKey(samples.e0.getKey()));
+  }
+
+  @CollectionSize.Require(ONE)
+  public void testSingletonMapLast() {
+    assertEquals(a, navigableMap.lastEntry());
+  }
+
+  @MapFeature.Require(SUPPORTS_REMOVE)
+  @CollectionSize.Require(ONE)
+  public void testSingletonMapPollLast() {
+    assertEquals(a, navigableMap.pollLastEntry());
+    assertTrue(navigableMap.isEmpty());
+  }
+
+  @CollectionSize.Require(SEVERAL)
+  public void testFirst() {
+    assertEquals(a, navigableMap.firstEntry());
+  }
+
+  @MapFeature.Require(SUPPORTS_REMOVE)
+  @CollectionSize.Require(SEVERAL)
+  public void testPollFirst() {
+    assertEquals(a, navigableMap.pollFirstEntry());
+    assertEquals(entries.subList(1, entries.size()),
+        Helpers.copyToList(navigableMap.entrySet()));
+  }
+
+  @MapFeature.Require(absent = SUPPORTS_REMOVE)
+  public void testPollFirstUnsupported() {
+    try {
+      navigableMap.pollFirstEntry();
+      fail();
+    } catch (UnsupportedOperationException e) {
+    }
+  }
+
+  @CollectionSize.Require(SEVERAL)
+  public void testLower() {
+    resetWithHole();
+    assertEquals(null, navigableMap.lowerEntry(a.getKey()));
+    assertEquals(null, navigableMap.lowerKey(a.getKey()));
+    assertEquals(a, navigableMap.lowerEntry(b.getKey()));
+    assertEquals(a.getKey(), navigableMap.lowerKey(b.getKey()));
+    assertEquals(a, navigableMap.lowerEntry(c.getKey()));
+    assertEquals(a.getKey(), navigableMap.lowerKey(c.getKey()));
+  }
+
+  @CollectionSize.Require(SEVERAL)
+  public void testFloor() {
+    resetWithHole();
+    assertEquals(a, navigableMap.floorEntry(a.getKey()));
+    assertEquals(a.getKey(), navigableMap.floorKey(a.getKey()));
+    assertEquals(a, navigableMap.floorEntry(b.getKey()));
+    assertEquals(a.getKey(), navigableMap.floorKey(b.getKey()));
+    assertEquals(c, navigableMap.floorEntry(c.getKey()));
+    assertEquals(c.getKey(), navigableMap.floorKey(c.getKey()));
+  }
+
+  @CollectionSize.Require(SEVERAL)
+  public void testCeiling() {
+    resetWithHole();
+    assertEquals(a, navigableMap.ceilingEntry(a.getKey()));
+    assertEquals(a.getKey(), navigableMap.ceilingKey(a.getKey()));
+    assertEquals(c, navigableMap.ceilingEntry(b.getKey()));
+    assertEquals(c.getKey(), navigableMap.ceilingKey(b.getKey()));
+    assertEquals(c, navigableMap.ceilingEntry(c.getKey()));
+    assertEquals(c.getKey(), navigableMap.ceilingKey(c.getKey()));
+  }
+
+  @CollectionSize.Require(SEVERAL)
+  public void testHigher() {
+    resetWithHole();
+    assertEquals(c, navigableMap.higherEntry(a.getKey()));
+    assertEquals(c.getKey(), navigableMap.higherKey(a.getKey()));
+    assertEquals(c, navigableMap.higherEntry(b.getKey()));
+    assertEquals(c.getKey(), navigableMap.higherKey(b.getKey()));
+    assertEquals(null, navigableMap.higherEntry(c.getKey()));
+    assertEquals(null, navigableMap.higherKey(c.getKey()));
+  }
+
+  @CollectionSize.Require(SEVERAL)
+  public void testLast() {
+    assertEquals(c, navigableMap.lastEntry());
+  }
+
+  @MapFeature.Require(SUPPORTS_REMOVE)
+  @CollectionSize.Require(SEVERAL)
+  public void testPollLast() {
+    assertEquals(c, navigableMap.pollLastEntry());
+    assertEquals(entries.subList(0, entries.size() - 1),
+        Helpers.copyToList(navigableMap.entrySet()));
+  }
+
+  @MapFeature.Require(absent = SUPPORTS_REMOVE)
+  @CollectionSize.Require(SEVERAL)
+  public void testPollLastUnsupported() {
+    try {
+      navigableMap.pollLastEntry();
+      fail();
+    } catch (UnsupportedOperationException e) {
+    }
+  }
+
+  @CollectionSize.Require(SEVERAL)
+  public void testDescendingNavigation() {
+    List<Entry<K, V>> descending = new ArrayList<Entry<K, V>>();
+    for (Entry<K, V> entry : navigableMap.descendingMap().entrySet()) {
+      descending.add(entry);
+    }
+    Collections.reverse(descending);
+    assertEquals(entries, descending);
+  }
+  
+  @CollectionSize.Require(absent = ZERO)
+  public void testHeadMapExclusive() {
+    assertFalse(navigableMap.headMap(a.getKey(), false).containsKey(a.getKey()));
+  }
+  
+  @CollectionSize.Require(absent = ZERO)
+  public void testHeadMapInclusive() {
+    assertTrue(navigableMap.headMap(a.getKey(), true).containsKey(a.getKey()));
+  }
+  
+  @CollectionSize.Require(absent = ZERO)
+  public void testTailMapExclusive() {
+    assertFalse(navigableMap.tailMap(a.getKey(), false).containsKey(a.getKey()));
+  }
+  
+  @CollectionSize.Require(absent = ZERO)
+  public void testTailMapInclusive() {
+    assertTrue(navigableMap.tailMap(a.getKey(), true).containsKey(a.getKey()));
+  }
+}
diff --git a/guava-testlib/src/com/google/common/collect/testing/testers/NavigableSetNavigationTester.java b/guava-testlib/src/com/google/common/collect/testing/testers/NavigableSetNavigationTester.java
new file mode 100644
index 0000000..14c6a47
--- /dev/null
+++ b/guava-testlib/src/com/google/common/collect/testing/testers/NavigableSetNavigationTester.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2010 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect.testing.testers;
+
+import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_REMOVE;
+import static com.google.common.collect.testing.features.CollectionSize.ONE;
+import static com.google.common.collect.testing.features.CollectionSize.SEVERAL;
+import static com.google.common.collect.testing.features.CollectionSize.ZERO;
+
+import com.google.common.collect.testing.Helpers;
+import com.google.common.collect.testing.features.CollectionFeature;
+import com.google.common.collect.testing.features.CollectionSize;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NavigableSet;
+import java.util.TreeSet;
+
+/**
+ * A generic JUnit test which tests operations on a NavigableSet. Can't be
+ * invoked directly; please see {@code NavigableSetTestSuiteBuilder}.
+ *
+ * @author Jesse Wilson
+ * @author Louis Wasserman
+ */
+public class NavigableSetNavigationTester<E> extends AbstractSetTester<E> {
+
+  private NavigableSet<E> navigableSet;
+  private List<E> values;
+  private E a;
+  private E b;
+  private E c;
+
+  @Override public void setUp() throws Exception {
+    super.setUp();
+    navigableSet = (NavigableSet<E>) getSet();
+    values = Helpers.copyToList(getSubjectGenerator().getSampleElements(
+        getSubjectGenerator().getCollectionSize().getNumElements()));
+    Collections.sort(values, navigableSet.comparator());
+
+    // some tests assume SEVERAL == 3
+    if (values.size() >= 1) {
+      a = values.get(0);
+      if (values.size() >= 3) {
+        b = values.get(1);
+        c = values.get(2);
+      }
+    }
+  }
+
+  /**
+   * Resets the contents of navigableSet to have elements a, c, for the
+   * navigation tests.
+   */
+  protected void resetWithHole() {
+    super.resetContainer(getSubjectGenerator().create(a, c));
+    navigableSet = (NavigableSet<E>) getSet();
+  }
+
+  @CollectionFeature.Require(SUPPORTS_REMOVE)
+  @CollectionSize.Require(ZERO)
+  public void testEmptySetPollFirst() {
+    assertNull(navigableSet.pollFirst());
+  }
+
+  @CollectionSize.Require(ZERO)
+  public void testEmptySetNearby() {
+    assertNull(navigableSet.lower(samples.e0));
+    assertNull(navigableSet.floor(samples.e0));
+    assertNull(navigableSet.ceiling(samples.e0));
+    assertNull(navigableSet.higher(samples.e0));
+  }
+
+  @CollectionFeature.Require(SUPPORTS_REMOVE)
+  @CollectionSize.Require(ZERO)
+  public void testEmptySetPollLast() {
+    assertNull(navigableSet.pollLast());
+  }
+
+  @CollectionFeature.Require(SUPPORTS_REMOVE)
+  @CollectionSize.Require(ONE)
+  public void testSingletonSetPollFirst() {
+    assertEquals(a, navigableSet.pollFirst());
+    assertTrue(navigableSet.isEmpty());
+  }
+
+  @CollectionSize.Require(ONE)
+  public void testSingletonSetNearby() {
+    assertNull(navigableSet.lower(samples.e0));
+    assertEquals(a, navigableSet.floor(samples.e0));
+    assertEquals(a, navigableSet.ceiling(samples.e0));
+    assertNull(navigableSet.higher(samples.e0));
+  }
+
+  @CollectionFeature.Require(SUPPORTS_REMOVE)
+  @CollectionSize.Require(ONE)
+  public void testSingletonSetPollLast() {
+    assertEquals(a, navigableSet.pollLast());
+    assertTrue(navigableSet.isEmpty());
+  }
+
+  @CollectionFeature.Require(SUPPORTS_REMOVE)
+  @CollectionSize.Require(SEVERAL)
+  public void testPollFirst() {
+    assertEquals(a, navigableSet.pollFirst());
+    assertEquals(
+        values.subList(1, values.size()), Helpers.copyToList(navigableSet));
+  }
+
+  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
+  public void testPollFirstUnsupported() {
+    try {
+      navigableSet.pollFirst();
+      fail();
+    } catch (UnsupportedOperationException e) {
+    }
+  }
+
+  @CollectionSize.Require(SEVERAL)
+  public void testLowerHole() {
+    resetWithHole();
+    assertEquals(null, navigableSet.lower(a));
+    assertEquals(a, navigableSet.lower(b));
+    assertEquals(a, navigableSet.lower(c));
+  }
+
+  @CollectionSize.Require(SEVERAL)
+  public void testFloorHole() {
+    resetWithHole();
+    assertEquals(a, navigableSet.floor(a));
+    assertEquals(a, navigableSet.floor(b));
+    assertEquals(c, navigableSet.floor(c));
+  }
+
+  @CollectionSize.Require(SEVERAL)
+  public void testCeilingHole() {
+    resetWithHole();
+    assertEquals(a, navigableSet.ceiling(a));
+    assertEquals(c, navigableSet.ceiling(b));
+    assertEquals(c, navigableSet.ceiling(c));
+  }
+
+  @CollectionSize.Require(SEVERAL)
+  public void testHigherHole() {
+    resetWithHole();
+    assertEquals(c, navigableSet.higher(a));
+    assertEquals(c, navigableSet.higher(b));
+    assertEquals(null, navigableSet.higher(c));
+  }
+
+  /*
+   * TODO(cpovirk): make "too small" and "too large" elements available for better navigation
+   * testing. At that point, we may be able to eliminate the "hole" tests, which would mean that
+   * ContiguousSet's tests would no longer need to suppress them.
+   */
+  @CollectionSize.Require(SEVERAL)
+  public void testLower() {
+    assertEquals(null, navigableSet.lower(a));
+    assertEquals(a, navigableSet.lower(b));
+    assertEquals(b, navigableSet.lower(c));
+  }
+
+  @CollectionSize.Require(SEVERAL)
+  public void testFloor() {
+    assertEquals(a, navigableSet.floor(a));
+    assertEquals(b, navigableSet.floor(b));
+    assertEquals(c, navigableSet.floor(c));
+  }
+
+  @CollectionSize.Require(SEVERAL)
+  public void testCeiling() {
+    assertEquals(a, navigableSet.ceiling(a));
+    assertEquals(b, navigableSet.ceiling(b));
+    assertEquals(c, navigableSet.ceiling(c));
+  }
+
+  @CollectionSize.Require(SEVERAL)
+  public void testHigher() {
+    assertEquals(b, navigableSet.higher(a));
+    assertEquals(c, navigableSet.higher(b));
+    assertEquals(null, navigableSet.higher(c));
+  }
+
+  @CollectionFeature.Require(SUPPORTS_REMOVE)
+  @CollectionSize.Require(SEVERAL)
+  public void testPollLast() {
+    assertEquals(c, navigableSet.pollLast());
+    assertEquals(
+        values.subList(0, values.size() - 1), Helpers.copyToList(navigableSet));
+  }
+
+  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
+  public void testPollLastUnsupported() {
+    try {
+      navigableSet.pollLast();
+      fail();
+    } catch (UnsupportedOperationException e) {
+    }
+  }
+
+  @CollectionSize.Require(SEVERAL)
+  public void testDescendingNavigation() {
+    List<E> descending = new ArrayList<E>();
+    for (Iterator<E> i = navigableSet.descendingIterator(); i.hasNext();) {
+      descending.add(i.next());
+    }
+    Collections.reverse(descending);
+    assertEquals(values, descending);
+  }
+
+  public void testEmptySubSet() {
+    NavigableSet<E> empty = navigableSet.subSet(samples.e0, false, samples.e0, false);
+    assertEquals(new TreeSet<E>(), empty);
+  }
+
+  /*
+   * TODO(cpovirk): more testing of subSet/headSet/tailSet/descendingSet? and/or generate derived
+   * suites?
+   */
+
+  /**
+   * Returns the {@link Method} instances for the test methods in this class that create a set with
+   * a "hole" in it so that set tests of {@code ContiguousSet} can suppress them with {@code
+   * FeatureSpecificTestSuiteBuilder.suppressing()}.
+   */
+  /*
+   * TODO(cpovirk): or we could make HOLES_FORBIDDEN a feature. Or we could declare that
+   * implementations are permitted to throw IAE if a hole is requested, and we could update
+   * test*Hole to permit IAE. (But might this ignore genuine bugs?) But see the TODO above
+   * testLower, which could make this all unnecessary
+   */
+  public static Method[] getHoleMethods() {
+    return new Method[] {
+        Helpers.getMethod(NavigableSetNavigationTester.class, "testLowerHole"),
+        Helpers.getMethod(NavigableSetNavigationTester.class, "testFloorHole"),
+        Helpers.getMethod(NavigableSetNavigationTester.class, "testCeilingHole"),
+        Helpers.getMethod(NavigableSetNavigationTester.class, "testHigherHole"),
+    };
+  }
+}
diff --git a/guava-testlib/src/com/google/common/collect/testing/testers/SortedMapNavigationTester.java b/guava-testlib/src/com/google/common/collect/testing/testers/SortedMapNavigationTester.java
index 4cbddb0..99446b5 100644
--- a/guava-testlib/src/com/google/common/collect/testing/testers/SortedMapNavigationTester.java
+++ b/guava-testlib/src/com/google/common/collect/testing/testers/SortedMapNavigationTester.java
@@ -19,7 +19,7 @@
 import static com.google.common.collect.testing.features.CollectionSize.ONE;
 import static com.google.common.collect.testing.features.CollectionSize.SEVERAL;
 import static com.google.common.collect.testing.features.CollectionSize.ZERO;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.testing.AbstractMapTester;
@@ -117,7 +117,7 @@
         getSubjectGenerator().getCollectionSize().getNumElements()));
     Collections.sort(entries, Helpers.<K, V>entryComparator(navigableMap.comparator()));
     for (int i = 0; i < entries.size(); i++) {
-      ASSERT.that(navigableMap.headMap(entries.get(i).getKey()).entrySet())
+      assertThat(navigableMap.headMap(entries.get(i).getKey()).entrySet())
           .iteratesAs(entries.subList(0, i));
     }
   }
@@ -127,7 +127,7 @@
         getSubjectGenerator().getCollectionSize().getNumElements()));
     Collections.sort(entries, Helpers.<K, V>entryComparator(navigableMap.comparator()));
     for (int i = 0; i < entries.size(); i++) {
-      ASSERT.that(navigableMap.tailMap(entries.get(i).getKey()).entrySet())
+      assertThat(navigableMap.tailMap(entries.get(i).getKey()).entrySet())
           .iteratesAs(entries.subList(i, entries.size()));
     }
   }
@@ -138,7 +138,7 @@
     Collections.sort(entries, Helpers.<K, V>entryComparator(navigableMap.comparator()));
     for (int i = 0; i < entries.size(); i++) {
       for (int j = i + 1; j < entries.size(); j++) {
-        ASSERT.that(navigableMap
+        assertThat(navigableMap
                  .subMap(entries.get(i).getKey(), entries.get(j).getKey())
                  .entrySet())
             .iteratesAs(entries.subList(i, j)); 
diff --git a/guava-testlib/src/com/google/common/testing/ArbitraryInstances.java b/guava-testlib/src/com/google/common/testing/ArbitraryInstances.java
index d9283e1..6e28db7 100644
--- a/guava-testlib/src/com/google/common/testing/ArbitraryInstances.java
+++ b/guava-testlib/src/com/google/common/testing/ArbitraryInstances.java
@@ -60,6 +60,7 @@
 import com.google.common.collect.Range;
 import com.google.common.collect.RowSortedTable;
 import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
 import com.google.common.collect.SortedMapDifference;
 import com.google.common.collect.SortedMultiset;
 import com.google.common.collect.SortedSetMultimap;
@@ -67,6 +68,11 @@
 import com.google.common.collect.Tables;
 import com.google.common.collect.TreeBasedTable;
 import com.google.common.collect.TreeMultimap;
+import com.google.common.io.ByteSink;
+import com.google.common.io.ByteSource;
+import com.google.common.io.ByteStreams;
+import com.google.common.io.CharSink;
+import com.google.common.io.CharSource;
 import com.google.common.primitives.Primitives;
 import com.google.common.primitives.UnsignedInteger;
 import com.google.common.primitives.UnsignedLong;
@@ -102,25 +108,33 @@
 import java.nio.LongBuffer;
 import java.nio.ShortBuffer;
 import java.nio.charset.Charset;
+import java.util.ArrayDeque;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.Currency;
+import java.util.Deque;
 import java.util.Iterator;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Locale;
 import java.util.Map;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
+import java.util.Queue;
 import java.util.Random;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.SortedSet;
+import java.util.concurrent.BlockingDeque;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentNavigableMap;
+import java.util.concurrent.ConcurrentSkipListMap;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
-import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.LinkedBlockingDeque;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.ThreadPoolExecutor;
@@ -215,8 +229,12 @@
       .put(FloatBuffer.class, FloatBuffer.allocate(0))
       .put(DoubleBuffer.class, DoubleBuffer.allocate(0))
       .put(File.class, new File(""))
+      .put(ByteSource.class, ByteSource.empty())
+      .put(CharSource.class, CharSource.empty())
+      .put(ByteSink.class, NullByteSink.INSTANCE)
+      .put(CharSink.class, NullByteSink.INSTANCE.asCharSink(Charsets.UTF_8))
       // All collections are immutable empty. So safe for any type parameter.
-      .put(Iterator.class, Iterators.emptyIterator())
+      .put(Iterator.class, ImmutableSet.of().iterator())
       .put(PeekingIterator.class, Iterators.peekingIterator(Iterators.emptyIterator()))
       .put(ListIterator.class, ImmutableList.of().listIterator())
       .put(Iterable.class, ImmutableSet.of())
@@ -228,10 +246,12 @@
       .put(ImmutableSet.class, ImmutableSet.of())
       .put(SortedSet.class, ImmutableSortedSet.of())
       .put(ImmutableSortedSet.class, ImmutableSortedSet.of())
+      .put(NavigableSet.class, Sets.unmodifiableNavigableSet(Sets.newTreeSet()))
       .put(Map.class, ImmutableMap.of())
       .put(ImmutableMap.class, ImmutableMap.of())
       .put(SortedMap.class, ImmutableSortedMap.of())
       .put(ImmutableSortedMap.class, ImmutableSortedMap.of())
+      .put(NavigableMap.class, Maps.unmodifiableNavigableMap(Maps.newTreeMap()))
       .put(Multimap.class, ImmutableMultimap.of())
       .put(ImmutableMultimap.class, ImmutableMultimap.of())
       .put(ListMultimap.class, ImmutableListMultimap.of())
@@ -280,12 +300,16 @@
 
   static {
     setImplementation(Appendable.class, StringBuilder.class);
-    setImplementation(BlockingQueue.class, LinkedBlockingQueue.class);
+    setImplementation(BlockingQueue.class, LinkedBlockingDeque.class);
+    setImplementation(BlockingDeque.class, LinkedBlockingDeque.class);
     setImplementation(ConcurrentMap.class, ConcurrentHashMap.class);
+    setImplementation(ConcurrentNavigableMap.class, ConcurrentSkipListMap.class);
     setImplementation(CountDownLatch.class, Dummies.DummyCountDownLatch.class);
+    setImplementation(Deque.class, ArrayDeque.class);
     setImplementation(OutputStream.class, ByteArrayOutputStream.class);
     setImplementation(PrintStream.class, Dummies.InMemoryPrintStream.class);
     setImplementation(PrintWriter.class, Dummies.InMemoryPrintWriter.class);
+    setImplementation(Queue.class, ArrayDeque.class);
     setImplementation(Random.class, Dummies.DeterministicRandom.class);
     setImplementation(ScheduledThreadPoolExecutor.class,
         Dummies.DummyScheduledThreadPoolExecutor.class);
@@ -429,6 +453,14 @@
     }
   }
 
+  private static final class NullByteSink extends ByteSink implements Serializable {
+    private static final NullByteSink INSTANCE = new NullByteSink();
+
+    @Override public OutputStream openStream() {
+      return ByteStreams.nullOutputStream();
+    }
+  }
+
   // Compare by toString() to satisfy 2 properties:
   // 1. compareTo(null) should throw NullPointerException
   // 2. the order is deterministic and easy to understand, for debugging purpose.
diff --git a/guava-testlib/src/com/google/common/testing/ForwardingWrapperTester.java b/guava-testlib/src/com/google/common/testing/ForwardingWrapperTester.java
index 91165df..74710e3 100644
--- a/guava-testlib/src/com/google/common/testing/ForwardingWrapperTester.java
+++ b/guava-testlib/src/com/google/common/testing/ForwardingWrapperTester.java
@@ -31,6 +31,7 @@
 import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -74,6 +75,12 @@
     Method[] methods = getMostConcreteMethods(interfaceType);
     AccessibleObject.setAccessible(methods, true);
     for (Method method : methods) {
+      // Under java 8, interfaces can have default methods that aren't abstract.
+      // No need to verify them.
+      // Can't check isDefault() for JDK 7 compatibility.
+      if (!Modifier.isAbstract(method.getModifiers())) {
+        continue;
+      }
       // The interface could be package-private or private.
       // filter out equals/hashCode/toString
       if (method.getName().equals("equals")
diff --git a/guava-testlib/src/com/google/common/testing/FreshValueGenerator.java b/guava-testlib/src/com/google/common/testing/FreshValueGenerator.java
index f007d7b..a656c83 100644
--- a/guava-testlib/src/com/google/common/testing/FreshValueGenerator.java
+++ b/guava-testlib/src/com/google/common/testing/FreshValueGenerator.java
@@ -109,6 +109,8 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.SortedSet;
@@ -543,6 +545,11 @@
 
   @Generates private static <E extends Comparable<? super E>> SortedSet<E>
       freshSortedSet(E freshElement) {
+    return freshNavigableSet(freshElement);
+  }
+
+  @Generates private static <E extends Comparable<? super E>> NavigableSet<E>
+      freshNavigableSet(E freshElement) {
     return freshTreeSet(freshElement);
   }
 
@@ -621,6 +628,11 @@
 
   @Generates private static <K extends Comparable<? super K>, V> SortedMap<K, V>
       freshSortedMap(K key, V value) {
+    return freshNavigableMap(key, value);
+  }
+
+  @Generates private static <K extends Comparable<? super K>, V> NavigableMap<K, V>
+      freshNavigableMap(K key, V value) {
     return freshTreeMap(key, value);
   }
 
diff --git a/guava-testlib/src/com/google/common/testing/NullPointerTester.java b/guava-testlib/src/com/google/common/testing/NullPointerTester.java
index c60e955..209b949 100644
--- a/guava-testlib/src/com/google/common/testing/NullPointerTester.java
+++ b/guava-testlib/src/com/google/common/testing/NullPointerTester.java
@@ -354,17 +354,6 @@
     }
   }
 
-  private static String bestAvailableString(
-      TypeToken type, int position, Invokable<?, ?> invokable) {
-    checkNotNull(type);
-    try {
-      return type.toString();
-    } catch (NullPointerException androidBug6636) {
-      // http://stackoverflow.com/a/8169250/28465
-      return String.format("unknown (arg %s of %s)", position, invokable);
-    }
-  }
-
   private Object[] buildParamList(Invokable<?, ?> invokable, int indexOfParamToSetToNull) {
     ImmutableList<Parameter> params = invokable.getParameters();
     Object[] args = new Object[params.size()];
@@ -375,7 +364,7 @@
         args[i] = getDefaultValue(param.getType());
         Assert.assertTrue(
             "Can't find or create a sample instance for type '"
-                + bestAvailableString(param.getType(), i, invokable)
+                + param.getType()
                 + "'; please provide one using NullPointerTester.setDefault()",
             args[i] != null || isNullable(param));
       }
diff --git a/guava-testlib/src/com/google/common/util/concurrent/testing/MockFutureListener.java b/guava-testlib/src/com/google/common/util/concurrent/testing/MockFutureListener.java
index d944995..8c38f2c 100644
--- a/guava-testlib/src/com/google/common/util/concurrent/testing/MockFutureListener.java
+++ b/guava-testlib/src/com/google/common/util/concurrent/testing/MockFutureListener.java
@@ -16,9 +16,10 @@
 
 package com.google.common.util.concurrent.testing;
 
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
+
 import com.google.common.annotations.Beta;
 import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.MoreExecutors;
 
 import junit.framework.Assert;
 
@@ -42,7 +43,7 @@
     this.countDownLatch = new CountDownLatch(1);
     this.future = future;
 
-    future.addListener(this, MoreExecutors.sameThreadExecutor());
+    future.addListener(this, directExecutor());
   }
 
   @Override
diff --git a/guava-testlib/src/com/google/common/util/concurrent/testing/SameThreadScheduledExecutorService.java b/guava-testlib/src/com/google/common/util/concurrent/testing/SameThreadScheduledExecutorService.java
index f1ad72a..7bf3937 100644
--- a/guava-testlib/src/com/google/common/util/concurrent/testing/SameThreadScheduledExecutorService.java
+++ b/guava-testlib/src/com/google/common/util/concurrent/testing/SameThreadScheduledExecutorService.java
@@ -16,13 +16,14 @@
 
 package com.google.common.util.concurrent.testing;
 
+import static com.google.common.util.concurrent.MoreExecutors.newDirectExecutorService;
+
 import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.ForwardingListenableFuture.SimpleForwardingListenableFuture;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListenableScheduledFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.ListeningScheduledExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
 
 import java.util.Collection;
 import java.util.List;
@@ -47,8 +48,7 @@
 class SameThreadScheduledExecutorService extends AbstractExecutorService
     implements ListeningScheduledExecutorService {
 
-  private final ListeningExecutorService delegate =
-      MoreExecutors.sameThreadExecutor();
+  private final ListeningExecutorService delegate = newDirectExecutorService();
 
   @Override
   public void shutdown() {
diff --git a/guava-testlib/src/com/google/common/util/concurrent/testing/TestingExecutors.java b/guava-testlib/src/com/google/common/util/concurrent/testing/TestingExecutors.java
index dfe2252..d1a87da 100644
--- a/guava-testlib/src/com/google/common/util/concurrent/testing/TestingExecutors.java
+++ b/guava-testlib/src/com/google/common/util/concurrent/testing/TestingExecutors.java
@@ -65,7 +65,7 @@
    * returned to the caller (unless the executor has been shutdown).
    *
    * <p>The returned executor is backed by the executor returned by
-   * {@link MoreExecutors#sameThreadExecutor} and subject to the same
+   * {@link MoreExecutors#newDirectExecutorService} and subject to the same
    * constraints.
    *
    * <p>Although all tasks are immediately executed in the thread that
diff --git a/guava-testlib/test/com/google/common/collect/testing/OpenJdk6MapTests.java b/guava-testlib/test/com/google/common/collect/testing/OpenJdk6MapTests.java
index 5ad858f..7429068 100644
--- a/guava-testlib/test/com/google/common/collect/testing/OpenJdk6MapTests.java
+++ b/guava-testlib/test/com/google/common/collect/testing/OpenJdk6MapTests.java
@@ -16,6 +16,9 @@
 
 package com.google.common.collect.testing;
 
+import static com.google.common.collect.testing.testers.CollectionAddAllTester.getAddAllUnsupportedNonePresentMethod;
+import static com.google.common.collect.testing.testers.CollectionAddAllTester.getAddAllUnsupportedSomePresentMethod;
+import static com.google.common.collect.testing.testers.CollectionAddTester.getAddUnsupportedNotPresentMethod;
 import static com.google.common.collect.testing.testers.CollectionCreationTester.getCreateWithNullUnsupportedMethod;
 import static com.google.common.collect.testing.testers.MapCreationTester.getCreateWithNullKeyUnsupportedMethod;
 import static com.google.common.collect.testing.testers.MapEntrySetTester.getContainsEntryWithIncomparableKeyMethod;
@@ -24,7 +27,6 @@
 import static com.google.common.collect.testing.testers.MapPutTester.getPutNullKeyUnsupportedMethod;
 
 import junit.framework.Test;
-import junit.framework.TestSuite;
 
 import java.lang.reflect.Method;
 import java.util.Arrays;
@@ -33,10 +35,14 @@
 
 /**
  * Tests the {@link Map} implementations of {@link java.util}, suppressing
- * tests that trip known OpenJDK 6 bugs.
+ * tests that trip known bugs in OpenJDK 6 or higher.
  *
  * @author Kevin Bourrillion
  */
+/*
+ * TODO(cpovirk): consider renaming this class in light of our now running it
+ * under JDK7
+ */
 public class OpenJdk6MapTests extends TestsForMapsInJavaUtil {
   public static Test suite() {
     return new OpenJdk6MapTests().allTests();
@@ -53,16 +59,28 @@
   }
 
   @Override
+  protected Collection<Method> suppressForConcurrentHashMap() {
+    /*
+     * The entrySet() of ConcurrentHashMap, unlike that of other Map
+     * implementations, supports add() under JDK8. This seems problematic, but I
+     * didn't see that discussed in the review, which included many other
+     * changes: http://goo.gl/okTTdr
+     *
+     * TODO(cpovirk): decide what the best long-term action here is: force users
+     * to suppress (as we do now), stop testing entrySet().add() at all, make
+     * entrySet().add() tests tolerant of either behavior, introduce a map
+     * feature for entrySet() that supports add(), or something else
+     */
+    return Arrays.asList(
+        getAddUnsupportedNotPresentMethod(),
+        getAddAllUnsupportedNonePresentMethod(),
+        getAddAllUnsupportedSomePresentMethod());
+  }
+
+  @Override
   protected Collection<Method> suppressForConcurrentSkipListMap() {
     return Arrays.asList(
         getContainsEntryWithIncomparableKeyMethod(),
         getContainsEntryWithIncomparableValueMethod()); 
   }
-
-  @Override public Test testsForEnumMap() {
-    // Do nothing.
-    // TODO: work around the reused-entry problem
-    // http://bugs.sun.com/view_bug.do?bug_id=6312706
-    return new TestSuite();
-  }
 }
diff --git a/guava-testlib/test/com/google/common/collect/testing/SafeTreeMapTest.java b/guava-testlib/test/com/google/common/collect/testing/SafeTreeMapTest.java
index 73eb568..0d9d3bd 100644
--- a/guava-testlib/test/com/google/common/collect/testing/SafeTreeMapTest.java
+++ b/guava-testlib/test/com/google/common/collect/testing/SafeTreeMapTest.java
@@ -16,16 +16,26 @@
 
 package com.google.common.collect.testing;
 
+import static java.util.Collections.sort;
+
 import com.google.common.annotations.GwtIncompatible;
 import com.google.common.collect.ImmutableSortedMap;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
+import com.google.common.collect.testing.Helpers.NullsBeforeTwo;
+import com.google.common.collect.testing.features.CollectionFeature;
+import com.google.common.collect.testing.features.CollectionSize;
+import com.google.common.collect.testing.features.MapFeature;
 import com.google.common.testing.SerializableTester;
 
 import junit.framework.Test;
 import junit.framework.TestCase;
 import junit.framework.TestSuite;
 
+import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NavigableMap;
 import java.util.SortedMap;
 
 /**
@@ -37,6 +47,42 @@
   public static Test suite() {
     TestSuite suite = new TestSuite();
     suite.addTestSuite(SafeTreeMapTest.class);
+    suite.addTest(
+        NavigableMapTestSuiteBuilder.using(new TestStringSortedMapGenerator() {
+          @Override protected SortedMap<String, String> create(
+              Entry<String, String>[] entries) {
+            NavigableMap<String, String> map =
+                new SafeTreeMap<String, String>(Ordering.natural());
+            for (Entry<String, String> entry : entries) {
+              map.put(entry.getKey(), entry.getValue());
+            }
+            return map;
+          }
+        }).withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER,
+            CollectionFeature.SERIALIZABLE, MapFeature.ALLOWS_NULL_VALUES, 
+            CollectionFeature.SUPPORTS_ITERATOR_REMOVE, MapFeature.GENERAL_PURPOSE).named(
+            "SafeTreeMap with natural comparator").createTestSuite());
+    suite.addTest(NavigableMapTestSuiteBuilder.using(new TestStringSortedMapGenerator() {
+      @Override protected SortedMap<String, String> create(
+          Entry<String, String>[] entries) {
+        NavigableMap<String, String> map =
+            new SafeTreeMap<String, String>(NullsBeforeTwo.INSTANCE);
+        for (Entry<String, String> entry : entries) {
+          map.put(entry.getKey(), entry.getValue());
+        }
+        return map;
+      }
+
+      @Override
+      public Iterable<Entry<String, String>> order(List<Entry<String, String>> insertionOrder) {
+        sort(insertionOrder, Helpers.<String, String>entryComparator(NullsBeforeTwo.INSTANCE));
+        return insertionOrder;
+      }
+    }).withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER,
+        MapFeature.ALLOWS_NULL_KEYS, MapFeature.ALLOWS_NULL_VALUES,
+        MapFeature.ALLOWS_ANY_NULL_QUERIES, MapFeature.GENERAL_PURPOSE,
+        CollectionFeature.SUPPORTS_ITERATOR_REMOVE, CollectionFeature.SERIALIZABLE).named(
+        "SafeTreeMap with null-friendly comparator").createTestSuite());
     return suite;
   }
 
@@ -58,7 +104,7 @@
     }
 
     @Override protected SortedMap<String, Integer> makePopulatedMap() {
-      SortedMap<String, Integer> map = new SafeTreeMap<String, Integer>();
+      NavigableMap<String, Integer> map = new SafeTreeMap<String, Integer>();
       map.put("one", 1);
       map.put("two", 2);
       map.put("three", 3);
@@ -67,7 +113,7 @@
 
     @Override protected SortedMap<String, Integer> makeEmptyMap()
         throws UnsupportedOperationException {
-      SortedMap<String, Integer> map = new SafeTreeMap<String, Integer>();
+      NavigableMap<String, Integer> map = new SafeTreeMap<String, Integer>();
       return SerializableTester.reserialize(map);
     }
 
diff --git a/guava-testlib/test/com/google/common/collect/testing/SafeTreeSetTest.java b/guava-testlib/test/com/google/common/collect/testing/SafeTreeSetTest.java
index cff57b2..dfeef40 100644
--- a/guava-testlib/test/com/google/common/collect/testing/SafeTreeSetTest.java
+++ b/guava-testlib/test/com/google/common/collect/testing/SafeTreeSetTest.java
@@ -33,6 +33,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.NavigableSet;
 import java.util.Set;
 import java.util.SortedSet;
 
@@ -40,9 +41,21 @@
   public static Test suite() {
     TestSuite suite = new TestSuite();
     suite.addTestSuite(SafeTreeSetTest.class);
+    suite.addTest(
+        NavigableSetTestSuiteBuilder.using(new TestStringSetGenerator() {
+          @Override protected Set<String> create(String[] elements) {
+            return new SafeTreeSet<String>(Arrays.asList(elements));
+          }
+
+          @Override public List<String> order(List<String> insertionOrder) {
+            return Lists.newArrayList(Sets.newTreeSet(insertionOrder));
+          }
+        }).withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER,
+            CollectionFeature.GENERAL_PURPOSE).named(
+            "SafeTreeSet with natural comparator").createTestSuite());
     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
       @Override protected Set<String> create(String[] elements) {
-        SortedSet<String> set =
+        NavigableSet<String> set =
             new SafeTreeSet<String>(Ordering.natural().nullsFirst());
         Collections.addAll(set, elements);
         return set;
diff --git a/guava-testlib/test/com/google/common/collect/testing/features/FeatureUtilTest.java b/guava-testlib/test/com/google/common/collect/testing/features/FeatureUtilTest.java
index 577b9c6..70ec78a 100644
--- a/guava-testlib/test/com/google/common/collect/testing/features/FeatureUtilTest.java
+++ b/guava-testlib/test/com/google/common/collect/testing/features/FeatureUtilTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect.testing.features;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
@@ -159,18 +159,18 @@
 
     features = Sets.<Feature<?>>newHashSet(
         ExampleDerivedFeature.DERIVED_FEATURE_1);
-    ASSERT.that(FeatureUtil.addImpliedFeatures(features)).has().item(
+    assertThat(FeatureUtil.addImpliedFeatures(features)).has().item(
         ExampleDerivedFeature.DERIVED_FEATURE_1);
 
     features = Sets.<Feature<?>>newHashSet(
         ExampleDerivedFeature.DERIVED_FEATURE_2);
-    ASSERT.that(FeatureUtil.addImpliedFeatures(features)).has().exactly(
+    assertThat(FeatureUtil.addImpliedFeatures(features)).has().exactly(
         ExampleDerivedFeature.DERIVED_FEATURE_2,
         ExampleBaseFeature.BASE_FEATURE_1);
 
     features = Sets.<Feature<?>>newHashSet(
         ExampleDerivedFeature.COMPOUND_DERIVED_FEATURE);
-    ASSERT.that(FeatureUtil.addImpliedFeatures(features)).has().exactly(
+    assertThat(FeatureUtil.addImpliedFeatures(features)).has().exactly(
         ExampleDerivedFeature.COMPOUND_DERIVED_FEATURE,
         ExampleDerivedFeature.DERIVED_FEATURE_1,
         ExampleDerivedFeature.DERIVED_FEATURE_2,
@@ -193,12 +193,12 @@
 
     features = Sets.<Feature<?>>newHashSet(
         ExampleDerivedFeature.DERIVED_FEATURE_2);
-    ASSERT.that(FeatureUtil.impliedFeatures(features)).has().item(
+    assertThat(FeatureUtil.impliedFeatures(features)).has().item(
         ExampleBaseFeature.BASE_FEATURE_1);
 
     features = Sets.<Feature<?>>newHashSet(
         ExampleDerivedFeature.COMPOUND_DERIVED_FEATURE);
-    ASSERT.that(FeatureUtil.impliedFeatures(features)).has().exactly(
+    assertThat(FeatureUtil.impliedFeatures(features)).has().exactly(
         ExampleDerivedFeature.DERIVED_FEATURE_1,
         ExampleDerivedFeature.DERIVED_FEATURE_2,
         ExampleBaseFeature.BASE_FEATURE_1,
@@ -250,7 +250,7 @@
           ExampleDerivedInterfaceTester_Conflict.class);
       fail("Expected ConflictingRequirementsException");
     } catch (ConflictingRequirementsException e) {
-      ASSERT.that(e.getConflicts()).has().item(
+      assertThat(e.getConflicts()).has().item(
           ExampleBaseFeature.BASE_FEATURE_1);
       assertEquals(ExampleDerivedInterfaceTester_Conflict.class, e.getSource());
     }
@@ -264,7 +264,7 @@
       FeatureUtil.buildTesterRequirements(method);
       fail("Expected ConflictingRequirementsException");
     } catch (ConflictingRequirementsException e) {
-      ASSERT.that(e.getConflicts()).has().item(
+      assertThat(e.getConflicts()).has().item(
           ExampleBaseFeature.BASE_FEATURE_1);
       assertEquals(method, e.getSource());
     }
diff --git a/guava-testlib/test/com/google/common/testing/AbstractPackageSanityTestsTest.java b/guava-testlib/test/com/google/common/testing/AbstractPackageSanityTestsTest.java
index b6199d1..43dcc1c 100644
--- a/guava-testlib/test/com/google/common/testing/AbstractPackageSanityTestsTest.java
+++ b/guava-testlib/test/com/google/common/testing/AbstractPackageSanityTestsTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.testing;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
@@ -36,54 +36,54 @@
   private final AbstractPackageSanityTests sanityTests = new AbstractPackageSanityTests() {};
 
   public void testFindClassesToTest_testClass() {
-    ASSERT.that(findClassesToTest(ImmutableList.of(EmptyTest.class)))
+    assertThat(findClassesToTest(ImmutableList.of(EmptyTest.class)))
         .isEmpty();
-    ASSERT.that(findClassesToTest(ImmutableList.of(EmptyTests.class)))
+    assertThat(findClassesToTest(ImmutableList.of(EmptyTests.class)))
         .isEmpty();
-    ASSERT.that(findClassesToTest(ImmutableList.of(EmptyTestCase.class)))
+    assertThat(findClassesToTest(ImmutableList.of(EmptyTestCase.class)))
         .isEmpty();
-    ASSERT.that(findClassesToTest(ImmutableList.of(EmptyTestSuite.class)))
+    assertThat(findClassesToTest(ImmutableList.of(EmptyTestSuite.class)))
         .isEmpty();
   }
 
   public void testFindClassesToTest_noCorrespondingTestClass() {
-    ASSERT.that(findClassesToTest(ImmutableList.of(Foo.class)))
+    assertThat(findClassesToTest(ImmutableList.of(Foo.class)))
         .has().exactly(Foo.class).inOrder();
-    ASSERT.that(findClassesToTest(ImmutableList.of(Foo.class, Foo2Test.class)))
+    assertThat(findClassesToTest(ImmutableList.of(Foo.class, Foo2Test.class)))
         .has().exactly(Foo.class).inOrder();
   }
 
   public void testFindClassesToTest_publicApiOnly() {
     sanityTests.publicApiOnly();
-    ASSERT.that(findClassesToTest(ImmutableList.of(Foo.class)))
+    assertThat(findClassesToTest(ImmutableList.of(Foo.class)))
         .isEmpty();
-    ASSERT.that(findClassesToTest(ImmutableList.of(PublicFoo.class))).has().item(PublicFoo.class);
+    assertThat(findClassesToTest(ImmutableList.of(PublicFoo.class))).has().item(PublicFoo.class);
   }
 
   public void testFindClassesToTest_ignoreClasses() {
     sanityTests.ignoreClasses(Predicates.<Object>equalTo(PublicFoo.class));
-    ASSERT.that(findClassesToTest(ImmutableList.of(PublicFoo.class)))
+    assertThat(findClassesToTest(ImmutableList.of(PublicFoo.class)))
         .isEmpty();
-    ASSERT.that(findClassesToTest(ImmutableList.of(Foo.class))).has().item(Foo.class);
+    assertThat(findClassesToTest(ImmutableList.of(Foo.class))).has().item(Foo.class);
   }
 
   public void testFindClassesToTest_withCorrespondingTestClassButNotExplicitlyTested() {
-    ASSERT.that(findClassesToTest(ImmutableList.of(Foo.class, FooTest.class), "testNotThere"))
+    assertThat(findClassesToTest(ImmutableList.of(Foo.class, FooTest.class), "testNotThere"))
         .has().exactly(Foo.class).inOrder();
-    ASSERT.that(findClassesToTest(ImmutableList.of(Foo.class, FooTest.class), "testNotPublic"))
+    assertThat(findClassesToTest(ImmutableList.of(Foo.class, FooTest.class), "testNotPublic"))
         .has().exactly(Foo.class).inOrder();
   }
 
   public void testFindClassesToTest_withCorrespondingTestClassAndExplicitlyTested() {
     ImmutableList<Class<? extends Object>> classes = ImmutableList.of(Foo.class, FooTest.class);
-    ASSERT.that(findClassesToTest(classes, "testPublic"))
+    assertThat(findClassesToTest(classes, "testPublic"))
         .isEmpty();
-    ASSERT.that(findClassesToTest(classes, "testNotThere", "testPublic"))
+    assertThat(findClassesToTest(classes, "testNotThere", "testPublic"))
         .isEmpty();
   }
 
   public void testFindClassesToTest_withCorrespondingTestClass_noTestName() {
-    ASSERT.that(findClassesToTest(ImmutableList.of(Foo.class, FooTest.class)))
+    assertThat(findClassesToTest(ImmutableList.of(Foo.class, FooTest.class)))
         .has().exactly(Foo.class).inOrder();
   }
 
diff --git a/guava-testlib/test/com/google/common/testing/ArbitraryInstancesTest.java b/guava-testlib/test/com/google/common/testing/ArbitraryInstancesTest.java
index 3ea0a70..bf2be65 100644
--- a/guava-testlib/test/com/google/common/testing/ArbitraryInstancesTest.java
+++ b/guava-testlib/test/com/google/common/testing/ArbitraryInstancesTest.java
@@ -40,7 +40,6 @@
 import com.google.common.collect.ImmutableSortedMap;
 import com.google.common.collect.ImmutableSortedSet;
 import com.google.common.collect.ImmutableTable;
-import com.google.common.collect.Iterators;
 import com.google.common.collect.ListMultimap;
 import com.google.common.collect.MapConstraint;
 import com.google.common.collect.MapDifference;
@@ -54,6 +53,10 @@
 import com.google.common.collect.SortedMultiset;
 import com.google.common.collect.SortedSetMultimap;
 import com.google.common.collect.Table;
+import com.google.common.io.ByteSink;
+import com.google.common.io.ByteSource;
+import com.google.common.io.CharSink;
+import com.google.common.io.CharSource;
 import com.google.common.primitives.UnsignedInteger;
 import com.google.common.primitives.UnsignedLong;
 import com.google.common.util.concurrent.AtomicDouble;
@@ -91,6 +94,7 @@
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.Currency;
+import java.util.Deque;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
@@ -98,15 +102,20 @@
 import java.util.ListIterator;
 import java.util.Locale;
 import java.util.Map;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
 import java.util.PriorityQueue;
+import java.util.Queue;
 import java.util.Random;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.SortedSet;
 import java.util.TreeMap;
 import java.util.TreeSet;
+import java.util.concurrent.BlockingDeque;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentNavigableMap;
 import java.util.concurrent.DelayQueue;
 import java.util.concurrent.Executor;
 import java.util.concurrent.PriorityBlockingQueue;
@@ -159,7 +168,7 @@
   }
 
   public void testGet_collections() {
-    assertEquals(Iterators.emptyIterator(), ArbitraryInstances.get(Iterator.class));
+    assertEquals(ImmutableSet.of().iterator(), ArbitraryInstances.get(Iterator.class));
     assertFalse(ArbitraryInstances.get(PeekingIterator.class).hasNext());
     assertFalse(ArbitraryInstances.get(ListIterator.class).hasNext());
     assertEquals(ImmutableSet.of(), ArbitraryInstances.get(Iterable.class));
@@ -195,13 +204,17 @@
     assertTrue(ArbitraryInstances.get(MapDifference.class).areEqual());
     assertTrue(ArbitraryInstances.get(SortedMapDifference.class).areEqual());
     assertEquals(Range.all(), ArbitraryInstances.get(Range.class));
+    assertTrue(ArbitraryInstances.get(NavigableSet.class).isEmpty());
+    assertTrue(ArbitraryInstances.get(NavigableMap.class).isEmpty());
     assertTrue(ArbitraryInstances.get(LinkedList.class).isEmpty());
+    assertTrue(ArbitraryInstances.get(Deque.class).isEmpty());
+    assertTrue(ArbitraryInstances.get(Queue.class).isEmpty());
     assertTrue(ArbitraryInstances.get(PriorityQueue.class).isEmpty());
     assertTrue(ArbitraryInstances.get(BitSet.class).isEmpty());
     assertTrue(ArbitraryInstances.get(TreeSet.class).isEmpty());
     assertTrue(ArbitraryInstances.get(TreeMap.class).isEmpty());
     assertFreshInstanceReturned(
-        LinkedList.class, PriorityQueue.class, BitSet.class,
+        LinkedList.class, Deque.class, Queue.class, PriorityQueue.class, BitSet.class, 
         TreeSet.class, TreeMap.class);
   }
 
@@ -221,17 +234,19 @@
   }
 
   public void testGet_concurrent() {
+    assertTrue(ArbitraryInstances.get(BlockingDeque.class).isEmpty());
     assertTrue(ArbitraryInstances.get(BlockingQueue.class).isEmpty());
     assertTrue(ArbitraryInstances.get(DelayQueue.class).isEmpty());
     assertTrue(ArbitraryInstances.get(SynchronousQueue.class).isEmpty());
     assertTrue(ArbitraryInstances.get(PriorityBlockingQueue.class).isEmpty());
     assertTrue(ArbitraryInstances.get(ConcurrentMap.class).isEmpty());
+    assertTrue(ArbitraryInstances.get(ConcurrentNavigableMap.class).isEmpty());
     ArbitraryInstances.get(Executor.class).execute(ArbitraryInstances.get(Runnable.class));
     assertNotNull(ArbitraryInstances.get(ThreadFactory.class));
     assertFreshInstanceReturned(
-        BlockingQueue.class, PriorityBlockingQueue.class,
+        BlockingQueue.class, BlockingDeque.class, PriorityBlockingQueue.class,
         DelayQueue.class, SynchronousQueue.class,
-        ConcurrentMap.class,
+        ConcurrentMap.class, ConcurrentNavigableMap.class,
         AtomicReference.class, AtomicBoolean.class,
         AtomicInteger.class, AtomicLong.class, AtomicDouble.class);
   }
@@ -317,6 +332,10 @@
         ByteArrayOutputStream.class, OutputStream.class,
         Writer.class, StringWriter.class,
         PrintStream.class, PrintWriter.class);
+    assertEquals(ByteSource.empty(), ArbitraryInstances.get(ByteSource.class));
+    assertEquals(CharSource.empty(), ArbitraryInstances.get(CharSource.class));
+    assertNotNull(ArbitraryInstances.get(ByteSink.class));
+    assertNotNull(ArbitraryInstances.get(CharSink.class));
   }
 
   public void testGet_reflect() {
@@ -401,11 +420,11 @@
   static class NonPublicClass {
     public NonPublicClass() {}
   }
-
+  
   private static class WithPrivateConstructor {
     public static final WithPrivateConstructor INSTANCE = new WithPrivateConstructor();
   }
-
+  
   public static class NoDefaultConstructor {
     public NoDefaultConstructor(@SuppressWarnings("unused") int i) {}
   }
diff --git a/guava-testlib/test/com/google/common/testing/ClassSanityTesterTest.java b/guava-testlib/test/com/google/common/testing/ClassSanityTesterTest.java
index 7d70616..4848293 100644
--- a/guava-testlib/test/com/google/common/testing/ClassSanityTesterTest.java
+++ b/guava-testlib/test/com/google/common/testing/ClassSanityTesterTest.java
@@ -17,7 +17,7 @@
 package com.google.common.testing;
 
 import static com.google.common.base.Preconditions.checkNotNull;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.base.Functions;
 import com.google.common.base.Optional;
@@ -312,7 +312,7 @@
     try {
       tester.testEquals(BadEquals.class);
     } catch (AssertionFailedError expected) {
-      ASSERT.that(expected.getMessage()).contains("create(null)");
+      assertThat(expected.getMessage()).contains("create(null)");
       return;
     }
     fail("should have failed");
@@ -322,7 +322,7 @@
     try {
       tester.testEquals(BadEqualsWithParameterizedType.class);
     } catch (AssertionFailedError expected) {
-      ASSERT.that(expected.getMessage()).contains("create([[1]])");
+      assertThat(expected.getMessage()).contains("create([[1]])");
       return;
     }
     fail("should have failed");
@@ -359,7 +359,7 @@
     try {
       tester.testEquals(cls);
     } catch (AssertionFailedError expected) {
-      ASSERT.that(expected.getMessage()).contains(cls.getSimpleName() + "(");
+      assertThat(expected.getMessage()).contains(cls.getSimpleName() + "(");
       return;
     }
     fail("should have failed");
@@ -472,7 +472,7 @@
     try {
       tester.instantiate(FactoryMethodReturnsNullButNotAnnotated.class);
     } catch (AssertionFailedError expected) {
-      ASSERT.that(expected.getMessage()).contains("@Nullable");
+      assertThat(expected.getMessage()).contains("@Nullable");
       return;
     }
     fail("should have failed");
diff --git a/guava-testlib/test/com/google/common/testing/EquivalenceTesterTest.java b/guava-testlib/test/com/google/common/testing/EquivalenceTesterTest.java
index ba40b6b..c2471dc 100644
--- a/guava-testlib/test/com/google/common/testing/EquivalenceTesterTest.java
+++ b/guava-testlib/test/com/google/common/testing/EquivalenceTesterTest.java
@@ -17,11 +17,11 @@
 package com.google.common.testing;
 
 import static com.google.common.base.Preconditions.checkState;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Equivalence;
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableTable;
 
@@ -102,7 +102,7 @@
     try {
       tester.addEquivalenceGroup(group1Item1, group1Item2).test();
     } catch (AssertionFailedError expected) {
-      ASSERT.that(expected.getMessage()).contains(
+      assertThat(expected.getMessage()).contains(
           "TestObject{group=1, item=2} [group 1, item 2] must be equivalent to "
           + "TestObject{group=1, item=1} [group 1, item 1]");
       return;
@@ -131,7 +131,7 @@
     try {
       tester.addEquivalenceGroup(group1Item1, group1Item2, group1Item3).test();
     } catch (AssertionFailedError expected) {
-      ASSERT.that(expected.getMessage()).contains(
+      assertThat(expected.getMessage()).contains(
           "TestObject{group=1, item=2} [group 1, item 2] must be equivalent to "
           + "TestObject{group=1, item=3} [group 1, item 3]");
       return;
@@ -154,7 +154,7 @@
     try {
       tester.addEquivalenceGroup(group1Item1).addEquivalenceGroup(group2Item1).test();
     } catch (AssertionFailedError expected) {
-      ASSERT.that(expected.getMessage()).contains(
+      assertThat(expected.getMessage()).contains(
           "TestObject{group=1, item=1} [group 1, item 1] must not be equivalent to "
           + "TestObject{group=2, item=1} [group 2, item 1]");
       return;
@@ -199,7 +199,7 @@
     }
 
     @Override public String toString() {
-      return Objects.toStringHelper("TestObject")
+      return MoreObjects.toStringHelper("TestObject")
           .add("group", group)
           .add("item", item)
           .toString();
diff --git a/guava-testlib/test/com/google/common/testing/FreshValueGeneratorTest.java b/guava-testlib/test/com/google/common/testing/FreshValueGeneratorTest.java
index dd4154b..b45fc03 100644
--- a/guava-testlib/test/com/google/common/testing/FreshValueGeneratorTest.java
+++ b/guava-testlib/test/com/google/common/testing/FreshValueGeneratorTest.java
@@ -99,6 +99,8 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.SortedSet;
@@ -342,6 +344,15 @@
     assertNotInstantiable(new TypeToken<SortedSet<EmptyEnum>>() {});
   }
 
+  public void testNavigableSet() {
+    assertFreshInstance(new TypeToken<NavigableSet<String>>() {});
+    TreeSet<String> expected = Sets.newTreeSet();
+    expected.add(new FreshValueGenerator().generate(String.class));
+    assertValueAndTypeEquals(expected,
+        new FreshValueGenerator().generate(new TypeToken<NavigableSet<String>>() {}));
+    assertNotInstantiable(new TypeToken<NavigableSet<EmptyEnum>>() {});
+  }
+
   public void testMultiset() {
     assertFreshInstance(new TypeToken<Multiset<String>>() {});
     Multiset<String> expected = HashMultiset.create();
@@ -455,6 +466,17 @@
     assertNotInstantiable(new TypeToken<SortedMap<EmptyEnum, String>>() {});
   }
 
+  public void testNavigableMap() {
+    assertFreshInstance(new TypeToken<NavigableMap<?, ?>>() {});
+    FreshValueGenerator generator = new FreshValueGenerator();
+    TreeMap<String, Integer> expected = Maps.newTreeMap();
+    expected.put(generator.generate(String.class), generator.generate(int.class));
+    assertValueAndTypeEquals(expected,
+        new FreshValueGenerator().generate(
+            new TypeToken<NavigableMap<String, Integer>>() {}));
+    assertNotInstantiable(new TypeToken<NavigableMap<EmptyEnum, String>>() {});
+  }
+
   public void testConcurrentMap() {
     assertFreshInstance(new TypeToken<ConcurrentMap<String, ?>>() {});
     FreshValueGenerator generator = new FreshValueGenerator();
diff --git a/guava-testlib/test/com/google/common/testing/NullPointerTesterTest.java b/guava-testlib/test/com/google/common/testing/NullPointerTesterTest.java
index 52cc121..5b44d7e 100644
--- a/guava-testlib/test/com/google/common/testing/NullPointerTesterTest.java
+++ b/guava-testlib/test/com/google/common/testing/NullPointerTesterTest.java
@@ -18,7 +18,7 @@
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.base.Converter;
 import com.google.common.base.Function;
@@ -1269,7 +1269,7 @@
       new NullPointerTester().testAllPublicConstructors(Inner.class);
       fail();
     } catch (IllegalArgumentException expected) {
-      ASSERT.that(expected.getMessage()).contains("inner class");
+      assertThat(expected.getMessage()).contains("inner class");
     }
   }
 }
diff --git a/guava-testlib/test/com/google/common/testing/anotherpackage/ForwardingWrapperTesterTest.java b/guava-testlib/test/com/google/common/testing/anotherpackage/ForwardingWrapperTesterTest.java
index eecd83c..2d1382a 100644
--- a/guava-testlib/test/com/google/common/testing/anotherpackage/ForwardingWrapperTesterTest.java
+++ b/guava-testlib/test/com/google/common/testing/anotherpackage/ForwardingWrapperTesterTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.testing.anotherpackage;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.base.Equivalence;
 import com.google.common.base.Function;
@@ -222,7 +222,7 @@
       tester.testForwarding(interfaceType, wrapperFunction);
     } catch (AssertionError expected) {
       for (String message : expectedMessages) {
-        ASSERT.that(expected.getMessage()).contains(message);
+        assertThat(expected.getMessage()).contains(message);
       }
       return;
     }
diff --git a/guava-tests/benchmark/com/google/common/collect/MapBenchmark.java b/guava-tests/benchmark/com/google/common/collect/MapBenchmark.java
index 2e309fc..9f93535 100644
--- a/guava-tests/benchmark/com/google/common/collect/MapBenchmark.java
+++ b/guava-tests/benchmark/com/google/common/collect/MapBenchmark.java
@@ -28,6 +28,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListMap;
 
 /**
  * A microbenchmark that tests the performance of get() and iteration on various map
@@ -77,6 +78,15 @@
         return map;
       }
     },
+    SkipList {
+      @Override Map<Element, Element> create(Collection<Element> keys) {
+        Map<Element, Element> map = new ConcurrentSkipListMap<Element, Element>();
+        for (Element element: keys) {
+          map.put(element, element);
+        }
+        return map;
+      }
+    },
     ConcurrentHM1 {
       @Override Map<Element, Element> create(Collection<Element> keys) {
         Map<Element, Element> map =
diff --git a/guava-tests/benchmark/com/google/common/math/IntMathBenchmark.java b/guava-tests/benchmark/com/google/common/math/IntMathBenchmark.java
index 717d460..fd7dd69 100644
--- a/guava-tests/benchmark/com/google/common/math/IntMathBenchmark.java
+++ b/guava-tests/benchmark/com/google/common/math/IntMathBenchmark.java
@@ -46,8 +46,8 @@
       exponent[i] = randomExponent();
       factorial[i] = RANDOM_SOURCE.nextInt(50);
       binomial[i] = RANDOM_SOURCE.nextInt(factorial[i] + 1);
-      positive[i] = randomPositiveBigInteger(Integer.SIZE - 2).intValue();
-      nonnegative[i] = randomNonNegativeBigInteger(Integer.SIZE - 2).intValue();
+      positive[i] = randomPositiveBigInteger(Integer.SIZE - 1).intValue();
+      nonnegative[i] = randomNonNegativeBigInteger(Integer.SIZE - 1).intValue();
       ints[i] = RANDOM_SOURCE.nextInt();
     }
   }
diff --git a/guava-tests/benchmark/com/google/common/math/LongMathBenchmark.java b/guava-tests/benchmark/com/google/common/math/LongMathBenchmark.java
index e8e09f3..912eb25 100644
--- a/guava-tests/benchmark/com/google/common/math/LongMathBenchmark.java
+++ b/guava-tests/benchmark/com/google/common/math/LongMathBenchmark.java
@@ -44,8 +44,8 @@
   void setUp() {
     for (int i = 0; i < ARRAY_SIZE; i++) {
       exponents[i] = randomExponent();
-      positive[i] = randomPositiveBigInteger(Long.SIZE - 2).longValue();
-      nonnegative[i] = randomNonNegativeBigInteger(Long.SIZE - 2).longValue();
+      positive[i] = randomPositiveBigInteger(Long.SIZE - 1).longValue();
+      nonnegative[i] = randomNonNegativeBigInteger(Long.SIZE - 1).longValue();
       longs[i] = RANDOM_SOURCE.nextLong();
       factorialArguments[i] = RANDOM_SOURCE.nextInt(30);
       binomialArguments[i][1] = RANDOM_SOURCE.nextInt(MathBenchmarking.biggestBinomials.length);
diff --git a/guava-tests/benchmark/com/google/common/primitives/UnsignedBytesBenchmark.java b/guava-tests/benchmark/com/google/common/primitives/UnsignedBytesBenchmark.java
index 9b1cac2..fd03d99 100644
--- a/guava-tests/benchmark/com/google/common/primitives/UnsignedBytesBenchmark.java
+++ b/guava-tests/benchmark/com/google/common/primitives/UnsignedBytesBenchmark.java
@@ -19,8 +19,8 @@
 import com.google.caliper.BeforeExperiment;
 import com.google.caliper.Benchmark;
 import com.google.caliper.Param;
-import com.google.common.jdk5backport.Arrays;
 
+import java.util.Arrays;
 import java.util.Comparator;
 import java.util.Random;
 
diff --git a/guava-tests/benchmark/com/google/common/util/concurrent/CycleDetectingLockFactoryBenchmark.java b/guava-tests/benchmark/com/google/common/util/concurrent/CycleDetectingLockFactoryBenchmark.java
new file mode 100644
index 0000000..a8c7807
--- /dev/null
+++ b/guava-tests/benchmark/com/google/common/util/concurrent/CycleDetectingLockFactoryBenchmark.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.util.concurrent;
+
+import com.google.caliper.BeforeExperiment;
+import com.google.caliper.Benchmark;
+import com.google.caliper.Param;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Benchmarks for {@link CycleDetectingLockFactory}.
+ *
+ * @author Darick Tong
+ */
+public class CycleDetectingLockFactoryBenchmark {
+
+  @Param({"2","3","4","5","10"}) int lockNestingDepth;
+
+  CycleDetectingLockFactory factory;
+  private Lock[] plainLocks;
+  private Lock[] detectingLocks;
+
+  @BeforeExperiment
+  void setUp() throws Exception {
+    this.factory = CycleDetectingLockFactory.newInstance(
+        CycleDetectingLockFactory.Policies.WARN);
+    this.plainLocks = new Lock[lockNestingDepth];
+    for (int i = 0; i < lockNestingDepth; i++) {
+      plainLocks[i] = new ReentrantLock();
+    }
+    this.detectingLocks = new Lock[lockNestingDepth];
+    for (int i = 0; i < lockNestingDepth; i++) {
+      detectingLocks[i] = factory.newReentrantLock("Lock" + i);
+    }
+  }
+
+  @Benchmark void unorderedPlainLocks(int reps) {
+    lockAndUnlock(new ReentrantLock(), reps);
+  }
+
+  @Benchmark void unorderedCycleDetectingLocks(int reps) {
+    lockAndUnlock(factory.newReentrantLock("foo"), reps);
+  }
+
+  private void lockAndUnlock(Lock lock, int reps) {
+    for (int i = 0; i < reps; i++) {
+      lock.lock();
+      lock.unlock();
+    }
+  }
+
+  @Benchmark void orderedPlainLocks(int reps) {
+    lockAndUnlockNested(plainLocks, reps);
+  }
+
+  @Benchmark void orderedCycleDetectingLocks(int reps) {
+    lockAndUnlockNested(detectingLocks, reps);
+  }
+
+  private void lockAndUnlockNested(Lock[] locks, int reps) {
+    for (int i = 0; i < reps; i++) {
+      for (int j = 0; j < locks.length; j++) {
+        locks[j].lock();
+      }
+      for (int j = locks.length - 1; j >= 0; j--) {
+        locks[j].unlock();
+      }
+    }
+  }
+}
diff --git a/guava-tests/benchmark/com/google/common/util/concurrent/ExecutionListBenchmark.java b/guava-tests/benchmark/com/google/common/util/concurrent/ExecutionListBenchmark.java
index 3db52db..4e86043 100644
--- a/guava-tests/benchmark/com/google/common/util/concurrent/ExecutionListBenchmark.java
+++ b/guava-tests/benchmark/com/google/common/util/concurrent/ExecutionListBenchmark.java
@@ -16,6 +16,8 @@
 
 package com.google.common.util.concurrent;
 
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
+
 import com.google.caliper.AfterExperiment;
 import com.google.caliper.BeforeExperiment;
 import com.google.caliper.Benchmark;
@@ -46,10 +48,6 @@
 public class ExecutionListBenchmark {
   private static final int NUM_THREADS = 10;  // make a param?
 
-  // We execute the listeners on the sameThreadExecutor because we don't really care about what the
-  // listeners are doing, and they aren't doing much.
-  private static final Executor SAME_THREAD_EXECUTOR = MoreExecutors.sameThreadExecutor();
-
   // simple interface to wrap our two implementations.
   interface ExecutionListWrapper {
     void add(Runnable runnable, Executor executor);
@@ -189,7 +187,7 @@
   public Object measureSize() {
     list = impl.newExecutionList();
     for (int i = 0; i < numListeners; i++) {
-      list.add(listener, SAME_THREAD_EXECUTOR);
+      list.add(listener, directExecutor());
     }
     return list.getImpl();
   }
@@ -200,7 +198,7 @@
       list = impl.newExecutionList();
       listenerLatch = new CountDownLatch(numListeners);
       for (int j = 0; j < numListeners; j++) {
-        list.add(listener, SAME_THREAD_EXECUTOR);
+        list.add(listener, directExecutor());
         returnValue += listenerLatch.getCount();
       }
       list.execute();
@@ -216,7 +214,7 @@
       list.execute();
       listenerLatch = new CountDownLatch(numListeners);
       for (int j = 0; j < numListeners; j++) {
-        list.add(listener, SAME_THREAD_EXECUTOR);
+        list.add(listener, directExecutor());
         returnValue += listenerLatch.getCount();
       }
       returnValue += listenerLatch.getCount();
@@ -234,7 +232,7 @@
     Runnable addTask = new Runnable() {
       @Override public void run() {
         for (int i = 0; i < numListeners; i++) {
-          list.add(listener, SAME_THREAD_EXECUTOR);
+          list.add(listener, directExecutor());
         }
       }
     };
@@ -256,7 +254,7 @@
     Runnable addTask = new Runnable() {
       @Override public void run() {
         for (int i = 0; i < numListeners; i++) {
-          list.add(listener, SAME_THREAD_EXECUTOR);
+          list.add(listener, directExecutor());
         }
       }
     };
diff --git a/guava-tests/benchmark/com/google/common/util/concurrent/FuturesCombineBenchmark.java b/guava-tests/benchmark/com/google/common/util/concurrent/FuturesCombineBenchmark.java
new file mode 100644
index 0000000..60b5e5c
--- /dev/null
+++ b/guava-tests/benchmark/com/google/common/util/concurrent/FuturesCombineBenchmark.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2014 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.util.concurrent;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.caliper.Benchmark;
+import com.google.caliper.Param;
+import com.google.caliper.api.VmOptions;
+import com.google.common.collect.ImmutableList;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+
+/**
+ * A benchmark for {@link Futures#combine}
+ */
+@VmOptions({"-Xms12g", "-Xmx12g", "-d64"})
+public class FuturesCombineBenchmark {
+
+  enum Impl {
+    OLD {
+      @Override <V> ListenableFuture<V> combine(final Callable<V> combiner, Executor executor,
+          Iterable<? extends ListenableFuture<?>> futures) {
+        ListenableFuture<?> trigger = Futures.successfulAsList(futures);
+        checkNotNull(combiner);
+        checkNotNull(trigger);
+        return Futures.transform(trigger, new AsyncFunction<Object, V>() {
+          @Override public ListenableFuture<V> apply(Object arg) throws Exception {
+            try {
+              return Futures.immediateFuture(combiner.call());
+            } catch (CancellationException e) {
+              return Futures.immediateCancelledFuture();
+            } catch (ExecutionException e) {
+              return Futures.immediateFailedFuture(e.getCause()); // OK to rethrow on Error
+            }
+          }
+        }, executor);
+      }
+    },
+    NEW {
+      @Override
+      <V> ListenableFuture<V> combine(Callable<V> combiner, final Executor executor,
+          Iterable<? extends ListenableFuture<?>> futures) {
+        return Futures.combine(combiner, executor, futures);
+      }
+    };
+
+    abstract <V> ListenableFuture<V> combine(
+        Callable<V> combiner, Executor executor,
+        Iterable<? extends ListenableFuture<?>> futures);
+  }
+
+  private static final Executor INLINE_EXECUTOR = new Executor() {
+    @Override public void execute(Runnable command) {
+      command.run();
+    }
+  };
+
+  @Param Impl impl;
+  @Param({"1", "5", "10"}) int numInputs;
+
+  @Benchmark int timeDoneSuccesfulFutures(int reps) throws Exception {
+    ImmutableList.Builder<ListenableFuture<?>> futuresBuilder = ImmutableList.builder();
+    for (int i = 0; i < numInputs; i++) {
+      futuresBuilder.add(Futures.immediateFuture(i));
+    }
+    ImmutableList<ListenableFuture<?>> futures = futuresBuilder.build();
+    Impl impl = this.impl;
+    Callable<Integer> callable = Callables.returning(12);
+    int sum = 0;
+    for (int i = 0; i < reps; i++) {
+      sum += impl.combine(callable, INLINE_EXECUTOR, futures).get();
+    }
+    return sum;
+  }
+  
+  @Benchmark int timeDoneFailedFutures(int reps) throws Exception {
+    ImmutableList.Builder<ListenableFuture<?>> futuresBuilder = ImmutableList.builder();
+    for (int i = 0; i < numInputs; i++) {
+      futuresBuilder.add(Futures.immediateFailedFuture(new Exception("boom")));
+    }
+    ImmutableList<ListenableFuture<?>> futures = futuresBuilder.build();
+    Impl impl = this.impl;
+    Callable<Integer> callable = Callables.returning(12);
+    int sum = 0;
+    for (int i = 0; i < reps; i++) {
+      sum += impl.combine(callable, INLINE_EXECUTOR, futures).get();
+    }
+    return sum;
+  }
+  
+  @Benchmark int timeSuccesfulFutures(int reps) throws Exception {
+    Impl impl = this.impl;
+    Callable<Integer> callable = Callables.returning(12);
+    int sum = 0;
+    for (int i = 0; i < reps; i++) {
+      ImmutableList<SettableFuture<Integer>> futures = getSettableFutureList();
+      ListenableFuture<Integer> combined = impl.combine(callable, INLINE_EXECUTOR, futures);
+      for (SettableFuture<Integer> future : futures) {
+        future.set(i);
+      }
+      sum += combined.get();
+    }
+    return sum;
+  }
+
+  @Benchmark int timeFailedFutures(int reps) throws Exception {
+    Impl impl = this.impl;
+    Callable<Integer> callable = Callables.returning(12);
+    int sum = 0;
+    Exception throwable = new Exception("boom");
+    for (int i = 0; i < reps; i++) {
+      ImmutableList<SettableFuture<Integer>> futures = getSettableFutureList();
+      ListenableFuture<Integer> combined = impl.combine(callable, INLINE_EXECUTOR, futures);
+      for (SettableFuture<Integer> future : futures) {
+        future.setException(throwable);
+      }
+      sum += combined.get();
+    }
+    return sum;
+  }
+
+  private ImmutableList<SettableFuture<Integer>> getSettableFutureList() {
+    ImmutableList.Builder<SettableFuture<Integer>> futuresBuilder = ImmutableList.builder();
+    for (int i = 0; i < numInputs; i++) {
+      futuresBuilder.add(SettableFuture.<Integer>create());
+    }
+    return futuresBuilder.build();
+  }
+}
diff --git a/guava-tests/benchmark/com/google/common/util/concurrent/MoreExecutorsDirectExecutorBenchmark.java b/guava-tests/benchmark/com/google/common/util/concurrent/MoreExecutorsDirectExecutorBenchmark.java
new file mode 100644
index 0000000..aaecd50
--- /dev/null
+++ b/guava-tests/benchmark/com/google/common/util/concurrent/MoreExecutorsDirectExecutorBenchmark.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2014 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.util.concurrent;
+
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
+import static com.google.common.util.concurrent.MoreExecutors.newDirectExecutorService;
+
+import com.google.caliper.AfterExperiment;
+import com.google.caliper.BeforeExperiment;
+import com.google.caliper.Benchmark;
+import com.google.caliper.Param;
+import com.google.caliper.api.Footprint;
+import com.google.caliper.api.VmOptions;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A benchmark comparing the {@link MoreExecutors#newDirectExecutorService()} to
+ * {@link MoreExecutors#directExecutor}.
+ */
+@VmOptions({"-Xms12g", "-Xmx12g", "-d64"})
+public class MoreExecutorsDirectExecutorBenchmark {
+  enum Impl {
+    EXECUTOR_SERVICE {
+      @Override Executor executor() {
+        return newDirectExecutorService();
+      }
+    },
+    EXECUTOR {
+      @Override Executor executor() {
+        return directExecutor();
+      }
+    };
+    abstract Executor executor();
+  }
+
+  @Param Impl impl;
+  Executor executor;
+
+  static final class CountingRunnable implements Runnable {
+    AtomicInteger integer = new AtomicInteger();
+    @Override public void run() {
+      integer.incrementAndGet();
+    }
+  }
+  
+  CountingRunnable countingRunnable = new CountingRunnable();
+
+  Set<Thread> threads = new HashSet<Thread>();
+  
+  @BeforeExperiment void before() {
+    executor = impl.executor();
+    for (int i = 0; i < 4; i++) {
+      Thread thread = new Thread() {
+        @Override public void run() {
+          CountingRunnable localRunnable = new CountingRunnable();
+          while (!isInterrupted()) {
+            executor.execute(localRunnable);
+          }
+          countingRunnable.integer.addAndGet(localRunnable.integer.get());
+        }
+      };
+      threads.add(thread);
+    }
+  }
+
+  @AfterExperiment void after() {
+    for (Thread thread : threads) {
+      thread.interrupt();  // try to get them to exit
+    }
+    threads.clear();
+  }
+  
+  @Footprint Object measureSize() {
+    return executor;
+  }
+  
+  @Benchmark int timeUncontendedExecute(int reps) {
+    final Executor executor = this.executor;
+    final CountingRunnable countingRunnable = this.countingRunnable;
+    for (int i = 0; i < reps; i++) {
+      executor.execute(countingRunnable);
+    }
+    return countingRunnable.integer.get();
+  }
+  
+  @Benchmark int timeContendedExecute(int reps) {
+    final Executor executor = this.executor;
+    for (Thread thread : threads) {
+      if (!thread.isAlive()) {
+        thread.start();
+      }
+    }
+    final CountingRunnable countingRunnable = this.countingRunnable;
+    for (int i = 0; i < reps; i++) {
+      executor.execute(countingRunnable);
+    }
+    return countingRunnable.integer.get();
+  }
+}
diff --git a/guava-tests/pom.xml b/guava-tests/pom.xml
index 55cd277..ea1e303 100644
--- a/guava-tests/pom.xml
+++ b/guava-tests/pom.xml
@@ -4,11 +4,11 @@
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>com.google.guava</groupId>
-    <artifactId>guava-parent-jdk5</artifactId>
-    <version>17.0</version>
+    <artifactId>guava-parent</artifactId>
+    <version>18.0</version>
   </parent>
-  <artifactId>guava-tests-jdk5</artifactId>
-  <name>Guava Unit Tests (JDK5 Backport)</name>
+  <artifactId>guava-tests</artifactId>
+  <name>Guava Unit Tests</name>
   <description>
     The unit tests for the Guava libraries - separated into a
     separate artifact to allow for the testlibs to depend on guava
@@ -17,17 +17,11 @@
   <dependencies>
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>guava-testlib-jdk5</artifactId>
+      <artifactId>guava-testlib</artifactId>
       <version>${project.version}</version>
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>guava-bootstrap-jdk5</artifactId>
-      <version>${project.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
       <groupId>com.google.code.findbugs</groupId>
       <artifactId>jsr305</artifactId>
     </dependency>
@@ -44,7 +38,7 @@
       <artifactId>mockito-core</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.truth0</groupId>
+      <groupId>com.google.truth</groupId>
       <artifactId>truth</artifactId>
     </dependency>
     <dependency>
@@ -56,23 +50,6 @@
     <plugins>
       <plugin>
         <artifactId>maven-compiler-plugin</artifactId>
-        <configuration>
-          <!-- Prepend guava-bootstrap to avoid an API incompatibility between JDK5 and JDK6 -->
-          <compilerArgument>-Xbootclasspath/p:${project.build.directory}/dependency/guava-bootstrap-jdk5-${project.version}.jar</compilerArgument>
-        </configuration>
-      </plugin>
-      <plugin>
-        <artifactId>maven-dependency-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>prep-guava-bootstrap</id>
-            <phase>process-sources</phase>
-            <goals><goal>copy-dependencies</goal></goals>
-            <configuration>
-              <includeArtifactIds>guava-bootstrap-jdk5</includeArtifactIds>
-            </configuration>
-          </execution>
-        </executions>
       </plugin>
       <plugin>
         <artifactId>maven-source-plugin</artifactId>
diff --git a/guava-tests/test/com/google/common/base/AsciiTest.java b/guava-tests/test/com/google/common/base/AsciiTest.java
index 8aaff5e..03a6a3e 100644
--- a/guava-tests/test/com/google/common/base/AsciiTest.java
+++ b/guava-tests/test/com/google/common/base/AsciiTest.java
@@ -17,6 +17,7 @@
 package com.google.common.base;
 
 import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
 
 import junit.framework.TestCase;
 
@@ -135,6 +136,7 @@
     assertFalse(Ascii.equalsIgnoreCase("[", "{"));
   }
 
+  @GwtIncompatible("String.toUpperCase() has browser semantics")
   public void testEqualsIgnoreCaseUnicodeEquivalence() {
     // Note that it's possible in future that the JDK's idea to toUpperCase() or equalsIgnoreCase()
     // may change and break assumptions in this test [*]. This is not a bug in the implementation of
diff --git a/guava-tests/test/com/google/common/base/CharsetsTest.java b/guava-tests/test/com/google/common/base/CharsetsTest.java
index bf0b177..f604dd0 100644
--- a/guava-tests/test/com/google/common/base/CharsetsTest.java
+++ b/guava-tests/test/com/google/common/base/CharsetsTest.java
@@ -21,7 +21,6 @@
 
 import junit.framework.TestCase;
 
-import java.io.UnsupportedEncodingException;
 import java.nio.charset.Charset;
 import java.util.Arrays;
 
@@ -63,12 +62,12 @@
   }
 
   @GwtIncompatible("Non-UTF-8 Charset")
-  public void testWhyUsAsciiIsDangerous() throws UnsupportedEncodingException {
-    byte[] b1 = "朝日新聞".getBytes(Charsets.US_ASCII.name());
-    byte[] b2 = "聞朝日新".getBytes(Charsets.US_ASCII.name());
-    byte[] b3 = "????".getBytes(Charsets.US_ASCII.name());
-    byte[] b4 = "ニュース".getBytes(Charsets.US_ASCII.name());
-    byte[] b5 = "スューー".getBytes(Charsets.US_ASCII.name());
+  public void testWhyUsAsciiIsDangerous() {
+    byte[] b1 = "朝日新聞".getBytes(Charsets.US_ASCII);
+    byte[] b2 = "聞朝日新".getBytes(Charsets.US_ASCII);
+    byte[] b3 = "????".getBytes(Charsets.US_ASCII);
+    byte[] b4 = "ニュース".getBytes(Charsets.US_ASCII);
+    byte[] b5 = "スューー".getBytes(Charsets.US_ASCII);
     // Assert they are all equal (using the transitive property)
     assertTrue(Arrays.equals(b1, b2));
     assertTrue(Arrays.equals(b2, b3));
diff --git a/guava-tests/test/com/google/common/base/EnumsTest.java b/guava-tests/test/com/google/common/base/EnumsTest.java
index c85455c..a5faed2 100644
--- a/guava-tests/test/com/google/common/base/EnumsTest.java
+++ b/guava-tests/test/com/google/common/base/EnumsTest.java
@@ -19,7 +19,6 @@
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.testing.EqualsTester;
 import com.google.common.testing.GcFinalization;
 import com.google.common.testing.NullPointerTester;
 import com.google.common.testing.SerializableTester;
@@ -50,39 +49,6 @@
 
   private enum OtherEnum {}
 
-  public void testValueOfFunction() {
-    Function<String, TestEnum> function = Enums.valueOfFunction(TestEnum.class);
-    assertEquals(TestEnum.CHEETO, function.apply("CHEETO"));
-    assertEquals(TestEnum.HONDA, function.apply("HONDA"));
-    assertEquals(TestEnum.POODLE, function.apply("POODLE"));
-  }
-
-  public void testValueOfFunction_caseSensitive() {
-    Function<String, TestEnum> function = Enums.valueOfFunction(TestEnum.class);
-    assertNull(function.apply("cHEETO"));
-    assertNull(function.apply("Honda"));
-    assertNull(function.apply("poodlE"));
-  }
-
-  public void testValueOfFunction_nullWhenNoMatchingConstant() {
-    Function<String, TestEnum> function = Enums.valueOfFunction(TestEnum.class);
-    assertNull(function.apply("WOMBAT"));
-  }
-
-  public void testValueOfFunction_equals() {
-    new EqualsTester()
-        .addEqualityGroup(
-            Enums.valueOfFunction(TestEnum.class), Enums.valueOfFunction(TestEnum.class))
-        .addEqualityGroup(Enums.valueOfFunction(OtherEnum.class))
-        .testEquals();
-  }
-
-  @GwtIncompatible("SerializableTester")
-  public void testValueOfFunction_serialization() {
-    Function<String, TestEnum> function = Enums.valueOfFunction(TestEnum.class);
-    SerializableTester.reserializeAndAssert(function);
-  }
-
   public void testGetIfPresent() {
     assertEquals(Optional.of(TestEnum.CHEETO), Enums.getIfPresent(TestEnum.class, "CHEETO"));
     assertEquals(Optional.of(TestEnum.HONDA), Enums.getIfPresent(TestEnum.class, "HONDA"));
diff --git a/guava-tests/test/com/google/common/base/FinalizableReferenceQueueClassLoaderUnloadingTest.java b/guava-tests/test/com/google/common/base/FinalizableReferenceQueueClassLoaderUnloadingTest.java
index 7f498b6..080c667 100644
--- a/guava-tests/test/com/google/common/base/FinalizableReferenceQueueClassLoaderUnloadingTest.java
+++ b/guava-tests/test/com/google/common/base/FinalizableReferenceQueueClassLoaderUnloadingTest.java
@@ -26,9 +26,7 @@
 import java.lang.reflect.Field;
 import java.net.URL;
 import java.net.URLClassLoader;
-import java.security.CodeSource;
 import java.security.Permission;
-import java.security.PermissionCollection;
 import java.security.Policy;
 import java.security.ProtectionDomain;
 import java.util.concurrent.Callable;
@@ -77,16 +75,6 @@
     public boolean implies(ProtectionDomain pd, Permission perm) {
       return true;
     }
-
-    @Override
-    public PermissionCollection getPermissions(CodeSource codesource) {
-      throw new AssertionError();
-    }
-
-    @Override
-    public void refresh() {
-      throw new AssertionError();
-    }
   }
 
   private WeakReference<ClassLoader> useFrqInSeparateLoader() throws Exception {
diff --git a/guava-tests/test/com/google/common/base/JoinerTest.java b/guava-tests/test/com/google/common/base/JoinerTest.java
index 169313e..32f22e2 100644
--- a/guava-tests/test/com/google/common/base/JoinerTest.java
+++ b/guava-tests/test/com/google/common/base/JoinerTest.java
@@ -22,7 +22,6 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableMultimap;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterators;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.testing.NullPointerTester;
@@ -357,10 +356,7 @@
 
   @GwtIncompatible("NullPointerTester")
   public void testNullPointers() {
-    NullPointerTester tester = new NullPointerTester()
-        // This is necessary because of the generics hackery we have to temporarily support
-        // parameters which implement both Iterator and Iterable.;
-        .setDefault(Object.class, Iterators.emptyIterator());
+    NullPointerTester tester = new NullPointerTester();
     tester.testAllPublicStaticMethods(Joiner.class);
     tester.testInstanceMethods(Joiner.on(","), NullPointerTester.Visibility.PACKAGE);
     tester.testInstanceMethods(Joiner.on(",").skipNulls(), NullPointerTester.Visibility.PACKAGE);
diff --git a/guava-tests/test/com/google/common/base/OptionalTest.java b/guava-tests/test/com/google/common/base/OptionalTest.java
index 113e331..daa8920 100644
--- a/guava-tests/test/com/google/common/base/OptionalTest.java
+++ b/guava-tests/test/com/google/common/base/OptionalTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.base;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -221,34 +221,34 @@
   public void testPresentInstances_allPresent() {
     List<Optional<String>> optionals =
         ImmutableList.of(Optional.of("a"), Optional.of("b"), Optional.of("c"));
-    ASSERT.that(Optional.presentInstances(optionals)).iteratesOverSequence("a", "b", "c");
+    assertThat(Optional.presentInstances(optionals)).iteratesAs("a", "b", "c");
   }
 
   public void testPresentInstances_allAbsent() {
     List<Optional<Object>> optionals =
         ImmutableList.of(Optional.absent(), Optional.absent());
-    ASSERT.that(Optional.presentInstances(optionals)).isEmpty();
+    assertThat(Optional.presentInstances(optionals)).isEmpty();
   }
 
   public void testPresentInstances_somePresent() {
     List<Optional<String>> optionals =
         ImmutableList.of(Optional.of("a"), Optional.<String>absent(), Optional.of("c"));
-    ASSERT.that(Optional.presentInstances(optionals)).iteratesOverSequence("a", "c");
+    assertThat(Optional.presentInstances(optionals)).iteratesAs("a", "c");
   }
 
   public void testPresentInstances_callingIteratorTwice() {
     List<Optional<String>> optionals =
         ImmutableList.of(Optional.of("a"), Optional.<String>absent(), Optional.of("c"));
     Iterable<String> onlyPresent = Optional.presentInstances(optionals);
-    ASSERT.that(onlyPresent).iteratesOverSequence("a", "c");
-    ASSERT.that(onlyPresent).iteratesOverSequence("a", "c");
+    assertThat(onlyPresent).iteratesAs("a", "c");
+    assertThat(onlyPresent).iteratesAs("a", "c");
   }
 
   public void testPresentInstances_wildcards() {
     List<Optional<? extends Number>> optionals =
         ImmutableList.<Optional<? extends Number>>of(Optional.<Double>absent(), Optional.of(2));
     Iterable<Number> onlyPresent = Optional.presentInstances(optionals);
-    ASSERT.that(onlyPresent).iteratesOverSequence(2);
+    assertThat(onlyPresent).iteratesAs(2);
   }
 
   private static Optional<Integer> getSomeOptionalInt() {
diff --git a/guava-tests/test/com/google/common/base/SplitterTest.java b/guava-tests/test/com/google/common/base/SplitterTest.java
index 0ac09cf..88b4c80 100644
--- a/guava-tests/test/com/google/common/base/SplitterTest.java
+++ b/guava-tests/test/com/google/common/base/SplitterTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.base;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -51,7 +51,7 @@
   public void testCharacterSimpleSplit() {
     String simple = "a,b,c";
     Iterable<String> letters = COMMA_SPLITTER.split(simple);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c");
+    assertThat(letters).iteratesAs("a", "b", "c");
   }
 
   /**
@@ -65,7 +65,7 @@
   public void testCharacterSimpleSplitToList() {
     String simple = "a,b,c";
     List<String> letters = COMMA_SPLITTER.splitToList(simple);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c");
+    assertThat(letters).iteratesAs("a", "b", "c");
   }
 
   public void testToString() {
@@ -77,37 +77,37 @@
   public void testCharacterSimpleSplitWithNoDelimiter() {
     String simple = "a,b,c";
     Iterable<String> letters = Splitter.on('.').split(simple);
-    ASSERT.that(letters).iteratesOverSequence("a,b,c");
+    assertThat(letters).iteratesAs("a,b,c");
   }
 
   public void testCharacterSplitWithDoubleDelimiter() {
     String doubled = "a,,b,c";
     Iterable<String> letters = COMMA_SPLITTER.split(doubled);
-    ASSERT.that(letters).iteratesOverSequence("a", "", "b", "c");
+    assertThat(letters).iteratesAs("a", "", "b", "c");
   }
 
   public void testCharacterSplitWithDoubleDelimiterAndSpace() {
     String doubled = "a,, b,c";
     Iterable<String> letters = COMMA_SPLITTER.split(doubled);
-    ASSERT.that(letters).iteratesOverSequence("a", "", " b", "c");
+    assertThat(letters).iteratesAs("a", "", " b", "c");
   }
 
   public void testCharacterSplitWithTrailingDelimiter() {
     String trailing = "a,b,c,";
     Iterable<String> letters = COMMA_SPLITTER.split(trailing);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c", "");
+    assertThat(letters).iteratesAs("a", "b", "c", "");
   }
 
   public void testCharacterSplitWithLeadingDelimiter() {
     String leading = ",a,b,c";
     Iterable<String> letters = COMMA_SPLITTER.split(leading);
-    ASSERT.that(letters).iteratesOverSequence("", "a", "b", "c");
+    assertThat(letters).iteratesAs("", "a", "b", "c");
   }
 
   public void testCharacterSplitWithMulitpleLetters() {
     Iterable<String> testCharacteringMotto = Splitter.on('-').split(
         "Testing-rocks-Debugging-sucks");
-    ASSERT.that(testCharacteringMotto).iteratesOverSequence(
+    assertThat(testCharacteringMotto).iteratesAs(
         "Testing", "rocks", "Debugging", "sucks");
   }
 
@@ -115,7 +115,7 @@
     Iterable<String> testCharacteringMotto = Splitter
         .on(CharMatcher.WHITESPACE)
         .split("Testing\nrocks\tDebugging sucks");
-    ASSERT.that(testCharacteringMotto).iteratesOverSequence(
+    assertThat(testCharacteringMotto).iteratesAs(
         "Testing", "rocks", "Debugging", "sucks");
   }
 
@@ -123,40 +123,40 @@
     String doubled = "a..b.c";
     Iterable<String> letters = Splitter.on('.')
         .omitEmptyStrings().split(doubled);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c");
+    assertThat(letters).iteratesAs("a", "b", "c");
   }
 
   public void testCharacterSplitEmptyToken() {
     String emptyToken = "a. .c";
     Iterable<String> letters = Splitter.on('.').trimResults()
         .split(emptyToken);
-    ASSERT.that(letters).iteratesOverSequence("a", "", "c");
+    assertThat(letters).iteratesAs("a", "", "c");
   }
 
   public void testCharacterSplitEmptyTokenOmitEmptyStrings() {
     String emptyToken = "a. .c";
     Iterable<String> letters = Splitter.on('.')
         .omitEmptyStrings().trimResults().split(emptyToken);
-    ASSERT.that(letters).iteratesOverSequence("a", "c");
+    assertThat(letters).iteratesAs("a", "c");
   }
 
   public void testCharacterSplitOnEmptyString() {
     Iterable<String> nothing = Splitter.on('.').split("");
-    ASSERT.that(nothing).iteratesOverSequence("");
+    assertThat(nothing).iteratesAs("");
   }
 
   public void testCharacterSplitOnEmptyStringOmitEmptyStrings() {
-    ASSERT.that(Splitter.on('.').omitEmptyStrings().split("")).isEmpty();
+    assertThat(Splitter.on('.').omitEmptyStrings().split("")).isEmpty();
   }
 
   public void testCharacterSplitOnOnlyDelimiter() {
     Iterable<String> blankblank = Splitter.on('.').split(".");
-    ASSERT.that(blankblank).iteratesOverSequence("", "");
+    assertThat(blankblank).iteratesAs("", "");
   }
 
   public void testCharacterSplitOnOnlyDelimitersOmitEmptyStrings() {
     Iterable<String> empty = Splitter.on('.').omitEmptyStrings().split("...");
-    ASSERT.that(empty).isEmpty();
+    assertThat(empty).isEmpty();
   }
 
   public void testCharacterSplitWithTrim() {
@@ -165,50 +165,50 @@
     Iterable<String> family = COMMA_SPLITTER
         .trimResults(CharMatcher.anyOf("afro").or(CharMatcher.WHITESPACE))
         .split(jacksons);
-    ASSERT.that(family).iteratesOverSequence(
+    assertThat(family).iteratesAs(
         "(Marlon)", "(Michael)", "(Jackie)", "(Jemaine)", "(Tito)");
   }
 
   public void testStringSimpleSplit() {
     String simple = "a,b,c";
     Iterable<String> letters = Splitter.on(',').split(simple);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c");
+    assertThat(letters).iteratesAs("a", "b", "c");
   }
 
   public void testStringSimpleSplitWithNoDelimiter() {
     String simple = "a,b,c";
     Iterable<String> letters = Splitter.on('.').split(simple);
-    ASSERT.that(letters).iteratesOverSequence("a,b,c");
+    assertThat(letters).iteratesAs("a,b,c");
   }
 
   public void testStringSplitWithDoubleDelimiter() {
     String doubled = "a,,b,c";
     Iterable<String> letters = Splitter.on(',').split(doubled);
-    ASSERT.that(letters).iteratesOverSequence("a", "", "b", "c");
+    assertThat(letters).iteratesAs("a", "", "b", "c");
   }
 
   public void testStringSplitWithDoubleDelimiterAndSpace() {
     String doubled = "a,, b,c";
     Iterable<String> letters = Splitter.on(',').split(doubled);
-    ASSERT.that(letters).iteratesOverSequence("a", "", " b", "c");
+    assertThat(letters).iteratesAs("a", "", " b", "c");
   }
 
   public void testStringSplitWithTrailingDelimiter() {
     String trailing = "a,b,c,";
     Iterable<String> letters = Splitter.on(',').split(trailing);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c", "");
+    assertThat(letters).iteratesAs("a", "b", "c", "");
   }
 
   public void testStringSplitWithLeadingDelimiter() {
     String leading = ",a,b,c";
     Iterable<String> letters = Splitter.on(',').split(leading);
-    ASSERT.that(letters).iteratesOverSequence("", "a", "b", "c");
+    assertThat(letters).iteratesAs("", "a", "b", "c");
   }
 
   public void testStringSplitWithMultipleLetters() {
     Iterable<String> testStringingMotto = Splitter.on('-').split(
         "Testing-rocks-Debugging-sucks");
-    ASSERT.that(testStringingMotto).iteratesOverSequence(
+    assertThat(testStringingMotto).iteratesAs(
         "Testing", "rocks", "Debugging", "sucks");
   }
 
@@ -216,46 +216,46 @@
     String doubled = "a..b.c";
     Iterable<String> letters = Splitter.on('.')
         .omitEmptyStrings().split(doubled);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c");
+    assertThat(letters).iteratesAs("a", "b", "c");
   }
 
   public void testStringSplitEmptyToken() {
     String emptyToken = "a. .c";
     Iterable<String> letters = Splitter.on('.').trimResults()
         .split(emptyToken);
-    ASSERT.that(letters).iteratesOverSequence("a", "", "c");
+    assertThat(letters).iteratesAs("a", "", "c");
   }
 
   public void testStringSplitEmptyTokenOmitEmptyStrings() {
     String emptyToken = "a. .c";
     Iterable<String> letters = Splitter.on('.')
         .omitEmptyStrings().trimResults().split(emptyToken);
-    ASSERT.that(letters).iteratesOverSequence("a", "c");
+    assertThat(letters).iteratesAs("a", "c");
   }
 
   public void testStringSplitWithLongDelimiter() {
     String longDelimiter = "a, b, c";
     Iterable<String> letters = Splitter.on(", ").split(longDelimiter);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c");
+    assertThat(letters).iteratesAs("a", "b", "c");
   }
 
   public void testStringSplitWithLongLeadingDelimiter() {
     String longDelimiter = ", a, b, c";
     Iterable<String> letters = Splitter.on(", ").split(longDelimiter);
-    ASSERT.that(letters).iteratesOverSequence("", "a", "b", "c");
+    assertThat(letters).iteratesAs("", "a", "b", "c");
   }
 
   public void testStringSplitWithLongTrailingDelimiter() {
     String longDelimiter = "a, b, c, ";
     Iterable<String> letters = Splitter.on(", ").split(longDelimiter);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c", "");
+    assertThat(letters).iteratesAs("a", "b", "c", "");
   }
 
   public void testStringSplitWithDelimiterSubstringInValue() {
     String fourCommasAndFourSpaces = ",,,,    ";
     Iterable<String> threeCommasThenThreeSpaces = Splitter.on(", ").split(
         fourCommasAndFourSpaces);
-    ASSERT.that(threeCommasThenThreeSpaces).iteratesOverSequence(",,,", "   ");
+    assertThat(threeCommasThenThreeSpaces).iteratesAs(",,,", "   ");
   }
 
   public void testStringSplitWithEmptyString() {
@@ -268,21 +268,21 @@
 
   public void testStringSplitOnEmptyString() {
     Iterable<String> notMuch = Splitter.on('.').split("");
-    ASSERT.that(notMuch).iteratesOverSequence("");
+    assertThat(notMuch).iteratesAs("");
   }
 
   public void testStringSplitOnEmptyStringOmitEmptyString() {
-    ASSERT.that(Splitter.on('.').omitEmptyStrings().split("")).isEmpty();
+    assertThat(Splitter.on('.').omitEmptyStrings().split("")).isEmpty();
   }
 
   public void testStringSplitOnOnlyDelimiter() {
     Iterable<String> blankblank = Splitter.on('.').split(".");
-    ASSERT.that(blankblank).iteratesOverSequence("", "");
+    assertThat(blankblank).iteratesAs("", "");
   }
 
   public void testStringSplitOnOnlyDelimitersOmitEmptyStrings() {
     Iterable<String> empty = Splitter.on('.').omitEmptyStrings().split("...");
-    ASSERT.that(empty).isEmpty();
+    assertThat(empty).isEmpty();
   }
 
   public void testStringSplitWithTrim() {
@@ -291,7 +291,7 @@
     Iterable<String> family = Splitter.on(',')
         .trimResults(CharMatcher.anyOf("afro").or(CharMatcher.WHITESPACE))
         .split(jacksons);
-    ASSERT.that(family).iteratesOverSequence(
+    assertThat(family).iteratesAs(
         "(Marlon)", "(Michael)", "(Jackie)", "(Jemaine)", "(Tito)");
   }
 
@@ -299,42 +299,42 @@
   public void testPatternSimpleSplit() {
     String simple = "a,b,c";
     Iterable<String> letters = Splitter.onPattern(",").split(simple);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c");
+    assertThat(letters).iteratesAs("a", "b", "c");
   }
 
   @GwtIncompatible("Splitter.onPattern")
   public void testPatternSimpleSplitWithNoDelimiter() {
     String simple = "a,b,c";
     Iterable<String> letters = Splitter.onPattern("foo").split(simple);
-    ASSERT.that(letters).iteratesOverSequence("a,b,c");
+    assertThat(letters).iteratesAs("a,b,c");
   }
 
   @GwtIncompatible("Splitter.onPattern")
   public void testPatternSplitWithDoubleDelimiter() {
     String doubled = "a,,b,c";
     Iterable<String> letters = Splitter.onPattern(",").split(doubled);
-    ASSERT.that(letters).iteratesOverSequence("a", "", "b", "c");
+    assertThat(letters).iteratesAs("a", "", "b", "c");
   }
 
   @GwtIncompatible("Splitter.onPattern")
   public void testPatternSplitWithDoubleDelimiterAndSpace() {
     String doubled = "a,, b,c";
     Iterable<String> letters = Splitter.onPattern(",").split(doubled);
-    ASSERT.that(letters).iteratesOverSequence("a", "", " b", "c");
+    assertThat(letters).iteratesAs("a", "", " b", "c");
   }
 
   @GwtIncompatible("Splitter.onPattern")
   public void testPatternSplitWithTrailingDelimiter() {
     String trailing = "a,b,c,";
     Iterable<String> letters = Splitter.onPattern(",").split(trailing);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c", "");
+    assertThat(letters).iteratesAs("a", "b", "c", "");
   }
 
   @GwtIncompatible("Splitter.onPattern")
   public void testPatternSplitWithLeadingDelimiter() {
     String leading = ",a,b,c";
     Iterable<String> letters = Splitter.onPattern(",").split(leading);
-    ASSERT.that(letters).iteratesOverSequence("", "a", "b", "c");
+    assertThat(letters).iteratesAs("", "a", "b", "c");
   }
 
   // TODO(kevinb): the name of this method suggests it might not actually be testing what it
@@ -343,7 +343,7 @@
   public void testPatternSplitWithMultipleLetters() {
     Iterable<String> testPatterningMotto = Splitter.onPattern("-").split(
         "Testing-rocks-Debugging-sucks");
-    ASSERT.that(testPatterningMotto).iteratesOverSequence("Testing", "rocks", "Debugging", "sucks");
+    assertThat(testPatterningMotto).iteratesAs("Testing", "rocks", "Debugging", "sucks");
   }
 
   @GwtIncompatible("java.util.regex.Pattern")
@@ -356,7 +356,7 @@
     String doubled = "a..b.c";
     Iterable<String> letters = Splitter.on(literalDotPattern())
         .omitEmptyStrings().split(doubled);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c");
+    assertThat(letters).iteratesAs("a", "b", "c");
   }
 
   @GwtIncompatible("java.util.regex.Pattern")
@@ -364,7 +364,7 @@
     String toSplit = ":foo::barbaz:";
     String regexPattern = "(?<=:)";
     Iterable<String> split = Splitter.onPattern(regexPattern).split(toSplit);
-    ASSERT.that(split).iteratesOverSequence(":", "foo:", ":", "barbaz:");
+    assertThat(split).iteratesAs(":", "foo:", ":", "barbaz:");
     // splits into chunks ending in :
   }
 
@@ -372,14 +372,14 @@
   public void testPatternSplitWordBoundary() {
     String string = "foo<bar>bletch";
     Iterable<String> words = Splitter.on(Pattern.compile("\\b")).split(string);
-    ASSERT.that(words).iteratesOverSequence("foo", "<", "bar", ">", "bletch");
+    assertThat(words).iteratesAs("foo", "<", "bar", ">", "bletch");
   }
 
   @GwtIncompatible("java.util.regex.Pattern")
   public void testPatternSplitEmptyToken() {
     String emptyToken = "a. .c";
     Iterable<String> letters = Splitter.on(literalDotPattern()).trimResults().split(emptyToken);
-    ASSERT.that(letters).iteratesOverSequence("a", "", "c");
+    assertThat(letters).iteratesAs("a", "", "c");
   }
 
   @GwtIncompatible("java.util.regex.Pattern")
@@ -387,21 +387,21 @@
     String emptyToken = "a. .c";
     Iterable<String> letters = Splitter.on(literalDotPattern())
         .omitEmptyStrings().trimResults().split(emptyToken);
-    ASSERT.that(letters).iteratesOverSequence("a", "c");
+    assertThat(letters).iteratesAs("a", "c");
   }
 
   @GwtIncompatible("java.util.regex.Pattern")
   public void testPatternSplitOnOnlyDelimiter() {
     Iterable<String> blankblank = Splitter.on(literalDotPattern()).split(".");
 
-    ASSERT.that(blankblank).iteratesOverSequence("", "");
+    assertThat(blankblank).iteratesAs("", "");
   }
 
   @GwtIncompatible("java.util.regex.Pattern")
   public void testPatternSplitOnOnlyDelimitersOmitEmptyStrings() {
     Iterable<String> empty = Splitter.on(literalDotPattern()).omitEmptyStrings()
         .split("...");
-    ASSERT.that(empty).isEmpty();
+    assertThat(empty).isEmpty();
   }
 
   @GwtIncompatible("java.util.regex.Pattern")
@@ -409,7 +409,7 @@
     String longDelimiter = "a, b,   c";
     Iterable<String> letters = Splitter.on(Pattern.compile(",\\s*"))
         .split(longDelimiter);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c");
+    assertThat(letters).iteratesAs("a", "b", "c");
   }
 
   @GwtIncompatible("java.util.regex.Pattern")
@@ -417,7 +417,7 @@
     String longDelimiter = ", a, b, c";
     Iterable<String> letters = Splitter.on(Pattern.compile(", "))
         .split(longDelimiter);
-    ASSERT.that(letters).iteratesOverSequence("", "a", "b", "c");
+    assertThat(letters).iteratesAs("", "a", "b", "c");
   }
 
   @GwtIncompatible("java.util.regex.Pattern")
@@ -425,7 +425,7 @@
     String longDelimiter = "a, b, c/ ";
     Iterable<String> letters = Splitter.on(Pattern.compile("[,/]\\s"))
         .split(longDelimiter);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c", "");
+    assertThat(letters).iteratesAs("a", "b", "c", "");
   }
 
   @GwtIncompatible("java.util.regex.Pattern")
@@ -444,7 +444,7 @@
     Iterable<String> family = Splitter.on(Pattern.compile(","))
         .trimResults(CharMatcher.anyOf("afro").or(CharMatcher.WHITESPACE))
         .split(jacksons);
-    ASSERT.that(family).iteratesOverSequence(
+    assertThat(family).iteratesAs(
         "(Marlon)", "(Michael)", "(Jackie)", "(Jemaine)", "(Tito)");
   }
 
@@ -505,41 +505,41 @@
   public void testFixedLengthSimpleSplit() {
     String simple = "abcde";
     Iterable<String> letters = Splitter.fixedLength(2).split(simple);
-    ASSERT.that(letters).iteratesOverSequence("ab", "cd", "e");
+    assertThat(letters).iteratesAs("ab", "cd", "e");
   }
 
   public void testFixedLengthSplitEqualChunkLength() {
     String simple = "abcdef";
     Iterable<String> letters = Splitter.fixedLength(2).split(simple);
-    ASSERT.that(letters).iteratesOverSequence("ab", "cd", "ef");
+    assertThat(letters).iteratesAs("ab", "cd", "ef");
   }
 
   public void testFixedLengthSplitOnlyOneChunk() {
     String simple = "abc";
     Iterable<String> letters = Splitter.fixedLength(3).split(simple);
-    ASSERT.that(letters).iteratesOverSequence("abc");
+    assertThat(letters).iteratesAs("abc");
   }
 
   public void testFixedLengthSplitSmallerString() {
     String simple = "ab";
     Iterable<String> letters = Splitter.fixedLength(3).split(simple);
-    ASSERT.that(letters).iteratesOverSequence("ab");
+    assertThat(letters).iteratesAs("ab");
   }
 
   public void testFixedLengthSplitEmptyString() {
     String simple = "";
     Iterable<String> letters = Splitter.fixedLength(3).split(simple);
-    ASSERT.that(letters).iteratesOverSequence("");
+    assertThat(letters).iteratesAs("");
   }
 
   public void testFixedLengthSplitEmptyStringWithOmitEmptyStrings() {
-    ASSERT.that(Splitter.fixedLength(3).omitEmptyStrings().split("")).isEmpty();
+    assertThat(Splitter.fixedLength(3).omitEmptyStrings().split("")).isEmpty();
   }
 
   public void testFixedLengthSplitIntoChars() {
     String simple = "abcd";
     Iterable<String> letters = Splitter.fixedLength(1).split(simple);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c", "d");
+    assertThat(letters).iteratesAs("a", "b", "c", "d");
   }
 
   public void testFixedLengthSplitZeroChunkLen() {
@@ -561,79 +561,79 @@
   public void testLimitLarge() {
     String simple = "abcd";
     Iterable<String> letters = Splitter.fixedLength(1).limit(100).split(simple);
-    ASSERT.that(letters).iteratesOverSequence("a", "b", "c", "d");
+    assertThat(letters).iteratesAs("a", "b", "c", "d");
   }
 
   public void testLimitOne() {
     String simple = "abcd";
     Iterable<String> letters = Splitter.fixedLength(1).limit(1).split(simple);
-    ASSERT.that(letters).iteratesOverSequence("abcd");
+    assertThat(letters).iteratesAs("abcd");
   }
 
   public void testLimitFixedLength() {
     String simple = "abcd";
     Iterable<String> letters = Splitter.fixedLength(1).limit(2).split(simple);
-    ASSERT.that(letters).iteratesOverSequence("a", "bcd");
+    assertThat(letters).iteratesAs("a", "bcd");
   }
 
   public void testLimitSeparator() {
     String simple = "a,b,c,d";
     Iterable<String> items = COMMA_SPLITTER.limit(2).split(simple);
-    ASSERT.that(items).iteratesOverSequence("a", "b,c,d");
+    assertThat(items).iteratesAs("a", "b,c,d");
   }
 
   public void testLimitExtraSeparators() {
     String text = "a,,,b,,c,d";
     Iterable<String> items = COMMA_SPLITTER.limit(2).split(text);
-    ASSERT.that(items).iteratesOverSequence("a", ",,b,,c,d");
+    assertThat(items).iteratesAs("a", ",,b,,c,d");
   }
 
   public void testLimitExtraSeparatorsOmitEmpty() {
     String text = "a,,,b,,c,d";
     Iterable<String> items = COMMA_SPLITTER.limit(2).omitEmptyStrings().split(text);
-    ASSERT.that(items).iteratesOverSequence("a", "b,,c,d");
+    assertThat(items).iteratesAs("a", "b,,c,d");
   }
 
   public void testLimitExtraSeparatorsOmitEmpty3() {
     String text = "a,,,b,,c,d";
     Iterable<String> items = COMMA_SPLITTER.limit(3).omitEmptyStrings().split(text);
-    ASSERT.that(items).iteratesOverSequence("a", "b", "c,d");
+    assertThat(items).iteratesAs("a", "b", "c,d");
   }
 
   public void testLimitExtraSeparatorsTrim() {
     String text = ",,a,,  , b ,, c,d ";
     Iterable<String> items = COMMA_SPLITTER.limit(2).omitEmptyStrings().trimResults().split(text);
-    ASSERT.that(items).iteratesOverSequence("a", "b ,, c,d");
+    assertThat(items).iteratesAs("a", "b ,, c,d");
   }
 
   public void testLimitExtraSeparatorsTrim3() {
     String text = ",,a,,  , b ,, c,d ";
     Iterable<String> items = COMMA_SPLITTER.limit(3).omitEmptyStrings().trimResults().split(text);
-    ASSERT.that(items).iteratesOverSequence("a", "b", "c,d");
+    assertThat(items).iteratesAs("a", "b", "c,d");
   }
 
   public void testLimitExtraSeparatorsTrim1() {
     String text = ",,a,,  , b ,, c,d ";
     Iterable<String> items = COMMA_SPLITTER.limit(1).omitEmptyStrings().trimResults().split(text);
-    ASSERT.that(items).iteratesOverSequence("a,,  , b ,, c,d");
+    assertThat(items).iteratesAs("a,,  , b ,, c,d");
   }
 
   public void testLimitExtraSeparatorsTrim1NoOmit() {
     String text = ",,a,,  , b ,, c,d ";
     Iterable<String> items = COMMA_SPLITTER.limit(1).trimResults().split(text);
-    ASSERT.that(items).iteratesOverSequence(",,a,,  , b ,, c,d");
+    assertThat(items).iteratesAs(",,a,,  , b ,, c,d");
   }
 
   public void testLimitExtraSeparatorsTrim1Empty() {
     String text = "";
     Iterable<String> items = COMMA_SPLITTER.limit(1).split(text);
-    ASSERT.that(items).iteratesOverSequence("");
+    assertThat(items).iteratesAs("");
   }
 
   public void testLimitExtraSeparatorsTrim1EmptyOmit() {
     String text = "";
     Iterable<String> items = COMMA_SPLITTER.omitEmptyStrings().limit(1).split(text);
-    ASSERT.that(items).isEmpty();
+    assertThat(items).isEmpty();
   }
 
   @SuppressWarnings("ReturnValueIgnored") // testing for exception
@@ -664,8 +664,8 @@
         .split("boy  : tom , girl: tina , cat  : kitty , dog: tommy ");
     ImmutableMap<String, String> expected =
           ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy");
-    ASSERT.that(m).isEqualTo(expected);
-    ASSERT.that(asList(m.entrySet())).is(asList(expected.entrySet()));
+    assertThat(m).isEqualTo(expected);
+    assertThat(asList(m.entrySet())).isEqualTo(asList(expected.entrySet()));
   }
 
   public void testMapSplitter_trimmedEntries() {
@@ -676,8 +676,8 @@
     ImmutableMap<String, String> expected =
         ImmutableMap.of("boy  ", " tom", "girl", " tina", "cat  ", " kitty", "dog", " tommy");
 
-    ASSERT.that(m).isEqualTo(expected);
-    ASSERT.that(asList(m.entrySet())).is(asList(expected.entrySet()));
+    assertThat(m).isEqualTo(expected);
+    assertThat(asList(m.entrySet())).isEqualTo(asList(expected.entrySet()));
   }
 
   public void testMapSplitter_trimmedKeyValue() {
@@ -686,8 +686,8 @@
             "boy  : tom , girl: tina , cat  : kitty , dog: tommy ");
     ImmutableMap<String, String> expected =
         ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy");
-    ASSERT.that(m).isEqualTo(expected);
-    ASSERT.that(asList(m.entrySet())).is(asList(expected.entrySet()));
+    assertThat(m).isEqualTo(expected);
+    assertThat(asList(m.entrySet())).isEqualTo(asList(expected.entrySet()));
   }
 
   public void testMapSplitter_notTrimmed() {
@@ -695,8 +695,8 @@
         " boy:tom , girl: tina , cat :kitty , dog:  tommy ");
     ImmutableMap<String, String> expected =
         ImmutableMap.of(" boy", "tom ", " girl", " tina ", " cat ", "kitty ", " dog", "  tommy ");
-    ASSERT.that(m).isEqualTo(expected);
-    ASSERT.that(asList(m.entrySet())).is(asList(expected.entrySet()));
+    assertThat(m).isEqualTo(expected);
+    assertThat(asList(m.entrySet())).isEqualTo(asList(expected.entrySet()));
   }
 
   public void testMapSplitter_CharacterSeparator() {
@@ -708,8 +708,8 @@
     ImmutableMap<String, String> expected =
         ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy");
 
-    ASSERT.that(m).isEqualTo(expected);
-    ASSERT.that(asList(m.entrySet())).is(asList(expected.entrySet()));
+    assertThat(m).isEqualTo(expected);
+    assertThat(asList(m.entrySet())).isEqualTo(asList(expected.entrySet()));
   }
 
   public void testMapSplitter_multiCharacterSeparator() {
@@ -721,8 +721,8 @@
     ImmutableMap<String, String> expected =
         ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy");
 
-    ASSERT.that(m).isEqualTo(expected);
-    ASSERT.that(asList(m.entrySet())).is(asList(expected.entrySet()));
+    assertThat(m).isEqualTo(expected);
+    assertThat(asList(m.entrySet())).isEqualTo(asList(expected.entrySet()));
   }
 
   @SuppressWarnings("ReturnValueIgnored") // testing for exception
@@ -747,8 +747,8 @@
         .withKeyValueSeparator(":")
         .split("boy:tom,girl:tina,cat:kitty,dog:tommy");
 
-    ASSERT.that(m.keySet()).iteratesOverSequence("boy", "girl", "cat", "dog");
-    ASSERT.that(m).isEqualTo(
+    assertThat(m.keySet()).iteratesAs("boy", "girl", "cat", "dog");
+    assertThat(m).isEqualTo(
         ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy"));
 
     // try in a different order
@@ -756,8 +756,8 @@
         .withKeyValueSeparator(":")
         .split("girl:tina,boy:tom,dog:tommy,cat:kitty");
 
-    ASSERT.that(m.keySet()).iteratesOverSequence("girl", "boy", "dog", "cat");
-    ASSERT.that(m).isEqualTo(
+    assertThat(m.keySet()).iteratesAs("girl", "boy", "dog", "cat");
+    assertThat(m).isEqualTo(
         ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy"));
   }
 
diff --git a/guava-tests/test/com/google/common/base/StopwatchTest.java b/guava-tests/test/com/google/common/base/StopwatchTest.java
index 4787343..bd6b2d2 100644
--- a/guava-tests/test/com/google/common/base/StopwatchTest.java
+++ b/guava-tests/test/com/google/common/base/StopwatchTest.java
@@ -233,6 +233,18 @@
     stopwatch.start();
     ticker.advance(5000000000L);
     assertEquals("5.000 s", stopwatch.toString());
+    stopwatch.reset();
+    stopwatch.start();
+    ticker.advance((long) (1.5 * 60 * 1000000000L));
+    assertEquals("1.500 min", stopwatch.toString());
+    stopwatch.reset();
+    stopwatch.start();
+    ticker.advance((long) (2.5 * 60 * 60 * 1000000000L));
+    assertEquals("2.500 h", stopwatch.toString());
+    stopwatch.reset();
+    stopwatch.start();
+    ticker.advance((long) (7.25 * 24 * 60 * 60 * 1000000000L));
+    assertEquals("7.250 d", stopwatch.toString());
   }
 
 }
diff --git a/guava-tests/test/com/google/common/base/Utf8Test.java b/guava-tests/test/com/google/common/base/Utf8Test.java
index e56a53a..f098123 100644
--- a/guava-tests/test/com/google/common/base/Utf8Test.java
+++ b/guava-tests/test/com/google/common/base/Utf8Test.java
@@ -21,7 +21,6 @@
 
 import junit.framework.TestCase;
 
-import java.io.UnsupportedEncodingException;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Random;
@@ -310,14 +309,9 @@
       }
       boolean isRoundTrippable = Utf8.isWellFormed(bytes);
       assertEquals(isRoundTrippable, Utf8.isWellFormed(bytes, 0, numBytes));
-      boolean bytesEqual;
-      try {
-        String s = new String(bytes, Charsets.UTF_8.name());
-        byte[] bytesReencoded = s.getBytes(Charsets.UTF_8.name());
-        bytesEqual = Arrays.equals(bytes, bytesReencoded);
-      } catch (UnsupportedEncodingException e) {
-        throw new AssertionError(e);
-      }
+      String s = new String(bytes, Charsets.UTF_8);
+      byte[] bytesReencoded = s.getBytes(Charsets.UTF_8);
+      boolean bytesEqual = Arrays.equals(bytes, bytesReencoded);
 
       if (bytesEqual != isRoundTrippable) {
         fail();
diff --git a/guava-tests/test/com/google/common/cache/AbstractCacheTest.java b/guava-tests/test/com/google/common/cache/AbstractCacheTest.java
index 6935133..b3bee1a 100644
--- a/guava-tests/test/com/google/common/cache/AbstractCacheTest.java
+++ b/guava-tests/test/com/google/common/cache/AbstractCacheTest.java
@@ -19,6 +19,7 @@
 import com.google.common.cache.AbstractCache.SimpleStatsCounter;
 import com.google.common.cache.AbstractCache.StatsCounter;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 
 import junit.framework.TestCase;
@@ -33,7 +34,7 @@
  */
 public class AbstractCacheTest extends TestCase {
 
-  public void testGetAllPresent() {
+  public void testGetIfPresent() {
     final AtomicReference<Object> valueRef = new AtomicReference<Object>();
     Cache<Object, Object> cache = new AbstractCache<Object, Object>() {
       @Override
@@ -49,6 +50,34 @@
     assertSame(newValue, cache.getIfPresent(new Object()));
   }
 
+  public void testGetAllPresent_empty() {
+    Cache<Object, Object> cache = new AbstractCache<Object, Object>() {
+      @Override
+      public Object getIfPresent(Object key) {
+        return null;
+      }
+    };
+
+    assertEquals(
+        ImmutableMap.of(),
+        cache.getAllPresent(ImmutableList.of(new Object())));
+  }
+
+  public void testGetAllPresent_cached() {
+    final Object cachedKey = new Object();
+    final Object cachedValue = new Object();
+    Cache<Object, Object> cache = new AbstractCache<Object, Object>() {
+      @Override
+      public Object getIfPresent(Object key) {
+        return cachedKey.equals(key) ? cachedValue : null;
+      }
+    };
+
+    assertEquals(
+        ImmutableMap.of(cachedKey, cachedValue),
+        cache.getAllPresent(ImmutableList.of(cachedKey, new Object())));
+  }
+
   public void testInvalidateAll() {
     final List<Object> invalidated = Lists.newArrayList();
     Cache<Integer, Integer> cache = new AbstractCache<Integer, Integer>() {
diff --git a/guava-tests/test/com/google/common/cache/CacheBuilderFactory.java b/guava-tests/test/com/google/common/cache/CacheBuilderFactory.java
index 865faf8..83ecf48 100644
--- a/guava-tests/test/com/google/common/cache/CacheBuilderFactory.java
+++ b/guava-tests/test/com/google/common/cache/CacheBuilderFactory.java
@@ -15,6 +15,7 @@
 package com.google.common.cache;
 
 import com.google.common.base.Function;
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
@@ -208,7 +209,7 @@
 
     @Override
     public String toString() {
-      return Objects.toStringHelper(this)
+      return MoreObjects.toStringHelper(this)
           .add("duration", duration)
           .add("unit", unit)
           .toString();
diff --git a/guava-tests/test/com/google/common/cache/CacheBuilderSpecTest.java b/guava-tests/test/com/google/common/cache/CacheBuilderSpecTest.java
index aae9a46..7dd5261 100644
--- a/guava-tests/test/com/google/common/cache/CacheBuilderSpecTest.java
+++ b/guava-tests/test/com/google/common/cache/CacheBuilderSpecTest.java
@@ -262,27 +262,27 @@
     assertNull(spec.concurrencyLevel);
     assertNull(spec.keyStrength);
     assertNull(spec.valueStrength);
-    assertEquals(TimeUnit.SECONDS, spec.writeExpirationTimeUnit);
-    assertEquals(24 * 60 * 60 * 10L, spec.writeExpirationDuration);
+    assertEquals(TimeUnit.DAYS, spec.writeExpirationTimeUnit);
+    assertEquals(10L, spec.writeExpirationDuration);
     assertNull(spec.accessExpirationTimeUnit);
     assertCacheBuilderEquivalence(
-        CacheBuilder.newBuilder().expireAfterWrite(24 * 60 * 60 * 10L, TimeUnit.SECONDS), CacheBuilder.from(spec));
+        CacheBuilder.newBuilder().expireAfterWrite(10L, TimeUnit.DAYS), CacheBuilder.from(spec));
   }
 
   public void testParse_writeExpirationHours() {
     CacheBuilderSpec spec = parse("expireAfterWrite=150h");
-    assertEquals(TimeUnit.SECONDS, spec.writeExpirationTimeUnit);
-    assertEquals(60 * 60 * 150L, spec.writeExpirationDuration);
+    assertEquals(TimeUnit.HOURS, spec.writeExpirationTimeUnit);
+    assertEquals(150L, spec.writeExpirationDuration);
     assertCacheBuilderEquivalence(
-        CacheBuilder.newBuilder().expireAfterWrite(60 * 60 * 150L, TimeUnit.SECONDS), CacheBuilder.from(spec));
+        CacheBuilder.newBuilder().expireAfterWrite(150L, TimeUnit.HOURS), CacheBuilder.from(spec));
   }
 
   public void testParse_writeExpirationMinutes() {
     CacheBuilderSpec spec = parse("expireAfterWrite=10m");
-    assertEquals(TimeUnit.SECONDS, spec.writeExpirationTimeUnit);
-    assertEquals(60 * 10L, spec.writeExpirationDuration);
+    assertEquals(TimeUnit.MINUTES, spec.writeExpirationTimeUnit);
+    assertEquals(10L, spec.writeExpirationDuration);
     assertCacheBuilderEquivalence(
-        CacheBuilder.newBuilder().expireAfterWrite(60 * 10L, TimeUnit.SECONDS), CacheBuilder.from(spec));
+        CacheBuilder.newBuilder().expireAfterWrite(10L, TimeUnit.MINUTES), CacheBuilder.from(spec));
   }
 
   public void testParse_writeExpirationSeconds() {
@@ -312,26 +312,26 @@
     assertNull(spec.keyStrength);
     assertNull(spec.valueStrength);
     assertNull(spec.writeExpirationTimeUnit);
-    assertEquals(TimeUnit.SECONDS, spec.accessExpirationTimeUnit);
-    assertEquals(24 * 60 * 60 * 10L, spec.accessExpirationDuration);
+    assertEquals(TimeUnit.DAYS, spec.accessExpirationTimeUnit);
+    assertEquals(10L, spec.accessExpirationDuration);
     assertCacheBuilderEquivalence(
-        CacheBuilder.newBuilder().expireAfterAccess(24 * 60 * 60 * 10L, TimeUnit.SECONDS), CacheBuilder.from(spec));
+        CacheBuilder.newBuilder().expireAfterAccess(10L, TimeUnit.DAYS), CacheBuilder.from(spec));
   }
 
   public void testParse_accessExpirationHours() {
     CacheBuilderSpec spec = parse("expireAfterAccess=150h");
-    assertEquals(TimeUnit.SECONDS, spec.accessExpirationTimeUnit);
-    assertEquals(60 * 60 * 150L, spec.accessExpirationDuration);
+    assertEquals(TimeUnit.HOURS, spec.accessExpirationTimeUnit);
+    assertEquals(150L, spec.accessExpirationDuration);
     assertCacheBuilderEquivalence(
-        CacheBuilder.newBuilder().expireAfterAccess(60 * 60 * 150L, TimeUnit.SECONDS), CacheBuilder.from(spec));
+        CacheBuilder.newBuilder().expireAfterAccess(150L, TimeUnit.HOURS), CacheBuilder.from(spec));
   }
 
   public void testParse_accessExpirationMinutes() {
     CacheBuilderSpec spec = parse("expireAfterAccess=10m");
-    assertEquals(TimeUnit.SECONDS, spec.accessExpirationTimeUnit);
-    assertEquals(60 * 10L, spec.accessExpirationDuration);
+    assertEquals(TimeUnit.MINUTES, spec.accessExpirationTimeUnit);
+    assertEquals(10L, spec.accessExpirationDuration);
     assertCacheBuilderEquivalence(
-        CacheBuilder.newBuilder().expireAfterAccess(60 * 10L, TimeUnit.SECONDS),
+        CacheBuilder.newBuilder().expireAfterAccess(10L, TimeUnit.MINUTES),
         CacheBuilder.from(spec));
   }
 
@@ -380,14 +380,14 @@
 
   public void testParse_accessExpirationAndWriteExpiration() {
     CacheBuilderSpec spec = parse("expireAfterAccess=10s,expireAfterWrite=9m");
-    assertEquals(TimeUnit.SECONDS, spec.writeExpirationTimeUnit);
-    assertEquals(60 * 9L, spec.writeExpirationDuration);
+    assertEquals(TimeUnit.MINUTES, spec.writeExpirationTimeUnit);
+    assertEquals(9L, spec.writeExpirationDuration);
     assertEquals(TimeUnit.SECONDS, spec.accessExpirationTimeUnit);
     assertEquals(10L, spec.accessExpirationDuration);
     assertCacheBuilderEquivalence(
         CacheBuilder.newBuilder()
           .expireAfterAccess(10L, TimeUnit.SECONDS)
-          .expireAfterWrite(60 * 9L, TimeUnit.SECONDS),
+          .expireAfterWrite(9L, TimeUnit.MINUTES),
         CacheBuilder.from(spec));
   }
 
@@ -400,18 +400,18 @@
     assertEquals(30, spec.concurrencyLevel.intValue());
     assertEquals(Strength.WEAK, spec.keyStrength);
     assertEquals(Strength.WEAK, spec.valueStrength);
-    assertEquals(TimeUnit.SECONDS, spec.writeExpirationTimeUnit);
-    assertEquals(TimeUnit.SECONDS, spec.accessExpirationTimeUnit);
-    assertEquals(60 * 60 * 1L, spec.writeExpirationDuration);
-    assertEquals(60 * 10L, spec.accessExpirationDuration);
+    assertEquals(TimeUnit.HOURS, spec.writeExpirationTimeUnit);
+    assertEquals(TimeUnit.MINUTES, spec.accessExpirationTimeUnit);
+    assertEquals(1L, spec.writeExpirationDuration);
+    assertEquals(10L, spec.accessExpirationDuration);
     CacheBuilder<?, ?> expected = CacheBuilder.newBuilder()
         .initialCapacity(10)
         .maximumSize(20)
         .concurrencyLevel(30)
         .weakKeys()
         .weakValues()
-        .expireAfterAccess(60 * 10L, TimeUnit.SECONDS)
-        .expireAfterWrite(60 * 60 * 1L, TimeUnit.SECONDS);
+        .expireAfterAccess(10L, TimeUnit.MINUTES)
+        .expireAfterWrite(1L, TimeUnit.HOURS);
     assertCacheBuilderEquivalence(expected, CacheBuilder.from(spec));
   }
 
@@ -540,7 +540,7 @@
         .concurrencyLevel(30)
         .weakKeys()
         .weakValues()
-        .expireAfterAccess(60 * 10L, TimeUnit.SECONDS);
+        .expireAfterAccess(10L, TimeUnit.MINUTES);
     assertCacheBuilderEquivalence(expected, fromString);
   }
 
diff --git a/guava-tests/test/com/google/common/cache/CacheEvictionTest.java b/guava-tests/test/com/google/common/cache/CacheEvictionTest.java
index 6746b7e..351af8b 100644
--- a/guava-tests/test/com/google/common/cache/CacheEvictionTest.java
+++ b/guava-tests/test/com/google/common/cache/CacheEvictionTest.java
@@ -18,8 +18,8 @@
 import static com.google.common.cache.TestingRemovalListeners.countingRemovalListener;
 import static com.google.common.cache.TestingWeighers.constantWeigher;
 import static com.google.common.cache.TestingWeighers.intKeyWeigher;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.cache.CacheTesting.Receiver;
 import com.google.common.cache.LocalCache.ReferenceEntry;
@@ -131,6 +131,21 @@
     CacheTesting.checkValidState(cache);
   }
 
+  public void testEviction_overflow() {
+    CountingRemovalListener<Object, Object> removalListener = countingRemovalListener();
+    IdentityLoader<Object> loader = identityLoader();
+    LoadingCache<Object, Object> cache = CacheBuilder.newBuilder()
+        .concurrencyLevel(1)
+        .maximumWeight(1L << 31)
+        .weigher(constantWeigher(Integer.MAX_VALUE))
+        .removalListener(removalListener)
+        .build(loader);
+    cache.getUnchecked(objectWithHash(0));
+    cache.getUnchecked(objectWithHash(0));
+    CacheTesting.processPendingNotifications(cache);
+    assertEquals(1, removalListener.getCount());
+  }
+
   public void testUpdateRecency_onGet() {
     IdentityLoader<Integer> loader = identityLoader();
     final LoadingCache<Integer, Integer> cache =
@@ -169,27 +184,27 @@
         .build(loader);
     CacheTesting.warmUp(cache, 0, 10);
     Set<Integer> keySet = cache.asMap().keySet();
-    ASSERT.that(keySet).has().exactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+    assertThat(keySet).has().exactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
 
     // re-order
     getAll(cache, asList(0, 1, 2));
     CacheTesting.drainRecencyQueues(cache);
-    ASSERT.that(keySet).has().exactly(3, 4, 5, 6, 7, 8, 9, 0, 1, 2);
+    assertThat(keySet).has().exactly(3, 4, 5, 6, 7, 8, 9, 0, 1, 2);
 
     // evict 3, 4, 5
     getAll(cache, asList(10, 11, 12));
     CacheTesting.drainRecencyQueues(cache);
-    ASSERT.that(keySet).has().exactly(6, 7, 8, 9, 0, 1, 2, 10, 11, 12);
+    assertThat(keySet).has().exactly(6, 7, 8, 9, 0, 1, 2, 10, 11, 12);
 
     // re-order
     getAll(cache, asList(6, 7, 8));
     CacheTesting.drainRecencyQueues(cache);
-    ASSERT.that(keySet).has().exactly(9, 0, 1, 2, 10, 11, 12, 6, 7, 8);
+    assertThat(keySet).has().exactly(9, 0, 1, 2, 10, 11, 12, 6, 7, 8);
 
     // evict 9, 0, 1
     getAll(cache, asList(13, 14, 15));
     CacheTesting.drainRecencyQueues(cache);
-    ASSERT.that(keySet).has().exactly(2, 10, 11, 12, 6, 7, 8, 13, 14, 15);
+    assertThat(keySet).has().exactly(2, 10, 11, 12, 6, 7, 8, 13, 14, 15);
   }
 
   public void testEviction_weightedLru() {
@@ -202,37 +217,37 @@
         .build(loader);
     CacheTesting.warmUp(cache, 0, 10);
     Set<Integer> keySet = cache.asMap().keySet();
-    ASSERT.that(keySet).has().exactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+    assertThat(keySet).has().exactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
 
     // re-order
     getAll(cache, asList(0, 1, 2));
     CacheTesting.drainRecencyQueues(cache);
-    ASSERT.that(keySet).has().exactly(3, 4, 5, 6, 7, 8, 9, 0, 1, 2);
+    assertThat(keySet).has().exactly(3, 4, 5, 6, 7, 8, 9, 0, 1, 2);
 
     // evict 3, 4, 5
     getAll(cache, asList(10));
     CacheTesting.drainRecencyQueues(cache);
-    ASSERT.that(keySet).has().exactly(6, 7, 8, 9, 0, 1, 2, 10);
+    assertThat(keySet).has().exactly(6, 7, 8, 9, 0, 1, 2, 10);
 
     // re-order
     getAll(cache, asList(6, 7, 8));
     CacheTesting.drainRecencyQueues(cache);
-    ASSERT.that(keySet).has().exactly(9, 0, 1, 2, 10, 6, 7, 8);
+    assertThat(keySet).has().exactly(9, 0, 1, 2, 10, 6, 7, 8);
 
     // evict 9, 1, 2, 10
     getAll(cache, asList(15));
     CacheTesting.drainRecencyQueues(cache);
-    ASSERT.that(keySet).has().exactly(0, 6, 7, 8, 15);
+    assertThat(keySet).has().exactly(0, 6, 7, 8, 15);
 
     // fill empty space
     getAll(cache, asList(9));
     CacheTesting.drainRecencyQueues(cache);
-    ASSERT.that(keySet).has().exactly(0, 6, 7, 8, 15, 9);
+    assertThat(keySet).has().exactly(0, 6, 7, 8, 15, 9);
 
     // evict 6
     getAll(cache, asList(1));
     CacheTesting.drainRecencyQueues(cache);
-    ASSERT.that(keySet).has().exactly(0, 7, 8, 15, 9, 1);
+    assertThat(keySet).has().exactly(0, 7, 8, 15, 9, 1);
   }
 
   public void testEviction_overweight() {
@@ -245,17 +260,17 @@
         .build(loader);
     CacheTesting.warmUp(cache, 0, 10);
     Set<Integer> keySet = cache.asMap().keySet();
-    ASSERT.that(keySet).has().exactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+    assertThat(keySet).has().exactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
 
     // add an at-the-maximum-weight entry
     getAll(cache, asList(45));
     CacheTesting.drainRecencyQueues(cache);
-    ASSERT.that(keySet).has().exactly(0, 45);
+    assertThat(keySet).has().exactly(0, 45);
 
     // add an over-the-maximum-weight entry
     getAll(cache, asList(46));
     CacheTesting.drainRecencyQueues(cache);
-    ASSERT.that(keySet).has().item(0);
+    assertThat(keySet).has().item(0);
   }
 
   public void testEviction_invalidateAll() {
@@ -267,22 +282,22 @@
         .build(loader);
 
     Set<Integer> keySet = cache.asMap().keySet();
-    ASSERT.that(keySet).isEmpty();
+    assertThat(keySet).isEmpty();
 
     // add 0, 1, 2, 3, 4
     getAll(cache, asList(0, 1, 2, 3, 4));
     CacheTesting.drainRecencyQueues(cache);
-    ASSERT.that(keySet).has().exactly(0, 1, 2, 3, 4);
+    assertThat(keySet).has().exactly(0, 1, 2, 3, 4);
 
     // invalidate all
     cache.invalidateAll();
     CacheTesting.drainRecencyQueues(cache);
-    ASSERT.that(keySet).isEmpty();
+    assertThat(keySet).isEmpty();
 
     // add 5, 6, 7, 8, 9, 10, 11, 12
     getAll(cache, asList(5, 6, 7, 8, 9, 10, 11, 12));
     CacheTesting.drainRecencyQueues(cache);
-    ASSERT.that(keySet).has().exactly(5, 6, 7, 8, 9, 10, 11, 12);
+    assertThat(keySet).has().exactly(5, 6, 7, 8, 9, 10, 11, 12);
   }
 
   private void getAll(LoadingCache<Integer, Integer> cache, List<Integer> keys) {
@@ -290,4 +305,12 @@
       cache.getUnchecked(i);
     }
   }
+
+  private Object objectWithHash(final int hash) {
+    return new Object() {
+      @Override public int hashCode() {
+        return hash;
+      }
+    };
+  }
 }
diff --git a/guava-tests/test/com/google/common/cache/CacheExpirationTest.java b/guava-tests/test/com/google/common/cache/CacheExpirationTest.java
index d39374d..b5c8266 100644
--- a/guava-tests/test/com/google/common/cache/CacheExpirationTest.java
+++ b/guava-tests/test/com/google/common/cache/CacheExpirationTest.java
@@ -16,9 +16,9 @@
 
 import static com.google.common.cache.TestingCacheLoaders.identityLoader;
 import static com.google.common.cache.TestingRemovalListeners.countingRemovalListener;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.cache.TestingCacheLoaders.IdentityLoader;
 import com.google.common.cache.TestingRemovalListeners.CountingRemovalListener;
@@ -260,42 +260,42 @@
       ticker.advance(1, MILLISECONDS);
     }
     Set<Integer> keySet = cache.asMap().keySet();
-    ASSERT.that(keySet).has().exactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+    assertThat(keySet).has().exactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
 
     // 0 expires
     ticker.advance(1, MILLISECONDS);
-    ASSERT.that(keySet).has().exactly(1, 2, 3, 4, 5, 6, 7, 8, 9);
+    assertThat(keySet).has().exactly(1, 2, 3, 4, 5, 6, 7, 8, 9);
 
     // reorder
     getAll(cache, asList(0, 1, 2));
     CacheTesting.drainRecencyQueues(cache);
     ticker.advance(2, MILLISECONDS);
-    ASSERT.that(keySet).has().exactly(3, 4, 5, 6, 7, 8, 9, 0, 1, 2);
+    assertThat(keySet).has().exactly(3, 4, 5, 6, 7, 8, 9, 0, 1, 2);
 
     // 3 expires
     ticker.advance(1, MILLISECONDS);
-    ASSERT.that(keySet).has().exactly(4, 5, 6, 7, 8, 9, 0, 1, 2);
+    assertThat(keySet).has().exactly(4, 5, 6, 7, 8, 9, 0, 1, 2);
 
     // reorder
     getAll(cache, asList(5, 7, 9));
     CacheTesting.drainRecencyQueues(cache);
-    ASSERT.that(keySet).has().exactly(4, 6, 8, 0, 1, 2, 5, 7, 9);
+    assertThat(keySet).has().exactly(4, 6, 8, 0, 1, 2, 5, 7, 9);
 
     // 4 expires
     ticker.advance(1, MILLISECONDS);
-    ASSERT.that(keySet).has().exactly(6, 8, 0, 1, 2, 5, 7, 9);
+    assertThat(keySet).has().exactly(6, 8, 0, 1, 2, 5, 7, 9);
     ticker.advance(1, MILLISECONDS);
-    ASSERT.that(keySet).has().exactly(6, 8, 0, 1, 2, 5, 7, 9);
+    assertThat(keySet).has().exactly(6, 8, 0, 1, 2, 5, 7, 9);
 
     // 6 expires
     ticker.advance(1, MILLISECONDS);
-    ASSERT.that(keySet).has().exactly(8, 0, 1, 2, 5, 7, 9);
+    assertThat(keySet).has().exactly(8, 0, 1, 2, 5, 7, 9);
     ticker.advance(1, MILLISECONDS);
-    ASSERT.that(keySet).has().exactly(8, 0, 1, 2, 5, 7, 9);
+    assertThat(keySet).has().exactly(8, 0, 1, 2, 5, 7, 9);
 
     // 8 expires
     ticker.advance(1, MILLISECONDS);
-    ASSERT.that(keySet).has().exactly(0, 1, 2, 5, 7, 9);
+    assertThat(keySet).has().exactly(0, 1, 2, 5, 7, 9);
   }
 
   public void testExpirationOrder_write() throws ExecutionException {
@@ -312,37 +312,37 @@
       ticker.advance(1, MILLISECONDS);
     }
     Set<Integer> keySet = cache.asMap().keySet();
-    ASSERT.that(keySet).has().exactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+    assertThat(keySet).has().exactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
 
     // 0 expires
     ticker.advance(1, MILLISECONDS);
-    ASSERT.that(keySet).has().exactly(1, 2, 3, 4, 5, 6, 7, 8, 9);
+    assertThat(keySet).has().exactly(1, 2, 3, 4, 5, 6, 7, 8, 9);
 
     // get doesn't stop 1 from expiring
     getAll(cache, asList(0, 1, 2));
     CacheTesting.drainRecencyQueues(cache);
     ticker.advance(1, MILLISECONDS);
-    ASSERT.that(keySet).has().exactly(2, 3, 4, 5, 6, 7, 8, 9, 0);
+    assertThat(keySet).has().exactly(2, 3, 4, 5, 6, 7, 8, 9, 0);
 
     // get(K, Callable) doesn't stop 2 from expiring
     cache.get(2, Callables.returning(-2));
     CacheTesting.drainRecencyQueues(cache);
     ticker.advance(1, MILLISECONDS);
-    ASSERT.that(keySet).has().exactly(3, 4, 5, 6, 7, 8, 9, 0);
+    assertThat(keySet).has().exactly(3, 4, 5, 6, 7, 8, 9, 0);
 
     // asMap.put saves 3
     cache.asMap().put(3, -3);
     ticker.advance(1, MILLISECONDS);
-    ASSERT.that(keySet).has().exactly(4, 5, 6, 7, 8, 9, 0, 3);
+    assertThat(keySet).has().exactly(4, 5, 6, 7, 8, 9, 0, 3);
 
     // asMap.replace saves 4
     cache.asMap().replace(4, -4);
     ticker.advance(1, MILLISECONDS);
-    ASSERT.that(keySet).has().exactly(5, 6, 7, 8, 9, 0, 3, 4);
+    assertThat(keySet).has().exactly(5, 6, 7, 8, 9, 0, 3, 4);
 
     // 5 expires
     ticker.advance(1, MILLISECONDS);
-    ASSERT.that(keySet).has().exactly(6, 7, 8, 9, 0, 3, 4);
+    assertThat(keySet).has().exactly(6, 7, 8, 9, 0, 3, 4);
   }
 
   public void testExpirationOrder_writeAccess() throws ExecutionException {
@@ -365,33 +365,33 @@
     ticker.advance(1, MILLISECONDS);
 
     Set<Integer> keySet = cache.asMap().keySet();
-    ASSERT.that(keySet).has().exactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+    assertThat(keySet).has().exactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
 
     // get saves 1, 3; 0, 2, 4 expire
     getAll(cache, asList(1, 3));
     CacheTesting.drainRecencyQueues(cache);
     ticker.advance(1, MILLISECONDS);
-    ASSERT.that(keySet).has().exactly(5, 6, 7, 8, 9, 1, 3);
+    assertThat(keySet).has().exactly(5, 6, 7, 8, 9, 1, 3);
 
     // get saves 6, 8; 5, 7, 9 expire
     getAll(cache, asList(6, 8));
     CacheTesting.drainRecencyQueues(cache);
     ticker.advance(1, MILLISECONDS);
-    ASSERT.that(keySet).has().exactly(1, 3, 6, 8);
+    assertThat(keySet).has().exactly(1, 3, 6, 8);
 
     // get fails to save 1, put saves 3
     cache.asMap().put(3, -3);
     getAll(cache, asList(1));
     CacheTesting.drainRecencyQueues(cache);
     ticker.advance(1, MILLISECONDS);
-    ASSERT.that(keySet).has().exactly(6, 8, 3);
+    assertThat(keySet).has().exactly(6, 8, 3);
 
     // get(K, Callable) fails to save 8, replace saves 6
     cache.asMap().replace(6, -6);
     cache.get(8, Callables.returning(-8));
     CacheTesting.drainRecencyQueues(cache);
     ticker.advance(1, MILLISECONDS);
-    ASSERT.that(keySet).has().exactly(3, 6);
+    assertThat(keySet).has().exactly(3, 6);
   }
 
   private void runRemovalScheduler(LoadingCache<String, Integer> cache,
diff --git a/guava-tests/test/com/google/common/cache/CacheLoadingTest.java b/guava-tests/test/com/google/common/cache/CacheLoadingTest.java
index 7d984d7..a08114d 100644
--- a/guava-tests/test/com/google/common/cache/CacheLoadingTest.java
+++ b/guava-tests/test/com/google/common/cache/CacheLoadingTest.java
@@ -20,10 +20,10 @@
 import static com.google.common.cache.TestingCacheLoaders.exceptionLoader;
 import static com.google.common.cache.TestingCacheLoaders.identityLoader;
 import static com.google.common.cache.TestingRemovalListeners.countingRemovalListener;
+import static com.google.common.truth.Truth.assertThat;
 import static java.lang.Thread.currentThread;
 import static java.util.Arrays.asList;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.cache.CacheLoader.InvalidCacheLoadException;
 import com.google.common.cache.TestingCacheLoaders.CountingLoader;
@@ -440,7 +440,7 @@
 
     Object[] lookupKeys = new Object[] { new Object(), new Object(), new Object() };
     Map<Object, Object> result = cache.getAll(asList(lookupKeys));
-    ASSERT.that(result.keySet()).has().exactlyAs(asList(lookupKeys));
+    assertThat(result.keySet()).has().exactlyAs(asList(lookupKeys));
     for (Map.Entry<Object, Object> entry : result.entrySet()) {
       Object key = entry.getKey();
       Object value = entry.getValue();
@@ -477,7 +477,7 @@
 
     Object[] lookupKeys = new Object[] { new Object(), new Object(), new Object() };
     Map<Object, Object> result = cache.getAll(asList(lookupKeys));
-    ASSERT.that(result.keySet()).has().exactlyAs(asList(lookupKeys));
+    assertThat(result.keySet()).has().exactlyAs(asList(lookupKeys));
     for (Map.Entry<Object, Object> entry : result.entrySet()) {
       Object key = entry.getKey();
       Object value = entry.getValue();
diff --git a/guava-tests/test/com/google/common/cache/CacheReferencesTest.java b/guava-tests/test/com/google/common/cache/CacheReferencesTest.java
index 8c7850c..88d6b23 100644
--- a/guava-tests/test/com/google/common/cache/CacheReferencesTest.java
+++ b/guava-tests/test/com/google/common/cache/CacheReferencesTest.java
@@ -16,7 +16,7 @@
 
 import static com.google.common.cache.LocalCache.Strength.STRONG;
 import static com.google.common.collect.Maps.immutableEntry;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.base.Function;
 import com.google.common.cache.LocalCache.Strength;
@@ -94,7 +94,7 @@
       assertSame(value1, cache.getUnchecked(key1));
       assertSame(value2, cache.getUnchecked(key2));
       assertEquals(ImmutableSet.of(key1, key2), cache.asMap().keySet());
-      ASSERT.that(cache.asMap().values()).has().exactly(value1, value2);
+      assertThat(cache.asMap().values()).has().exactly(value1, value2);
       assertEquals(ImmutableSet.of(immutableEntry(key1, value1), immutableEntry(key2, value2)),
           cache.asMap().entrySet());
     }
@@ -113,7 +113,7 @@
       assertTrue(cache.asMap().containsKey(key2));
       assertEquals(1, cache.size());
       assertEquals(ImmutableSet.of(key2), cache.asMap().keySet());
-      ASSERT.that(cache.asMap().values()).has().item(value2);
+      assertThat(cache.asMap().values()).has().item(value2);
       assertEquals(ImmutableSet.of(immutableEntry(key2, value2)), cache.asMap().entrySet());
     }
   }
diff --git a/guava-tests/test/com/google/common/cache/EmptyCachesTest.java b/guava-tests/test/com/google/common/cache/EmptyCachesTest.java
index 9051861..994f236 100644
--- a/guava-tests/test/com/google/common/cache/EmptyCachesTest.java
+++ b/guava-tests/test/com/google/common/cache/EmptyCachesTest.java
@@ -17,6 +17,7 @@
 import static com.google.common.cache.CacheTesting.checkEmpty;
 import static com.google.common.cache.TestingCacheLoaders.identityLoader;
 import static java.util.Arrays.asList;
+import static java.util.concurrent.TimeUnit.DAYS;
 import static java.util.concurrent.TimeUnit.SECONDS;
 
 import com.google.common.base.Function;
@@ -368,14 +369,14 @@
         .withExpireAfterWrites(ImmutableSet.of(
             DurationSpec.of(0, SECONDS),
             DurationSpec.of(1, SECONDS),
-            DurationSpec.of(24 * 60 * 60 * 1, SECONDS)))
+            DurationSpec.of(1, DAYS)))
         .withExpireAfterAccesses(ImmutableSet.of(
             DurationSpec.of(0, SECONDS),
             DurationSpec.of(1, SECONDS),
-            DurationSpec.of(24 * 60 * 60 * 1, SECONDS)))
+            DurationSpec.of(1, DAYS)))
         .withRefreshes(ImmutableSet.of(
             DurationSpec.of(1, SECONDS),
-            DurationSpec.of(24 * 60 * 60 * 1, SECONDS)));
+            DurationSpec.of(1, DAYS)));
   }
 
   private void warmUp(LoadingCache<Object, Object> cache, int minimum, int maximum) {
diff --git a/guava-tests/test/com/google/common/cache/LocalCacheTest.java b/guava-tests/test/com/google/common/cache/LocalCacheTest.java
index 9801f12..7e1d614 100644
--- a/guava-tests/test/com/google/common/cache/LocalCacheTest.java
+++ b/guava-tests/test/com/google/common/cache/LocalCacheTest.java
@@ -27,6 +27,7 @@
 import static com.google.common.cache.TestingWeighers.constantWeigher;
 import static com.google.common.collect.Lists.newArrayList;
 import static com.google.common.collect.Maps.immutableEntry;
+import static java.util.concurrent.TimeUnit.MINUTES;
 import static java.util.concurrent.TimeUnit.NANOSECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
 
@@ -2395,7 +2396,7 @@
         .weakKeys()
         .softValues()
         .expireAfterAccess(123, SECONDS)
-        .expireAfterWrite(60 * 456, SECONDS) // 456 minutes
+        .expireAfterWrite(456, MINUTES)
         .maximumWeight(789)
         .weigher(weigher)
         .concurrencyLevel(12)
diff --git a/guava-tests/test/com/google/common/cache/LocalLoadingCacheTest.java b/guava-tests/test/com/google/common/cache/LocalLoadingCacheTest.java
index f4684fc..5ae1b45 100644
--- a/guava-tests/test/com/google/common/cache/LocalLoadingCacheTest.java
+++ b/guava-tests/test/com/google/common/cache/LocalLoadingCacheTest.java
@@ -19,7 +19,7 @@
 import static com.google.common.cache.CacheBuilder.EMPTY_STATS;
 import static com.google.common.cache.LocalCacheTest.SMALL_MAX_SIZE;
 import static com.google.common.cache.TestingCacheLoaders.identityLoader;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.cache.LocalCache.LocalLoadingCache;
 import com.google.common.cache.LocalCache.Segment;
@@ -160,17 +160,17 @@
     assertNull(map.put(three, one));
     assertNull(map.put(one, two));
 
-    ASSERT.that(map).hasKey(three).withValue(one);
-    ASSERT.that(map).hasKey(one).withValue(two);
+    assertThat(map).hasKey(three).withValue(one);
+    assertThat(map).hasKey(one).withValue(two);
 
     //TODO(user): Confirm with fry@ that this is a reasonable substitute.
     //Set<Map.Entry<Object, Object>> entries = map.entrySet();
-    //ASSERT.that(entries).has().exactly(
+    //assertThat(entries).has().exactly(
     //    Maps.immutableEntry(three, one), Maps.immutableEntry(one, two));
     //Set<Object> keys = map.keySet();
-    //ASSERT.that(keys).has().exactly(one, three);
+    //assertThat(keys).has().exactly(one, three);
     //Collection<Object> values = map.values();
-    //ASSERT.that(values).has().exactly(one, two);
+    //assertThat(values).has().exactly(one, two);
 
     map.clear();
 
diff --git a/guava-tests/test/com/google/common/cache/LongAdderTest.java b/guava-tests/test/com/google/common/cache/LongAdderTest.java
new file mode 100644
index 0000000..78f6edc
--- /dev/null
+++ b/guava-tests/test/com/google/common/cache/LongAdderTest.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2014 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.common.cache;
+
+/**
+ * No-op null-pointer test for {@link LongAdder} to override the {@link PackageSanityTests} version,
+ * which checks package-private methods that we don't want to have to annotate as {@code Nullable}
+ * because we don't want diffs from jsr166e.
+ */
+public class LongAdderTest {
+  public void testNulls() {}
+}
diff --git a/guava-tests/test/com/google/common/cache/PopulatedCachesTest.java b/guava-tests/test/com/google/common/cache/PopulatedCachesTest.java
index 6d50030..d7fee82 100644
--- a/guava-tests/test/com/google/common/cache/PopulatedCachesTest.java
+++ b/guava-tests/test/com/google/common/cache/PopulatedCachesTest.java
@@ -17,8 +17,9 @@
 import static com.google.common.cache.CacheTesting.checkEmpty;
 import static com.google.common.cache.CacheTesting.checkValidState;
 import static com.google.common.cache.TestingCacheLoaders.identityLoader;
+import static com.google.common.truth.Truth.assertThat;
+import static java.util.concurrent.TimeUnit.DAYS;
 import static java.util.concurrent.TimeUnit.SECONDS;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.base.Function;
 import com.google.common.cache.CacheBuilderFactory.DurationSpec;
@@ -33,8 +34,6 @@
 
 import junit.framework.TestCase;
 
-import junit.framework.TestCase;
-
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -196,9 +195,9 @@
       List<Entry<Object, Object>> warmed = warmUp(cache);
 
       Set<Object> expected = Maps.newHashMap(cache.asMap()).keySet();
-      ASSERT.that(keys).has().exactlyAs(expected);
-      ASSERT.that(keys.toArray()).has().exactlyAs(expected);
-      ASSERT.that(keys.toArray(new Object[0])).has().exactlyAs(expected);
+      assertThat(keys).has().exactlyAs(expected);
+      assertThat(keys.toArray()).asList().has().exactlyAs(expected);
+      assertThat(keys.toArray(new Object[0])).asList().has().exactlyAs(expected);
 
       new EqualsTester()
           .addEqualityGroup(cache.asMap().keySet(), keys)
@@ -223,9 +222,9 @@
       List<Entry<Object, Object>> warmed = warmUp(cache);
 
       Collection<Object> expected = Maps.newHashMap(cache.asMap()).values();
-      ASSERT.that(values).has().exactlyAs(expected);
-      ASSERT.that(values.toArray()).has().exactlyAs(expected);
-      ASSERT.that(values.toArray(new Object[0])).has().exactlyAs(expected);
+      assertThat(values).has().exactlyAs(expected);
+      assertThat(values.toArray()).asList().has().exactlyAs(expected);
+      assertThat(values.toArray(new Object[0])).asList().has().exactlyAs(expected);
 
       assertEquals(WARMUP_SIZE, values.size());
       for (int i = WARMUP_MIN; i < WARMUP_MAX; i++) {
@@ -248,9 +247,10 @@
       List<Entry<Object, Object>> warmed = warmUp(cache, WARMUP_MIN, WARMUP_MAX);
 
       Set<?> expected = Maps.newHashMap(cache.asMap()).entrySet();
-      ASSERT.that(entries).has().exactlyAs((Collection<Entry<Object, Object>>) expected);
-      ASSERT.that(entries.toArray()).has().exactlyAs((Collection<Object>) expected);
-      ASSERT.that(entries.toArray(new Entry[0])).has().exactlyAs((Collection<Entry>) expected);
+      assertThat(entries).has().exactlyAs((Collection<Entry<Object, Object>>) expected);
+      assertThat(entries.toArray()).asList().has().exactlyAs((Collection<Object>) expected);
+      assertThat(entries.toArray(new Entry[0])).asList()
+          .has().exactlyAs((Collection<Entry>) expected);
 
       new EqualsTester()
           .addEqualityGroup(cache.asMap().entrySet(), entries)
@@ -320,15 +320,15 @@
         .withExpireAfterWrites(ImmutableSet.of(
             // DurationSpec.of(500, MILLISECONDS),
             DurationSpec.of(1, SECONDS),
-            DurationSpec.of(24 * 60 * 60 * 1, SECONDS)))
+            DurationSpec.of(1, DAYS)))
         .withExpireAfterAccesses(ImmutableSet.of(
             // DurationSpec.of(500, MILLISECONDS),
             DurationSpec.of(1, SECONDS),
-            DurationSpec.of(24 * 60 * 60 * 1, SECONDS)))
+            DurationSpec.of(1, DAYS)))
         .withRefreshes(ImmutableSet.of(
             // DurationSpec.of(500, MILLISECONDS),
             DurationSpec.of(1, SECONDS),
-            DurationSpec.of(24 * 60 * 60 * 1, SECONDS)));
+            DurationSpec.of(1, DAYS)));
   }
 
   private List<Map.Entry<Object, Object>> warmUp(LoadingCache<Object, Object> cache) {
diff --git a/guava-tests/test/com/google/common/collect/AbstractImmutableSetTest.java b/guava-tests/test/com/google/common/collect/AbstractImmutableSetTest.java
index 16d5fd8..ea309f4 100644
--- a/guava-tests/test/com/google/common/collect/AbstractImmutableSetTest.java
+++ b/guava-tests/test/com/google/common/collect/AbstractImmutableSetTest.java
@@ -17,8 +17,8 @@
 package com.google.common.collect;
 
 import static com.google.common.collect.testing.IteratorFeature.UNMODIFIABLE;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -295,7 +295,7 @@
         .add("d", "e", "f")
         .add("g", "h", "i", "j")
         .build();
-    ASSERT.that(set).has().exactly(
+    assertThat(set).has().exactly(
         "a", "b", "c", "d", "e", "f", "g", "h", "i", "j").inOrder();
   }
 
@@ -303,9 +303,9 @@
     ImmutableSet.Builder<String> builder = this.<String>builder()
         .add("a")
         .add("b");
-    ASSERT.that(builder.build()).has().exactly("a", "b").inOrder();
+    assertThat(builder.build()).has().exactly("a", "b").inOrder();
     builder.add("c", "d");
-    ASSERT.that(builder.build()).has().exactly("a", "b", "c", "d").inOrder();
+    assertThat(builder.build()).has().exactly("a", "b", "c", "d").inOrder();
   }
 
   public void testBuilderWithDuplicateElements() {
@@ -325,9 +325,9 @@
         .add("a")
         .add("a", "a")
         .add("b");
-    ASSERT.that(builder.build()).has().exactly("a", "b").inOrder();
+    assertThat(builder.build()).has().exactly("a", "b").inOrder();
     builder.add("a", "b", "c", "c");
-    ASSERT.that(builder.build()).has().exactly("a", "b", "c").inOrder();
+    assertThat(builder.build()).has().exactly("a", "b", "c").inOrder();
   }
 
   public void testBuilderAddAll() {
@@ -337,7 +337,7 @@
         .addAll(a)
         .addAll(b)
         .build();
-    ASSERT.that(set).has().exactly("a", "b", "c", "d", "e").inOrder();
+    assertThat(set).has().exactly("a", "b", "c", "d", "e").inOrder();
   }
 
   static final int LAST_COLOR_ADDED = 0x00BFFF;
diff --git a/guava-tests/test/com/google/common/collect/AbstractRangeSetTest.java b/guava-tests/test/com/google/common/collect/AbstractRangeSetTest.java
new file mode 100644
index 0000000..1a44e87
--- /dev/null
+++ b/guava-tests/test/com/google/common/collect/AbstractRangeSetTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import com.google.common.annotations.GwtIncompatible;
+
+import junit.framework.TestCase;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * Base class for {@link RangeSet} tests.
+ *
+ * @author Louis Wasserman
+ */
+@GwtIncompatible("TreeRangeSet")
+public abstract class AbstractRangeSetTest extends TestCase {
+  public static void testInvariants(RangeSet<?> rangeSet) {
+    testInvariantsInternal(rangeSet);
+    testInvariantsInternal(rangeSet.complement());
+  }
+
+  private static <C extends Comparable> void testInvariantsInternal(RangeSet<C> rangeSet) {
+    assertEquals(rangeSet.asRanges().isEmpty(), rangeSet.isEmpty());
+    assertEquals(!rangeSet.asRanges().iterator().hasNext(), rangeSet.isEmpty());
+
+    List<Range<C>> asRanges = ImmutableList.copyOf(rangeSet.asRanges());
+
+    // test that connected ranges are coalesced
+    for (int i = 0; i + 1 < asRanges.size(); i++) {
+      Range<C> range1 = asRanges.get(i);
+      Range<C> range2 = asRanges.get(i + 1);
+      assertFalse(range1.isConnected(range2));
+    }
+
+    // test that there are no empty ranges
+    for (Range<C> range : asRanges) {
+      assertFalse(range.isEmpty());
+    }
+
+    Iterator<Range<C>> itr = rangeSet.asRanges().iterator();
+    Range<C> expectedSpan = null;
+    if (itr.hasNext()) {
+      expectedSpan = itr.next();
+      while (itr.hasNext()) {
+        expectedSpan = expectedSpan.span(itr.next());
+      }
+    }
+
+    try {
+      Range<C> span = rangeSet.span();
+      assertEquals(expectedSpan, span);
+    } catch (NoSuchElementException e) {
+      assertNull(expectedSpan);
+    }
+  }
+}
diff --git a/guava-tests/test/com/google/common/collect/AbstractSequentialIteratorTest.java b/guava-tests/test/com/google/common/collect/AbstractSequentialIteratorTest.java
index 803ea5a..83b3900 100644
--- a/guava-tests/test/com/google/common/collect/AbstractSequentialIteratorTest.java
+++ b/guava-tests/test/com/google/common/collect/AbstractSequentialIteratorTest.java
@@ -17,7 +17,7 @@
 package com.google.common.collect;
 
 import static com.google.common.collect.testing.IteratorFeature.UNMODIFIABLE;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -50,7 +50,7 @@
         return newDoubler(2, 32);
       }
     };
-    ASSERT.that(doubled).iteratesOverSequence(2, 4, 8, 16, 32);
+    assertThat(doubled).iteratesAs(2, 4, 8, 16, 32);
   }
 
   public void testSampleCode() {
@@ -65,7 +65,7 @@
         return powersOfTwo;
       }
     };
-    ASSERT.that(actual).iteratesOverSequence(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
+    assertThat(actual).iteratesAs(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
         4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304,
         8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824);
   }
diff --git a/guava-tests/test/com/google/common/collect/AbstractTableReadTest.java b/guava-tests/test/com/google/common/collect/AbstractTableReadTest.java
index 1265e31..45a08c5 100644
--- a/guava-tests/test/com/google/common/collect/AbstractTableReadTest.java
+++ b/guava-tests/test/com/google/common/collect/AbstractTableReadTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -183,7 +183,7 @@
   public void testColumnSetPartialOverlap() {
     table = create(
         "foo", 1, 'a', "bar", 1, 'b', "foo", 2, 'c', "bar", 3, 'd');
-    ASSERT.that(table.columnKeySet()).has().exactly(1, 2, 3);
+    assertThat(table.columnKeySet()).has().exactly(1, 2, 3);
   }
 
   @GwtIncompatible("NullPointerTester")
diff --git a/guava-tests/test/com/google/common/collect/ArrayListMultimapTest.java b/guava-tests/test/com/google/common/collect/ArrayListMultimapTest.java
index 676e175..6a567d8 100644
--- a/guava-tests/test/com/google/common/collect/ArrayListMultimapTest.java
+++ b/guava-tests/test/com/google/common/collect/ArrayListMultimapTest.java
@@ -16,8 +16,8 @@
 
 package com.google.common.collect;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -119,9 +119,9 @@
     ListMultimap<String, Integer> multimap = create();
     multimap.putAll("foo", asList(1, 2, 3, 4, 5));
     List<Integer> list = multimap.get("foo");
-    ASSERT.that(multimap.get("foo")).has().exactly(1, 2, 3, 4, 5).inOrder();
+    assertThat(multimap.get("foo")).has().exactly(1, 2, 3, 4, 5).inOrder();
     List<Integer> sublist = list.subList(0, 5);
-    ASSERT.that(sublist).has().exactly(1, 2, 3, 4, 5).inOrder();
+    assertThat(sublist).has().exactly(1, 2, 3, 4, 5).inOrder();
 
     sublist.clear();
     assertTrue(sublist.isEmpty());
@@ -190,7 +190,7 @@
     multimap.put("bar", 3);
     multimap.trimToSize();
     assertEquals(3, multimap.size());
-    ASSERT.that(multimap.get("foo")).has().exactly(1, 2).inOrder();
-    ASSERT.that(multimap.get("bar")).has().item(3);
+    assertThat(multimap.get("foo")).has().exactly(1, 2).inOrder();
+    assertThat(multimap.get("bar")).has().item(3);
   }
 }
diff --git a/guava-tests/test/com/google/common/collect/ArrayTableTest.java b/guava-tests/test/com/google/common/collect/ArrayTableTest.java
index 29100ce..c535619 100644
--- a/guava-tests/test/com/google/common/collect/ArrayTableTest.java
+++ b/guava-tests/test/com/google/common/collect/ArrayTableTest.java
@@ -16,8 +16,8 @@
 
 package com.google.common.collect;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -286,13 +286,13 @@
   public void testRowKeyList() {
     ArrayTable<String, Integer, Character> table
         = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
-    ASSERT.that(table.rowKeyList()).has().exactly("foo", "bar", "cat").inOrder();
+    assertThat(table.rowKeyList()).has().exactly("foo", "bar", "cat").inOrder();
   }
 
   public void testColumnKeyList() {
     ArrayTable<String, Integer, Character> table
         = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
-    ASSERT.that(table.columnKeyList()).has().exactly(1, 2, 3).inOrder();
+    assertThat(table.columnKeyList()).has().exactly(1, 2, 3).inOrder();
   }
 
   public void testGetMissingKeys() {
@@ -400,9 +400,9 @@
         = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
     Character[][] array = table.toArray(Character.class);
     assertEquals(3, array.length);
-    ASSERT.that(array[0]).has().exactly('a', null, 'c').inOrder();
-    ASSERT.that(array[1]).has().exactly('b', null, null).inOrder();
-    ASSERT.that(array[2]).has().exactly(null, null, null).inOrder();
+    assertThat(array[0]).asList().has().exactly('a', null, 'c').inOrder();
+    assertThat(array[1]).asList().has().exactly('b', null, null).inOrder();
+    assertThat(array[2]).asList().has().exactly(null, null, null).inOrder();
     table.set(0, 2, 'd');
     assertEquals((Character) 'c', array[0][2]);
     array[0][2] = 'e';
diff --git a/guava-tests/test/com/google/common/collect/BenchmarkHelpers.java b/guava-tests/test/com/google/common/collect/BenchmarkHelpers.java
index f7fc520..4997e69 100644
--- a/guava-tests/test/com/google/common/collect/BenchmarkHelpers.java
+++ b/guava-tests/test/com/google/common/collect/BenchmarkHelpers.java
@@ -26,6 +26,7 @@
 import java.util.SortedMap;
 import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListMap;
 
 /**
  * Helper classes for various benchmarks.
@@ -172,6 +173,12 @@
         return result;
       }
     },
+    ConcurrentSkipList {
+      @Override
+      <K extends Comparable<K>, V> SortedMap<K, V> create(Map<K, V> map) {
+        return new ConcurrentSkipListMap<K, V>(map);
+      }
+    },
     ImmutableSorted {
       @Override
       <K extends Comparable<K>, V> SortedMap<K, V> create(Map<K, V> map) {
diff --git a/guava-tests/test/com/google/common/collect/Collections2Test.java b/guava-tests/test/com/google/common/collect/Collections2Test.java
index ed21ec6..83d9014 100644
--- a/guava-tests/test/com/google/common/collect/Collections2Test.java
+++ b/guava-tests/test/com/google/common/collect/Collections2Test.java
@@ -19,9 +19,9 @@
 import static com.google.common.collect.Iterables.concat;
 import static com.google.common.collect.Lists.newArrayList;
 import static com.google.common.collect.Lists.newLinkedList;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
 import static java.util.Collections.nCopies;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -237,7 +237,7 @@
         Collections2.orderedPermutations(list);
 
     assertEquals(1, permutationSet.size());
-    ASSERT.that(permutationSet).has().item(list);
+    assertThat(permutationSet).has().item(list);
 
     Iterator<List<Integer>> permutations = permutationSet.iterator();
 
diff --git a/guava-tests/test/com/google/common/collect/ConcurrentHashMultisetBasherTest.java b/guava-tests/test/com/google/common/collect/ConcurrentHashMultisetBasherTest.java
index 87e73ca..6c022a7 100644
--- a/guava-tests/test/com/google/common/collect/ConcurrentHashMultisetBasherTest.java
+++ b/guava-tests/test/com/google/common/collect/ConcurrentHashMultisetBasherTest.java
@@ -26,6 +26,7 @@
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentSkipListMap;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -47,6 +48,10 @@
     testAddAndRemove(new ConcurrentHashMap<String, AtomicInteger>());
   }
 
+  public void testAddAndRemove_ConcurrentSkipListMap() throws Exception {
+    testAddAndRemove(new ConcurrentSkipListMap<String, AtomicInteger>());
+  }
+
   public void testAddAndRemove_MapMakerMap() throws Exception {
     MapMaker mapMaker = new MapMaker();
     // force MapMaker to use its own MapMakerInternalMap
diff --git a/guava-tests/test/com/google/common/collect/ConcurrentHashMultisetTest.java b/guava-tests/test/com/google/common/collect/ConcurrentHashMultisetTest.java
index 467d793..c935f27 100644
--- a/guava-tests/test/com/google/common/collect/ConcurrentHashMultisetTest.java
+++ b/guava-tests/test/com/google/common/collect/ConcurrentHashMultisetTest.java
@@ -42,6 +42,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentSkipListMap;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -62,6 +63,14 @@
             CollectionFeature.ALLOWS_NULL_QUERIES)
         .named("ConcurrentHashMultiset")
         .createTestSuite());
+    suite.addTest(MultisetTestSuiteBuilder.using(concurrentSkipListMultisetGenerator())
+        .withFeatures(CollectionSize.ANY,
+            CollectionFeature.KNOWN_ORDER,
+            CollectionFeature.GENERAL_PURPOSE,
+            CollectionFeature.SERIALIZABLE,
+            CollectionFeature.ALLOWS_NULL_QUERIES)
+        .named("ConcurrentSkipListMultiset")
+        .createTestSuite());
     suite.addTestSuite(ConcurrentHashMultisetTest.class);
     return suite;
   }
@@ -74,6 +83,22 @@
     };
   }
 
+  private static TestStringMultisetGenerator concurrentSkipListMultisetGenerator() {
+    return new TestStringMultisetGenerator() {
+      @Override protected Multiset<String> create(String[] elements) {
+        Multiset<String> multiset = new ConcurrentHashMultiset<String>(
+            new ConcurrentSkipListMap<String, AtomicInteger>());
+        Collections.addAll(multiset, elements);
+        return multiset;
+      }
+
+      @Override
+      public List<String> order(List<String> insertionOrder) {
+        return Ordering.natural().sortedCopy(insertionOrder);
+      }
+    };
+  }
+
   private static final String KEY = "puppies";
 
   ConcurrentMap<String, AtomicInteger> backingMap;
diff --git a/guava-tests/test/com/google/common/collect/ConstraintsTest.java b/guava-tests/test/com/google/common/collect/ConstraintsTest.java
index 08a2866..d93c642 100644
--- a/guava-tests/test/com/google/common/collect/ConstraintsTest.java
+++ b/guava-tests/test/com/google/common/collect/ConstraintsTest.java
@@ -16,12 +16,10 @@
 
 package com.google.common.collect;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
-import com.google.common.testing.SerializableTester;
 
 import junit.framework.TestCase;
 
@@ -41,7 +39,7 @@
  * @author Mike Bostock
  * @author Jared Levy
  */
-@GwtCompatible(emulated = true)
+@GwtCompatible
 public class ConstraintsTest extends TestCase {
 
   private static final String TEST_ELEMENT = "test";
@@ -62,16 +60,6 @@
           }
         };
 
-  public void testNotNull() {
-    Constraint<? super String> constraint = Constraints.notNull();
-    assertSame(TEST_ELEMENT, constraint.checkElement(TEST_ELEMENT));
-    try {
-      constraint.checkElement(null);
-      fail("NullPointerException expected");
-    } catch (NullPointerException expected) {}
-    assertEquals("Not null", constraint.toString());
-  }
-
   public void testConstrainedCollectionLegal() {
     Collection<String> collection = Lists.newArrayList("foo", "bar");
     Collection<String> constrained = Constraints.constrainedCollection(
@@ -80,9 +68,9 @@
     constrained.add("qux");
     constrained.addAll(asList("cat", "dog"));
     /* equals and hashCode aren't defined for Collection */
-    ASSERT.that(collection).has()
+    assertThat(collection).has()
         .exactly("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder();
-    ASSERT.that(constrained).has()
+    assertThat(constrained).has()
         .exactly("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder();
   }
 
@@ -98,8 +86,8 @@
       constrained.addAll(asList("baz", TEST_ELEMENT));
       fail("TestElementException expected");
     } catch (TestElementException expected) {}
-    ASSERT.that(constrained).has().exactly("foo", "bar").inOrder();
-    ASSERT.that(collection).has().exactly("foo", "bar").inOrder();
+    assertThat(constrained).has().exactly("foo", "bar").inOrder();
+    assertThat(collection).has().exactly("foo", "bar").inOrder();
   }
 
   public void testConstrainedSetLegal() {
@@ -112,8 +100,8 @@
     assertTrue(constrained.equals(set));
     assertEquals(set.toString(), constrained.toString());
     assertEquals(set.hashCode(), constrained.hashCode());
-    ASSERT.that(set).has().exactly("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder();
-    ASSERT.that(constrained).has()
+    assertThat(set).has().exactly("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder();
+    assertThat(constrained).has()
         .exactly("foo", "bar", TEST_ELEMENT, "qux", "cat", "dog").inOrder();
   }
 
@@ -128,8 +116,8 @@
       constrained.addAll(asList("baz", TEST_ELEMENT));
       fail("TestElementException expected");
     } catch (TestElementException expected) {}
-    ASSERT.that(constrained).has().exactly("foo", "bar").inOrder();
-    ASSERT.that(set).has().exactly("foo", "bar").inOrder();
+    assertThat(constrained).has().exactly("foo", "bar").inOrder();
+    assertThat(set).has().exactly("foo", "bar").inOrder();
   }
 
   public void testConstrainedSortedSetLegal() {
@@ -143,8 +131,8 @@
     assertTrue(constrained.equals(sortedSet));
     assertEquals(sortedSet.toString(), constrained.toString());
     assertEquals(sortedSet.hashCode(), constrained.hashCode());
-    ASSERT.that(sortedSet).has().exactly("bar", "cat", "dog", "foo", "qux", TEST_ELEMENT).inOrder();
-    ASSERT.that(constrained).has()
+    assertThat(sortedSet).has().exactly("bar", "cat", "dog", "foo", "qux", TEST_ELEMENT).inOrder();
+    assertThat(constrained).has()
         .exactly("bar", "cat", "dog", "foo", "qux", TEST_ELEMENT).inOrder();
     assertNull(constrained.comparator());
     assertEquals("bar", constrained.first());
@@ -175,8 +163,8 @@
       constrained.addAll(asList("baz", TEST_ELEMENT));
       fail("TestElementException expected");
     } catch (TestElementException expected) {}
-    ASSERT.that(constrained).has().exactly("bar", "foo").inOrder();
-    ASSERT.that(sortedSet).has().exactly("bar", "foo").inOrder();
+    assertThat(constrained).has().exactly("bar", "foo").inOrder();
+    assertThat(sortedSet).has().exactly("bar", "foo").inOrder();
   }
 
   public void testConstrainedListLegal() {
@@ -193,17 +181,17 @@
     assertTrue(constrained.equals(list));
     assertEquals(list.toString(), constrained.toString());
     assertEquals(list.hashCode(), constrained.hashCode());
-    ASSERT.that(list).has().exactly(
+    assertThat(list).has().exactly(
         "foo", "cow", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog").inOrder();
-    ASSERT.that(constrained).has().exactly(
+    assertThat(constrained).has().exactly(
         "foo", "cow", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog").inOrder();
     ListIterator<String> iterator = constrained.listIterator();
     iterator.next();
     iterator.set("sun");
     constrained.listIterator(2).add("sky");
-    ASSERT.that(list).has().exactly(
+    assertThat(list).has().exactly(
         "sun", "cow", "sky", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog").inOrder();
-    ASSERT.that(constrained).has().exactly(
+    assertThat(constrained).has().exactly(
         "sun", "cow", "sky", "baz", TEST_ELEMENT, "box", "fan", "qux", "cat", "dog").inOrder();
     assertTrue(constrained instanceof RandomAccess);
   }
@@ -261,51 +249,8 @@
       constrained.addAll(1, asList("baz", TEST_ELEMENT));
       fail("TestElementException expected");
     } catch (TestElementException expected) {}
-    ASSERT.that(constrained).has().exactly("foo", "bar").inOrder();
-    ASSERT.that(list).has().exactly("foo", "bar").inOrder();
-  }
-
-  public void testConstrainedMultisetLegal() {
-    Multiset<String> multiset = HashMultiset.create(asList("foo", "bar"));
-    Multiset<String> constrained = Constraints.constrainedMultiset(
-        multiset, TEST_CONSTRAINT);
-    multiset.add(TEST_ELEMENT);
-    constrained.add("qux");
-    constrained.addAll(asList("cat", "dog"));
-    constrained.add("cow", 2);
-    assertTrue(multiset.equals(constrained));
-    assertTrue(constrained.equals(multiset));
-    assertEquals(multiset.toString(), constrained.toString());
-    assertEquals(multiset.hashCode(), constrained.hashCode());
-    ASSERT.that(multiset).has().exactly(
-        "foo", "bar", TEST_ELEMENT, "qux", "cat", "dog", "cow", "cow");
-    ASSERT.that(constrained).has().exactly(
-        "foo", "bar", TEST_ELEMENT, "qux", "cat", "dog", "cow", "cow");
-    assertEquals(1, constrained.count("foo"));
-    assertEquals(1, constrained.remove("foo", 3));
-    assertEquals(2, constrained.setCount("cow", 0));
-    ASSERT.that(multiset).has().exactly("bar", TEST_ELEMENT, "qux", "cat", "dog");
-    ASSERT.that(constrained).has().exactly("bar", TEST_ELEMENT, "qux", "cat", "dog");
-  }
-
-  public void testConstrainedMultisetIllegal() {
-    Multiset<String> multiset = HashMultiset.create(asList("foo", "bar"));
-    Multiset<String> constrained = Constraints.constrainedMultiset(
-        multiset, TEST_CONSTRAINT);
-    try {
-      constrained.add(TEST_ELEMENT);
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    try {
-      constrained.add(TEST_ELEMENT, 2);
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    try {
-      constrained.addAll(asList("baz", TEST_ELEMENT));
-      fail("TestElementException expected");
-    } catch (TestElementException expected) {}
-    ASSERT.that(constrained).has().exactly("foo", "bar");
-    ASSERT.that(multiset).has().exactly("foo", "bar");
+    assertThat(constrained).has().exactly("foo", "bar").inOrder();
+    assertThat(list).has().exactly("foo", "bar").inOrder();
   }
 
   public void testNefariousAddAll() {
@@ -314,8 +259,8 @@
         list, TEST_CONSTRAINT);
     Collection<String> onceIterable = onceIterableCollection("baz");
     constrained.addAll(onceIterable);
-    ASSERT.that(constrained).has().exactly("foo", "bar", "baz").inOrder();
-    ASSERT.that(list).has().exactly("foo", "bar", "baz").inOrder();
+    assertThat(constrained).has().exactly("foo", "bar", "baz").inOrder();
+    assertThat(list).has().exactly("foo", "bar", "baz").inOrder();
   }
 
   /**
@@ -345,10 +290,5 @@
     };
   }
 
-  @GwtIncompatible("SerializableTester")
-  public void testSerialization() {
-    // TODO: Test serialization of constrained collections.
-    assertSame(Constraints.notNull(),
-        SerializableTester.reserialize(Constraints.notNull()));
-  }
+  // TODO: Test serialization of constrained collections.
 }
diff --git a/guava-tests/test/com/google/common/collect/ContiguousSetTest.java b/guava-tests/test/com/google/common/collect/ContiguousSetTest.java
index 1d26941..5e01e02 100644
--- a/guava-tests/test/com/google/common/collect/ContiguousSetTest.java
+++ b/guava-tests/test/com/google/common/collect/ContiguousSetTest.java
@@ -19,16 +19,29 @@
 import static com.google.common.collect.BoundType.CLOSED;
 import static com.google.common.collect.BoundType.OPEN;
 import static com.google.common.collect.DiscreteDomain.integers;
+import static com.google.common.collect.testing.features.CollectionFeature.ALLOWS_NULL_QUERIES;
+import static com.google.common.collect.testing.features.CollectionFeature.KNOWN_ORDER;
+import static com.google.common.collect.testing.features.CollectionFeature.NON_STANDARD_TOSTRING;
+import static com.google.common.collect.testing.features.CollectionFeature.RESTRICTS_ELEMENTS;
+import static com.google.common.collect.testing.testers.NavigableSetNavigationTester.getHoleMethods;
 import static com.google.common.testing.SerializableTester.reserialize;
 import static com.google.common.testing.SerializableTester.reserializeAndAssert;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
+import com.google.common.collect.testing.NavigableSetTestSuiteBuilder;
+import com.google.common.collect.testing.features.CollectionSize;
+import com.google.common.collect.testing.google.SetGenerators.ContiguousSetDescendingGenerator;
+import com.google.common.collect.testing.google.SetGenerators.ContiguousSetGenerator;
+import com.google.common.collect.testing.google.SetGenerators.ContiguousSetHeadsetGenerator;
+import com.google.common.collect.testing.google.SetGenerators.ContiguousSetSubsetGenerator;
+import com.google.common.collect.testing.google.SetGenerators.ContiguousSetTailsetGenerator;
 import com.google.common.testing.EqualsTester;
 
 import junit.framework.Test;
 import junit.framework.TestCase;
+import junit.framework.TestSuite;
 
 import java.util.Set;
 
@@ -132,53 +145,53 @@
 
   public void testHeadSet() {
     ImmutableSortedSet<Integer> set = ContiguousSet.create(Range.closed(1, 3), integers());
-    ASSERT.that(set.headSet(1)).isEmpty();
-    ASSERT.that(set.headSet(2)).has().item(1);
-    ASSERT.that(set.headSet(3)).has().exactly(1, 2).inOrder();
-    ASSERT.that(set.headSet(4)).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(set.headSet(Integer.MAX_VALUE)).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(set.headSet(1, true)).has().item(1);
-    ASSERT.that(set.headSet(2, true)).has().exactly(1, 2).inOrder();
-    ASSERT.that(set.headSet(3, true)).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(set.headSet(4, true)).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(set.headSet(Integer.MAX_VALUE, true)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.headSet(1)).isEmpty();
+    assertThat(set.headSet(2)).has().item(1);
+    assertThat(set.headSet(3)).has().exactly(1, 2).inOrder();
+    assertThat(set.headSet(4)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.headSet(Integer.MAX_VALUE)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.headSet(1, true)).has().item(1);
+    assertThat(set.headSet(2, true)).has().exactly(1, 2).inOrder();
+    assertThat(set.headSet(3, true)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.headSet(4, true)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.headSet(Integer.MAX_VALUE, true)).has().exactly(1, 2, 3).inOrder();
   }
 
   public void testHeadSet_tooSmall() {
-    ASSERT.that(ContiguousSet.create(Range.closed(1, 3), integers()).headSet(0)).isEmpty();
+    assertThat(ContiguousSet.create(Range.closed(1, 3), integers()).headSet(0)).isEmpty();
   }
 
   public void testTailSet() {
     ImmutableSortedSet<Integer> set = ContiguousSet.create(Range.closed(1, 3), integers());
-    ASSERT.that(set.tailSet(Integer.MIN_VALUE)).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(set.tailSet(1)).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(set.tailSet(2)).has().exactly(2, 3).inOrder();
-    ASSERT.that(set.tailSet(3)).has().item(3);
-    ASSERT.that(set.tailSet(Integer.MIN_VALUE, false)).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(set.tailSet(1, false)).has().exactly(2, 3).inOrder();
-    ASSERT.that(set.tailSet(2, false)).has().item(3);
-    ASSERT.that(set.tailSet(3, false)).isEmpty();
+    assertThat(set.tailSet(Integer.MIN_VALUE)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.tailSet(1)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.tailSet(2)).has().exactly(2, 3).inOrder();
+    assertThat(set.tailSet(3)).has().item(3);
+    assertThat(set.tailSet(Integer.MIN_VALUE, false)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.tailSet(1, false)).has().exactly(2, 3).inOrder();
+    assertThat(set.tailSet(2, false)).has().item(3);
+    assertThat(set.tailSet(3, false)).isEmpty();
   }
 
   public void testTailSet_tooLarge() {
-    ASSERT.that(ContiguousSet.create(Range.closed(1, 3), integers()).tailSet(4)).isEmpty();
+    assertThat(ContiguousSet.create(Range.closed(1, 3), integers()).tailSet(4)).isEmpty();
   }
 
   public void testSubSet() {
     ImmutableSortedSet<Integer> set = ContiguousSet.create(Range.closed(1, 3), integers());
-    ASSERT.that(set.subSet(1, 4)).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(set.subSet(2, 4)).has().exactly(2, 3).inOrder();
-    ASSERT.that(set.subSet(3, 4)).has().item(3);
-    ASSERT.that(set.subSet(3, 3)).isEmpty();
-    ASSERT.that(set.subSet(2, 3)).has().item(2);
-    ASSERT.that(set.subSet(1, 3)).has().exactly(1, 2).inOrder();
-    ASSERT.that(set.subSet(1, 2)).has().item(1);
-    ASSERT.that(set.subSet(2, 2)).isEmpty();
-    ASSERT.that(set.subSet(Integer.MIN_VALUE, Integer.MAX_VALUE)).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(set.subSet(1, true, 3, true)).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(set.subSet(1, false, 3, true)).has().exactly(2, 3).inOrder();
-    ASSERT.that(set.subSet(1, true, 3, false)).has().exactly(1, 2).inOrder();
-    ASSERT.that(set.subSet(1, false, 3, false)).has().item(2);
+    assertThat(set.subSet(1, 4)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.subSet(2, 4)).has().exactly(2, 3).inOrder();
+    assertThat(set.subSet(3, 4)).has().item(3);
+    assertThat(set.subSet(3, 3)).isEmpty();
+    assertThat(set.subSet(2, 3)).has().item(2);
+    assertThat(set.subSet(1, 3)).has().exactly(1, 2).inOrder();
+    assertThat(set.subSet(1, 2)).has().item(1);
+    assertThat(set.subSet(2, 2)).isEmpty();
+    assertThat(set.subSet(Integer.MIN_VALUE, Integer.MAX_VALUE)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.subSet(1, true, 3, true)).has().exactly(1, 2, 3).inOrder();
+    assertThat(set.subSet(1, false, 3, true)).has().exactly(2, 3).inOrder();
+    assertThat(set.subSet(1, true, 3, false)).has().exactly(1, 2).inOrder();
+    assertThat(set.subSet(1, false, 3, false)).has().item(2);
   }
 
   public void testSubSet_outOfOrder() {
@@ -190,11 +203,11 @@
   }
 
   public void testSubSet_tooLarge() {
-    ASSERT.that(ContiguousSet.create(Range.closed(1, 3), integers()).subSet(4, 6)).isEmpty();
+    assertThat(ContiguousSet.create(Range.closed(1, 3), integers()).subSet(4, 6)).isEmpty();
   }
 
   public void testSubSet_tooSmall() {
-    ASSERT.that(ContiguousSet.create(Range.closed(1, 3), integers()).subSet(-1, 0)).isEmpty();
+    assertThat(ContiguousSet.create(Range.closed(1, 3), integers()).subSet(-1, 0)).isEmpty();
   }
 
   public void testFirst() {
@@ -303,4 +316,53 @@
     assertEquals(ImmutableSet.of(1, 2, 3),
         set.intersection(ContiguousSet.create(Range.open(-1, 4), integers())));
   }
+
+  @GwtIncompatible("suite")
+  public static class BuiltTests extends TestCase {
+    public static Test suite() {
+      TestSuite suite = new TestSuite();
+
+      suite.addTest(NavigableSetTestSuiteBuilder.using(
+          new ContiguousSetGenerator())
+          .named("Range.asSet")
+          .withFeatures(CollectionSize.ANY, KNOWN_ORDER, ALLOWS_NULL_QUERIES,
+              NON_STANDARD_TOSTRING, RESTRICTS_ELEMENTS)
+          .suppressing(getHoleMethods())
+          .createTestSuite());
+
+      suite.addTest(NavigableSetTestSuiteBuilder.using(
+          new ContiguousSetHeadsetGenerator())
+          .named("Range.asSet, headset")
+          .withFeatures(CollectionSize.ANY, KNOWN_ORDER, ALLOWS_NULL_QUERIES,
+              NON_STANDARD_TOSTRING, RESTRICTS_ELEMENTS)
+          .suppressing(getHoleMethods())
+          .createTestSuite());
+
+      suite.addTest(NavigableSetTestSuiteBuilder.using(
+          new ContiguousSetTailsetGenerator())
+          .named("Range.asSet, tailset")
+          .withFeatures(CollectionSize.ANY, KNOWN_ORDER, ALLOWS_NULL_QUERIES,
+              NON_STANDARD_TOSTRING, RESTRICTS_ELEMENTS)
+          .suppressing(getHoleMethods())
+          .createTestSuite());
+
+      suite.addTest(NavigableSetTestSuiteBuilder.using(
+          new ContiguousSetSubsetGenerator())
+          .named("Range.asSet, subset")
+          .withFeatures(CollectionSize.ANY, KNOWN_ORDER, ALLOWS_NULL_QUERIES,
+              NON_STANDARD_TOSTRING, RESTRICTS_ELEMENTS)
+          .suppressing(getHoleMethods())
+          .createTestSuite());
+
+      suite.addTest(NavigableSetTestSuiteBuilder.using(
+          new ContiguousSetDescendingGenerator())
+          .named("Range.asSet.descendingSet")
+          .withFeatures(CollectionSize.ANY, KNOWN_ORDER, ALLOWS_NULL_QUERIES,
+              NON_STANDARD_TOSTRING, RESTRICTS_ELEMENTS)
+          .suppressing(getHoleMethods())
+          .createTestSuite());
+
+      return suite;
+    }
+  }
 }
diff --git a/guava-tests/test/com/google/common/collect/EnumBiMapTest.java b/guava-tests/test/com/google/common/collect/EnumBiMapTest.java
index 4d2a89d..6d75bf3 100644
--- a/guava-tests/test/com/google/common/collect/EnumBiMapTest.java
+++ b/guava-tests/test/com/google/common/collect/EnumBiMapTest.java
@@ -17,7 +17,7 @@
 package com.google.common.collect;
 
 import static com.google.common.collect.testing.Helpers.orderEntriesByKey;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -196,16 +196,16 @@
     EnumBiMap<Currency, Country> bimap = EnumBiMap.create(map);
 
     // forward map ordered by currency
-    ASSERT.that(bimap.keySet())
+    assertThat(bimap.keySet())
         .has().exactly(Currency.DOLLAR, Currency.FRANC, Currency.PESO).inOrder();
     // forward map ordered by currency (even for country values)
-    ASSERT.that(bimap.values())
+    assertThat(bimap.values())
         .has().exactly(Country.CANADA, Country.SWITZERLAND, Country.CHILE).inOrder();
     // backward map ordered by country
-    ASSERT.that(bimap.inverse().keySet())
+    assertThat(bimap.inverse().keySet())
         .has().exactly(Country.CANADA, Country.CHILE, Country.SWITZERLAND).inOrder();
     // backward map ordered by country (even for currency values)
-    ASSERT.that(bimap.inverse().values())
+    assertThat(bimap.inverse().values())
         .has().exactly(Currency.DOLLAR, Currency.PESO, Currency.FRANC).inOrder();
   }
 
@@ -223,16 +223,16 @@
     iter.remove();
 
     // forward map ordered by currency
-    ASSERT.that(bimap.keySet())
+    assertThat(bimap.keySet())
         .has().exactly(Currency.FRANC, Currency.PESO).inOrder();
     // forward map ordered by currency (even for country values)
-    ASSERT.that(bimap.values())
+    assertThat(bimap.values())
         .has().exactly(Country.SWITZERLAND, Country.CHILE).inOrder();
     // backward map ordered by country
-    ASSERT.that(bimap.inverse().keySet())
+    assertThat(bimap.inverse().keySet())
         .has().exactly(Country.CHILE, Country.SWITZERLAND).inOrder();
     // backward map ordered by country (even for currency values)
-    ASSERT.that(bimap.inverse().values())
+    assertThat(bimap.inverse().values())
         .has().exactly(Currency.PESO, Currency.FRANC).inOrder();
   }
 
@@ -251,16 +251,16 @@
     iter.remove();
 
     // forward map ordered by currency
-    ASSERT.that(bimap.keySet())
+    assertThat(bimap.keySet())
         .has().exactly(Currency.DOLLAR, Currency.PESO).inOrder();
     // forward map ordered by currency (even for country values)
-    ASSERT.that(bimap.values())
+    assertThat(bimap.values())
         .has().exactly(Country.CANADA, Country.CHILE).inOrder();
     // backward map ordered by country
-    ASSERT.that(bimap.inverse().keySet())
+    assertThat(bimap.inverse().keySet())
         .has().exactly(Country.CANADA, Country.CHILE).inOrder();
     // backward map ordered by country (even for currency values)
-    ASSERT.that(bimap.inverse().values())
+    assertThat(bimap.inverse().values())
         .has().exactly(Currency.DOLLAR, Currency.PESO).inOrder();
   }
 
diff --git a/guava-tests/test/com/google/common/collect/FilteredCollectionsTest.java b/guava-tests/test/com/google/common/collect/FilteredCollectionsTest.java
index 20fb592..579d378 100644
--- a/guava-tests/test/com/google/common/collect/FilteredCollectionsTest.java
+++ b/guava-tests/test/com/google/common/collect/FilteredCollectionsTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
@@ -27,6 +27,7 @@
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
+import java.util.NavigableSet;
 import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.SortedSet;
@@ -100,7 +101,7 @@
         target.add(4);
         C addThenFilter = filter(createUnfiltered(target), EVEN);
 
-        ASSERT.that(filterThenAdd).has().exactlyAs(addThenFilter);
+        assertThat(filterThenAdd).has().exactlyAs(addThenFilter);
       }
     }
 
@@ -156,7 +157,7 @@
         } catch (IllegalArgumentException expected) {
         }
 
-        ASSERT.that(filteredToModify).has().exactlyAs(filtered);
+        assertThat(filteredToModify).has().exactlyAs(filtered);
       }
     }
 
@@ -190,7 +191,7 @@
             Predicates.not(Predicates.and(EVEN, PRIME_DIGIT)));
 
         filtered2.clear();
-        ASSERT.that(unfiltered).has().exactlyAs(inverseFiltered);
+        assertThat(unfiltered).has().exactlyAs(inverseFiltered);
       }
     }
   }
@@ -277,6 +278,94 @@
     }
   }
 
+  public static abstract class AbstractFilteredNavigableSetTest
+      extends AbstractFilteredSortedSetTest<NavigableSet<Integer>> {
+
+    public void testNavigableHeadSet() {
+      for (List<Integer> contents : SAMPLE_INPUTS) {
+        for (int i = 0; i < 10; i++) {
+          for (boolean inclusive : ImmutableList.of(true, false)) {
+            assertEquals(
+                filter(createUnfiltered(contents).headSet(i, inclusive), EVEN),
+                filter(createUnfiltered(contents), EVEN).headSet(i, inclusive));
+          }
+        }
+      }
+    }
+
+    public void testNavigableTailSet() {
+      for (List<Integer> contents : SAMPLE_INPUTS) {
+        for (int i = 0; i < 10; i++) {
+          for (boolean inclusive : ImmutableList.of(true, false)) {
+            assertEquals(
+                filter(createUnfiltered(contents).tailSet(i, inclusive), EVEN),
+                filter(createUnfiltered(contents), EVEN).tailSet(i, inclusive));
+          }
+        }
+      }
+    }
+
+    public void testNavigableSubSet() {
+      for (List<Integer> contents : SAMPLE_INPUTS) {
+        for (int i = 0; i < 10; i++) {
+          for (int j = i + 1; j < 10; j++) {
+            for (boolean fromInclusive : ImmutableList.of(true, false)) {
+              for (boolean toInclusive : ImmutableList.of(true, false)) {
+                NavigableSet<Integer> filterSubset = filter(
+                    createUnfiltered(contents).subSet(i, fromInclusive, j, toInclusive), EVEN);
+                NavigableSet<Integer> subsetFilter = filter(createUnfiltered(contents), EVEN)
+                    .subSet(i, fromInclusive, j, toInclusive);
+                assertEquals(filterSubset, subsetFilter);
+              }
+            }
+          }
+        }
+      }
+    }
+
+    public void testDescendingSet() {
+      for (List<Integer> contents : SAMPLE_INPUTS) {
+        NavigableSet<Integer> filtered = filter(createUnfiltered(contents), EVEN);
+        NavigableSet<Integer> unfiltered = createUnfiltered(filtered);
+
+        assertThat(filtered.descendingSet()).has().exactlyAs(unfiltered.descendingSet()).inOrder();
+      }
+    }
+
+    public void testPollFirst() {
+      for (List<Integer> contents : SAMPLE_INPUTS) {
+        NavigableSet<Integer> filtered = filter(createUnfiltered(contents), EVEN);
+        NavigableSet<Integer> unfiltered = createUnfiltered(filtered);
+
+        assertEquals(unfiltered.pollFirst(), filtered.pollFirst());
+        assertEquals(unfiltered, filtered);
+      }
+    }
+
+    public void testPollLast() {
+      for (List<Integer> contents : SAMPLE_INPUTS) {
+        NavigableSet<Integer> filtered = filter(createUnfiltered(contents), EVEN);
+        NavigableSet<Integer> unfiltered = createUnfiltered(filtered);
+
+        assertEquals(unfiltered.pollLast(), filtered.pollLast());
+        assertEquals(unfiltered, filtered);
+      }
+    }
+
+    public void testNavigation() {
+      for (List<Integer> contents : SAMPLE_INPUTS) {
+        NavigableSet<Integer> filtered = filter(createUnfiltered(contents), EVEN);
+        NavigableSet<Integer> unfiltered = createUnfiltered(filtered);
+        for (int i = 0; i < 10; i++) {
+          assertEquals(unfiltered.lower(i), filtered.lower(i));
+          assertEquals(unfiltered.floor(i), filtered.floor(i));
+          assertEquals(unfiltered.ceiling(i), filtered.ceiling(i));
+          assertEquals(unfiltered.higher(i), filtered.higher(i));
+        }
+      }
+    }
+  }
+
   // implementation tests
 
   public static final class IterablesFilterArrayListTest
@@ -338,6 +427,19 @@
     }
   }
 
+  public static final class SetsFilterNavigableSetTest extends AbstractFilteredNavigableSetTest {
+    @Override
+    NavigableSet<Integer> createUnfiltered(Iterable<Integer> contents) {
+      return Sets.newTreeSet(contents);
+    }
+
+    @Override
+    NavigableSet<Integer> filter(
+        NavigableSet<Integer> elements, Predicate<? super Integer> predicate) {
+      return Sets.filter(elements, predicate);
+    }
+  }
+
   /** No-op test so that the class has at least one method, making Maven's test runner happy. */
   public void testNoop() {
   }
diff --git a/guava-tests/test/com/google/common/collect/FluentIterableTest.java b/guava-tests/test/com/google/common/collect/FluentIterableTest.java
index 4925861..674c642 100644
--- a/guava-tests/test/com/google/common/collect/FluentIterableTest.java
+++ b/guava-tests/test/com/google/common/collect/FluentIterableTest.java
@@ -16,13 +16,14 @@
 
 package com.google.common.collect;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
 import com.google.common.base.Function;
 import com.google.common.base.Functions;
+import com.google.common.base.Joiner;
 import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
@@ -68,6 +69,11 @@
     assertSame(iterable, FluentIterable.from(iterable));
   }
 
+  public void testOfArray() {
+    assertEquals(ImmutableList.of("1", "2", "3", "4"),
+        Lists.newArrayList(FluentIterable.of(new Object[] {"1", "2", "3", "4"})));
+  }
+
   public void testSize1Collection() {
     assertEquals(1, FluentIterable.from(asList("a")).size());
   }
@@ -160,6 +166,32 @@
     assertFalse(cycle.iterator().hasNext());
   }
 
+  public void testAppend() {
+    FluentIterable<Integer> result =
+        FluentIterable.<Integer>from(asList(1, 2, 3)).append(Lists.newArrayList(4, 5, 6));
+    assertEquals(asList(1, 2, 3, 4, 5, 6), Lists.newArrayList(result));
+    assertEquals("[1, 2, 3, 4, 5, 6]", result.toString());
+
+    result = FluentIterable.<Integer>from(asList(1, 2, 3)).append(4, 5, 6);
+    assertEquals(asList(1, 2, 3, 4, 5, 6), Lists.newArrayList(result));
+    assertEquals("[1, 2, 3, 4, 5, 6]", result.toString());
+  }
+
+  public void testAppend_emptyList() {
+    FluentIterable<Integer> result =
+        FluentIterable.<Integer>from(asList(1, 2, 3)).append(Lists.<Integer>newArrayList());
+    assertEquals(asList(1, 2, 3), Lists.newArrayList(result));
+  }
+
+  @SuppressWarnings("ReturnValueIgnored")
+  public void testAppend_nullPointerException() {
+    try {
+      FluentIterable.<Integer>from(asList(1, 2)).append((List<Integer>) null);
+      fail("Appending null iterable should throw NPE.");
+    } catch (NullPointerException expected) {
+    }
+  }
+
   /*
    * Tests for partition(int size) method.
    */
@@ -189,7 +221,7 @@
     FluentIterable<TypeA> alist =
         FluentIterable.from(asList(new TypeA(), new TypeA(), hasBoth, new TypeA()));
     Iterable<TypeB> blist = alist.filter(TypeB.class);
-    ASSERT.that(blist).iteratesOverSequence(hasBoth);
+    assertThat(blist).iteratesAs(hasBoth);
   }
 
   public void testAnyMatch() {
@@ -450,7 +482,7 @@
     FluentIterable<String> tail = FluentIterable.from(set).skip(1);
     set.remove("b");
     set.addAll(Lists.newArrayList("X", "Y", "Z"));
-    ASSERT.that(tail).iteratesOverSequence("c", "X", "Y", "Z");
+    assertThat(tail).iteratesAs("c", "X", "Y", "Z");
   }
 
   public void testSkip_structurallyModifiedSkipSomeList() throws Exception {
@@ -458,7 +490,7 @@
     FluentIterable<String> tail = FluentIterable.from(list).skip(1);
     list.subList(1, 3).clear();
     list.addAll(0, Lists.newArrayList("X", "Y", "Z"));
-    ASSERT.that(tail).iteratesOverSequence("Y", "Z", "a");
+    assertThat(tail).iteratesAs("Y", "Z", "a");
   }
 
   public void testSkip_structurallyModifiedSkipAll() throws Exception {
@@ -474,7 +506,7 @@
     List<String> list = Lists.newArrayList("a", "b", "c");
     FluentIterable<String> tail = FluentIterable.from(list).skip(2);
     list.subList(0, 2).clear();
-    ASSERT.that(tail).isEmpty();
+    assertThat(tail).isEmpty();
   }
 
   @SuppressWarnings("ReturnValueIgnored")
@@ -528,11 +560,11 @@
   }
 
   public void testToSet() {
-    ASSERT.that(fluent(1, 2, 3, 4).toSet()).has().exactly(1, 2, 3, 4).inOrder();
+    assertThat(fluent(1, 2, 3, 4).toSet()).has().exactly(1, 2, 3, 4).inOrder();
   }
 
   public void testToSet_removeDuplicates() {
-    ASSERT.that(fluent(1, 2, 1, 2).toSet()).has().exactly(1, 2).inOrder();
+    assertThat(fluent(1, 2, 1, 2).toSet()).has().exactly(1, 2).inOrder();
   }
 
   public void testToSet_empty() {
@@ -540,17 +572,17 @@
   }
 
   public void testToSortedSet() {
-    ASSERT.that(fluent(1, 4, 2, 3).toSortedSet(Ordering.<Integer>natural().reverse()))
+    assertThat(fluent(1, 4, 2, 3).toSortedSet(Ordering.<Integer>natural().reverse()))
         .has().exactly(4, 3, 2, 1).inOrder();
   }
 
   public void testToSortedSet_removeDuplicates() {
-    ASSERT.that(fluent(1, 4, 1, 3).toSortedSet(Ordering.<Integer>natural().reverse()))
+    assertThat(fluent(1, 4, 1, 3).toSortedSet(Ordering.<Integer>natural().reverse()))
         .has().exactly(4, 3, 1).inOrder();
   }
 
   public void testToMap() {
-    ASSERT.that(fluent(1, 2, 3).toMap(Functions.toStringFunction()).entrySet())
+    assertThat(fluent(1, 2, 3).toMap(Functions.toStringFunction()).entrySet())
         .has().exactly(
             Maps.immutableEntry(1, "1"),
             Maps.immutableEntry(2, "2"),
@@ -657,17 +689,17 @@
   }
 
   public void testCopyInto_List() {
-    ASSERT.that(fluent(1, 3, 5).copyInto(Lists.newArrayList(1, 2)))
+    assertThat(fluent(1, 3, 5).copyInto(Lists.newArrayList(1, 2)))
         .has().exactly(1, 2, 1, 3, 5).inOrder();
   }
 
   public void testCopyInto_Set() {
-    ASSERT.that(fluent(1, 3, 5).copyInto(Sets.newHashSet(1, 2)))
+    assertThat(fluent(1, 3, 5).copyInto(Sets.newHashSet(1, 2)))
         .has().exactly(1, 2, 3, 5);
   }
 
   public void testCopyInto_SetAllDuplicates() {
-    ASSERT.that(fluent(1, 3, 5).copyInto(Sets.newHashSet(1, 2, 3, 5)))
+    assertThat(fluent(1, 3, 5).copyInto(Sets.newHashSet(1, 2, 3, 5)))
         .has().exactly(1, 2, 3, 5);
   }
 
@@ -682,10 +714,18 @@
       }
     };
 
-    ASSERT.that(FluentIterable.from(iterable).copyInto(list))
+    assertThat(FluentIterable.from(iterable).copyInto(list))
         .has().exactly(1, 2, 3, 9, 8, 7).inOrder();
   }
 
+  public void testJoin() {
+    assertEquals("2,1,3,4", fluent(2, 1, 3, 4).join(Joiner.on(",")));
+  }
+
+  public void testJoin_empty() {
+    assertEquals("", fluent().join(Joiner.on(",")));
+  }
+
   public void testGet() {
     assertEquals("a", FluentIterable
         .from(Lists.newArrayList("a", "b", "c")).get(0));
diff --git a/guava-tests/test/com/google/common/collect/ForwardingBlockingDequeTest.java b/guava-tests/test/com/google/common/collect/ForwardingBlockingDequeTest.java
new file mode 100644
index 0000000..ecb67bb
--- /dev/null
+++ b/guava-tests/test/com/google/common/collect/ForwardingBlockingDequeTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2012 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import java.util.concurrent.BlockingDeque;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test for {@link ForwardingBlockingDeque}
+ * 
+ * @author Emily Soldal
+ */
+public class ForwardingBlockingDequeTest extends ForwardingTestCase {
+  private BlockingDeque<String> forward;
+
+  /*
+   * Class parameters must be raw, so we can't create a proxy with generic
+   * type arguments. The created proxy only records calls and returns null, so
+   * the type is irrelevant at runtime.
+   */
+  @SuppressWarnings("unchecked")
+  @Override protected void setUp() throws Exception {
+    super.setUp();
+    final BlockingDeque<String> deque = createProxyInstance(BlockingDeque.class);
+    forward = new ForwardingBlockingDeque<String>() {
+      @Override protected BlockingDeque<String> delegate() {
+        return deque;
+      }
+    };
+  }
+
+  public void testRemainingCapacity() {
+    forward.remainingCapacity();
+    assertEquals("[remainingCapacity]", getCalls());
+  }
+
+  public void testPutFirst_T() throws InterruptedException {
+    forward.putFirst("asf");
+    assertEquals("[putFirst(Object)]", getCalls());
+  }
+
+  public void testPutLast_T() throws InterruptedException {
+    forward.putFirst("asf");
+    assertEquals("[putFirst(Object)]", getCalls());
+  }
+
+  public void testOfferFirst_T() throws InterruptedException {
+    forward.offerFirst("asf", 2L, TimeUnit.SECONDS);
+    assertEquals("[offerFirst(Object,long,TimeUnit)]", getCalls());
+  }
+
+  public void testOfferLast_T() throws InterruptedException {
+    forward.offerLast("asf", 2L, TimeUnit.SECONDS);
+    assertEquals("[offerLast(Object,long,TimeUnit)]", getCalls());
+  }
+
+  public void testTakeFirst() throws InterruptedException {
+    forward.takeFirst();
+    assertEquals("[takeFirst]", getCalls());
+  }
+
+  public void testTakeLast() throws InterruptedException {
+    forward.takeLast();
+    assertEquals("[takeLast]", getCalls());
+  }
+
+  public void testPollFirst() throws InterruptedException {
+    forward.pollFirst(2L, TimeUnit.SECONDS);
+    assertEquals("[pollFirst(long,TimeUnit)]", getCalls());
+  }
+
+  public void testPollLast() throws InterruptedException {
+    forward.pollLast(2L, TimeUnit.SECONDS);
+    assertEquals("[pollLast(long,TimeUnit)]", getCalls());
+  }
+
+  public void testPut_T() throws InterruptedException {
+    forward.put("asf");
+    assertEquals("[put(Object)]", getCalls());
+  }
+
+  public void testOffer_T() throws InterruptedException {
+    forward.offer("asf", 2L, TimeUnit.SECONDS);
+    assertEquals("[offer(Object,long,TimeUnit)]", getCalls());
+  }
+
+  public void testTake() throws InterruptedException {
+    forward.take();
+    assertEquals("[take]", getCalls());
+  }
+
+  public void testPoll() throws InterruptedException {
+    forward.poll(2L, TimeUnit.SECONDS);
+    assertEquals("[poll(long,TimeUnit)]", getCalls());
+  }
+
+  public void testDrainTo_T() {
+    forward.drainTo(Lists.newArrayList());
+    assertEquals("[drainTo(Collection)]", getCalls());
+  }
+
+  public void testDrainTo_T_maxElements() {
+    forward.drainTo(Lists.newArrayList(), 3);
+    assertEquals("[drainTo(Collection,int)]", getCalls());
+  }
+}
diff --git a/guava-tests/test/com/google/common/collect/ForwardingDequeTest.java b/guava-tests/test/com/google/common/collect/ForwardingDequeTest.java
new file mode 100644
index 0000000..0ff18fb
--- /dev/null
+++ b/guava-tests/test/com/google/common/collect/ForwardingDequeTest.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2012 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import java.util.Collections;
+import java.util.Deque;
+
+/**
+ * Tests for {@code ForwardingDeque}.
+ *
+ * @author Kurt Alfred Kluever
+ */
+public class ForwardingDequeTest extends ForwardingTestCase {
+  private Deque<String> forward;
+  
+  /*
+   * Class parameters must be raw, so we can't create a proxy with generic
+   * type arguments. The created proxy only records calls and returns null, so
+   * the type is irrelevant at runtime.
+   */
+  @SuppressWarnings("unchecked")
+  @Override protected void setUp() throws Exception {
+    super.setUp();
+    final Deque<String> deque = createProxyInstance(Deque.class);
+    forward = new ForwardingDeque<String>() {
+      @Override protected Deque<String> delegate() {
+        return deque;
+      }
+    };
+  }
+
+  public void testAdd_T() {
+    forward.add("asdf");
+    assertEquals("[add(Object)]", getCalls());
+  }
+
+  public void testAddFirst_T() {
+    forward.addFirst("asdf");
+    assertEquals("[addFirst(Object)]", getCalls());
+  }
+
+  public void testAddLast_T() {
+    forward.addLast("asdf");
+    assertEquals("[addLast(Object)]", getCalls());
+  }
+
+  public void testAddAll_Collection() {
+    forward.addAll(Collections.singleton("asdf"));
+    assertEquals("[addAll(Collection)]", getCalls());
+  }
+
+  public void testClear() {
+    forward.clear();
+    assertEquals("[clear]", getCalls());
+  }
+
+  public void testContains_T() {
+    forward.contains("asdf");
+    assertEquals("[contains(Object)]", getCalls());
+  }
+
+  public void testContainsAll_Collection() {
+    forward.containsAll(Collections.singleton("asdf"));
+    assertEquals("[containsAll(Collection)]", getCalls());
+  }
+
+  public void testDescendingIterator() {
+    forward.descendingIterator();
+    assertEquals("[descendingIterator]", getCalls());
+  }
+
+  public void testElement() {
+    forward.element();
+    assertEquals("[element]", getCalls());
+  }
+
+  public void testGetFirst() {
+    forward.getFirst();
+    assertEquals("[getFirst]", getCalls());
+  }
+
+  public void testGetLast() {
+    forward.getLast();
+    assertEquals("[getLast]", getCalls());
+  }
+
+  public void testIterator() {
+    forward.iterator();
+    assertEquals("[iterator]", getCalls());
+  }
+
+  public void testIsEmpty() {
+    forward.isEmpty();
+    assertEquals("[isEmpty]", getCalls());
+  }
+
+  public void testOffer_T() {
+    forward.offer("asdf");
+    assertEquals("[offer(Object)]", getCalls());
+  }
+
+  public void testOfferFirst_T() {
+    forward.offerFirst("asdf");
+    assertEquals("[offerFirst(Object)]", getCalls());
+  }
+
+  public void testOfferLast_T() {
+    forward.offerLast("asdf");
+    assertEquals("[offerLast(Object)]", getCalls());
+  }
+
+  public void testPeek() {
+    forward.peek();
+    assertEquals("[peek]", getCalls());
+  }
+
+  public void testPeekFirst() {
+    forward.peekFirst();
+    assertEquals("[peekFirst]", getCalls());
+  }
+
+  public void testPeekLast() {
+    forward.peekLast();
+    assertEquals("[peekLast]", getCalls());
+  }
+
+  public void testPoll() {
+    forward.poll();
+    assertEquals("[poll]", getCalls());
+  }
+
+  public void testPollFirst() {
+    forward.pollFirst();
+    assertEquals("[pollFirst]", getCalls());
+  }
+
+  public void testPollLast() {
+    forward.pollLast();
+    assertEquals("[pollLast]", getCalls());
+  }
+
+  public void testPop() {
+    forward.pop();
+    assertEquals("[pop]", getCalls());
+  }
+
+  public void testPush_Object() {
+    forward.push("asdf");
+    assertEquals("[push(Object)]", getCalls());
+  }
+
+  public void testRemove() {
+    forward.remove();
+    assertEquals("[remove]", getCalls());
+  }
+
+  public void testRemoveFirst() {
+    forward.removeFirst();
+    assertEquals("[removeFirst]", getCalls());
+  }
+
+  public void testRemoveLast() {
+    forward.removeLast();
+    assertEquals("[removeLast]", getCalls());
+  }
+
+  public void testRemove_Object() {
+    forward.remove(Object.class);
+    assertEquals("[remove(Object)]", getCalls());
+  }
+
+  public void testRemoveFirstOccurrence_Object() {
+    forward.removeFirstOccurrence(Object.class);
+    assertEquals("[removeFirstOccurrence(Object)]", getCalls());
+  }
+
+  public void testRemoveLastOccurrence_Object() {
+    forward.removeLastOccurrence(Object.class);
+    assertEquals("[removeLastOccurrence(Object)]", getCalls());
+  }
+
+  public void testRemoveAll_Collection() {
+    forward.removeAll(Collections.singleton("asdf"));
+    assertEquals("[removeAll(Collection)]", getCalls());
+  }
+
+  public void testRetainAll_Collection() {
+    forward.retainAll(Collections.singleton("asdf"));
+    assertEquals("[retainAll(Collection)]", getCalls());
+  }
+
+  public void testSize() {
+    forward.size();
+    assertEquals("[size]", getCalls());
+  }
+
+  public void testToArray() {
+    forward.toArray();
+    assertEquals("[toArray]", getCalls());
+  }
+
+  public void testToArray_TArray() {
+    forward.toArray(new String[0]);
+    assertEquals("[toArray(Object[])]", getCalls());
+  }
+      
+  public void testToString() {
+    forward.toString();
+    assertEquals("[toString]", getCalls());
+  }
+}
diff --git a/guava-tests/test/com/google/common/collect/ForwardingNavigableMapTest.java b/guava-tests/test/com/google/common/collect/ForwardingNavigableMapTest.java
new file mode 100644
index 0000000..d10ff09
--- /dev/null
+++ b/guava-tests/test/com/google/common/collect/ForwardingNavigableMapTest.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import static com.google.common.collect.Maps.immutableEntry;
+
+import com.google.common.collect.testing.NavigableMapTestSuiteBuilder;
+import com.google.common.collect.testing.SafeTreeMap;
+import com.google.common.collect.testing.TestStringSortedMapGenerator;
+import com.google.common.collect.testing.features.CollectionFeature;
+import com.google.common.collect.testing.features.CollectionSize;
+import com.google.common.collect.testing.features.MapFeature;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
+import java.util.Set;
+import java.util.SortedMap;
+
+/**
+ * Tests for {@code ForwardingNavigableMap}.
+ *
+ * @author Robert Konigsberg
+ * @author Louis Wasserman
+ */
+public class ForwardingNavigableMapTest extends ForwardingSortedMapTest {
+  static class StandardImplForwardingNavigableMap<K, V>
+      extends ForwardingNavigableMap<K, V> {
+    private final NavigableMap<K, V> backingMap;
+
+    StandardImplForwardingNavigableMap(NavigableMap<K, V> backingMap) {
+      this.backingMap = backingMap;
+    }
+
+    @Override protected NavigableMap<K, V> delegate() {
+      return backingMap;
+    }
+
+    @Override public boolean containsKey(Object key) {
+      return standardContainsKey(key);
+    }
+
+    @Override public boolean containsValue(Object value) {
+      return standardContainsValue(value);
+    }
+
+    @Override public void putAll(Map<? extends K, ? extends V> map) {
+      standardPutAll(map);
+    }
+
+    @Override public V remove(Object object) {
+      return standardRemove(object);
+    }
+
+    @Override public boolean equals(Object object) {
+      return standardEquals(object);
+    }
+
+    @Override public int hashCode() {
+      return standardHashCode();
+    }
+
+    @Override public Set<K> keySet() {
+      /*
+       * We can't use StandardKeySet, as NavigableMapTestSuiteBuilder assumes that our keySet is a
+       * NavigableSet. We test StandardKeySet in the superclass, so it's still covered.
+       */
+      return navigableKeySet();
+    }
+
+    @Override public Collection<V> values() {
+      return new StandardValues();
+    }
+
+    @Override public String toString() {
+      return standardToString();
+    }
+
+    @Override public Set<Entry<K, V>> entrySet() {
+      return new StandardEntrySet() {
+        @Override
+        public Iterator<Entry<K, V>> iterator() {
+          return backingMap.entrySet().iterator();
+        }
+      };
+    }
+
+    @Override public void clear() {
+      standardClear();
+    }
+
+    @Override public boolean isEmpty() {
+      return standardIsEmpty();
+    }
+
+    @Override public SortedMap<K, V> subMap(K fromKey, K toKey) {
+      return standardSubMap(fromKey, toKey);
+    }
+
+    @Override
+    public Entry<K, V> lowerEntry(K key) {
+      return standardLowerEntry(key);
+    }
+
+    @Override
+    public K lowerKey(K key) {
+      return standardLowerKey(key);
+    }
+
+    @Override
+    public Entry<K, V> floorEntry(K key) {
+      return standardFloorEntry(key);
+    }
+
+    @Override
+    public K floorKey(K key) {
+      return standardFloorKey(key);
+    }
+
+    @Override
+    public Entry<K, V> ceilingEntry(K key) {
+      return standardCeilingEntry(key);
+    }
+
+    @Override
+    public K ceilingKey(K key) {
+      return standardCeilingKey(key);
+    }
+
+    @Override
+    public Entry<K, V> higherEntry(K key) {
+      return standardHigherEntry(key);
+    }
+
+    @Override
+    public K higherKey(K key) {
+      return standardHigherKey(key);
+    }
+
+    @Override
+    public Entry<K, V> firstEntry() {
+      return standardFirstEntry();
+    }
+
+    /*
+     * We can't override lastEntry to delegate to standardLastEntry, as it would create an infinite
+     * loop. Instead, we test standardLastEntry manually below.
+     */
+
+    @Override
+    public Entry<K, V> pollFirstEntry() {
+      return standardPollFirstEntry();
+    }
+
+    @Override
+    public Entry<K, V> pollLastEntry() {
+      return standardPollLastEntry();
+    }
+
+    @Override
+    public NavigableMap<K, V> descendingMap() {
+      return new StandardDescendingMap();
+    }
+
+    @Override
+    public NavigableSet<K> navigableKeySet() {
+      return new StandardNavigableKeySet();
+    }
+
+    @Override
+    public NavigableSet<K> descendingKeySet() {
+      return standardDescendingKeySet();
+    }
+
+    @Override
+    public K firstKey() {
+      return standardFirstKey();
+    }
+
+    @Override
+    public SortedMap<K, V> headMap(K toKey) {
+      return standardHeadMap(toKey);
+    }
+
+    @Override
+    public K lastKey() {
+      return standardLastKey();
+    }
+
+    @Override
+    public SortedMap<K, V> tailMap(K fromKey) {
+      return standardTailMap(fromKey);
+    }
+  }
+
+  static class StandardLastEntryForwardingNavigableMap<K, V>
+      extends ForwardingNavigableMap<K, V> {
+    private final NavigableMap<K, V> backingMap;
+
+    StandardLastEntryForwardingNavigableMap(NavigableMap<K, V> backingMap) {
+      this.backingMap = backingMap;
+    }
+
+    @Override protected NavigableMap<K, V> delegate() {
+      return backingMap;
+    }
+
+    @Override
+    public Entry<K, V> lastEntry() {
+      return standardLastEntry();
+    }
+  }
+
+  public static Test suite() {
+    TestSuite suite = new TestSuite();
+
+    suite.addTestSuite(ForwardingNavigableMapTest.class);
+    suite.addTest(NavigableMapTestSuiteBuilder.using(new TestStringSortedMapGenerator() {
+      @Override protected SortedMap<String, String> create(
+          Entry<String, String>[] entries) {
+        NavigableMap<String, String> map = new SafeTreeMap<String, String>();
+        for (Entry<String, String> entry : entries) {
+          map.put(entry.getKey(), entry.getValue());
+        }
+        return new StandardImplForwardingNavigableMap<String, String>(map);
+      }
+    }).named("ForwardingNavigableMap[SafeTreeMap] with no comparator and standard "
+        + "implementations").withFeatures(CollectionSize.ANY,
+        CollectionFeature.KNOWN_ORDER, MapFeature.ALLOWS_NULL_VALUES,
+        CollectionFeature.SUPPORTS_ITERATOR_REMOVE, MapFeature.GENERAL_PURPOSE)
+        .createTestSuite());
+    // TODO(user): add forwarding-to-ImmutableSortedMap test
+    return suite;
+  }
+
+  @Override public void setUp() throws Exception {
+    super.setUp();
+    /*
+     * Class parameters must be raw, so we can't create a proxy with generic
+     * type arguments. The created proxy only records calls and returns null, so
+     * the type is irrelevant at runtime.
+     */
+    @SuppressWarnings("unchecked")
+    final NavigableMap<String, Boolean> sortedMap =
+        createProxyInstance(NavigableMap.class);
+    forward = new ForwardingNavigableMap<String, Boolean>() {
+      @Override protected NavigableMap<String, Boolean> delegate() {
+        return sortedMap;
+      }
+    };
+  }
+
+  public void testStandardLastEntry() {
+    NavigableMap<String, Integer> forwarding =
+        new StandardLastEntryForwardingNavigableMap<String, Integer>(
+            new SafeTreeMap<String, Integer>());
+    assertNull(forwarding.lastEntry());
+    forwarding.put("b", 2);
+    assertEquals(immutableEntry("b", 2), forwarding.lastEntry());
+    forwarding.put("c", 3);
+    assertEquals(immutableEntry("c", 3), forwarding.lastEntry());
+    forwarding.put("a", 1);
+    assertEquals(immutableEntry("c", 3), forwarding.lastEntry());
+    forwarding.remove("c");
+    assertEquals(immutableEntry("b", 2), forwarding.lastEntry());
+  }
+
+  public void testLowerEntry() {
+    forward().lowerEntry("key");
+    assertEquals("[lowerEntry(Object)]", getCalls());
+  }
+
+  public void testLowerKey() {
+    forward().lowerKey("key");
+    assertEquals("[lowerKey(Object)]", getCalls());
+  }
+
+  public void testFloorEntry() {
+    forward().floorEntry("key");
+    assertEquals("[floorEntry(Object)]", getCalls());
+  }
+
+  public void testFloorKey() {
+    forward().floorKey("key");
+    assertEquals("[floorKey(Object)]", getCalls());
+  }
+
+  public void testCeilingEntry() {
+    forward().ceilingEntry("key");
+    assertEquals("[ceilingEntry(Object)]", getCalls());
+  }
+
+  public void testCeilingKey() {
+    forward().ceilingKey("key");
+    assertEquals("[ceilingKey(Object)]", getCalls());
+  }
+
+  public void testHigherEntry() {
+    forward().higherEntry("key");
+    assertEquals("[higherEntry(Object)]", getCalls());
+  }
+
+  public void testHigherKey() {
+    forward().higherKey("key");
+    assertEquals("[higherKey(Object)]", getCalls());
+  }
+
+  public void testPollFirstEntry() {
+    forward().pollFirstEntry();
+    assertEquals("[pollFirstEntry]", getCalls());
+  }
+
+  public void testPollLastEntry() {
+    forward().pollLastEntry();
+    assertEquals("[pollLastEntry]", getCalls());
+  }
+
+  public void testFirstEntry() {
+    forward().firstEntry();
+    assertEquals("[firstEntry]", getCalls());
+  }
+
+  public void testLastEntry() {
+    forward().lastEntry();
+    assertEquals("[lastEntry]", getCalls());
+  }
+
+  public void testDescendingMap() {
+    forward().descendingMap();
+    assertEquals("[descendingMap]", getCalls());
+  }
+
+  public void testNavigableKeySet() {
+    forward().navigableKeySet();
+    assertEquals("[navigableKeySet]", getCalls());
+  }
+
+  public void testDescendingKeySet() {
+    forward().descendingKeySet();
+    assertEquals("[descendingKeySet]", getCalls());
+  }
+
+  public void testSubMap_K_Bool_K_Bool() {
+    forward().subMap("a", false, "b", true);
+    assertEquals("[subMap(Object,boolean,Object,boolean)]", getCalls());
+  }
+
+  public void testHeadMap_K_Bool() {
+    forward().headMap("a", false);
+    assertEquals("[headMap(Object,boolean)]", getCalls());
+  }
+
+  public void testTailMap_K_Bool() {
+    forward().tailMap("a", false);
+    assertEquals("[tailMap(Object,boolean)]", getCalls());
+  }
+
+  @Override NavigableMap<String, Boolean> forward() {
+    return (NavigableMap<String, Boolean>) super.forward();
+  }
+}
diff --git a/guava-tests/test/com/google/common/collect/ForwardingNavigableSetTest.java b/guava-tests/test/com/google/common/collect/ForwardingNavigableSetTest.java
new file mode 100644
index 0000000..70178b1
--- /dev/null
+++ b/guava-tests/test/com/google/common/collect/ForwardingNavigableSetTest.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2012 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import com.google.common.collect.testing.SafeTreeSet;
+import com.google.common.collect.testing.SetTestSuiteBuilder;
+import com.google.common.collect.testing.TestStringSetGenerator;
+import com.google.common.collect.testing.features.CollectionFeature;
+import com.google.common.collect.testing.features.CollectionSize;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.NavigableSet;
+import java.util.Set;
+import java.util.SortedSet;
+
+/**
+ * Tests for {@code ForwardingNavigableSet}.
+ *
+ * @author Louis Wasserman
+ */
+public class ForwardingNavigableSetTest extends ForwardingSortedSetTest {
+  static class StandardImplForwardingNavigableSet<T>
+      extends ForwardingNavigableSet<T> {
+    private final NavigableSet<T> backingSet;
+
+    StandardImplForwardingNavigableSet(NavigableSet<T> backingSet) {
+      this.backingSet = backingSet;
+    }
+
+    @Override protected NavigableSet<T> delegate() {
+      return backingSet;
+    }
+
+    @Override public boolean equals(Object object) {
+      return standardEquals(object);
+    }
+
+    @Override public int hashCode() {
+      return standardHashCode();
+    }
+
+    @Override public boolean addAll(Collection<? extends T> collection) {
+      return standardAddAll(collection);
+    }
+
+    @Override public void clear() {
+      standardClear();
+    }
+
+    @Override public boolean contains(Object object) {
+      return standardContains(object);
+    }
+
+    @Override public boolean containsAll(Collection<?> collection) {
+      return standardContainsAll(collection);
+    }
+
+    @Override public boolean remove(Object object) {
+      return standardRemove(object);
+    }
+
+    @Override public boolean removeAll(Collection<?> collection) {
+      return standardRemoveAll(collection);
+    }
+
+    @Override public boolean retainAll(Collection<?> collection) {
+      return standardRetainAll(collection);
+    }
+
+    @Override public Object[] toArray() {
+      return standardToArray();
+    }
+
+    @Override public <T> T[] toArray(T[] array) {
+      return standardToArray(array);
+    }
+
+    @Override public String toString() {
+      return standardToString();
+    }
+
+    @Override public SortedSet<T> subSet(T fromElement, T toElement) {
+      return standardSubSet(fromElement, toElement);
+    }
+
+    @Override
+    public T lower(T e) {
+      return standardLower(e);
+    }
+
+    @Override
+    public T floor(T e) {
+      return standardFloor(e);
+    }
+
+    @Override
+    public T ceiling(T e) {
+      return standardCeiling(e);
+    }
+
+    @Override
+    public T higher(T e) {
+      return standardHigher(e);
+    }
+
+    @Override
+    public T pollFirst() {
+      return standardPollFirst();
+    }
+
+    @Override
+    public T pollLast() {
+      return standardPollLast();
+    }
+
+    @Override
+    public SortedSet<T> headSet(T toElement) {
+      return standardHeadSet(toElement);
+    }
+
+    @Override
+    public SortedSet<T> tailSet(T fromElement) {
+      return standardTailSet(fromElement);
+    }
+  }
+  
+  public static Test suite() {
+    TestSuite suite = new TestSuite();
+    
+    suite.addTestSuite(ForwardingNavigableSetTest.class);
+    suite.addTest(
+        SetTestSuiteBuilder.using(new TestStringSetGenerator() {
+          @Override protected Set<String> create(String[] elements) {
+            return new StandardImplForwardingNavigableSet<String>(
+                new SafeTreeSet<String>(Arrays.asList(elements)));
+          }
+
+          @Override public List<String> order(List<String> insertionOrder) {
+            return Lists.newArrayList(Sets.newTreeSet(insertionOrder));
+          }
+        }).named(
+            "ForwardingNavigableSet[SafeTreeSet] with standard implementations")
+            .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER,
+                CollectionFeature.GENERAL_PURPOSE).createTestSuite());
+    suite.addTest(
+        SetTestSuiteBuilder.using(new TestStringSetGenerator() {
+          @Override protected Set<String> create(String[] elements) {
+            SafeTreeSet<String> set = new SafeTreeSet<String>(Ordering.natural().nullsFirst());
+            Collections.addAll(set, elements);
+            return new StandardImplForwardingNavigableSet<String>(set);
+          }
+
+          @Override public List<String> order(List<String> insertionOrder) {
+            return Lists.newArrayList(Sets.newTreeSet(insertionOrder));
+          }
+        }).named(
+            "ForwardingNavigableSet[SafeTreeSet[Ordering.natural.nullsFirst]]"
+                + " with standard implementations")
+            .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER,
+                CollectionFeature.GENERAL_PURPOSE, CollectionFeature.ALLOWS_NULL_VALUES)
+                .createTestSuite());
+    
+    return suite;
+  }
+  
+  @Override public void setUp() throws Exception {
+    super.setUp();
+    /*
+     * Class parameters must be raw, so we can't create a proxy with generic
+     * type arguments. The created proxy only records calls and returns null, so
+     * the type is irrelevant at runtime.
+     */
+    @SuppressWarnings("unchecked")
+    final NavigableSet<String> navigableSet
+        = createProxyInstance(NavigableSet.class);
+    forward = new ForwardingNavigableSet<String>() {
+      @Override protected NavigableSet<String> delegate() {
+        return navigableSet;
+      }
+    };
+  }
+
+  public void testLower() {
+    forward().lower("a");
+    assertEquals("[lower(Object)]", getCalls());
+  }
+
+  public void testFloor() {
+    forward().floor("a");
+    assertEquals("[floor(Object)]", getCalls());
+  }
+
+  public void testCeiling() {
+    forward().ceiling("a");
+    assertEquals("[ceiling(Object)]", getCalls());
+  }
+
+  public void testHigher() {
+    forward().higher("a");
+    assertEquals("[higher(Object)]", getCalls());
+  }
+
+  public void testPollFirst() {
+    forward().pollFirst();
+    assertEquals("[pollFirst]", getCalls());
+  }
+
+  public void testPollLast() {
+    forward().pollLast();
+    assertEquals("[pollLast]", getCalls());
+  }
+
+  public void testDescendingIterator() {
+    forward().descendingIterator();
+    assertEquals("[descendingIterator]", getCalls());
+  }
+  
+  public void testHeadSet_K_Boolean() {
+    forward().headSet("key", false);
+    assertEquals("[headSet(Object,boolean)]", getCalls());
+  }
+  
+  public void testSubSet_K_Boolean_K_Boolean() {
+    forward().subSet("a", true, "b", false);
+    assertEquals("[subSet(Object,boolean,Object,boolean)]", getCalls());
+  }
+  
+  public void testTailSet_K_Boolean() {
+    forward().tailSet("key", false);
+    assertEquals("[tailSet(Object,boolean)]", getCalls());
+  }
+
+  @Override NavigableSet<String> forward() {
+    return (NavigableSet<String>) super.forward();
+  }
+}
diff --git a/guava-tests/test/com/google/common/collect/ForwardingSortedMapTest.java b/guava-tests/test/com/google/common/collect/ForwardingSortedMapTest.java
index e2cf067..36d55b7 100644
--- a/guava-tests/test/com/google/common/collect/ForwardingSortedMapTest.java
+++ b/guava-tests/test/com/google/common/collect/ForwardingSortedMapTest.java
@@ -17,7 +17,6 @@
 package com.google.common.collect;
 
 import com.google.common.collect.testing.Helpers.NullsBeforeTwo;
-import com.google.common.collect.testing.MapTestSuiteBuilder;
 import com.google.common.collect.testing.SafeTreeMap;
 import com.google.common.collect.testing.SortedMapTestSuiteBuilder;
 import com.google.common.collect.testing.TestStringSortedMapGenerator;
@@ -66,11 +65,9 @@
       standardPutAll(map);
     }
 
-    /* This test would fail due to a bug fixed in JDK7
     @Override public V remove(Object object) {
       return standardRemove(object);
     }
-    */
 
     @Override public boolean equals(Object object) {
       return standardEquals(object);
@@ -132,7 +129,7 @@
         CollectionFeature.KNOWN_ORDER, MapFeature.ALLOWS_NULL_VALUES,
         MapFeature.GENERAL_PURPOSE, CollectionFeature.SUPPORTS_ITERATOR_REMOVE)
         .createTestSuite());
-    suite.addTest(MapTestSuiteBuilder.using(new TestStringSortedMapGenerator() {
+    suite.addTest(SortedMapTestSuiteBuilder.using(new TestStringSortedMapGenerator() {
       private final Comparator<String> comparator = NullsBeforeTwo.INSTANCE;
 
       @Override protected SortedMap<String, String> create(
diff --git a/guava-tests/test/com/google/common/collect/ForwardingSortedMultisetTest.java b/guava-tests/test/com/google/common/collect/ForwardingSortedMultisetTest.java
index 092fe0d..33aed37 100644
--- a/guava-tests/test/com/google/common/collect/ForwardingSortedMultisetTest.java
+++ b/guava-tests/test/com/google/common/collect/ForwardingSortedMultisetTest.java
@@ -29,7 +29,7 @@
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
-import java.util.SortedSet;
+import java.util.NavigableSet;
 
 import javax.annotation.Nullable;
 
@@ -66,7 +66,7 @@
     }
 
     @Override
-    public SortedSet<E> elementSet() {
+    public NavigableSet<E> elementSet() {
       return new StandardElementSet();
     }
 
diff --git a/guava-tests/test/com/google/common/collect/ForwardingTestCase.java b/guava-tests/test/com/google/common/collect/ForwardingTestCase.java
index 15f89e5..31e54a3 100644
--- a/guava-tests/test/com/google/common/collect/ForwardingTestCase.java
+++ b/guava-tests/test/com/google/common/collect/ForwardingTestCase.java
@@ -115,6 +115,28 @@
       return Iterators.emptyModifiableIterator();
     } else if (returnType.isArray()) {
       return Array.newInstance(returnType.getComponentType(), 0);
+    } else if ("java.util.function.Predicate".equals(returnType.getCanonicalName())
+        || ("java.util.function.Consumer".equals(returnType.getCanonicalName()))) {
+      // Generally, methods that accept java.util.function.* instances
+      // don't like to get null values.  We generate them dynamically
+      // using Proxy so that we can have Java 7 compliant code.
+      InvocationHandler handler = new InvocationHandler() {
+          @Override public Object invoke(Object proxy, Method method,
+              Object[] args) {
+            // Crude, but acceptable until we can use Java 8.  Other
+            // methods have default implementations, and it is hard to
+            // distinguish.
+            if ("test".equals(method.getName())
+                || "accept".equals(method.getName())) {
+              return getDefaultValue(method.getReturnType());
+            }
+            throw new IllegalStateException(
+                "Unexpected " + method + " invoked on " + proxy);
+          }
+        };
+      return Proxy.newProxyInstance(returnType.getClassLoader(),
+          new Class[] { returnType },
+          handler);
     } else {
       return null;
     }
diff --git a/guava-tests/test/com/google/common/collect/ImmutableBiMapTest.java b/guava-tests/test/com/google/common/collect/ImmutableBiMapTest.java
index 3c7111a..8609e05 100644
--- a/guava-tests/test/com/google/common/collect/ImmutableBiMapTest.java
+++ b/guava-tests/test/com/google/common/collect/ImmutableBiMapTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -445,7 +445,7 @@
           ImmutableMap.of("one", 1, "two", 2, "three", 3, "four", 4));
       Set<String> keys = bimap.keySet();
       assertEquals(Sets.newHashSet("one", "two", "three", "four"), keys);
-      ASSERT.that(keys).has().exactly("one", "two", "three", "four").inOrder();
+      assertThat(keys).has().exactly("one", "two", "three", "four").inOrder();
     }
 
     public void testValues() {
@@ -453,7 +453,7 @@
           ImmutableMap.of("one", 1, "two", 2, "three", 3, "four", 4));
       Set<Integer> values = bimap.values();
       assertEquals(Sets.newHashSet(1, 2, 3, 4), values);
-      ASSERT.that(values).has().exactly(1, 2, 3, 4).inOrder();
+      assertThat(values).has().exactly(1, 2, 3, 4).inOrder();
     }
 
     public void testDoubleInverse() {
diff --git a/guava-tests/test/com/google/common/collect/ImmutableEnumMapTest.java b/guava-tests/test/com/google/common/collect/ImmutableEnumMapTest.java
index 3bcb17a..e8244a9 100644
--- a/guava-tests/test/com/google/common/collect/ImmutableEnumMapTest.java
+++ b/guava-tests/test/com/google/common/collect/ImmutableEnumMapTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -74,7 +74,7 @@
     ImmutableMap<AnEnum, String> map = Maps.immutableEnumMap(
         ImmutableMap.of(AnEnum.C, "c", AnEnum.A, "a", AnEnum.E, "e"));
 
-    ASSERT.that(map.entrySet()).has().exactly(
+    assertThat(map.entrySet()).has().exactly(
         Helpers.mapEntry(AnEnum.A, "a"),
         Helpers.mapEntry(AnEnum.C, "c"),
         Helpers.mapEntry(AnEnum.E, "e")).inOrder();
diff --git a/guava-tests/test/com/google/common/collect/ImmutableListMultimapTest.java b/guava-tests/test/com/google/common/collect/ImmutableListMultimapTest.java
index 3e680f1..b632735 100644
--- a/guava-tests/test/com/google/common/collect/ImmutableListMultimapTest.java
+++ b/guava-tests/test/com/google/common/collect/ImmutableListMultimapTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -263,10 +263,10 @@
     builder.put("a", 2);
     builder.put("b", 6);
     ImmutableListMultimap<String, Integer> multimap = builder.build();
-    ASSERT.that(multimap.keySet()).has().exactly("d", "c", "b", "a").inOrder();
-    ASSERT.that(multimap.values()).has().exactly(2, 4, 3, 6, 5, 2).inOrder();
-    ASSERT.that(multimap.get("a")).has().exactly(5, 2).inOrder();
-    ASSERT.that(multimap.get("b")).has().exactly(3, 6).inOrder();
+    assertThat(multimap.keySet()).has().exactly("d", "c", "b", "a").inOrder();
+    assertThat(multimap.values()).has().exactly(2, 4, 3, 6, 5, 2).inOrder();
+    assertThat(multimap.get("a")).has().exactly(5, 2).inOrder();
+    assertThat(multimap.get("b")).has().exactly(3, 6).inOrder();
   }
 
   public void testBuilderOrderKeysByDuplicates() {
@@ -285,10 +285,10 @@
     builder.put("a", 2);
     builder.put("bb", 6);
     ImmutableListMultimap<String, Integer> multimap = builder.build();
-    ASSERT.that(multimap.keySet()).has().exactly("d", "a", "bb", "cc").inOrder();
-    ASSERT.that(multimap.values()).has().exactly(2, 5, 2, 3, 6, 4).inOrder();
-    ASSERT.that(multimap.get("a")).has().exactly(5, 2).inOrder();
-    ASSERT.that(multimap.get("bb")).has().exactly(3, 6).inOrder();
+    assertThat(multimap.keySet()).has().exactly("d", "a", "bb", "cc").inOrder();
+    assertThat(multimap.values()).has().exactly(2, 5, 2, 3, 6, 4).inOrder();
+    assertThat(multimap.get("a")).has().exactly(5, 2).inOrder();
+    assertThat(multimap.get("bb")).has().exactly(3, 6).inOrder();
   }
 
   public void testBuilderOrderValuesBy() {
@@ -302,10 +302,10 @@
     builder.put("a", 2);
     builder.put("b", 6);
     ImmutableListMultimap<String, Integer> multimap = builder.build();
-    ASSERT.that(multimap.keySet()).has().exactly("b", "d", "a", "c").inOrder();
-    ASSERT.that(multimap.values()).has().exactly(6, 3, 2, 5, 2, 4).inOrder();
-    ASSERT.that(multimap.get("a")).has().exactly(5, 2).inOrder();
-    ASSERT.that(multimap.get("b")).has().exactly(6, 3).inOrder();
+    assertThat(multimap.keySet()).has().exactly("b", "d", "a", "c").inOrder();
+    assertThat(multimap.values()).has().exactly(6, 3, 2, 5, 2, 4).inOrder();
+    assertThat(multimap.get("a")).has().exactly(5, 2).inOrder();
+    assertThat(multimap.get("b")).has().exactly(6, 3).inOrder();
   }
 
   public void testBuilderOrderKeysAndValuesBy() {
@@ -320,10 +320,10 @@
     builder.put("a", 2);
     builder.put("b", 6);
     ImmutableListMultimap<String, Integer> multimap = builder.build();
-    ASSERT.that(multimap.keySet()).has().exactly("d", "c", "b", "a").inOrder();
-    ASSERT.that(multimap.values()).has().exactly(2, 4, 6, 3, 5, 2).inOrder();
-    ASSERT.that(multimap.get("a")).has().exactly(5, 2).inOrder();
-    ASSERT.that(multimap.get("b")).has().exactly(6, 3).inOrder();
+    assertThat(multimap.keySet()).has().exactly("d", "c", "b", "a").inOrder();
+    assertThat(multimap.values()).has().exactly(2, 4, 6, 3, 5, 2).inOrder();
+    assertThat(multimap.get("a")).has().exactly(5, 2).inOrder();
+    assertThat(multimap.get("b")).has().exactly(6, 3).inOrder();
   }
 
   public void testCopyOf() {
diff --git a/guava-tests/test/com/google/common/collect/ImmutableMultisetTest.java b/guava-tests/test/com/google/common/collect/ImmutableMultisetTest.java
index 5e94ac3..a0ad481 100644
--- a/guava-tests/test/com/google/common/collect/ImmutableMultisetTest.java
+++ b/guava-tests/test/com/google/common/collect/ImmutableMultisetTest.java
@@ -17,8 +17,8 @@
 package com.google.common.collect;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -452,7 +452,7 @@
   public void testSerialization_multiple() {
     Collection<String> c = ImmutableMultiset.of("a", "b", "a");
     Collection<String> copy = SerializableTester.reserializeAndAssert(c);
-    ASSERT.that(copy).has().exactly("a", "a", "b").inOrder();
+    assertThat(copy).has().exactly("a", "a", "b").inOrder();
   }
 
   @GwtIncompatible("SerializableTester")
@@ -460,7 +460,7 @@
     Multiset<String> c = ImmutableMultiset.of("a", "b", "a");
     Collection<String> copy =
         LenientSerializableTester.reserializeAndAssertLenient(c.elementSet());
-    ASSERT.that(copy).has().exactly("a", "b").inOrder();
+    assertThat(copy).has().exactly("a", "b").inOrder();
   }
 
   @GwtIncompatible("SerializableTester")
@@ -473,13 +473,13 @@
     Collection<String> c = ImmutableMultiset.of("a", "b", "a");
     assertEquals(c, ImmutableMultiset.of("a", "b", "a"));
     assertEquals(c, ImmutableMultiset.of("a", "a", "b"));
-    ASSERT.that(c).isNotEqualTo(ImmutableMultiset.of("a", "b"));
-    ASSERT.that(c).isNotEqualTo(ImmutableMultiset.of("a", "b", "c", "d"));
+    assertThat(c).isNotEqualTo(ImmutableMultiset.of("a", "b"));
+    assertThat(c).isNotEqualTo(ImmutableMultiset.of("a", "b", "c", "d"));
   }
 
   public void testIterationOrder() {
     Collection<String> c = ImmutableMultiset.of("a", "b", "a");
-    ASSERT.that(c).has().exactly("a", "a", "b").inOrder();
+    assertThat(c).has().exactly("a", "a", "b").inOrder();
   }
 
   public void testMultisetWrites() {
diff --git a/guava-tests/test/com/google/common/collect/ImmutableRangeMapTest.java b/guava-tests/test/com/google/common/collect/ImmutableRangeMapTest.java
new file mode 100644
index 0000000..3d1d7b4
--- /dev/null
+++ b/guava-tests/test/com/google/common/collect/ImmutableRangeMapTest.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2012 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.common.collect;
+
+import static com.google.common.collect.BoundType.OPEN;
+
+import com.google.common.annotations.GwtIncompatible;
+
+import junit.framework.TestCase;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NoSuchElementException;
+
+/**
+ * Tests for {@code ImmutableRangeMap}.
+ *
+ * @author Louis Wasserman
+ */
+@GwtIncompatible("NavigableMap")
+public class ImmutableRangeMapTest extends TestCase {
+  private static final ImmutableList<Range<Integer>> RANGES;
+  private static final int MIN_BOUND = 0;
+  private static final int MAX_BOUND = 10;
+  static {
+    ImmutableList.Builder<Range<Integer>> builder = ImmutableList.builder();
+
+    builder.add(Range.<Integer>all());
+
+    // Add one-ended ranges
+    for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
+      for (BoundType type : BoundType.values()) {
+        builder.add(Range.upTo(i, type));
+        builder.add(Range.downTo(i, type));
+      }
+    }
+
+    // Add two-ended ranges
+    for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
+      for (int j = i + 1; j <= MAX_BOUND; j++) {
+        for (BoundType lowerType : BoundType.values()) {
+          for (BoundType upperType : BoundType.values()) {
+            if (i == j & lowerType == OPEN & upperType == OPEN) {
+              continue;
+            }
+            builder.add(Range.range(i, lowerType, j, upperType));
+          }
+        }
+      }
+    }
+    RANGES = builder.build();
+  }
+
+  public void testBuilderRejectsEmptyRanges() {
+    for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
+      ImmutableRangeMap.Builder<Integer, Integer> builder = ImmutableRangeMap.builder();
+      try {
+        builder.put(Range.closedOpen(i, i), 1);
+        fail("Expected IllegalArgumentException");
+      } catch (IllegalArgumentException expected) {
+        // success
+      }
+      try {
+        builder.put(Range.openClosed(i, i), 1);
+        fail("Expected IllegalArgumentException");
+      } catch (IllegalArgumentException expected) {
+      }
+    }
+  }
+
+  public void testOverlapRejection() {
+    for (Range<Integer> range1 : RANGES) {
+      for (Range<Integer> range2 : RANGES) {
+        boolean expectRejection =
+            range1.isConnected(range2) && !range1.intersection(range2).isEmpty();
+        ImmutableRangeMap.Builder<Integer, Integer> builder = ImmutableRangeMap.builder();
+        builder.put(range1, 1);
+        try {
+          builder.put(range2, 2);
+          assertFalse(expectRejection);
+        } catch (IllegalArgumentException e) {
+          assertTrue(expectRejection);
+        }
+      }
+    }
+  }
+
+  public void testGet() {
+    for (Range<Integer> range1 : RANGES) {
+      for (Range<Integer> range2 : RANGES) {
+        if (!range1.isConnected(range2) || range1.intersection(range2).isEmpty()) {
+          ImmutableRangeMap<Integer, Integer> rangeMap =
+              ImmutableRangeMap.<Integer, Integer>builder().put(range1, 1).put(range2, 2).build();
+
+          for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
+            Integer expectedValue = null;
+            if (range1.contains(i)) {
+              expectedValue = 1;
+            } else if (range2.contains(i)) {
+              expectedValue = 2;
+            }
+
+            assertEquals(expectedValue, rangeMap.get(i));
+          }
+        }
+      }
+    }
+  }
+
+  public void testSpanEmpty() {
+    try {
+      ImmutableRangeMap.of().span();
+      fail("Expected NoSuchElementException");
+    } catch (NoSuchElementException expected) {
+    }
+  }
+
+  public void testSpanSingleRange() {
+    for (Range<Integer> range : RANGES) {
+      RangeMap<Integer, Integer> rangemap =
+          ImmutableRangeMap.<Integer, Integer>builder().put(range, 1).build();
+      assertEquals(range, rangemap.span());
+    }
+  }
+
+  public void testSpanTwoRanges() {
+    for (Range<Integer> range1 : RANGES) {
+      for (Range<Integer> range2 : RANGES) {
+        if (!range1.isConnected(range2) || range1.intersection(range2).isEmpty()) {
+          RangeMap<Integer, Integer> rangemap =
+              ImmutableRangeMap.<Integer, Integer>builder().put(range1, 1).put(range2, 2).build();
+          assertEquals(range1.span(range2), rangemap.span());
+        }
+      }
+    }
+  }
+
+  public void testGetEntry() {
+    for (Range<Integer> range1 : RANGES) {
+      for (Range<Integer> range2 : RANGES) {
+        if (!range1.isConnected(range2) || range1.intersection(range2).isEmpty()) {
+          ImmutableRangeMap<Integer, Integer> rangeMap =
+              ImmutableRangeMap.<Integer, Integer>builder().put(range1, 1).put(range2, 2).build();
+
+          for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
+            Entry<Range<Integer>, Integer> expectedEntry = null;
+            if (range1.contains(i)) {
+              expectedEntry = Maps.immutableEntry(range1, 1);
+            } else if (range2.contains(i)) {
+              expectedEntry = Maps.immutableEntry(range2, 2);
+            }
+
+            assertEquals(expectedEntry, rangeMap.getEntry(i));
+          }
+        }
+      }
+    }
+  }
+
+  public void testGetLargeRangeMap() {
+    ImmutableRangeMap.Builder<Integer, Integer> builder = ImmutableRangeMap.builder();
+    for (int i = 0; i < 100; i++) {
+      builder.put(Range.closedOpen(i, i + 1), i);
+    }
+    ImmutableRangeMap<Integer, Integer> map = builder.build();
+    for (int i = 0; i < 100; i++) {
+      assertEquals(Integer.valueOf(i), map.get(i));
+    }
+  }
+
+  public void testAsMapOfRanges() {
+    for (Range<Integer> range1 : RANGES) {
+      for (Range<Integer> range2 : RANGES) {
+        if (!range1.isConnected(range2) || range1.intersection(range2).isEmpty()) {
+          ImmutableRangeMap<Integer, Integer> rangeMap =
+              ImmutableRangeMap.<Integer, Integer>builder().put(range1, 1).put(range2, 2).build();
+
+          ImmutableMap<Range<Integer>, Integer> expectedAsMap =
+              ImmutableMap.of(range1, 1, range2, 2);
+          ImmutableMap<Range<Integer>, Integer> asMap = rangeMap.asMapOfRanges();
+          assertEquals(expectedAsMap, asMap);
+
+          for (Range<Integer> query : RANGES) {
+            assertEquals(expectedAsMap.get(query), asMap.get(query));
+          }
+        }
+      }
+    }
+  }
+
+  public void testSubRangeMap() {
+    for (Range<Integer> range1 : RANGES) {
+      for (Range<Integer> range2 : RANGES) {
+        if (!range1.isConnected(range2) || range1.intersection(range2).isEmpty()) {
+          for (Range<Integer> subRange : RANGES) {
+            ImmutableRangeMap<Integer, Integer> rangeMap =
+                ImmutableRangeMap.<Integer, Integer>builder()
+                  .put(range1, 1).put(range2, 2).build();
+
+            ImmutableRangeMap.Builder<Integer, Integer> expectedBuilder =
+                ImmutableRangeMap.builder();
+            for (Map.Entry<Range<Integer>, Integer> entry : rangeMap.asMapOfRanges().entrySet()) {
+              if (entry.getKey().isConnected(subRange)
+                  && !entry.getKey().intersection(subRange).isEmpty()) {
+                expectedBuilder.put(entry.getKey().intersection(subRange), entry.getValue());
+              }
+            }
+
+            ImmutableRangeMap<Integer, Integer> expected = expectedBuilder.build();
+            assertEquals(expected, rangeMap.subRangeMap(subRange));
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/guava-tests/test/com/google/common/collect/ImmutableRangeSetTest.java b/guava-tests/test/com/google/common/collect/ImmutableRangeSetTest.java
new file mode 100644
index 0000000..cf7843b
--- /dev/null
+++ b/guava-tests/test/com/google/common/collect/ImmutableRangeSetTest.java
@@ -0,0 +1,508 @@
+/*
+ * Copyright (C) 2012 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.common.collect;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.collect.testing.NavigableSetTestSuiteBuilder;
+import com.google.common.collect.testing.SampleElements;
+import com.google.common.collect.testing.TestSetGenerator;
+import com.google.common.collect.testing.features.CollectionFeature;
+import com.google.common.collect.testing.features.CollectionSize;
+import com.google.common.testing.SerializableTester;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import java.math.BigInteger;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Tests for {@link ImmutableRangeSet}.
+ *
+ * @author Louis Wasserman
+ */
+@GwtIncompatible("ImmutableRangeSet")
+public class ImmutableRangeSetTest extends AbstractRangeSetTest {
+  @SuppressWarnings("unchecked") // varargs
+  private static final ImmutableSet<Range<Integer>> RANGES = ImmutableSet.of(
+      Range.<Integer>all(),
+      Range.closedOpen(3, 5),
+      Range.singleton(1),
+      Range.lessThan(2),
+      Range.greaterThan(10),
+      Range.atMost(4),
+      Range.atLeast(3),
+      Range.closed(4, 6),
+      Range.closedOpen(1, 3),
+      Range.openClosed(5, 7),
+      Range.open(3, 4));
+  
+  static final class ImmutableRangeSetIntegerAsSetGenerator implements TestSetGenerator<Integer> {
+    @Override
+    public SampleElements<Integer> samples() {
+      return new SampleElements<Integer>(1, 4, 3, 2, 5);
+    }
+
+    @Override
+    public Integer[] createArray(int length) {
+      return new Integer[length];
+    }
+
+    @Override
+    public Iterable<Integer> order(List<Integer> insertionOrder) {
+      return Ordering.natural().sortedCopy(insertionOrder);
+    }
+
+    @Override
+    public Set<Integer> create(Object... elements) {
+      ImmutableRangeSet.Builder<Integer> builder = ImmutableRangeSet.builder();
+      for (Object o : elements) {
+        Integer i = (Integer) o;
+        builder.add(Range.singleton(i));
+      }
+      return builder.build().asSet(DiscreteDomain.integers());
+    }
+  }
+
+  static final class ImmutableRangeSetBigIntegerAsSetGenerator
+      implements TestSetGenerator<BigInteger> {
+    @Override
+    public SampleElements<BigInteger> samples() {
+      return new SampleElements<BigInteger>(
+          BigInteger.valueOf(1),
+          BigInteger.valueOf(4),
+          BigInteger.valueOf(3),
+          BigInteger.valueOf(2),
+          BigInteger.valueOf(5));
+    }
+
+    @Override
+    public BigInteger[] createArray(int length) {
+      return new BigInteger[length];
+    }
+
+    @Override
+    public Iterable<BigInteger> order(List<BigInteger> insertionOrder) {
+      return Ordering.natural().sortedCopy(insertionOrder);
+    }
+
+    @Override
+    public Set<BigInteger> create(Object... elements) {
+      ImmutableRangeSet.Builder<BigInteger> builder = ImmutableRangeSet.builder();
+      for (Object o : elements) {
+        BigInteger i = (BigInteger) o;
+        builder.add(Range.closedOpen(i, i.add(BigInteger.ONE)));
+      }
+      return builder.build().asSet(DiscreteDomain.bigIntegers());
+    }
+  }
+
+  public static Test suite() {
+    TestSuite suite = new TestSuite();
+    suite.addTestSuite(ImmutableRangeSetTest.class);
+    suite.addTest(NavigableSetTestSuiteBuilder.using(new ImmutableRangeSetIntegerAsSetGenerator())
+        .named("ImmutableRangeSet.asSet[DiscreteDomain.integers[]]")
+        .withFeatures(
+            CollectionSize.ANY,
+            CollectionFeature.REJECTS_DUPLICATES_AT_CREATION,
+            CollectionFeature.ALLOWS_NULL_QUERIES,
+            CollectionFeature.KNOWN_ORDER,
+            CollectionFeature.NON_STANDARD_TOSTRING,
+            CollectionFeature.SERIALIZABLE)
+        .createTestSuite());
+
+    suite.addTest(NavigableSetTestSuiteBuilder.using(
+          new ImmutableRangeSetBigIntegerAsSetGenerator())
+        .named("ImmutableRangeSet.asSet[DiscreteDomain.bigIntegers[]]")
+        .withFeatures(
+            CollectionSize.ANY,
+            CollectionFeature.REJECTS_DUPLICATES_AT_CREATION,
+            CollectionFeature.ALLOWS_NULL_QUERIES,
+            CollectionFeature.KNOWN_ORDER,
+            CollectionFeature.NON_STANDARD_TOSTRING,
+            CollectionFeature.SERIALIZABLE)
+        .createTestSuite());
+    return suite;
+  }
+
+  public void testEmpty() {
+    ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.of();
+
+    assertThat(rangeSet.asRanges()).isEmpty();
+    assertEquals(ImmutableRangeSet.<Integer>all(), rangeSet.complement());
+    assertFalse(rangeSet.contains(0));
+    assertFalse(rangeSet.encloses(Range.singleton(0)));
+    assertTrue(rangeSet.enclosesAll(rangeSet));
+    assertTrue(rangeSet.isEmpty());
+  }
+
+  public void testAll() {
+    ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.all();
+
+    assertThat(rangeSet.asRanges()).has().item(Range.<Integer>all());
+    assertTrue(rangeSet.contains(0));
+    assertTrue(rangeSet.encloses(Range.<Integer>all()));
+    assertTrue(rangeSet.enclosesAll(rangeSet));
+    assertEquals(ImmutableRangeSet.<Integer>of(), rangeSet.complement());
+  }
+
+  public void testSingleBoundedRange() {
+    ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.of(Range.closedOpen(1, 5));
+
+    assertThat(rangeSet.asRanges()).has().item(Range.closedOpen(1, 5));
+
+    assertTrue(rangeSet.encloses(Range.closed(3, 4)));
+    assertTrue(rangeSet.encloses(Range.closedOpen(1, 4)));
+    assertTrue(rangeSet.encloses(Range.closedOpen(1, 5)));
+    assertFalse(rangeSet.encloses(Range.greaterThan(2)));
+
+    assertTrue(rangeSet.contains(3));
+    assertFalse(rangeSet.contains(5));
+    assertFalse(rangeSet.contains(0));
+
+    RangeSet<Integer> expectedComplement = TreeRangeSet.create();
+    expectedComplement.add(Range.lessThan(1));
+    expectedComplement.add(Range.atLeast(5));
+
+    assertEquals(expectedComplement, rangeSet.complement());
+  }
+
+  public void testSingleBoundedBelowRange() {
+    ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.of(Range.greaterThan(2));
+
+    assertThat(rangeSet.asRanges()).has().item(Range.greaterThan(2));
+
+    assertTrue(rangeSet.encloses(Range.closed(3, 4)));
+    assertTrue(rangeSet.encloses(Range.greaterThan(3)));
+    assertFalse(rangeSet.encloses(Range.closedOpen(1, 5)));
+
+    assertTrue(rangeSet.contains(3));
+    assertTrue(rangeSet.contains(5));
+    assertFalse(rangeSet.contains(0));
+    assertFalse(rangeSet.contains(2));
+
+    assertEquals(ImmutableRangeSet.of(Range.atMost(2)), rangeSet.complement());
+  }
+
+  public void testSingleBoundedAboveRange() {
+    ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.of(Range.atMost(3));
+
+    assertThat(rangeSet.asRanges()).has().item(Range.atMost(3));
+
+    assertTrue(rangeSet.encloses(Range.closed(2, 3)));
+    assertTrue(rangeSet.encloses(Range.lessThan(1)));
+    assertFalse(rangeSet.encloses(Range.closedOpen(1, 5)));
+
+    assertTrue(rangeSet.contains(3));
+    assertTrue(rangeSet.contains(0));
+    assertFalse(rangeSet.contains(4));
+    assertFalse(rangeSet.contains(5));
+
+    assertEquals(ImmutableRangeSet.of(Range.greaterThan(3)), rangeSet.complement());
+  }
+
+  public void testMultipleBoundedRanges() {
+    ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder()
+        .add(Range.closed(5, 8)).add(Range.closedOpen(1, 3)).build();
+
+    assertThat(rangeSet.asRanges())
+        .has().exactly(Range.closedOpen(1, 3), Range.closed(5, 8)).inOrder();
+
+    assertTrue(rangeSet.encloses(Range.closed(1, 2)));
+    assertTrue(rangeSet.encloses(Range.open(5, 8)));
+    assertFalse(rangeSet.encloses(Range.closed(1, 8)));
+    assertFalse(rangeSet.encloses(Range.greaterThan(5)));
+
+    RangeSet<Integer> expectedComplement = ImmutableRangeSet.<Integer>builder()
+        .add(Range.lessThan(1))
+        .add(Range.closedOpen(3, 5))
+        .add(Range.greaterThan(8))
+        .build();
+
+    assertEquals(expectedComplement, rangeSet.complement());
+  }
+
+  public void testMultipleBoundedBelowRanges() {
+    ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder()
+        .add(Range.greaterThan(6)).add(Range.closedOpen(1, 3)).build();
+
+    assertThat(rangeSet.asRanges())
+        .has().exactly(Range.closedOpen(1, 3), Range.greaterThan(6)).inOrder();
+
+    assertTrue(rangeSet.encloses(Range.closed(1, 2)));
+    assertTrue(rangeSet.encloses(Range.open(6, 8)));
+    assertFalse(rangeSet.encloses(Range.closed(1, 8)));
+    assertFalse(rangeSet.encloses(Range.greaterThan(5)));
+
+    RangeSet<Integer> expectedComplement = ImmutableRangeSet.<Integer>builder()
+        .add(Range.lessThan(1))
+        .add(Range.closed(3, 6))
+        .build();
+
+    assertEquals(expectedComplement, rangeSet.complement());
+  }
+
+  public void testMultipleBoundedAboveRanges() {
+    ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder()
+        .add(Range.atMost(0)).add(Range.closedOpen(2, 5)).build();
+
+    assertThat(rangeSet.asRanges())
+        .has().exactly(Range.atMost(0), Range.closedOpen(2, 5)).inOrder();
+
+    assertTrue(rangeSet.encloses(Range.closed(2, 4)));
+    assertTrue(rangeSet.encloses(Range.open(-5, -2)));
+    assertFalse(rangeSet.encloses(Range.closed(1, 8)));
+    assertFalse(rangeSet.encloses(Range.greaterThan(5)));
+
+    RangeSet<Integer> expectedComplement = ImmutableRangeSet.<Integer>builder()
+        .add(Range.open(0, 2))
+        .add(Range.atLeast(5))
+        .build();
+
+    assertEquals(expectedComplement, rangeSet.complement());
+  }
+
+  public void testAddUnsupported() {
+    ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder()
+        .add(Range.closed(5, 8)).add(Range.closedOpen(1, 3)).build();
+
+    try {
+      rangeSet.add(Range.open(3, 4));
+      fail();
+    } catch (UnsupportedOperationException expected) {
+      // success
+    }
+  }
+
+  public void testAddAllUnsupported() {
+    ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder()
+        .add(Range.closed(5, 8)).add(Range.closedOpen(1, 3)).build();
+
+    try {
+      rangeSet.addAll(ImmutableRangeSet.<Integer>of());
+      fail();
+    } catch (UnsupportedOperationException expected) {
+      // success
+    }
+  }
+
+  public void testRemoveUnsupported() {
+    ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder()
+        .add(Range.closed(5, 8)).add(Range.closedOpen(1, 3)).build();
+
+    try {
+      rangeSet.remove(Range.closed(6, 7));
+      fail();
+    } catch (UnsupportedOperationException expected) {
+      // success
+    }
+  }
+
+  public void testRemoveAllUnsupported() {
+    ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder()
+        .add(Range.closed(5, 8)).add(Range.closedOpen(1, 3)).build();
+
+    try {
+      rangeSet.removeAll(ImmutableRangeSet.<Integer>of());
+      fail();
+    } catch (UnsupportedOperationException expected) {
+      // success
+    }
+
+    try {
+      rangeSet.removeAll(ImmutableRangeSet.of(Range.closed(6, 8)));
+      fail();
+    } catch (UnsupportedOperationException expected) {
+      // success
+    }
+  }
+
+  public void testExhaustive() {
+    @SuppressWarnings("unchecked")
+    ImmutableSet<Range<Integer>> ranges = ImmutableSet.of(
+        Range.<Integer>all(),
+        Range.<Integer>closedOpen(3, 5),
+        Range.singleton(1),
+        Range.lessThan(2),
+        Range.greaterThan(10),
+        Range.atMost(4),
+        Range.atLeast(3),
+        Range.closed(4, 6),
+        Range.closedOpen(1, 3),
+        Range.openClosed(5, 7),
+        Range.open(3, 4));
+    for (Set<Range<Integer>> subset : Sets.powerSet(ranges)) {
+      RangeSet<Integer> mutable = TreeRangeSet.create();
+      ImmutableRangeSet.Builder<Integer> builder = ImmutableRangeSet.builder();
+
+      int expectedRanges = 0;
+      for (Range<Integer> range : subset) {
+        boolean overlaps = false;
+        for (Range<Integer> other : mutable.asRanges()) {
+          if (other.isConnected(range) && !other.intersection(range).isEmpty()) {
+            overlaps = true;
+          }
+        }
+
+        try {
+          builder.add(range);
+          assertFalse(overlaps);
+          mutable.add(range);
+        } catch (IllegalArgumentException e) {
+          assertTrue(overlaps);
+        }
+      }
+
+      ImmutableRangeSet<Integer> built = builder.build();
+      assertEquals(mutable, built);
+      assertEquals(ImmutableRangeSet.copyOf(mutable), built);
+      assertEquals(mutable.complement(), built.complement());
+
+      for (int i = 0; i <= 11; i++) {
+        assertEquals(mutable.contains(i), built.contains(i));
+      }
+
+      SerializableTester.reserializeAndAssert(built);
+    }
+  }
+
+  public void testAsSet() {
+    ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder()
+        .add(Range.closed(2, 4))
+        .add(Range.open(6, 7))
+        .add(Range.closedOpen(8, 10))
+        .add(Range.openClosed(15, 17))
+        .build();
+    ImmutableSortedSet<Integer> expectedSet = ImmutableSortedSet.of(2, 3, 4, 8, 9, 16, 17);
+    ImmutableSortedSet<Integer> asSet = rangeSet.asSet(DiscreteDomain.integers());
+    assertEquals(expectedSet, asSet);
+    assertThat(asSet).has().exactlyAs(expectedSet).inOrder();
+    assertTrue(asSet.containsAll(expectedSet));
+    SerializableTester.reserializeAndAssert(asSet);
+  }
+
+  public void testAsSetHeadSet() {
+    ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder()
+        .add(Range.closed(2, 4))
+        .add(Range.open(6, 7))
+        .add(Range.closedOpen(8, 10))
+        .add(Range.openClosed(15, 17))
+        .build();
+
+    ImmutableSortedSet<Integer> expectedSet = ImmutableSortedSet.of(2, 3, 4, 8, 9, 16, 17);
+    ImmutableSortedSet<Integer> asSet = rangeSet.asSet(DiscreteDomain.integers());
+
+    for (int i = 0; i <= 20; i++) {
+      assertEquals(asSet.headSet(i, false), expectedSet.headSet(i, false));
+      assertEquals(asSet.headSet(i, true), expectedSet.headSet(i, true));
+    }
+  }
+
+  public void testAsSetTailSet() {
+    ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder()
+        .add(Range.closed(2, 4))
+        .add(Range.open(6, 7))
+        .add(Range.closedOpen(8, 10))
+        .add(Range.openClosed(15, 17))
+        .build();
+
+    ImmutableSortedSet<Integer> expectedSet = ImmutableSortedSet.of(2, 3, 4, 8, 9, 16, 17);
+    ImmutableSortedSet<Integer> asSet = rangeSet.asSet(DiscreteDomain.integers());
+
+    for (int i = 0; i <= 20; i++) {
+      assertEquals(asSet.tailSet(i, false), expectedSet.tailSet(i, false));
+      assertEquals(asSet.tailSet(i, true), expectedSet.tailSet(i, true));
+    }
+  }
+
+  public void testAsSetSubSet() {
+    ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder()
+        .add(Range.closed(2, 4))
+        .add(Range.open(6, 7))
+        .add(Range.closedOpen(8, 10))
+        .add(Range.openClosed(15, 17))
+        .build();
+
+    ImmutableSortedSet<Integer> expectedSet = ImmutableSortedSet.of(2, 3, 4, 8, 9, 16, 17);
+    ImmutableSortedSet<Integer> asSet = rangeSet.asSet(DiscreteDomain.integers());
+
+    for (int i = 0; i <= 20; i++) {
+      for (int j = i + 1; j <= 20; j++) {
+        assertEquals(expectedSet.subSet(i, false, j, false),
+            asSet.subSet(i, false, j, false));
+        assertEquals(expectedSet.subSet(i, true, j, false),
+            asSet.subSet(i, true, j, false));
+        assertEquals(expectedSet.subSet(i, false, j, true),
+            asSet.subSet(i, false, j, true));
+        assertEquals(expectedSet.subSet(i, true, j, true),
+            asSet.subSet(i, true, j, true));
+      }
+    }
+  }
+  
+  public void testSubRangeSet() {
+    ImmutableList.Builder<Range<Integer>> rangesBuilder = ImmutableList.builder();
+    rangesBuilder.add(Range.<Integer>all());
+    for (int i = -2; i <= 2; i++) {
+      for (BoundType boundType : BoundType.values()) {
+        rangesBuilder.add(Range.upTo(i, boundType));
+        rangesBuilder.add(Range.downTo(i, boundType));
+      }
+      for (int j = i + 1; j <= 2; j++) {
+        for (BoundType lbType : BoundType.values()) {
+          for (BoundType ubType : BoundType.values()) {
+            rangesBuilder.add(Range.range(i, lbType, j, ubType));
+          }
+        }
+      }
+    }
+    ImmutableList<Range<Integer>> ranges = rangesBuilder.build();
+    for (int i = -2; i <= 2; i++) {
+      rangesBuilder.add(Range.closedOpen(i, i));
+      rangesBuilder.add(Range.openClosed(i, i));
+    }
+    ImmutableList<Range<Integer>> subRanges = rangesBuilder.build();
+    for (Range<Integer> range1 : ranges) {
+      for (Range<Integer> range2 : ranges) {
+        if (!range1.isConnected(range2) || range1.intersection(range2).isEmpty()) {
+          ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder()
+              .add(range1)
+              .add(range2)
+              .build();
+          for (Range<Integer> subRange : subRanges) {
+            RangeSet<Integer> expected = TreeRangeSet.create();
+            for (Range<Integer> range : rangeSet.asRanges()) {
+              if (range.isConnected(subRange)) {
+                expected.add(range.intersection(subRange));
+              }
+            }
+            ImmutableRangeSet<Integer> subRangeSet = rangeSet.subRangeSet(subRange);
+            assertEquals(expected, subRangeSet);
+            assertEquals(expected.asRanges(), subRangeSet.asRanges());
+            if (!expected.isEmpty()) {
+              assertEquals(expected.span(), subRangeSet.span());
+            }
+            for (int i = -3; i <= 3; i++) {
+              assertEquals(expected.contains(i), subRangeSet.contains(i));
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/guava-tests/test/com/google/common/collect/ImmutableSetMultimapTest.java b/guava-tests/test/com/google/common/collect/ImmutableSetMultimapTest.java
index 6621483..cf50625 100644
--- a/guava-tests/test/com/google/common/collect/ImmutableSetMultimapTest.java
+++ b/guava-tests/test/com/google/common/collect/ImmutableSetMultimapTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -249,10 +249,10 @@
     builder.put("a", 2);
     builder.put("b", 6);
     ImmutableSetMultimap<String, Integer> multimap = builder.build();
-    ASSERT.that(multimap.keySet()).has().exactly("d", "c", "b", "a").inOrder();
-    ASSERT.that(multimap.values()).has().exactly(2, 4, 3, 6, 5, 2).inOrder();
-    ASSERT.that(multimap.get("a")).has().exactly(5, 2).inOrder();
-    ASSERT.that(multimap.get("b")).has().exactly(3, 6).inOrder();
+    assertThat(multimap.keySet()).has().exactly("d", "c", "b", "a").inOrder();
+    assertThat(multimap.values()).has().exactly(2, 4, 3, 6, 5, 2).inOrder();
+    assertThat(multimap.get("a")).has().exactly(5, 2).inOrder();
+    assertThat(multimap.get("b")).has().exactly(3, 6).inOrder();
     assertFalse(multimap.get("a") instanceof ImmutableSortedSet);
     assertFalse(multimap.get("x") instanceof ImmutableSortedSet);
     assertFalse(multimap.asMap().get("a") instanceof ImmutableSortedSet);
@@ -274,10 +274,10 @@
     builder.put("a", 2);
     builder.put("bb", 6);
     ImmutableSetMultimap<String, Integer> multimap = builder.build();
-    ASSERT.that(multimap.keySet()).has().exactly("d", "a", "bb", "cc").inOrder();
-    ASSERT.that(multimap.values()).has().exactly(2, 5, 2, 3, 6, 4).inOrder();
-    ASSERT.that(multimap.get("a")).has().exactly(5, 2).inOrder();
-    ASSERT.that(multimap.get("bb")).has().exactly(3, 6).inOrder();
+    assertThat(multimap.keySet()).has().exactly("d", "a", "bb", "cc").inOrder();
+    assertThat(multimap.values()).has().exactly(2, 5, 2, 3, 6, 4).inOrder();
+    assertThat(multimap.get("a")).has().exactly(5, 2).inOrder();
+    assertThat(multimap.get("bb")).has().exactly(3, 6).inOrder();
     assertFalse(multimap.get("a") instanceof ImmutableSortedSet);
     assertFalse(multimap.get("x") instanceof ImmutableSortedSet);
     assertFalse(multimap.asMap().get("a") instanceof ImmutableSortedSet);
@@ -294,10 +294,10 @@
     builder.put("a", 2);
     builder.put("b", 6);
     ImmutableSetMultimap<String, Integer> multimap = builder.build();
-    ASSERT.that(multimap.keySet()).has().exactly("b", "d", "a", "c").inOrder();
-    ASSERT.that(multimap.values()).has().exactly(6, 3, 2, 5, 2, 4).inOrder();
-    ASSERT.that(multimap.get("a")).has().exactly(5, 2).inOrder();
-    ASSERT.that(multimap.get("b")).has().exactly(6, 3).inOrder();
+    assertThat(multimap.keySet()).has().exactly("b", "d", "a", "c").inOrder();
+    assertThat(multimap.values()).has().exactly(6, 3, 2, 5, 2, 4).inOrder();
+    assertThat(multimap.get("a")).has().exactly(5, 2).inOrder();
+    assertThat(multimap.get("b")).has().exactly(6, 3).inOrder();
     assertTrue(multimap.get("a") instanceof ImmutableSortedSet);
     assertEquals(Collections.reverseOrder(),
         ((ImmutableSortedSet<Integer>) multimap.get("a")).comparator());
@@ -321,10 +321,10 @@
     builder.put("a", 2);
     builder.put("b", 6);
     ImmutableSetMultimap<String, Integer> multimap = builder.build();
-    ASSERT.that(multimap.keySet()).has().exactly("d", "c", "b", "a").inOrder();
-    ASSERT.that(multimap.values()).has().exactly(2, 4, 6, 3, 5, 2).inOrder();
-    ASSERT.that(multimap.get("a")).has().exactly(5, 2).inOrder();
-    ASSERT.that(multimap.get("b")).has().exactly(6, 3).inOrder();
+    assertThat(multimap.keySet()).has().exactly("d", "c", "b", "a").inOrder();
+    assertThat(multimap.values()).has().exactly(2, 4, 6, 3, 5, 2).inOrder();
+    assertThat(multimap.get("a")).has().exactly(5, 2).inOrder();
+    assertThat(multimap.get("b")).has().exactly(6, 3).inOrder();
     assertTrue(multimap.get("a") instanceof ImmutableSortedSet);
     assertEquals(Collections.reverseOrder(),
         ((ImmutableSortedSet<Integer>) multimap.get("a")).comparator());
@@ -536,8 +536,8 @@
         .put("b", 1)
         .build();
     multimap = SerializableTester.reserialize(multimap);
-    ASSERT.that(multimap.keySet()).has().exactly("b", "a").inOrder();
-    ASSERT.that(multimap.get("a")).has().exactly(10, 2).inOrder();
+    assertThat(multimap.keySet()).has().exactly("b", "a").inOrder();
+    assertThat(multimap.get("a")).has().exactly(10, 2).inOrder();
     assertEquals(Ordering.usingToString(),
         ((ImmutableSortedSet<Integer>) multimap.get("a")).comparator());
     assertEquals(Ordering.usingToString(),
diff --git a/guava-tests/test/com/google/common/collect/ImmutableSetTest.java b/guava-tests/test/com/google/common/collect/ImmutableSetTest.java
index fb561d6..43a9352 100644
--- a/guava-tests/test/com/google/common/collect/ImmutableSetTest.java
+++ b/guava-tests/test/com/google/common/collect/ImmutableSetTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -153,7 +153,7 @@
     // now we'll get the varargs overload
     ImmutableSet<String> set = ImmutableSet.of(
         "a", "b", "c", "c", "c", "c", "b", "b", "a", "a", "c", "c", "c", "a");
-    ASSERT.that(set).has().exactly("a", "b", "c").inOrder();
+    assertThat(set).has().exactly("a", "b", "c").inOrder();
   }
 
   public void testCreation_arrayOfArray() {
diff --git a/guava-tests/test/com/google/common/collect/ImmutableSortedMapTest.java b/guava-tests/test/com/google/common/collect/ImmutableSortedMapTest.java
index 3350722..8ea6660 100644
--- a/guava-tests/test/com/google/common/collect/ImmutableSortedMapTest.java
+++ b/guava-tests/test/com/google/common/collect/ImmutableSortedMapTest.java
@@ -16,17 +16,20 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
 import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableSortedMap.Builder;
 import com.google.common.collect.testing.ListTestSuiteBuilder;
+import com.google.common.collect.testing.NavigableMapTestSuiteBuilder;
 import com.google.common.collect.testing.SortedMapInterfaceTest;
 import com.google.common.collect.testing.features.CollectionFeature;
 import com.google.common.collect.testing.features.CollectionSize;
+import com.google.common.collect.testing.features.MapFeature;
 import com.google.common.collect.testing.google.SortedMapGenerators.ImmutableSortedMapEntryListGenerator;
+import com.google.common.collect.testing.google.SortedMapGenerators.ImmutableSortedMapGenerator;
 import com.google.common.collect.testing.google.SortedMapGenerators.ImmutableSortedMapKeyListGenerator;
 import com.google.common.collect.testing.google.SortedMapGenerators.ImmutableSortedMapValueListGenerator;
 import com.google.common.testing.NullPointerTester;
@@ -60,6 +63,17 @@
     TestSuite suite = new TestSuite();
     suite.addTestSuite(ImmutableSortedMapTest.class);
 
+    suite.addTest(NavigableMapTestSuiteBuilder.using(
+        new ImmutableSortedMapGenerator())
+        .withFeatures(
+            CollectionSize.ANY,
+            CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS,
+            CollectionFeature.KNOWN_ORDER,
+            MapFeature.REJECTS_DUPLICATES_AT_CREATION,
+            MapFeature.ALLOWS_ANY_NULL_QUERIES)
+        .named("ImmutableSortedMap")
+        .createTestSuite());
+
     suite.addTest(ListTestSuiteBuilder.using(
         new ImmutableSortedMapEntryListGenerator())
         .named("ImmutableSortedMap.entrySet.asList")
@@ -696,7 +710,7 @@
   public void testHeadMapInclusive() {
     Map<String, Integer> map =
         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).headMap("three", true);
-    ASSERT.that(map.entrySet()).has().exactly(
+    assertThat(map.entrySet()).has().exactly(
         Maps.immutableEntry("one", 1),
         Maps.immutableEntry("three", 3)).inOrder();
   }
@@ -705,14 +719,14 @@
   public void testHeadMapExclusive() {
     Map<String, Integer> map =
         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).headMap("three", false);
-    ASSERT.that(map.entrySet()).has().exactly(Maps.immutableEntry("one", 1)).inOrder();
+    assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("one", 1)).inOrder();
   }
 
   @SuppressWarnings("unchecked") // varargs
   public void testTailMapInclusive() {
     Map<String, Integer> map =
         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).tailMap("three", true);
-    ASSERT.that(map.entrySet()).has().exactly(Maps.immutableEntry("three", 3),
+    assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("three", 3),
         Maps.immutableEntry("two", 2)).inOrder();
   }
 
@@ -720,21 +734,21 @@
   public void testTailMapExclusive() {
     Map<String, Integer> map =
         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).tailMap("three", false);
-    ASSERT.that(map.entrySet()).has().exactly(Maps.immutableEntry("two", 2)).inOrder();
+    assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("two", 2)).inOrder();
   }
 
   @SuppressWarnings("unchecked") // varargs
   public void testSubMapExclusiveExclusive() {
     Map<String, Integer> map =
         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).subMap("one", false, "two", false);
-    ASSERT.that(map.entrySet()).has().exactly(Maps.immutableEntry("three", 3)).inOrder();
+    assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("three", 3)).inOrder();
   }
 
   @SuppressWarnings("unchecked") // varargs
   public void testSubMapInclusiveExclusive() {
     Map<String, Integer> map =
         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).subMap("one", true, "two", false);
-    ASSERT.that(map.entrySet()).has().exactly(Maps.immutableEntry("one", 1),
+    assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("one", 1),
         Maps.immutableEntry("three", 3)).inOrder();
   }
 
@@ -742,7 +756,7 @@
   public void testSubMapExclusiveInclusive() {
     Map<String, Integer> map =
         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).subMap("one", false, "two", true);
-    ASSERT.that(map.entrySet()).has().exactly(Maps.immutableEntry("three", 3),
+    assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("three", 3),
         Maps.immutableEntry("two", 2)).inOrder();
   }
 
@@ -750,7 +764,7 @@
   public void testSubMapInclusiveInclusive() {
     Map<String, Integer> map =
         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).subMap("one", true, "two", true);
-    ASSERT.that(map.entrySet()).has().exactly(Maps.immutableEntry("one", 1),
+    assertThat(map.entrySet()).has().exactly(Maps.immutableEntry("one", 1),
         Maps.immutableEntry("three", 3), Maps.immutableEntry("two", 2)).inOrder();
   }
 
diff --git a/guava-tests/test/com/google/common/collect/ImmutableSortedMultisetTest.java b/guava-tests/test/com/google/common/collect/ImmutableSortedMultisetTest.java
index e82a719..ed069fb 100644
--- a/guava-tests/test/com/google/common/collect/ImmutableSortedMultisetTest.java
+++ b/guava-tests/test/com/google/common/collect/ImmutableSortedMultisetTest.java
@@ -15,8 +15,8 @@
 package com.google.common.collect;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.base.Function;
 import com.google.common.collect.Multiset.Entry;
@@ -422,13 +422,13 @@
   public void testSerialization_multiple() {
     Collection<String> c = ImmutableSortedMultiset.of("a", "b", "a");
     Collection<String> copy = SerializableTester.reserializeAndAssert(c);
-    ASSERT.that(copy).has().exactly("a", "a", "b").inOrder();
+    assertThat(copy).has().exactly("a", "a", "b").inOrder();
   }
 
   public void testSerialization_elementSet() {
     Multiset<String> c = ImmutableSortedMultiset.of("a", "b", "a");
     Collection<String> copy = SerializableTester.reserializeAndAssert(c.elementSet());
-    ASSERT.that(copy).has().exactly("a", "b").inOrder();
+    assertThat(copy).has().exactly("a", "b").inOrder();
   }
 
   public void testSerialization_entrySet() {
@@ -440,13 +440,13 @@
     Collection<String> c = ImmutableSortedMultiset.of("a", "b", "a");
     assertEquals(c, ImmutableSortedMultiset.of("a", "b", "a"));
     assertEquals(c, ImmutableSortedMultiset.of("a", "a", "b"));
-    ASSERT.that(c).isNotEqualTo(ImmutableSortedMultiset.of("a", "b"));
-    ASSERT.that(c).isNotEqualTo(ImmutableSortedMultiset.of("a", "b", "c", "d"));
+    assertThat(c).isNotEqualTo(ImmutableSortedMultiset.of("a", "b"));
+    assertThat(c).isNotEqualTo(ImmutableSortedMultiset.of("a", "b", "c", "d"));
   }
 
   public void testIterationOrder() {
     Collection<String> c = ImmutableSortedMultiset.of("a", "b", "a");
-    ASSERT.that(c).has().exactly("a", "a", "b").inOrder();
+    assertThat(c).has().exactly("a", "a", "b").inOrder();
   }
 
   public void testMultisetWrites() {
diff --git a/guava-tests/test/com/google/common/collect/ImmutableSortedSetTest.java b/guava-tests/test/com/google/common/collect/ImmutableSortedSetTest.java
index e8d4a31..ea0c825 100644
--- a/guava-tests/test/com/google/common/collect/ImmutableSortedSetTest.java
+++ b/guava-tests/test/com/google/common/collect/ImmutableSortedSetTest.java
@@ -16,13 +16,13 @@
 
 package com.google.common.collect;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
 import com.google.common.collect.testing.ListTestSuiteBuilder;
-import com.google.common.collect.testing.SortedSetTestSuiteBuilder;
+import com.google.common.collect.testing.NavigableSetTestSuiteBuilder;
 import com.google.common.collect.testing.features.CollectionFeature;
 import com.google.common.collect.testing.features.CollectionSize;
 import com.google.common.collect.testing.google.SetGenerators.ImmutableSortedSetAsListGenerator;
@@ -63,7 +63,7 @@
   public static Test suite() {
     TestSuite suite = new TestSuite();
 
-    suite.addTest(SortedSetTestSuiteBuilder.using(
+    suite.addTest(NavigableSetTestSuiteBuilder.using(
         new ImmutableSortedSetCopyOfGenerator())
         .named(ImmutableSortedSetTest.class.getName())
         .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER,
@@ -71,7 +71,7 @@
             CollectionFeature.ALLOWS_NULL_QUERIES)
             .createTestSuite());
 
-    suite.addTest(SortedSetTestSuiteBuilder.using(
+    suite.addTest(NavigableSetTestSuiteBuilder.using(
         new ImmutableSortedSetExplicitComparator())
         .named(ImmutableSortedSetTest.class.getName()
             + ", explicit comparator, vararg")
@@ -80,7 +80,7 @@
                 CollectionFeature.ALLOWS_NULL_QUERIES)
                 .createTestSuite());
 
-    suite.addTest(SortedSetTestSuiteBuilder.using(
+    suite.addTest(NavigableSetTestSuiteBuilder.using(
         new ImmutableSortedSetExplicitSuperclassComparatorGenerator())
         .named(ImmutableSortedSetTest.class.getName()
             + ", explicit superclass comparator, iterable")
@@ -89,7 +89,7 @@
                 CollectionFeature.ALLOWS_NULL_QUERIES)
                 .createTestSuite());
 
-    suite.addTest(SortedSetTestSuiteBuilder.using(
+    suite.addTest(NavigableSetTestSuiteBuilder.using(
         new ImmutableSortedSetReversedOrderGenerator())
         .named(ImmutableSortedSetTest.class.getName()
             + ", reverseOrder, iterator")
@@ -98,7 +98,7 @@
                 CollectionFeature.ALLOWS_NULL_QUERIES)
                 .createTestSuite());
 
-    suite.addTest(SortedSetTestSuiteBuilder.using(
+    suite.addTest(NavigableSetTestSuiteBuilder.using(
         new ImmutableSortedSetUnhashableGenerator())
         .suppressing(SetHashCodeTester.getHashCodeMethods())
         .named(ImmutableSortedSetTest.class.getName() + ", unhashable")
@@ -106,7 +106,7 @@
             CollectionFeature.ALLOWS_NULL_QUERIES)
             .createTestSuite());
 
-    suite.addTest(SortedSetTestSuiteBuilder.using(
+    suite.addTest(NavigableSetTestSuiteBuilder.using(
         new ImmutableSortedSetDescendingGenerator())
         .named(ImmutableSortedSetTest.class.getName() + ", descending")
         .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER,
@@ -264,7 +264,7 @@
   public void testSingle_headSet() {
     SortedSet<String> set = of("e");
     assertTrue(set.headSet("g") instanceof ImmutableSortedSet);
-    ASSERT.that(set.headSet("g")).has().item("e");
+    assertThat(set.headSet("g")).has().item("e");
     assertSame(of(), set.headSet("c"));
     assertSame(of(), set.headSet("e"));
   }
@@ -272,16 +272,16 @@
   public void testSingle_tailSet() {
     SortedSet<String> set = of("e");
     assertTrue(set.tailSet("c") instanceof ImmutableSortedSet);
-    ASSERT.that(set.tailSet("c")).has().item("e");
-    ASSERT.that(set.tailSet("e")).has().item("e");
+    assertThat(set.tailSet("c")).has().item("e");
+    assertThat(set.tailSet("e")).has().item("e");
     assertSame(of(), set.tailSet("g"));
   }
 
   public void testSingle_subSet() {
     SortedSet<String> set = of("e");
     assertTrue(set.subSet("c", "g") instanceof ImmutableSortedSet);
-    ASSERT.that(set.subSet("c", "g")).has().item("e");
-    ASSERT.that(set.subSet("e", "g")).has().item("e");
+    assertThat(set.subSet("c", "g")).has().item("e");
+    assertThat(set.subSet("e", "g")).has().item("e");
     assertSame(of(), set.subSet("f", "g"));
     assertSame(of(), set.subSet("c", "e"));
     assertSame(of(), set.subSet("c", "d"));
@@ -306,7 +306,7 @@
 
   public void testOf_ordering() {
     SortedSet<String> set = of("e", "a", "f", "b", "d", "c");
-    ASSERT.that(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
   }
 
   /*
@@ -355,7 +355,7 @@
 
   public void testOf_ordering_dupes() {
     SortedSet<String> set = of("e", "a", "e", "f", "b", "b", "d", "a", "c");
-    ASSERT.that(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
   }
 
   public void testOf_comparator() {
@@ -366,8 +366,8 @@
   public void testOf_headSet() {
     SortedSet<String> set = of("e", "f", "b", "d", "c");
     assertTrue(set.headSet("e") instanceof ImmutableSortedSet);
-    ASSERT.that(set.headSet("e")).has().exactly("b", "c", "d").inOrder();
-    ASSERT.that(set.headSet("g")).has().exactly("b", "c", "d", "e", "f").inOrder();
+    assertThat(set.headSet("e")).has().exactly("b", "c", "d").inOrder();
+    assertThat(set.headSet("g")).has().exactly("b", "c", "d", "e", "f").inOrder();
     assertSame(of(), set.headSet("a"));
     assertSame(of(), set.headSet("b"));
   }
@@ -375,16 +375,16 @@
   public void testOf_tailSet() {
     SortedSet<String> set = of("e", "f", "b", "d", "c");
     assertTrue(set.tailSet("e") instanceof ImmutableSortedSet);
-    ASSERT.that(set.tailSet("e")).has().exactly("e", "f").inOrder();
-    ASSERT.that(set.tailSet("a")).has().exactly("b", "c", "d", "e", "f").inOrder();
+    assertThat(set.tailSet("e")).has().exactly("e", "f").inOrder();
+    assertThat(set.tailSet("a")).has().exactly("b", "c", "d", "e", "f").inOrder();
     assertSame(of(), set.tailSet("g"));
   }
 
   public void testOf_subSet() {
     SortedSet<String> set = of("e", "f", "b", "d", "c");
     assertTrue(set.subSet("c", "e") instanceof ImmutableSortedSet);
-    ASSERT.that(set.subSet("c", "e")).has().exactly("c", "d").inOrder();
-    ASSERT.that(set.subSet("a", "g")).has().exactly("b", "c", "d", "e", "f").inOrder();
+    assertThat(set.subSet("c", "e")).has().exactly("c", "d").inOrder();
+    assertThat(set.subSet("a", "g")).has().exactly("b", "c", "d", "e", "f").inOrder();
     assertSame(of(), set.subSet("a", "b"));
     assertSame(of(), set.subSet("g", "h"));
     assertSame(of(), set.subSet("c", "c"));
@@ -424,14 +424,14 @@
   public void testExplicit_ordering() {
     SortedSet<String> set = ImmutableSortedSet.orderedBy(STRING_LENGTH).add(
         "in", "the", "quick", "jumped", "over", "a").build();
-    ASSERT.that(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
+    assertThat(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
   }
 
   public void testExplicit_ordering_dupes() {
     SortedSet<String> set = ImmutableSortedSet.orderedBy(STRING_LENGTH).add(
         "in", "the", "quick", "brown", "fox", "jumped",
         "over", "a", "lazy", "dog").build();
-    ASSERT.that(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
+    assertThat(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
   }
 
   public void testExplicit_contains() {
@@ -461,8 +461,8 @@
         "in", "the", "quick", "jumped", "over", "a").build();
     assertTrue(set.headSet("a") instanceof ImmutableSortedSet);
     assertTrue(set.headSet("fish") instanceof ImmutableSortedSet);
-    ASSERT.that(set.headSet("fish")).has().exactly("a", "in", "the").inOrder();
-    ASSERT.that(set.headSet("california")).has()
+    assertThat(set.headSet("fish")).has().exactly("a", "in", "the").inOrder();
+    assertThat(set.headSet("california")).has()
         .exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
     assertTrue(set.headSet("a").isEmpty());
     assertTrue(set.headSet("").isEmpty());
@@ -473,8 +473,8 @@
         "in", "the", "quick", "jumped", "over", "a").build();
     assertTrue(set.tailSet("california") instanceof ImmutableSortedSet);
     assertTrue(set.tailSet("fish") instanceof ImmutableSortedSet);
-    ASSERT.that(set.tailSet("fish")).has().exactly("over", "quick", "jumped").inOrder();
-    ASSERT.that(
+    assertThat(set.tailSet("fish")).has().exactly("over", "quick", "jumped").inOrder();
+    assertThat(
         set.tailSet("a")).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
     assertTrue(set.tailSet("california").isEmpty());
   }
@@ -484,8 +484,8 @@
         "in", "the", "quick", "jumped", "over", "a").build();
     assertTrue(set.subSet("the", "quick") instanceof ImmutableSortedSet);
     assertTrue(set.subSet("", "b") instanceof ImmutableSortedSet);
-    ASSERT.that(set.subSet("the", "quick")).has().exactly("the", "over").inOrder();
-    ASSERT.that(set.subSet("a", "california"))
+    assertThat(set.subSet("the", "quick")).has().exactly("the", "over").inOrder();
+    assertThat(set.subSet("a", "california"))
         .has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
     assertTrue(set.subSet("", "b").isEmpty());
     assertTrue(set.subSet("vermont", "california").isEmpty());
@@ -530,13 +530,13 @@
   public void testCopyOf_ordering() {
     SortedSet<String> set =
         copyOf(asList("e", "a", "f", "b", "d", "c"));
-    ASSERT.that(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
   }
 
   public void testCopyOf_ordering_dupes() {
     SortedSet<String> set =
         copyOf(asList("e", "a", "e", "f", "b", "b", "d", "a", "c"));
-    ASSERT.that(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
   }
 
   public void testCopyOf_subSet() {
@@ -567,13 +567,13 @@
 
   public void testCopyOf_iterator_ordering() {
     SortedSet<String> set = copyOf(asIterator("e", "a", "f", "b", "d", "c"));
-    ASSERT.that(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
   }
 
   public void testCopyOf_iterator_ordering_dupes() {
     SortedSet<String> set =
         copyOf(asIterator("e", "a", "e", "f", "b", "b", "d", "a", "c"));
-    ASSERT.that(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
   }
 
   public void testCopyOf_iterator_comparator() {
@@ -584,7 +584,7 @@
   public void testCopyOf_sortedSet_ordering() {
     SortedSet<String> set =
         copyOf(Sets.newTreeSet(asList("e", "a", "f", "b", "d", "c")));
-    ASSERT.that(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(set).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
   }
 
   public void testCopyOf_sortedSet_comparator() {
@@ -596,7 +596,7 @@
     SortedSet<String> set =
         ImmutableSortedSet.copyOf(STRING_LENGTH, asList(
             "in", "the", "quick", "jumped", "over", "a"));
-    ASSERT.that(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
+    assertThat(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
   }
 
   public void testCopyOfExplicit_ordering_dupes() {
@@ -604,7 +604,7 @@
         ImmutableSortedSet.copyOf(STRING_LENGTH, asList(
             "in", "the", "quick", "brown", "fox", "jumped", "over", "a",
             "lazy", "dog"));
-    ASSERT.that(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
+    assertThat(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
   }
 
   public void testCopyOfExplicit_comparator() {
@@ -618,7 +618,7 @@
     SortedSet<String> set =
         ImmutableSortedSet.copyOf(STRING_LENGTH, asIterator(
             "in", "the", "quick", "jumped", "over", "a"));
-    ASSERT.that(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
+    assertThat(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
   }
 
   public void testCopyOfExplicit_iterator_ordering_dupes() {
@@ -626,7 +626,7 @@
         ImmutableSortedSet.copyOf(STRING_LENGTH, asIterator(
             "in", "the", "quick", "brown", "fox", "jumped", "over", "a",
             "lazy", "dog"));
-    ASSERT.that(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
+    assertThat(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
   }
 
   public void testCopyOfExplicit_iterator_comparator() {
@@ -640,14 +640,14 @@
     SortedSet<String> input = Sets.newTreeSet(STRING_LENGTH);
     Collections.addAll(input, "in", "the", "quick", "jumped", "over", "a");
     SortedSet<String> set = copyOf(input);
-    ASSERT.that(set).has().exactly("a", "in", "jumped", "over", "quick", "the").inOrder();
+    assertThat(set).has().exactly("a", "in", "jumped", "over", "quick", "the").inOrder();
   }
 
   public void testCopyOfSorted_natural_ordering() {
     SortedSet<String> input = Sets.newTreeSet(
         asList("in", "the", "quick", "jumped", "over", "a"));
     SortedSet<String> set = ImmutableSortedSet.copyOfSorted(input);
-    ASSERT.that(set).has().exactly("a", "in", "jumped", "over", "quick", "the").inOrder();
+    assertThat(set).has().exactly("a", "in", "jumped", "over", "quick", "the").inOrder();
   }
 
   public void testCopyOfSorted_natural_comparator() {
@@ -661,7 +661,7 @@
     SortedSet<String> input = Sets.newTreeSet(STRING_LENGTH);
     Collections.addAll(input, "in", "the", "quick", "jumped", "over", "a");
     SortedSet<String> set = ImmutableSortedSet.copyOfSorted(input);
-    ASSERT.that(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
+    assertThat(set).has().exactly("a", "in", "the", "over", "quick", "jumped").inOrder();
     assertSame(STRING_LENGTH, set.comparator());
   }
 
@@ -760,7 +760,7 @@
   public void testReverseOrder() {
     SortedSet<String> set = ImmutableSortedSet.<String>reverseOrder()
         .add("a", "b", "c").build();
-    ASSERT.that(set).has().exactly("c", "b", "a").inOrder();
+    assertThat(set).has().exactly("c", "b", "a").inOrder();
     assertEquals(Ordering.natural().reverse(), set.comparator());
   }
 
@@ -775,13 +775,13 @@
   public void testSupertypeComparator() {
     SortedSet<Integer> set = new ImmutableSortedSet.Builder<Integer>(TO_STRING)
         .add(3, 12, 101, 44).build();
-    ASSERT.that(set).has().exactly(101, 12, 3, 44).inOrder();
+    assertThat(set).has().exactly(101, 12, 3, 44).inOrder();
   }
 
   public void testSupertypeComparatorSubtypeElements() {
     SortedSet<Number> set = new ImmutableSortedSet.Builder<Number>(TO_STRING)
         .add(3, 12, 101, 44).build();
-    ASSERT.that(set).has().exactly(101, 12, 3, 44).inOrder();
+    assertThat(set).has().exactly(101, 12, 3, 44).inOrder();
   }
 
   @Override <E extends Comparable<E>> ImmutableSortedSet.Builder<E> builder() {
@@ -912,7 +912,7 @@
   private static void assertNotEqualLenient(
       TreeSet<?> unexpected, SortedSet<?> actual) {
     try {
-      ASSERT.that(actual).isNotEqualTo(unexpected);
+      assertThat(actual).isNotEqualTo(unexpected);
     } catch (ClassCastException accepted) {
     }
   }
@@ -922,7 +922,7 @@
     ImmutableSortedSet<String> set = ImmutableSortedSet.copyOf(strings);
     Arrays.sort(strings);
     for (int i = 0; i < strings.length; i++) {
-      ASSERT.that(set.headSet(strings[i], true))
+      assertThat(set.headSet(strings[i], true))
           .has().exactlyAs(sortedNumberNames(0, i + 1)).inOrder();
     }
   }
@@ -932,7 +932,7 @@
     ImmutableSortedSet<String> set = ImmutableSortedSet.copyOf(strings);
     Arrays.sort(strings);
     for (int i = 0; i < strings.length; i++) {
-      ASSERT.that(set.headSet(strings[i], false)).has().exactlyAs(
+      assertThat(set.headSet(strings[i], false)).has().exactlyAs(
           sortedNumberNames(0, i)).inOrder();
     }
   }
@@ -942,7 +942,7 @@
     ImmutableSortedSet<String> set = ImmutableSortedSet.copyOf(strings);
     Arrays.sort(strings);
     for (int i = 0; i < strings.length; i++) {
-      ASSERT.that(set.tailSet(strings[i], true)).has().exactlyAs(
+      assertThat(set.tailSet(strings[i], true)).has().exactlyAs(
           sortedNumberNames(i, strings.length)).inOrder();
     }
   }
@@ -952,7 +952,7 @@
     ImmutableSortedSet<String> set = ImmutableSortedSet.copyOf(strings);
     Arrays.sort(strings);
     for (int i = 0; i < strings.length; i++) {
-      ASSERT.that(set.tailSet(strings[i], false)).has().exactlyAs(
+      assertThat(set.tailSet(strings[i], false)).has().exactlyAs(
           sortedNumberNames(i + 1, strings.length)).inOrder();
     }
   }
@@ -963,7 +963,7 @@
     Arrays.sort(strings);
     for (int i = 0; i < strings.length; i++) {
       for (int j = i; j < strings.length; j++) {
-        ASSERT.that(set.subSet(strings[i], false, strings[j], false))
+        assertThat(set.subSet(strings[i], false, strings[j], false))
             .has().exactlyAs(sortedNumberNames(Math.min(i + 1, j), j)).inOrder();
       }
     }
@@ -975,7 +975,7 @@
     Arrays.sort(strings);
     for (int i = 0; i < strings.length; i++) {
       for (int j = i; j < strings.length; j++) {
-        ASSERT.that(set.subSet(strings[i], true, strings[j], false))
+        assertThat(set.subSet(strings[i], true, strings[j], false))
             .has().exactlyAs(sortedNumberNames(i, j)).inOrder();
       }
     }
@@ -987,7 +987,7 @@
     Arrays.sort(strings);
     for (int i = 0; i < strings.length; i++) {
       for (int j = i; j < strings.length; j++) {
-        ASSERT.that(set.subSet(strings[i], false, strings[j], true))
+        assertThat(set.subSet(strings[i], false, strings[j], true))
             .has().exactlyAs(sortedNumberNames(i + 1, j + 1)).inOrder();
       }
     }
@@ -999,7 +999,7 @@
     Arrays.sort(strings);
     for (int i = 0; i < strings.length; i++) {
       for (int j = i; j < strings.length; j++) {
-        ASSERT.that(set.subSet(strings[i], true, strings[j], true))
+        assertThat(set.subSet(strings[i], true, strings[j], true))
             .has().exactlyAs(sortedNumberNames(i, j + 1)).inOrder();
       }
     }
diff --git a/guava-tests/test/com/google/common/collect/ImmutableTableTest.java b/guava-tests/test/com/google/common/collect/ImmutableTableTest.java
index 36931fe..7d88619 100644
--- a/guava-tests/test/com/google/common/collect/ImmutableTableTest.java
+++ b/guava-tests/test/com/google/common/collect/ImmutableTableTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -185,8 +185,8 @@
     validateTableCopies(table);
     // Even though rowKeySet, columnKeySet, and cellSet have the same
     // iteration ordering, row has an inconsistent ordering.
-    ASSERT.that(table.row('b').keySet()).has().exactly(1, 2).inOrder();
-    ASSERT.that(ImmutableTable.copyOf(table).row('b').keySet())
+    assertThat(table.row('b').keySet()).has().exactly(1, 2).inOrder();
+    assertThat(ImmutableTable.copyOf(table).row('b').keySet())
         .has().exactly(2, 1).inOrder();
   }
 
@@ -228,10 +228,10 @@
         = builder.orderRowsBy(Ordering.natural())
             .orderColumnsBy(Ordering.natural())
             .putAll(table).build();
-    ASSERT.that(copy.rowKeySet()).has().exactly('a', 'b').inOrder();
-    ASSERT.that(copy.columnKeySet()).has().exactly(1, 2).inOrder();
-    ASSERT.that(copy.values()).has().exactly("baz", "bar", "foo").inOrder();
-    ASSERT.that(copy.row('b').keySet()).has().exactly(1, 2).inOrder();
+    assertThat(copy.rowKeySet()).has().exactly('a', 'b').inOrder();
+    assertThat(copy.columnKeySet()).has().exactly(1, 2).inOrder();
+    assertThat(copy.values()).has().exactly("baz", "bar", "foo").inOrder();
+    assertThat(copy.row('b').keySet()).has().exactly(1, 2).inOrder();
   }
 
   public void testBuilder_orderRowsAndColumnsBy_sparse() {
@@ -249,12 +249,12 @@
     builder.put('r', 4, "foo");
     builder.put('x', 5, "bar");
     Table<Character, Integer, String> table = builder.build();
-    ASSERT.that(table.rowKeySet()).has().exactly('b', 'c', 'e', 'r', 'x').inOrder();
-    ASSERT.that(table.columnKeySet()).has().exactly(0, 1, 2, 3, 4, 5, 7).inOrder();
-    ASSERT.that(table.values()).has().exactly("cat", "axe", "baz", "tub",
+    assertThat(table.rowKeySet()).has().exactly('b', 'c', 'e', 'r', 'x').inOrder();
+    assertThat(table.columnKeySet()).has().exactly(0, 1, 2, 3, 4, 5, 7).inOrder();
+    assertThat(table.values()).has().exactly("cat", "axe", "baz", "tub",
         "dog", "bar", "foo", "foo", "bar").inOrder();
-    ASSERT.that(table.row('c').keySet()).has().exactly(0, 3).inOrder();
-    ASSERT.that(table.column(5).keySet()).has().exactly('e', 'x').inOrder();
+    assertThat(table.row('c').keySet()).has().exactly(0, 3).inOrder();
+    assertThat(table.column(5).keySet()).has().exactly('e', 'x').inOrder();
   }
 
   public void testBuilder_orderRowsAndColumnsBy_dense() {
@@ -271,12 +271,12 @@
     builder.put('a', 2, "bar");
     builder.put('a', 1, "baz");
     Table<Character, Integer, String> table = builder.build();
-    ASSERT.that(table.rowKeySet()).has().exactly('a', 'b', 'c').inOrder();
-    ASSERT.that(table.columnKeySet()).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(table.values()).has().exactly("baz", "bar", "foo", "dog",
+    assertThat(table.rowKeySet()).has().exactly('a', 'b', 'c').inOrder();
+    assertThat(table.columnKeySet()).has().exactly(1, 2, 3).inOrder();
+    assertThat(table.values()).has().exactly("baz", "bar", "foo", "dog",
         "cat", "baz", "bar", "foo").inOrder();
-    ASSERT.that(table.row('c').keySet()).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(table.column(1).keySet()).has().exactly('a', 'b', 'c').inOrder();
+    assertThat(table.row('c').keySet()).has().exactly(1, 2, 3).inOrder();
+    assertThat(table.column(1).keySet()).has().exactly('a', 'b', 'c').inOrder();
   }
 
   public void testBuilder_orderRowsBy_sparse() {
@@ -293,8 +293,8 @@
     builder.put('r', 4, "foo");
     builder.put('x', 5, "bar");
     Table<Character, Integer, String> table = builder.build();
-    ASSERT.that(table.rowKeySet()).has().exactly('b', 'c', 'e', 'r', 'x').inOrder();
-    ASSERT.that(table.column(5).keySet()).has().exactly('e', 'x').inOrder();
+    assertThat(table.rowKeySet()).has().exactly('b', 'c', 'e', 'r', 'x').inOrder();
+    assertThat(table.column(5).keySet()).has().exactly('e', 'x').inOrder();
   }
 
   public void testBuilder_orderRowsBy_dense() {
@@ -310,8 +310,8 @@
     builder.put('a', 2, "bar");
     builder.put('a', 1, "baz");
     Table<Character, Integer, String> table = builder.build();
-    ASSERT.that(table.rowKeySet()).has().exactly('a', 'b', 'c').inOrder();
-    ASSERT.that(table.column(1).keySet()).has().exactly('a', 'b', 'c').inOrder();
+    assertThat(table.rowKeySet()).has().exactly('a', 'b', 'c').inOrder();
+    assertThat(table.column(1).keySet()).has().exactly('a', 'b', 'c').inOrder();
   }
 
   public void testBuilder_orderColumnsBy_sparse() {
@@ -328,8 +328,8 @@
     builder.put('r', 4, "foo");
     builder.put('x', 5, "bar");
     Table<Character, Integer, String> table = builder.build();
-    ASSERT.that(table.columnKeySet()).has().exactly(0, 1, 2, 3, 4, 5, 7).inOrder();
-    ASSERT.that(table.row('c').keySet()).has().exactly(0, 3).inOrder();
+    assertThat(table.columnKeySet()).has().exactly(0, 1, 2, 3, 4, 5, 7).inOrder();
+    assertThat(table.row('c').keySet()).has().exactly(0, 3).inOrder();
   }
 
   public void testBuilder_orderColumnsBy_dense() {
@@ -345,8 +345,8 @@
     builder.put('a', 2, "bar");
     builder.put('a', 1, "baz");
     Table<Character, Integer, String> table = builder.build();
-    ASSERT.that(table.columnKeySet()).has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(table.row('c').keySet()).has().exactly(1, 2, 3).inOrder();
+    assertThat(table.columnKeySet()).has().exactly(1, 2, 3).inOrder();
+    assertThat(table.row('c').keySet()).has().exactly(1, 2, 3).inOrder();
   }
 
   @GwtIncompatible("Mind-bogglingly slow in GWT")
diff --git a/guava-tests/test/com/google/common/collect/IterablesTest.java b/guava-tests/test/com/google/common/collect/IterablesTest.java
index a16beac..1dbbb97 100644
--- a/guava-tests/test/com/google/common/collect/IterablesTest.java
+++ b/guava-tests/test/com/google/common/collect/IterablesTest.java
@@ -21,9 +21,9 @@
 import static com.google.common.collect.Sets.newLinkedHashSet;
 import static com.google.common.collect.testing.IteratorFeature.MODIFIABLE;
 import static com.google.common.collect.testing.IteratorFeature.UNMODIFIABLE;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
 import static java.util.Collections.emptyList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -283,7 +283,7 @@
     Iterable<TypeA> alist = Lists
         .newArrayList(new TypeA(), new TypeA(), hasBoth, new TypeA());
     Iterable<TypeB> blist = Iterables.filter(alist, TypeB.class);
-    ASSERT.that(blist).iteratesOverSequence(hasBoth);
+    assertThat(blist).iteratesAs(hasBoth);
   }
 
   public void testTransform() {
@@ -411,7 +411,7 @@
     int n = 4;
     Iterable<Integer> repeated
         = Iterables.concat(Collections.nCopies(n, iterable));
-    ASSERT.that(repeated).iteratesOverSequence(
+    assertThat(repeated).iteratesAs(
         1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3);
   }
 
@@ -510,7 +510,7 @@
     List<String> freshlyAdded = newArrayList("freshly", "added");
 
     boolean changed = Iterables.addAll(alreadyThere, freshlyAdded);
-    ASSERT.that(alreadyThere).has().exactly(
+    assertThat(alreadyThere).has().exactly(
         "already", "there", "freshly", "added").inOrder();
     assertTrue(changed);
   }
@@ -688,7 +688,7 @@
     Iterable<String> tail = skip(set, 1);
     set.remove("b");
     set.addAll(newArrayList("A", "B", "C"));
-    ASSERT.that(tail).iteratesOverSequence("c", "A", "B", "C");
+    assertThat(tail).iteratesAs("c", "A", "B", "C");
   }
 
   public void testSkip_structurallyModifiedSkipSomeList() throws Exception {
@@ -696,7 +696,7 @@
     Iterable<String> tail = skip(list, 1);
     list.subList(1, 3).clear();
     list.addAll(0, newArrayList("A", "B", "C"));
-    ASSERT.that(tail).iteratesOverSequence("B", "C", "a");
+    assertThat(tail).iteratesAs("B", "C", "a");
   }
 
   public void testSkip_structurallyModifiedSkipAll() throws Exception {
@@ -1127,16 +1127,16 @@
     assertEquals("Iterables.consumingIterable(...)", consumingIterable.toString());
     Iterator<String> consumingIterator = consumingIterable.iterator();
 
-    ASSERT.that(list).has().exactly("a", "b").inOrder();
+    assertThat(list).has().exactly("a", "b").inOrder();
 
     assertTrue(consumingIterator.hasNext());
-    ASSERT.that(list).has().exactly("a", "b").inOrder();
+    assertThat(list).has().exactly("a", "b").inOrder();
     assertEquals("a", consumingIterator.next());
-    ASSERT.that(list).has().item("b");
+    assertThat(list).has().item("b");
 
     assertTrue(consumingIterator.hasNext());
     assertEquals("b", consumingIterator.next());
-    ASSERT.that(list).isEmpty();
+    assertThat(list).isEmpty();
 
     assertFalse(consumingIterator.hasNext());
   }
diff --git a/guava-tests/test/com/google/common/collect/IteratorsTest.java b/guava-tests/test/com/google/common/collect/IteratorsTest.java
index 2f9d83a..c3f9263 100644
--- a/guava-tests/test/com/google/common/collect/IteratorsTest.java
+++ b/guava-tests/test/com/google/common/collect/IteratorsTest.java
@@ -22,9 +22,9 @@
 import static com.google.common.collect.Lists.newArrayList;
 import static com.google.common.collect.testing.IteratorFeature.MODIFIABLE;
 import static com.google.common.collect.testing.IteratorFeature.UNMODIFIABLE;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
 import static java.util.Collections.singleton;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -765,7 +765,7 @@
 
     boolean changed = Iterators.addAll(alreadyThere,
                                        Iterators.<String>emptyIterator());
-    ASSERT.that(alreadyThere).has().exactly("already", "there").inOrder();
+    assertThat(alreadyThere).has().exactly("already", "there").inOrder();
     assertFalse(changed);
   }
 
@@ -775,7 +775,7 @@
 
     boolean changed = Iterators.addAll(alreadyThere, freshlyAdded.iterator());
 
-    ASSERT.that(alreadyThere).has().exactly("already", "there", "freshly", "added");
+    assertThat(alreadyThere).has().exactly("already", "there", "freshly", "added");
     assertTrue(changed);
   }
 
@@ -785,7 +785,7 @@
     List<String> oneMore = Lists.newArrayList("there");
 
     boolean changed = Iterators.addAll(alreadyThere, oneMore.iterator());
-    ASSERT.that(alreadyThere).has().exactly("already", "there").inOrder();
+    assertThat(alreadyThere).has().exactly("already", "there").inOrder();
     assertFalse(changed);
   }
 
@@ -1523,16 +1523,16 @@
 
     assertEquals("Iterators.consumingIterator(...)", consumingIterator.toString());
 
-    ASSERT.that(list).has().exactly("a", "b").inOrder();
+    assertThat(list).has().exactly("a", "b").inOrder();
 
     assertTrue(consumingIterator.hasNext());
-    ASSERT.that(list).has().exactly("a", "b").inOrder();
+    assertThat(list).has().exactly("a", "b").inOrder();
     assertEquals("a", consumingIterator.next());
-    ASSERT.that(list).has().item("b");
+    assertThat(list).has().item("b");
 
     assertTrue(consumingIterator.hasNext());
     assertEquals("b", consumingIterator.next());
-    ASSERT.that(list).isEmpty();
+    assertThat(list).isEmpty();
 
     assertFalse(consumingIterator.hasNext());
   }
diff --git a/guava-tests/test/com/google/common/collect/LinkedHashMultimapTest.java b/guava-tests/test/com/google/common/collect/LinkedHashMultimapTest.java
index c905370..80bbcc1 100644
--- a/guava-tests/test/com/google/common/collect/LinkedHashMultimapTest.java
+++ b/guava-tests/test/com/google/common/collect/LinkedHashMultimapTest.java
@@ -21,8 +21,8 @@
 import static com.google.common.collect.Sets.newLinkedHashSet;
 import static com.google.common.collect.testing.Helpers.mapEntry;
 import static com.google.common.collect.testing.IteratorFeature.MODIFIABLE;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -151,8 +151,8 @@
     multimap.put("c", 4);
     multimap.remove("a", 1);
     multimap = SerializableTester.reserializeAndAssert(multimap);
-    ASSERT.that(multimap.keySet()).has().exactly("a", "b", "c").inOrder();
-    ASSERT.that(multimap.entries()).has().exactly(
+    assertThat(multimap.keySet()).has().exactly("a", "b", "c").inOrder();
+    assertThat(multimap.entries()).has().exactly(
         mapEntry("b", 2),
         mapEntry("a", 3),
         mapEntry("c", 4)).inOrder();
@@ -160,12 +160,12 @@
   }
 
   private void assertOrderingReadOnly(Multimap<String, Integer> multimap) {
-    ASSERT.that(multimap.get("foo")).has().exactly(5, 3).inOrder();
-    ASSERT.that(multimap.get("bar")).has().exactly(4, 1).inOrder();
-    ASSERT.that(multimap.get("cow")).has().item(2);
+    assertThat(multimap.get("foo")).has().exactly(5, 3).inOrder();
+    assertThat(multimap.get("bar")).has().exactly(4, 1).inOrder();
+    assertThat(multimap.get("cow")).has().item(2);
 
-    ASSERT.that(multimap.keySet()).has().exactly("foo", "bar", "cow").inOrder();
-    ASSERT.that(multimap.values()).has().exactly(5, 4, 3, 2, 1).inOrder();
+    assertThat(multimap.keySet()).has().exactly("foo", "bar", "cow").inOrder();
+    assertThat(multimap.values()).has().exactly(5, 4, 3, 2, 1).inOrder();
 
     Iterator<Map.Entry<String, Integer>> entryIterator =
         multimap.entries().iterator();
@@ -179,28 +179,28 @@
         multimap.asMap().entrySet().iterator();
     Map.Entry<String, Collection<Integer>> entry = collectionIterator.next();
     assertEquals("foo", entry.getKey());
-    ASSERT.that(entry.getValue()).has().exactly(5, 3).inOrder();
+    assertThat(entry.getValue()).has().exactly(5, 3).inOrder();
     entry = collectionIterator.next();
     assertEquals("bar", entry.getKey());
-    ASSERT.that(entry.getValue()).has().exactly(4, 1).inOrder();
+    assertThat(entry.getValue()).has().exactly(4, 1).inOrder();
     entry = collectionIterator.next();
     assertEquals("cow", entry.getKey());
-    ASSERT.that(entry.getValue()).has().item(2);
+    assertThat(entry.getValue()).has().item(2);
   }
 
   public void testOrderingUpdates() {
     Multimap<String, Integer> multimap = initializeMultimap5();
 
-    ASSERT.that(multimap.replaceValues("foo", asList(6, 7))).has().exactly(5, 3).inOrder();
-    ASSERT.that(multimap.keySet()).has().exactly("foo", "bar", "cow").inOrder();
-    ASSERT.that(multimap.removeAll("foo")).has().exactly(6, 7).inOrder();
-    ASSERT.that(multimap.keySet()).has().exactly("bar", "cow").inOrder();
+    assertThat(multimap.replaceValues("foo", asList(6, 7))).has().exactly(5, 3).inOrder();
+    assertThat(multimap.keySet()).has().exactly("foo", "bar", "cow").inOrder();
+    assertThat(multimap.removeAll("foo")).has().exactly(6, 7).inOrder();
+    assertThat(multimap.keySet()).has().exactly("bar", "cow").inOrder();
     assertTrue(multimap.remove("bar", 4));
-    ASSERT.that(multimap.keySet()).has().exactly("bar", "cow").inOrder();
+    assertThat(multimap.keySet()).has().exactly("bar", "cow").inOrder();
     assertTrue(multimap.remove("bar", 1));
-    ASSERT.that(multimap.keySet()).has().item("cow");
+    assertThat(multimap.keySet()).has().item("cow");
     multimap.put("bar", 9);
-    ASSERT.that(multimap.keySet()).has().exactly("cow", "bar").inOrder();
+    assertThat(multimap.keySet()).has().exactly("cow", "bar").inOrder();
   }
 
   public void testToStringNullExact() {
diff --git a/guava-tests/test/com/google/common/collect/LinkedHashMultisetTest.java b/guava-tests/test/com/google/common/collect/LinkedHashMultisetTest.java
index db8859a..ca359cb 100644
--- a/guava-tests/test/com/google/common/collect/LinkedHashMultisetTest.java
+++ b/guava-tests/test/com/google/common/collect/LinkedHashMultisetTest.java
@@ -16,8 +16,8 @@
 
 package com.google.common.collect;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -121,13 +121,13 @@
     ms.add("a");
     ms.add("b", 2);
     ms.add("c");
-    ASSERT.that(ms.elementSet()).has().exactly("a", "b", "c").inOrder();
+    assertThat(ms.elementSet()).has().exactly("a", "b", "c").inOrder();
     ms.remove("b");
-    ASSERT.that(ms.elementSet()).has().exactly("a", "b", "c").inOrder();
+    assertThat(ms.elementSet()).has().exactly("a", "b", "c").inOrder();
     ms.add("b");
-    ASSERT.that(ms.elementSet()).has().exactly("a", "b", "c").inOrder();
+    assertThat(ms.elementSet()).has().exactly("a", "b", "c").inOrder();
     ms.remove("b", 2);
     ms.add("b");
-    ASSERT.that(ms.elementSet()).has().exactly("a", "c", "b").inOrder();
+    assertThat(ms.elementSet()).has().exactly("a", "c", "b").inOrder();
   }
 }
diff --git a/guava-tests/test/com/google/common/collect/LinkedListMultimapTest.java b/guava-tests/test/com/google/common/collect/LinkedListMultimapTest.java
index fc4ff60..bc4a2df 100644
--- a/guava-tests/test/com/google/common/collect/LinkedListMultimapTest.java
+++ b/guava-tests/test/com/google/common/collect/LinkedListMultimapTest.java
@@ -22,8 +22,8 @@
 import static com.google.common.collect.testing.IteratorFeature.MODIFIABLE;
 import static com.google.common.collect.testing.IteratorFeature.SUPPORTS_REMOVE;
 import static com.google.common.collect.testing.IteratorFeature.SUPPORTS_SET;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -136,7 +136,7 @@
     LinkedListMultimap<String, Integer> copy =
         LinkedListMultimap.create(multimap);
     assertEquals(multimap, copy);
-    ASSERT.that(copy.entries()).has().exactlyAs(multimap.entries()).inOrder();
+    assertThat(copy.entries()).has().exactlyAs(multimap.entries()).inOrder();
   }
 
   public void testCreateFromSize() {
@@ -230,10 +230,10 @@
     List<Integer> foos = map.get("foo");
     Collection<Integer> values = map.values();
     assertEquals(asList(1, 2), foos);
-    ASSERT.that(values).has().exactly(1, 2, 3).inOrder();
+    assertThat(values).has().exactly(1, 2, 3).inOrder();
     map.clear();
     assertEquals(Collections.emptyList(), foos);
-    ASSERT.that(values).isEmpty();
+    assertThat(values).isEmpty();
     assertEquals("[]", map.entries().toString());
     assertEquals("{}", map.toString());
   }
@@ -257,7 +257,7 @@
     map.put("bar", 4);
     assertEquals("[bar=1, foo=2, bar=3, bar=4]",
         map.entries().toString());
-    ASSERT.that(map.keys()).has().exactly("bar", "foo", "bar", "bar").inOrder();
+    assertThat(map.keys()).has().exactly("bar", "foo", "bar", "bar").inOrder();
     map.keys().remove("bar"); // bar is no longer the first key!
     assertEquals("{foo=[2], bar=[3, 4]}", map.toString());
   }
@@ -303,7 +303,7 @@
         = map.asMap().entrySet().iterator();
     Map.Entry<String, Collection<Integer>> entry = entries.next();
     assertEquals("bar", entry.getKey());
-    ASSERT.that(entry.getValue()).has().exactly(1, 3).inOrder();
+    assertThat(entry.getValue()).has().exactly(1, 3).inOrder();
     try {
       entry.setValue(Arrays.<Integer>asList());
       fail("UnsupportedOperationException expected");
@@ -311,7 +311,7 @@
     entries.remove(); // clear
     entry = entries.next();
     assertEquals("foo", entry.getKey());
-    ASSERT.that(entry.getValue()).has().item(2);
+    assertThat(entry.getValue()).has().item(2);
     assertFalse(entries.hasNext());
     assertEquals("{foo=[2]}", map.toString());
   }
diff --git a/guava-tests/test/com/google/common/collect/ListsTest.java b/guava-tests/test/com/google/common/collect/ListsTest.java
index 31731f2..7c422f4 100644
--- a/guava-tests/test/com/google/common/collect/ListsTest.java
+++ b/guava-tests/test/com/google/common/collect/ListsTest.java
@@ -18,9 +18,9 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.testing.IteratorFeature.UNMODIFIABLE;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
 import static java.util.Collections.singletonList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -418,7 +418,7 @@
   }
 
   private void checkFooBarBazList(List<String> list) {
-    ASSERT.that(list).has().exactly("foo", "bar", "baz").inOrder();
+    assertThat(list).has().exactly("foo", "bar", "baz").inOrder();
     assertEquals(3, list.size());
     assertIndexIsOutOfBounds(list, -1);
     assertEquals("foo", list.get(0));
@@ -429,7 +429,7 @@
 
   public void testAsList1Small() {
     List<String> list = Lists.asList("foo", new String[0]);
-    ASSERT.that(list).has().item("foo");
+    assertThat(list).has().item("foo");
     assertEquals(1, list.size());
     assertIndexIsOutOfBounds(list, -1);
     assertEquals("foo", list.get(0));
@@ -460,7 +460,7 @@
   @GwtIncompatible("SerializableTester")
   public void testAsList2Small() {
     List<String> list = Lists.asList("foo", "bar", new String[0]);
-    ASSERT.that(list).has().exactly("foo", "bar").inOrder();
+    assertThat(list).has().exactly("foo", "bar").inOrder();
     assertEquals(2, list.size());
     assertIndexIsOutOfBounds(list, -1);
     assertEquals("foo", list.get(0));
@@ -532,24 +532,24 @@
 
   @SuppressWarnings("unchecked") // varargs!
   public void testCartesianProduct_binary1x1() {
-    ASSERT.that(Lists.cartesianProduct(list(1), list(2))).has().item(list(1, 2));
+    assertThat(Lists.cartesianProduct(list(1), list(2))).has().item(list(1, 2));
   }
 
   @SuppressWarnings("unchecked") // varargs!
   public void testCartesianProduct_binary1x2() {
-    ASSERT.that(Lists.cartesianProduct(list(1), list(2, 3)))
+    assertThat(Lists.cartesianProduct(list(1), list(2, 3)))
         .has().exactly(list(1, 2), list(1, 3)).inOrder();
   }
 
   @SuppressWarnings("unchecked") // varargs!
   public void testCartesianProduct_binary2x2() {
-    ASSERT.that(Lists.cartesianProduct(list(1, 2), list(3, 4)))
+    assertThat(Lists.cartesianProduct(list(1, 2), list(3, 4)))
         .has().exactly(list(1, 3), list(1, 4), list(2, 3), list(2, 4)).inOrder();
   }
 
   @SuppressWarnings("unchecked") // varargs!
   public void testCartesianProduct_2x2x2() {
-    ASSERT.that(Lists.cartesianProduct(list(0, 1), list(0, 1), list(0, 1))).has().exactly(
+    assertThat(Lists.cartesianProduct(list(0, 1), list(0, 1), list(0, 1))).has().exactly(
         list(0, 0, 0), list(0, 0, 1), list(0, 1, 0), list(0, 1, 1),
         list(1, 0, 0), list(1, 0, 1), list(1, 1, 0), list(1, 1, 1)).inOrder();
   }
@@ -574,7 +574,7 @@
     List<Object> exp3 = list((Object) 2, "3");
     List<Object> exp4 = list((Object) 2, "4");
 
-    ASSERT.that(Lists.<Object>cartesianProduct(x, y))
+    assertThat(Lists.<Object>cartesianProduct(x, y))
         .has().exactly(exp1, exp2, exp3, exp4).inOrder();
   }
 
diff --git a/guava-tests/test/com/google/common/collect/MapConstraintsTest.java b/guava-tests/test/com/google/common/collect/MapConstraintsTest.java
index 3f9fa66..70ac072 100644
--- a/guava-tests/test/com/google/common/collect/MapConstraintsTest.java
+++ b/guava-tests/test/com/google/common/collect/MapConstraintsTest.java
@@ -17,7 +17,7 @@
 package com.google.common.collect;
 
 import static com.google.common.collect.testing.Helpers.nefariousMapEntry;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -115,7 +115,7 @@
     assertFalse(map.values() instanceof Serializable);
     assertEquals(map.toString(), constrained.toString());
     assertEquals(map.hashCode(), constrained.hashCode());
-    ASSERT.that(map.entrySet()).has().exactly(
+    assertThat(map.entrySet()).has().exactly(
         Maps.immutableEntry(TEST_KEY, TEST_VALUE),
         Maps.immutableEntry("foo", 1),
         Maps.immutableEntry("bar", 2),
@@ -163,7 +163,7 @@
     assertEquals(map.values(), constrained.values());
     assertEquals(map.toString(), constrained.toString());
     assertEquals(map.hashCode(), constrained.hashCode());
-    ASSERT.that(map.entrySet()).has().exactly(
+    assertThat(map.entrySet()).has().exactly(
         Maps.immutableEntry(TEST_KEY, TEST_VALUE),
         Maps.immutableEntry("foo", 1),
         Maps.immutableEntry("bar", 2),
@@ -230,9 +230,9 @@
         .put("dag", 11).build());
     assertTrue(multimap.equals(constrained));
     assertTrue(constrained.equals(multimap));
-    ASSERT.that(ImmutableList.copyOf(multimap.entries()))
-        .is(ImmutableList.copyOf(constrained.entries()));
-    ASSERT.that(constrained.asMap().get("foo")).has().item(1);
+    assertThat(ImmutableList.copyOf(multimap.entries())).isEqualTo(
+        ImmutableList.copyOf(constrained.entries()));
+    assertThat(constrained.asMap().get("foo")).has().item(1);
     assertNull(constrained.asMap().get("missing"));
     assertEquals(multimap.asMap(), constrained.asMap());
     assertEquals(multimap.values(), constrained.values());
@@ -240,7 +240,7 @@
     assertEquals(multimap.keySet(), constrained.keySet());
     assertEquals(multimap.toString(), constrained.toString());
     assertEquals(multimap.hashCode(), constrained.hashCode());
-    ASSERT.that(multimap.entries()).has().exactly(
+    assertThat(multimap.entries()).has().exactly(
         Maps.immutableEntry(TEST_KEY, TEST_VALUE),
         Maps.immutableEntry("foo", 1),
         Maps.immutableEntry("bar", 2),
@@ -407,8 +407,8 @@
           .add(TEST_VALUE);
       fail("TestValueException expected");
     } catch (TestValueException expected) {}
-    ASSERT.that(ImmutableList.copyOf(multimap.entries()))
-        .is(ImmutableList.copyOf(constrained.entries()));
+    assertThat(ImmutableList.copyOf(multimap.entries())).isEqualTo(
+        ImmutableList.copyOf(constrained.entries()));
     assertEquals(multimap.asMap(), constrained.asMap());
     assertEquals(multimap.values(), constrained.values());
     assertEquals(multimap.keys(), constrained.keys());
diff --git a/guava-tests/test/com/google/common/collect/MapMakerTest.java b/guava-tests/test/com/google/common/collect/MapMakerTest.java
index 27e34b9..3d12ec3 100644
--- a/guava-tests/test/com/google/common/collect/MapMakerTest.java
+++ b/guava-tests/test/com/google/common/collect/MapMakerTest.java
@@ -17,7 +17,7 @@
 package com.google.common.collect;
 
 import static com.google.common.util.concurrent.Uninterruptibles.awaitUninterruptibly;
-import static java.util.concurrent.TimeUnit.SECONDS;
+import static java.util.concurrent.TimeUnit.HOURS;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -222,10 +222,10 @@
 
     @SuppressWarnings("deprecation") // test of deprecated method
     public void testExpiration_setTwice() {
-      MapMaker maker = new MapMaker().expireAfterWrite(1 * 60 * 60, SECONDS);
+      MapMaker maker = new MapMaker().expireAfterWrite(1, HOURS);
       try {
         // even to the same value is not allowed
-        maker.expireAfterWrite(1 * 60 * 60, SECONDS);
+        maker.expireAfterWrite(1, HOURS);
         fail();
       } catch (IllegalStateException expected) {
       }
diff --git a/guava-tests/test/com/google/common/collect/MapsCollectionTest.java b/guava-tests/test/com/google/common/collect/MapsCollectionTest.java
index a6f4b04..2024399 100644
--- a/guava-tests/test/com/google/common/collect/MapsCollectionTest.java
+++ b/guava-tests/test/com/google/common/collect/MapsCollectionTest.java
@@ -25,6 +25,7 @@
 import com.google.common.collect.Maps.EntryTransformer;
 import com.google.common.collect.testing.Helpers;
 import com.google.common.collect.testing.MapTestSuiteBuilder;
+import com.google.common.collect.testing.NavigableMapTestSuiteBuilder;
 import com.google.common.collect.testing.SafeTreeMap;
 import com.google.common.collect.testing.SampleElements;
 import com.google.common.collect.testing.SortedMapTestSuiteBuilder;
@@ -42,12 +43,13 @@
 import junit.framework.TestCase;
 import junit.framework.TestSuite;
 
-import java.io.UnsupportedEncodingException;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.SortedSet;
@@ -63,6 +65,20 @@
   public static Test suite() {
     TestSuite suite = new TestSuite();
 
+    suite.addTest(NavigableMapTestSuiteBuilder
+        .using(new TestStringSortedMapGenerator() {
+          @Override
+          protected SortedMap<String, String> create(Entry<String, String>[] entries) {
+            SafeTreeMap<String, String> map = new SafeTreeMap<String, String>();
+            putEntries(map, entries);
+            return Maps.unmodifiableNavigableMap(map);
+          }
+        })
+        .named("unmodifiableNavigableMap[SafeTreeMap]")
+        .withFeatures(CollectionSize.ANY,
+            MapFeature.ALLOWS_NULL_VALUES,
+            CollectionFeature.SERIALIZABLE)
+        .createTestSuite());
     suite.addTest(BiMapTestSuiteBuilder
         .using(new TestStringBiMapGenerator() {
           @Override
@@ -196,6 +212,67 @@
           }
         })
         .named("Maps.asMap[SortedSet, Function]")
+        .withFeatures(CollectionSize.ANY, 
+            CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
+            MapFeature.SUPPORTS_REMOVE)
+        .createTestSuite());
+    suite.addTest(NavigableMapTestSuiteBuilder
+        .using(new TestMapGenerator<String, Integer>() {
+          @Override
+          public String[] createKeyArray(int length) {
+            return new String[length];
+          }
+
+          @Override
+          public Integer[] createValueArray(int length) {
+            return new Integer[length];
+          }
+
+          @Override
+          public SampleElements<Entry<String, Integer>> samples() {
+            return new SampleElements<Entry<String, Integer>>(
+                mapEntry("a", 1),
+                mapEntry("aa", 2),
+                mapEntry("aba", 3),
+                mapEntry("bbbb", 4),
+                mapEntry("ccccc", 5));
+          }
+
+          @Override
+          public NavigableMap<String, Integer> create(Object... elements) {
+            NavigableSet<String> set = Sets.newTreeSet(Ordering.natural());
+            for (Object e : elements) {
+              Map.Entry<?, ?> entry = (Entry<?, ?>) e;
+              checkNotNull(entry.getValue());
+              set.add((String) checkNotNull(entry.getKey()));
+            }
+            return Maps.asMap(set, new Function<String, Integer>() {
+              @Override
+              public Integer apply(String input) {
+                return input.length();
+              }
+            });
+          }
+
+          @SuppressWarnings("unchecked")
+          @Override
+          public Entry<String, Integer>[] createArray(int length) {
+            return new Entry[length];
+          }
+
+          @Override
+          public Iterable<Entry<String, Integer>> order(
+              List<Entry<String, Integer>> insertionOrder) {
+            Collections.sort(insertionOrder, new Comparator<Entry<String, Integer>>() {
+              @Override
+              public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
+                return o1.getKey().compareTo(o2.getKey());
+              }
+            });
+            return insertionOrder;
+          }
+        })
+        .named("Maps.asMap[NavigableSet, Function]")
         .withFeatures(CollectionSize.ANY,
             MapFeature.SUPPORTS_REMOVE,
             CollectionFeature.SUPPORTS_ITERATOR_REMOVE)
@@ -210,6 +287,7 @@
     suite.addTest(filterMapSuite());
     suite.addTest(filterBiMapSuite());
     suite.addTest(filterSortedMapSuite());
+    suite.addTest(filterNavigableMapSuite());
     return suite;
   }
   
@@ -392,6 +470,59 @@
     return suite;
   }
   
+  static TestSuite filterNavigableMapSuite() {
+    TestSuite suite = new TestSuite("FilterNavigableMap");
+    suite.addTest(NavigableMapTestSuiteBuilder.using(new TestStringSortedMapGenerator() {
+      @Override
+      protected NavigableMap<String, String> create(Entry<String, String>[] entries) {
+        NavigableMap<String, String> map = new SafeTreeMap<String, String>();
+        putEntries(map, entries);
+        map.put("banana", "toast");
+        map.put("eggplant", "spam");
+        return Maps.filterKeys(map, FILTER_KEYS);
+      }
+    })
+    .named("Maps.filterKeys[NavigableMap, Predicate]")
+    .withFeatures(
+        MapFeature.ALLOWS_NULL_VALUES,
+        MapFeature.GENERAL_PURPOSE,
+        CollectionSize.ANY)
+        .createTestSuite());
+    suite.addTest(NavigableMapTestSuiteBuilder.using(new TestStringSortedMapGenerator() {
+      @Override
+      protected NavigableMap<String, String> create(Entry<String, String>[] entries) {
+        NavigableMap<String, String> map = new SafeTreeMap<String, String>();
+        putEntries(map, entries);
+        map.put("banana", "toast");
+        map.put("eggplant", "spam");
+          return Maps.filterValues(map, FILTER_VALUES);
+        }
+      })
+      .named("Maps.filterValues[NavigableMap, Predicate]")
+      .withFeatures(
+          MapFeature.ALLOWS_NULL_VALUES,
+          MapFeature.GENERAL_PURPOSE,
+          CollectionSize.ANY)
+          .createTestSuite());
+    suite.addTest(NavigableMapTestSuiteBuilder.using(new TestStringSortedMapGenerator() {
+      @Override
+      protected NavigableMap<String, String> create(Entry<String, String>[] entries) {
+        NavigableMap<String, String> map = new SafeTreeMap<String, String>();
+        putEntries(map, entries);
+        map.put("banana", "toast");
+        map.put("eggplant", "spam");
+          return Maps.filterEntries(map, FILTER_ENTRIES);
+        }
+      })
+      .named("Maps.filterEntries[NavigableMap, Predicate]")
+      .withFeatures(
+          MapFeature.ALLOWS_NULL_VALUES,
+          MapFeature.GENERAL_PURPOSE,
+          CollectionSize.ANY)
+          .createTestSuite());
+    return suite;
+  }
+  
   static void putEntries(Map<String, String> map, Entry<String, String>[] entries) {
     for (Entry<String, String> entry : entries) {
        map.put(entry.getKey(), entry.getValue());
@@ -472,21 +603,13 @@
   }
   
   private static String encode(String str) {
-    try {
-      return BaseEncoding.base64().encode(str.getBytes(Charsets.UTF_8.name()));
-    } catch (UnsupportedEncodingException e) {
-      throw new AssertionError(e);
-    }
+    return BaseEncoding.base64().encode(str.getBytes(Charsets.UTF_8));
   }
   
   private static final Function<String, String> DECODE_FUNCTION = new Function<String, String>() {
     @Override
     public String apply(String input) {
-      try {
-        return new String(BaseEncoding.base64().decode(input), Charsets.UTF_8.name());
-      } catch (UnsupportedEncodingException e) {
-        throw new AssertionError(e);
-      }
+      return new String(BaseEncoding.base64().decode(input), Charsets.UTF_8);
     }    
   };
   
@@ -502,6 +625,7 @@
     TestSuite suite = new TestSuite("Maps.transform");
     suite.addTest(transformMapSuite());
     suite.addTest(transformSortedMapSuite());
+    suite.addTest(transformNavigableMapSuite());
     return suite;
   }
   
@@ -586,4 +710,43 @@
       .createTestSuite());
     return suite;
   }
+  
+  static TestSuite transformNavigableMapSuite() {
+    TestSuite suite = new TestSuite("TransformNavigableMap");
+    suite.addTest(NavigableMapTestSuiteBuilder.using(new TestStringSortedMapGenerator() {
+        @Override
+        protected NavigableMap<String, String> create(Entry<String, String>[] entries) {
+          NavigableMap<String, String> map = new SafeTreeMap<String, String>();
+          for (Entry<String, String> entry : entries) {
+            map.put(entry.getKey(), encode(entry.getValue()));
+          }
+          return Maps.transformValues(map, DECODE_FUNCTION);
+        }
+      })
+      .named("Maps.transformValues[NavigableMap, Function]")
+      .withFeatures(
+          CollectionSize.ANY,
+          CollectionFeature.KNOWN_ORDER,
+          MapFeature.SUPPORTS_REMOVE,
+          CollectionFeature.SUPPORTS_ITERATOR_REMOVE)
+      .createTestSuite());
+    suite.addTest(NavigableMapTestSuiteBuilder.using(new TestStringSortedMapGenerator() {
+        @Override
+        protected NavigableMap<String, String> create(Entry<String, String>[] entries) {
+          NavigableMap<String, String> map = new SafeTreeMap<String, String>();
+          for (Entry<String, String> entry : entries) {
+            map.put(entry.getKey(), encode(entry.getValue()));
+          }
+          return Maps.transformEntries(map, DECODE_ENTRY_TRANSFORMER);
+        }
+      })
+      .named("Maps.transformEntries[NavigableMap, EntryTransformer]")
+      .withFeatures(
+          CollectionSize.ANY,
+          CollectionFeature.KNOWN_ORDER,
+          MapFeature.SUPPORTS_REMOVE,
+          CollectionFeature.SUPPORTS_ITERATOR_REMOVE)
+      .createTestSuite());
+    return suite;
+  }
 }
diff --git a/guava-tests/test/com/google/common/collect/MapsTest.java b/guava-tests/test/com/google/common/collect/MapsTest.java
index 2eddd09..226d831 100644
--- a/guava-tests/test/com/google/common/collect/MapsTest.java
+++ b/guava-tests/test/com/google/common/collect/MapsTest.java
@@ -18,9 +18,10 @@
 
 import static com.google.common.collect.Maps.transformEntries;
 import static com.google.common.collect.Maps.transformValues;
+import static com.google.common.collect.Maps.unmodifiableNavigableMap;
 import static com.google.common.collect.testing.Helpers.mapEntry;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -40,7 +41,7 @@
 import junit.framework.TestCase;
 
 import java.io.IOException;
-import java.io.StringBufferInputStream;
+import java.io.StringReader;
 import java.lang.reflect.Field;
 import java.util.Arrays;
 import java.util.Collection;
@@ -55,6 +56,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
 import java.util.Properties;
 import java.util.Set;
 import java.util.SortedMap;
@@ -241,9 +244,9 @@
     assertEquals(Collections.emptyMap(), map);
     map.put(new Derived("foo"), 1);
     map.put(new Derived("bar"), 2);
-    ASSERT.that(map.keySet()).has().exactly(
+    assertThat(map.keySet()).has().exactly(
         new Derived("bar"), new Derived("foo")).inOrder();
-    ASSERT.that(map.values()).has().exactly(2, 1).inOrder();
+    assertThat(map.values()).has().exactly(2, 1).inOrder();
     assertNull(map.comparator());
   }
 
@@ -252,9 +255,9 @@
     assertEquals(Collections.emptyMap(), map);
     map.put(new LegacyComparable("foo"), 1);
     map.put(new LegacyComparable("bar"), 2);
-    ASSERT.that(map.keySet()).has().exactly(
+    assertThat(map.keySet()).has().exactly(
         new LegacyComparable("bar"), new LegacyComparable("foo")).inOrder();
-    ASSERT.that(map.values()).has().exactly(2, 1).inOrder();
+    assertThat(map.values()).has().exactly(2, 1).inOrder();
     assertNull(map.comparator());
   }
 
@@ -523,13 +526,13 @@
     SortedMapDifference<Integer, String> diff1 =
         Maps.difference(left, right);
     assertFalse(diff1.areEqual());
-    ASSERT.that(diff1.entriesOnlyOnLeft().entrySet()).has().exactly(
+    assertThat(diff1.entriesOnlyOnLeft().entrySet()).has().exactly(
         Maps.immutableEntry(4, "d"), Maps.immutableEntry(2, "b")).inOrder();
-    ASSERT.that(diff1.entriesOnlyOnRight().entrySet()).has().item(
+    assertThat(diff1.entriesOnlyOnRight().entrySet()).has().item(
         Maps.immutableEntry(6, "z"));
-    ASSERT.that(diff1.entriesInCommon().entrySet()).has().item(
+    assertThat(diff1.entriesInCommon().entrySet()).has().item(
         Maps.immutableEntry(1, "a"));
-    ASSERT.that(diff1.entriesDiffering().entrySet()).has().exactly(
+    assertThat(diff1.entriesDiffering().entrySet()).has().exactly(
         Maps.immutableEntry(5, ValueDifferenceImpl.create("e", "g")),
         Maps.immutableEntry(3, ValueDifferenceImpl.create("c", "f"))).inOrder();
     assertEquals("not equal: only on left={4=d, 2=b}: only on right={6=z}: "
@@ -538,11 +541,11 @@
     SortedMapDifference<Integer, String> diff2 =
         Maps.difference(right, left);
     assertFalse(diff2.areEqual());
-    ASSERT.that(diff2.entriesOnlyOnLeft().entrySet()).has().item(
+    assertThat(diff2.entriesOnlyOnLeft().entrySet()).has().item(
         Maps.immutableEntry(6, "z"));
-    ASSERT.that(diff2.entriesOnlyOnRight().entrySet()).has().exactly(
+    assertThat(diff2.entriesOnlyOnRight().entrySet()).has().exactly(
         Maps.immutableEntry(2, "b"), Maps.immutableEntry(4, "d")).inOrder();
-    ASSERT.that(diff1.entriesInCommon().entrySet()).has().item(
+    assertThat(diff1.entriesInCommon().entrySet()).has().item(
         Maps.immutableEntry(1, "a"));
     assertEquals(ImmutableMap.of(
             3, ValueDifferenceImpl.create("f", "c"),
@@ -562,13 +565,13 @@
         Maps.difference(left, right);
     left.put(6, "z");
     assertFalse(diff1.areEqual());
-    ASSERT.that(diff1.entriesOnlyOnLeft().entrySet()).has().exactly(
+    assertThat(diff1.entriesOnlyOnLeft().entrySet()).has().exactly(
         Maps.immutableEntry(2, "b"), Maps.immutableEntry(4, "d")).inOrder();
-    ASSERT.that(diff1.entriesOnlyOnRight().entrySet()).has().item(
+    assertThat(diff1.entriesOnlyOnRight().entrySet()).has().item(
         Maps.immutableEntry(6, "z"));
-    ASSERT.that(diff1.entriesInCommon().entrySet()).has().item(
+    assertThat(diff1.entriesInCommon().entrySet()).has().item(
         Maps.immutableEntry(1, "a"));
-    ASSERT.that(diff1.entriesDiffering().entrySet()).has().exactly(
+    assertThat(diff1.entriesDiffering().entrySet()).has().exactly(
         Maps.immutableEntry(3, ValueDifferenceImpl.create("c", "f")),
         Maps.immutableEntry(5, ValueDifferenceImpl.create("e", "g"))).inOrder();
     try {
@@ -625,7 +628,7 @@
     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
     assertEquals(Integer.valueOf(5), map.get("three"));
     assertNull(map.get("five"));
-    ASSERT.that(map.entrySet()).has().exactly(
+    assertThat(map.entrySet()).has().exactly(
         mapEntry("one", 3),
         mapEntry("two", 3),
         mapEntry("three", 5)).inOrder();
@@ -648,13 +651,13 @@
     Map<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION);
     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
     assertEquals(Integer.valueOf(3), map.remove("two"));
-    ASSERT.that(strings).has().exactly("one", "three").inOrder();
+    assertThat(strings).has().exactly("one", "three").inOrder();
   }
 
   public void testAsMapEmpty() {
     Set<String> strings = ImmutableSet.of();
     Map<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION);
-    ASSERT.that(map.entrySet()).isEmpty();
+    assertThat(map.entrySet()).isEmpty();
     assertTrue(map.isEmpty());
     assertNull(map.get("five"));
   }
@@ -681,14 +684,14 @@
     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
     assertEquals(Integer.valueOf(5), map.get("three"));
     assertNull(map.get("five"));
-    ASSERT.that(map.entrySet()).has().exactly(
+    assertThat(map.entrySet()).has().exactly(
         mapEntry("one", 3),
         mapEntry("three", 5),
         mapEntry("two", 3)).inOrder();
-    ASSERT.that(map.tailMap("onea").entrySet()).has().exactly(
+    assertThat(map.tailMap("onea").entrySet()).has().exactly(
         mapEntry("three", 5),
         mapEntry("two", 3)).inOrder();
-    ASSERT.that(map.subMap("one", "two").entrySet()).has().exactly(
+    assertThat(map.subMap("one", "two").entrySet()).has().exactly(
         mapEntry("one", 3),
         mapEntry("three", 5)).inOrder();
   }
@@ -714,7 +717,7 @@
     assertEquals(
         ImmutableSortedMap.of("five", 4, "four", 4, "three", 5),
         headMap);
-    ASSERT.that(map.entrySet()).has().exactly(
+    assertThat(map.entrySet()).has().exactly(
         mapEntry("five", 4),
         mapEntry("four", 4),
         mapEntry("three", 5),
@@ -727,7 +730,7 @@
     SortedMap<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION);
     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
     assertEquals(Integer.valueOf(3), map.remove("two"));
-    ASSERT.that(strings).has().exactly("one", "three").inOrder();
+    assertThat(strings).has().exactly("one", "three").inOrder();
   }
 
   public void testAsMapSortedSubViewKeySetsDoNotSupportAdd() {
@@ -758,7 +761,165 @@
   public void testAsMapSortedEmpty() {
     SortedSet<String> strings = new NonNavigableSortedSet();
     SortedMap<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION);
-    ASSERT.that(map.entrySet()).isEmpty();
+    assertThat(map.entrySet()).isEmpty();
+    assertTrue(map.isEmpty());
+    assertNull(map.get("five"));
+  }
+
+  @GwtIncompatible("NavigableMap")
+  public void testAsMapReturnsNavigableMapForNavigableSetInput() {
+    Set<String> set = Sets.newTreeSet();
+    assertTrue(Maps.asMap(set, Functions.identity()) instanceof NavigableMap);
+  }
+
+  @GwtIncompatible("NavigableMap")
+  public void testAsMapNavigable() {
+    NavigableSet<String> strings =
+        Sets.newTreeSet(asList("one", "two", "three"));
+    NavigableMap<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION);
+    assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
+    assertEquals(Integer.valueOf(5), map.get("three"));
+    assertNull(map.get("five"));
+    assertThat(map.entrySet()).has().exactly(
+        mapEntry("one", 3),
+        mapEntry("three", 5),
+        mapEntry("two", 3)).inOrder();
+    assertThat(map.tailMap("onea").entrySet()).has().exactly(
+        mapEntry("three", 5),
+        mapEntry("two", 3)).inOrder();
+    assertThat(map.subMap("one", "two").entrySet()).has().exactly(
+        mapEntry("one", 3),
+        mapEntry("three", 5)).inOrder();
+
+    assertEquals(ImmutableSortedMap.of("two", 3, "three", 5),
+        map.tailMap("three", true));
+    assertEquals(ImmutableSortedMap.of("one", 3, "three", 5),
+        map.headMap("two", false));
+    assertEquals(ImmutableSortedMap.of("three", 5),
+        map.subMap("one", false, "tr", true));
+
+    assertEquals("three", map.higherKey("one"));
+    assertEquals("three", map.higherKey("r"));
+    assertEquals("three", map.ceilingKey("r"));
+    assertEquals("one", map.ceilingKey("one"));
+    assertEquals(mapEntry("three", 5), map.higherEntry("one"));
+    assertEquals(mapEntry("one", 3), map.ceilingEntry("one"));
+    assertEquals("one", map.lowerKey("three"));
+    assertEquals("one", map.lowerKey("r"));
+    assertEquals("one", map.floorKey("r"));
+    assertEquals("three", map.floorKey("three"));
+
+    assertThat(map.descendingMap().entrySet()).has().exactly(
+        mapEntry("two", 3),
+        mapEntry("three", 5),
+        mapEntry("one", 3)).inOrder();
+    assertEquals(map.headMap("three", true),
+        map.descendingMap().tailMap("three", true));
+    assertThat(map.tailMap("three", false).entrySet()).has().item(
+        mapEntry("two", 3));
+    assertNull(map.tailMap("three", true).lowerEntry("three"));
+    assertThat(map.headMap("two", false).values()).has().exactly(3, 5).inOrder();
+    assertThat(map.headMap("two", false).descendingMap().values())
+        .has().exactly(5, 3).inOrder();
+    assertThat(map.descendingKeySet()).has().exactly(
+        "two", "three", "one").inOrder();
+
+    assertEquals(mapEntry("one", 3), map.pollFirstEntry());
+    assertEquals(mapEntry("two", 3), map.pollLastEntry());
+    assertEquals(1, map.size());
+  }
+
+  @GwtIncompatible("NavigableMap")
+  public void testAsMapNavigableReadsThrough() {
+    NavigableSet<String> strings = Sets.newTreeSet();
+    Collections.addAll(strings, "one", "two", "three");
+    NavigableMap<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION);
+    assertNull(map.comparator());
+    assertEquals(ImmutableSortedMap.of("one", 3, "two", 3, "three", 5), map);
+    assertNull(map.get("four"));
+    strings.add("four");
+    assertEquals(
+        ImmutableSortedMap.of("one", 3, "two", 3, "three", 5, "four", 4),
+        map);
+    assertEquals(Integer.valueOf(4), map.get("four"));
+    SortedMap<String, Integer> headMap = map.headMap("two");
+    assertEquals(
+        ImmutableSortedMap.of("four", 4, "one", 3, "three", 5),
+        headMap);
+    strings.add("five");
+    strings.remove("one");
+    assertEquals(
+        ImmutableSortedMap.of("five", 4, "four", 4, "three", 5),
+        headMap);
+    assertThat(map.entrySet()).has().exactly(
+        mapEntry("five", 4),
+        mapEntry("four", 4),
+        mapEntry("three", 5),
+        mapEntry("two", 3)).inOrder();
+
+    NavigableMap<String, Integer> tailMap = map.tailMap("s", true);
+    NavigableMap<String, Integer> subMap = map.subMap("a", true, "t", false);
+
+    strings.add("six");
+    strings.remove("two");
+    assertThat(tailMap.entrySet()).has().exactly(
+        mapEntry("six", 3),
+        mapEntry("three", 5)).inOrder();
+    assertThat(subMap.entrySet()).has().exactly(
+        mapEntry("five", 4),
+        mapEntry("four", 4),
+        mapEntry("six", 3)).inOrder();
+  }
+
+  @GwtIncompatible("NavigableMap")
+  public void testAsMapNavigableWritesThrough() {
+    NavigableSet<String> strings = Sets.newTreeSet();
+    Collections.addAll(strings, "one", "two", "three");
+    NavigableMap<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION);
+    assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
+    assertEquals(Integer.valueOf(3), map.remove("two"));
+    assertThat(strings).has().exactly("one", "three").inOrder();
+    assertEquals(mapEntry("three", 5),
+        map.subMap("one", false, "zzz", true).pollLastEntry());
+    assertThat(strings).has().item("one");
+  }
+
+  @GwtIncompatible("NavigableMap")
+  public void testAsMapNavigableSubViewKeySetsDoNotSupportAdd() {
+    NavigableMap<String, Integer> map = Maps.asMap(
+        Sets.<String>newTreeSet(), LENGTH_FUNCTION);
+    try {
+      map.descendingKeySet().add("a");
+      fail();
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      map.subMap("a", true, "z", false).keySet().add("a");
+      fail();
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      map.tailMap("a", true).keySet().add("a");
+      fail();
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      map.headMap("r", true).keySet().add("a");
+      fail();
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      map.headMap("r", false).tailMap("m", true).keySet().add("a");
+      fail();
+    } catch (UnsupportedOperationException expected) {
+    }
+  }
+
+  @GwtIncompatible("NavigableMap")
+  public void testAsMapNavigableEmpty() {
+    NavigableSet<String> strings = ImmutableSortedSet.of();
+    NavigableMap<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION);
+    assertThat(map.entrySet()).isEmpty();
     assertTrue(map.isEmpty());
     assertNull(map.get("five"));
   }
@@ -767,7 +928,7 @@
     Iterable<String> strings = ImmutableList.of("one", "two", "three");
     ImmutableMap<String, Integer> map = Maps.toMap(strings, LENGTH_FUNCTION);
     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
-    ASSERT.that(map.entrySet()).has().exactly(
+    assertThat(map.entrySet()).has().exactly(
         mapEntry("one", 3),
         mapEntry("two", 3),
         mapEntry("three", 5)).inOrder();
@@ -777,7 +938,7 @@
     Iterator<String> strings = ImmutableList.of("one", "two", "three").iterator();
     ImmutableMap<String, Integer> map = Maps.toMap(strings, LENGTH_FUNCTION);
     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
-    ASSERT.that(map.entrySet()).has().exactly(
+    assertThat(map.entrySet()).has().exactly(
         mapEntry("one", 3),
         mapEntry("two", 3),
         mapEntry("three", 5)).inOrder();
@@ -787,7 +948,7 @@
     Iterable<String> strings = ImmutableList.of("one", "two", "three", "two", "one");
     ImmutableMap<String, Integer> map = Maps.toMap(strings, LENGTH_FUNCTION);
     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
-    ASSERT.that(map.entrySet()).has().exactly(
+    assertThat(map.entrySet()).has().exactly(
         mapEntry("one", 3),
         mapEntry("two", 3),
         mapEntry("three", 5)).inOrder();
@@ -895,7 +1056,7 @@
     // Now test values loaded from a stream.
     String props = "test\n second = 2\n Third item :   a short  phrase   ";
 
-    testProp.load(new StringBufferInputStream(props));
+    testProp.load(new StringReader(props));
 
     result = Maps.fromProperties(testProp);
     assertEquals(4, result.size());
@@ -913,7 +1074,7 @@
     testProp = new Properties(System.getProperties());
     String override = "test\njava.version : hidden";
 
-    testProp.load(new StringBufferInputStream(override));
+    testProp.load(new StringReader(override));
 
     result = Maps.fromProperties(testProp);
     assertTrue(result.size() > 2);
@@ -957,37 +1118,6 @@
     } catch (ClassCastException expected) {}
   }
 
-  /**
-   * Constructs a "nefarious" map entry with the specified key and value,
-   * meaning an entry that is suitable for testing that map entries cannot be
-   * modified via a nefarious implementation of equals. This is used for testing
-   * unmodifiable collections of map entries; for example, it should not be
-   * possible to access the raw (modifiable) map entry via a nefarious equals
-   * method.
-   */
-  public static <K, V> Map.Entry<K, V> nefariousEntry(
-      final K key, final V value) {
-    return new AbstractMapEntry<K, V>() {
-        @Override public K getKey() {
-          return key;
-        }
-        @Override public V getValue() {
-          return value;
-        }
-        @Override public V setValue(V value) {
-          throw new UnsupportedOperationException();
-        }
-        @SuppressWarnings("unchecked")
-        @Override public boolean equals(Object o) {
-          if (o instanceof Map.Entry) {
-            Map.Entry<K, V> e = (Map.Entry<K, V>) o;
-            e.setValue(value); // muhahaha!
-          }
-          return super.equals(o);
-        }
-      };
-  }
-
   public void testAsConverter_nominal() throws Exception {
     ImmutableBiMap<String, Integer> biMap = ImmutableBiMap.of(
         "one", 1,
@@ -1487,6 +1617,21 @@
     assertTrue(transformed instanceof SortedMap);
   }
 
+  @GwtIncompatible("NavigableMap")
+  public void testTransformValuesSecretlyNavigable() {
+    Map<String, Integer> map = ImmutableSortedMap.of("a", 4, "b", 9);
+    Map<String, Double> transformed;
+
+    transformed = transformValues(map, SQRT_FUNCTION);
+    assertEquals(ImmutableMap.of("a", 2.0, "b", 3.0), transformed);
+    assertTrue(transformed instanceof NavigableMap);
+
+    transformed =
+        transformValues((SortedMap<String, Integer>) map, SQRT_FUNCTION);
+    assertEquals(ImmutableMap.of("a", 2.0, "b", 3.0), transformed);
+    assertTrue(transformed instanceof NavigableMap);
+  }
+
   public void testTransformEntries() {
     Map<String, String> map = ImmutableMap.of("a", "4", "b", "9");
     EntryTransformer<String, String, String> concat =
@@ -1516,6 +1661,27 @@
     assertTrue(transformed instanceof SortedMap);
   }
 
+  @GwtIncompatible("NavigableMap")
+  public void testTransformEntriesSecretlyNavigable() {
+    Map<String, String> map = ImmutableSortedMap.of("a", "4", "b", "9");
+    EntryTransformer<String, String, String> concat =
+        new EntryTransformer<String, String, String>() {
+          @Override
+          public String transformEntry(String key, String value) {
+            return key + value;
+          }
+        };
+    Map<String, String> transformed;
+
+    transformed = transformEntries(map, concat);
+    assertEquals(ImmutableMap.of("a", "a4", "b", "b9"), transformed);
+    assertTrue(transformed instanceof NavigableMap);
+
+    transformed = transformEntries((SortedMap<String, String>) map, concat);
+    assertEquals(ImmutableMap.of("a", "a4", "b", "b9"), transformed);
+    assertTrue(transformed instanceof NavigableMap);
+  }
+
   @SuppressWarnings("unused")
   public void testTransformEntriesGenerics() {
     Map<Object, Object> map1 = ImmutableMap.<Object, Object>of(1, 2);
@@ -1610,6 +1776,15 @@
     assertEquals(ImmutableSortedMap.of("a", 2.0, "b", 3.0), transformed);
   }
 
+  @GwtIncompatible("NavigableMap")
+  public void testNavigableMapTransformValues() {
+    NavigableMap<String, Integer> map = ImmutableSortedMap.of("a", 4, "b", 9);
+    NavigableMap<String, Double> transformed =
+        transformValues(map, SQRT_FUNCTION);
+
+    assertEquals(ImmutableSortedMap.of("a", 2.0, "b", 3.0), transformed);
+  }
+
   public void testSortedMapTransformEntries() {
     SortedMap<String, String> map =
         sortedNotNavigable(ImmutableSortedMap.of("a", "4", "b", "9"));
@@ -1628,4 +1803,160 @@
      */
     assertEquals(ImmutableSortedMap.of("a", "a4", "b", "b9"), transformed);
   }
+
+  @GwtIncompatible("NavigableMap")
+  public void testNavigableMapTransformEntries() {
+    NavigableMap<String, String> map =
+        ImmutableSortedMap.of("a", "4", "b", "9");
+    EntryTransformer<String, String, String> concat =
+        new EntryTransformer<String, String, String>() {
+          @Override
+          public String transformEntry(String key, String value) {
+            return key + value;
+          }
+        };
+    NavigableMap<String, String> transformed = transformEntries(map, concat);
+
+    assertEquals(ImmutableSortedMap.of("a", "a4", "b", "b9"), transformed);
+  }
+
+  @GwtIncompatible("NavigableMap")
+  public void testUnmodifiableNavigableMap() {
+    TreeMap<Integer, String> mod = Maps.newTreeMap();
+    mod.put(1, "one");
+    mod.put(2, "two");
+    mod.put(3, "three");
+
+    NavigableMap<Integer, String> unmod = unmodifiableNavigableMap(mod);
+
+    /* unmod is a view. */
+    mod.put(4, "four");
+    assertEquals("four", unmod.get(4));
+    assertEquals("four", unmod.descendingMap().get(4));
+
+    ensureNotDirectlyModifiable(unmod);
+    ensureNotDirectlyModifiable(unmod.descendingMap());
+    ensureNotDirectlyModifiable(unmod.headMap(2, true));
+    ensureNotDirectlyModifiable(unmod.subMap(1, true, 3, true));
+    ensureNotDirectlyModifiable(unmod.tailMap(2, true));
+
+    Collection<String> values = unmod.values();
+    try {
+      values.add("4");
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      values.remove("four");
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      values.removeAll(Collections.singleton("four"));
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      values.retainAll(Collections.singleton("four"));
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      Iterator<String> iterator = values.iterator();
+      iterator.next();
+      iterator.remove();
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+
+    Set<Map.Entry<Integer, String>> entries = unmod.entrySet();
+    try {
+      Iterator<Map.Entry<Integer, String>> iterator = entries.iterator();
+      iterator.next();
+      iterator.remove();
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    Map.Entry<Integer, String> entry = entries.iterator().next();
+    try {
+      entry.setValue("four");
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    entry = unmod.lowerEntry(1);
+    assertNull(entry);
+    entry = unmod.floorEntry(2);
+    try {
+      entry.setValue("four");
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    entry = unmod.ceilingEntry(2);
+    try {
+      entry.setValue("four");
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    entry = unmod.lowerEntry(2);
+    try {
+      entry.setValue("four");
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    entry = unmod.higherEntry(2);
+    try {
+      entry.setValue("four");
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    entry = unmod.firstEntry();
+    try {
+      entry.setValue("four");
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    entry = unmod.lastEntry();
+    try {
+      entry.setValue("four");
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+        @SuppressWarnings("unchecked")
+    Map.Entry<Integer, String> entry2 =
+        (Map.Entry<Integer, String>) entries.toArray()[0];
+    try {
+      entry2.setValue("four");
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+  }
+
+  @GwtIncompatible("NavigableMap")
+  void ensureNotDirectlyModifiable(NavigableMap<Integer, String> unmod) {
+    try {
+      unmod.put(4, "four");
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      unmod.putAll(Collections.singletonMap(4, "four"));
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      unmod.remove("four");
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      unmod.pollFirstEntry();
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      unmod.pollLastEntry();
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+  }
 }
diff --git a/guava-tests/test/com/google/common/collect/MinMaxPriorityQueueTest.java b/guava-tests/test/com/google/common/collect/MinMaxPriorityQueueTest.java
index c6461c8..803f63f 100644
--- a/guava-tests/test/com/google/common/collect/MinMaxPriorityQueueTest.java
+++ b/guava-tests/test/com/google/common/collect/MinMaxPriorityQueueTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.collect.testing.IteratorFeature;
 import com.google.common.collect.testing.IteratorTester;
@@ -355,7 +355,7 @@
       }
     }
     assertTrue(q.isIntact());
-    ASSERT.that(result).has().exactly(1, 15, 13, 8, 14);
+    assertThat(result).has().exactly(1, 15, 13, 8, 14);
   }
 
   /**
@@ -718,23 +718,23 @@
     List<Integer> contents = Lists.newArrayList(expected);
     List<Integer> elements = Lists.newArrayListWithCapacity(size);
     while (!q.isEmpty()) {
-      ASSERT.that(q).has().exactlyAs(contents);
+      assertThat(q).has().exactlyAs(contents);
       Integer next = q.pollFirst();
       contents.remove(next);
-      ASSERT.that(q).has().exactlyAs(contents);
+      assertThat(q).has().exactlyAs(contents);
       for (int i = 0; i <= size; i++) {
         q.add(i);
         contents.add(i);
-        ASSERT.that(q).has().exactlyAs(contents);
+        assertThat(q).has().exactlyAs(contents);
         q.add(next);
         contents.add(next);
-        ASSERT.that(q).has().exactlyAs(contents);
+        assertThat(q).has().exactlyAs(contents);
         q.remove(i);
         assertTrue(contents.remove(Integer.valueOf(i)));
-        ASSERT.that(q).has().exactlyAs(contents);
+        assertThat(q).has().exactlyAs(contents);
         assertEquals(next, q.poll());
         contents.remove(next);
-        ASSERT.that(q).has().exactlyAs(contents);
+        assertThat(q).has().exactlyAs(contents);
       }
       elements.add(next);
     }
diff --git a/guava-tests/test/com/google/common/collect/MultimapBuilderTest.java b/guava-tests/test/com/google/common/collect/MultimapBuilderTest.java
index 1dd3fa9..5733994 100644
--- a/guava-tests/test/com/google/common/collect/MultimapBuilderTest.java
+++ b/guava-tests/test/com/google/common/collect/MultimapBuilderTest.java
@@ -19,10 +19,13 @@
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
 import com.google.common.collect.MultimapBuilder.MultimapBuilderWithKeys;
-import com.google.common.testing.SerializableTester;
 
 import junit.framework.TestCase;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.math.RoundingMode;
 import java.util.SortedMap;
 import java.util.SortedSet;
@@ -66,7 +69,8 @@
     assertTrue(multimap.asMap() instanceof SortedMap);
   }
 
-  public void testSerialization() {
+  @GwtIncompatible("serialization")
+  public void testSerialization() throws Exception {
     for (MultimapBuilderWithKeys<?> builderWithKeys : ImmutableList.of(
         MultimapBuilder.hashKeys(), MultimapBuilder.linkedHashKeys(), MultimapBuilder.treeKeys(),
         MultimapBuilder.enumKeys(RoundingMode.class))) {
@@ -77,8 +81,25 @@
           builderWithKeys.linkedHashSetValues(),
           builderWithKeys.treeSetValues(),
           builderWithKeys.enumSetValues(RoundingMode.class))) {
-        SerializableTester.reserializeAndAssert(builder.build());
+        /*
+         * Temporarily inlining SerializableTester here for obscure internal reasons.
+         */
+        reserializeAndAssert(builder.build());
       }
     }
   }
+
+  @GwtIncompatible("serialization")
+  private static void reserializeAndAssert(Object object) throws Exception {
+    Object copy = reserialize(object);
+    assertEquals(object, copy);
+    assertEquals(object.getClass(), copy.getClass());
+  }
+
+  @GwtIncompatible("serialization")
+  private static Object reserialize(Object object) throws Exception {
+    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+    new ObjectOutputStream(bytes).writeObject(object);
+    return new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray())).readObject();
+  }
 }
diff --git a/guava-tests/test/com/google/common/collect/MultimapsTest.java b/guava-tests/test/com/google/common/collect/MultimapsTest.java
index c99681a..43123ef 100644
--- a/guava-tests/test/com/google/common/collect/MultimapsTest.java
+++ b/guava-tests/test/com/google/common/collect/MultimapsTest.java
@@ -21,8 +21,8 @@
 import static com.google.common.collect.Sets.newHashSet;
 import static com.google.common.collect.testing.Helpers.nefariousMapEntry;
 import static com.google.common.collect.testing.IteratorFeature.MODIFIABLE;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -297,7 +297,7 @@
     assertEquals(multimap.hashCode(), unmodifiable.hashCode());
     assertEquals(multimap, unmodifiable);
 
-    ASSERT.that(unmodifiable.asMap().get("bar")).has().exactly(5, -1);
+    assertThat(unmodifiable.asMap().get("bar")).has().exactly(5, -1);
     assertNull(unmodifiable.asMap().get("missing"));
 
     assertFalse(unmodifiable.entries() instanceof Serializable);
@@ -454,11 +454,11 @@
     assertFalse(map.containsKey("bar"));
     assertEquals(map.keySet(), multimapView.keySet());
     assertEquals(map.keySet(), multimapView.keys().elementSet());
-    ASSERT.that(multimapView.keys()).has().item("foo");
-    ASSERT.that(multimapView.values()).has().item(1);
-    ASSERT.that(multimapView.entries()).has().item(
+    assertThat(multimapView.keys()).has().item("foo");
+    assertThat(multimapView.values()).has().item(1);
+    assertThat(multimapView.entries()).has().item(
         Maps.immutableEntry("foo", 1));
-    ASSERT.that(multimapView.asMap().entrySet()).has().item(
+    assertThat(multimapView.asMap().entrySet()).has().item(
         Maps.immutableEntry(
             "foo", (Collection<Integer>) Collections.singleton(1)));
     multimapView.clear();
@@ -615,7 +615,7 @@
     } catch (IllegalArgumentException expected) {
       // expected
     }
-    ASSERT.that(multimap.entries()).has().exactly(
+    assertThat(multimap.entries()).has().exactly(
         Maps.immutableEntry(Color.RED, 1),
         Maps.immutableEntry(Color.BLUE, 2));
   }
@@ -838,7 +838,7 @@
       }
     };
     Multimap<String, Integer> transformed = Multimaps.transformValues(multimap, square);
-    ASSERT.that(transformed.entries()).has().exactly(immutableEntry("a", 4),
+    assertThat(transformed.entries()).has().exactly(immutableEntry("a", 4),
         immutableEntry("a", 16), immutableEntry("b", 9), immutableEntry("b", 9),
         immutableEntry("c", 36)).inOrder();
   }
@@ -856,7 +856,7 @@
         });
     Entry<String, String> entry = multimap.entries().iterator().next();
     entry.setValue("bbb");
-    ASSERT.that(transformed.entries()).has().exactly(immutableEntry("a", 3)).inOrder();
+    assertThat(transformed.entries()).has().exactly(immutableEntry("a", 3)).inOrder();
   }
 
   @GwtIncompatible(value = "untested")
@@ -871,7 +871,7 @@
     };
     ListMultimap<String, Integer> transformed =
         Multimaps.transformValues(multimap, square);
-    ASSERT.that(transformed.entries()).has().exactly(immutableEntry("a", 4),
+    assertThat(transformed.entries()).has().exactly(immutableEntry("a", 4),
         immutableEntry("a", 16), immutableEntry("b", 9), immutableEntry("b", 9),
         immutableEntry("c", 36)).inOrder();
   }
@@ -889,7 +889,7 @@
         };
     Multimap<String, String> transformed =
         Multimaps.transformEntries(multimap, transformer);
-    ASSERT.that(transformed.entries()).has().exactly(immutableEntry("a", "a"),
+    assertThat(transformed.entries()).has().exactly(immutableEntry("a", "a"),
         immutableEntry("a", "a"), immutableEntry("b", "nob")).inOrder();
   }
 
@@ -959,7 +959,7 @@
     SetMultimap<String, Integer> filtered = Multimaps.filterKeys(
         multimap, Predicates.in(ImmutableSet.of("foo", "bar")));
     Set<Integer> bazSet = filtered.get("baz");
-    ASSERT.that(bazSet).isEmpty();
+    assertThat(bazSet).isEmpty();
     try {
       bazSet.add(5);
       fail("Expected IllegalArgumentException");
@@ -982,7 +982,7 @@
     ListMultimap<String, Integer> filtered = Multimaps.filterKeys(
         multimap, Predicates.in(ImmutableSet.of("foo", "bar")));
     List<Integer> bazList = filtered.get("baz");
-    ASSERT.that(bazList).isEmpty();
+    assertThat(bazList).isEmpty();
     try {
       bazList.add(5);
       fail("Expected IllegalArgumentException");
diff --git a/guava-tests/test/com/google/common/collect/MultisetsTest.java b/guava-tests/test/com/google/common/collect/MultisetsTest.java
index 69cf56a..6623e15 100644
--- a/guava-tests/test/com/google/common/collect/MultisetsTest.java
+++ b/guava-tests/test/com/google/common/collect/MultisetsTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -27,6 +27,7 @@
 
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.List;
 
 /**
  * Tests for {@link Multisets}.
@@ -45,7 +46,7 @@
     assertTrue(set.isEmpty());
     set.add(new DerivedComparable("foo"), 2);
     set.add(new DerivedComparable("bar"), 3);
-    ASSERT.that(set).has().exactly(
+    assertThat(set).has().exactly(
         new DerivedComparable("bar"), new DerivedComparable("bar"), new DerivedComparable("bar"),
         new DerivedComparable("foo"), new DerivedComparable("foo")).inOrder();
   }
@@ -55,7 +56,7 @@
     assertTrue(set.isEmpty());
     set.add(new LegacyComparable("foo"), 2);
     set.add(new LegacyComparable("bar"), 3);
-    ASSERT.that(set).has().exactly(new LegacyComparable("bar"),
+    assertThat(set).has().exactly(new LegacyComparable("bar"),
         new LegacyComparable("bar"), new LegacyComparable("bar"),
         new LegacyComparable("foo"), new LegacyComparable("foo")).inOrder();
   }
@@ -65,7 +66,7 @@
         = TreeMultiset.create(Collections.reverseOrder());
     multiset.add("bar", 3);
     multiset.add("foo", 2);
-    ASSERT.that(multiset).has().exactly("foo", "foo", "bar", "bar", "bar").inOrder();
+    assertThat(multiset).has().exactly("foo", "foo", "bar", "bar", "bar").inOrder();
   }
 
   public void testRetainOccurrencesEmpty() {
@@ -73,10 +74,17 @@
     Multiset<String> toRetain =
         HashMultiset.create(Arrays.asList("a", "b", "a"));
     assertFalse(Multisets.retainOccurrences(multiset, toRetain));
-    ASSERT.that(multiset).isEmpty();
+    assertThat(multiset).isEmpty();
   }
 
-  public void testRemoveOccurrencesEmpty() {
+  public void testRemoveOccurrencesIterableEmpty() {
+    Multiset<String> multiset = HashMultiset.create();
+    Iterable<String> toRemove = Arrays.asList("a", "b", "a");
+    assertFalse(Multisets.removeOccurrences(multiset, toRemove));
+    assertTrue(multiset.isEmpty());
+  }
+
+  public void testRemoveOccurrencesMultisetEmpty() {
     Multiset<String> multiset = HashMultiset.create();
     Multiset<String> toRemove =
         HashMultiset.create(Arrays.asList("a", "b", "a"));
@@ -88,7 +96,7 @@
     Multiset<String> ms1 = HashMultiset.create(Arrays.asList("a", "b", "a"));
     Multiset<String> ms2 = HashMultiset.create(
         Arrays.asList("a", "b", "b", "c"));
-    ASSERT.that(Multisets.union(ms1, ms2)).has().exactly("a", "a", "b", "b", "c");
+    assertThat(Multisets.union(ms1, ms2)).has().exactly("a", "a", "b", "b", "c");
   }
 
   public void testUnionEqualMultisets() {
@@ -112,50 +120,50 @@
   public void testIntersectEmptyNonempty() {
     Multiset<String> ms1 = HashMultiset.create();
     Multiset<String> ms2 = HashMultiset.create(Arrays.asList("a", "b", "a"));
-    ASSERT.that(Multisets.intersection(ms1, ms2)).isEmpty();
+    assertThat(Multisets.intersection(ms1, ms2)).isEmpty();
   }
 
   public void testIntersectNonemptyEmpty() {
     Multiset<String> ms1 = HashMultiset.create(Arrays.asList("a", "b", "a"));
     Multiset<String> ms2 = HashMultiset.create();
-    ASSERT.that(Multisets.intersection(ms1, ms2)).isEmpty();
+    assertThat(Multisets.intersection(ms1, ms2)).isEmpty();
   }
 
   public void testSum() {
     Multiset<String> ms1 = HashMultiset.create(Arrays.asList("a", "b", "a"));
     Multiset<String> ms2 = HashMultiset.create(Arrays.asList("b", "c"));
-    ASSERT.that(Multisets.sum(ms1, ms2)).has().exactly("a", "a", "b", "b", "c");
+    assertThat(Multisets.sum(ms1, ms2)).has().exactly("a", "a", "b", "b", "c");
   }
 
   public void testSumEmptyNonempty() {
     Multiset<String> ms1 = HashMultiset.create();
     Multiset<String> ms2 = HashMultiset.create(Arrays.asList("a", "b", "a"));
-    ASSERT.that(Multisets.sum(ms1, ms2)).has().exactly("a", "b", "a");
+    assertThat(Multisets.sum(ms1, ms2)).has().exactly("a", "b", "a");
   }
 
   public void testSumNonemptyEmpty() {
     Multiset<String> ms1 = HashMultiset.create(Arrays.asList("a", "b", "a"));
     Multiset<String> ms2 = HashMultiset.create();
-    ASSERT.that(Multisets.sum(ms1, ms2)).has().exactly("a", "b", "a");
+    assertThat(Multisets.sum(ms1, ms2)).has().exactly("a", "b", "a");
   }
 
   public void testDifferenceWithNoRemovedElements() {
     Multiset<String> ms1 = HashMultiset.create(Arrays.asList("a", "b", "a"));
     Multiset<String> ms2 = HashMultiset.create(Arrays.asList("a"));
-    ASSERT.that(Multisets.difference(ms1, ms2)).has().exactly("a", "b");
+    assertThat(Multisets.difference(ms1, ms2)).has().exactly("a", "b");
   }
 
   public void testDifferenceWithRemovedElement() {
     Multiset<String> ms1 = HashMultiset.create(Arrays.asList("a", "b", "a"));
     Multiset<String> ms2 = HashMultiset.create(Arrays.asList("b"));
-    ASSERT.that(Multisets.difference(ms1, ms2)).has().exactly("a", "a");
+    assertThat(Multisets.difference(ms1, ms2)).has().exactly("a", "a");
   }
 
   public void testDifferenceWithMoreElementsInSecondMultiset() {
     Multiset<String> ms1 = HashMultiset.create(Arrays.asList("a", "b", "a"));
     Multiset<String> ms2 = HashMultiset.create(Arrays.asList("a", "b", "b", "b"));
     Multiset<String> diff = Multisets.difference(ms1, ms2);
-    ASSERT.that(diff).has().item("a");
+    assertThat(diff).has().item("a");
     assertEquals(0, diff.count("b"));
     assertEquals(1, diff.count("a"));
     assertFalse(diff.contains("b"));
@@ -205,24 +213,40 @@
     Multiset<String> toRetain =
         HashMultiset.create(Arrays.asList("a", "b", "b"));
     assertTrue(Multisets.retainOccurrences(multiset, toRetain));
-    ASSERT.that(multiset).has().exactly("a", "b").inOrder();
+    assertThat(multiset).has().exactly("a", "b").inOrder();
   }
 
-  public void testRemoveEmptyOccurrences() {
+  public void testRemoveEmptyOccurrencesMultiset() {
     Multiset<String> multiset =
         TreeMultiset.create(Arrays.asList("a", "b", "a"));
     Multiset<String> toRemove = HashMultiset.create();
     assertFalse(Multisets.removeOccurrences(multiset, toRemove));
-    ASSERT.that(multiset).has().exactly("a", "a", "b").inOrder();
+    assertThat(multiset).has().exactly("a", "a", "b").inOrder();
   }
 
-  public void testRemoveOccurrences() {
+  public void testRemoveOccurrencesMultiset() {
     Multiset<String> multiset =
         TreeMultiset.create(Arrays.asList("a", "b", "a", "c"));
     Multiset<String> toRemove =
         HashMultiset.create(Arrays.asList("a", "b", "b"));
     assertTrue(Multisets.removeOccurrences(multiset, toRemove));
-    ASSERT.that(multiset).has().exactly("a", "c").inOrder();
+    assertThat(multiset).has().exactly("a", "c").inOrder();
+  }
+
+  public void testRemoveEmptyOccurrencesIterable() {
+    Multiset<String> multiset =
+        TreeMultiset.create(Arrays.asList("a", "b", "a"));
+    Iterable<String> toRemove = ImmutableList.of();
+    assertFalse(Multisets.removeOccurrences(multiset, toRemove));
+    assertThat(multiset).has().exactly("a", "a", "b").inOrder();
+  }
+
+  public void testRemoveOccurrencesMultisetIterable() {
+    Multiset<String> multiset =
+        TreeMultiset.create(Arrays.asList("a", "b", "a", "c"));
+    List<String> toRemove = Arrays.asList("a", "b", "b");
+    assertTrue(Multisets.removeOccurrences(multiset, toRemove));
+    assertThat(multiset).has().exactly("a", "c").inOrder();
   }
 
   @SuppressWarnings("deprecation")
@@ -242,11 +266,11 @@
     ImmutableMultiset<String> sortedMultiset =
         Multisets.copyHighestCountFirst(multiset);
 
-    ASSERT.that(sortedMultiset.entrySet()).has().exactly(
+    assertThat(sortedMultiset.entrySet()).has().exactly(
         Multisets.immutableEntry("a", 3), Multisets.immutableEntry("c", 2),
         Multisets.immutableEntry("b", 1)).inOrder();
 
-    ASSERT.that(sortedMultiset).has().exactly(
+    assertThat(sortedMultiset).has().exactly(
         "a",
         "a",
         "a",
@@ -254,7 +278,7 @@
         "c",
         "b").inOrder();
 
-    ASSERT.that(Multisets.copyHighestCountFirst(ImmutableMultiset.of())).isEmpty();
+    assertThat(Multisets.copyHighestCountFirst(ImmutableMultiset.of())).isEmpty();
   }
 
   @GwtIncompatible("NullPointerTester")
diff --git a/guava-tests/test/com/google/common/collect/NewCustomTableTest.java b/guava-tests/test/com/google/common/collect/NewCustomTableTest.java
index c172826..9355aad 100644
--- a/guava-tests/test/com/google/common/collect/NewCustomTableTest.java
+++ b/guava-tests/test/com/google/common/collect/NewCustomTableTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Supplier;
@@ -51,11 +51,11 @@
 
   public void testRowKeySetOrdering() {
     table = create("foo", 3, 'a', "bar", 1, 'b', "foo", 2, 'c');
-    ASSERT.that(table.rowKeySet()).has().exactly("foo", "bar").inOrder();
+    assertThat(table.rowKeySet()).has().exactly("foo", "bar").inOrder();
   }
 
   public void testRowOrdering() {
     table = create("foo", 3, 'a', "bar", 1, 'b', "foo", 2, 'c');
-    ASSERT.that(table.row("foo").keySet()).has().exactly(2, 3).inOrder();
+    assertThat(table.row("foo").keySet()).has().exactly(2, 3).inOrder();
   }
 }
diff --git a/guava-tests/test/com/google/common/collect/ObjectArraysTest.java b/guava-tests/test/com/google/common/collect/ObjectArraysTest.java
index 4c2cd85..c379857 100644
--- a/guava-tests/test/com/google/common/collect/ObjectArraysTest.java
+++ b/guava-tests/test/com/google/common/collect/ObjectArraysTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -98,7 +98,7 @@
     String[] result = ObjectArrays.concat(
         new String[0], new String[] { "a", "b" }, String.class);
     assertEquals(String[].class, result.getClass());
-    ASSERT.that(result).has().exactly("a", "b").inOrder();
+    assertThat(result).asList().has().exactly("a", "b").inOrder();
   }
 
   @GwtIncompatible("ObjectArrays.concat(Object[], Object[], Class)")
@@ -106,7 +106,7 @@
     String[] result = ObjectArrays.concat(
         new String[] { "a", "b" }, new String[0], String.class);
     assertEquals(String[].class, result.getClass());
-    ASSERT.that(result).has().exactly("a", "b").inOrder();
+    assertThat(result).asList().has().exactly("a", "b").inOrder();
   }
 
   @GwtIncompatible("ObjectArrays.concat(Object[], Object[], Class)")
@@ -114,7 +114,7 @@
     String[] result = ObjectArrays.concat(
         new String[] { "a", "b" }, new String[] { "c", "d" }, String.class);
     assertEquals(String[].class, result.getClass());
-    ASSERT.that(result).has().exactly("a", "b", "c", "d").inOrder();
+    assertThat(result).asList().has().exactly("a", "b", "c", "d").inOrder();
   }
 
   @GwtIncompatible("ObjectArrays.concat(Object[], Object[], Class)")
@@ -170,32 +170,32 @@
 
   public void testPrependZeroElements() {
     String[] result = ObjectArrays.concat("foo", new String[] {});
-    ASSERT.that(result).has().item("foo");
+    assertThat(result).asList().has().item("foo");
   }
 
   public void testPrependOneElement() {
     String[] result = ObjectArrays.concat("foo", new String[] { "bar" });
-    ASSERT.that(result).has().exactly("foo", "bar").inOrder();
+    assertThat(result).asList().has().exactly("foo", "bar").inOrder();
   }
 
   public void testPrependTwoElements() {
     String[] result = ObjectArrays.concat("foo", new String[] { "bar", "baz" });
-    ASSERT.that(result).has().exactly("foo", "bar", "baz").inOrder();
+    assertThat(result).asList().has().exactly("foo", "bar", "baz").inOrder();
   }
 
   public void testAppendZeroElements() {
     String[] result = ObjectArrays.concat(new String[] {}, "foo");
-    ASSERT.that(result).has().item("foo");
+    assertThat(result).asList().has().item("foo");
   }
 
   public void testAppendOneElement() {
     String[] result = ObjectArrays.concat(new String[] { "foo" }, "bar");
-    ASSERT.that(result).has().exactly("foo", "bar").inOrder();
+    assertThat(result).asList().has().exactly("foo", "bar").inOrder();
   }
 
   public void testAppendTwoElements() {
     String[] result = ObjectArrays.concat(new String[] { "foo", "bar" }, "baz");
-    ASSERT.that(result).has().exactly("foo", "bar", "baz").inOrder();
+    assertThat(result).asList().has().exactly("foo", "bar", "baz").inOrder();
   }
 
   public void testEmptyArrayToEmpty() {
diff --git a/guava-tests/test/com/google/common/collect/OrderingTest.java b/guava-tests/test/com/google/common/collect/OrderingTest.java
index 4af99d5..8054740 100644
--- a/guava-tests/test/com/google/common/collect/OrderingTest.java
+++ b/guava-tests/test/com/google/common/collect/OrderingTest.java
@@ -20,8 +20,8 @@
 import static com.google.common.collect.Lists.newArrayList;
 import static com.google.common.testing.SerializableTester.reserialize;
 import static com.google.common.testing.SerializableTester.reserializeAndAssert;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -157,7 +157,7 @@
         = Ordering.explicit(2, 8, 6, 1, 7, 5, 3, 4, 0, 9);
     List<Integer> list = Arrays.asList(0, 3, 5, 6, 7, 8, 9);
     Collections.sort(list, c);
-    ASSERT.that(list).has().exactly(8, 6, 7, 5, 3, 0, 9).inOrder();
+    assertThat(list).has().exactly(8, 6, 7, 5, 3, 0, 9).inOrder();
     reserializeAndAssert(c);
   }
 
diff --git a/guava-tests/test/com/google/common/collect/QueuesTest.java b/guava-tests/test/com/google/common/collect/QueuesTest.java
index bffcb39..d64caae 100644
--- a/guava-tests/test/com/google/common/collect/QueuesTest.java
+++ b/guava-tests/test/com/google/common/collect/QueuesTest.java
@@ -208,6 +208,17 @@
     assertEquals(100, buf.size());
   }
 
+  public void testNewLinkedBlockingDequeCapacity() {
+    try {
+      Queues.newLinkedBlockingDeque(0);
+      fail("Should have thrown IllegalArgumentException");
+    } catch (IllegalArgumentException expected) {
+      // any capacity less than 1 should throw IllegalArgumentException
+    }
+    assertEquals(1, Queues.newLinkedBlockingDeque(1).remainingCapacity());
+    assertEquals(11, Queues.newLinkedBlockingDeque(11).remainingCapacity());
+  }
+
   public void testNewLinkedBlockingQueueCapacity() {
     try {
       Queues.newLinkedBlockingQueue(0);
diff --git a/guava-tests/test/com/google/common/collect/RegularImmutableTableTest.java b/guava-tests/test/com/google/common/collect/RegularImmutableTableTest.java
index b76942b..d1f97f5 100644
--- a/guava-tests/test/com/google/common/collect/RegularImmutableTableTest.java
+++ b/guava-tests/test/com/google/common/collect/RegularImmutableTableTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.Table.Cell;
@@ -62,7 +62,7 @@
   public void testValues() {
     for (ImmutableTable<Character, Integer, String> testInstance :
         getTestInstances()) {
-      ASSERT.that(testInstance.values())
+      assertThat(testInstance.values())
           .has().exactly("foo", "bar", "baz")
           .inOrder();
     }
diff --git a/guava-tests/test/com/google/common/collect/SetsTest.java b/guava-tests/test/com/google/common/collect/SetsTest.java
index e726f63..68a76c6 100644
--- a/guava-tests/test/com/google/common/collect/SetsTest.java
+++ b/guava-tests/test/com/google/common/collect/SetsTest.java
@@ -21,19 +21,21 @@
 import static com.google.common.collect.Sets.newHashSet;
 import static com.google.common.collect.Sets.newLinkedHashSet;
 import static com.google.common.collect.Sets.powerSet;
+import static com.google.common.collect.Sets.unmodifiableNavigableSet;
 import static com.google.common.collect.testing.IteratorFeature.UNMODIFIABLE;
-import static com.google.common.collect.testing.testers.CollectionIteratorTester.getIteratorKnownOrderRemoveSupportedMethod;
+import static com.google.common.truth.Truth.assertThat;
 import static java.io.ObjectStreamConstants.TC_REFERENCE;
 import static java.io.ObjectStreamConstants.baseWireHandle;
 import static java.util.Collections.emptySet;
 import static java.util.Collections.singleton;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
 import com.google.common.collect.testing.AnEnum;
 import com.google.common.collect.testing.IteratorTester;
 import com.google.common.collect.testing.MinimalIterable;
+import com.google.common.collect.testing.NavigableSetTestSuiteBuilder;
+import com.google.common.collect.testing.SafeTreeSet;
 import com.google.common.collect.testing.SetTestSuiteBuilder;
 import com.google.common.collect.testing.TestEnumSetGenerator;
 import com.google.common.collect.testing.TestStringSetGenerator;
@@ -68,6 +70,7 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.NavigableSet;
 import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.SortedSet;
@@ -180,6 +183,22 @@
             CollectionFeature.ALLOWS_NULL_QUERIES)
         .createTestSuite());
 
+    suite.addTest(NavigableSetTestSuiteBuilder.using(new TestStringSetGenerator() {
+          @Override protected Set<String> create(String[] elements) {
+            SafeTreeSet<String> set = new SafeTreeSet<String>(Arrays.asList(elements));
+            return Sets.unmodifiableNavigableSet(set);
+          }
+
+          @Override
+          public List<String> order(List<String> insertionOrder) {
+            return Ordering.natural().sortedCopy(insertionOrder);
+          }
+        })
+        .named("Sets.unmodifiableNavigableSet[TreeSet]")
+        .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER,
+            CollectionFeature.SERIALIZABLE)
+        .createTestSuite());
+
     suite.addTest(testsForFilter());
     suite.addTest(testsForFilterNoNulls());
     suite.addTest(testsForFilterFiltered());
@@ -205,7 +224,6 @@
             CollectionFeature.ALLOWS_NULL_VALUES,
             CollectionFeature.KNOWN_ORDER,
             CollectionSize.ANY)
-        .suppressing(getIteratorKnownOrderRemoveSupportedMethod())
         .createTestSuite();
   }
 
@@ -222,11 +240,35 @@
           }
         })
         .named("Sets.filter, no nulls")
-        .withFeatures(SetFeature.GENERAL_PURPOSE, CollectionFeature.KNOWN_ORDER,
-            CollectionSize.ANY, CollectionFeature.ALLOWS_NULL_QUERIES)
-        .suppressing(getIteratorKnownOrderRemoveSupportedMethod())
+        .withFeatures(
+            CollectionFeature.SUPPORTS_ADD,
+            CollectionFeature.SUPPORTS_REMOVE,
+            CollectionFeature.KNOWN_ORDER,
+            CollectionSize.ANY,
+            CollectionFeature.ALLOWS_NULL_QUERIES)
         .createTestSuite());
+    suite.addTest(NavigableSetTestSuiteBuilder.using(new TestStringSetGenerator() {
+          @Override public NavigableSet<String> create(String[] elements) {
+            NavigableSet<String> unfiltered = Sets.newTreeSet();
+            unfiltered.add("yyy");
+            unfiltered.addAll(ImmutableList.copyOf(elements));
+            unfiltered.add("zzz");
+            return Sets.filter(unfiltered, Collections2Test.LENGTH_1);
+          }
 
+          @Override
+          public List<String> order(List<String> insertionOrder) {
+            return Ordering.natural().sortedCopy(insertionOrder);
+          }
+        })
+        .named("Sets.filter[NavigableSet]")
+        .withFeatures(
+            CollectionFeature.SUPPORTS_ADD,
+            CollectionFeature.SUPPORTS_REMOVE,
+            CollectionFeature.KNOWN_ORDER,
+            CollectionSize.ANY,
+            CollectionFeature.ALLOWS_NULL_QUERIES)
+        .createTestSuite());
     return suite;
   }
 
@@ -251,7 +293,6 @@
             CollectionFeature.KNOWN_ORDER,
             CollectionSize.ANY,
             CollectionFeature.ALLOWS_NULL_QUERIES)
-        .suppressing(getIteratorKnownOrderRemoveSupportedMethod())
         .createTestSuite();
   }
 
@@ -260,7 +301,7 @@
   public void testImmutableEnumSet() {
     Set<SomeEnum> units = Sets.immutableEnumSet(SomeEnum.D, SomeEnum.B);
 
-    ASSERT.that(units).has().exactly(SomeEnum.B, SomeEnum.D).inOrder();
+    assertThat(units).has().exactly(SomeEnum.B, SomeEnum.D).inOrder();
     try {
       units.remove(SomeEnum.B);
       fail("ImmutableEnumSet should throw an exception on remove()");
@@ -275,7 +316,7 @@
   public void testImmutableEnumSet_serialized() {
     Set<SomeEnum> units = Sets.immutableEnumSet(SomeEnum.D, SomeEnum.B);
 
-    ASSERT.that(units).has().exactly(SomeEnum.B, SomeEnum.D).inOrder();
+    assertThat(units).has().exactly(SomeEnum.B, SomeEnum.D).inOrder();
 
     Set<SomeEnum> copy = SerializableTester.reserializeAndAssert(units);
     assertTrue(copy instanceof ImmutableEnumSet);
@@ -284,15 +325,15 @@
   public void testImmutableEnumSet_fromIterable() {
     ImmutableSet<SomeEnum> none
         = Sets.immutableEnumSet(MinimalIterable.<SomeEnum>of());
-    ASSERT.that(none).isEmpty();
+    assertThat(none).isEmpty();
 
     ImmutableSet<SomeEnum> one
         = Sets.immutableEnumSet(MinimalIterable.of(SomeEnum.B));
-    ASSERT.that(one).has().item(SomeEnum.B);
+    assertThat(one).has().item(SomeEnum.B);
 
     ImmutableSet<SomeEnum> two
         = Sets.immutableEnumSet(MinimalIterable.of(SomeEnum.D, SomeEnum.B));
-    ASSERT.that(two).has().exactly(SomeEnum.B, SomeEnum.D).inOrder();
+    assertThat(two).has().exactly(SomeEnum.B, SomeEnum.D).inOrder();
   }
 
   @GwtIncompatible("java serialization not supported in GWT.")
@@ -447,7 +488,7 @@
     assertTrue(set.isEmpty());
     set.add(new Derived("foo"));
     set.add(new Derived("bar"));
-    ASSERT.that(set).has().exactly(new Derived("bar"), new Derived("foo")).inOrder();
+    assertThat(set).has().exactly(new Derived("bar"), new Derived("foo")).inOrder();
   }
 
   public void testNewTreeSetEmptyNonGeneric() {
@@ -455,7 +496,7 @@
     assertTrue(set.isEmpty());
     set.add(new LegacyComparable("foo"));
     set.add(new LegacyComparable("bar"));
-    ASSERT.that(set).has()
+    assertThat(set).has()
         .exactly(new LegacyComparable("bar"), new LegacyComparable("foo")).inOrder();
   }
 
@@ -473,7 +514,7 @@
     Iterable<Derived> iterable =
         Arrays.asList(new Derived("foo"), new Derived("bar"));
     TreeSet<Derived> set = Sets.newTreeSet(iterable);
-    ASSERT.that(set).has().exactly(
+    assertThat(set).has().exactly(
         new Derived("bar"), new Derived("foo")).inOrder();
   }
 
@@ -481,7 +522,7 @@
     Iterable<LegacyComparable> iterable =
         Arrays.asList(new LegacyComparable("foo"), new LegacyComparable("bar"));
     TreeSet<LegacyComparable> set = Sets.newTreeSet(iterable);
-    ASSERT.that(set).has().exactly(
+    assertThat(set).has().exactly(
         new LegacyComparable("bar"), new LegacyComparable("foo")).inOrder();
   }
 
@@ -583,7 +624,7 @@
         Sets.newSetFromMap(new LinkedHashMap<Integer, Boolean>());
     set.addAll(SOME_COLLECTION);
     Set<Integer> copy = SerializableTester.reserializeAndAssert(set);
-    ASSERT.that(copy).has().exactly(0, 1).inOrder();
+    assertThat(copy).has().exactly(0, 1).inOrder();
   }
 
   public void testNewSetFromMapIllegal() {
@@ -603,7 +644,7 @@
    */
   @SuppressWarnings("unchecked") // varargs!
   public void testCartesianProduct_zeroary() {
-    ASSERT.that(Sets.cartesianProduct()).has().exactly(list());
+    assertThat(Sets.cartesianProduct()).has().exactly(list());
   }
 
   /**
@@ -612,7 +653,7 @@
    */
   @SuppressWarnings("unchecked") // varargs!
   public void testCartesianProduct_unary() {
-    ASSERT.that(Sets.cartesianProduct(set(1, 2))).has().exactly(list(1), list(2));
+    assertThat(Sets.cartesianProduct(set(1, 2))).has().exactly(list(1), list(2));
   }
 
   @SuppressWarnings("unchecked") // varargs!
@@ -641,24 +682,24 @@
 
   @SuppressWarnings("unchecked") // varargs!
   public void testCartesianProduct_binary1x1() {
-    ASSERT.that(Sets.cartesianProduct(set(1), set(2))).has().item(list(1, 2));
+    assertThat(Sets.cartesianProduct(set(1), set(2))).has().item(list(1, 2));
   }
 
   @SuppressWarnings("unchecked") // varargs!
   public void testCartesianProduct_binary1x2() {
-    ASSERT.that(Sets.cartesianProduct(set(1), set(2, 3)))
+    assertThat(Sets.cartesianProduct(set(1), set(2, 3)))
         .has().exactly(list(1, 2), list(1, 3)).inOrder();
   }
 
   @SuppressWarnings("unchecked") // varargs!
   public void testCartesianProduct_binary2x2() {
-    ASSERT.that(Sets.cartesianProduct(set(1, 2), set(3, 4)))
+    assertThat(Sets.cartesianProduct(set(1, 2), set(3, 4)))
         .has().exactly(list(1, 3), list(1, 4), list(2, 3), list(2, 4)).inOrder();
   }
 
   @SuppressWarnings("unchecked") // varargs!
   public void testCartesianProduct_2x2x2() {
-    ASSERT.that(Sets.cartesianProduct(set(0, 1), set(0, 1), set(0, 1))).has().exactly(
+    assertThat(Sets.cartesianProduct(set(0, 1), set(0, 1), set(0, 1))).has().exactly(
         list(0, 0, 0), list(0, 0, 1), list(0, 1, 0), list(0, 1, 1),
         list(1, 0, 0), list(1, 0, 1), list(1, 1, 0), list(1, 1, 1)).inOrder();
   }
@@ -683,7 +724,7 @@
     List<Object> exp3 = list((Object) 2, "3");
     List<Object> exp4 = list((Object) 2, "4");
 
-    ASSERT.that(Sets.<Object>cartesianProduct(x, y))
+    assertThat(Sets.<Object>cartesianProduct(x, y))
         .has().exactly(exp1, exp2, exp3, exp4).inOrder();
   }
 
@@ -1028,6 +1069,48 @@
     private static final long serialVersionUID = 0;
   }
 
+  @GwtIncompatible("NavigableSet")
+  public void testUnmodifiableNavigableSet() {
+    TreeSet<Integer> mod = Sets.newTreeSet();
+    mod.add(1);
+    mod.add(2);
+    mod.add(3);
+
+    NavigableSet<Integer> unmod = unmodifiableNavigableSet(mod);
+
+    /* Unmodifiable is a view. */
+    mod.add(4);
+    assertTrue(unmod.contains(4));
+    assertTrue(unmod.descendingSet().contains(4));
+
+    ensureNotDirectlyModifiable(unmod);
+    ensureNotDirectlyModifiable(unmod.descendingSet());
+    ensureNotDirectlyModifiable(unmod.headSet(2));
+    ensureNotDirectlyModifiable(unmod.headSet(2, true));
+    ensureNotDirectlyModifiable(unmod.tailSet(2));
+    ensureNotDirectlyModifiable(unmod.tailSet(2, true));
+    ensureNotDirectlyModifiable(unmod.subSet(1, 3));
+    ensureNotDirectlyModifiable(unmod.subSet(1, true, 3, true));
+
+    /* UnsupportedOperationException on indirect modifications. */
+    NavigableSet<Integer> reverse = unmod.descendingSet();
+    try {
+      reverse.add(4);
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      reverse.addAll(Collections.singleton(4));
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      reverse.remove(4);
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+  }
+
   void ensureNotDirectlyModifiable(SortedSet<Integer> unmod) {
     try {
       unmod.add(4);
@@ -1052,4 +1135,47 @@
     } catch (UnsupportedOperationException expected) {
     }
   }
+
+  @GwtIncompatible("NavigableSet")
+  void ensureNotDirectlyModifiable(NavigableSet<Integer> unmod) {
+    try {
+      unmod.add(4);
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      unmod.remove(4);
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      unmod.addAll(Collections.singleton(4));
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      unmod.pollFirst();
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      unmod.pollLast();
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      Iterator<Integer> iterator = unmod.iterator();
+      iterator.next();
+      iterator.remove();
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      Iterator<Integer> iterator = unmod.descendingIterator();
+      iterator.next();
+      iterator.remove();
+      fail("UnsupportedOperationException expected");
+    } catch (UnsupportedOperationException expected) {
+    }
+  }
 }
diff --git a/guava-tests/test/com/google/common/collect/SingletonImmutableTableTest.java b/guava-tests/test/com/google/common/collect/SingletonImmutableTableTest.java
index 8fba129..f16498b 100644
--- a/guava-tests/test/com/google/common/collect/SingletonImmutableTableTest.java
+++ b/guava-tests/test/com/google/common/collect/SingletonImmutableTableTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -126,7 +126,7 @@
   }
 
   public void testValues() {
-    ASSERT.that(testTable.values()).has().item("blah");
+    assertThat(testTable.values()).has().item("blah");
   }
 
   @Override Iterable<ImmutableTable<Character, Integer, String>> getTestInstances() {
diff --git a/guava-tests/test/com/google/common/collect/SynchronizedDequeTest.java b/guava-tests/test/com/google/common/collect/SynchronizedDequeTest.java
new file mode 100644
index 0000000..4e99280
--- /dev/null
+++ b/guava-tests/test/com/google/common/collect/SynchronizedDequeTest.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2013 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import junit.framework.TestCase;
+
+import java.util.Collection;
+import java.util.Deque;
+import java.util.Iterator;
+
+/**
+ * Tests for {@link Synchronized#deque} and {@link Queues#synchronizedDeque}.
+ *
+ * @author Kurt Alfred Kluever
+ */
+public class SynchronizedDequeTest extends TestCase {
+
+  protected Deque<String> create() {
+    TestDeque<String> inner = new TestDeque<String>();
+    Deque<String> outer = Synchronized.deque(inner, inner.mutex);
+    outer.add("foo");  // necessary because we try to remove elements later on
+    return outer;
+  }
+
+  private static final class TestDeque<E> implements Deque<E> {
+    private final Deque<E> delegate = Lists.newLinkedList();
+    public final Object mutex = new Integer(1); // something Serializable
+
+    @Override
+    public boolean offer(E o) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.offer(o);
+    }
+
+    @Override
+    public E poll() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.poll();
+    }
+
+    @Override
+    public E remove() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.remove();
+    }
+
+    @Override
+    public E peek() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.peek();
+    }
+
+    @Override
+    public E element() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.element();
+    }
+
+    @Override
+    public Iterator<E> iterator() {
+      // We explicitly don't lock for iterator()
+      assertFalse(Thread.holdsLock(mutex));
+      return delegate.iterator();
+    }
+
+    @Override
+    public int size() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.size();
+    }
+
+    @Override
+    public boolean removeAll(Collection<?> collection) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.removeAll(collection);
+    }
+
+    @Override
+    public boolean isEmpty() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.isEmpty();
+    }
+
+    @Override
+    public boolean contains(Object object) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.contains(object);
+    }
+
+    @Override
+    public boolean add(E element) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.add(element);
+    }
+
+    @Override
+    public boolean remove(Object object) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.remove(object);
+    }
+
+    @Override
+    public boolean containsAll(Collection<?> collection) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.containsAll(collection);
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends E> collection) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.addAll(collection);
+    }
+
+    @Override
+    public boolean retainAll(Collection<?> collection) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.retainAll(collection);
+    }
+
+    @Override
+    public void clear() {
+      assertTrue(Thread.holdsLock(mutex));
+      delegate.clear();
+    }
+
+    @Override
+    public Object[] toArray() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.toArray();
+    }
+
+    @Override
+    public <T> T[] toArray(T[] array) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.toArray(array);
+    }
+
+    @Override
+    public void addFirst(E e) {
+      assertTrue(Thread.holdsLock(mutex));
+      delegate.addFirst(e);
+    }
+
+    @Override
+    public void addLast(E e) {
+      assertTrue(Thread.holdsLock(mutex));
+      delegate.addLast(e);
+    }
+
+    @Override
+    public boolean offerFirst(E e) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.offerFirst(e);
+    }
+
+    @Override
+    public boolean offerLast(E e) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.offerLast(e);
+    }
+
+    @Override
+    public E removeFirst() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.removeFirst();
+    }
+
+    @Override
+    public E removeLast() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.removeLast();
+    }
+
+    @Override
+    public E pollFirst() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.pollFirst();
+    }
+
+    @Override
+    public E pollLast() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.pollLast();
+    }
+
+    @Override
+    public E getFirst() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.getFirst();
+    }
+
+    @Override
+    public E getLast() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.getLast();
+    }
+
+    @Override
+    public E peekFirst() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.peekFirst();
+    }
+
+    @Override
+    public E peekLast() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.peekLast();
+    }
+
+    @Override
+    public boolean removeFirstOccurrence(Object o) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.removeFirstOccurrence(o);
+    }
+
+    @Override
+    public boolean removeLastOccurrence(Object o) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.removeLastOccurrence(o);
+    }
+
+    @Override
+    public void push(E e) {
+      assertTrue(Thread.holdsLock(mutex));
+      delegate.push(e);
+    }
+
+    @Override
+    public E pop() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.pop();
+    }
+
+    @Override
+    public Iterator<E> descendingIterator() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate.descendingIterator();
+    }
+
+    private static final long serialVersionUID = 0;
+  }
+
+  public void testHoldsLockOnAllOperations() {
+    create().element();
+    create().offer("foo");
+    create().peek();
+    create().poll();
+    create().remove();
+    create().add("foo");
+    create().addAll(ImmutableList.of("foo"));
+    create().clear();
+    create().contains("foo");
+    create().containsAll(ImmutableList.of("foo"));
+    create().equals(ImmutableList.of("foo"));
+    create().hashCode();
+    create().isEmpty();
+    create().iterator();
+    create().remove("foo");
+    create().removeAll(ImmutableList.of("foo"));
+    create().retainAll(ImmutableList.of("foo"));
+    create().size();
+    create().toArray();
+    create().toArray(new String[] { "foo" });
+    create().addFirst("e");
+    create().addLast("e");
+    create().offerFirst("e");
+    create().offerLast("e");
+    create().removeFirst();
+    create().removeLast();
+    create().pollFirst();
+    create().pollLast();
+    create().getFirst();
+    create().getLast();
+    create().peekFirst();
+    create().peekLast();
+    create().removeFirstOccurrence("e");
+    create().removeLastOccurrence("e");
+    create().push("e");
+    create().pop();
+    create().descendingIterator();
+  }
+}
diff --git a/guava-tests/test/com/google/common/collect/SynchronizedMultimapTest.java b/guava-tests/test/com/google/common/collect/SynchronizedMultimapTest.java
index 2b85d7d..e7a6aac 100644
--- a/guava-tests/test/com/google/common/collect/SynchronizedMultimapTest.java
+++ b/guava-tests/test/com/google/common/collect/SynchronizedMultimapTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.collect.testing.features.CollectionFeature;
 import com.google.common.collect.testing.features.CollectionSize;
@@ -204,11 +204,11 @@
             ArrayListMultimap.<String, Integer>create());
     multimap.putAll("foo", Arrays.asList(3, -1, 2, 4, 1));
     multimap.putAll("bar", Arrays.asList(1, 2, 3, 1));
-    ASSERT.that(multimap.removeAll("foo")).has().exactly(3, -1, 2, 4, 1).inOrder();
+    assertThat(multimap.removeAll("foo")).has().exactly(3, -1, 2, 4, 1).inOrder();
     assertFalse(multimap.containsKey("foo"));
-    ASSERT.that(multimap.replaceValues("bar", Arrays.asList(6, 5)))
+    assertThat(multimap.replaceValues("bar", Arrays.asList(6, 5)))
         .has().exactly(1, 2, 3, 1).inOrder();
-    ASSERT.that(multimap.get("bar")).has().exactly(6, 5).inOrder();
+    assertThat(multimap.get("bar")).has().exactly(6, 5).inOrder();
   }
 
   public void testSynchronizedSortedSetMultimap() {
@@ -217,11 +217,11 @@
             TreeMultimap.<String, Integer>create());
     multimap.putAll("foo", Arrays.asList(3, -1, 2, 4, 1));
     multimap.putAll("bar", Arrays.asList(1, 2, 3, 1));
-    ASSERT.that(multimap.removeAll("foo")).has().exactly(-1, 1, 2, 3, 4).inOrder();
+    assertThat(multimap.removeAll("foo")).has().exactly(-1, 1, 2, 3, 4).inOrder();
     assertFalse(multimap.containsKey("foo"));
-    ASSERT.that(multimap.replaceValues("bar", Arrays.asList(6, 5)))
+    assertThat(multimap.replaceValues("bar", Arrays.asList(6, 5)))
         .has().exactly(1, 2, 3).inOrder();
-    ASSERT.that(multimap.get("bar")).has().exactly(5, 6).inOrder();
+    assertThat(multimap.get("bar")).has().exactly(5, 6).inOrder();
   }
 
   public void testSynchronizedArrayListMultimapRandomAccess() {
diff --git a/guava-tests/test/com/google/common/collect/SynchronizedNavigableMapTest.java b/guava-tests/test/com/google/common/collect/SynchronizedNavigableMapTest.java
new file mode 100644
index 0000000..5b78e9b
--- /dev/null
+++ b/guava-tests/test/com/google/common/collect/SynchronizedNavigableMapTest.java
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2010 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import com.google.common.collect.Synchronized.SynchronizedNavigableMap;
+import com.google.common.collect.Synchronized.SynchronizedNavigableSet;
+import com.google.common.collect.Synchronized.SynchronizedSortedMap;
+import com.google.common.collect.testing.NavigableMapTestSuiteBuilder;
+import com.google.common.collect.testing.SafeTreeMap;
+import com.google.common.collect.testing.TestStringSortedMapGenerator;
+import com.google.common.collect.testing.features.CollectionFeature;
+import com.google.common.collect.testing.features.CollectionSize;
+import com.google.common.collect.testing.features.MapFeature;
+import com.google.common.testing.SerializableTester;
+
+import junit.framework.TestSuite;
+
+import java.io.Serializable;
+import java.util.Comparator;
+import java.util.Map.Entry;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
+import java.util.SortedMap;
+
+/**
+ * Tests for {@link Maps#synchronizedNavigableMap(NavigableMap)}.
+ *
+ * @author Louis Wasserman
+ */
+public class SynchronizedNavigableMapTest extends SynchronizedMapTest {
+  @Override protected <K, V> NavigableMap<K, V> create() {
+    @SuppressWarnings("unchecked")
+    NavigableMap<K, V> innermost = new SafeTreeMap<K, V>(
+        (Comparator<? super K>) Ordering.natural().nullsFirst());
+    TestMap<K, V> inner = new TestMap<K, V>(innermost, mutex);
+    NavigableMap<K, V> outer = Synchronized.navigableMap(inner, mutex);
+    return outer;
+  }
+
+  static class TestEntry<K, V> extends ForwardingMapEntry<K, V>
+      implements Serializable {
+    private final Entry<K, V> delegate;
+    private final Object mutex;
+
+    TestEntry(Entry<K, V> delegate, Object mutex) {
+      this.delegate = delegate;
+      this.mutex = mutex;
+    }
+
+    @Override protected Entry<K, V> delegate() {
+      return delegate;
+    }
+
+    @Override public boolean equals(Object object) {
+      assertTrue(Thread.holdsLock(mutex));
+      return super.equals(object);
+    }
+
+    @Override public K getKey() {
+      assertTrue(Thread.holdsLock(mutex));
+      return super.getKey();
+    }
+
+    @Override public V getValue() {
+      assertTrue(Thread.holdsLock(mutex));
+      return super.getValue();
+    }
+
+    @Override public int hashCode() {
+      assertTrue(Thread.holdsLock(mutex));
+      return super.hashCode();
+    }
+
+    @Override public V setValue(V value) {
+      assertTrue(Thread.holdsLock(mutex));
+      return super.setValue(value);
+    }
+
+    private static final long serialVersionUID = 0;
+  }
+
+  static class TestMap<K, V> extends SynchronizedMapTest.TestMap<K, V>
+      implements NavigableMap<K, V> {
+
+    public TestMap(NavigableMap<K, V> delegate, Object mutex) {
+      super(delegate, mutex);
+    }
+
+    @Override protected NavigableMap<K, V> delegate() {
+      return (NavigableMap<K, V>) super.delegate();
+    }
+
+    @Override public Entry<K, V> ceilingEntry(K key) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().ceilingEntry(key);
+    }
+
+    @Override public K ceilingKey(K key) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().ceilingKey(key);
+    }
+
+    @Override public NavigableSet<K> descendingKeySet() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().descendingKeySet();
+    }
+
+    @Override public NavigableMap<K, V> descendingMap() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().descendingMap();
+    }
+
+    @Override public Entry<K, V> firstEntry() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().firstEntry();
+    }
+
+    @Override public Entry<K, V> floorEntry(K key) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().floorEntry(key);
+    }
+
+    @Override public K floorKey(K key) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().floorKey(key);
+    }
+
+    @Override public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().headMap(toKey, inclusive);
+    }
+
+    @Override public SortedMap<K, V> headMap(K toKey) {
+      return headMap(toKey, false);
+    }
+
+    @Override public Entry<K, V> higherEntry(K key) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().higherEntry(key);
+    }
+
+    @Override public K higherKey(K key) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().higherKey(key);
+    }
+
+    @Override public Entry<K, V> lastEntry() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().lastEntry();
+    }
+
+    @Override public Entry<K, V> lowerEntry(K key) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().lowerEntry(key);
+    }
+
+    @Override public K lowerKey(K key) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().lowerKey(key);
+    }
+
+    @Override public NavigableSet<K> navigableKeySet() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().navigableKeySet();
+    }
+
+    @Override public Entry<K, V> pollFirstEntry() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().pollFirstEntry();
+    }
+
+    @Override public Entry<K, V> pollLastEntry() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().pollLastEntry();
+    }
+
+    @Override public NavigableMap<K, V> subMap(
+        K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().subMap(fromKey, fromInclusive, toKey, toInclusive);
+    }
+
+    @Override public SortedMap<K, V> subMap(K fromKey, K toKey) {
+      return delegate().subMap(fromKey, true, toKey, false);
+    }
+
+    @Override public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().tailMap(fromKey, inclusive);
+    }
+
+    @Override public SortedMap<K, V> tailMap(K fromKey) {
+      return tailMap(fromKey, true);
+    }
+
+    @Override public Comparator<? super K> comparator() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().comparator();
+    }
+
+    @Override public K firstKey() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().firstKey();
+    }
+
+    @Override public K lastKey() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().lastKey();
+    }
+
+    private static final long serialVersionUID = 0;
+  }
+
+  public static TestSuite suite() {
+    TestSuite suite = new TestSuite();
+    suite.addTestSuite(SynchronizedNavigableMapTest.class);
+    suite.addTest(
+        NavigableMapTestSuiteBuilder.using(new TestStringSortedMapGenerator() {
+          private final Object mutex = new Integer(1);
+
+          @Override protected SortedMap<String, String> create(
+              Entry<String, String>[] entries) {
+            NavigableMap<String, String> innermost =
+                new SafeTreeMap<String, String>();
+            for (Entry<String, String> entry : entries) {
+              innermost.put(entry.getKey(), entry.getValue());
+            }
+            TestMap<String, String> inner =
+                new TestMap<String, String>(innermost, mutex);
+            NavigableMap<String, String> outer =
+                Synchronized.navigableMap(inner, mutex);
+            return outer;
+          }
+        }).named("Maps.synchronizedNavigableMap[SafeTreeMap]")
+            .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER,
+                MapFeature.GENERAL_PURPOSE, MapFeature.ALLOWS_NULL_VALUES, 
+                CollectionFeature.SUPPORTS_ITERATOR_REMOVE)
+            .createTestSuite());
+
+    return suite;
+  }
+
+  public void testComparator() {
+    create().comparator();
+  }
+
+  public void testCeilingEntry() {
+    create().ceilingEntry("a");
+  }
+
+  public void testCeilingKey() {
+    create().ceilingKey("a");
+  }
+
+  public void testDescendingKeySet() {
+    NavigableMap<String, Integer> map = create();
+    NavigableSet<String> descendingKeySet = map.descendingKeySet();
+    assertTrue(descendingKeySet instanceof SynchronizedNavigableSet);
+    assertSame(
+        mutex, ((SynchronizedNavigableSet<String>) descendingKeySet).mutex);
+  }
+
+  public void testDescendingMap() {
+    NavigableMap<String, Integer> map = create();
+    NavigableMap<String, Integer> descendingMap = map.descendingMap();
+    assertTrue(descendingMap instanceof SynchronizedNavigableMap);
+    assertSame(mutex,
+        ((SynchronizedNavigableMap<String, Integer>) descendingMap).mutex);
+  }
+
+  public void testFirstEntry() {
+    create().firstEntry();
+  }
+
+  public void testFirstKey() {
+    NavigableMap<String, Integer> map = create();
+    map.put("a", 1);
+    map.firstKey();
+  }
+
+  public void testFloorEntry() {
+    create().floorEntry("a");
+  }
+
+  public void testFloorKey() {
+    create().floorKey("a");
+  }
+
+  public void testHeadMap_K() {
+    NavigableMap<String, Integer> map = create();
+    SortedMap<String, Integer> headMap = map.headMap("a");
+    assertTrue(headMap instanceof SynchronizedSortedMap);
+    assertSame(mutex, ((SynchronizedSortedMap<String, Integer>) headMap).mutex);
+  }
+
+  public void testHeadMap_K_B() {
+    NavigableMap<String, Integer> map = create();
+    NavigableMap<String, Integer> headMap = map.headMap("a", true);
+    assertTrue(headMap instanceof SynchronizedNavigableMap);
+    assertSame(
+        mutex, ((SynchronizedNavigableMap<String, Integer>) headMap).mutex);
+  }
+
+  public void testHigherEntry() {
+    create().higherEntry("a");
+  }
+
+  public void testHigherKey() {
+    create().higherKey("a");
+  }
+
+  public void testLastEntry() {
+    create().lastEntry();
+  }
+
+  public void testLastKey() {
+    NavigableMap<String, Integer> map = create();
+    map.put("a", 1);
+    map.lastKey();
+  }
+
+  public void testLowerEntry() {
+    create().lowerEntry("a");
+  }
+
+  public void testLowerKey() {
+    create().lowerKey("a");
+  }
+
+  public void testNavigableKeySet() {
+    NavigableMap<String, Integer> map = create();
+    NavigableSet<String> navigableKeySet = map.navigableKeySet();
+    assertTrue(navigableKeySet instanceof SynchronizedNavigableSet);
+    assertSame(
+        mutex, ((SynchronizedNavigableSet<String>) navigableKeySet).mutex);
+  }
+
+  public void testPollFirstEntry() {
+    create().pollFirstEntry();
+  }
+
+  public void testPollLastEntry() {
+    create().pollLastEntry();
+  }
+
+  public void testSubMap_K_K() {
+    NavigableMap<String, Integer> map = create();
+    SortedMap<String, Integer> subMap = map.subMap("a", "b");
+    assertTrue(subMap instanceof SynchronizedSortedMap);
+    assertSame(mutex, ((SynchronizedSortedMap<String, Integer>) subMap).mutex);
+  }
+
+  public void testSubMap_K_B_K_B() {
+    NavigableMap<String, Integer> map = create();
+    NavigableMap<String, Integer> subMap = map.subMap("a", true, "b", false);
+    assertTrue(subMap instanceof SynchronizedNavigableMap);
+    assertSame(
+        mutex, ((SynchronizedNavigableMap<String, Integer>) subMap).mutex);
+  }
+
+  public void testTailMap_K() {
+    NavigableMap<String, Integer> map = create();
+    SortedMap<String, Integer> subMap = map.tailMap("a");
+    assertTrue(subMap instanceof SynchronizedSortedMap);
+    assertSame(mutex, ((SynchronizedSortedMap<String, Integer>) subMap).mutex);
+  }
+
+  public void testTailMap_K_B() {
+    NavigableMap<String, Integer> map = create();
+    NavigableMap<String, Integer> subMap = map.tailMap("a", true);
+    assertTrue(subMap instanceof SynchronizedNavigableMap);
+    assertSame(
+        mutex, ((SynchronizedNavigableMap<String, Integer>) subMap).mutex);
+  }
+
+  @Override public void testSerialization() {
+    SerializableTester.reserializeAndAssert(create());
+  }
+}
diff --git a/guava-tests/test/com/google/common/collect/SynchronizedNavigableSetTest.java b/guava-tests/test/com/google/common/collect/SynchronizedNavigableSetTest.java
new file mode 100644
index 0000000..5bf965a
--- /dev/null
+++ b/guava-tests/test/com/google/common/collect/SynchronizedNavigableSetTest.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2010 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import com.google.common.collect.Synchronized.SynchronizedNavigableSet;
+import com.google.common.collect.Synchronized.SynchronizedSortedSet;
+import com.google.common.collect.testing.NavigableSetTestSuiteBuilder;
+import com.google.common.collect.testing.SafeTreeSet;
+import com.google.common.collect.testing.TestStringSortedSetGenerator;
+import com.google.common.collect.testing.features.CollectionFeature;
+import com.google.common.collect.testing.features.CollectionSize;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NavigableSet;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ * Tests for {@link Sets#synchronizedNavigableSet(NavigableSet)}.
+ *
+ * @author Louis Wasserman
+ */
+public class SynchronizedNavigableSetTest extends TestCase {
+  private static final Object MUTEX = new Integer(1); // something Serializable
+  
+  @SuppressWarnings("unchecked")
+  protected <E> NavigableSet<E> create() {
+    TestSet<E> inner = new TestSet<E>(
+        new TreeSet<E>((Comparator<E>) Ordering.natural().nullsFirst()), MUTEX);
+    NavigableSet<E> outer =
+        Synchronized.navigableSet(inner, MUTEX);
+    return outer;
+  }
+
+  static class TestSet<E> extends SynchronizedSetTest.TestSet<E>
+      implements NavigableSet<E> {
+
+    TestSet(NavigableSet<E> delegate, Object mutex) {
+      super(delegate, mutex);
+    }
+
+    @Override protected NavigableSet<E> delegate() {
+      return (NavigableSet<E>) super.delegate();
+    }
+
+    @Override public E ceiling(E e) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().ceiling(e);
+    }
+
+    @Override public Iterator<E> descendingIterator() {
+      return delegate().descendingIterator();
+    }
+
+    @Override public NavigableSet<E> descendingSet() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().descendingSet();
+    }
+
+    @Override public E floor(E e) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().floor(e);
+    }
+
+    @Override public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().headSet(toElement, inclusive);
+    }
+
+    @Override public SortedSet<E> headSet(E toElement) {
+      return headSet(toElement, false);
+    }
+
+    @Override public E higher(E e) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().higher(e);
+    }
+
+    @Override public E lower(E e) {
+      return delegate().lower(e);
+    }
+
+    @Override public E pollFirst() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().pollFirst();
+    }
+
+    @Override public E pollLast() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().pollLast();
+    }
+
+    @Override public NavigableSet<E> subSet(E fromElement,
+        boolean fromInclusive, E toElement, boolean toInclusive) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().subSet(
+          fromElement, fromInclusive, toElement, toInclusive);
+    }
+
+    @Override public SortedSet<E> subSet(E fromElement, E toElement) {
+      return subSet(fromElement, true, toElement, false);
+    }
+
+    @Override public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().tailSet(fromElement, inclusive);
+    }
+
+    @Override public SortedSet<E> tailSet(E fromElement) {
+      return tailSet(fromElement, true);
+    }
+
+    @Override public Comparator<? super E> comparator() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().comparator();
+    }
+
+    @Override public E first() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().first();
+    }
+
+    @Override public E last() {
+      assertTrue(Thread.holdsLock(mutex));
+      return delegate().last();
+    }
+
+    private static final long serialVersionUID = 0;
+  }
+
+  public static TestSuite suite() {
+    TestSuite suite = new TestSuite();
+    suite.addTestSuite(SynchronizedNavigableSetTest.class);
+    suite.addTest(
+        NavigableSetTestSuiteBuilder.using(new TestStringSortedSetGenerator() {
+
+          @Override protected NavigableSet<String> create(String[] elements) {
+            NavigableSet<String> innermost = new SafeTreeSet<String>();
+            Collections.addAll(innermost, elements);
+            TestSet<String> inner = new TestSet<String>(innermost, MUTEX);
+            NavigableSet<String> outer =
+                Synchronized.navigableSet(inner, MUTEX);
+            return outer;
+          }
+
+          @Override public List<String> order(List<String> insertionOrder) {
+            return Ordering.natural().sortedCopy(insertionOrder);
+          }
+        }).named("Sets.synchronizedNavigableSet[SafeTreeSet]")
+            .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER,
+                CollectionFeature.GENERAL_PURPOSE, CollectionFeature.SERIALIZABLE)
+            .createTestSuite());
+
+    return suite;
+  }
+
+  public void testDescendingSet() {
+    NavigableSet<String> map = create();
+    NavigableSet<String> descendingSet = map.descendingSet();
+    assertTrue(descendingSet instanceof SynchronizedNavigableSet);
+    assertSame(MUTEX, ((SynchronizedNavigableSet<String>) descendingSet).mutex);
+  }
+
+  public void testHeadSet_E() {
+    NavigableSet<String> map = create();
+    SortedSet<String> headSet = map.headSet("a");
+    assertTrue(headSet instanceof SynchronizedSortedSet);
+    assertSame(MUTEX, ((SynchronizedSortedSet<String>) headSet).mutex);
+  }
+
+  public void testHeadSet_E_B() {
+    NavigableSet<String> map = create();
+    NavigableSet<String> headSet = map.headSet("a", true);
+    assertTrue(headSet instanceof SynchronizedNavigableSet);
+    assertSame(MUTEX, ((SynchronizedNavigableSet<String>) headSet).mutex);
+  }
+
+  public void testSubSet_E_E() {
+    NavigableSet<String> map = create();
+    SortedSet<String> subSet = map.subSet("a", "b");
+    assertTrue(subSet instanceof SynchronizedSortedSet);
+    assertSame(MUTEX, ((SynchronizedSortedSet<String>) subSet).mutex);
+  }
+
+  public void testSubSet_E_B_E_B() {
+    NavigableSet<String> map = create();
+    NavigableSet<String> subSet = map.subSet("a", false, "b", true);
+    assertTrue(subSet instanceof SynchronizedNavigableSet);
+    assertSame(MUTEX, ((SynchronizedNavigableSet<String>) subSet).mutex);
+  }
+
+  public void testTailSet_E() {
+    NavigableSet<String> map = create();
+    SortedSet<String> tailSet = map.tailSet("a");
+    assertTrue(tailSet instanceof SynchronizedSortedSet);
+    assertSame(MUTEX, ((SynchronizedSortedSet<String>) tailSet).mutex);
+  }
+
+  public void testTailSet_E_B() {
+    NavigableSet<String> map = create();
+    NavigableSet<String> tailSet = map.tailSet("a", true);
+    assertTrue(tailSet instanceof SynchronizedNavigableSet);
+    assertSame(MUTEX, ((SynchronizedNavigableSet<String>) tailSet).mutex);
+  }
+}
diff --git a/guava-tests/test/com/google/common/collect/TreeBasedTableTest.java b/guava-tests/test/com/google/common/collect/TreeBasedTableTest.java
index 1e12b17..292a3b7 100644
--- a/guava-tests/test/com/google/common/collect/TreeBasedTableTest.java
+++ b/guava-tests/test/com/google/common/collect/TreeBasedTableTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -154,8 +154,8 @@
     table.put("foo", 12, 'b');
     table.put("bar", 5, 'c');
     table.put("cat", 8, 'd');
-    ASSERT.that(table.rowKeySet()).has().exactly("foo", "cat", "bar").inOrder();
-    ASSERT.that(table.row("foo").keySet()).has().exactly(12, 3).inOrder();
+    assertThat(table.rowKeySet()).has().exactly("foo", "cat", "bar").inOrder();
+    assertThat(table.row("foo").keySet()).has().exactly(12, 3).inOrder();
   }
 
   public void testCreateCopy() {
@@ -166,8 +166,8 @@
     original.put("bar", 5, 'c');
     original.put("cat", 8, 'd');
     table = TreeBasedTable.create(original);
-    ASSERT.that(table.rowKeySet()).has().exactly("foo", "cat", "bar").inOrder();
-    ASSERT.that(table.row("foo").keySet()).has().exactly(12, 3).inOrder();
+    assertThat(table.rowKeySet()).has().exactly("foo", "cat", "bar").inOrder();
+    assertThat(table.row("foo").keySet()).has().exactly(12, 3).inOrder();
     assertEquals(original, table);
   }
 
diff --git a/guava-tests/test/com/google/common/collect/TreeMultimapExplicitTest.java b/guava-tests/test/com/google/common/collect/TreeMultimapExplicitTest.java
index 68b4fd9..c6ec282 100644
--- a/guava-tests/test/com/google/common/collect/TreeMultimapExplicitTest.java
+++ b/guava-tests/test/com/google/common/collect/TreeMultimapExplicitTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -99,13 +99,13 @@
     tree.put("google", 6);
     tree.put("tree", 0);
     tree.put("tree", 3);
-    ASSERT.that(tree.keySet()).has().exactly("tree", "google").inOrder();
-    ASSERT.that(tree.get("google")).has().exactly(6, 2).inOrder();
+    assertThat(tree.keySet()).has().exactly("tree", "google").inOrder();
+    assertThat(tree.get("google")).has().exactly(6, 2).inOrder();
 
     TreeMultimap<String, Integer> copy = TreeMultimap.create(tree);
     assertEquals(tree, copy);
-    ASSERT.that(copy.keySet()).has().exactly("google", "tree").inOrder();
-    ASSERT.that(copy.get("google")).has().exactly(2, 6).inOrder();
+    assertThat(copy.keySet()).has().exactly("google", "tree").inOrder();
+    assertThat(copy.get("google")).has().exactly(2, 6).inOrder();
     assertEquals(Ordering.natural(), copy.keyComparator());
     assertEquals(Ordering.natural(), copy.valueComparator());
     assertEquals(Ordering.natural(), copy.get("google").comparator());
@@ -130,14 +130,14 @@
 
   public void testOrderedGet() {
     TreeMultimap<String, Integer> multimap = createPopulate();
-    ASSERT.that(multimap.get(null)).has().exactly(7, 3, 1).inOrder();
-    ASSERT.that(multimap.get("google")).has().exactly(6, 2).inOrder();
-    ASSERT.that(multimap.get("tree")).has().exactly(null, 0).inOrder();
+    assertThat(multimap.get(null)).has().exactly(7, 3, 1).inOrder();
+    assertThat(multimap.get("google")).has().exactly(6, 2).inOrder();
+    assertThat(multimap.get("tree")).has().exactly(null, 0).inOrder();
   }
 
   public void testOrderedKeySet() {
     TreeMultimap<String, Integer> multimap = createPopulate();
-    ASSERT.that(multimap.keySet()).has().exactly(null, "tree", "google").inOrder();
+    assertThat(multimap.keySet()).has().exactly(null, "tree", "google").inOrder();
   }
 
   public void testOrderedAsMapEntries() {
@@ -146,18 +146,18 @@
         multimap.asMap().entrySet().iterator();
     Map.Entry<String, Collection<Integer>> entry = iterator.next();
     assertEquals(null, entry.getKey());
-    ASSERT.that(entry.getValue()).has().exactly(7, 3, 1);
+    assertThat(entry.getValue()).has().exactly(7, 3, 1);
     entry = iterator.next();
     assertEquals("tree", entry.getKey());
-    ASSERT.that(entry.getValue()).has().exactly(null, 0);
+    assertThat(entry.getValue()).has().exactly(null, 0);
     entry = iterator.next();
     assertEquals("google", entry.getKey());
-    ASSERT.that(entry.getValue()).has().exactly(6, 2);
+    assertThat(entry.getValue()).has().exactly(6, 2);
   }
 
   public void testOrderedEntries() {
     TreeMultimap<String, Integer> multimap = createPopulate();
-    ASSERT.that(multimap.entries()).has().exactly(
+    assertThat(multimap.entries()).has().exactly(
         Maps.immutableEntry((String) null, 7),
         Maps.immutableEntry((String) null, 3),
         Maps.immutableEntry((String) null, 1),
@@ -169,7 +169,7 @@
 
   public void testOrderedValues() {
     TreeMultimap<String, Integer> multimap = createPopulate();
-    ASSERT.that(multimap.values()).has().exactly(7, 3, 1, null, 0, 6, 2).inOrder();
+    assertThat(multimap.values()).has().exactly(7, 3, 1, null, 0, 6, 2).inOrder();
   }
 
   public void testComparator() {
@@ -211,8 +211,8 @@
     TreeMultimap<String, Integer> multimap = createPopulate();
     TreeMultimap<String, Integer> copy
         = SerializableTester.reserializeAndAssert(multimap);
-    ASSERT.that(copy.values()).has().exactly(7, 3, 1, null, 0, 6, 2).inOrder();
-    ASSERT.that(copy.keySet()).has().exactly(null, "tree", "google").inOrder();
+    assertThat(copy.values()).has().exactly(7, 3, 1, null, 0, 6, 2).inOrder();
+    assertThat(copy.keySet()).has().exactly(null, "tree", "google").inOrder();
     assertEquals(multimap.keyComparator(), copy.keyComparator());
     assertEquals(multimap.valueComparator(), copy.valueComparator());
   }
diff --git a/guava-tests/test/com/google/common/collect/TreeMultimapNaturalTest.java b/guava-tests/test/com/google/common/collect/TreeMultimapNaturalTest.java
index f1f52f6..b0edc71 100644
--- a/guava-tests/test/com/google/common/collect/TreeMultimapNaturalTest.java
+++ b/guava-tests/test/com/google/common/collect/TreeMultimapNaturalTest.java
@@ -16,11 +16,19 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
 import com.google.common.collect.testing.DerivedComparable;
+import com.google.common.collect.testing.Helpers;
+import com.google.common.collect.testing.NavigableMapTestSuiteBuilder;
+import com.google.common.collect.testing.NavigableSetTestSuiteBuilder;
+import com.google.common.collect.testing.SampleElements;
+import com.google.common.collect.testing.TestSortedMapGenerator;
+import com.google.common.collect.testing.TestStringSetGenerator;
+import com.google.common.collect.testing.TestStringSortedSetGenerator;
 import com.google.common.collect.testing.features.CollectionFeature;
 import com.google.common.collect.testing.features.CollectionSize;
 import com.google.common.collect.testing.features.MapFeature;
@@ -40,6 +48,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.SortedSet;
@@ -92,6 +102,153 @@
           CollectionFeature.SERIALIZABLE,
           CollectionSize.ANY)
       .createTestSuite());
+    suite.addTest(NavigableSetTestSuiteBuilder.using(new TestStringSortedSetGenerator() {
+        @Override
+        protected NavigableSet<String> create(String[] elements) {
+          TreeMultimap<String, Integer> multimap = TreeMultimap.create(
+              Ordering.natural().nullsFirst(), Ordering.natural());
+          for (int i = 0; i < elements.length; i++) {
+            multimap.put(elements[i], i);
+          }
+          return multimap.keySet();
+        }
+
+        @Override
+        public List<String> order(List<String> insertionOrder) {
+          return Ordering.natural().nullsFirst().sortedCopy(insertionOrder);
+        }
+      })
+      .named("TreeMultimap.keySet")
+      .withFeatures(
+          CollectionFeature.ALLOWS_NULL_VALUES,
+          CollectionFeature.REMOVE_OPERATIONS,
+          CollectionFeature.KNOWN_ORDER,
+          CollectionSize.ANY)
+      .createTestSuite());
+    suite.addTest(NavigableMapTestSuiteBuilder.using(
+      new TestSortedMapGenerator<String, Collection<String>>() {
+
+        @Override
+        public String[] createKeyArray(int length) {
+          return new String[length];
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public Collection<String>[] createValueArray(int length) {
+          return new Collection[length];
+        }
+
+        @Override
+        public SampleElements<Entry<String, Collection<String>>> samples() {
+          return new SampleElements<Entry<String, Collection<String>>>(
+              Helpers.mapEntry("a", (Collection<String>) ImmutableSortedSet.of("alex")),
+              Helpers.mapEntry("b", (Collection<String>) ImmutableSortedSet.of("bob", "bagel")),
+              Helpers.mapEntry("c", (Collection<String>) ImmutableSortedSet.of("carl", "carol")),
+              Helpers.mapEntry("d", (Collection<String>) ImmutableSortedSet.of("david", "dead")),
+              Helpers.mapEntry("e", (Collection<String>) ImmutableSortedSet.of("eric", "elaine")));
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public Entry<String, Collection<String>>[] createArray(int length) {
+          return new Entry[length];
+        }
+
+        @Override
+        public Iterable<Entry<String, Collection<String>>> order(
+            List<Entry<String, Collection<String>>> insertionOrder) {
+          return new Ordering<Entry<String, ?>>() {
+            @Override
+            public int compare(Entry<String, ?> left, Entry<String, ?> right) {
+              return left.getKey().compareTo(right.getKey());
+            }
+          }.sortedCopy(insertionOrder);
+        }
+
+        @Override
+        public NavigableMap<String, Collection<String>> create(Object... elements) {
+          TreeMultimap<String, String> multimap = TreeMultimap.create();
+          for (Object o : elements) {
+            @SuppressWarnings("unchecked")
+            Entry<String, Collection<String>> entry = (Entry<String, Collection<String>>) o;
+            checkArgument(!multimap.containsKey(entry.getKey()));
+            multimap.putAll(entry.getKey(), entry.getValue());
+          }
+          return multimap.asMap();
+        }
+
+        @Override
+        public Entry<String, Collection<String>> belowSamplesLesser() {
+          return Helpers.mapEntry("-- a", (Collection<String>) ImmutableSortedSet.of("--below"));
+        }
+
+        @Override
+        public Entry<String, Collection<String>> belowSamplesGreater() {
+          return Helpers.mapEntry("-- b", (Collection<String>) ImmutableSortedSet.of("--below"));
+        }
+
+        @Override
+        public Entry<String, Collection<String>> aboveSamplesLesser() {
+          return Helpers.mapEntry("~~ b", (Collection<String>) ImmutableSortedSet.of("~above"));
+        }
+
+        @Override
+        public Entry<String, Collection<String>> aboveSamplesGreater() {
+          return Helpers.mapEntry("~~ c", (Collection<String>) ImmutableSortedSet.of("~above"));
+        }
+      })
+      .named("TreeMultimap.asMap")
+      .withFeatures(
+          MapFeature.SUPPORTS_REMOVE,
+          MapFeature.REJECTS_DUPLICATES_AT_CREATION,
+          CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
+          CollectionFeature.KNOWN_ORDER,
+          CollectionSize.ANY)
+      .createTestSuite());
+    suite.addTest(NavigableSetTestSuiteBuilder.using(new TestStringSetGenerator() {
+        @Override
+        protected Set<String> create(String[] elements) {
+          TreeMultimap<Integer, String> multimap = TreeMultimap.create(
+              Ordering.natural(), Ordering.natural().nullsFirst());
+          multimap.putAll(1, Arrays.asList(elements));
+          return multimap.get(1);
+        }
+
+        @Override
+        public List<String> order(List<String> insertionOrder) {
+          return Ordering.natural().nullsFirst().sortedCopy(insertionOrder);
+        }
+      })
+      .named("TreeMultimap.get")
+      .withFeatures(
+          CollectionFeature.ALLOWS_NULL_VALUES,
+          CollectionFeature.GENERAL_PURPOSE,
+          CollectionFeature.KNOWN_ORDER,
+          CollectionSize.ANY)
+      .createTestSuite());
+    suite.addTest(NavigableSetTestSuiteBuilder.using(new TestStringSetGenerator() {
+        @Override
+        protected Set<String> create(String[] elements) {
+          TreeMultimap<Integer, String> multimap = TreeMultimap.create(
+              Ordering.natural(), Ordering.natural().nullsFirst());
+          multimap.putAll(1, Arrays.asList(elements));
+          return (Set<String>) multimap.asMap().entrySet().iterator().next().getValue();
+        }
+
+        @Override
+        public List<String> order(List<String> insertionOrder) {
+          return Ordering.natural().nullsFirst().sortedCopy(insertionOrder);
+        }
+      })
+      .named("TreeMultimap.asMap.entrySet collection")
+      .withFeatures(
+          CollectionFeature.ALLOWS_NULL_VALUES,
+          CollectionFeature.GENERAL_PURPOSE,
+          CollectionFeature.KNOWN_ORDER,
+          CollectionSize.ONE,
+          CollectionSize.SEVERAL)
+      .createTestSuite());
     suite.addTestSuite(TreeMultimapNaturalTest.class);
     return suite;
   }
@@ -126,14 +283,14 @@
 
   public void testOrderedGet() {
     TreeMultimap<String, Integer> multimap = createPopulate();
-    ASSERT.that(multimap.get("foo")).has().exactly(1, 3, 7).inOrder();
-    ASSERT.that(multimap.get("google")).has().exactly(2, 6).inOrder();
-    ASSERT.that(multimap.get("tree")).has().exactly(0, 4).inOrder();
+    assertThat(multimap.get("foo")).has().exactly(1, 3, 7).inOrder();
+    assertThat(multimap.get("google")).has().exactly(2, 6).inOrder();
+    assertThat(multimap.get("tree")).has().exactly(0, 4).inOrder();
   }
 
   public void testOrderedKeySet() {
     TreeMultimap<String, Integer> multimap = createPopulate();
-    ASSERT.that(multimap.keySet()).has().exactly("foo", "google", "tree").inOrder();
+    assertThat(multimap.keySet()).has().exactly("foo", "google", "tree").inOrder();
   }
 
   public void testOrderedAsMapEntries() {
@@ -142,18 +299,18 @@
         multimap.asMap().entrySet().iterator();
     Map.Entry<String, Collection<Integer>> entry = iterator.next();
     assertEquals("foo", entry.getKey());
-    ASSERT.that(entry.getValue()).has().exactly(1, 3, 7);
+    assertThat(entry.getValue()).has().exactly(1, 3, 7);
     entry = iterator.next();
     assertEquals("google", entry.getKey());
-    ASSERT.that(entry.getValue()).has().exactly(2, 6);
+    assertThat(entry.getValue()).has().exactly(2, 6);
     entry = iterator.next();
     assertEquals("tree", entry.getKey());
-    ASSERT.that(entry.getValue()).has().exactly(0, 4);
+    assertThat(entry.getValue()).has().exactly(0, 4);
   }
 
   public void testOrderedEntries() {
     TreeMultimap<String, Integer> multimap = createPopulate();
-    ASSERT.that(multimap.entries()).has().exactly(
+    assertThat(multimap.entries()).has().exactly(
         Maps.immutableEntry("foo", 1),
         Maps.immutableEntry("foo", 3),
         Maps.immutableEntry("foo", 7),
@@ -165,7 +322,7 @@
 
   public void testOrderedValues() {
     TreeMultimap<String, Integer> multimap = createPopulate();
-    ASSERT.that(multimap.values()).has().exactly(
+    assertThat(multimap.values()).has().exactly(
         1, 3, 7, 2, 6, 0, 4).inOrder();
   }
 
@@ -248,8 +405,8 @@
     TreeMultimap<String, Integer> multimap = createPopulate();
     TreeMultimap<String, Integer> copy
         = SerializableTester.reserializeAndAssert(multimap);
-    ASSERT.that(copy.values()).has().exactly(1, 3, 7, 2, 6, 0, 4).inOrder();
-    ASSERT.that(copy.keySet()).has().exactly("foo", "google", "tree").inOrder();
+    assertThat(copy.values()).has().exactly(1, 3, 7, 2, 6, 0, 4).inOrder();
+    assertThat(copy.keySet()).has().exactly("foo", "google", "tree").inOrder();
     assertEquals(multimap.keyComparator(), copy.keyComparator());
     assertEquals(multimap.valueComparator(), copy.valueComparator());
   }
@@ -264,9 +421,9 @@
     multimap.put(new DerivedComparable("bar"), new DerivedComparable("b"));
     multimap.put(new DerivedComparable("bar"), new DerivedComparable("a"));
     multimap.put(new DerivedComparable("bar"), new DerivedComparable("r"));
-    ASSERT.that(multimap.keySet()).has().exactly(
+    assertThat(multimap.keySet()).has().exactly(
         new DerivedComparable("bar"), new DerivedComparable("foo")).inOrder();
-    ASSERT.that(multimap.values()).has().exactly(
+    assertThat(multimap.values()).has().exactly(
         new DerivedComparable("a"), new DerivedComparable("b"), new DerivedComparable("r"),
         new DerivedComparable("f"), new DerivedComparable("o")).inOrder();
     assertEquals(Ordering.natural(), multimap.keyComparator());
@@ -285,9 +442,9 @@
     multimap.put(new LegacyComparable("bar"), new LegacyComparable("b"));
     multimap.put(new LegacyComparable("bar"), new LegacyComparable("a"));
     multimap.put(new LegacyComparable("bar"), new LegacyComparable("r"));
-    ASSERT.that(multimap.keySet()).has().exactly(
+    assertThat(multimap.keySet()).has().exactly(
         new LegacyComparable("bar"), new LegacyComparable("foo")).inOrder();
-    ASSERT.that(multimap.values()).has().exactly(
+    assertThat(multimap.values()).has().exactly(
         new LegacyComparable("a"),
         new LegacyComparable("b"),
         new LegacyComparable("r"),
diff --git a/guava-tests/test/com/google/common/collect/TreeMultisetTest.java b/guava-tests/test/com/google/common/collect/TreeMultisetTest.java
index 8cb98ab..86a2197 100644
--- a/guava-tests/test/com/google/common/collect/TreeMultisetTest.java
+++ b/guava-tests/test/com/google/common/collect/TreeMultisetTest.java
@@ -17,13 +17,13 @@
 package com.google.common.collect;
 
 import static com.google.common.collect.BoundType.CLOSED;
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Collections.sort;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
 import com.google.common.collect.testing.Helpers.NullsBeforeB;
-import com.google.common.collect.testing.SortedSetTestSuiteBuilder;
+import com.google.common.collect.testing.NavigableSetTestSuiteBuilder;
 import com.google.common.collect.testing.TestStringSetGenerator;
 import com.google.common.collect.testing.features.CollectionFeature;
 import com.google.common.collect.testing.features.CollectionSize;
@@ -95,7 +95,7 @@
             MultisetFeature.ENTRIES_ARE_VIEWS)
         .named("TreeMultiset, NullsBeforeB")
         .createTestSuite());
-    suite.addTest(SortedSetTestSuiteBuilder.using(new TestStringSetGenerator() {
+    suite.addTest(NavigableSetTestSuiteBuilder.using(new TestStringSetGenerator() {
         @Override
         protected Set<String> create(String[] elements) {
           return TreeMultiset.create(Arrays.asList(elements)).elementSet();
@@ -163,9 +163,9 @@
     assertEquals("c", elementSet.last());
     assertEquals(Ordering.natural(), elementSet.comparator());
 
-    ASSERT.that(elementSet.headSet("b")).has().exactly("a").inOrder();
-    ASSERT.that(elementSet.tailSet("b")).has().exactly("b", "c").inOrder();
-    ASSERT.that(elementSet.subSet("a", "c")).has().exactly("a", "b").inOrder();
+    assertThat(elementSet.headSet("b")).has().exactly("a").inOrder();
+    assertThat(elementSet.tailSet("b")).has().exactly("b", "c").inOrder();
+    assertThat(elementSet.subSet("a", "c")).has().exactly("a", "b").inOrder();
   }
 
   public void testElementSetSubsetRemove() {
@@ -178,18 +178,18 @@
     ms.add("f", 2);
 
     SortedSet<String> elementSet = ms.elementSet();
-    ASSERT.that(elementSet).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(elementSet).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
     SortedSet<String> subset = elementSet.subSet("b", "f");
-    ASSERT.that(subset).has().exactly("b", "c", "d", "e").inOrder();
+    assertThat(subset).has().exactly("b", "c", "d", "e").inOrder();
 
     assertTrue(subset.remove("c"));
-    ASSERT.that(elementSet).has().exactly("a", "b", "d", "e", "f").inOrder();
-    ASSERT.that(subset).has().exactly("b", "d", "e").inOrder();
+    assertThat(elementSet).has().exactly("a", "b", "d", "e", "f").inOrder();
+    assertThat(subset).has().exactly("b", "d", "e").inOrder();
     assertEquals(10, ms.size());
 
     assertFalse(subset.remove("a"));
-    ASSERT.that(elementSet).has().exactly("a", "b", "d", "e", "f").inOrder();
-    ASSERT.that(subset).has().exactly("b", "d", "e").inOrder();
+    assertThat(elementSet).has().exactly("a", "b", "d", "e", "f").inOrder();
+    assertThat(subset).has().exactly("b", "d", "e").inOrder();
     assertEquals(10, ms.size());
   }
 
@@ -203,13 +203,13 @@
     ms.add("f", 2);
 
     SortedSet<String> elementSet = ms.elementSet();
-    ASSERT.that(elementSet).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(elementSet).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
     SortedSet<String> subset = elementSet.subSet("b", "f");
-    ASSERT.that(subset).has().exactly("b", "c", "d", "e").inOrder();
+    assertThat(subset).has().exactly("b", "c", "d", "e").inOrder();
 
     assertTrue(subset.removeAll(Arrays.asList("a", "c")));
-    ASSERT.that(elementSet).has().exactly("a", "b", "d", "e", "f").inOrder();
-    ASSERT.that(subset).has().exactly("b", "d", "e").inOrder();
+    assertThat(elementSet).has().exactly("a", "b", "d", "e", "f").inOrder();
+    assertThat(subset).has().exactly("b", "d", "e").inOrder();
     assertEquals(10, ms.size());
   }
 
@@ -223,13 +223,13 @@
     ms.add("f", 2);
 
     SortedSet<String> elementSet = ms.elementSet();
-    ASSERT.that(elementSet).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(elementSet).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
     SortedSet<String> subset = elementSet.subSet("b", "f");
-    ASSERT.that(subset).has().exactly("b", "c", "d", "e").inOrder();
+    assertThat(subset).has().exactly("b", "c", "d", "e").inOrder();
 
     assertTrue(subset.retainAll(Arrays.asList("a", "c")));
-    ASSERT.that(elementSet).has().exactly("a", "c", "f").inOrder();
-    ASSERT.that(subset).has().exactly("c").inOrder();
+    assertThat(elementSet).has().exactly("a", "c", "f").inOrder();
+    assertThat(subset).has().exactly("c").inOrder();
     assertEquals(5, ms.size());
   }
 
@@ -243,13 +243,13 @@
     ms.add("f", 2);
 
     SortedSet<String> elementSet = ms.elementSet();
-    ASSERT.that(elementSet).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
+    assertThat(elementSet).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
     SortedSet<String> subset = elementSet.subSet("b", "f");
-    ASSERT.that(subset).has().exactly("b", "c", "d", "e").inOrder();
+    assertThat(subset).has().exactly("b", "c", "d", "e").inOrder();
 
     subset.clear();
-    ASSERT.that(elementSet).has().exactly("a", "f").inOrder();
-    ASSERT.that(subset).isEmpty();
+    assertThat(elementSet).has().exactly("a", "f").inOrder();
+    assertThat(subset).isEmpty();
     assertEquals(3, ms.size());
   }
 
@@ -268,7 +268,7 @@
     ms.add("b");
     ms.add("d");
 
-    ASSERT.that(ms).has().exactly("d", "c", "b", "b", "a").inOrder();
+    assertThat(ms).has().exactly("d", "c", "b", "b", "a").inOrder();
 
     SortedSet<String> elementSet = ms.elementSet();
     assertEquals("d", elementSet.first());
@@ -286,7 +286,7 @@
     ms.add("b");
     ms.add(null, 2);
 
-    ASSERT.that(ms).has().exactly(null, null, null, "a", "b", "b").inOrder();
+    assertThat(ms).has().exactly(null, null, null, "a", "b", "b").inOrder();
     assertEquals(3, ms.count(null));
 
     SortedSet<String> elementSet = ms.elementSet();
diff --git a/guava-tests/test/com/google/common/collect/TreeRangeMapTest.java b/guava-tests/test/com/google/common/collect/TreeRangeMapTest.java
new file mode 100644
index 0000000..02dbbc4
--- /dev/null
+++ b/guava-tests/test/com/google/common/collect/TreeRangeMapTest.java
@@ -0,0 +1,479 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.common.collect;
+
+import static com.google.common.collect.BoundType.OPEN;
+import static com.google.common.collect.testing.Helpers.mapEntry;
+
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.collect.testing.MapTestSuiteBuilder;
+import com.google.common.collect.testing.SampleElements;
+import com.google.common.collect.testing.TestMapGenerator;
+import com.google.common.collect.testing.features.CollectionFeature;
+import com.google.common.collect.testing.features.CollectionSize;
+import com.google.common.collect.testing.features.MapFeature;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NoSuchElementException;
+
+/**
+ * Tests for {@code TreeRangeMap}.
+ *
+ * @author Louis Wasserman
+ */
+@GwtIncompatible("NavigableMap")
+public class TreeRangeMapTest extends TestCase {
+  public static Test suite() {
+    TestSuite suite = new TestSuite();
+    suite.addTestSuite(TreeRangeMapTest.class);
+    suite.addTest(MapTestSuiteBuilder.using(new TestMapGenerator<Range<Integer>, String>() {
+        @Override
+        public SampleElements<Entry<Range<Integer>, String>> samples() {
+          return new SampleElements<Entry<Range<Integer>, String>>(
+              mapEntry(Range.singleton(0), "banana"),
+              mapEntry(Range.closedOpen(3, 5), "frisbee"),
+              mapEntry(Range.atMost(-1), "fruitcake"),
+              mapEntry(Range.open(10, 15), "elephant"),
+              mapEntry(Range.closed(20, 22), "umbrella"));
+        }
+
+        @Override
+        public Map<Range<Integer>, String> create(Object... elements) {
+          RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
+          for (Object o : elements) {
+            @SuppressWarnings("unchecked")
+            Entry<Range<Integer>, String> entry = (Entry<Range<Integer>, String>) o;
+            rangeMap.put(entry.getKey(), entry.getValue());
+          }
+          return rangeMap.asMapOfRanges();
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public Entry<Range<Integer>, String>[] createArray(int length) {
+          return new Entry[length];
+        }
+
+        @Override
+        public Iterable<Entry<Range<Integer>, String>> order(
+            List<Entry<Range<Integer>, String>> insertionOrder) {
+          return Range.RANGE_LEX_ORDERING.<Range<Integer>>onKeys()
+              .sortedCopy(insertionOrder);
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public Range<Integer>[] createKeyArray(int length) {
+          return new Range[length];
+        }
+
+        @Override
+        public String[] createValueArray(int length) {
+          return new String[length];
+        }
+      })
+      .named("TreeRangeMap.asMapOfRanges")
+      .withFeatures(
+          CollectionSize.ANY,
+          MapFeature.SUPPORTS_REMOVE,
+          MapFeature.ALLOWS_ANY_NULL_QUERIES,
+          CollectionFeature.KNOWN_ORDER,
+          CollectionFeature.SUPPORTS_ITERATOR_REMOVE)
+      .createTestSuite());
+
+    suite.addTest(MapTestSuiteBuilder.using(new TestMapGenerator<Range<Integer>, String>() {
+        @Override
+        public SampleElements<Entry<Range<Integer>, String>> samples() {
+          return new SampleElements<Entry<Range<Integer>, String>>(
+              mapEntry(Range.singleton(0), "banana"),
+              mapEntry(Range.closedOpen(3, 5), "frisbee"),
+              mapEntry(Range.atMost(-1), "fruitcake"),
+              mapEntry(Range.open(10, 15), "elephant"),
+              mapEntry(Range.closed(20, 22), "umbrella"));
+        }
+
+        @Override
+        public Map<Range<Integer>, String> create(Object... elements) {
+          RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
+          for (Object o : elements) {
+            @SuppressWarnings("unchecked")
+            Entry<Range<Integer>, String> entry = (Entry<Range<Integer>, String>) o;
+            rangeMap.put(entry.getKey(), entry.getValue());
+          }
+          return rangeMap.subRangeMap(Range.atMost(22)).asMapOfRanges();
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public Entry<Range<Integer>, String>[] createArray(int length) {
+          return new Entry[length];
+        }
+
+        @Override
+        public Iterable<Entry<Range<Integer>, String>> order(
+            List<Entry<Range<Integer>, String>> insertionOrder) {
+          return Range.RANGE_LEX_ORDERING.<Range<Integer>>onKeys()
+              .sortedCopy(insertionOrder);
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public Range<Integer>[] createKeyArray(int length) {
+          return new Range[length];
+        }
+
+        @Override
+        public String[] createValueArray(int length) {
+          return new String[length];
+        }
+      })
+      .named("TreeRangeMap.subRangeMap.asMapOfRanges")
+      .withFeatures(
+          CollectionSize.ANY,
+          MapFeature.SUPPORTS_REMOVE,
+          MapFeature.ALLOWS_ANY_NULL_QUERIES,
+          CollectionFeature.KNOWN_ORDER)
+      .createTestSuite());
+    return suite;
+  }
+
+  private static final ImmutableList<Range<Integer>> RANGES;
+  private static final int MIN_BOUND = -2;
+  private static final int MAX_BOUND = 2;
+  static {
+    ImmutableList.Builder<Range<Integer>> builder = ImmutableList.builder();
+
+    builder.add(Range.<Integer>all());
+
+    // Add one-ended ranges
+    for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
+      for (BoundType type : BoundType.values()) {
+        builder.add(Range.upTo(i, type));
+        builder.add(Range.downTo(i, type));
+      }
+    }
+
+    // Add two-ended ranges
+    for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
+      for (int j = i; j <= MAX_BOUND; j++) {
+        for (BoundType lowerType : BoundType.values()) {
+          for (BoundType upperType : BoundType.values()) {
+            if (i == j & lowerType == OPEN & upperType == OPEN) {
+              continue;
+            }
+            builder.add(Range.range(i, lowerType, j, upperType));
+          }
+        }
+      }
+    }
+    RANGES = builder.build();
+  }
+
+  public void testSpanSingleRange() {
+    for (Range<Integer> range : RANGES) {
+      RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
+      rangeMap.put(range, 1);
+
+      try {
+        assertEquals(range, rangeMap.span());
+        assertFalse(range.isEmpty());
+      } catch (NoSuchElementException e) {
+        assertTrue(range.isEmpty());
+      }
+    }
+  }
+
+  public void testSpanTwoRanges() {
+    for (Range<Integer> range1 : RANGES) {
+      for (Range<Integer> range2 : RANGES) {
+        RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
+        rangeMap.put(range1, 1);
+        rangeMap.put(range2, 2);
+
+        Range<Integer> expected;
+        if (range1.isEmpty()) {
+          if (range2.isEmpty()) {
+            expected = null;
+          } else {
+            expected = range2;
+          }
+        } else {
+          if (range2.isEmpty()) {
+            expected = range1;
+          } else {
+            expected = range1.span(range2);
+          }
+        }
+
+        try {
+          assertEquals(expected, rangeMap.span());
+          assertNotNull(expected);
+        } catch (NoSuchElementException e) {
+          assertNull(expected);
+        }
+      }
+    }
+  }
+
+  public void testAllRangesAlone() {
+    for (Range<Integer> range : RANGES) {
+      Map<Integer, Integer> model = Maps.newHashMap();
+      putModel(model, range, 1);
+      RangeMap<Integer, Integer> test = TreeRangeMap.create();
+      test.put(range, 1);
+      verify(model, test);
+    }
+  }
+
+  public void testAllRangePairs() {
+    for (Range<Integer> range1 : RANGES) {
+      for (Range<Integer> range2 : RANGES) {
+        Map<Integer, Integer> model = Maps.newHashMap();
+        putModel(model, range1, 1);
+        putModel(model, range2, 2);
+        RangeMap<Integer, Integer> test = TreeRangeMap.create();
+        test.put(range1, 1);
+        test.put(range2, 2);
+        verify(model, test);
+      }
+    }
+  }
+
+  public void testAllRangeTriples() {
+    for (Range<Integer> range1 : RANGES) {
+      for (Range<Integer> range2 : RANGES) {
+        for (Range<Integer> range3 : RANGES) {
+          Map<Integer, Integer> model = Maps.newHashMap();
+          putModel(model, range1, 1);
+          putModel(model, range2, 2);
+          putModel(model, range3, 3);
+          RangeMap<Integer, Integer> test = TreeRangeMap.create();
+          test.put(range1, 1);
+          test.put(range2, 2);
+          test.put(range3, 3);
+          verify(model, test);
+        }
+      }
+    }
+  }
+
+  public void testPutAll() {
+    for (Range<Integer> range1 : RANGES) {
+      for (Range<Integer> range2 : RANGES) {
+        for (Range<Integer> range3 : RANGES) {
+          Map<Integer, Integer> model = Maps.newHashMap();
+          putModel(model, range1, 1);
+          putModel(model, range2, 2);
+          putModel(model, range3, 3);
+          RangeMap<Integer, Integer> test = TreeRangeMap.create();
+          RangeMap<Integer, Integer> test2 = TreeRangeMap.create();
+          // put range2 and range3 into test2, and then put test2 into test
+          test.put(range1, 1);
+          test2.put(range2, 2);
+          test2.put(range3, 3);
+          test.putAll(test2);
+          verify(model, test);
+        }
+      }
+    }
+  }
+
+  public void testPutAndRemove() {
+    for (Range<Integer> rangeToPut : RANGES) {
+      for (Range<Integer> rangeToRemove : RANGES) {
+        Map<Integer, Integer> model = Maps.newHashMap();
+        putModel(model, rangeToPut, 1);
+        removeModel(model, rangeToRemove);
+        RangeMap<Integer, Integer> test = TreeRangeMap.create();
+        test.put(rangeToPut, 1);
+        test.remove(rangeToRemove);
+        verify(model, test);
+      }
+    }
+  }
+
+  public void testPutTwoAndRemove() {
+    for (Range<Integer> rangeToPut1 : RANGES) {
+      for (Range<Integer> rangeToPut2 : RANGES) {
+        for (Range<Integer> rangeToRemove : RANGES) {
+          Map<Integer, Integer> model = Maps.newHashMap();
+          putModel(model, rangeToPut1, 1);
+          putModel(model, rangeToPut2, 2);
+          removeModel(model, rangeToRemove);
+          RangeMap<Integer, Integer> test = TreeRangeMap.create();
+          test.put(rangeToPut1, 1);
+          test.put(rangeToPut2, 2);
+          test.remove(rangeToRemove);
+          verify(model, test);
+        }
+      }
+    }
+  }
+
+  public void testSubRangeMapExhaustive() {
+    for (Range<Integer> range1 : RANGES) {
+      for (Range<Integer> range2 : RANGES) {
+        RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
+        rangeMap.put(range1, 1);
+        rangeMap.put(range2, 2);
+
+        for (Range<Integer> subRange : RANGES) {
+          RangeMap<Integer, Integer> expected = TreeRangeMap.create();
+          for (Map.Entry<Range<Integer>, Integer> entry : rangeMap.asMapOfRanges().entrySet()) {
+            if (entry.getKey().isConnected(subRange)) {
+              expected.put(entry.getKey().intersection(subRange), entry.getValue());
+            }
+          }
+          RangeMap<Integer, Integer> subRangeMap = rangeMap.subRangeMap(subRange);
+          assertEquals(expected, subRangeMap);
+          assertEquals(expected.asMapOfRanges(), subRangeMap.asMapOfRanges());
+
+          if (!expected.asMapOfRanges().isEmpty()) {
+            assertEquals(expected.span(), subRangeMap.span());
+          }
+
+          for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
+            assertEquals(expected.get(i), subRangeMap.get(i));
+          }
+
+          for (Range<Integer> query : RANGES) {
+            assertEquals(
+                expected.asMapOfRanges().get(query),
+                subRangeMap.asMapOfRanges().get(query));
+          }
+        }
+      }
+    }
+  }
+
+  public void testSubSubRangeMap() {
+    RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
+    rangeMap.put(Range.open(3, 7), 1);
+    rangeMap.put(Range.closed(9, 10), 2);
+    rangeMap.put(Range.closed(12, 16), 3);
+    RangeMap<Integer, Integer> sub1 = rangeMap.subRangeMap(Range.closed(5, 11));
+    assertEquals(ImmutableMap.of(Range.closedOpen(5, 7), 1, Range.closed(9, 10), 2),
+        sub1.asMapOfRanges());
+    RangeMap<Integer, Integer> sub2 = sub1.subRangeMap(Range.open(6, 15));
+    assertEquals(ImmutableMap.of(Range.open(6, 7), 1, Range.closed(9, 10), 2),
+        sub2.asMapOfRanges());
+  }
+
+  public void testSubRangeMapPut() {
+    RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
+    rangeMap.put(Range.open(3, 7), 1);
+    rangeMap.put(Range.closed(9, 10), 2);
+    rangeMap.put(Range.closed(12, 16), 3);
+    RangeMap<Integer, Integer> sub = rangeMap.subRangeMap(Range.closed(5, 11));
+    assertEquals(ImmutableMap.of(Range.closedOpen(5, 7), 1, Range.closed(9, 10), 2),
+        sub.asMapOfRanges());
+    sub.put(Range.closed(7, 9), 4);
+    assertEquals(
+        ImmutableMap.of(
+            Range.closedOpen(5, 7), 1, Range.closed(7, 9), 4, Range.openClosed(9, 10), 2),
+        sub.asMapOfRanges());
+    assertEquals(
+        ImmutableMap.of(Range.open(3, 7), 1, Range.closed(7, 9), 4, Range.openClosed(9, 10), 2,
+            Range.closed(12, 16), 3),
+        rangeMap.asMapOfRanges());
+
+    try {
+      sub.put(Range.open(9, 12), 5);
+      fail("Expected IllegalArgumentException");
+    } catch (IllegalArgumentException expected) {
+    }
+
+    sub = sub.subRangeMap(Range.closedOpen(5, 5));
+    sub.put(Range.closedOpen(5, 5), 6); // should be a no-op
+    assertEquals(
+        ImmutableMap.of(Range.open(3, 7), 1, Range.closed(7, 9), 4, Range.openClosed(9, 10), 2,
+            Range.closed(12, 16), 3),
+        rangeMap.asMapOfRanges());
+  }
+
+  public void testSubRangeMapRemove() {
+    RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
+    rangeMap.put(Range.open(3, 7), 1);
+    rangeMap.put(Range.closed(9, 10), 2);
+    rangeMap.put(Range.closed(12, 16), 3);
+    RangeMap<Integer, Integer> sub = rangeMap.subRangeMap(Range.closed(5, 11));
+    assertEquals(ImmutableMap.of(Range.closedOpen(5, 7), 1, Range.closed(9, 10), 2),
+        sub.asMapOfRanges());
+    sub.remove(Range.closed(7, 9));
+    assertEquals(
+        ImmutableMap.of(Range.closedOpen(5, 7), 1, Range.openClosed(9, 10), 2),
+        sub.asMapOfRanges());
+    assertEquals(
+        ImmutableMap.of(Range.open(3, 7), 1, Range.openClosed(9, 10), 2, Range.closed(12, 16), 3),
+        rangeMap.asMapOfRanges());
+
+    sub.remove(Range.closed(3, 9));
+    assertEquals(
+        ImmutableMap.of(Range.openClosed(9, 10), 2),
+        sub.asMapOfRanges());
+    assertEquals(
+        ImmutableMap.of(Range.open(3, 5), 1, Range.openClosed(9, 10), 2, Range.closed(12, 16), 3),
+        rangeMap.asMapOfRanges());
+  }
+
+  public void testSubRangeMapClear() {
+    RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
+    rangeMap.put(Range.open(3, 7), 1);
+    rangeMap.put(Range.closed(9, 10), 2);
+    rangeMap.put(Range.closed(12, 16), 3);
+    RangeMap<Integer, Integer> sub = rangeMap.subRangeMap(Range.closed(5, 11));
+    sub.clear();
+    assertEquals(
+        ImmutableMap.of(Range.open(3, 5), 1, Range.closed(12, 16), 3),
+        rangeMap.asMapOfRanges());
+  }
+
+  private void verify(Map<Integer, Integer> model, RangeMap<Integer, Integer> test) {
+    for (int i = MIN_BOUND - 1; i <= MAX_BOUND + 1; i++) {
+      assertEquals(model.get(i), test.get(i));
+
+      Map.Entry<Range<Integer>, Integer> entry = test.getEntry(i);
+      assertEquals(model.containsKey(i), entry != null);
+      if (entry != null) {
+        assertTrue(test.asMapOfRanges().entrySet().contains(entry));
+      }
+    }
+    for (Range<Integer> range : test.asMapOfRanges().keySet()) {
+      assertFalse(range.isEmpty());
+    }
+  }
+
+  private void putModel(Map<Integer, Integer> model, Range<Integer> range, int value) {
+    for (int i = MIN_BOUND - 1; i <= MAX_BOUND + 1; i++) {
+      if (range.contains(i)) {
+        model.put(i, value);
+      }
+    }
+  }
+
+  private void removeModel(Map<Integer, Integer> model, Range<Integer> range) {
+    for (int i = MIN_BOUND - 1; i <= MAX_BOUND + 1; i++) {
+      if (range.contains(i)) {
+        model.remove(i);
+      }
+    }
+  }
+}
diff --git a/guava-tests/test/com/google/common/collect/TreeRangeSetTest.java b/guava-tests/test/com/google/common/collect/TreeRangeSetTest.java
new file mode 100644
index 0000000..55a618e
--- /dev/null
+++ b/guava-tests/test/com/google/common/collect/TreeRangeSetTest.java
@@ -0,0 +1,571 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.common.collect;
+
+import static com.google.common.collect.BoundType.OPEN;
+import static com.google.common.collect.Range.range;
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.annotations.GwtIncompatible;
+
+import java.util.List;
+import java.util.NavigableMap;
+
+/**
+ * Tests for {@link TreeRangeSet}.
+ *
+ * @author Louis Wasserman
+ * @author Chris Povirk
+ */
+@GwtIncompatible("TreeRangeSet")
+public class TreeRangeSetTest extends AbstractRangeSetTest {
+  // TODO(cpovirk): test all of these with the ranges added in the reverse order
+
+  private static final ImmutableList<Range<Integer>> QUERY_RANGES;
+
+  private static final int MIN_BOUND = -1;
+  private static final int MAX_BOUND = 1;
+
+  static {
+    ImmutableList.Builder<Range<Integer>> queryBuilder = ImmutableList.builder();
+
+    queryBuilder.add(Range.<Integer>all());
+
+    for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
+      for (BoundType boundType : BoundType.values()) {
+        queryBuilder.add(Range.upTo(i, boundType));
+        queryBuilder.add(Range.downTo(i, boundType));
+      }
+      queryBuilder.add(Range.singleton(i));
+      queryBuilder.add(Range.openClosed(i, i));
+      queryBuilder.add(Range.closedOpen(i, i));
+
+      for (BoundType lowerBoundType : BoundType.values()) {
+        for (int j = i + 1; j <= MAX_BOUND; j++) {
+          for (BoundType upperBoundType : BoundType.values()) {
+            queryBuilder.add(Range.range(i, lowerBoundType, j, upperBoundType));
+          }
+        }
+      }
+    }
+    QUERY_RANGES = queryBuilder.build();
+  }
+
+  void testViewAgainstExpected(RangeSet<Integer> expected, RangeSet<Integer> view) {
+    assertEquals(expected, view);
+    assertEquals(expected.asRanges(), view.asRanges());
+    assertEquals(expected.isEmpty(), view.isEmpty());
+
+    if (!expected.isEmpty()) {
+      assertEquals(expected.span(), view.span());
+    }
+
+    for (int i = MIN_BOUND - 1; i <= MAX_BOUND + 1; i++) {
+      assertEquals(expected.contains(i), view.contains(i));
+      assertEquals(expected.rangeContaining(i), view.rangeContaining(i));
+    }
+    testEnclosing(view);
+    if (view instanceof TreeRangeSet) {
+      testRangesByLowerBounds((TreeRangeSet<Integer>) view, expected.asRanges());
+    }
+  }
+
+  private static final ImmutableList<Cut<Integer>> CUTS_TO_TEST;
+
+  static {
+    List<Cut<Integer>> cutsToTest = Lists.newArrayList();
+    for (int i = MIN_BOUND - 1; i <= MAX_BOUND + 1; i++) {
+      cutsToTest.add(Cut.belowValue(i));
+      cutsToTest.add(Cut.aboveValue(i));
+    }
+    cutsToTest.add(Cut.<Integer>aboveAll());
+    cutsToTest.add(Cut.<Integer>belowAll());
+    CUTS_TO_TEST = ImmutableList.copyOf(cutsToTest);
+  }
+
+  private void testRangesByLowerBounds(
+      TreeRangeSet<Integer> rangeSet, Iterable<Range<Integer>> expectedRanges) {
+    NavigableMap<Cut<Integer>, Range<Integer>> expectedRangesByLowerBound = Maps.newTreeMap();
+    for (Range<Integer> range : expectedRanges) {
+      expectedRangesByLowerBound.put(range.lowerBound, range);
+    }
+
+    NavigableMap<Cut<Integer>, Range<Integer>> rangesByLowerBound = rangeSet.rangesByLowerBound;
+    testNavigationAgainstExpected(expectedRangesByLowerBound, rangesByLowerBound, CUTS_TO_TEST);
+  }
+
+  <K, V> void testNavigationAgainstExpected(
+      NavigableMap<K, V> expected, NavigableMap<K, V> navigableMap, Iterable<K> keysToTest) {
+    for (K key : keysToTest) {
+      assertEquals(expected.lowerEntry(key), navigableMap.lowerEntry(key));
+      assertEquals(expected.floorEntry(key), navigableMap.floorEntry(key));
+      assertEquals(expected.ceilingEntry(key), navigableMap.ceilingEntry(key));
+      assertEquals(expected.higherEntry(key), navigableMap.higherEntry(key));
+      for (boolean inclusive : new boolean[] {false, true}) {
+        assertThat(navigableMap.headMap(key, inclusive).entrySet())
+            .has().exactlyAs(expected.headMap(key, inclusive).entrySet()).inOrder();
+        assertThat(navigableMap.tailMap(key, inclusive).entrySet())
+            .has().exactlyAs(expected.tailMap(key, inclusive).entrySet()).inOrder();
+        assertThat(navigableMap.headMap(key, inclusive).descendingMap().entrySet())
+            .has().exactlyAs(expected.headMap(key, inclusive).descendingMap().entrySet()).inOrder();
+        assertThat(navigableMap.tailMap(key, inclusive).descendingMap().entrySet())
+            .has().exactlyAs(expected.tailMap(key, inclusive).descendingMap().entrySet()).inOrder();
+      }
+    }
+  }
+
+  public void testEnclosing(RangeSet<Integer> rangeSet) {
+    for (Range<Integer> query : QUERY_RANGES) {
+      boolean expectEnclose = false;
+      for (Range<Integer> expectedRange : rangeSet.asRanges()) {
+        if (expectedRange.encloses(query)) {
+          expectEnclose = true;
+          break;
+        }
+      }
+
+      assertEquals(rangeSet + " was incorrect on encloses(" + query + ")", expectEnclose,
+          rangeSet.encloses(query));
+    }
+  }
+
+  public void testAllSingleRangesComplementAgainstRemove() {
+    for (Range<Integer> range : QUERY_RANGES) {
+      TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+      rangeSet.add(range);
+
+      TreeRangeSet<Integer> complement = TreeRangeSet.create();
+      complement.add(Range.<Integer>all());
+      complement.remove(range);
+
+      assertEquals(complement, rangeSet.complement());
+      assertThat(rangeSet.complement().asRanges())
+          .has().exactlyAs(complement.asRanges()).inOrder();
+    }
+  }
+
+  public void testInvariantsEmpty() {
+    testInvariants(TreeRangeSet.create());
+  }
+
+  public void testAllSingleRangesEnclosing() {
+    for (Range<Integer> range : QUERY_RANGES) {
+      TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+      rangeSet.add(range);
+      testEnclosing(rangeSet);
+      testEnclosing(rangeSet.complement());
+    }
+  }
+
+  public void testAllTwoRangesEnclosing() {
+    for (Range<Integer> range1 : QUERY_RANGES) {
+      for (Range<Integer> range2 : QUERY_RANGES) {
+        TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+        rangeSet.add(range1);
+        rangeSet.add(range2);
+        testEnclosing(rangeSet);
+        testEnclosing(rangeSet.complement());
+      }
+    }
+  }
+
+  public void testCreateCopy() {
+    for (Range<Integer> range1 : QUERY_RANGES) {
+      for (Range<Integer> range2 : QUERY_RANGES) {
+        TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+        rangeSet.add(range1);
+        rangeSet.add(range2);
+
+        assertEquals(rangeSet, TreeRangeSet.create(rangeSet));
+      }
+    }
+  }
+
+  private RangeSet<Integer> expectedSubRangeSet(
+      RangeSet<Integer> rangeSet, Range<Integer> subRange) {
+    RangeSet<Integer> expected = TreeRangeSet.create();
+    for (Range<Integer> range : rangeSet.asRanges()) {
+      if (range.isConnected(subRange)) {
+        expected.add(range.intersection(subRange));
+      }
+    }
+    return expected;
+  }
+
+  private RangeSet<Integer> expectedComplement(RangeSet<Integer> rangeSet) {
+    RangeSet<Integer> expected = TreeRangeSet.create();
+    expected.add(Range.<Integer>all());
+    expected.removeAll(rangeSet);
+    return expected;
+  }
+
+  public void testSubRangeSet() {
+    for (Range<Integer> range1 : QUERY_RANGES) {
+      for (Range<Integer> range2 : QUERY_RANGES) {
+        TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+        rangeSet.add(range1);
+        rangeSet.add(range2);
+        for (Range<Integer> subRange : QUERY_RANGES) {
+          testViewAgainstExpected(
+              expectedSubRangeSet(rangeSet, subRange), rangeSet.subRangeSet(subRange));
+        }
+      }
+    }
+  }
+
+  public void testComplement() {
+    for (Range<Integer> range1 : QUERY_RANGES) {
+      for (Range<Integer> range2 : QUERY_RANGES) {
+        TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+        rangeSet.add(range1);
+        rangeSet.add(range2);
+        testViewAgainstExpected(expectedComplement(rangeSet), rangeSet.complement());
+      }
+    }
+  }
+
+  public void testSubRangeSetOfComplement() {
+    for (Range<Integer> range1 : QUERY_RANGES) {
+      for (Range<Integer> range2 : QUERY_RANGES) {
+        TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+        rangeSet.add(range1);
+        rangeSet.add(range2);
+        for (Range<Integer> subRange : QUERY_RANGES) {
+          testViewAgainstExpected(
+              expectedSubRangeSet(expectedComplement(rangeSet), subRange),
+              rangeSet.complement().subRangeSet(subRange));
+        }
+      }
+    }
+  }
+
+  public void testComplementOfSubRangeSet() {
+    for (Range<Integer> range1 : QUERY_RANGES) {
+      for (Range<Integer> range2 : QUERY_RANGES) {
+        TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+        rangeSet.add(range1);
+        rangeSet.add(range2);
+        for (Range<Integer> subRange : QUERY_RANGES) {
+          testViewAgainstExpected(
+              expectedComplement(expectedSubRangeSet(rangeSet, subRange)),
+              rangeSet.subRangeSet(subRange).complement());
+        }
+      }
+    }
+  }
+
+  public void testRangesByUpperBound() {
+    for (Range<Integer> range1 : QUERY_RANGES) {
+      for (Range<Integer> range2 : QUERY_RANGES) {
+        TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+        rangeSet.add(range1);
+        rangeSet.add(range2);
+
+        NavigableMap<Cut<Integer>, Range<Integer>> expectedRangesByUpperBound = Maps.newTreeMap();
+        for (Range<Integer> range : rangeSet.asRanges()) {
+          expectedRangesByUpperBound.put(range.upperBound, range);
+        }
+        testNavigationAgainstExpected(expectedRangesByUpperBound,
+            new TreeRangeSet.RangesByUpperBound<Integer>(rangeSet.rangesByLowerBound),
+            CUTS_TO_TEST);
+      }
+    }
+  }
+
+  public void testMergesConnectedWithOverlap() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(1, 4));
+    rangeSet.add(Range.open(2, 6));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).has().item(Range.closedOpen(1, 6));
+    assertThat(rangeSet.complement().asRanges())
+        .has().exactly(Range.lessThan(1), Range.atLeast(6)).inOrder();
+  }
+
+  public void testMergesConnectedDisjoint() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(1, 4));
+    rangeSet.add(Range.open(4, 6));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).has().item(Range.closedOpen(1, 6));
+    assertThat(rangeSet.complement().asRanges())
+        .has().exactly(Range.lessThan(1), Range.atLeast(6)).inOrder();
+  }
+
+  public void testIgnoresSmallerSharingNoBound() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(1, 6));
+    rangeSet.add(Range.open(2, 4));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).has().item(Range.closed(1, 6));
+    assertThat(rangeSet.complement().asRanges())
+        .has().exactly(Range.lessThan(1), Range.greaterThan(6)).inOrder();
+  }
+
+  public void testIgnoresSmallerSharingLowerBound() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(1, 6));
+    rangeSet.add(Range.closed(1, 4));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).has().item(Range.closed(1, 6));
+    assertThat(rangeSet.complement().asRanges())
+        .has().exactly(Range.lessThan(1), Range.greaterThan(6)).inOrder();
+  }
+
+  public void testIgnoresSmallerSharingUpperBound() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(1, 6));
+    rangeSet.add(Range.closed(3, 6));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).has().item(Range.closed(1, 6));
+    assertThat(rangeSet.complement().asRanges())
+        .has().exactly(Range.lessThan(1), Range.greaterThan(6)).inOrder();
+  }
+
+  public void testIgnoresEqual() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(1, 6));
+    rangeSet.add(Range.closed(1, 6));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).has().item(Range.closed(1, 6));
+    assertThat(rangeSet.complement().asRanges())
+        .has().exactly(Range.lessThan(1), Range.greaterThan(6)).inOrder();
+  }
+
+  public void testExtendSameLowerBound() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(1, 4));
+    rangeSet.add(Range.closed(1, 6));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).has().item(Range.closed(1, 6));
+    assertThat(rangeSet.complement().asRanges())
+        .has().exactly(Range.lessThan(1), Range.greaterThan(6)).inOrder();
+  }
+
+  public void testExtendSameUpperBound() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(3, 6));
+    rangeSet.add(Range.closed(1, 6));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).has().item(Range.closed(1, 6));
+    assertThat(rangeSet.complement().asRanges())
+        .has().exactly(Range.lessThan(1), Range.greaterThan(6)).inOrder();
+  }
+
+  public void testExtendBothDirections() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(3, 4));
+    rangeSet.add(Range.closed(1, 6));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).has().item(Range.closed(1, 6));
+    assertThat(rangeSet.complement().asRanges())
+        .has().exactly(Range.lessThan(1), Range.greaterThan(6)).inOrder();
+  }
+
+  public void testAddEmpty() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closedOpen(3, 3));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).isEmpty();
+    assertThat(rangeSet.complement().asRanges()).has().exactly(Range.<Integer>all()).inOrder();
+  }
+
+  public void testFillHoleExactly() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closedOpen(1, 3));
+    rangeSet.add(Range.closedOpen(4, 6));
+    rangeSet.add(Range.closedOpen(3, 4));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).has().item(Range.closedOpen(1, 6));
+    assertThat(rangeSet.complement().asRanges())
+        .has().exactly(Range.lessThan(1), Range.atLeast(6)).inOrder();
+  }
+
+  public void testFillHoleWithOverlap() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closedOpen(1, 3));
+    rangeSet.add(Range.closedOpen(4, 6));
+    rangeSet.add(Range.closedOpen(2, 5));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).has().item(Range.closedOpen(1, 6));
+    assertThat(rangeSet.complement().asRanges())
+        .has().exactly(Range.lessThan(1), Range.atLeast(6)).inOrder();
+  }
+
+  public void testAddManyPairs() {
+    for (int aLow = 0; aLow < 6; aLow++) {
+      for (int aHigh = 0; aHigh < 6; aHigh++) {
+        for (BoundType aLowType : BoundType.values()) {
+          for (BoundType aHighType : BoundType.values()) {
+            if ((aLow == aHigh && aLowType == OPEN && aHighType == OPEN) || aLow > aHigh) {
+              continue;
+            }
+            for (int bLow = 0; bLow < 6; bLow++) {
+              for (int bHigh = 0; bHigh < 6; bHigh++) {
+                for (BoundType bLowType : BoundType.values()) {
+                  for (BoundType bHighType : BoundType.values()) {
+                    if ((bLow == bHigh && bLowType == OPEN && bHighType == OPEN) || bLow > bHigh) {
+                      continue;
+                    }
+                    doPairTest(range(aLow, aLowType, aHigh, aHighType),
+                        range(bLow, bLowType, bHigh, bHighType));
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  private static void doPairTest(Range<Integer> a, Range<Integer> b) {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(a);
+    rangeSet.add(b);
+    if (a.isEmpty() && b.isEmpty()) {
+      assertThat(rangeSet.asRanges()).isEmpty();
+    } else if (a.isEmpty()) {
+      assertThat(rangeSet.asRanges()).has().item(b);
+    } else if (b.isEmpty()) {
+      assertThat(rangeSet.asRanges()).has().item(a);
+    } else if (a.isConnected(b)) {
+      assertThat(rangeSet.asRanges()).has().exactly(a.span(b)).inOrder();
+    } else {
+      if (a.lowerEndpoint() < b.lowerEndpoint()) {
+        assertThat(rangeSet.asRanges()).has().exactly(a, b).inOrder();
+      } else {
+        assertThat(rangeSet.asRanges()).has().exactly(b, a).inOrder();
+      }
+    }
+  }
+
+  public void testRemoveEmpty() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(1, 6));
+    rangeSet.remove(Range.closedOpen(3, 3));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).has().item(Range.closed(1, 6));
+    assertThat(rangeSet.complement().asRanges())
+        .has().exactly(Range.lessThan(1), Range.greaterThan(6)).inOrder();
+  }
+
+  public void testRemovePartSharingLowerBound() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(3, 5));
+    rangeSet.remove(Range.closedOpen(3, 5));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).has().item(Range.singleton(5));
+    assertThat(rangeSet.complement().asRanges())
+        .has().exactly(Range.lessThan(5), Range.greaterThan(5)).inOrder();
+  }
+
+  public void testRemovePartSharingUpperBound() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(3, 5));
+    rangeSet.remove(Range.openClosed(3, 5));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).has().item(Range.singleton(3));
+    assertThat(rangeSet.complement().asRanges())
+        .has().exactly(Range.lessThan(3), Range.greaterThan(3)).inOrder();
+  }
+
+  public void testRemoveMiddle() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.atMost(6));
+    rangeSet.remove(Range.closedOpen(3, 4));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).has().exactly(Range.lessThan(3), Range.closed(4, 6)).inOrder();
+    assertThat(rangeSet.complement().asRanges())
+        .has().exactly(Range.closedOpen(3, 4), Range.greaterThan(6)).inOrder();
+  }
+
+  public void testRemoveNoOverlap() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(3, 6));
+    rangeSet.remove(Range.closedOpen(1, 3));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).has().exactly(Range.closed(3, 6)).inOrder();
+  }
+
+  public void testRemovePartFromBelowLowerBound() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(3, 6));
+    rangeSet.remove(Range.closed(1, 3));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).has().exactly(Range.openClosed(3, 6)).inOrder();
+  }
+
+  public void testRemovePartFromAboveUpperBound() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(3, 6));
+    rangeSet.remove(Range.closed(6, 9));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).has().exactly(Range.closedOpen(3, 6)).inOrder();
+  }
+
+  public void testRemoveExact() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(3, 6));
+    rangeSet.remove(Range.closed(3, 6));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).isEmpty();
+  }
+
+  public void testRemoveAllFromBelowLowerBound() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(3, 6));
+    rangeSet.remove(Range.closed(2, 6));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).isEmpty();
+  }
+
+  public void testRemoveAllFromAboveUpperBound() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(3, 6));
+    rangeSet.remove(Range.closed(3, 7));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).isEmpty();
+  }
+
+  public void testRemoveAllExtendingBothDirections() {
+    TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(3, 6));
+    rangeSet.remove(Range.closed(2, 7));
+    testInvariants(rangeSet);
+    assertThat(rangeSet.asRanges()).isEmpty();
+  }
+
+  public void testRangeContaining1() {
+    RangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(3, 10));
+    assertEquals(Range.closed(3, 10), rangeSet.rangeContaining(5));
+    assertTrue(rangeSet.contains(5));
+    assertNull(rangeSet.rangeContaining(1));
+    assertFalse(rangeSet.contains(1));
+  }
+
+  public void testRangeContaining2() {
+    RangeSet<Integer> rangeSet = TreeRangeSet.create();
+    rangeSet.add(Range.closed(3, 10));
+    rangeSet.remove(Range.open(5, 7));
+    assertEquals(Range.closed(3, 5), rangeSet.rangeContaining(5));
+    assertTrue(rangeSet.contains(5));
+    assertEquals(Range.closed(7, 10), rangeSet.rangeContaining(8));
+    assertTrue(rangeSet.contains(8));
+    assertNull(rangeSet.rangeContaining(6));
+    assertFalse(rangeSet.contains(6));
+  }
+}
diff --git a/guava-tests/test/com/google/common/collect/TreeTraverserTest.java b/guava-tests/test/com/google/common/collect/TreeTraverserTest.java
index 37c9859..b5438e1 100644
--- a/guava-tests/test/com/google/common/collect/TreeTraverserTest.java
+++ b/guava-tests/test/com/google/common/collect/TreeTraverserTest.java
@@ -14,7 +14,7 @@
 
 package com.google.common.collect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -128,22 +128,22 @@
   }
 
   public void testPreOrder() {
-    ASSERT.that(iterationOrder(ADAPTER.preOrderTraversal(h))).is("hdabcegf");
-    ASSERT.that(binaryIterationOrder(BIN_ADAPTER.preOrderTraversal(bd))).is("dbacefg");
+    assertThat(iterationOrder(ADAPTER.preOrderTraversal(h))).isEqualTo("hdabcegf");
+    assertThat(binaryIterationOrder(BIN_ADAPTER.preOrderTraversal(bd))).isEqualTo("dbacefg");
   }
 
   public void testPostOrder() {
-    ASSERT.that(iterationOrder(ADAPTER.postOrderTraversal(h))).is("abcdefgh");
-    ASSERT.that(binaryIterationOrder(BIN_ADAPTER.postOrderTraversal(bd))).is("acbgfed");
+    assertThat(iterationOrder(ADAPTER.postOrderTraversal(h))).isEqualTo("abcdefgh");
+    assertThat(binaryIterationOrder(BIN_ADAPTER.postOrderTraversal(bd))).isEqualTo("acbgfed");
   }
 
   public void testBreadthOrder() {
-    ASSERT.that(iterationOrder(ADAPTER.breadthFirstTraversal(h))).is("hdegabcf");
-    ASSERT.that(binaryIterationOrder(BIN_ADAPTER.breadthFirstTraversal(bd))).is("dbeacfg");
+    assertThat(iterationOrder(ADAPTER.breadthFirstTraversal(h))).isEqualTo("hdegabcf");
+    assertThat(binaryIterationOrder(BIN_ADAPTER.breadthFirstTraversal(bd))).isEqualTo("dbeacfg");
   }
 
   public void testInOrder() {
-    ASSERT.that(binaryIterationOrder(BIN_ADAPTER.inOrderTraversal(bd))).is("abcdegf");
+    assertThat(binaryIterationOrder(BIN_ADAPTER.inOrderTraversal(bd))).isEqualTo("abcdegf");
   }
 
   @GwtIncompatible("NullPointerTester")
diff --git a/guava-tests/test/com/google/common/eventbus/EventBusTest.java b/guava-tests/test/com/google/common/eventbus/EventBusTest.java
index 30fa0da..35cb2f1 100644
--- a/guava-tests/test/com/google/common/eventbus/EventBusTest.java
+++ b/guava-tests/test/com/google/common/eventbus/EventBusTest.java
@@ -27,6 +27,7 @@
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Test case for {@link EventBus}.
@@ -285,13 +286,35 @@
     }
   }
 
+  /**
+   * Tests that bridge methods are not subscribed to events. In Java 8,
+   * annotations are included on the bridge method in addition to the original
+   * method, which causes both the original and bridge methods to be subscribed
+   * (since both are annotated @Subscribe) without specifically checking for
+   * bridge methods.
+   */
+  public void testRegistrationWithBridgeMethod() {
+    final AtomicInteger calls = new AtomicInteger();
+    bus.register(new Callback<String>() {
+      @Subscribe
+      @Override
+      public void call(String s) {
+        calls.incrementAndGet();
+      }
+    });
+
+    bus.post("hello");
+
+    assertEquals(1, calls.get());
+  }
+
   private <T> void assertContains(T element, Collection<T> collection) {
     assertTrue("Collection must contain " + element,
         collection.contains(element));
   }
 
   /**
-   * Records a thrown exception information.
+   * Records thrown exception information.
    */
   private static final class RecordingSubscriberExceptionHandler
       implements SubscriberExceptionHandler {
@@ -304,7 +327,6 @@
         SubscriberExceptionContext context) {
       this.exception = exception;
       this.context = context;
-
     }
   }
 
@@ -348,22 +370,25 @@
     }
   }
 
-  public interface HierarchyFixtureInterface {
+  private interface HierarchyFixtureInterface {
     // Exists only for hierarchy mapping; no members.
   }
 
-  public interface HierarchyFixtureSubinterface
+  private interface HierarchyFixtureSubinterface
       extends HierarchyFixtureInterface {
     // Exists only for hierarchy mapping; no members.
   }
 
-  public static class HierarchyFixtureParent
+  private static class HierarchyFixtureParent
       implements HierarchyFixtureSubinterface {
     // Exists only for hierarchy mapping; no members.
   }
 
-  public static class HierarchyFixture extends HierarchyFixtureParent {
+  private static class HierarchyFixture extends HierarchyFixtureParent {
     // Exists only for hierarchy mapping; no members.
   }
 
+  private interface Callback<T> {
+    void call(T t);
+  }
 }
diff --git a/guava-tests/test/com/google/common/eventbus/outside/AnnotatedSubscriberFinderTests.java b/guava-tests/test/com/google/common/eventbus/outside/AnnotatedSubscriberFinderTests.java
index 922b956..b22eefd 100644
--- a/guava-tests/test/com/google/common/eventbus/outside/AnnotatedSubscriberFinderTests.java
+++ b/guava-tests/test/com/google/common/eventbus/outside/AnnotatedSubscriberFinderTests.java
@@ -16,7 +16,7 @@
 
 package com.google.common.eventbus.outside;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.collect.Lists;
 import com.google.common.eventbus.EventBus;
@@ -79,11 +79,11 @@
     }
 
     public void testNonSubscriber() {
-      ASSERT.that(getSubscriber().nonSubscriberEvents).isEmpty();
+      assertThat(getSubscriber().nonSubscriberEvents).isEmpty();
     }
 
     public void testSubscriber() {
-      ASSERT.that(getSubscriber().subscriberEvents).has().item(EVENT);
+      assertThat(getSubscriber().subscriberEvents).has().item(EVENT);
     }
 
     @Override
@@ -119,11 +119,11 @@
     }
 
     public void testOverriddenAndAnnotatedInSubclass() {
-      ASSERT.that(getSubscriber().overriddenAndAnnotatedInSubclassEvents).has().item(EVENT);
+      assertThat(getSubscriber().overriddenAndAnnotatedInSubclassEvents).has().item(EVENT);
     }
 
     public void testOverriddenNotAnnotatedInSubclass() {
-      ASSERT.that(getSubscriber().overriddenInSubclassEvents).has().item(EVENT);
+      assertThat(getSubscriber().overriddenInSubclassEvents).has().item(EVENT);
     }
 
     @Override
@@ -199,29 +199,27 @@
     }
 
     public void testNotOverriddenInSubclass() {
-      ASSERT.that(getSubscriber().notOverriddenInSubclassEvents).has().item(EVENT);
+      assertThat(getSubscriber().notOverriddenInSubclassEvents).has().item(EVENT);
     }
 
     public void testOverriddenNotAnnotatedInSubclass() {
-      ASSERT.that(getSubscriber().overriddenNotAnnotatedInSubclassEvents).has().item(EVENT);
+      assertThat(getSubscriber().overriddenNotAnnotatedInSubclassEvents).has().item(EVENT);
     }
 
     public void testDifferentlyOverriddenNotAnnotatedInSubclass() {
-      ASSERT
-          .that(getSubscriber().differentlyOverriddenNotAnnotatedInSubclassGoodEvents)
+      assertThat(getSubscriber().differentlyOverriddenNotAnnotatedInSubclassGoodEvents)
           .has().item(EVENT);
-      ASSERT.that(getSubscriber().differentlyOverriddenNotAnnotatedInSubclassBadEvents).isEmpty();
+      assertThat(getSubscriber().differentlyOverriddenNotAnnotatedInSubclassBadEvents).isEmpty();
     }
 
     public void testOverriddenAndAnnotatedInSubclass() {
-      ASSERT.that(getSubscriber().overriddenAndAnnotatedInSubclassEvents).has().item(EVENT);
+      assertThat(getSubscriber().overriddenAndAnnotatedInSubclassEvents).has().item(EVENT);
     }
 
     public void testDifferentlyOverriddenAndAnnotatedInSubclass() {
-      ASSERT
-          .that(getSubscriber().differentlyOverriddenAnnotatedInSubclassGoodEvents)
+      assertThat(getSubscriber().differentlyOverriddenAnnotatedInSubclassGoodEvents)
           .has().item(EVENT);
-      ASSERT.that(getSubscriber().differentlyOverriddenAnnotatedInSubclassBadEvents).isEmpty();
+      assertThat(getSubscriber().differentlyOverriddenAnnotatedInSubclassBadEvents).isEmpty();
     }
 
     @Override
@@ -255,11 +253,11 @@
     }
 
     public void testOverriddenAndAnnotatedInSubclass() {
-      ASSERT.that(getSubscriber().overriddenAndAnnotatedInSubclassEvents).has().item(EVENT);
+      assertThat(getSubscriber().overriddenAndAnnotatedInSubclassEvents).has().item(EVENT);
     }
 
     public void testOverriddenInSubclassNowhereAnnotated() {
-      ASSERT.that(getSubscriber().overriddenInSubclassNowhereAnnotatedEvents).isEmpty();
+      assertThat(getSubscriber().overriddenInSubclassNowhereAnnotatedEvents).isEmpty();
     }
 
     @Override
@@ -302,15 +300,15 @@
     }
 
     public void testNeitherOverriddenNorAnnotated() {
-      ASSERT.that(getSubscriber().neitherOverriddenNorAnnotatedEvents).isEmpty();
+      assertThat(getSubscriber().neitherOverriddenNorAnnotatedEvents).isEmpty();
     }
 
     public void testOverriddenInSubclassNowhereAnnotated() {
-      ASSERT.that(getSubscriber().overriddenInSubclassNowhereAnnotatedEvents).isEmpty();
+      assertThat(getSubscriber().overriddenInSubclassNowhereAnnotatedEvents).isEmpty();
     }
 
     public void testOverriddenAndAnnotatedInSubclass() {
-      ASSERT.that(getSubscriber().overriddenAndAnnotatedInSubclassEvents).has().item(EVENT);
+      assertThat(getSubscriber().overriddenAndAnnotatedInSubclassEvents).has().item(EVENT);
     }
 
     @Override
@@ -412,35 +410,35 @@
     }
 
     public void testAnnotatedIn1() {
-      ASSERT.that(getSubscriber().annotatedIn1Events).has().item(EVENT);
+      assertThat(getSubscriber().annotatedIn1Events).has().item(EVENT);
     }
 
     public void testAnnotatedIn2() {
-      ASSERT.that(getSubscriber().annotatedIn2Events).has().item(EVENT);
+      assertThat(getSubscriber().annotatedIn2Events).has().item(EVENT);
     }
 
     public void testAnnotatedIn1And2() {
-      ASSERT.that(getSubscriber().annotatedIn1And2Events).has().item(EVENT);
+      assertThat(getSubscriber().annotatedIn1And2Events).has().item(EVENT);
     }
 
     public void testAnnotatedIn1And2AndClass() {
-      ASSERT.that(getSubscriber().annotatedIn1And2AndClassEvents).has().item(EVENT);
+      assertThat(getSubscriber().annotatedIn1And2AndClassEvents).has().item(EVENT);
     }
 
     public void testDeclaredIn1AnnotatedIn2() {
-      ASSERT.that(getSubscriber().declaredIn1AnnotatedIn2Events).has().item(EVENT);
+      assertThat(getSubscriber().declaredIn1AnnotatedIn2Events).has().item(EVENT);
     }
 
     public void testDeclaredIn1AnnotatedInClass() {
-      ASSERT.that(getSubscriber().declaredIn1AnnotatedInClassEvents).has().item(EVENT);
+      assertThat(getSubscriber().declaredIn1AnnotatedInClassEvents).has().item(EVENT);
     }
 
     public void testDeclaredIn2AnnotatedInClass() {
-      ASSERT.that(getSubscriber().declaredIn2AnnotatedInClassEvents).has().item(EVENT);
+      assertThat(getSubscriber().declaredIn2AnnotatedInClassEvents).has().item(EVENT);
     }
 
     public void testNowhereAnnotated() {
-      ASSERT.that(getSubscriber().nowhereAnnotatedEvents).isEmpty();
+      assertThat(getSubscriber().nowhereAnnotatedEvents).isEmpty();
     }
 
     @Override
diff --git a/guava-tests/test/com/google/common/hash/AbstractByteHasherTest.java b/guava-tests/test/com/google/common/hash/AbstractByteHasherTest.java
index ee47a1b..c7626c2 100644
--- a/guava-tests/test/com/google/common/hash/AbstractByteHasherTest.java
+++ b/guava-tests/test/com/google/common/hash/AbstractByteHasherTest.java
@@ -20,7 +20,6 @@
 import junit.framework.TestCase;
 
 import java.io.ByteArrayOutputStream;
-import java.io.UnsupportedEncodingException;
 import java.util.Random;
 
 /**
@@ -65,17 +64,17 @@
     hasher.assertBytes(new byte[]{1, 2});
   }
 
-  public void testString() throws UnsupportedEncodingException {
+  public void testString() {
     Random random = new Random();
     for (int i = 0; i < 100; i++) {
       byte[] bytes = new byte[64];
       random.nextBytes(bytes);
-      String s = new String(bytes, UTF_16LE.name()); // so all random strings are valid
+      String s = new String(bytes, UTF_16LE); // so all random strings are valid
       assertEquals(
-          new TestHasher().putString(s).hash(),
-          new TestHasher().putBytes(s.getBytes(UTF_16LE.name())).hash());
+          new TestHasher().putUnencodedChars(s).hash(),
+          new TestHasher().putBytes(s.getBytes(UTF_16LE)).hash());
       assertEquals(
-          new TestHasher().putString(s).hash(),
+          new TestHasher().putUnencodedChars(s).hash(),
           new TestHasher().putString(s, UTF_16LE).hash());
     }
   }
diff --git a/guava-tests/test/com/google/common/hash/AbstractNonStreamingHashFunctionTest.java b/guava-tests/test/com/google/common/hash/AbstractNonStreamingHashFunctionTest.java
index e8a262e..0c8ddf3 100644
--- a/guava-tests/test/com/google/common/hash/AbstractNonStreamingHashFunctionTest.java
+++ b/guava-tests/test/com/google/common/hash/AbstractNonStreamingHashFunctionTest.java
@@ -18,15 +18,13 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.hash.HashTestUtils.RandomHasherAction;
-import com.google.common.jdk5backport.Arrays;
-
-import junit.framework.TestCase;
 
 import junit.framework.TestCase;
 
 import java.io.ByteArrayOutputStream;
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Random;
 
@@ -142,11 +140,6 @@
     }
 
     @Override
-    public HashCode hashString(CharSequence input) {
-      throw new UnsupportedOperationException();
-    }
-
-    @Override
     public HashCode hashString(CharSequence input, Charset charset) {
       throw new UnsupportedOperationException();
     }
diff --git a/guava-tests/test/com/google/common/hash/AbstractStreamingHasherTest.java b/guava-tests/test/com/google/common/hash/AbstractStreamingHasherTest.java
index d4f2d2e..901fcc0 100644
--- a/guava-tests/test/com/google/common/hash/AbstractStreamingHasherTest.java
+++ b/guava-tests/test/com/google/common/hash/AbstractStreamingHasherTest.java
@@ -22,15 +22,14 @@
 import com.google.common.collect.Lists;
 import com.google.common.hash.AbstractStreamingHashFunction.AbstractStreamingHasher;
 import com.google.common.hash.HashTestUtils.RandomHasherAction;
-import com.google.common.jdk5backport.Arrays;
 
 import junit.framework.TestCase;
 
 import java.io.ByteArrayOutputStream;
-import java.io.UnsupportedEncodingException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.charset.Charset;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Random;
@@ -86,17 +85,17 @@
     sink.assertBytes(new byte[] { 1, 2, 0, 0  }); // padded with zeros
   }
 
-  public void testString() throws UnsupportedEncodingException {
+  public void testString() {
     Random random = new Random();
     for (int i = 0; i < 100; i++) {
       byte[] bytes = new byte[64];
       random.nextBytes(bytes);
-      String s = new String(bytes, UTF_16LE.name()); // so all random strings are valid
+      String s = new String(bytes, UTF_16LE); // so all random strings are valid
       assertEquals(
-          new Sink(4).putString(s).hash(),
-          new Sink(4).putBytes(s.getBytes(UTF_16LE.name())).hash());
+          new Sink(4).putUnencodedChars(s).hash(),
+          new Sink(4).putBytes(s.getBytes(UTF_16LE)).hash());
       assertEquals(
-          new Sink(4).putString(s).hash(),
+          new Sink(4).putUnencodedChars(s).hash(),
           new Sink(4).putString(s, UTF_16LE).hash());
     }
   }
@@ -265,11 +264,6 @@
     }
 
     @Override
-    public HashCode hashString(CharSequence input) {
-      throw new UnsupportedOperationException();
-    }
-
-    @Override
     public HashCode hashString(CharSequence input, Charset charset) {
       throw new UnsupportedOperationException();
     }
diff --git a/guava-tests/test/com/google/common/hash/BloomFilterTest.java b/guava-tests/test/com/google/common/hash/BloomFilterTest.java
index be8c614..4f54d10 100644
--- a/guava-tests/test/com/google/common/hash/BloomFilterTest.java
+++ b/guava-tests/test/com/google/common/hash/BloomFilterTest.java
@@ -16,6 +16,7 @@
 
 package com.google.common.hash;
 
+import static com.google.common.base.Charsets.UTF_8;
 import static com.google.common.hash.BloomFilterStrategies.BitArray;
 
 import com.google.common.collect.ImmutableSet;
@@ -27,6 +28,8 @@
 
 import junit.framework.TestCase;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.math.RoundingMode;
 import java.util.Random;
 
@@ -53,7 +56,7 @@
 
   public void testCreateAndCheckMitz32BloomFilterWithKnownFalsePositives() {
     int numInsertions = 1000000;
-    BloomFilter<CharSequence> bf = BloomFilter.create(
+    BloomFilter<String> bf = BloomFilter.create(
         Funnels.unencodedCharsFunnel(), numInsertions, 0.03,
         BloomFilterStrategies.MURMUR128_MITZ_32);
 
@@ -94,7 +97,7 @@
 
   public void testCreateAndCheckBloomFilterWithKnownFalsePositives64() {
     int numInsertions = 1000000;
-    BloomFilter<CharSequence> bf = BloomFilter.create(
+    BloomFilter<String> bf = BloomFilter.create(
         Funnels.unencodedCharsFunnel(), numInsertions, 0.03,
         BloomFilterStrategies.MURMUR128_MITZ_64);
 
@@ -133,6 +136,47 @@
     assertEquals(actualFpp, expectedFpp, 0.00033);
   }
 
+  public void testCreateAndCheckBloomFilterWithKnownUtf8FalsePositives64() {
+    int numInsertions = 1000000;
+    BloomFilter<String> bf = BloomFilter.create(
+        Funnels.stringFunnel(UTF_8), numInsertions, 0.03,
+        BloomFilterStrategies.MURMUR128_MITZ_64);
+
+    // Insert "numInsertions" even numbers into the BF.
+    for (int i = 0; i < numInsertions * 2; i += 2) {
+      bf.put(Integer.toString(i));
+    }
+
+    // Assert that the BF "might" have all of the even numbers.
+    for (int i = 0; i < numInsertions * 2; i += 2) {
+      assertTrue(bf.mightContain(Integer.toString(i)));
+    }
+
+    // Now we check for known false positives using a set of known false positives.
+    // (These are all of the false positives under 900.)
+    ImmutableSet<Integer> falsePositives =
+        ImmutableSet.of(129, 471, 723, 89, 751, 835, 871);
+    for (int i = 1; i < 900; i += 2) {
+      if (!falsePositives.contains(i)) {
+        assertFalse("BF should not contain " + i, bf.mightContain(Integer.toString(i)));
+      }
+    }
+
+    // Check that there are exactly 29763 false positives for this BF.
+    int knownNumberOfFalsePositives = 29763;
+    int numFpp = 0;
+    for (int i = 1; i < numInsertions * 2; i += 2) {
+      if (bf.mightContain(Integer.toString(i))) {
+        numFpp++;
+      }
+    }
+    assertEquals(knownNumberOfFalsePositives, numFpp);
+    double actualFpp = (double) knownNumberOfFalsePositives / numInsertions;
+    double expectedFpp = bf.expectedFpp();
+    // The normal order of (expected, actual) is reversed here on purpose.
+    assertEquals(actualFpp, expectedFpp, 0.00033);
+  }
+
   /**
    * Sanity checking with many combinations of false positive rates and expected insertions
    */
@@ -189,6 +233,11 @@
     }
   }
 
+  // https://code.google.com/p/guava-libraries/issues/detail?id=1781
+  public void testOptimalNumOfHashFunctionsRounding() {
+    assertEquals(7, BloomFilter.optimalNumOfHashFunctions(319, 3072));
+  }
+
   /**
    * Tests that we always get a non-negative optimal size.
    */
@@ -228,8 +277,8 @@
   }
 
   public void testCopy() {
-    BloomFilter<CharSequence> original = BloomFilter.create(Funnels.unencodedCharsFunnel(), 100);
-    BloomFilter<CharSequence> copy = original.copy();
+    BloomFilter<String> original = BloomFilter.create(Funnels.unencodedCharsFunnel(), 100);
+    BloomFilter<String> copy = original.copy();
     assertNotSame(original, copy);
     assertEquals(original, copy);
   }
@@ -273,11 +322,11 @@
   }
 
   public void testEquals() {
-    BloomFilter<CharSequence> bf1 = BloomFilter.create(Funnels.unencodedCharsFunnel(), 100);
+    BloomFilter<String> bf1 = BloomFilter.create(Funnels.unencodedCharsFunnel(), 100);
     bf1.put("1");
     bf1.put("2");
 
-    BloomFilter<CharSequence> bf2 = BloomFilter.create(Funnels.unencodedCharsFunnel(), 100);
+    BloomFilter<String> bf2 = BloomFilter.create(Funnels.unencodedCharsFunnel(), 100);
     bf2.put("1");
     bf2.put("2");
 
@@ -320,7 +369,7 @@
 
   public void testPutReturnValue() {
     for (int i = 0; i < 10; i++) {
-      BloomFilter<CharSequence> bf = BloomFilter.create(Funnels.unencodedCharsFunnel(), 100);
+      BloomFilter<String> bf = BloomFilter.create(Funnels.unencodedCharsFunnel(), 100);
       for (int j = 0; j < 10; j++) {
         String value = new Object().toString();
         boolean mightContain = bf.mightContain(value);
@@ -396,6 +445,19 @@
     SerializableTester.reserializeAndAssert(bf);
   }
 
+  public void testCustomSerialization() throws Exception {
+    Funnel<byte[]> funnel = Funnels.byteArrayFunnel();
+    BloomFilter<byte[]> bf = BloomFilter.create(funnel, 100);
+    for (int i = 0; i < 100; i++) {
+      bf.put(Ints.toByteArray(i));
+    }
+
+    ByteArrayOutputStream out = new ByteArrayOutputStream();
+    bf.writeTo(out);
+
+    assertEquals(bf, BloomFilter.readFrom(new ByteArrayInputStream(out.toByteArray()), funnel));
+  }
+
   /**
    * This test will fail whenever someone updates/reorders the BloomFilterStrategies constants.
    * Only appending a new constant is allowed.
@@ -405,23 +467,4 @@
     assertEquals(BloomFilterStrategies.MURMUR128_MITZ_32, BloomFilterStrategies.values()[0]);
     assertEquals(BloomFilterStrategies.MURMUR128_MITZ_64, BloomFilterStrategies.values()[1]);
   }
-
-  public void testGetDefaultStrategyFromSystemProperty() {
-    // clear the property to test the case when the property is not set (the default)
-    System.clearProperty(BloomFilter.USE_MITZ32_PROPERTY);
-    assertEquals(BloomFilterStrategies.MURMUR128_MITZ_64,
-        BloomFilter.getDefaultStrategyFromSystemProperty());
-
-    System.setProperty(BloomFilter.USE_MITZ32_PROPERTY, "true");
-    assertEquals(BloomFilterStrategies.MURMUR128_MITZ_32,
-        BloomFilter.getDefaultStrategyFromSystemProperty());
-
-    System.setProperty(BloomFilter.USE_MITZ32_PROPERTY, "TRUE");
-    assertEquals(BloomFilterStrategies.MURMUR128_MITZ_32,
-        BloomFilter.getDefaultStrategyFromSystemProperty());
-
-    System.setProperty(BloomFilter.USE_MITZ32_PROPERTY, "false");
-    assertEquals(BloomFilterStrategies.MURMUR128_MITZ_64,
-        BloomFilter.getDefaultStrategyFromSystemProperty());
-  }
 }
diff --git a/guava-tests/test/com/google/common/hash/Crc32cHashFunctionTest.java b/guava-tests/test/com/google/common/hash/Crc32cHashFunctionTest.java
new file mode 100644
index 0000000..b36f723
--- /dev/null
+++ b/guava-tests/test/com/google/common/hash/Crc32cHashFunctionTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.common.hash;
+
+import static com.google.common.base.Charsets.UTF_8;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+
+/**
+ * Unit tests for {@link Crc32c}. Known test values are from RFC 3720, Section B.4.
+ *
+ * @author Patrick Costello
+ * @author Kurt Alfred Kluever
+ */
+public class Crc32cHashFunctionTest extends TestCase {
+
+  public void testZeros() {
+    // Test 32 byte array of 0x00.
+    byte[] zeros = new byte[32];
+    Arrays.fill(zeros, (byte) 0x00);
+    assertCrc(0x8a9136aa, zeros);
+  }
+
+  public void testFull() {
+    // Test 32 byte array of 0xFF.
+    byte[] fulls = new byte[32];
+    Arrays.fill(fulls, (byte) 0xFF);
+    assertCrc(0x62a8ab43, fulls);
+  }
+
+  public void testAscending() {
+    // Test 32 byte arrays of ascending.
+    byte[] ascending = new byte[32];
+    for (int i = 0; i < 32; i++) {
+      ascending[i] = (byte) i;
+    }
+    assertCrc(0x46dd794e, ascending);
+  }
+
+  public void testDescending() {
+    // Test 32 byte arrays of descending.
+    byte[] descending = new byte[32];
+    for (int i = 0; i < 32; i++) {
+      descending[i] = (byte) (31 - i);
+    }
+    assertCrc(0x113fdb5c, descending);
+  }
+
+  public void testScsiReadCommad() {
+    // Test SCSI read command.
+    byte[] scsiReadCommand = new byte[] {
+        0x01, (byte) 0xc0, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+        0x14, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x04, 0x00,
+        0x00, 0x00, 0x00, 0x14,
+        0x00, 0x00, 0x00, 0x18,
+        0x28, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+        0x02, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00 };
+    assertCrc(0xd9963a56, scsiReadCommand);
+  }
+
+  // Known values from http://www.evanjones.ca/crc32c.html
+  public void testSomeOtherKnownValues() {
+    assertCrc(0x22620404, "The quick brown fox jumps over the lazy dog".getBytes(UTF_8));
+    assertCrc(0xE3069283, "123456789".getBytes(UTF_8));
+    assertCrc(0xf3dbd4fe, "1234567890".getBytes(UTF_8));
+    assertCrc(0xBFE92A83, "23456789".getBytes(UTF_8));
+  }
+
+  /**
+   * Verfies that the crc of an array of byte data matches the expected value.
+   *
+   * @param expectedCrc the expected crc value.
+   * @param data the data to run the checksum on.
+   */
+  private static void assertCrc(int expectedCrc, byte[] data) {
+    int actualCrc = Hashing.crc32c().hashBytes(data).asInt();
+    assertEquals(expectedCrc, actualCrc);
+  }
+
+  // From RFC 3720, Section 12.1, the polynomial generator is 0x11EDC6F41.
+  // We calculate the constant below by:
+  //   1. Omitting the most significant bit (because it's always 1). => 0x1EDC6F41
+  //   2. Flipping the bits of the constant so we can process a byte at a time. => 0x82F63B78
+  private static final int CRC32C_GENERATOR = 0x1EDC6F41;  // 0x11EDC6F41
+  private static final int CRC32C_GENERATOR_FLIPPED = Integer.reverse(CRC32C_GENERATOR);
+
+  public void testCrc32cLookupTable() {
+    // See Hacker's Delight 2nd Edition, Figure 14-7.
+    int[] expected = new int[256];
+    for (int i = 0; i < expected.length; i++) {
+      int crc = i;
+      for (int j = 7; j >= 0; j--) {
+        int mask = -(crc & 1);
+        crc = ((crc >>> 1) ^ (CRC32C_GENERATOR_FLIPPED & mask));
+      }
+      expected[i] = crc;
+    }
+
+    int[] actual = Crc32cHashFunction.Crc32cHasher.CRC_TABLE;
+    assertTrue(
+        "Expected: \n" + Arrays.toString(expected) + "\nActual:\n" + Arrays.toString(actual),
+        Arrays.equals(expected, actual));
+  }
+}
diff --git a/guava-tests/test/com/google/common/hash/HashCodeTest.java b/guava-tests/test/com/google/common/hash/HashCodeTest.java
index 121d983..a15a57b 100644
--- a/guava-tests/test/com/google/common/hash/HashCodeTest.java
+++ b/guava-tests/test/com/google/common/hash/HashCodeTest.java
@@ -18,13 +18,15 @@
 
 import static com.google.common.io.BaseEncoding.base16;
 
+import com.google.common.base.Charsets;
 import com.google.common.collect.ImmutableList;
 import com.google.common.io.BaseEncoding;
-import com.google.common.jdk5backport.Arrays;
 import com.google.common.testing.ClassSanityTester;
 
 import junit.framework.TestCase;
 
+import java.util.Arrays;
+
 /**
  * Unit tests for {@link HashCode}.
  *
@@ -168,7 +170,7 @@
   }
 
   public void testRoundTripHashCodeUsingBaseEncoding() {
-    HashCode hash1 = Hashing.sha1().hashString("foo");
+    HashCode hash1 = Hashing.sha1().hashString("foo", Charsets.US_ASCII);
     HashCode hash2 =
         HashCode.fromBytes(BaseEncoding.base16().lowerCase().decode(hash1.toString()));
     assertEquals(hash1, hash2);
@@ -201,18 +203,18 @@
   }
 
   public void testRoundTripHashCodeUsingFromString() {
-    HashCode hash1 = Hashing.sha1().hashString("foo");
+    HashCode hash1 = Hashing.sha1().hashString("foo", Charsets.US_ASCII);
     HashCode hash2 = HashCode.fromString(hash1.toString());
     assertEquals(hash1, hash2);
   }
 
   public void testRoundTrip() {
     for (ExpectedHashCode expected : expectedHashCodes) {
-      String string = HashCodes.fromBytes(expected.bytes).toString();
+      String string = HashCode.fromBytes(expected.bytes).toString();
       assertEquals(expected.toString, string);
       assertEquals(
           expected.toString,
-          HashCodes.fromBytes(
+          HashCode.fromBytes(
               BaseEncoding.base16().lowerCase().decode(string)).toString());
     }
   }
@@ -226,7 +228,7 @@
   }
 
   public void testFromStringFailsWithUpperCaseString() {
-    String string = Hashing.sha1().hashString("foo").toString().toUpperCase();
+    String string = Hashing.sha1().hashString("foo", Charsets.US_ASCII).toString().toUpperCase();
     try {
       HashCode.fromString(string);
       fail();
@@ -258,17 +260,17 @@
 
   public void testIntWriteBytesTo() {
     byte[] dest = new byte[4];
-    HashCodes.fromInt(42).writeBytesTo(dest, 0, 4);
+    HashCode.fromInt(42).writeBytesTo(dest, 0, 4);
     assertTrue(Arrays.equals(
-        HashCodes.fromInt(42).asBytes(),
+        HashCode.fromInt(42).asBytes(),
         dest));
   }
 
   public void testLongWriteBytesTo() {
     byte[] dest = new byte[8];
-    HashCodes.fromLong(42).writeBytesTo(dest, 0, 8);
+    HashCode.fromLong(42).writeBytesTo(dest, 0, 8);
     assertTrue(Arrays.equals(
-        HashCodes.fromLong(42).asBytes(),
+        HashCode.fromLong(42).asBytes(),
         dest));
   }
 
diff --git a/guava-tests/test/com/google/common/hash/HashTestUtils.java b/guava-tests/test/com/google/common/hash/HashTestUtils.java
index 5427513..886ad91 100644
--- a/guava-tests/test/com/google/common/hash/HashTestUtils.java
+++ b/guava-tests/test/com/google/common/hash/HashTestUtils.java
@@ -21,13 +21,13 @@
 import com.google.common.base.Charsets;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
-import com.google.common.jdk5backport.Arrays;
 import com.google.common.primitives.Ints;
 import com.google.common.testing.EqualsTester;
 
 import org.junit.Assert;
 
 import java.nio.charset.Charset;
+import java.util.Arrays;
 import java.util.Random;
 import java.util.Set;
 
@@ -227,7 +227,7 @@
       return actions[random.nextInt(actions.length)];
     }
   }
-
+  
   /**
    * Test that the hash function contains no funnels. A funnel is a situation where a set of input
    * (key) bits 'affects' a strictly smaller set of output bits. Funneling is bad because it can
diff --git a/guava-tests/test/com/google/common/hash/HashingInputStreamTest.java b/guava-tests/test/com/google/common/hash/HashingInputStreamTest.java
index f6709ce..326cc8e 100644
--- a/guava-tests/test/com/google/common/hash/HashingInputStreamTest.java
+++ b/guava-tests/test/com/google/common/hash/HashingInputStreamTest.java
@@ -24,6 +24,7 @@
 import org.easymock.EasyMock;
 
 import java.io.ByteArrayInputStream;
+import java.util.Arrays;
 
 /**
  * Tests for {@link HashingInputStream}.
@@ -76,7 +77,7 @@
   }
 
   public void testRead_putByteArrayAtPos() throws Exception {
-    EasyMock.expect(hasher.putBytes(aryEq(new byte[] {'y', 'a', 'm'}), eq(0), eq(3)))
+    EasyMock.expect(hasher.putBytes(aryEq(Arrays.copyOfRange(testBytes, 0, 3)), eq(0), eq(3)))
         .andReturn(hasher).once();
     EasyMock.replay(hasher);
     HashingInputStream in = new HashingInputStream(hashFunction, buffer);
diff --git a/guava-tests/test/com/google/common/hash/HashingTest.java b/guava-tests/test/com/google/common/hash/HashingTest.java
index 2f369f2..74b43c9 100644
--- a/guava-tests/test/com/google/common/hash/HashingTest.java
+++ b/guava-tests/test/com/google/common/hash/HashingTest.java
@@ -150,13 +150,6 @@
     HashTestUtils.assertInvariants(Hashing.goodFastHash(256));
   }
 
-  public void testPadToLong() {
-    assertEquals(0x1111111111111111L, Hashing.padToLong(HashCodes.fromLong(0x1111111111111111L)));
-    assertEquals(0x9999999999999999L, Hashing.padToLong(HashCodes.fromLong(0x9999999999999999L)));
-    assertEquals(0x0000000011111111L, Hashing.padToLong(HashCodes.fromInt(0x11111111)));
-    assertEquals(0x0000000099999999L, Hashing.padToLong(HashCodes.fromInt(0x99999999)));
-  }
-
   public void testConsistentHash_correctness() {
     long[] interestingValues = { -1, 0, 1, 2, Long.MAX_VALUE, Long.MIN_VALUE };
     for (long h : interestingValues) {
@@ -421,6 +414,9 @@
           .put(Hashing.sipHash24(), EMPTY_STRING, "310e0edd47db6f72")
           .put(Hashing.sipHash24(), TQBFJOTLD, "e46f1fdc05612752")
           .put(Hashing.sipHash24(), TQBFJOTLDP, "9b602581fce4d4f8")
+          .put(Hashing.crc32c(), EMPTY_STRING, "00000000")
+          .put(Hashing.crc32c(), TQBFJOTLD, "04046222")
+          .put(Hashing.crc32c(), TQBFJOTLDP, "b3970019")
           .build();
 
   public void testAllHashFunctionsHaveKnownHashes() throws Exception {
diff --git a/guava-tests/test/com/google/common/hash/MessageDigestHashFunctionTest.java b/guava-tests/test/com/google/common/hash/MessageDigestHashFunctionTest.java
index 2a625d6..4ff932a 100644
--- a/guava-tests/test/com/google/common/hash/MessageDigestHashFunctionTest.java
+++ b/guava-tests/test/com/google/common/hash/MessageDigestHashFunctionTest.java
@@ -19,12 +19,13 @@
 import com.google.common.base.Charsets;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.jdk5backport.Arrays;
 
 import junit.framework.TestCase;
 
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
 /**
  * Tests for the MessageDigestHashFunction.
  *
diff --git a/guava-tests/test/com/google/common/io/ByteSinkTester.java b/guava-tests/test/com/google/common/io/ByteSinkTester.java
index 5222a18..a743be5 100644
--- a/guava-tests/test/com/google/common/io/ByteSinkTester.java
+++ b/guava-tests/test/com/google/common/io/ByteSinkTester.java
@@ -28,7 +28,6 @@
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
 import java.lang.reflect.Method;
 import java.util.Map;
 
@@ -56,12 +55,7 @@
 
   private static TestSuite suiteForString(String name, ByteSinkFactory factory,
       String string, String desc) {
-    byte[] bytes;
-    try {
-      bytes = string.getBytes(Charsets.UTF_8.name());
-    } catch (UnsupportedEncodingException e) {
-      throw new AssertionError(e);
-    }
+    byte[] bytes = string.getBytes(Charsets.UTF_8);
     TestSuite suite = suiteForBytes(name, factory, desc, bytes);
     CharSinkFactory charSinkFactory = SourceSinkFactories.asCharSinkFactory(factory);
     suite.addTest(CharSinkTester.suiteForString(name + ".asCharSink[Charset]", charSinkFactory,
diff --git a/guava-tests/test/com/google/common/io/ByteSourceTest.java b/guava-tests/test/com/google/common/io/ByteSourceTest.java
index c40fcdd..24aaeed 100644
--- a/guava-tests/test/com/google/common/io/ByteSourceTest.java
+++ b/guava-tests/test/com/google/common/io/ByteSourceTest.java
@@ -164,7 +164,7 @@
   }
 
   public void testHash() throws IOException {
-    ByteSource byteSource = new TestByteSource("hamburger\n".getBytes(Charsets.US_ASCII.name()));
+    ByteSource byteSource = new TestByteSource("hamburger\n".getBytes(Charsets.US_ASCII));
 
     // Pasted this expected string from `echo hamburger | md5sum`
     assertEquals("cfa0c5002275c90508338a5cdb2a9781", byteSource.hash(Hashing.md5()).toString());
@@ -219,8 +219,8 @@
 
   /**
    * @param input      the size of the input source
-   * @param offset     the first argument to {@link ByteStreams#slice}
-   * @param length     the second argument to {@link ByteStreams#slice}
+   * @param offset     the first argument to {@link ByteSource#slice}
+   * @param length     the second argument to {@link ByteSource#slice}
    * @param expectRead the number of bytes we expect to read
    */
   private static void assertCorrectSlice(
diff --git a/guava-tests/test/com/google/common/io/ByteSourceTester.java b/guava-tests/test/com/google/common/io/ByteSourceTester.java
index 789cb8f..f9a735e 100644
--- a/guava-tests/test/com/google/common/io/ByteSourceTester.java
+++ b/guava-tests/test/com/google/common/io/ByteSourceTester.java
@@ -32,7 +32,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
 import java.lang.reflect.Method;
 import java.util.Map;
 import java.util.Random;
@@ -56,12 +55,8 @@
       if (testAsCharSource) {
         suite.addTest(suiteForString(factory, entry.getValue(), name, entry.getKey()));
       } else {
-        try {
-          suite.addTest(suiteForBytes(factory, entry.getValue().getBytes(Charsets.UTF_8.name()),
-              name, entry.getKey(), true));
-        } catch (UnsupportedEncodingException e) {
-          throw new AssertionError(e);
-        }
+        suite.addTest(suiteForBytes(
+            factory, entry.getValue().getBytes(Charsets.UTF_8), name, entry.getKey(), true));
       }
     }
     return suite;
@@ -69,12 +64,7 @@
 
   private static TestSuite suiteForString(ByteSourceFactory factory, String string,
       String name, String desc) {
-    TestSuite suite;
-    try {
-      suite = suiteForBytes(factory, string.getBytes(Charsets.UTF_8.name()), name, desc, true);
-    } catch (UnsupportedEncodingException e) {
-      throw new AssertionError(e);
-    }
+    TestSuite suite = suiteForBytes(factory, string.getBytes(Charsets.UTF_8), name, desc, true);
     CharSourceFactory charSourceFactory = SourceSinkFactories.asCharSourceFactory(factory);
     suite.addTest(CharSourceTester.suiteForString(charSourceFactory, string,
         name + ".asCharSource[Charset]", desc));
diff --git a/guava-tests/test/com/google/common/io/ByteStreamsTest.java b/guava-tests/test/com/google/common/io/ByteStreamsTest.java
index 96a4ab0..484b48d 100644
--- a/guava-tests/test/com/google/common/io/ByteStreamsTest.java
+++ b/guava-tests/test/com/google/common/io/ByteStreamsTest.java
@@ -16,9 +16,7 @@
 
 package com.google.common.io;
 
-import static com.google.common.base.Charsets.UTF_16;
 import com.google.common.base.Charsets;
-import com.google.common.jdk5backport.Arrays;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -27,12 +25,10 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
 import java.nio.channels.Channels;
 import java.nio.channels.ReadableByteChannel;
 import java.nio.channels.WritableByteChannel;
-import java.util.zip.CRC32;
-import java.util.zip.Checksum;
+import java.util.Arrays;
 
 /**
  * Unit test for {@link ByteStreams}.
@@ -183,9 +179,9 @@
     assertEquals(bytes[1], actual[3]);
   }
   
-  public void testNewDataInput_readLine() throws UnsupportedEncodingException {
+  public void testNewDataInput_readLine() {
     ByteArrayDataInput in = ByteStreams.newDataInput(
-        "This is a line\r\nThis too\rand this\nand also this".getBytes(Charsets.UTF_8.name()));
+        "This is a line\r\nThis too\rand this\nand also this".getBytes(Charsets.UTF_8));
     assertEquals("This is a line", in.readLine());
     assertEquals("This too", in.readLine());
     assertEquals("and this", in.readLine());
@@ -205,16 +201,16 @@
     assertEquals(Double.longBitsToDouble(0x1234567876543210L), in.readDouble(), 0.0);
   }
 
-  public void testNewDataInput_readUTF() throws UnsupportedEncodingException {
+  public void testNewDataInput_readUTF() {
     byte[] data = new byte[17];
     data[1] = 15;
-    System.arraycopy("Kilroy was here".getBytes(Charsets.UTF_8.name()), 0, data, 2, 15);
+    System.arraycopy("Kilroy was here".getBytes(Charsets.UTF_8), 0, data, 2, 15);
     ByteArrayDataInput in = ByteStreams.newDataInput(data);
     assertEquals("Kilroy was here", in.readUTF());
   }
 
-  public void testNewDataInput_readChar() throws UnsupportedEncodingException {
-    byte[] data = "qed".getBytes(Charsets.UTF_16BE.name());
+  public void testNewDataInput_readChar() {
+    byte[] data = "qed".getBytes(Charsets.UTF_16BE);
     ByteArrayDataInput in = ByteStreams.newDataInput(data);
     assertEquals('q', in.readChar());
     assertEquals('e', in.readChar());
@@ -348,18 +344,18 @@
     assertEquals(new byte[] {0, 97}, out.toByteArray());
   }
 
-  public void testNewDataOutput_writeChars() throws UnsupportedEncodingException {
+  public void testNewDataOutput_writeChars() {
     ByteArrayDataOutput out = ByteStreams.newDataOutput();
     out.writeChars("r\u00C9sum\u00C9");
     // need to remove byte order mark before comparing
-    byte[] expected = Arrays.copyOfRange("r\u00C9sum\u00C9".getBytes(UTF_16.name()), 2, 14);
+    byte[] expected = Arrays.copyOfRange("r\u00C9sum\u00C9".getBytes(Charsets.UTF_16), 2, 14);
     assertEquals(expected, out.toByteArray());
   }
 
-  public void testNewDataOutput_writeUTF() throws UnsupportedEncodingException {
+  public void testNewDataOutput_writeUTF() {
     ByteArrayDataOutput out = ByteStreams.newDataOutput();
     out.writeUTF("r\u00C9sum\u00C9");
-    byte[] expected ="r\u00C9sum\u00C9".getBytes(Charsets.UTF_8.name());
+    byte[] expected ="r\u00C9sum\u00C9".getBytes(Charsets.UTF_8);
     byte[] actual = out.toByteArray();
     // writeUTF writes the length of the string in 2 bytes
     assertEquals(0, actual[0]);
@@ -386,21 +382,6 @@
     assertEquals(bytes, out.toByteArray());
   }
 
-  public void testChecksum() throws IOException {
-    InputSupplier<ByteArrayInputStream> asciiBytes =
-        ByteStreams.newInputStreamSupplier(ASCII.getBytes(Charsets.US_ASCII.name()));
-    InputSupplier<ByteArrayInputStream> i18nBytes =
-        ByteStreams.newInputStreamSupplier(I18N.getBytes(Charsets.UTF_8.name()));
-
-    Checksum checksum = new CRC32();
-    assertEquals(0L, checksum.getValue());
-    assertEquals(3145994718L, ByteStreams.getChecksum(asciiBytes, checksum));
-    assertEquals(0L, checksum.getValue());
-    assertEquals(3145994718L, ByteStreams.getChecksum(asciiBytes, checksum));
-    assertEquals(1138302340L, ByteStreams.getChecksum(i18nBytes, checksum));
-    assertEquals(0L, checksum.getValue());
-  }
-
   public void testNewDataOutput_BAOS() {
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     ByteArrayDataOutput out = ByteStreams.newDataOutput(baos);
diff --git a/guava-tests/test/com/google/common/io/CharSourceTester.java b/guava-tests/test/com/google/common/io/CharSourceTester.java
index 8d5bc79..f2882cd 100644
--- a/guava-tests/test/com/google/common/io/CharSourceTester.java
+++ b/guava-tests/test/com/google/common/io/CharSourceTester.java
@@ -139,7 +139,7 @@
   }
 
   public void testIsEmpty() throws IOException {
-    assertEquals(expected.length() == 0, source.isEmpty());
+    assertEquals(expected.isEmpty(), source.isEmpty());
   }
 
   public void testReadLines_withProcessor() throws IOException {
diff --git a/guava-tests/test/com/google/common/io/CloseablesTest.java b/guava-tests/test/com/google/common/io/CloseablesTest.java
index a4cd1bb..e564e3c 100644
--- a/guava-tests/test/com/google/common/io/CloseablesTest.java
+++ b/guava-tests/test/com/google/common/io/CloseablesTest.java
@@ -67,14 +67,6 @@
     doClose(mockCloseable, false);
   }
 
-  public void testCloseQuietly_closeableWithEatenException()
-      throws IOException {
-    // make sure that no exception is thrown by CloseQuietly when the mock does
-    // throw an exception on close
-    setupCloseable(true);
-    Closeables.closeQuietly(mockCloseable);
-  }
-
   public void testCloseQuietly_inputStreamWithEatenException() throws IOException {
     TestInputStream in = new TestInputStream(
         new ByteArrayInputStream(new byte[1]), TestOption.CLOSE_THROWS);
@@ -91,7 +83,6 @@
   public void testCloseNull() throws IOException {
     Closeables.close(null, true);
     Closeables.close(null, false);
-    Closeables.closeQuietly((Closeable) null);
   }
 
   public void testCloseQuietlyNull_inputStream() {
diff --git a/guava-tests/test/com/google/common/io/CloserTest.java b/guava-tests/test/com/google/common/io/CloserTest.java
index 9481ca5..c33a4b8 100644
--- a/guava-tests/test/com/google/common/io/CloserTest.java
+++ b/guava-tests/test/com/google/common/io/CloserTest.java
@@ -16,6 +16,7 @@
 
 package com.google.common.io;
 
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 import com.google.common.base.Splitter;
 import com.google.common.base.Throwables;
@@ -422,7 +423,7 @@
 
     @Override
     public String toString() {
-      return Objects.toStringHelper(this)
+      return MoreObjects.toStringHelper(this)
           .add("closeable", closeable)
           .add("thrown", thrown)
           .add("suppressed", suppressed)
diff --git a/guava-tests/test/com/google/common/io/FilesTest.java b/guava-tests/test/com/google/common/io/FilesTest.java
index f8eb3d0..5a4dd68 100644
--- a/guava-tests/test/com/google/common/io/FilesTest.java
+++ b/guava-tests/test/com/google/common/io/FilesTest.java
@@ -18,7 +18,7 @@
 
 import static com.google.common.io.Files.createTempDir;
 import static com.google.common.io.Files.touch;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.base.Charsets;
 import com.google.common.collect.ImmutableList;
@@ -73,11 +73,11 @@
   public void testToByteArray() throws IOException {
     File asciiFile = getTestFile("ascii.txt");
     File i18nFile = getTestFile("i18n.txt");
-    assertTrue(Arrays.equals(ASCII.getBytes(Charsets.US_ASCII.name()),
+    assertTrue(Arrays.equals(ASCII.getBytes(Charsets.US_ASCII),
         Files.toByteArray(asciiFile)));
-    assertTrue(Arrays.equals(I18N.getBytes(Charsets.UTF_8.name()),
+    assertTrue(Arrays.equals(I18N.getBytes(Charsets.UTF_8),
         Files.toByteArray(i18nFile)));
-    assertTrue(Arrays.equals(I18N.getBytes(Charsets.UTF_8.name()),
+    assertTrue(Arrays.equals(I18N.getBytes(Charsets.UTF_8),
         Files.asByteSource(i18nFile).read()));
   }
 
@@ -88,7 +88,7 @@
     try {
       InputStream in = closer.register(new FileInputStream(asciiFile));
       byte[] bytes = Files.readFile(in, asciiFile.length());
-      assertTrue(Arrays.equals(ASCII.getBytes(Charsets.US_ASCII.name()), bytes));
+      assertTrue(Arrays.equals(ASCII.getBytes(Charsets.US_ASCII), bytes));
     } catch (Throwable e) {
       throw closer.rethrow(e);
     } finally {
@@ -103,7 +103,7 @@
     try {
       InputStream in = closer.register(new FileInputStream(asciiFile));
       byte[] bytes = Files.readFile(in, 10);
-      assertTrue(Arrays.equals(ASCII.getBytes(Charsets.US_ASCII.name()), bytes));
+      assertTrue(Arrays.equals(ASCII.getBytes(Charsets.US_ASCII), bytes));
     } catch (Throwable e) {
       throw closer.rethrow(e);
     } finally {
@@ -118,7 +118,7 @@
     try {
       InputStream in = closer.register(new FileInputStream(asciiFile));
       byte[] bytes = Files.readFile(in, 500);
-      assertTrue(Arrays.equals(ASCII.getBytes(Charsets.US_ASCII.name()), bytes));
+      assertTrue(Arrays.equals(ASCII.getBytes(Charsets.US_ASCII), bytes));
     } catch (Throwable e) {
       throw closer.rethrow(e);
     } finally {
@@ -133,7 +133,7 @@
     try {
       InputStream in = closer.register(new FileInputStream(asciiFile));
       byte[] bytes = Files.readFile(in, 0);
-      assertTrue(Arrays.equals(ASCII.getBytes(Charsets.US_ASCII.name()), bytes));
+      assertTrue(Arrays.equals(ASCII.getBytes(Charsets.US_ASCII), bytes));
     } catch (Throwable e) {
       throw closer.rethrow(e);
     } finally {
@@ -166,26 +166,10 @@
     File i18nFile = getTestFile("i18n.txt");
     assertEquals(ASCII, Files.toString(asciiFile, Charsets.US_ASCII));
     assertEquals(I18N, Files.toString(i18nFile, Charsets.UTF_8));
-    ASSERT.that(Files.toString(i18nFile, Charsets.US_ASCII))
+    assertThat(Files.toString(i18nFile, Charsets.US_ASCII))
         .isNotEqualTo(I18N);
   }
 
-  public void testCopyCharacters() throws IOException {
-    File i18nFile = getTestFile("i18n.txt");
-    File temp = createTempFile();
-    Files.copy(i18nFile, Charsets.UTF_8,
-        Files.asCharSink(temp, Charsets.UTF_8));
-    assertEquals(I18N, Files.toString(temp, Charsets.UTF_8));
-
-    Files.copy(Files.asCharSource(i18nFile, Charsets.UTF_8), temp,
-        Charsets.UTF_8);
-    assertEquals(I18N, Files.toString(temp, Charsets.UTF_8));
-
-    Files.copy(i18nFile, Charsets.UTF_8,
-        Files.asCharSink(temp, Charsets.UTF_16LE));
-    assertEquals(I18N, Files.toString(temp, Charsets.UTF_16LE));
-  }
-
   public void testWriteString() throws IOException {
     File temp = createTempFile();
     Files.write(I18N, temp, Charsets.UTF_16LE);
@@ -229,20 +213,6 @@
     assertEquals(I18N, sb.toString());
   }
 
-  public void testCopyToByteSink() throws IOException {
-    File i18nFile = getTestFile("i18n.txt");
-    File temp = createTempFile();
-    Files.copy(i18nFile, Files.asByteSink(temp));
-    assertEquals(I18N, Files.toString(temp, Charsets.UTF_8));
-  }
-
-  public void testCopyFromByteSource() throws IOException {
-    File i18nFile = getTestFile("i18n.txt");
-    File temp = createTempFile();
-    Files.copy(Files.asByteSource(i18nFile), temp);
-    assertEquals(I18N, Files.toString(temp, Charsets.UTF_8));
-  }
-
   public void testCopyFile() throws IOException {
     File i18nFile = getTestFile("i18n.txt");
     File temp = createTempFile();
@@ -387,7 +357,7 @@
     temp.setLastModified(0);
     assertEquals(0, temp.lastModified());
     Files.touch(temp);
-    ASSERT.that(temp.lastModified()).isNotEqualTo(0);
+    assertThat(temp.lastModified()).isNotEqualTo(0);
   }
 
   public void testCreateParentDirs_root() throws IOException {
@@ -562,7 +532,7 @@
         return collector;
       }
     };
-    ASSERT.that(Files.readLines(temp, Charsets.UTF_8, collect)).isEmpty();
+    assertThat(Files.readLines(temp, Charsets.UTF_8, collect)).isEmpty();
 
     PrintWriter w = new PrintWriter(Files.newWriter(temp, Charsets.UTF_8));
     w.println("hello");
@@ -571,7 +541,7 @@
     w.println("");
     w.close();
     Files.readLines(temp, Charsets.UTF_8, collect);
-    ASSERT.that(collect.getResult())
+    assertThat(collect.getResult())
         .has().exactly("hello", "", " world  ", "").inOrder();
 
     LineProcessor<List<String>> collectNonEmptyLines =
@@ -592,7 +562,7 @@
           }
         };
     Files.readLines(temp, Charsets.UTF_8, collectNonEmptyLines);
-    ASSERT.that(collectNonEmptyLines.getResult()).has().exactly(
+    assertThat(collectNonEmptyLines.getResult()).has().exactly(
         "hello", " world  ").inOrder();
 
     assertTrue(temp.delete());
diff --git a/guava-tests/test/com/google/common/io/LittleEndianDataOutputStreamTest.java b/guava-tests/test/com/google/common/io/LittleEndianDataOutputStreamTest.java
index 109bf0e..93e9809 100644
--- a/guava-tests/test/com/google/common/io/LittleEndianDataOutputStreamTest.java
+++ b/guava-tests/test/com/google/common/io/LittleEndianDataOutputStreamTest.java
@@ -34,9 +34,9 @@
  */
 public class LittleEndianDataOutputStreamTest extends TestCase {
 
-  private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-  private final LittleEndianDataOutputStream out = new LittleEndianDataOutputStream(baos);
-
+  private ByteArrayOutputStream baos = new ByteArrayOutputStream();
+  private LittleEndianDataOutputStream out = new LittleEndianDataOutputStream(baos);
+  
   public void testWriteLittleEndian() throws IOException {
 
     /* Write out various test values in LITTLE ENDIAN FORMAT */
@@ -79,10 +79,10 @@
     assertEquals(0xBEBAFECA, Float.floatToIntBits(in.readFloat()));
     assertEquals(0xBEBAFECAEFBEADDEL, Double.doubleToLongBits(in.readDouble()));
   }
-
+  
   @SuppressWarnings("deprecation") // testing a deprecated method
   public void testWriteBytes() throws IOException {
-
+    
     /* Write out various test values in LITTLE ENDIAN FORMAT */
     out.writeBytes("r\u00C9sum\u00C9");
 
@@ -94,12 +94,12 @@
     /* Read in various values NORMALLY */
     byte[] b = new byte[6];
     in.readFully(b);
-    assertEquals("r\u00C9sum\u00C9".getBytes(Charsets.ISO_8859_1.name()), b);
+    assertEquals("r\u00C9sum\u00C9".getBytes(Charsets.ISO_8859_1), b);
   }
-
+  
   @SuppressWarnings("deprecation") // testing a deprecated method
   public void testWriteBytes_discardHighOrderBytes() throws IOException {
-
+    
     /* Write out various test values in LITTLE ENDIAN FORMAT */
     out.writeBytes("\uAAAA\uAABB\uAACC");
 
diff --git a/guava-tests/test/com/google/common/io/ResourcesTest.java b/guava-tests/test/com/google/common/io/ResourcesTest.java
index dac1d80..3bf17ac 100644
--- a/guava-tests/test/com/google/common/io/ResourcesTest.java
+++ b/guava-tests/test/com/google/common/io/ResourcesTest.java
@@ -17,7 +17,7 @@
 package com.google.common.io;
 
 import static com.google.common.base.CharMatcher.WHITESPACE;
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.base.Charsets;
 import com.google.common.collect.ImmutableList;
@@ -56,7 +56,7 @@
   public void testToString() throws IOException {
     URL resource = getClass().getResource("testdata/i18n.txt");
     assertEquals(I18N, Resources.toString(resource, Charsets.UTF_8));
-    ASSERT.that(Resources.toString(resource, Charsets.US_ASCII))
+    assertThat(Resources.toString(resource, Charsets.US_ASCII))
         .isNotEqualTo(I18N);
   }
 
diff --git a/guava-tests/test/com/google/common/io/SourceSinkFactories.java b/guava-tests/test/com/google/common/io/SourceSinkFactories.java
index 56c73e2..0165bf8 100644
--- a/guava-tests/test/com/google/common/io/SourceSinkFactories.java
+++ b/guava-tests/test/com/google/common/io/SourceSinkFactories.java
@@ -23,7 +23,6 @@
 import static com.google.common.io.SourceSinkFactory.CharSourceFactory;
 
 import com.google.common.base.Charsets;
-import com.google.common.jdk5backport.Arrays;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -35,9 +34,9 @@
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.Reader;
-import java.io.UnsupportedEncodingException;
 import java.io.Writer;
 import java.nio.CharBuffer;
+import java.util.Arrays;
 import java.util.logging.Logger;
 
 import javax.annotation.Nullable;
@@ -77,11 +76,7 @@
 
   public static ByteSinkFactory appendingFileByteSinkFactory() {
     String initialString = IoTestCase.ASCII + IoTestCase.I18N;
-    try {
-      return new FileByteSinkFactory(initialString.getBytes(Charsets.UTF_8.name()));
-    } catch (UnsupportedEncodingException e) {
-      throw new AssertionError(e);
-    }
+    return new FileByteSinkFactory(initialString.getBytes(Charsets.UTF_8));
   }
 
   public static CharSourceFactory fileCharSourceFactory() {
@@ -110,18 +105,13 @@
     return new CharSourceFactory() {
       @Override
       public CharSource createSource(String string) throws IOException {
-        return factory.createSource(string.getBytes(Charsets.UTF_8.name()))
+        return factory.createSource(string.getBytes(Charsets.UTF_8))
             .asCharSource(Charsets.UTF_8);
       }
 
       @Override
       public String getExpected(String data) {
-        try {
-          return new String(factory.getExpected(data.getBytes(Charsets.UTF_8.name())),
-              Charsets.UTF_8.name());
-        } catch (UnsupportedEncodingException e) {
-          throw new AssertionError();
-        }
+        return new String(factory.getExpected(data.getBytes(Charsets.UTF_8)), Charsets.UTF_8);
       }
 
       @Override
@@ -141,7 +131,7 @@
 
       @Override
       public String getSinkContents() throws IOException {
-        return new String(factory.getSinkContents(), Charsets.UTF_8.name());
+        return new String(factory.getSinkContents(), Charsets.UTF_8);
       }
 
       @Override
@@ -151,11 +141,7 @@
          * string to that.
          */
         byte[] factoryExpectedForNothing = factory.getExpected(new byte[0]);
-        try {
-          return new String(factoryExpectedForNothing, Charsets.UTF_8.name()) + checkNotNull(data);
-        } catch (UnsupportedEncodingException e) {
-          throw new AssertionError();
-        }
+        return new String(factoryExpectedForNothing, Charsets.UTF_8) + checkNotNull(data);
       }
 
       @Override
diff --git a/guava-tests/test/com/google/common/io/TestCharSink.java b/guava-tests/test/com/google/common/io/TestCharSink.java
index c14b747..6f7686f 100644
--- a/guava-tests/test/com/google/common/io/TestCharSink.java
+++ b/guava-tests/test/com/google/common/io/TestCharSink.java
@@ -21,7 +21,6 @@
 import java.io.FilterWriter;
 import java.io.IOException;
 import java.io.OutputStreamWriter;
-import java.io.UnsupportedEncodingException;
 import java.io.Writer;
 
 /**
@@ -38,11 +37,7 @@
   }
 
   public String getString() {
-    try {
-      return new String(byteSink.getBytes(), UTF_8.name());
-    } catch (UnsupportedEncodingException e) {
-      throw new AssertionError();
-    }
+    return new String(byteSink.getBytes(), UTF_8);
   }
 
   @Override
diff --git a/guava-tests/test/com/google/common/io/TestCharSource.java b/guava-tests/test/com/google/common/io/TestCharSource.java
index 38bb716..37ee8dc 100644
--- a/guava-tests/test/com/google/common/io/TestCharSource.java
+++ b/guava-tests/test/com/google/common/io/TestCharSource.java
@@ -21,7 +21,6 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.Reader;
-import java.io.UnsupportedEncodingException;
 
 /**
  * A char source for testing that has configurable options.
@@ -33,11 +32,7 @@
   private final TestByteSource byteSource;
 
   public TestCharSource(String content, TestOption... options) {
-    try {
-      this.byteSource = new TestByteSource(content.getBytes(UTF_8.name()), options);
-    } catch (UnsupportedEncodingException e) {
-      throw new AssertionError(e);
-    }
+    this.byteSource = new TestByteSource(content.getBytes(UTF_8), options);
   }
 
   @Override
diff --git a/guava-tests/test/com/google/common/jdk5backport/Arrays.java b/guava-tests/test/com/google/common/jdk5backport/Arrays.java
deleted file mode 100644
index adb934b..0000000
--- a/guava-tests/test/com/google/common/jdk5backport/Arrays.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.google.common.jdk5backport;
-
-/**
- * An Arrays alternative containing JDK 1.6 method equivalents used
- * to support JDK 1.5 with a few pass-through methods to reduce import
- * conflicts.
- */
-public final class Arrays {
-  public static byte[] copyOf(byte[] original, int newLength) {
-    return copyOfRange(original, 0, newLength);
-  }
-
-  public static byte[] copyOfRange(byte[] original, int from, int to) {
-    int newLength = to - from;
-    if (newLength >= 0) {
-      byte[] copy = new byte[newLength];
-      System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength));
-      return copy;
-    }
-    throw new IllegalArgumentException();
-  }
-
-  public static void fill(byte[] array, byte val) {
-    java.util.Arrays.fill(array, val);
-  }
-
-  public static boolean equals(byte[] a, byte[] a2) {
-     return java.util.Arrays.equals(a, a2);
-  }
-}
diff --git a/guava-tests/test/com/google/common/math/DoubleMathTest.java b/guava-tests/test/com/google/common/math/DoubleMathTest.java
index 1231142..a234007 100644
--- a/guava-tests/test/com/google/common/math/DoubleMathTest.java
+++ b/guava-tests/test/com/google/common/math/DoubleMathTest.java
@@ -29,6 +29,9 @@
 import static java.math.RoundingMode.CEILING;
 import static java.math.RoundingMode.DOWN;
 import static java.math.RoundingMode.FLOOR;
+import static java.math.RoundingMode.HALF_DOWN;
+import static java.math.RoundingMode.HALF_EVEN;
+import static java.math.RoundingMode.HALF_UP;
 import static java.math.RoundingMode.UNNECESSARY;
 import static java.math.RoundingMode.UP;
 import static java.util.Arrays.asList;
@@ -62,8 +65,6 @@
   private static final BigDecimal MAX_LONG_AS_BIG_DECIMAL = BigDecimal.valueOf(Long.MAX_VALUE);
   private static final BigDecimal MIN_LONG_AS_BIG_DECIMAL = BigDecimal.valueOf(Long.MIN_VALUE);
 
-  private static final double MIN_NORMAL = 2.2250738585072014E-308; // Doubles.MIN_NORMAL from 1.6
-
   public void testConstantsMaxFactorial() {
     BigInteger maxDoubleValue = BigDecimal.valueOf(Double.MAX_VALUE).toBigInteger();
     assertTrue(BigIntegerMath.factorial(DoubleMath.MAX_FACTORIAL).compareTo(maxDoubleValue) <= 0);
@@ -365,6 +366,38 @@
   }
 
   @GwtIncompatible("DoubleMath.log2(double, RoundingMode)")
+  public void testRoundLog2Half() {
+    // We don't expect perfect rounding accuracy.
+    for (int exp : asList(-1022, -50, -1, 0, 1, 2, 3, 4, 100, 1022, 1023)) {
+      for (RoundingMode mode : asList(HALF_EVEN, HALF_UP, HALF_DOWN)) {
+        double x = Math.scalb(Math.sqrt(2) + 0.001, exp);
+        double y = Math.scalb(Math.sqrt(2) - 0.001, exp);
+        if (exp < 0) {
+          assertEquals(exp + 1, DoubleMath.log2(x, mode));
+          assertEquals(exp, DoubleMath.log2(y, mode));
+        } else {
+          assertEquals(exp + 1, DoubleMath.log2(x, mode));
+          assertEquals(exp, DoubleMath.log2(y, mode));
+        }
+      }
+    }
+  }
+
+  @GwtIncompatible("DoubleMath.log2(double, RoundingMode)")
+  public void testRoundLog2Exact() {
+    for (double x : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
+      boolean isPowerOfTwo = StrictMath.pow(2.0, DoubleMath.log2(x, FLOOR)) == x;
+      try {
+        int log2 = DoubleMath.log2(x, UNNECESSARY);
+        assertEquals(x, Math.scalb(1.0, log2));
+        assertTrue(isPowerOfTwo);
+      } catch (ArithmeticException e) {
+        assertFalse(isPowerOfTwo);
+      }
+    }
+  }
+
+  @GwtIncompatible("DoubleMath.log2(double, RoundingMode)")
   public void testRoundLog2ThrowsOnZerosInfinitiesAndNaN() {
     for (RoundingMode mode : ALL_ROUNDING_MODES) {
       for (double d :
@@ -405,6 +438,15 @@
     }
   }
 
+  @GwtIncompatible("#trueLog2, Math.ulp")
+  public void testLog2Accuracy() {
+    for (double d : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
+      double dmLog2 = DoubleMath.log2(d);
+      double trueLog2 = trueLog2(d);
+      assertTrue(Math.abs(dmLog2 - trueLog2) <= Math.ulp(trueLog2));
+    }
+  }
+
   public void testLog2SemiMonotonic() {
     for (double d : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
       assertTrue(DoubleMath.log2(d + 0.01) >= DoubleMath.log2(d));
@@ -428,6 +470,23 @@
     assertTrue(Double.isNaN(DoubleMath.log2(Double.NaN)));
   }
 
+  @GwtIncompatible("StrictMath")
+  private strictfp double trueLog2(double d) {
+    double trueLog2 = StrictMath.log(d) / StrictMath.log(2);
+    // increment until it's >= the true value
+    while (StrictMath.pow(2.0, trueLog2) < d) {
+      trueLog2 = StrictMath.nextUp(trueLog2);
+    }
+    // decrement until it's <= the true value
+    while (StrictMath.pow(2.0, trueLog2) > d) {
+      trueLog2 = StrictMath.nextAfter(trueLog2, Double.NEGATIVE_INFINITY);
+    }
+    if (StrictMath.abs(StrictMath.pow(2.0, trueLog2) - d)
+        > StrictMath.abs(StrictMath.pow(2.0, StrictMath.nextUp(trueLog2)) - d)) {
+      trueLog2 = StrictMath.nextUp(trueLog2);
+    }
+    return trueLog2;
+  }
 
   @GwtIncompatible("DoubleMath.isMathematicalInteger")
   public void testIsMathematicalIntegerIntegral() {
@@ -481,7 +540,7 @@
       Iterables.concat(FINITE_TOLERANCE_CANDIDATES, ImmutableList.of(Double.POSITIVE_INFINITY));
 
   private static final List<Double> BAD_TOLERANCE_CANDIDATES =
-      Doubles.asList(-Double.MIN_VALUE, -MIN_NORMAL, -1, -20, Double.NaN,
+      Doubles.asList(-Double.MIN_VALUE, -Double.MIN_NORMAL, -1, -20, Double.NaN,
           Double.NEGATIVE_INFINITY, -0.001);
 
   public void testFuzzyEqualsFinite() {
diff --git a/guava-tests/test/com/google/common/math/IntMathTest.java b/guava-tests/test/com/google/common/math/IntMathTest.java
index aba46c3..841a7fc 100644
--- a/guava-tests/test/com/google/common/math/IntMathTest.java
+++ b/guava-tests/test/com/google/common/math/IntMathTest.java
@@ -95,7 +95,7 @@
   public void testPowersSqrtMaxInt() {
     assertEquals(IntMath.sqrt(Integer.MAX_VALUE, FLOOR), IntMath.FLOOR_SQRT_MAX_INT);
   }
-  
+
   public void testLessThanBranchFree() {
     for (int x : ALL_INTEGER_CANDIDATES) {
       for (int y : ALL_INTEGER_CANDIDATES) {
diff --git a/guava-tests/test/com/google/common/math/MathBenchmarking.java b/guava-tests/test/com/google/common/math/MathBenchmarking.java
index 09e57b2..455d10c 100644
--- a/guava-tests/test/com/google/common/math/MathBenchmarking.java
+++ b/guava-tests/test/com/google/common/math/MathBenchmarking.java
@@ -22,6 +22,11 @@
 /**
  * Utilities for benchmarks.
  *
+ * In many cases, we wish to vary the order of magnitude of the input as much as we
+ * want to vary the input itself, so most methods which generate values use
+ * an exponential distribution varying the order of magnitude of the generated values
+ * uniformly at random.
+ *
  * @author Louis Wasserman
  */
 final class MathBenchmarking {
@@ -40,28 +45,71 @@
           887, 534, 361, 265, 206, 169, 143, 125, 111, 101, 94, 88, 83, 79, 76, 74, 72, 70, 69, 68,
           67, 67, 66, 66, 66, 66};
 
+  /**
+   * Generates values in a distribution equivalent to randomNonNegativeBigInteger
+   * but omitting zero.
+   */
   static BigInteger randomPositiveBigInteger(int numBits) {
-    int digits = RANDOM_SOURCE.nextInt(numBits) + 1;
-    return new BigInteger(digits, RANDOM_SOURCE).add(BigInteger.ONE);
+    BigInteger result;
+    do {
+      result = randomNonNegativeBigInteger(numBits);
+    } while (result.signum() == 0);
+    return result;
   }
 
+  /**
+   * Generates a number in [0, 2^numBits) with an exponential distribution.
+   * The floor of the log2 of the result is chosen uniformly at random in
+   * [0, numBits), and then the result is chosen in that range uniformly at random.
+   * Zero is treated as having log2 == 0.
+   */
   static BigInteger randomNonNegativeBigInteger(int numBits) {
-    int digits = RANDOM_SOURCE.nextInt(numBits) + 1;
-    return new BigInteger(digits, RANDOM_SOURCE);
+    int digits = RANDOM_SOURCE.nextInt(numBits);
+    if (digits == 0) {
+      return new BigInteger(1, RANDOM_SOURCE);
+    } else {
+      return new BigInteger(digits, RANDOM_SOURCE)
+          .setBit(digits);
+    }
   }
 
+  /**
+   * Equivalent to calling randomPositiveBigInteger(numBits) and then flipping
+   * the sign with 50% probability.
+   */
   static BigInteger randomNonZeroBigInteger(int numBits) {
     BigInteger result = randomPositiveBigInteger(numBits);
     return RANDOM_SOURCE.nextBoolean() ? result : result.negate();
   }
 
+  /**
+   * Chooses a number in (-2^numBits, 2^numBits) at random, with density
+   * concentrated in numbers of lower magnitude.
+   */
   static BigInteger randomBigInteger(int numBits) {
-    BigInteger result = randomNonNegativeBigInteger(numBits);
-    return RANDOM_SOURCE.nextBoolean() ? result : result.negate();
+    while (true) {
+      if (RANDOM_SOURCE.nextBoolean()) {
+        return randomNonNegativeBigInteger(numBits);
+      }
+      BigInteger neg = randomNonNegativeBigInteger(numBits).negate();
+      if (neg.signum() != 0) {
+        return neg;
+      }
+    }
   }
 
+  /**
+   * Generates a number in [0, 2^numBits) with an exponential distribution.
+   * The floor of the log2 of the absolute value of the result is chosen uniformly
+   * at random in [0, numBits), and then the result is chosen from those possibilities
+   * uniformly at random.
+   *
+   * Zero is treated as having log2 == 0.
+   */
   static double randomDouble(int maxExponent) {
-    return RANDOM_SOURCE.nextDouble();
+    double result = RANDOM_SOURCE.nextDouble();
+    result = Math.scalb(result, RANDOM_SOURCE.nextInt(maxExponent + 1));
+    return RANDOM_SOURCE.nextBoolean() ? result : -result;
   }
 
   /**
diff --git a/guava-tests/test/com/google/common/math/MathTesting.java b/guava-tests/test/com/google/common/math/MathTesting.java
index 6b69d5f..a4bc6a9 100644
--- a/guava-tests/test/com/google/common/math/MathTesting.java
+++ b/guava-tests/test/com/google/common/math/MathTesting.java
@@ -149,6 +149,7 @@
     longValues.addAll(Iterables.transform(POSITIVE_INTEGER_CANDIDATES, TO_LONG));
     // Add boundary values manually to avoid over/under flow (this covers 2^N for 31 and 63).
     longValues.add(Integer.MAX_VALUE + 1L, Long.MAX_VALUE - 1L, Long.MAX_VALUE);
+
     // Now add values near 2^N for lots of values of N.
     for (int exponent : asList(32, 33, 39, 40, 41, 47, 48, 49, 55, 56, 57)) {
       long x = 1L << exponent;
@@ -176,10 +177,6 @@
 
   static final Iterable<BigInteger> ALL_BIGINTEGER_CANDIDATES;
 
-  static final int MAX_EXPONENT = 1023; // Double.MAX_EXPONENT not present in JDK5
-
-  static final double MIN_NORMAL = 2.2250738585072014E-308;
-
   static {
     ImmutableSet.Builder<BigInteger> bigValues = ImmutableSet.builder();
     // First of all add all the long candidate values.
@@ -188,7 +185,7 @@
     bigValues.add(BigInteger.valueOf(Long.MAX_VALUE).add(ONE));
     // Now add values near 2^N for lots of values of N.
     for (int exponent : asList(64, 65, 71, 72, 73, 79, 80, 81, 255, 256, 257, 511, 512, 513,
-        MAX_EXPONENT - 1, MAX_EXPONENT, MAX_EXPONENT + 1)) {
+        Double.MAX_EXPONENT - 1, Double.MAX_EXPONENT, Double.MAX_EXPONENT + 1)) {
       BigInteger x = ONE.shiftLeft(exponent);
       bigValues.add(x, x.add(ONE), x.subtract(ONE));
     }
@@ -219,11 +216,11 @@
     integralBuilder.addAll(Doubles.asList(0.0, -0.0, Double.MAX_VALUE, -Double.MAX_VALUE));
     // Add small multiples of MIN_VALUE and MIN_NORMAL
     for (int scale = 1; scale <= 4; scale++) {
-      for (double d : Doubles.asList(Double.MIN_VALUE, MIN_NORMAL)) {
+      for (double d : Doubles.asList(Double.MIN_VALUE, Double.MIN_NORMAL)) {
         fractionalBuilder.add(d * scale).add(-d * scale);
       }
     }
-    for (double d : Doubles.asList(0, 1, 2, 7, 51, 102, Integer.MIN_VALUE,
+    for (double d : Doubles.asList(0, 1, 2, 7, 51, 102, Math.scalb(1.0, 53), Integer.MIN_VALUE,
         Integer.MAX_VALUE, Long.MIN_VALUE, Long.MAX_VALUE)) {
       for (double delta : Doubles.asList(0.0, 1.0, 2.0)) {
         integralBuilder.addAll(Doubles.asList(d + delta, d - delta, -d - delta, -d + delta));
diff --git a/guava-tests/test/com/google/common/net/HttpHeadersTest.java b/guava-tests/test/com/google/common/net/HttpHeadersTest.java
index 282f41f..3b42aff 100644
--- a/guava-tests/test/com/google/common/net/HttpHeadersTest.java
+++ b/guava-tests/test/com/google/common/net/HttpHeadersTest.java
@@ -62,7 +62,7 @@
        * fields, they will cause similar problems, and we may want to switch
        * this check to isAccessible().
        */
-      if (!field.isSynthetic()) {
+      if (!field.isSynthetic() && field.getType() == String.class) {
         builder.add(field);
       }
     }
diff --git a/guava-tests/test/com/google/common/net/InetAddressesTest.java b/guava-tests/test/com/google/common/net/InetAddressesTest.java
index 90d3285..7978155 100644
--- a/guava-tests/test/com/google/common/net/InetAddressesTest.java
+++ b/guava-tests/test/com/google/common/net/InetAddressesTest.java
@@ -724,4 +724,51 @@
       fail();
     } catch (IllegalArgumentException expected) {}
   }
+
+  public void testDecrementIPv4() throws UnknownHostException {
+    InetAddress address660 = InetAddress.getByName("172.24.66.0");
+    InetAddress address66255 = InetAddress.getByName("172.24.66.255");
+    InetAddress address670 = InetAddress.getByName("172.24.67.0");
+
+    InetAddress address = address670;
+    address = InetAddresses.decrement(address);
+
+    assertEquals(address66255, address);
+
+    for (int i = 0; i < 255; i++) {
+      address = InetAddresses.decrement(address);
+    }
+    assertEquals(address660, address);
+
+    InetAddress address0000 = InetAddress.getByName("0.0.0.0");
+    address = address0000;
+    try {
+      address = InetAddresses.decrement(address);
+      fail();
+    } catch (IllegalArgumentException expected) {}
+  }
+
+  public void testDecrementIPv6() throws UnknownHostException {
+    InetAddress addressV6660 = InetAddress.getByName("2001:db8::6600");
+    InetAddress addressV666ff = InetAddress.getByName("2001:db8::66ff");
+    InetAddress addressV6670 = InetAddress.getByName("2001:db8::6700");
+
+    InetAddress address = addressV6670;
+    address = InetAddresses.decrement(address);
+
+    assertEquals(addressV666ff, address);
+
+    for (int i = 0; i < 255; i++) {
+      address = InetAddresses.decrement(address);
+    }
+    assertEquals(addressV6660, address);
+
+    InetAddress addressV6000000 =
+        InetAddress.getByName("0:0:0:0:0:0:0:0");
+    address = addressV6000000;
+    try {
+      address = InetAddresses.decrement(address);
+      fail();
+    } catch (IllegalArgumentException expected) {}
+  }
 }
diff --git a/guava-tests/test/com/google/common/net/InternetDomainNameTest.java b/guava-tests/test/com/google/common/net/InternetDomainNameTest.java
index a63c147..91a4347 100644
--- a/guava-tests/test/com/google/common/net/InternetDomainNameTest.java
+++ b/guava-tests/test/com/google/common/net/InternetDomainNameTest.java
@@ -367,9 +367,9 @@
   }
 
   public void testExclusion() {
-    InternetDomainName domain = InternetDomainName.from("foo.nic.uk");
+    InternetDomainName domain = InternetDomainName.from("foo.teledata.mz");
     assertTrue(domain.hasPublicSuffix());
-    assertEquals("uk", domain.publicSuffix().toString());
+    assertEquals("mz", domain.publicSuffix().toString());
 
     // Behold the weirdness!
     assertFalse(domain.publicSuffix().isPublicSuffix());
diff --git a/guava-tests/test/com/google/common/primitives/DoublesTest.java b/guava-tests/test/com/google/common/primitives/DoublesTest.java
index 9f04471..3ee962f 100644
--- a/guava-tests/test/com/google/common/primitives/DoublesTest.java
+++ b/guava-tests/test/com/google/common/primitives/DoublesTest.java
@@ -16,8 +16,8 @@
 
 package com.google.common.primitives;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.lang.Double.NaN;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -50,11 +50,10 @@
 
   private static final double LEAST = Double.NEGATIVE_INFINITY;
   private static final double GREATEST = Double.POSITIVE_INFINITY;
-  private static final double MIN_NORMAL = 2.2250738585072014E-308; // Doubles.MIN_NORMAL from 1.6
 
   private static final double[] NUMBERS = new double[] {
       LEAST, -Double.MAX_VALUE, -1.0, -0.5, -0.1, -0.0, 0.0, 0.1, 0.5, 1.0,
-      Double.MAX_VALUE, GREATEST, MIN_NORMAL, -MIN_NORMAL,
+      Double.MAX_VALUE, GREATEST, Double.MIN_NORMAL, -Double.MIN_NORMAL,
       Double.MIN_VALUE, -Double.MIN_VALUE, Integer.MIN_VALUE,
       Integer.MAX_VALUE, Long.MIN_VALUE, Long.MAX_VALUE
   };
@@ -370,7 +369,7 @@
     list.set(0, (double) 2);
     assertTrue(Arrays.equals(new double[] {(double) 2, (double) 1}, array));
     array[1] = (double) 3;
-    ASSERT.that(list).has().exactly((double) 2, (double) 3).inOrder();
+    assertThat(list).has().exactly((double) 2, (double) 3).inOrder();
   }
 
   public void testAsList_toArray_roundTrip() {
diff --git a/guava-tests/test/com/google/common/primitives/FloatsTest.java b/guava-tests/test/com/google/common/primitives/FloatsTest.java
index 2b0c441..2584328 100644
--- a/guava-tests/test/com/google/common/primitives/FloatsTest.java
+++ b/guava-tests/test/com/google/common/primitives/FloatsTest.java
@@ -16,8 +16,8 @@
 
 package com.google.common.primitives;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.lang.Float.NaN;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
@@ -50,11 +50,10 @@
 
   private static final float LEAST = Float.NEGATIVE_INFINITY;
   private static final float GREATEST = Float.POSITIVE_INFINITY;
-  private static final float MIN_NORMAL = 1.17549435E-38f; // Doubles.MIN_NORMAL from 1.6
 
   private static final float[] NUMBERS = new float[] {
       LEAST, -Float.MAX_VALUE, -1f, -0f, 0f, 1f, Float.MAX_VALUE, GREATEST,
-      MIN_NORMAL, -MIN_NORMAL,  Float.MIN_VALUE, -Float.MIN_VALUE,
+      Float.MIN_NORMAL, -Float.MIN_NORMAL,  Float.MIN_VALUE, -Float.MIN_VALUE,
       Integer.MIN_VALUE, Integer.MAX_VALUE, Long.MIN_VALUE, Long.MAX_VALUE
   };
 
@@ -361,7 +360,7 @@
     list.set(0, (float) 2);
     assertTrue(Arrays.equals(new float[] {(float) 2, (float) 1}, array));
     array[1] = (float) 3;
-    ASSERT.that(list).has().exactly((float) 2, (float) 3).inOrder();
+    assertThat(list).has().exactly((float) 2, (float) 3).inOrder();
   }
 
   public void testAsList_toArray_roundTrip() {
diff --git a/guava-tests/test/com/google/common/primitives/IntsTest.java b/guava-tests/test/com/google/common/primitives/IntsTest.java
index a475739..58279e6 100644
--- a/guava-tests/test/com/google/common/primitives/IntsTest.java
+++ b/guava-tests/test/com/google/common/primitives/IntsTest.java
@@ -463,7 +463,6 @@
     tester.testAllPublicInstanceMethods(Ints.stringConverter());
   }
 
-  @GwtIncompatible("AndroidInteger")
   public void testTryParse() {
     tryParseAndAssertEquals(0, "0");
     tryParseAndAssertEquals(0, "-0");
@@ -479,8 +478,14 @@
     assertNull(Ints.tryParse("9999999999999999"));
     assertNull("Max integer + 1",
         Ints.tryParse(Long.toString(((long) GREATEST) + 1)));
+    assertNull("Max integer * 10",
+        Ints.tryParse(Long.toString(((long) GREATEST) * 10)));
     assertNull("Min integer - 1",
         Ints.tryParse(Long.toString(((long) LEAST) - 1)));
+    assertNull("Min integer * 10",
+        Ints.tryParse(Long.toString(((long) LEAST) * 10)));
+    assertNull("Max long", Ints.tryParse(Long.toString(Long.MAX_VALUE)));
+    assertNull("Min long", Ints.tryParse(Long.toString(Long.MIN_VALUE)));
     assertNull(Ints.tryParse("\u0662\u06f3"));
   }
 
@@ -488,7 +493,6 @@
    * Applies {@link Ints#tryParse(String)} to the given string and asserts that
    * the result is as expected.
    */
-  @GwtIncompatible("AndroidInteger")
   private static void tryParseAndAssertEquals(Integer expected, String value) {
     assertEquals(expected, Ints.tryParse(value));
   }
diff --git a/guava-tests/test/com/google/common/primitives/LongsTest.java b/guava-tests/test/com/google/common/primitives/LongsTest.java
index 6f490d7..7575a14 100644
--- a/guava-tests/test/com/google/common/primitives/LongsTest.java
+++ b/guava-tests/test/com/google/common/primitives/LongsTest.java
@@ -446,7 +446,6 @@
     tester.testAllPublicInstanceMethods(Longs.stringConverter());
   }
 
-  @GwtIncompatible("AndroidInteger")
   public void testTryParse() {
     tryParseAndAssertEquals(0L, "0");
     tryParseAndAssertEquals(0L, "-0");
@@ -460,10 +459,14 @@
     assertNull(Longs.tryParse("-"));
     assertNull(Longs.tryParse("+1"));
     assertNull(Longs.tryParse("999999999999999999999999"));
-    assertNull("Max integer + 1",
+    assertNull("Max long + 1",
         Longs.tryParse(BigInteger.valueOf(MAX_VALUE).add(BigInteger.ONE).toString()));
-    assertNull("Min integer - 1",
+    assertNull("Max long * 10",
+        Longs.tryParse(BigInteger.valueOf(MAX_VALUE).multiply(BigInteger.TEN).toString()));
+    assertNull("Min long - 1",
         Longs.tryParse(BigInteger.valueOf(MIN_VALUE).subtract(BigInteger.ONE).toString()));
+    assertNull("Min long * 10",
+        Longs.tryParse(BigInteger.valueOf(MIN_VALUE).multiply(BigInteger.TEN).toString()));
     assertNull(Longs.tryParse("\u0662\u06f3"));
   }
 
diff --git a/guava-tests/test/com/google/common/reflect/ClassPathTest.java b/guava-tests/test/com/google/common/reflect/ClassPathTest.java
index bd63635..f492409 100644
--- a/guava-tests/test/com/google/common/reflect/ClassPathTest.java
+++ b/guava-tests/test/com/google/common/reflect/ClassPathTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.reflect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.base.Charsets;
 import com.google.common.collect.ImmutableMap;
@@ -31,6 +31,7 @@
 import com.google.common.testing.NullPointerTester;
 
 import junit.framework.TestCase;
+
 import org.junit.Test;
 
 import java.io.ByteArrayInputStream;
@@ -60,20 +61,19 @@
     Map<String, ResourceInfo> byToString = Maps.newHashMap();
     ClassPath classpath = ClassPath.from(getClass().getClassLoader());
     for (ResourceInfo resource : classpath.getResources()) {
-      ASSERT.that(resource.getResourceName()).isNotEqualTo(JarFile.MANIFEST_NAME);
-      ASSERT.that(resource.toString()).isNotEqualTo(JarFile.MANIFEST_NAME);
+      assertThat(resource.getResourceName()).isNotEqualTo(JarFile.MANIFEST_NAME);
+      assertThat(resource.toString()).isNotEqualTo(JarFile.MANIFEST_NAME);
       byName.put(resource.getResourceName(), resource);
       byToString.put(resource.toString(), resource);
-      // TODO: This will fail on maven resources in the classes directory on a mac.
-      // assertNotNull(resource.url());
+      assertNotNull(resource.url());
     }
     String testResourceName = "com/google/common/reflect/test.txt";
-    ASSERT.that(byName.keySet()).has().allOf(
+    assertThat(byName.keySet()).has().allOf(
         "com/google/common/reflect/ClassPath.class",
         "com/google/common/reflect/ClassPathTest.class",
         "com/google/common/reflect/ClassPathTest$Nested.class",
         testResourceName);
-    ASSERT.that(byToString.keySet()).has().allOf(
+    assertThat(byToString.keySet()).has().allOf(
         "com.google.common.reflect.ClassPath",
         "com.google.common.reflect.ClassPathTest",
         "com.google.common.reflect.ClassPathTest$Nested",
@@ -101,14 +101,14 @@
     }
     class LocalClass {}
     Class<?> anonymousClass = new Object() {}.getClass();
-    ASSERT.that(names).has().allOf(anonymousClass.getName(), LocalClass.class.getName(),
+    assertThat(names).has().allOf(anonymousClass.getName(), LocalClass.class.getName(),
         ClassPath.class.getName(), ClassPathTest.class.getName());
-    ASSERT.that(strings).has().allOf(anonymousClass.getName(), LocalClass.class.getName(),
+    assertThat(strings).has().allOf(anonymousClass.getName(), LocalClass.class.getName(),
         ClassPath.class.getName(), ClassPathTest.class.getName());
-    ASSERT.that(classes).has().allOf(anonymousClass, LocalClass.class, ClassPath.class,
+    assertThat(classes).has().allOf(anonymousClass, LocalClass.class, ClassPath.class,
         ClassPathTest.class);
-    ASSERT.that(packageNames).has().exactly(ClassPath.class.getPackage().getName());
-    ASSERT.that(simpleNames).has().allOf("", "Local", "ClassPath", "ClassPathTest");
+    assertThat(packageNames).has().exactly(ClassPath.class.getPackage().getName());
+    assertThat(simpleNames).has().allOf("", "Local", "ClassPath", "ClassPathTest");
   }
 
   public void testGetTopLevelClasses() throws Exception {
@@ -126,11 +126,11 @@
       packageNames.add(classInfo.getPackageName());
       simpleNames.add(classInfo.getSimpleName());
     }
-    ASSERT.that(names).has().allOf(ClassPath.class.getName(), ClassPathTest.class.getName());
-    ASSERT.that(strings).has().allOf(ClassPath.class.getName(), ClassPathTest.class.getName());
-    ASSERT.that(classes).has().allOf(ClassPath.class, ClassPathTest.class);
-    ASSERT.that(packageNames).has().item(ClassPath.class.getPackage().getName());
-    ASSERT.that(simpleNames).has().allOf("ClassPath", "ClassPathTest");
+    assertThat(names).has().allOf(ClassPath.class.getName(), ClassPathTest.class.getName());
+    assertThat(strings).has().allOf(ClassPath.class.getName(), ClassPathTest.class.getName());
+    assertThat(classes).has().allOf(ClassPath.class, ClassPathTest.class);
+    assertThat(packageNames).has().item(ClassPath.class.getPackage().getName());
+    assertThat(simpleNames).has().allOf("ClassPath", "ClassPathTest");
     assertFalse(classes.contains(ClassInSubPackage.class));
   }
 
@@ -144,7 +144,7 @@
       }
       classes.add(classInfo.load());
     }
-    ASSERT.that(classes).has().allOf(ClassPathTest.class, ClassInSubPackage.class);
+    assertThat(classes).has().allOf(ClassPathTest.class, ClassInSubPackage.class);
   }
 
   public void testGetTopLevelClasses_diamond() throws Exception {
@@ -168,7 +168,7 @@
   }
 
   public void testClassPathEntries_emptyURLClassLoader_noParent() {
-    ASSERT.that(ClassPath.getClassPathEntries(new URLClassLoader(new URL[0], null)).keySet())
+    assertThat(ClassPath.getClassPathEntries(new URLClassLoader(new URL[0], null)).keySet())
         .isEmpty();
   }
 
@@ -188,7 +188,7 @@
     URLClassLoader child = new URLClassLoader(new URL[] {url2}, parent) {};
     ImmutableMap<URI, ClassLoader> classPathEntries = ClassPath.getClassPathEntries(child);
     assertEquals(ImmutableMap.of(url1.toURI(), parent, url2.toURI(), child),  classPathEntries);
-    ASSERT.that(classPathEntries.keySet()).has().exactly(url1.toURI(), url2.toURI()).inOrder();
+    assertThat(classPathEntries.keySet()).has().exactly(url1.toURI(), url2.toURI()).inOrder();
   }
 
   public void testClassPathEntries_duplicateUri_parentWins() throws Exception {
@@ -199,7 +199,7 @@
   }
 
   public void testClassPathEntries_notURLClassLoader_noParent() {
-    ASSERT.that(ClassPath.getClassPathEntries(new ClassLoader(null) {}).keySet()).isEmpty();
+    assertThat(ClassPath.getClassPathEntries(new ClassLoader(null) {}).keySet()).isEmpty();
   }
 
   public void testClassPathEntries_notURLClassLoader_withParent() throws Exception {
@@ -245,7 +245,7 @@
     ClassLoader classLoader = ClassPathTest.class.getClassLoader();
     ClassPath.Scanner scanner = new ClassPath.Scanner();
     scanner.scanFrom(new File("no/such/file/anywhere"), classLoader);
-    ASSERT.that(scanner.getResources()).isEmpty();
+    assertThat(scanner.getResources()).isEmpty();
   }
 
   public void testScanFromFile_notJarFile() throws IOException {
@@ -257,7 +257,7 @@
     } finally {
       notJar.delete();
     }
-    ASSERT.that(scanner.getResources()).isEmpty();
+    assertThat(scanner.getResources()).isEmpty();
   }
 
   public void testGetClassPathEntry() throws URISyntaxException {
@@ -273,25 +273,25 @@
   }
 
   public void testGetClassPathFromManifest_nullManifest() {
-    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(new File("some.jar"), null)).isEmpty();
+    assertThat(ClassPath.Scanner.getClassPathFromManifest(new File("some.jar"), null)).isEmpty();
   }
 
   public void testGetClassPathFromManifest_noClassPath() throws IOException {
     File jarFile = new File("base.jar");
-    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest("")))
+    assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest("")))
         .isEmpty();
   }
 
   public void testGetClassPathFromManifest_emptyClassPath() throws IOException {
     File jarFile = new File("base.jar");
-    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifestClasspath("")))
+    assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifestClasspath("")))
         .isEmpty();
   }
 
   public void testGetClassPathFromManifest_badClassPath() throws IOException {
     File jarFile = new File("base.jar");
     Manifest manifest = manifestClasspath("an_invalid^path");
-    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
+    assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
         .isEmpty();
   }
 
@@ -299,7 +299,7 @@
     File jarFile = new File("base/some.jar");
     // with/relative/directory is the Class-Path value in the mf file.
     Manifest manifest = manifestClasspath("with/relative/dir");
-    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
+    assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
         .has().exactly(new File("base/with/relative/dir").toURI()).inOrder();
   }
 
@@ -307,7 +307,7 @@
     File jarFile = new File("base/some.jar");
     // with/relative/directory is the Class-Path value in the mf file.
     Manifest manifest = manifestClasspath("with/relative.jar");
-    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
+    assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
         .has().exactly(new File("base/with/relative.jar").toURI()).inOrder();
   }
 
@@ -315,28 +315,28 @@
     File jarFile = new File("base/some.jar");
     // with/relative/directory is the Class-Path value in the mf file.
     Manifest manifest = manifestClasspath("current.jar");
-    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
+    assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
         .has().exactly(new File("base/current.jar").toURI()).inOrder();
   }
 
   public void testGetClassPathFromManifest_absoluteDirectory() throws IOException {
     File jarFile = new File("base/some.jar");
     Manifest manifest = manifestClasspath("file:/with/absolute/dir");
-    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
+    assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
         .has().exactly(new File("/with/absolute/dir").toURI()).inOrder();
   }
 
   public void testGetClassPathFromManifest_absoluteJar() throws IOException {
     File jarFile = new File("base/some.jar");
     Manifest manifest = manifestClasspath("file:/with/absolute.jar");
-    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
+    assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
         .has().exactly(new File("/with/absolute.jar").toURI()).inOrder();
   }
 
   public void testGetClassPathFromManifest_multiplePaths() throws IOException {
     File jarFile = new File("base/some.jar");
     Manifest manifest = manifestClasspath("file:/with/absolute.jar relative.jar  relative/dir");
-    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
+    assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
         .has().exactly(
             new File("/with/absolute.jar").toURI(),
             new File("base/relative.jar").toURI(),
@@ -347,14 +347,14 @@
   public void testGetClassPathFromManifest_leadingBlanks() throws IOException {
     File jarFile = new File("base/some.jar");
     Manifest manifest = manifestClasspath(" relative.jar");
-    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
+    assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
         .has().exactly(new File("base/relative.jar").toURI()).inOrder();
   }
 
   public void testGetClassPathFromManifest_trailingBlanks() throws IOException {
     File jarFile = new File("base/some.jar");
     Manifest manifest = manifestClasspath("relative.jar ");
-    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
+    assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
         .has().exactly(new File("base/relative.jar").toURI()).inOrder();
   }
 
@@ -451,7 +451,7 @@
   }
 
   private static Manifest manifest(String content) throws IOException {
-    InputStream in = new ByteArrayInputStream(content.getBytes(Charsets.US_ASCII.name()));
+    InputStream in = new ByteArrayInputStream(content.getBytes(Charsets.US_ASCII));
     Manifest manifest = new Manifest();
     manifest.read(in);
     return manifest;
diff --git a/guava-tests/test/com/google/common/reflect/ImmutableTypeToInstanceMapTest.java b/guava-tests/test/com/google/common/reflect/ImmutableTypeToInstanceMapTest.java
index d3937da..d622b22 100644
--- a/guava-tests/test/com/google/common/reflect/ImmutableTypeToInstanceMapTest.java
+++ b/guava-tests/test/com/google/common/reflect/ImmutableTypeToInstanceMapTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.reflect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Maps;
@@ -109,7 +109,7 @@
             .put(type, array)
             .build();
     assertEquals(1, map.size());
-    ASSERT.that(map.getInstance(type)).has().exactly(array[0]).inOrder();
+    assertThat(map.getInstance(type)).asList().has().exactly(array[0]).inOrder();
   }
 
   public void testWildcardType() {
diff --git a/guava-tests/test/com/google/common/reflect/MutableTypeToInstanceMapTest.java b/guava-tests/test/com/google/common/reflect/MutableTypeToInstanceMapTest.java
index f2bd5b0..26f702e 100644
--- a/guava-tests/test/com/google/common/reflect/MutableTypeToInstanceMapTest.java
+++ b/guava-tests/test/com/google/common/reflect/MutableTypeToInstanceMapTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.reflect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -194,13 +194,13 @@
     assertEquals(ImmutableList.of(1), map.getInstance(type));
   }
 
-  public void testGeneriArrayType() {
+  public void testGenericArrayType() {
     @SuppressWarnings("unchecked") // Trying to test generic array
     ImmutableList<Integer>[] array = new ImmutableList[] {ImmutableList.of(1)};
     TypeToken<ImmutableList<Integer>[]> type = new TypeToken<ImmutableList<Integer>[]>() {};
     map.putInstance(type, array);
     assertEquals(1, map.size());
-    ASSERT.that(map.getInstance(type)).has().exactly(array[0]).inOrder();
+    assertThat(map.getInstance(type)).asList().has().exactly(array[0]).inOrder();
   }
 
   public void testWildcardType() {
diff --git a/guava-tests/test/com/google/common/reflect/TypeTokenResolutionTest.java b/guava-tests/test/com/google/common/reflect/TypeTokenResolutionTest.java
index 2c7e050..bf9dd11 100644
--- a/guava-tests/test/com/google/common/reflect/TypeTokenResolutionTest.java
+++ b/guava-tests/test/com/google/common/reflect/TypeTokenResolutionTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.reflect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
@@ -124,7 +124,7 @@
         parameterized.parameterizedType());
     assertEquals(TypeTokenResolutionTest.class, resolved.getOwnerType());
     assertEquals(Bar.class, resolved.getRawType());
-    ASSERT.that(resolved.getActualTypeArguments()).has().item(String.class);
+    assertThat(resolved.getActualTypeArguments()).asList().has().item(String.class);
   }
   
   private interface StringListPredicate extends Predicate<List<String>> {}
diff --git a/guava-tests/test/com/google/common/reflect/TypeTokenTest.java b/guava-tests/test/com/google/common/reflect/TypeTokenTest.java
index a4a869c..893a054 100644
--- a/guava-tests/test/com/google/common/reflect/TypeTokenTest.java
+++ b/guava-tests/test/com/google/common/reflect/TypeTokenTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.reflect;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
@@ -27,11 +27,10 @@
 import com.google.common.testing.EqualsTester;
 import com.google.common.testing.NullPointerTester;
 import com.google.common.testing.SerializableTester;
+import com.google.common.truth.CollectionSubject;
 
 import junit.framework.TestCase;
 
-import org.truth0.subjects.CollectionSubject;
-
 import java.io.Serializable;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.GenericArrayType;
@@ -161,39 +160,39 @@
 
   public void testGetTypes_noSuperclass() {
     TypeToken<Object>.TypeSet types = new TypeToken<Object>() {}.getTypes();
-    ASSERT.that(types).has().item(TypeToken.of(Object.class));
-    ASSERT.that(types.rawTypes()).has().item(Object.class);
-    ASSERT.that(types.interfaces()).isEmpty();
-    ASSERT.that(types.interfaces().rawTypes()).isEmpty();
-    ASSERT.that(types.classes()).has().item(TypeToken.of(Object.class));
-    ASSERT.that(types.classes().rawTypes()).has().item(Object.class);
+    assertThat(types).has().item(TypeToken.of(Object.class));
+    assertThat(types.rawTypes()).has().item(Object.class);
+    assertThat(types.interfaces()).isEmpty();
+    assertThat(types.interfaces().rawTypes()).isEmpty();
+    assertThat(types.classes()).has().item(TypeToken.of(Object.class));
+    assertThat(types.classes().rawTypes()).has().item(Object.class);
   }
 
   public void testGetTypes_fromInterface() {
     TypeToken<Interface1>.TypeSet types = new TypeToken<Interface1>() {}.getTypes();
-    ASSERT.that(types).has().item(TypeToken.of(Interface1.class));
-    ASSERT.that(types.rawTypes()).has().item(Interface1.class);
-    ASSERT.that(types.interfaces()).has().item(TypeToken.of(Interface1.class));
-    ASSERT.that(types.interfaces().rawTypes()).has().item(Interface1.class);
-    ASSERT.that(types.classes()).isEmpty();
-    ASSERT.that(types.classes().rawTypes()).isEmpty();
+    assertThat(types).has().item(TypeToken.of(Interface1.class));
+    assertThat(types.rawTypes()).has().item(Interface1.class);
+    assertThat(types.interfaces()).has().item(TypeToken.of(Interface1.class));
+    assertThat(types.interfaces().rawTypes()).has().item(Interface1.class);
+    assertThat(types.classes()).isEmpty();
+    assertThat(types.classes().rawTypes()).isEmpty();
   }
 
   public void testGetTypes_fromPrimitive() {
     TypeToken<Integer>.TypeSet types = TypeToken.of(int.class).getTypes();
-    ASSERT.that(types).has().item(TypeToken.of(int.class));
-    ASSERT.that(types.rawTypes()).has().item(int.class);
-    ASSERT.that(types.interfaces()).isEmpty();
-    ASSERT.that(types.interfaces().rawTypes()).isEmpty();
-    ASSERT.that(types.classes()).has().item(TypeToken.of(int.class));
-    ASSERT.that(types.classes().rawTypes()).has().item(int.class);
+    assertThat(types).has().item(TypeToken.of(int.class));
+    assertThat(types.rawTypes()).has().item(int.class);
+    assertThat(types.interfaces()).isEmpty();
+    assertThat(types.interfaces().rawTypes()).isEmpty();
+    assertThat(types.classes()).has().item(TypeToken.of(int.class));
+    assertThat(types.classes().rawTypes()).has().item(int.class);
   }
 
   public void testGetTypes_withInterfacesAndSuperclasses() {
     abstract class Class2 extends Class1 implements Interface12 {}
     abstract class Class3<T> extends Class2 implements Interface3<T> {}
     TypeToken<Class3<String>>.TypeSet types = new TypeToken<Class3<String>>() {}.getTypes();
-    assertThat(types).has().exactly(
+    makeUnmodifiable(types).has().exactly(
         new TypeToken<Class3<String>>() {},
         new TypeToken<Interface3<String>>() {},
         new TypeToken<Iterable<String>>() {},
@@ -203,13 +202,13 @@
         TypeToken.of(Interface2.class),
         TypeToken.of(Class1.class),
         TypeToken.of(Object.class));
-    assertThat(types.interfaces()).has().exactly(
+    makeUnmodifiable(types.interfaces()).has().exactly(
         new TypeToken<Interface3<String>>() {},
         TypeToken.of(Interface12.class),
         TypeToken.of(Interface1.class),
         TypeToken.of(Interface2.class),
         new TypeToken<Iterable<String>>() {});
-    assertThat(types.classes()).has().exactly(
+    makeUnmodifiable(types.classes()).has().exactly(
         new TypeToken<Class3<String>>() {},
         TypeToken.of(Class2.class),
         TypeToken.of(Class1.class),
@@ -221,7 +220,7 @@
     abstract class Class2 extends Class1 implements Interface12 {}
     abstract class Class3<T> extends Class2 implements Interface3<T> {}
     TypeToken<Class3<String>>.TypeSet types = new TypeToken<Class3<String>>() {}.getTypes();
-    assertThat(types.rawTypes()).has().exactly(
+    makeUnmodifiable(types.rawTypes()).has().exactly(
         Class3.class, Interface3.class,
         Iterable.class,
         Class2.class,
@@ -230,13 +229,13 @@
         Interface2.class,
         Class1.class,
         Object.class);
-    assertThat(types.interfaces().rawTypes()).has().exactly(
+    makeUnmodifiable(types.interfaces().rawTypes()).has().exactly(
         Interface3.class,
         Interface12.class,
         Interface1.class,
         Interface2.class,
         Iterable.class);
-    assertThat(types.classes().rawTypes()).has().exactly(
+    makeUnmodifiable(types.classes().rawTypes()).has().exactly(
         Class3.class,
         Class2.class,
         Class1.class,
@@ -247,14 +246,14 @@
   public <A extends Class1 & Interface1, B extends A>
   void testGetTypes_ignoresTypeVariablesByDefault() {
     TypeToken<?>.TypeSet types = TypeToken.of(new TypeCapture<B>() {}.capture()).getTypes();
-    assertThat(types).has().exactly(
+    makeUnmodifiable(types).has().exactly(
         TypeToken.of(Interface1.class), TypeToken.of(Class1.class),
         TypeToken.of(Object.class));
     assertSubtypeFirst(types);
-    assertThat(types.interfaces())
+    makeUnmodifiable(types.interfaces())
         .has().exactly(TypeToken.of(Interface1.class))
         .inOrder();
-    assertThat(types.classes())
+    makeUnmodifiable(types.classes())
         .has().exactly(TypeToken.of(Class1.class), TypeToken.of(Object.class))
         .inOrder();
   }
@@ -262,12 +261,12 @@
   public <A extends Class1 & Interface1, B extends A>
   void testGetTypes_rawTypes_ignoresTypeVariablesByDefault() {
     TypeToken<?>.TypeSet types = TypeToken.of(new TypeCapture<B>() {}.capture()).getTypes();
-    assertThat(types.rawTypes())
+    makeUnmodifiable(types.rawTypes())
         .has().exactly(Interface1.class, Class1.class, Object.class);
-    assertThat(types.interfaces().rawTypes())
+    makeUnmodifiable(types.interfaces().rawTypes())
         .has().exactly(Interface1.class)
         .inOrder();
-    assertThat(types.classes().rawTypes())
+    makeUnmodifiable(types.classes().rawTypes())
         .has().exactly(Class1.class, Object.class)
         .inOrder();
   }
@@ -275,7 +274,7 @@
   public <A extends Interface1 & Interface2 & Interface3<String>>
   void testGetTypes_manyBounds() {
     TypeToken<?>.TypeSet types = TypeToken.of(new TypeCapture<A>() {}.capture()).getTypes();
-    assertThat(types.rawTypes())
+    makeUnmodifiable(types.rawTypes())
         .has().exactly(Interface1.class, Interface2.class, Interface3.class, Iterable.class);
   }
 
@@ -466,75 +465,75 @@
   }
 
   public <T> void testGetGenericInterfaces_typeVariable_unbounded() {
-    ASSERT.that(TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericInterfaces()).isEmpty();
+    assertThat(TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericInterfaces()).isEmpty();
     assertHasArrayInterfaces(new TypeToken<T[]>() {});
   }
 
   public <T extends NoInterface> void testGetGenericInterfaces_typeVariable_boundIsClass() {
-    ASSERT.that(TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericInterfaces()).isEmpty();
+    assertThat(TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericInterfaces()).isEmpty();
     assertHasArrayInterfaces(new TypeToken<T[]>() {});
   }
 
   public <T extends NoInterface&Iterable<String>>
   void testGetGenericInterfaces_typeVariable_boundsAreClassWithInterface() {
-    assertThat(TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericInterfaces())
+    makeUnmodifiable(TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericInterfaces())
         .has().exactly(new TypeToken<Iterable<String>>() {});
     assertHasArrayInterfaces(new TypeToken<T[]>() {});
   }
 
   public <T extends CharSequence&Iterable<String>>
   void testGetGenericInterfaces_typeVariable_boundsAreInterfaces() {
-    assertThat(TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericInterfaces())
+    makeUnmodifiable(TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericInterfaces())
         .has().exactly(TypeToken.of(CharSequence.class), new TypeToken<Iterable<String>>() {});
     assertHasArrayInterfaces(new TypeToken<T[]>() {});
   }
 
   public <T extends CharSequence&Iterable<T>>
   void testGetGenericInterfaces_typeVariable_boundsAreFBoundedInterfaces() {
-    assertThat(TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericInterfaces())
+    makeUnmodifiable(TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericInterfaces())
         .has().exactly(TypeToken.of(CharSequence.class), new TypeToken<Iterable<T>>() {});
     assertHasArrayInterfaces(new TypeToken<T[]>() {});
   }
 
   public <T extends Base&Iterable<T>>
   void testGetGenericInterfaces_typeVariable_boundsAreClassWithFBoundedInterface() {
-    assertThat(TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericInterfaces())
+    makeUnmodifiable(TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericInterfaces())
         .has().exactly(new TypeToken<Iterable<T>>() {});
     assertHasArrayInterfaces(new TypeToken<T[]>() {});
   }
 
   public <T extends NoInterface, T1 extends T, T2 extends T1>
   void testGetGenericInterfaces_typeVariable_boundIsTypeVariableAndClass() {
-    ASSERT.that(TypeToken.of(new TypeCapture<T2>() {}.capture()).getGenericInterfaces()).isEmpty();
+    assertThat(TypeToken.of(new TypeCapture<T2>() {}.capture()).getGenericInterfaces()).isEmpty();
     assertHasArrayInterfaces(new TypeToken<T2[]>() {});
   }
 
   public <T extends Iterable<T>, T1 extends T, T2 extends T1>
   void testGetGenericInterfaces_typeVariable_boundIsTypeVariableAndInterface() {
-    assertThat(TypeToken.of(new TypeCapture<T2>() {}.capture()).getGenericInterfaces())
+    makeUnmodifiable(TypeToken.of(new TypeCapture<T2>() {}.capture()).getGenericInterfaces())
         .has().exactly(TypeToken.of(new TypeCapture<T1>() {}.capture()));
     assertHasArrayInterfaces(new TypeToken<T2[]>() {});
   }
 
   public void testGetGenericInterfaces_wildcard_lowerBounded() {
-    ASSERT.that(TypeToken.of(Types.supertypeOf(String.class)).getGenericInterfaces()).isEmpty();
-    ASSERT.that(TypeToken.of(Types.supertypeOf(String[].class)).getGenericInterfaces()).isEmpty();
+    assertThat(TypeToken.of(Types.supertypeOf(String.class)).getGenericInterfaces()).isEmpty();
+    assertThat(TypeToken.of(Types.supertypeOf(String[].class)).getGenericInterfaces()).isEmpty();
   }
 
   public void testGetGenericInterfaces_wildcard_boundIsClass() {
-    ASSERT.that(TypeToken.of(Types.subtypeOf(Object.class)).getGenericInterfaces()).isEmpty();
-    ASSERT.that(TypeToken.of(Types.subtypeOf(Object[].class)).getGenericInterfaces()).isEmpty();
+    assertThat(TypeToken.of(Types.subtypeOf(Object.class)).getGenericInterfaces()).isEmpty();
+    assertThat(TypeToken.of(Types.subtypeOf(Object[].class)).getGenericInterfaces()).isEmpty();
   }
 
   public void testGetGenericInterfaces_wildcard_boundIsInterface() {
     TypeToken<Iterable<String>> interfaceType = new TypeToken<Iterable<String>>() {};
-    assertThat(TypeToken.of(Types.subtypeOf(interfaceType.getType())).getGenericInterfaces())
+    makeUnmodifiable(TypeToken.of(Types.subtypeOf(interfaceType.getType())).getGenericInterfaces())
         .has().exactly(interfaceType);
     assertHasArrayInterfaces(new TypeToken<Iterable<String>[]>() {});
   }
 
   public void testGetGenericInterfaces_noInterface() {
-    ASSERT.that(new TypeToken<NoInterface>() {}.getGenericInterfaces()).isEmpty();
+    assertThat(new TypeToken<NoInterface>() {}.getGenericInterfaces()).isEmpty();
     assertHasArrayInterfaces(new TypeToken<NoInterface[]>() {});
   }
 
@@ -1204,7 +1203,7 @@
     TypeToken<?> matrixType = type.resolveType(
         Holder.class.getDeclaredField("matrix").getGenericType());
     assertEquals(List[].class, matrixType.getRawType());
-    ASSERT.that(matrixType.getType())
+    assertThat(matrixType.getType())
         .isNotEqualTo(new TypeToken<List<?>[]>() {}.getType());
   }
 
@@ -1278,7 +1277,7 @@
       throws NoSuchMethodException {
     Method failMethod = Loser.class.getMethod("lose");
     Invokable<T, ?> invokable = new TypeToken<T>(getClass()) {}.method(failMethod);
-    ASSERT.that(invokable.getExceptionTypes()).has().item(TypeToken.of(AssertionError.class));
+    assertThat(invokable.getExceptionTypes()).has().item(TypeToken.of(AssertionError.class));
   }
 
   public void testConstructor_getOwnerType() throws NoSuchMethodException {
@@ -1344,7 +1343,7 @@
     @SuppressWarnings("rawtypes") // Reflection API skew
     Constructor<CannotConstruct> constructor = CannotConstruct.class.getConstructor();
     Invokable<T, ?> invokable = new TypeToken<T>(getClass()) {}.constructor(constructor);
-    ASSERT.that(invokable.getExceptionTypes()).has().item(TypeToken.of(AssertionError.class));
+    assertThat(invokable.getExceptionTypes()).has().item(TypeToken.of(AssertionError.class));
   }
 
   public void testRejectTypeVariable_class() {
@@ -1509,7 +1508,7 @@
   private static <T, X> TypeToken<T> substitute(TypeToken<T> type, Class<X> arg) {
     return type.where(new TypeParameter<X>() {}, arg);
   }
-  
+
   private abstract static class ToReproduceGenericSignatureFormatError<V> {
     private abstract class BaseOuter {
       abstract class BaseInner {}
@@ -1659,7 +1658,7 @@
   private static class Base implements BaseInterface {}
   private static class Sub extends Base {}
 
-  private static CollectionSubject<?, Object, ?> assertThat(Collection<?> actual) {
-    return ASSERT.that(Collections.<Object>unmodifiableCollection(actual));
+  private static CollectionSubject<?, Object, ?> makeUnmodifiable(Collection<?> actual) {
+    return assertThat(Collections.<Object>unmodifiableCollection(actual));
   }
 }
diff --git a/guava-tests/test/com/google/common/reflect/TypesTest.java b/guava-tests/test/com/google/common/reflect/TypesTest.java
index a41b6a9..8e223bc 100644
--- a/guava-tests/test/com/google/common/reflect/TypesTest.java
+++ b/guava-tests/test/com/google/common/reflect/TypesTest.java
@@ -16,8 +16,8 @@
 
 package com.google.common.reflect;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.collect.Lists;
 import com.google.common.testing.EqualsTester;
@@ -66,8 +66,8 @@
     assertEquals(jvmType.toString(), ourType.toString());
     assertEquals(jvmType.hashCode(), ourType.hashCode());
     assertEquals(HashMap.class, ourType.getRawType());
-    ASSERT.that(ourType.getActualTypeArguments())
-        .iteratesOverSequence(jvmType.getActualTypeArguments());
+    assertThat(ourType.getActualTypeArguments()).asList()
+        .has().exactlyAs(asList(jvmType.getActualTypeArguments())).inOrder();
     assertEquals(Arrays.asList(
             String.class,
             Types.newArrayType(Types.newArrayType(int.class))),
@@ -107,8 +107,8 @@
     assertEquals(jvmType.toString(), ourType.toString());
     assertEquals(Map.class, ourType.getOwnerType());
     assertEquals(Map.Entry.class, ourType.getRawType());
-    ASSERT.that(ourType.getActualTypeArguments())
-        .iteratesOverSequence(jvmType.getActualTypeArguments());
+    assertThat(ourType.getActualTypeArguments()).asList()
+        .has().exactlyAs(asList(jvmType.getActualTypeArguments())).inOrder();
   }
 
   public void testNewParameterizedType_serializable() {
@@ -268,9 +268,9 @@
       WildcardType expected, WildcardType actual) {
     assertEquals(expected.toString(), actual.toString());
     assertEquals(actual.toString(), expected.hashCode(), actual.hashCode());
-    ASSERT.that(actual.getLowerBounds())
+    assertThat(actual.getLowerBounds()).asList()
         .has().exactlyAs(asList(expected.getLowerBounds())).inOrder();
-    ASSERT.that(actual.getUpperBounds())
+    assertThat(actual.getUpperBounds()).asList()
         .has().exactlyAs(asList(expected.getUpperBounds())).inOrder();
   }
 
@@ -366,7 +366,8 @@
     if (!Types.NativeTypeVariableEquals.NATIVE_TYPE_VARIABLE_ONLY) {
       assertEquals(actual.toString(), expected.hashCode(), actual.hashCode());
     }
-    ASSERT.that(actual.getBounds()).has().exactlyAs(asList(expected.getBounds())).inOrder();
+    assertThat(actual.getBounds()).asList()
+        .has().exactlyAs(asList(expected.getBounds())).inOrder();
   }
 
   /**
diff --git a/guava-tests/test/com/google/common/util/concurrent/AbstractFutureTest.java b/guava-tests/test/com/google/common/util/concurrent/AbstractFutureTest.java
index 4024a8e..166be3d 100644
--- a/guava-tests/test/com/google/common/util/concurrent/AbstractFutureTest.java
+++ b/guava-tests/test/com/google/common/util/concurrent/AbstractFutureTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.util.concurrent;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import junit.framework.AssertionFailedError;
 import junit.framework.TestCase;
@@ -153,11 +153,11 @@
     int index = findStackFrame(
         e, getClass().getName(), "getExpectingExecutionException");
 
-    ASSERT.that(index).isNotEqualTo(0);
+    assertThat(index).isNotEqualTo(0);
 
     // Above our method should be the call to get(). Don't assert on the class
     // because it could be some superclass.
-    ASSERT.that(e.getStackTrace()[index - 1].getMethodName()).isEqualTo("get");
+    assertThat(e.getStackTrace()[index - 1].getMethodName()).isEqualTo("get");
   }
 
   private static int findStackFrame(
diff --git a/guava-tests/test/com/google/common/util/concurrent/AbstractIdleServiceTest.java b/guava-tests/test/com/google/common/util/concurrent/AbstractIdleServiceTest.java
index eb159df..2dfad5c 100644
--- a/guava-tests/test/com/google/common/util/concurrent/AbstractIdleServiceTest.java
+++ b/guava-tests/test/com/google/common/util/concurrent/AbstractIdleServiceTest.java
@@ -16,7 +16,8 @@
 
 package com.google.common.util.concurrent;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
 
 import com.google.common.collect.Lists;
 
@@ -93,7 +94,7 @@
     service.startAsync().awaitRunning();
     assertEquals(1, service.startUpCalled);
     assertEquals(Service.State.RUNNING, service.state());
-    ASSERT.that(service.transitionStates).has().exactly(Service.State.STARTING).inOrder();
+    assertThat(service.transitionStates).has().exactly(Service.State.STARTING).inOrder();
   }
 
   public void testStart_failed() {
@@ -113,7 +114,7 @@
     }
     assertEquals(1, service.startUpCalled);
     assertEquals(Service.State.FAILED, service.state());
-    ASSERT.that(service.transitionStates).has().exactly(Service.State.STARTING).inOrder();
+    assertThat(service.transitionStates).has().exactly(Service.State.STARTING).inOrder();
   }
 
   public void testStop_withoutStart() {
@@ -122,7 +123,7 @@
     assertEquals(0, service.startUpCalled);
     assertEquals(0, service.shutDownCalled);
     assertEquals(Service.State.TERMINATED, service.state());
-    ASSERT.that(service.transitionStates).isEmpty();
+    assertThat(service.transitionStates).isEmpty();
   }
 
   public void testStop_afterStart() {
@@ -134,7 +135,7 @@
     assertEquals(1, service.startUpCalled);
     assertEquals(1, service.shutDownCalled);
     assertEquals(Service.State.TERMINATED, service.state());
-    ASSERT.that(service.transitionStates)
+    assertThat(service.transitionStates)
         .has().exactly(Service.State.STARTING, Service.State.STOPPING).inOrder();
   }
 
@@ -158,7 +159,7 @@
     assertEquals(1, service.startUpCalled);
     assertEquals(1, service.shutDownCalled);
     assertEquals(Service.State.FAILED, service.state());
-    ASSERT.that(service.transitionStates)
+    assertThat(service.transitionStates)
         .has().exactly(Service.State.STARTING, Service.State.STOPPING).inOrder();
   }
 
@@ -184,7 +185,7 @@
       service.startAsync().awaitRunning(1, TimeUnit.MILLISECONDS);
       fail("Expected timeout");
     } catch (TimeoutException e) {
-      ASSERT.that(e.getMessage()).contains(Service.State.STARTING.toString());
+      assertThat(e.getMessage()).contains(Service.State.STARTING.toString());
     }
   }
 
@@ -209,7 +210,7 @@
 
     @Override protected Executor executor() {
       transitionStates.add(state());
-      return MoreExecutors.sameThreadExecutor();
+      return directExecutor();
     }
   }
 }
diff --git a/guava-tests/test/com/google/common/util/concurrent/AbstractScheduledServiceTest.java b/guava-tests/test/com/google/common/util/concurrent/AbstractScheduledServiceTest.java
index 59ed10e..7c01d41 100644
--- a/guava-tests/test/com/google/common/util/concurrent/AbstractScheduledServiceTest.java
+++ b/guava-tests/test/com/google/common/util/concurrent/AbstractScheduledServiceTest.java
@@ -21,7 +21,6 @@
 
 import junit.framework.TestCase;
 
-import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.CyclicBarrier;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executors;
@@ -32,6 +31,7 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * Unit test for {@link AbstractScheduledService}.
@@ -149,71 +149,53 @@
   }
 
   public void testDefaultExecutorIsShutdownWhenServiceIsStopped() throws Exception {
-    final CountDownLatch terminationLatch = new CountDownLatch(1);
+    final AtomicReference<ScheduledExecutorService> executor = Atomics.newReference();
     AbstractScheduledService service = new AbstractScheduledService() {
-      volatile ScheduledExecutorService executorService;
       @Override protected void runOneIteration() throws Exception {}
 
       @Override protected ScheduledExecutorService executor() {
-        if (executorService == null) {
-          executorService = super.executor();
-          // Add a listener that will be executed after the listener that shuts down the executor.
-          addListener(new Listener() {
-            @Override public void terminated(State from) {
-              terminationLatch.countDown();
-            }
-            }, MoreExecutors.sameThreadExecutor());
-        }
-        return executorService;
+        executor.set(super.executor());
+        return executor.get();
       }
 
       @Override protected Scheduler scheduler() {
         return Scheduler.newFixedDelaySchedule(0, 1, TimeUnit.MILLISECONDS);
-      }};
+      }
+    };
 
-      service.startAsync();
-      assertFalse(service.executor().isShutdown());
-      service.awaitRunning();
-      service.stopAsync();
-      terminationLatch.await();
-      assertTrue(service.executor().isShutdown());
-      assertTrue(service.executor().awaitTermination(100, TimeUnit.MILLISECONDS));
+    service.startAsync();
+    assertFalse(service.executor().isShutdown());
+    service.awaitRunning();
+    service.stopAsync();
+    service.awaitTerminated();
+    assertTrue(executor.get().awaitTermination(100, TimeUnit.MILLISECONDS));
   }
 
   public void testDefaultExecutorIsShutdownWhenServiceFails() throws Exception {
-    final CountDownLatch failureLatch = new CountDownLatch(1);
+    final AtomicReference<ScheduledExecutorService> executor = Atomics.newReference();
     AbstractScheduledService service = new AbstractScheduledService() {
-      volatile ScheduledExecutorService executorService;
-      @Override protected void runOneIteration() throws Exception {}
-
       @Override protected void startUp() throws Exception {
         throw new Exception("Failed");
       }
 
+      @Override protected void runOneIteration() throws Exception {}
+
       @Override protected ScheduledExecutorService executor() {
-        if (executorService == null) {
-          executorService = super.executor();
-          // Add a listener that will be executed after the listener that shuts down the executor.
-          addListener(new Listener() {
-            @Override public void failed(State from, Throwable failure) {
-              failureLatch.countDown();
-            }
-            }, MoreExecutors.sameThreadExecutor());
-        }
-        return executorService;
+        executor.set(super.executor());
+        return executor.get();
       }
 
       @Override protected Scheduler scheduler() {
         return Scheduler.newFixedDelaySchedule(0, 1, TimeUnit.MILLISECONDS);
-      }};
+      }
+    };
 
-      try {
-        service.startAsync().awaitRunning();
-        fail("Expected service to fail during startup");
-      } catch (IllegalStateException expected) {}
-      failureLatch.await();
-      assertTrue(service.executor().isShutdown());
-      assertTrue(service.executor().awaitTermination(100, TimeUnit.MILLISECONDS));
+    try {
+      service.startAsync().awaitRunning();
+      fail("Expected service to fail during startup");
+    } catch (IllegalStateException expected) {}
+
+    assertTrue(executor.get().awaitTermination(100, TimeUnit.MILLISECONDS));
   }
 
   public void testSchedulerOnlyCalledOnce() throws Exception {
diff --git a/guava-tests/test/com/google/common/util/concurrent/AbstractServiceTest.java b/guava-tests/test/com/google/common/util/concurrent/AbstractServiceTest.java
index 5ebd205..1fdac38 100644
--- a/guava-tests/test/com/google/common/util/concurrent/AbstractServiceTest.java
+++ b/guava-tests/test/com/google/common/util/concurrent/AbstractServiceTest.java
@@ -16,6 +16,7 @@
 
 package com.google.common.util.concurrent;
 
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
 import static java.lang.Thread.currentThread;
 import static java.util.concurrent.TimeUnit.SECONDS;
 
@@ -258,7 +259,7 @@
       @Override public void stopping(State from) {
         stopppingCount.incrementAndGet();
       }
-    }, MoreExecutors.sameThreadExecutor());
+    }, directExecutor());
 
     service.startAsync();
     service.stopAsync();
@@ -686,7 +687,7 @@
     final StartFailingService service = new StartFailingService();
     service.startAsync();
     assertEquals(State.FAILED, service.state());
-    service.addListener(new RecordingListener(service), MoreExecutors.sameThreadExecutor());
+    service.addListener(new RecordingListener(service), directExecutor());
     Thread thread = new Thread() {
       @Override public void run() {
         // Internally stopAsync() grabs a lock, this could be any such method on AbstractService.
@@ -704,7 +705,7 @@
       @Override public void running() {
         service.awaitRunning();
       }
-    }, MoreExecutors.sameThreadExecutor());
+    }, directExecutor());
     service.startAsync().awaitRunning(LONG_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
     service.stopAsync();
   }
@@ -715,7 +716,7 @@
       @Override public void terminated(State from) {
         service.stopAsync().awaitTerminated();
       }
-    }, MoreExecutors.sameThreadExecutor());
+    }, directExecutor());
     service.startAsync().awaitRunning();
 
     Thread thread = new Thread() {
@@ -812,7 +813,7 @@
   private static class RecordingListener extends Listener {
     static RecordingListener record(Service service) {
       RecordingListener listener = new RecordingListener(service);
-      service.addListener(listener, MoreExecutors.sameThreadExecutor());
+      service.addListener(listener, directExecutor());
       return listener;
     }
 
diff --git a/guava-tests/test/com/google/common/util/concurrent/CycleDetectingLockFactoryTest.java b/guava-tests/test/com/google/common/util/concurrent/CycleDetectingLockFactoryTest.java
new file mode 100644
index 0000000..162d687
--- /dev/null
+++ b/guava-tests/test/com/google/common/util/concurrent/CycleDetectingLockFactoryTest.java
@@ -0,0 +1,578 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.util.concurrent;
+
+import com.google.common.base.Joiner;
+import com.google.common.util.concurrent.CycleDetectingLockFactory.Policies;
+import com.google.common.util.concurrent.CycleDetectingLockFactory.Policy;
+import com.google.common.util.concurrent.CycleDetectingLockFactory.PotentialDeadlockException;
+
+import junit.framework.TestCase;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Unittests for {@link CycleDetectingLockFactory}.
+ *
+ * @author Darick Tong
+ */
+public class CycleDetectingLockFactoryTest extends TestCase {
+
+  private ReentrantLock lockA;
+  private ReentrantLock lockB;
+  private ReentrantLock lockC;
+  private ReentrantReadWriteLock.ReadLock readLockA;
+  private ReentrantReadWriteLock.ReadLock readLockB;
+  private ReentrantReadWriteLock.ReadLock readLockC;
+  private ReentrantReadWriteLock.WriteLock writeLockA;
+  private ReentrantReadWriteLock.WriteLock writeLockB;
+  private ReentrantReadWriteLock.WriteLock writeLockC;
+  private ReentrantLock lock1;
+  private ReentrantLock lock2;
+  private ReentrantLock lock3;
+  private ReentrantLock lock01;
+  private ReentrantLock lock02;
+  private ReentrantLock lock03;
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    CycleDetectingLockFactory factory =
+        CycleDetectingLockFactory.newInstance(Policies.THROW);
+    lockA = factory.newReentrantLock("LockA");
+    lockB = factory.newReentrantLock("LockB");
+    lockC = factory.newReentrantLock("LockC");
+    ReentrantReadWriteLock readWriteLockA =
+        factory.newReentrantReadWriteLock("ReadWriteA");
+    ReentrantReadWriteLock readWriteLockB =
+        factory.newReentrantReadWriteLock("ReadWriteB");
+    ReentrantReadWriteLock readWriteLockC =
+        factory.newReentrantReadWriteLock("ReadWriteC");
+    readLockA = readWriteLockA.readLock();
+    readLockB = readWriteLockB.readLock();
+    readLockC = readWriteLockC.readLock();
+    writeLockA = readWriteLockA.writeLock();
+    writeLockB = readWriteLockB.writeLock();
+    writeLockC = readWriteLockC.writeLock();
+
+    CycleDetectingLockFactory.WithExplicitOrdering<MyOrder> factory2 =
+        newInstanceWithExplicitOrdering(MyOrder.class, Policies.THROW);
+    lock1 = factory2.newReentrantLock(MyOrder.FIRST);
+    lock2 = factory2.newReentrantLock(MyOrder.SECOND);
+    lock3 = factory2.newReentrantLock(MyOrder.THIRD);
+
+    CycleDetectingLockFactory.WithExplicitOrdering<OtherOrder> factory3 =
+        newInstanceWithExplicitOrdering(OtherOrder.class, Policies.THROW);
+    lock01 = factory3.newReentrantLock(OtherOrder.FIRST);
+    lock02 = factory3.newReentrantLock(OtherOrder.SECOND);
+    lock03 = factory3.newReentrantLock(OtherOrder.THIRD);
+  }
+
+  // In the unittest, create each ordered factory with its own set of lock
+  // graph nodes (as opposed to using the static per-Enum map) to avoid
+  // conflicts across different test runs.
+  private <E extends Enum<E>> CycleDetectingLockFactory.WithExplicitOrdering<E>
+      newInstanceWithExplicitOrdering(Class<E> enumClass, Policy policy) {
+    return new CycleDetectingLockFactory.WithExplicitOrdering<E>(
+        policy, CycleDetectingLockFactory.createNodes(enumClass));
+  }
+
+  public void testDeadlock_twoLocks() {
+    // Establish an acquisition order of lockA -> lockB.
+    lockA.lock();
+    lockB.lock();
+    lockA.unlock();
+    lockB.unlock();
+
+    // The opposite order should fail (Policies.THROW).
+    PotentialDeadlockException firstException = null;
+    lockB.lock();
+    try {
+      lockA.lock();
+      fail("Expected PotentialDeadlockException");
+    } catch (PotentialDeadlockException expected) {
+      checkMessage(expected, "LockB -> LockA", "LockA -> LockB");
+      firstException = expected;
+    }
+
+    // Second time should also fail, with a cached causal chain.
+    try {
+      lockA.lock();
+      fail("Expected PotentialDeadlockException");
+    } catch (PotentialDeadlockException expected) {
+      checkMessage(expected, "LockB -> LockA", "LockA -> LockB");
+      // The causal chain should be cached.
+      assertSame(firstException.getCause(), expected.getCause());
+    }
+
+    // lockA should work after lockB is released.
+    lockB.unlock();
+    lockA.lock();
+  }
+
+  // Tests transitive deadlock detection.
+  public void testDeadlock_threeLocks() {
+    // Establish an ordering from lockA -> lockB.
+    lockA.lock();
+    lockB.lock();
+    lockB.unlock();
+    lockA.unlock();
+
+    // Establish an ordering from lockB -> lockC.
+    lockB.lock();
+    lockC.lock();
+    lockB.unlock();
+
+    // lockC -> lockA should fail.
+    try {
+      lockA.lock();
+      fail("Expected PotentialDeadlockException");
+    } catch (PotentialDeadlockException expected) {
+      checkMessage(
+          expected, "LockC -> LockA", "LockB -> LockC", "LockA -> LockB");
+    }
+  }
+
+  public void testReentrancy_noDeadlock() {
+    lockA.lock();
+    lockB.lock();
+    lockA.lock();  // Should not assert on lockB -> reentrant(lockA)
+  }
+
+  public void testExplicitOrdering_noViolations() {
+    lock1.lock();
+    lock3.lock();
+    lock3.unlock();
+    lock2.lock();
+    lock3.lock();
+  }
+
+  public void testExplicitOrdering_violations() {
+    lock3.lock();
+    try {
+      lock2.lock();
+      fail("Expected PotentialDeadlockException");
+    } catch (PotentialDeadlockException expected) {
+      checkMessage(expected, "MyOrder.THIRD -> MyOrder.SECOND");
+    }
+
+    try {
+      lock1.lock();
+      fail("Expected PotentialDeadlockException");
+    } catch (PotentialDeadlockException expected) {
+      checkMessage(expected, "MyOrder.THIRD -> MyOrder.FIRST");
+    }
+
+    lock3.unlock();
+    lock2.lock();
+
+    try {
+      lock1.lock();
+      fail("Expected PotentialDeadlockException");
+    } catch (PotentialDeadlockException expected) {
+      checkMessage(expected, "MyOrder.SECOND -> MyOrder.FIRST");
+    }
+  }
+
+  public void testDifferentOrderings_noViolations() {
+    lock3.lock();   // MyOrder, ordinal() == 3
+    lock01.lock();  // OtherOrder, ordinal() == 1
+  }
+
+  public void testExplicitOrderings_generalCycleDetection() {
+    lock3.lock();   // MyOrder, ordinal() == 3
+    lock01.lock();  // OtherOrder, ordinal() == 1
+
+    lock3.unlock();
+    try {
+      lock3.lock();
+      fail("Expected PotentialDeadlockException");
+    } catch (PotentialDeadlockException expected) {
+      checkMessage(
+          expected,
+          "OtherOrder.FIRST -> MyOrder.THIRD",
+          "MyOrder.THIRD -> OtherOrder.FIRST");
+    }
+
+    lockA.lock();
+    lock01.unlock();
+    lockB.lock();
+    lockA.unlock();
+
+    try {
+      lock01.lock();
+      fail("Expected PotentialDeadlockException");
+    } catch (PotentialDeadlockException expected) {
+      checkMessage(
+          expected,
+          "LockB -> OtherOrder.FIRST",
+          "LockA -> LockB",
+          "OtherOrder.FIRST -> LockA");
+    }
+  }
+
+  public void testExplicitOrdering_cycleWithUnorderedLock() {
+    Lock myLock = CycleDetectingLockFactory.newInstance(Policies.THROW)
+        .newReentrantLock("MyLock");
+    lock03.lock();
+    myLock.lock();
+    lock03.unlock();
+
+    try {
+      lock01.lock();
+      fail("Expected PotentialDeadlockException");
+    } catch (PotentialDeadlockException expected) {
+      checkMessage(
+          expected,
+          "MyLock -> OtherOrder.FIRST",
+          "OtherOrder.THIRD -> MyLock",
+          "OtherOrder.FIRST -> OtherOrder.THIRD");
+    }
+  }
+
+  public void testExplicitOrdering_reentrantAcquisition() {
+    CycleDetectingLockFactory.WithExplicitOrdering<OtherOrder> factory =
+        newInstanceWithExplicitOrdering(OtherOrder.class, Policies.THROW);
+    Lock lockA = factory.newReentrantReadWriteLock(OtherOrder.FIRST).readLock();
+    Lock lockB = factory.newReentrantLock(OtherOrder.SECOND);
+
+    lockA.lock();
+    lockA.lock();
+    lockB.lock();
+    lockB.lock();
+    lockA.unlock();
+    lockA.unlock();
+    lockB.unlock();
+    lockB.unlock();
+  }
+
+  public void testExplicitOrdering_acquiringMultipleLocksWithSameRank() {
+    CycleDetectingLockFactory.WithExplicitOrdering<OtherOrder> factory =
+        newInstanceWithExplicitOrdering(OtherOrder.class, Policies.THROW);
+    Lock lockA = factory.newReentrantLock(OtherOrder.FIRST);
+    Lock lockB = factory.newReentrantReadWriteLock(OtherOrder.FIRST).readLock();
+
+    lockA.lock();
+    try {
+      lockB.lock();
+      fail("Expected IllegalStateException");
+    } catch (IllegalStateException expected) {
+    }
+
+    lockA.unlock();
+    lockB.lock();
+  }
+
+  public void testReadLock_deadlock() {
+    readLockA.lock();  // Establish an ordering from readLockA -> lockB.
+    lockB.lock();
+    lockB.unlock();
+    readLockA.unlock();
+
+    lockB.lock();
+    try {
+      readLockA.lock();
+      fail("Expected PotentialDeadlockException");
+    } catch (PotentialDeadlockException expected) {
+      checkMessage(expected, "LockB -> ReadWriteA", "ReadWriteA -> LockB");
+    }
+  }
+
+  public void testReadLock_transitive() {
+    readLockA.lock();  // Establish an ordering from readLockA -> lockB.
+    lockB.lock();
+    lockB.unlock();
+    readLockA.unlock();
+
+    // Establish an ordering from lockB -> readLockC.
+    lockB.lock();
+    readLockC.lock();
+    lockB.unlock();
+    readLockC.unlock();
+
+    // readLockC -> readLockA
+    readLockC.lock();
+    try {
+      readLockA.lock();
+      fail("Expected PotentialDeadlockException");
+    } catch (PotentialDeadlockException expected) {
+      checkMessage(
+          expected,
+          "ReadWriteC -> ReadWriteA",
+          "LockB -> ReadWriteC",
+          "ReadWriteA -> LockB");
+    }
+  }
+
+  public void testWriteLock_threeLockDeadLock() {
+    // Establish an ordering from writeLockA -> writeLockB.
+    writeLockA.lock();
+    writeLockB.lock();
+    writeLockB.unlock();
+    writeLockA.unlock();
+
+    // Establish an ordering from writeLockB -> writeLockC.
+    writeLockB.lock();
+    writeLockC.lock();
+    writeLockB.unlock();
+
+    // writeLockC -> writeLockA should fail.
+    try {
+      writeLockA.lock();
+      fail("Expected PotentialDeadlockException");
+    } catch (PotentialDeadlockException expected) {
+      checkMessage(
+          expected,
+          "ReadWriteC -> ReadWriteA",
+          "ReadWriteB -> ReadWriteC",
+          "ReadWriteA -> ReadWriteB");
+    }
+  }
+
+  public void testWriteToReadLockDowngrading() {
+    writeLockA.lock();  // writeLockA downgrades to readLockA
+    readLockA.lock();
+    writeLockA.unlock();
+
+    lockB.lock();  // readLockA -> lockB
+    readLockA.unlock();
+
+    // lockB -> writeLockA should fail
+    try {
+      writeLockA.lock();
+      fail("Expected PotentialDeadlockException");
+    } catch (PotentialDeadlockException expected) {
+      checkMessage(
+          expected, "LockB -> ReadWriteA", "ReadWriteA -> LockB");
+    }
+  }
+
+  public void testReadWriteLockDeadlock() {
+    writeLockA.lock();  // Establish an ordering from writeLockA -> lockB
+    lockB.lock();
+    writeLockA.unlock();
+    lockB.unlock();
+
+    // lockB -> readLockA should fail.
+    lockB.lock();
+    try {
+      readLockA.lock();
+      fail("Expected PotentialDeadlockException");
+    } catch (PotentialDeadlockException expected) {
+      checkMessage(
+          expected, "LockB -> ReadWriteA", "ReadWriteA -> LockB");
+    }
+  }
+
+  public void testReadWriteLockDeadlock_transitive() {
+    readLockA.lock();  // Establish an ordering from readLockA -> lockB
+    lockB.lock();
+    readLockA.unlock();
+    lockB.unlock();
+
+    // Establish an ordering from lockB -> lockC
+    lockB.lock();
+    lockC.lock();
+    lockB.unlock();
+    lockC.unlock();
+
+    // lockC -> writeLockA should fail.
+    lockC.lock();
+    try {
+      writeLockA.lock();
+      fail("Expected PotentialDeadlockException");
+    } catch (PotentialDeadlockException expected) {
+      checkMessage(
+          expected,
+          "LockC -> ReadWriteA",
+          "LockB -> LockC",
+          "ReadWriteA -> LockB");
+    }
+  }
+
+  public void testReadWriteLockDeadlock_treatedEquivalently() {
+    readLockA.lock();  // readLockA -> writeLockB
+    writeLockB.lock();
+    readLockA.unlock();
+    writeLockB.unlock();
+
+    // readLockB -> writeLockA should fail.
+    readLockB.lock();
+    try {
+      writeLockA.lock();
+      fail("Expected PotentialDeadlockException");
+    } catch (PotentialDeadlockException expected) {
+      checkMessage(
+          expected, "ReadWriteB -> ReadWriteA", "ReadWriteA -> ReadWriteB");
+    }
+  }
+
+  public void testDifferentLockFactories() {
+    CycleDetectingLockFactory otherFactory =
+        CycleDetectingLockFactory.newInstance(Policies.WARN);
+    ReentrantLock lockD = otherFactory.newReentrantLock("LockD");
+
+    // lockA -> lockD
+    lockA.lock();
+    lockD.lock();
+    lockA.unlock();
+    lockD.unlock();
+
+    // lockD -> lockA should fail even though lockD is from a different factory.
+    lockD.lock();
+    try {
+      lockA.lock();
+      fail("Expected PotentialDeadlockException");
+    } catch (PotentialDeadlockException expected) {
+      checkMessage(expected, "LockD -> LockA", "LockA -> LockD");
+    }
+  }
+
+  public void testDifferentLockFactories_policyExecution() {
+    CycleDetectingLockFactory otherFactory =
+        CycleDetectingLockFactory.newInstance(Policies.WARN);
+    ReentrantLock lockD = otherFactory.newReentrantLock("LockD");
+
+    // lockD -> lockA
+    lockD.lock();
+    lockA.lock();
+    lockA.unlock();
+    lockD.unlock();
+
+    // lockA -> lockD should warn but otherwise succeed because lockD was
+    // created by a factory with the WARN policy.
+    lockA.lock();
+    lockD.lock();
+  }
+
+  public void testReentrantLock_tryLock() throws Exception {
+    LockingThread thread = new LockingThread(lockA);
+    thread.start();
+
+    thread.waitUntilHoldingLock();
+    assertFalse(lockA.tryLock());
+
+    thread.releaseLockAndFinish();
+    assertTrue(lockA.tryLock());
+  }
+
+  public void testReentrantWriteLock_tryLock() throws Exception {
+    LockingThread thread = new LockingThread(writeLockA);
+    thread.start();
+
+    thread.waitUntilHoldingLock();
+    assertFalse(writeLockA.tryLock());
+    assertFalse(readLockA.tryLock());
+
+    thread.releaseLockAndFinish();
+    assertTrue(writeLockA.tryLock());
+    assertTrue(readLockA.tryLock());
+  }
+
+  public void testReentrantReadLock_tryLock() throws Exception {
+    LockingThread thread = new LockingThread(readLockA);
+    thread.start();
+
+    thread.waitUntilHoldingLock();
+    assertFalse(writeLockA.tryLock());
+    assertTrue(readLockA.tryLock());
+    readLockA.unlock();
+
+    thread.releaseLockAndFinish();
+    assertTrue(writeLockA.tryLock());
+    assertTrue(readLockA.tryLock());
+  }
+
+  private static class LockingThread extends Thread {
+    final CountDownLatch locked = new CountDownLatch(1);
+    final CountDownLatch finishLatch = new CountDownLatch(1);
+    final Lock lock;
+
+    LockingThread(Lock lock) {
+      this.lock = lock;
+    }
+
+    @Override
+    public void run() {
+      lock.lock();
+      try {
+        locked.countDown();
+        finishLatch.await(1, TimeUnit.MINUTES);
+      } catch (InterruptedException e) {
+        fail(e.toString());
+      } finally {
+        lock.unlock();
+      }
+    }
+
+    void waitUntilHoldingLock() throws InterruptedException {
+      locked.await(1, TimeUnit.MINUTES);
+    }
+
+    void releaseLockAndFinish() throws InterruptedException {
+      finishLatch.countDown();
+      this.join(10000);
+      assertFalse(this.isAlive());
+    }
+  }
+
+  public void testReentrantReadWriteLock_implDoesNotExposeShadowedLocks() {
+    assertEquals(
+        "Unexpected number of public methods in ReentrantReadWriteLock. " +
+        "The correctness of CycleDetectingReentrantReadWriteLock depends on " +
+        "the fact that the shadowed ReadLock and WriteLock are never used or " +
+        "exposed by the superclass implementation. If the implementation has " +
+        "changed, the code must be re-inspected to ensure that the " +
+        "assumption is still valid.",
+        24, ReentrantReadWriteLock.class.getMethods().length);
+  }
+
+  private enum MyOrder {
+    FIRST, SECOND, THIRD;
+  }
+
+  private enum OtherOrder {
+    FIRST, SECOND, THIRD;
+  }
+
+  // Given a sequence of lock acquisition descriptions
+  // (e.g. "LockA -> LockB", "LockB -> LockC", ...)
+  // Checks that the exception.getMessage() matches a regex of the form:
+  // "LockA -> LockB \b.*\b LockB -> LockC \b.*\b LockC -> LockA"
+  private void checkMessage(
+      IllegalStateException exception, String... expectedLockCycle) {
+    String regex = Joiner.on("\\b.*\\b").join(expectedLockCycle);
+    assertContainsRegex(regex, exception.getMessage());
+  }
+
+  // TODO(cpovirk): consider adding support for regex to Truth
+  private static void assertContainsRegex(String expectedRegex, String actual) {
+    Pattern pattern = Pattern.compile(expectedRegex);
+    Matcher matcher = pattern.matcher(actual);
+    if (!matcher.find()) {
+      String actualDesc = (actual == null) ? "null" : ('<' + actual + '>');
+      fail("expected to contain regex:<" + expectedRegex + "> but was:"
+          + actualDesc);
+    }
+  }
+}
diff --git a/guava-tests/test/com/google/common/util/concurrent/ExecutionListTest.java b/guava-tests/test/com/google/common/util/concurrent/ExecutionListTest.java
index 4340c60..dd4799b 100644
--- a/guava-tests/test/com/google/common/util/concurrent/ExecutionListTest.java
+++ b/guava-tests/test/com/google/common/util/concurrent/ExecutionListTest.java
@@ -16,10 +16,9 @@
 
 package com.google.common.util.concurrent;
 
-import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
 
 import com.google.common.testing.NullPointerTester;
-import com.google.common.util.concurrent.ExecutionList;
 
 import junit.framework.TestCase;
 
@@ -59,7 +58,7 @@
       @Override public void run() {
         runCalled.getAndIncrement();
       }
-    }, MoreExecutors.sameThreadExecutor());
+    }, directExecutor());
     list.execute();
     assertEquals(1, runCalled.get());
     list.execute();
@@ -79,7 +78,7 @@
         }
         runCalled.getAndIncrement();
       }
-    }, MoreExecutors.sameThreadExecutor());
+    }, directExecutor());
     Runnable execute = new Runnable() {
       @Override public void run() {
         list.execute();
@@ -116,7 +115,7 @@
               integer.compareAndSet(expectedCount, expectedCount + 1);
             }
           },
-          MoreExecutors.sameThreadExecutor());
+          MoreExecutors.directExecutor());
     }
     list.execute();
     assertEquals(10, integer.get());
@@ -135,9 +134,9 @@
   }
 
   public void testExceptionsCaught() {
-    list.add(THROWING_RUNNABLE, sameThreadExecutor());
+    list.add(THROWING_RUNNABLE, directExecutor());
     list.execute();
-    list.add(THROWING_RUNNABLE, sameThreadExecutor());
+    list.add(THROWING_RUNNABLE, directExecutor());
   }
 
   public void testNulls() {
diff --git a/guava-tests/test/com/google/common/util/concurrent/FutureCallbackTest.java b/guava-tests/test/com/google/common/util/concurrent/FutureCallbackTest.java
new file mode 100644
index 0000000..14e0179
--- /dev/null
+++ b/guava-tests/test/com/google/common/util/concurrent/FutureCallbackTest.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.util.concurrent;
+
+import com.google.common.base.Preconditions;
+
+import junit.framework.TestCase;
+
+import org.mockito.Mockito;
+
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.Nullable;
+
+/**
+ * Test for {@link FutureCallback}.
+ *
+ * @author Anthony Zana
+ */
+public class FutureCallbackTest extends TestCase {
+  public void testSameThreadSuccess() {
+    SettableFuture<String> f = SettableFuture.create();
+    MockCallback callback = new MockCallback("foo");
+    Futures.addCallback(f, callback);
+    f.set("foo");
+  }
+
+  public void testExecutorSuccess() {
+    CountingSameThreadExecutor ex = new CountingSameThreadExecutor();
+    SettableFuture<String> f = SettableFuture.create();
+    MockCallback callback = new MockCallback("foo");
+    Futures.addCallback(f, callback, ex);
+    f.set("foo");
+    assertEquals(1, ex.runCount);
+  }
+
+  // Error cases
+  public void testSameThreadExecutionException() {
+    SettableFuture<String> f = SettableFuture.create();
+    Exception e = new IllegalArgumentException("foo not found");
+    MockCallback callback = new MockCallback(e);
+    Futures.addCallback(f, callback);
+    f.setException(e);
+  }
+
+  public void testCancel() {
+    SettableFuture<String> f = SettableFuture.create();
+    FutureCallback<String> callback =
+        new FutureCallback<String>() {
+          private boolean called = false;
+          @Override
+          public void onSuccess(String result) {
+            fail("Was not expecting onSuccess() to be called.");
+          }
+
+          @Override
+          public synchronized void onFailure(Throwable t) {
+            assertFalse(called);
+            assertTrue(t instanceof CancellationException);
+            called = true;
+          }
+        };
+    Futures.addCallback(f, callback);
+    f.cancel(true);
+  }
+
+  public void testThrowErrorFromGet() {
+    Error error = new AssertionError("ASSERT!");
+    ListenableFuture<String> f = ThrowingFuture.throwingError(error);
+    MockCallback callback = new MockCallback(error);
+    Futures.addCallback(f, callback);
+  }
+
+  public void testRuntimeExeceptionFromGet() {
+    RuntimeException e = new IllegalArgumentException("foo not found");
+    ListenableFuture<String> f = ThrowingFuture.throwingRuntimeException(e);
+    MockCallback callback = new MockCallback(e);
+    Futures.addCallback(f, callback);
+  }
+
+  public void testOnSuccessThrowsRuntimeException() throws Exception {
+    RuntimeException exception = new RuntimeException();
+    String result = "result";
+    SettableFuture<String> future = SettableFuture.create();
+    @SuppressWarnings("unchecked") // Safe for a mock
+    FutureCallback<String> callback = Mockito.mock(FutureCallback.class);
+    Futures.addCallback(future, callback);
+    Mockito.doThrow(exception).when(callback).onSuccess(result);
+    future.set(result);
+    assertEquals(result, future.get());
+    Mockito.verify(callback).onSuccess(result);
+    Mockito.verifyNoMoreInteractions(callback);
+  }
+
+  public void testOnSuccessThrowsError() throws Exception {
+    class TestError extends Error {}
+    TestError error = new TestError();
+    String result = "result";
+    SettableFuture<String> future = SettableFuture.create();
+    @SuppressWarnings("unchecked") // Safe for a mock
+    FutureCallback<String> callback = Mockito.mock(FutureCallback.class);
+    Futures.addCallback(future, callback);
+    Mockito.doThrow(error).when(callback).onSuccess(result);
+    try {
+      future.set(result);
+      fail("Should have thrown");
+    } catch (TestError e) {
+      assertSame(error, e);
+    }
+    assertEquals(result, future.get());
+    Mockito.verify(callback).onSuccess(result);
+    Mockito.verifyNoMoreInteractions(callback);
+  }
+
+  public void testWildcardFuture() {
+    SettableFuture<String> settable = SettableFuture.create();
+    ListenableFuture<?> f = settable;
+    FutureCallback<Object> callback = new FutureCallback<Object>() {
+      @Override
+      public void onSuccess(Object result) {}
+
+      @Override
+      public void onFailure(Throwable t) {}
+    };
+    Futures.addCallback(f, callback);
+  }
+
+  private class CountingSameThreadExecutor implements Executor {
+    int runCount = 0;
+    @Override
+    public void execute(Runnable command) {
+      command.run();
+      runCount++;
+    }
+  }
+
+  // TODO(user): Move to testing, unify with RuntimeExceptionThrowingFuture
+
+  /**
+   * A {@link Future} implementation which always throws directly from calls to
+   * get() (i.e. not wrapped in ExecutionException.
+   * For just a normal Future failure, use {@link SettableFuture}).
+   *
+   * <p>Useful for testing the behavior of Future utilities against odd futures.
+   *
+   * @author Anthony Zana
+   */
+  private static class ThrowingFuture<V> implements ListenableFuture<V> {
+    private final Error error;
+    private final RuntimeException runtime;
+
+    public static <V> ListenableFuture<V> throwingError(Error error) {
+      return new ThrowingFuture<V>(error);
+    }
+
+    public static <V> ListenableFuture<V>
+        throwingRuntimeException(RuntimeException e) {
+      return new ThrowingFuture<V>(e);
+    }
+
+    private ThrowingFuture(Error error) {
+      this.error = Preconditions.checkNotNull(error);
+      this.runtime = null;
+    }
+
+    public ThrowingFuture(RuntimeException e) {
+      this.runtime = Preconditions.checkNotNull(e);
+      this.error = null;
+    }
+
+    @Override
+    public boolean cancel(boolean mayInterruptIfRunning) {
+      return false;
+    }
+
+    @Override
+    public boolean isCancelled() {
+      return false;
+    }
+
+    @Override
+    public boolean isDone() {
+      return true;
+    }
+
+    @Override
+    public V get() {
+      throwOnGet();
+      throw new AssertionError("Unreachable");
+    }
+
+    @Override
+    public V get(long timeout, TimeUnit unit) {
+      throwOnGet();
+      throw new AssertionError("Unreachable");
+    }
+
+    @Override
+    public void addListener(Runnable listener, Executor executor) {
+      executor.execute(listener);
+    }
+
+    private void throwOnGet() {
+      if (error != null) {
+        throw error;
+      } else {
+        throw runtime;
+      }
+    }
+  }
+
+  private final class MockCallback implements FutureCallback<String> {
+    @Nullable private String value = null;
+    @Nullable private Throwable failure = null;
+    private boolean wasCalled = false;
+
+    MockCallback(String expectedValue) {
+      this.value = expectedValue;
+    }
+
+    public MockCallback(Throwable expectedFailure) {
+      this.failure = expectedFailure;
+    }
+
+    @Override
+    public synchronized void onSuccess(String result) {
+      assertFalse(wasCalled);
+      wasCalled = true;
+      assertEquals(value, result);
+    }
+
+    @Override
+    public synchronized void onFailure(Throwable t) {
+      assertFalse(wasCalled);
+      wasCalled = true;
+      assertEquals(failure, t);
+    }
+  }
+}
diff --git a/guava-tests/test/com/google/common/util/concurrent/FuturesTest.java b/guava-tests/test/com/google/common/util/concurrent/FuturesTest.java
index 87367b2..b39dac0 100644
--- a/guava-tests/test/com/google/common/util/concurrent/FuturesTest.java
+++ b/guava-tests/test/com/google/common/util/concurrent/FuturesTest.java
@@ -17,18 +17,19 @@
 package com.google.common.util.concurrent;
 
 import static com.google.common.base.Throwables.propagateIfInstanceOf;
+import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.util.concurrent.Futures.allAsList;
 import static com.google.common.util.concurrent.Futures.get;
 import static com.google.common.util.concurrent.Futures.getUnchecked;
 import static com.google.common.util.concurrent.Futures.immediateFailedFuture;
 import static com.google.common.util.concurrent.Futures.immediateFuture;
 import static com.google.common.util.concurrent.Futures.successfulAsList;
-import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
+import static com.google.common.util.concurrent.MoreExecutors.newDirectExecutorService;
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
 import static org.easymock.EasyMock.expect;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.base.Function;
 import com.google.common.base.Functions;
@@ -60,6 +61,7 @@
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
+import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.logging.Handler;
@@ -277,6 +279,22 @@
     assertTrue(secondary.wasInterrupted());
   }
 
+  public void testTransform_rejectionPropagatesToOutput()
+      throws Exception {
+    SettableFuture<Foo> input = SettableFuture.create();
+    ExecutorService executor = newDirectExecutorService();
+    ListenableFuture<String> transformed =
+        Futures.transform(input, Functions.toStringFunction(), executor);
+    executor.shutdown();
+    input.set(new Foo());
+    try {
+      transformed.get(5, TimeUnit.SECONDS);
+      fail();
+    } catch (ExecutionException expected) {
+      assertTrue(expected.getCause() instanceof RejectedExecutionException);
+    }
+  }
+
   /**
    * Tests that the function is invoked only once, even if it throws an
    * exception.
@@ -420,7 +438,7 @@
 
   public void testTransform_Executor() throws Exception {
     Object value = new Object();
-    ExecutorSpy spy = new ExecutorSpy(MoreExecutors.sameThreadExecutor());
+    ExecutorSpy spy = new ExecutorSpy(directExecutor());
 
     assertFalse(spy.wasExecuted);
 
@@ -807,7 +825,7 @@
 
     // Attach a listener
     SingleCallListener listener = new SingleCallListener();
-    compound.addListener(listener, MoreExecutors.sameThreadExecutor());
+    compound.addListener(listener, directExecutor());
 
     // Satisfy each input and check the output
     assertFalse(compound.isDone());
@@ -821,7 +839,7 @@
     assertTrue(listener.wasCalled());
 
     List<String> results = compound.get();
-    ASSERT.that(results).has().exactly(DATA1, DATA2, DATA3).inOrder();
+    assertThat(results).has().exactly(DATA1, DATA2, DATA3).inOrder();
   }
 
   public void testAllAsList_emptyList() throws Exception {
@@ -829,7 +847,7 @@
     listener.expectCall();
     List<ListenableFuture<String>> futures = ImmutableList.of();
     ListenableFuture<List<String>> compound = Futures.allAsList(futures);
-    compound.addListener(listener, MoreExecutors.sameThreadExecutor());
+    compound.addListener(listener, directExecutor());
     assertTrue(compound.isDone());
     assertTrue(compound.get().isEmpty());
     assertTrue(listener.wasCalled());
@@ -840,7 +858,7 @@
     listener.expectCall();
     @SuppressWarnings("unchecked") // array is never modified
     ListenableFuture<List<String>> compound = Futures.allAsList();
-    compound.addListener(listener, MoreExecutors.sameThreadExecutor());
+    compound.addListener(listener, directExecutor());
     assertTrue(compound.isDone());
     assertTrue(compound.get().isEmpty());
     assertTrue(listener.wasCalled());
@@ -853,7 +871,7 @@
     @SuppressWarnings("unchecked") // array is never modified
     ListenableFuture<List<String>> compound =
         Futures.allAsList(future1, future2);
-    compound.addListener(listener, MoreExecutors.sameThreadExecutor());
+    compound.addListener(listener, directExecutor());
 
     listener.expectCall();
     Throwable exception = new Throwable("failed1");
@@ -919,7 +937,7 @@
     @SuppressWarnings("unchecked") // array is never modified
     ListenableFuture<List<String>> compound =
         Futures.allAsList(future1, future2);
-    compound.addListener(listener, MoreExecutors.sameThreadExecutor());
+    compound.addListener(listener, directExecutor());
 
     listener.expectCall();
     future1.cancel(true);
@@ -990,13 +1008,13 @@
     // Attach a listener
     SingleCallListener listener = new SingleCallListener();
     listener.expectCall();
-    compound.addListener(listener, MoreExecutors.sameThreadExecutor());
+    compound.addListener(listener, directExecutor());
 
     assertTrue(compound.isDone());
     assertTrue(listener.wasCalled());
 
     List<String> results = compound.get();
-    ASSERT.that(results).has().exactly(DATA1, DATA2, DATA3).inOrder();
+    assertThat(results).has().exactly(DATA1, DATA2, DATA3).inOrder();
   }
 
   /**
@@ -1450,7 +1468,7 @@
 
     // Attach a listener
     SingleCallListener listener = new SingleCallListener();
-    compound.addListener(listener, MoreExecutors.sameThreadExecutor());
+    compound.addListener(listener, directExecutor());
 
     // Satisfy each input and check the output
     assertFalse(compound.isDone());
@@ -1464,7 +1482,7 @@
     assertTrue(listener.wasCalled());
 
     List<String> results = compound.get();
-    ASSERT.that(results).has().exactly(DATA1, DATA2, DATA3).inOrder();
+    assertThat(results).has().exactly(DATA1, DATA2, DATA3).inOrder();
   }
 
   public void testSuccessfulAsList_emptyList() throws Exception {
@@ -1472,7 +1490,7 @@
     listener.expectCall();
     List<ListenableFuture<String>> futures = ImmutableList.of();
     ListenableFuture<List<String>> compound = Futures.successfulAsList(futures);
-    compound.addListener(listener, MoreExecutors.sameThreadExecutor());
+    compound.addListener(listener, directExecutor());
     assertTrue(compound.isDone());
     assertTrue(compound.get().isEmpty());
     assertTrue(listener.wasCalled());
@@ -1483,7 +1501,7 @@
     listener.expectCall();
     @SuppressWarnings("unchecked") // array is never modified
     ListenableFuture<List<String>> compound = Futures.successfulAsList();
-    compound.addListener(listener, MoreExecutors.sameThreadExecutor());
+    compound.addListener(listener, directExecutor());
     assertTrue(compound.isDone());
     assertTrue(compound.get().isEmpty());
     assertTrue(listener.wasCalled());
@@ -1496,7 +1514,7 @@
     @SuppressWarnings("unchecked") // array is never modified
     ListenableFuture<List<String>> compound =
         Futures.successfulAsList(future1, future2);
-    compound.addListener(listener, MoreExecutors.sameThreadExecutor());
+    compound.addListener(listener, directExecutor());
 
     assertFalse(compound.isDone());
     future1.setException(new Throwable("failed1"));
@@ -1507,7 +1525,7 @@
     assertTrue(listener.wasCalled());
 
     List<String> results = compound.get();
-    ASSERT.that(results).has().exactly(null, DATA2).inOrder();
+    assertThat(results).has().exactly(null, DATA2).inOrder();
   }
 
   public void testSuccessfulAsList_totalFailure() throws Exception {
@@ -1517,7 +1535,7 @@
     @SuppressWarnings("unchecked") // array is never modified
     ListenableFuture<List<String>> compound =
         Futures.successfulAsList(future1, future2);
-    compound.addListener(listener, MoreExecutors.sameThreadExecutor());
+    compound.addListener(listener, directExecutor());
 
     assertFalse(compound.isDone());
     future1.setException(new Throwable("failed1"));
@@ -1528,7 +1546,7 @@
     assertTrue(listener.wasCalled());
 
     List<String> results = compound.get();
-    ASSERT.that(results).has().exactly(null, null).inOrder();
+    assertThat(results).has().exactly(null, null).inOrder();
   }
 
   public void testSuccessfulAsList_cancelled() throws Exception {
@@ -1538,7 +1556,7 @@
     @SuppressWarnings("unchecked") // array is never modified
     ListenableFuture<List<String>> compound =
         Futures.successfulAsList(future1, future2);
-    compound.addListener(listener, MoreExecutors.sameThreadExecutor());
+    compound.addListener(listener, directExecutor());
 
     assertFalse(compound.isDone());
     future1.cancel(true);
@@ -1549,7 +1567,7 @@
     assertTrue(listener.wasCalled());
 
     List<String> results = compound.get();
-    ASSERT.that(results).has().exactly(null, DATA2).inOrder();
+    assertThat(results).has().exactly(null, DATA2).inOrder();
   }
 
   public void testSuccessfulAsList_resultCancelled() throws Exception {
@@ -1624,7 +1642,7 @@
         // Now attempt to trigger the exception:
         future2.set(DATA2);
       }
-    }, sameThreadExecutor());
+    }, directExecutor());
     assertTrue(compound.cancel(false));
     assertTrue(compound.isCancelled());
     assertTrue(future1.isCancelled());
@@ -1661,7 +1679,7 @@
     @SuppressWarnings("unchecked") // array is never modified
     ListenableFuture<List<String>> compound =
         Futures.successfulAsList(future1, future2, future3);
-    compound.addListener(listener, MoreExecutors.sameThreadExecutor());
+    compound.addListener(listener, directExecutor());
 
     // First is cancelled, second fails, third succeeds
     assertFalse(compound.isDone());
@@ -1675,7 +1693,7 @@
     assertTrue(listener.wasCalled());
 
     List<String> results = compound.get();
-    ASSERT.that(results).has().exactly(null, null, DATA3).inOrder();
+    assertThat(results).has().exactly(null, null, DATA3).inOrder();
   }
 
   /** Non-Error exceptions are never logged. */
@@ -2337,7 +2355,7 @@
           ExceptionWithoutThrowableConstructor.class);
       fail();
     } catch (ExceptionWithoutThrowableConstructor expected) {
-      ASSERT.that(expected.getMessage()).contains("mymessage");
+      assertThat(expected.getMessage()).contains("mymessage");
       assertEquals(CHECKED_EXCEPTION, expected.getCause());
     }
   }
diff --git a/guava-tests/test/com/google/common/util/concurrent/InterruptibleMonitorTest.java b/guava-tests/test/com/google/common/util/concurrent/InterruptibleMonitorTest.java
new file mode 100644
index 0000000..6e08eb3
--- /dev/null
+++ b/guava-tests/test/com/google/common/util/concurrent/InterruptibleMonitorTest.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2010 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.util.concurrent;
+
+/**
+ * Tests for {@link Monitor}'s interruptible methods.
+ *
+ * @author Justin T. Sampson
+ */
+
+public class InterruptibleMonitorTest extends MonitorTestCase {
+
+  public InterruptibleMonitorTest() {
+    super(true);
+  }
+
+}
diff --git a/guava-tests/test/com/google/common/util/concurrent/JdkFutureAdaptersTest.java b/guava-tests/test/com/google/common/util/concurrent/JdkFutureAdaptersTest.java
index 5042d83..1f41cf4 100644
--- a/guava-tests/test/com/google/common/util/concurrent/JdkFutureAdaptersTest.java
+++ b/guava-tests/test/com/google/common/util/concurrent/JdkFutureAdaptersTest.java
@@ -19,7 +19,7 @@
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.util.concurrent.Futures.immediateFuture;
 import static com.google.common.util.concurrent.JdkFutureAdapters.listenInPoolThread;
-import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
 import static java.util.concurrent.Executors.newCachedThreadPool;
 import static java.util.concurrent.TimeUnit.SECONDS;
 
@@ -56,7 +56,7 @@
     NonListenableSettableFuture<String> abstractFuture =
         NonListenableSettableFuture.create();
     abstractFuture.set(DATA1);
-    ExecutorSpy spy = new ExecutorSpy(sameThreadExecutor());
+    ExecutorSpy spy = new ExecutorSpy(directExecutor());
     ListenableFuture<String> listenableFuture =
         listenInPoolThread(abstractFuture, spy);
 
@@ -69,7 +69,7 @@
 
     // #addListener() will run the listener immediately because the Future is
     // already finished (we explicitly set the result of it above).
-    listenableFuture.addListener(singleCallListener, sameThreadExecutor());
+    listenableFuture.addListener(singleCallListener, directExecutor());
     assertEquals(DATA1, listenableFuture.get());
 
     // 'spy' should have been ignored since 'abstractFuture' was done before
@@ -128,7 +128,7 @@
     assertFalse(singleCallListener.wasCalled());
     assertFalse(listenableFuture.isDone());
 
-    listenableFuture.addListener(singleCallListener, sameThreadExecutor());
+    listenableFuture.addListener(singleCallListener, directExecutor());
     /*
      * Don't shut down until the listenInPoolThread task has been accepted to
      * run. We want to see what happens when it's interrupted, not when it's
@@ -235,7 +235,7 @@
      * listenInPoolThread-spawned thread completes:
      */
     RecordingRunnable earlyListener = new RecordingRunnable();
-    listenable.addListener(earlyListener, sameThreadExecutor());
+    listenable.addListener(earlyListener, directExecutor());
 
     input.allowGetToComplete.countDown();
     // Now give the get() thread time to finish:
@@ -243,7 +243,7 @@
 
     // Now test an additional addListener call, which will be run in-thread:
     RecordingRunnable lateListener = new RecordingRunnable();
-    listenable.addListener(lateListener, sameThreadExecutor());
+    listenable.addListener(lateListener, directExecutor());
     assertTrue(lateListener.wasRun.await(1, SECONDS));
   }
 
diff --git a/guava-tests/test/com/google/common/util/concurrent/ListenableFutureTaskTest.java b/guava-tests/test/com/google/common/util/concurrent/ListenableFutureTaskTest.java
index 479e569..cdc5fe3 100644
--- a/guava-tests/test/com/google/common/util/concurrent/ListenableFutureTaskTest.java
+++ b/guava-tests/test/com/google/common/util/concurrent/ListenableFutureTaskTest.java
@@ -16,6 +16,8 @@
 
 package com.google.common.util.concurrent;
 
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
+
 import junit.framework.TestCase;
 
 import java.util.concurrent.Callable;
@@ -64,7 +66,7 @@
       public void run() {
         listenerLatch.countDown();
       }
-    }, MoreExecutors.sameThreadExecutor());
+    }, directExecutor());
   }
 
   @Override
diff --git a/guava-tests/test/com/google/common/util/concurrent/ListenerCallQueueTest.java b/guava-tests/test/com/google/common/util/concurrent/ListenerCallQueueTest.java
index 651eb96..99fb924 100644
--- a/guava-tests/test/com/google/common/util/concurrent/ListenerCallQueueTest.java
+++ b/guava-tests/test/com/google/common/util/concurrent/ListenerCallQueueTest.java
@@ -16,6 +16,8 @@
 
 package com.google.common.util.concurrent;
 
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
+
 import com.google.common.util.concurrent.ListenerCallQueue.Callback;
 
 import junit.framework.TestCase;
@@ -39,7 +41,7 @@
   public void testAddAndExecute() {
     Object listenerInstance = new Object();
     ListenerCallQueue<Object> queue =
-        new ListenerCallQueue<Object>(listenerInstance, MoreExecutors.sameThreadExecutor());
+        new ListenerCallQueue<Object>(listenerInstance, directExecutor());
 
     AtomicInteger counter = new AtomicInteger();
     queue.add(incrementingCallback(counter, 1));
@@ -54,7 +56,7 @@
   public void testAddAndExecute_withExceptions() {
     Object listenerInstance = new Object();
     ListenerCallQueue<Object> queue =
-        new ListenerCallQueue<Object>(listenerInstance, MoreExecutors.sameThreadExecutor());
+        new ListenerCallQueue<Object>(listenerInstance, directExecutor());
 
     AtomicInteger counter = new AtomicInteger();
     queue.add(incrementingCallback(counter, 1));
diff --git a/guava-tests/test/com/google/common/util/concurrent/MonitorTestCase.java b/guava-tests/test/com/google/common/util/concurrent/MonitorTestCase.java
new file mode 100644
index 0000000..1fa2700
--- /dev/null
+++ b/guava-tests/test/com/google/common/util/concurrent/MonitorTestCase.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2010 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.util.concurrent;
+
+import com.google.common.testing.NullPointerTester;
+import com.google.common.testing.TearDownStack;
+
+import junit.framework.TestCase;
+
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests for {@link Monitor}, either interruptible or uninterruptible.
+ *
+ * @author Justin T. Sampson
+ */
+
+public abstract class MonitorTestCase extends TestCase {
+
+  public class TestGuard extends Monitor.Guard {
+    private volatile boolean satisfied;
+
+    public TestGuard(boolean satisfied) {
+      super(MonitorTestCase.this.monitor);
+      this.satisfied = satisfied;
+    }
+
+    @Override public boolean isSatisfied() {
+      return this.satisfied;
+    }
+
+    public void setSatisfied(boolean satisfied) {
+      this.satisfied = satisfied;
+    }
+  }
+
+  private final boolean interruptible;
+  private Monitor monitor;
+  private final TearDownStack tearDownStack = new TearDownStack(true);
+  private TestThread<Monitor> thread1;
+  private TestThread<Monitor> thread2;
+
+  protected MonitorTestCase(boolean interruptible) {
+    this.interruptible = interruptible;
+  }
+
+  @Override protected final void setUp() throws Exception {
+    boolean fair = new Random().nextBoolean();
+    monitor = new Monitor(fair);
+    tearDownStack.addTearDown(thread1 = new TestThread<Monitor>(monitor, "TestThread #1"));
+    tearDownStack.addTearDown(thread2 = new TestThread<Monitor>(monitor, "TestThread #2"));
+  }
+
+  @Override protected final void tearDown() {
+    tearDownStack.runTearDown();
+  }
+
+  private String enter() {
+    return interruptible ? "enterInterruptibly" : "enter";
+  }
+
+  private String tryEnter() {
+    return "tryEnter";
+  }
+
+  private String enterIf() {
+    return interruptible ? "enterIfInterruptibly" : "enterIf";
+  }
+
+  private String tryEnterIf() {
+    return "tryEnterIf";
+  }
+
+  private String enterWhen() {
+    return interruptible ? "enterWhen" : "enterWhenUninterruptibly";
+  }
+
+  private String waitFor() {
+    return interruptible ? "waitFor" : "waitForUninterruptibly";
+  }
+
+  private String leave() {
+    return "leave";
+  }
+
+  public final void testMutualExclusion() throws Exception {
+    thread1.callAndAssertReturns(enter());
+    thread2.callAndAssertBlocks(enter());
+    thread1.callAndAssertReturns(leave());
+    thread2.assertPriorCallReturns(enter());
+  }
+
+  public final void testTryEnter() throws Exception {
+    thread1.callAndAssertReturns(true, tryEnter());
+    thread2.callAndAssertReturns(false, tryEnter());
+    thread1.callAndAssertReturns(true, tryEnter());
+    thread2.callAndAssertReturns(false, tryEnter());
+    thread1.callAndAssertReturns(leave());
+    thread2.callAndAssertReturns(false, tryEnter());
+    thread1.callAndAssertReturns(leave());
+    thread2.callAndAssertReturns(true, tryEnter());
+  }
+
+  public final void testSystemStateMethods() throws Exception {
+    checkSystemStateMethods(0);
+    thread1.callAndAssertReturns(enter());
+    checkSystemStateMethods(1);
+    thread1.callAndAssertReturns(enter());
+    checkSystemStateMethods(2);
+    thread1.callAndAssertReturns(leave());
+    checkSystemStateMethods(1);
+    thread1.callAndAssertReturns(leave());
+    checkSystemStateMethods(0);
+  }
+
+  private void checkSystemStateMethods(int enterCount) throws Exception {
+    thread1.callAndAssertReturns(enterCount != 0, "isOccupied");
+    thread1.callAndAssertReturns(enterCount != 0, "isOccupiedByCurrentThread");
+    thread1.callAndAssertReturns(enterCount, "getOccupiedDepth");
+
+    thread2.callAndAssertReturns(enterCount != 0, "isOccupied");
+    thread2.callAndAssertReturns(false, "isOccupiedByCurrentThread");
+    thread2.callAndAssertReturns(0, "getOccupiedDepth");
+  }
+
+  public final void testEnterWhen_initiallyTrue() throws Exception {
+    TestGuard guard = new TestGuard(true);
+    thread1.callAndAssertReturns(enterWhen(), guard);
+  }
+
+  public final void testEnterWhen_initiallyFalse() throws Exception {
+    TestGuard guard = new TestGuard(false);
+    thread1.callAndAssertWaits(enterWhen(), guard);
+    monitor.enter();
+    guard.setSatisfied(true);
+    monitor.leave();
+    thread1.assertPriorCallReturns(enterWhen());
+  }
+
+  public final void testEnterWhen_alreadyOccupied() throws Exception {
+    TestGuard guard = new TestGuard(true);
+    thread2.callAndAssertReturns(enter());
+    thread1.callAndAssertBlocks(enterWhen(), guard);
+    thread2.callAndAssertReturns(leave());
+    thread1.assertPriorCallReturns(enterWhen());
+  }
+
+  public final void testEnterIf_initiallyTrue() throws Exception {
+    TestGuard guard = new TestGuard(true);
+    thread1.callAndAssertReturns(true, enterIf(), guard);
+    thread2.callAndAssertBlocks(enter());
+  }
+
+  public final void testEnterIf_initiallyFalse() throws Exception {
+    TestGuard guard = new TestGuard(false);
+    thread1.callAndAssertReturns(false, enterIf(), guard);
+    thread2.callAndAssertReturns(enter());
+  }
+
+  public final void testEnterIf_alreadyOccupied() throws Exception {
+    TestGuard guard = new TestGuard(true);
+    thread2.callAndAssertReturns(enter());
+    thread1.callAndAssertBlocks(enterIf(), guard);
+    thread2.callAndAssertReturns(leave());
+    thread1.assertPriorCallReturns(true, enterIf());
+  }
+
+  public final void testTryEnterIf_initiallyTrue() throws Exception {
+    TestGuard guard = new TestGuard(true);
+    thread1.callAndAssertReturns(true, tryEnterIf(), guard);
+    thread2.callAndAssertBlocks(enter());
+  }
+
+  public final void testTryEnterIf_initiallyFalse() throws Exception {
+    TestGuard guard = new TestGuard(false);
+    thread1.callAndAssertReturns(false, tryEnterIf(), guard);
+    thread2.callAndAssertReturns(enter());
+  }
+
+  public final void testTryEnterIf_alreadyOccupied() throws Exception {
+    TestGuard guard = new TestGuard(true);
+    thread2.callAndAssertReturns(enter());
+    thread1.callAndAssertReturns(false, tryEnterIf(), guard);
+  }
+
+  public final void testWaitFor_initiallyTrue() throws Exception {
+    TestGuard guard = new TestGuard(true);
+    thread1.callAndAssertReturns(enter());
+    thread1.callAndAssertReturns(waitFor(), guard);
+  }
+
+  public final void testWaitFor_initiallyFalse() throws Exception {
+    TestGuard guard = new TestGuard(false);
+    thread1.callAndAssertReturns(enter());
+    thread1.callAndAssertWaits(waitFor(), guard);
+    monitor.enter();
+    guard.setSatisfied(true);
+    monitor.leave();
+    thread1.assertPriorCallReturns(waitFor());
+  }
+
+  public final void testWaitFor_withoutEnter() throws Exception {
+    TestGuard guard = new TestGuard(true);
+    thread1.callAndAssertThrows(IllegalMonitorStateException.class, waitFor(), guard);
+  }
+
+  public void testNulls() {
+    monitor.enter();  // Inhibit IllegalMonitorStateException
+    new NullPointerTester()
+        .setDefault(TimeUnit.class, TimeUnit.SECONDS)
+        .setDefault(Monitor.Guard.class, new TestGuard(true))
+        .testAllPublicInstanceMethods(monitor);
+  }
+
+  // TODO: Test enter(long, TimeUnit).
+  // TODO: Test enterWhen(Guard, long, TimeUnit).
+  // TODO: Test enterIf(Guard, long, TimeUnit).
+  // TODO: Test waitFor(Guard, long, TimeUnit).
+  // TODO: Test getQueueLength().
+  // TODO: Test hasQueuedThreads().
+  // TODO: Test getWaitQueueLength(Guard).
+  // TODO: Test automatic signaling before leave, waitFor, and reentrant enterWhen.
+  // TODO: Test blocking to re-enter monitor after being signaled.
+  // TODO: Test interrupts with both interruptible and uninterruptible monitor.
+  // TODO: Test multiple waiters: If guard is still satisfied, signal next waiter.
+  // TODO: Test multiple waiters: If guard is no longer satisfied, do not signal next waiter.
+
+}
diff --git a/guava-tests/test/com/google/common/util/concurrent/MoreExecutorsTest.java b/guava-tests/test/com/google/common/util/concurrent/MoreExecutorsTest.java
index 3b0af7f..cb1898c 100644
--- a/guava-tests/test/com/google/common/util/concurrent/MoreExecutorsTest.java
+++ b/guava-tests/test/com/google/common/util/concurrent/MoreExecutorsTest.java
@@ -29,10 +29,12 @@
 package com.google.common.util.concurrent;
 
 import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
 import static com.google.common.util.concurrent.MoreExecutors.invokeAnyImpl;
 import static com.google.common.util.concurrent.MoreExecutors.listeningDecorator;
+import static com.google.common.util.concurrent.MoreExecutors.newDirectExecutorService;
 import static com.google.common.util.concurrent.MoreExecutors.renamingDecorator;
-import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
 import static com.google.common.util.concurrent.MoreExecutors.shutdownAndAwaitTermination;
 import static java.util.concurrent.TimeUnit.NANOSECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
@@ -40,7 +42,6 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.truth0.Truth.ASSERT;
 
 import com.google.common.base.Suppliers;
 import com.google.common.base.Throwables;
@@ -85,10 +86,9 @@
     @Override public void run() {}
   };
 
-  public void testSameThreadExecutorServiceInThreadExecution()
+  public void testDirectExecutorServiceServiceInThreadExecution()
       throws Exception {
-    final ListeningExecutorService executor =
-        MoreExecutors.sameThreadExecutor();
+    final ListeningExecutorService executor = newDirectExecutorService();
     final ThreadLocal<Integer> threadLocalCount = new ThreadLocal<Integer>() {
       @Override
       protected Integer initialValue() {
@@ -133,8 +133,8 @@
         throwableFromOtherThread.get());
   }
 
-  public void testSameThreadExecutorInvokeAll() throws Exception {
-    final ExecutorService executor = MoreExecutors.sameThreadExecutor();
+  public void testDirectExecutorServiceInvokeAll() throws Exception {
+    final ExecutorService executor = newDirectExecutorService();
     final ThreadLocal<Integer> threadLocalCount = new ThreadLocal<Integer>() {
       @Override
       protected Integer initialValue() {
@@ -163,9 +163,9 @@
     assertEquals(10, threadLocalCount.get().intValue());
   }
 
-  public void testSameThreadExecutorServiceTermination()
+  public void testDirectExecutorServiceServiceTermination()
       throws Exception {
-    final ExecutorService executor = MoreExecutors.sameThreadExecutor();
+    final ExecutorService executor = newDirectExecutorService();
     final CyclicBarrier barrier = new CyclicBarrier(2);
     final AtomicReference<Throwable> throwableFromOtherThread =
         new AtomicReference<Throwable>(null);
@@ -243,14 +243,14 @@
         throwableFromOtherThread.get());
   }
 
-  public void testSameThreadExecutor_shutdownNow() {
-    ExecutorService executor = MoreExecutors.sameThreadExecutor();
+  public void testDirectExecutorService_shutdownNow() {
+    ExecutorService executor = newDirectExecutorService();
     assertEquals(ImmutableList.of(), executor.shutdownNow());
     assertTrue(executor.isShutdown());
   }
 
   public void testExecuteAfterShutdown() {
-    ExecutorService executor = MoreExecutors.sameThreadExecutor();
+    ExecutorService executor = newDirectExecutorService();
     executor.shutdown();
     try {
       executor.execute(EMPTY_RUNNABLE);
@@ -260,7 +260,7 @@
 
   public <T> void testListeningExecutorServiceInvokeAllJavadocCodeCompiles()
       throws Exception {
-    ListeningExecutorService executor = MoreExecutors.sameThreadExecutor();
+    ListeningExecutorService executor = newDirectExecutorService();
     List<Callable<T>> tasks = ImmutableList.of();
     @SuppressWarnings("unchecked") // guaranteed by invokeAll contract
     List<ListenableFuture<T>> futures = (List) executor.invokeAll(tasks);
@@ -268,17 +268,17 @@
 
   public void testListeningDecorator() throws Exception {
     ListeningExecutorService service =
-        listeningDecorator(MoreExecutors.sameThreadExecutor());
+        listeningDecorator(newDirectExecutorService());
     assertSame(service, listeningDecorator(service));
     List<Callable<String>> callables =
         ImmutableList.of(Callables.returning("x"));
     List<Future<String>> results;
 
     results = service.invokeAll(callables);
-    ASSERT.that(getOnlyElement(results)).isA(ListenableFutureTask.class);
+    assertThat(getOnlyElement(results)).isA(ListenableFutureTask.class);
 
     results = service.invokeAll(callables, 1, SECONDS);
-    ASSERT.that(getOnlyElement(results)).isA(ListenableFutureTask.class);
+    assertThat(getOnlyElement(results)).isA(ListenableFutureTask.class);
 
     /*
      * TODO(cpovirk): move ForwardingTestCase somewhere common, and use it to
@@ -361,7 +361,7 @@
       @Override public void run() {}
     };
 
-    future = service.schedule(runnable, 5 * 60, TimeUnit.SECONDS);
+    future = service.schedule(runnable, 5, TimeUnit.MINUTES);
     future.cancel(true);
     assertTrue(future.isCancelled());
     delegateFuture = (ScheduledFuture<?>) delegateQueue.element();
@@ -369,7 +369,7 @@
 
     delegateQueue.clear();
 
-    future = service.scheduleAtFixedRate(runnable, 5 * 60, 5 * 60, TimeUnit.SECONDS);
+    future = service.scheduleAtFixedRate(runnable, 5, 5, TimeUnit.MINUTES);
     future.cancel(true);
     assertTrue(future.isCancelled());
     delegateFuture = (ScheduledFuture<?>) delegateQueue.element();
@@ -377,7 +377,7 @@
 
     delegateQueue.clear();
 
-    future = service.scheduleWithFixedDelay(runnable, 5 * 60, 5 * 60, TimeUnit.SECONDS);
+    future = service.scheduleWithFixedDelay(runnable, 5, 5, TimeUnit.MINUTES);
     future.cancel(true);
     assertTrue(future.isCancelled());
     delegateFuture = (ScheduledFuture<?>) delegateQueue.element();
@@ -416,7 +416,7 @@
    * invokeAny(null) throws NPE
    */
   public void testInvokeAnyImpl_nullTasks() throws Exception {
-    ListeningExecutorService e = sameThreadExecutor();
+    ListeningExecutorService e = newDirectExecutorService();
     try {
       invokeAnyImpl(e, null, false, 0);
       shouldThrow();
@@ -430,7 +430,7 @@
    * invokeAny(empty collection) throws IAE
    */
   public void testInvokeAnyImpl_emptyTasks() throws Exception {
-    ListeningExecutorService e = sameThreadExecutor();
+    ListeningExecutorService e = newDirectExecutorService();
     try {
       invokeAnyImpl(e, new ArrayList<Callable<String>>(), false, 0);
       shouldThrow();
@@ -444,7 +444,7 @@
    * invokeAny(c) throws NPE if c has null elements
    */
   public void testInvokeAnyImpl_nullElement() throws Exception {
-    ListeningExecutorService e = sameThreadExecutor();
+    ListeningExecutorService e = newDirectExecutorService();
     List<Callable<Integer>> l = new ArrayList<Callable<Integer>>();
     l.add(new Callable<Integer>() {
       @Override public Integer call() {
@@ -465,7 +465,7 @@
    * invokeAny(c) throws ExecutionException if no task in c completes
    */
   public void testInvokeAnyImpl_noTaskCompletes() throws Exception {
-    ListeningExecutorService e = sameThreadExecutor();
+    ListeningExecutorService e = newDirectExecutorService();
     List<Callable<String>> l = new ArrayList<Callable<String>>();
     l.add(new NPETask());
     try {
@@ -482,7 +482,7 @@
    * invokeAny(c) returns result of some task in c if at least one completes
    */
   public void testInvokeAnyImpl() throws Exception {
-    ListeningExecutorService e = sameThreadExecutor();
+    ListeningExecutorService e = newDirectExecutorService();
     try {
       List<Callable<String>> l = new ArrayList<Callable<String>>();
       l.add(new StringTask());
@@ -496,7 +496,7 @@
 
   private static void assertListenerRunImmediately(ListenableFuture<?> future) {
     CountingRunnable listener = new CountingRunnable();
-    future.addListener(listener, sameThreadExecutor());
+    future.addListener(listener, directExecutor());
     assertEquals(1, listener.count);
   }
 
@@ -591,7 +591,7 @@
   }
 
   public void testThreadRenaming() {
-    Executor renamingExecutor = renamingDecorator(sameThreadExecutor(),
+    Executor renamingExecutor = renamingDecorator(newDirectExecutorService(),
         Suppliers.ofInstance("FooBar"));
     String oldName = Thread.currentThread().getName();
     renamingExecutor.execute(new Runnable() {
diff --git a/guava-tests/test/com/google/common/util/concurrent/PackageSanityTests.java b/guava-tests/test/com/google/common/util/concurrent/PackageSanityTests.java
index d79b7b9..669e547 100644
--- a/guava-tests/test/com/google/common/util/concurrent/PackageSanityTests.java
+++ b/guava-tests/test/com/google/common/util/concurrent/PackageSanityTests.java
@@ -17,6 +17,7 @@
 package com.google.common.util.concurrent;
 
 import com.google.common.testing.AbstractPackageSanityTests;
+import com.google.common.util.concurrent.RateLimiter.SleepingStopwatch;
 
 /**
  * Basic sanity tests for the entire package.
@@ -25,7 +26,20 @@
  */
 
 public class PackageSanityTests extends AbstractPackageSanityTests {
+  private static final SleepingStopwatch NO_OP_STOPWATCH = new SleepingStopwatch() {
+    @Override
+    long readMicros() {
+      return 0;
+    }
+
+    @Override
+    void sleepMicrosUninterruptibly(long micros) {
+    }
+  };
+
   public PackageSanityTests() {
     setDefault(RateLimiter.class, RateLimiter.create(1.0));
+    setDefault(SleepingStopwatch.class, NO_OP_STOPWATCH);
+    setDefault(long.class, 0L);
   }
 }
diff --git a/guava-tests/test/com/google/common/util/concurrent/RateLimiterTest.java b/guava-tests/test/com/google/common/util/concurrent/RateLimiterTest.java
index 93fff44..62ced5c 100644
--- a/guava-tests/test/com/google/common/util/concurrent/RateLimiterTest.java
+++ b/guava-tests/test/com/google/common/util/concurrent/RateLimiterTest.java
@@ -16,12 +16,25 @@
 
 package com.google.common.util.concurrent;
 
+import static java.lang.reflect.Modifier.isStatic;
+import static java.util.concurrent.TimeUnit.MICROSECONDS;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import com.google.common.collect.ImmutableClassToInstanceMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import com.google.common.testing.NullPointerTester;
 import com.google.common.testing.NullPointerTester.Visibility;
+import com.google.common.util.concurrent.RateLimiter.SleepingStopwatch;
 
 import junit.framework.TestCase;
 
+import org.easymock.EasyMock;
+import org.mockito.Mockito;
+
+import java.lang.reflect.Method;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Random;
@@ -35,15 +48,10 @@
 public class RateLimiterTest extends TestCase {
   private static final double EPSILON = 1e-8;
 
-  /**
-   * The ticker gathers events and presents them as strings.
-   * R0.6 means a delay of 0.6 seconds caused by the (R)ateLimiter
-   * U1.0 means the (U)ser caused the ticker to sleep for a second.
-   */
-  private final FakeTicker ticker = new FakeTicker();
+  private final FakeStopwatch stopwatch = new FakeStopwatch();
 
   public void testSimple() {
-    RateLimiter limiter = RateLimiter.create(ticker, 5.0);
+    RateLimiter limiter = RateLimiter.create(stopwatch, 5.0);
     limiter.acquire(); // R0.00, since it's the first request
     limiter.acquire(); // R0.20
     limiter.acquire(); // R0.20
@@ -57,7 +65,7 @@
   }
 
   public void testSimpleRateUpdate() {
-    RateLimiter limiter = RateLimiter.create(5.0, 5, TimeUnit.SECONDS);
+    RateLimiter limiter = RateLimiter.create(5.0, 5, SECONDS);
     assertEquals(5.0, limiter.getRate());
     limiter.setRate(10.0);
     assertEquals(10.0, limiter.getRate());
@@ -65,35 +73,78 @@
     try {
       limiter.setRate(0.0);
       fail();
-    } catch (IllegalArgumentException ok) {}
+    } catch (IllegalArgumentException expected) {}
     try {
       limiter.setRate(-10.0);
       fail();
-    } catch (IllegalArgumentException ok) {}
+    } catch (IllegalArgumentException expected) {}
+  }
+
+  public void testAcquireParameterValidation() {
+    RateLimiter limiter = RateLimiter.create(999);
+    try {
+      limiter.acquire(0);
+      fail();
+    } catch (IllegalArgumentException expected) {
+    }
+    try {
+      limiter.acquire(-1);
+      fail();
+    } catch (IllegalArgumentException expected) {
+    }
+    try {
+      limiter.tryAcquire(0);
+      fail();
+    } catch (IllegalArgumentException expected) {
+    }
+    try {
+      limiter.tryAcquire(-1);
+      fail();
+    } catch (IllegalArgumentException expected) {
+    }
+    try {
+      limiter.tryAcquire(0, 1, SECONDS);
+      fail();
+    } catch (IllegalArgumentException expected) {
+    }
+    try {
+      limiter.tryAcquire(-1, 1, SECONDS);
+      fail();
+    } catch (IllegalArgumentException expected) {
+    }
   }
 
   public void testSimpleWithWait() {
-    RateLimiter limiter = RateLimiter.create(ticker, 5.0);
+    RateLimiter limiter = RateLimiter.create(stopwatch, 5.0);
     limiter.acquire();          // R0.00
-    ticker.sleepMillis(200);    // U0.20, we are ready for the next request...
+    stopwatch.sleepMillis(200);    // U0.20, we are ready for the next request...
     limiter.acquire();          // R0.00, ...which is granted immediately
     limiter.acquire();          // R0.20
     assertEvents("R0.00", "U0.20", "R0.00", "R0.20");
   }
 
   public void testSimpleAcquireReturnValues() {
-    RateLimiter limiter = RateLimiter.create(ticker, 5.0);
+    RateLimiter limiter = RateLimiter.create(stopwatch, 5.0);
     assertEquals(0.0, limiter.acquire(), EPSILON);  // R0.00
-    ticker.sleepMillis(200);                        // U0.20, we are ready for the next request...
+    stopwatch.sleepMillis(200);                     // U0.20, we are ready for the next request...
     assertEquals(0.0, limiter.acquire(), EPSILON);  // R0.00, ...which is granted immediately
     assertEquals(0.2, limiter.acquire(), EPSILON);  // R0.20
     assertEvents("R0.00", "U0.20", "R0.00", "R0.20");
   }
 
+  public void testSimpleAcquireEarliestAvailableIsInPast() {
+    RateLimiter limiter = RateLimiter.create(stopwatch, 5.0);
+    assertEquals(0.0, limiter.acquire(), EPSILON);
+    stopwatch.sleepMillis(400);
+    assertEquals(0.0, limiter.acquire(), EPSILON);
+    assertEquals(0.0, limiter.acquire(), EPSILON);
+    assertEquals(0.2, limiter.acquire(), EPSILON);
+  }
+
   public void testOneSecondBurst() {
-    RateLimiter limiter = RateLimiter.create(ticker, 5.0);
-    ticker.sleepMillis(1000); // max capacity reached
-    ticker.sleepMillis(1000); // this makes no difference
+    RateLimiter limiter = RateLimiter.create(stopwatch, 5.0);
+    stopwatch.sleepMillis(1000); // max capacity reached
+    stopwatch.sleepMillis(1000); // this makes no difference
     limiter.acquire(1); // R0.00, since it's the first request
 
     limiter.acquire(1); // R0.00, from capacity
@@ -106,18 +157,35 @@
         "R0.20");
   }
 
+  public void testCreateWarmupParameterValidation() {
+    RateLimiter.create(1.0, 1, NANOSECONDS);
+    RateLimiter.create(1.0, 0, NANOSECONDS);
+
+    try {
+      RateLimiter.create(0.0, 1, NANOSECONDS);
+      fail();
+    } catch (IllegalArgumentException expected) {
+    }
+
+    try {
+      RateLimiter.create(1.0, -1, NANOSECONDS);
+      fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
   public void testWarmUp() {
-    RateLimiter limiter = RateLimiter.create(ticker, 2.0, 4000, TimeUnit.MILLISECONDS);
+    RateLimiter limiter = RateLimiter.create(stopwatch, 2.0, 4000, MILLISECONDS);
     for (int i = 0; i < 8; i++) {
       limiter.acquire(); // #1
     }
-    ticker.sleepMillis(500); // #2: to repay for the last acquire
-    ticker.sleepMillis(4000); // #3: becomes cold again
+    stopwatch.sleepMillis(500); // #2: to repay for the last acquire
+    stopwatch.sleepMillis(4000); // #3: becomes cold again
     for (int i = 0; i < 8; i++) {
       limiter.acquire(); // // #4
     }
-    ticker.sleepMillis(500); // #5: to repay for the last acquire
-    ticker.sleepMillis(2000); // #6: didn't get cold! It would take another 2 seconds to go cold
+    stopwatch.sleepMillis(500); // #5: to repay for the last acquire
+    stopwatch.sleepMillis(2000); // #6: didn't get cold! It would take another 2 seconds to go cold
     for (int i = 0; i < 8; i++) {
       limiter.acquire(); // #7
     }
@@ -132,11 +200,11 @@
   }
 
   public void testWarmUpAndUpdate() {
-    RateLimiter limiter = RateLimiter.create(ticker, 2.0, 4000, TimeUnit.MILLISECONDS);
+    RateLimiter limiter = RateLimiter.create(stopwatch, 2.0, 4000, MILLISECONDS);
     for (int i = 0; i < 8; i++) {
       limiter.acquire(); // // #1
     }
-    ticker.sleepMillis(4500); // #2: back to cold state (warmup period + repay last acquire)
+    stopwatch.sleepMillis(4500); // #2: back to cold state (warmup period + repay last acquire)
     for (int i = 0; i < 3; i++) { // only three steps, we're somewhere in the warmup period
       limiter.acquire(); // #3
     }
@@ -146,7 +214,7 @@
     for (int i = 0; i < 4; i++) {
       limiter.acquire(); // #5
     }
-    ticker.sleepMillis(4250); // #6, back to cold state (warmup period + repay last acquire)
+    stopwatch.sleepMillis(4250); // #6, back to cold state (warmup period + repay last acquire)
     for (int i = 0; i < 11; i++) {
       limiter.acquire(); // #7, showing off the warmup starting from totally cold
     }
@@ -163,26 +231,8 @@
         "R0.34, R0.28, R0.25, R0.25"); // #7 (cont.), note, this matches #5
   }
 
-  public void testBursty() {
-    RateLimiter limiter = RateLimiter.createWithCapacity(ticker, 1.0, 10, TimeUnit.SECONDS);
-    ticker.sleepMillis(10000); // reach full capacity
-    limiter.acquire(11); // all these are served in a burst (10 + 1 by borrowing from the future)
-    limiter.acquire(1); // out of capacity, we have to wait
-    limiter.acquire(1); // and wait
-    ticker.sleepMillis(3000); // fill up 3 permits
-    limiter.acquire(5); // we had 3 ready, thus we borrow 2 permits
-    limiter.acquire(1); // this acquire() will also repay for the previous acquire()
-    assertEvents(
-        "U10.00",
-        "R0.00", // 10 permits grabbed
-        "R1.00", "R1.00", // 1 and 1
-        "U3.00", "R0.00", // 5 grabbed
-        "R3.00" // 1 grabbed
-        );
-  }
-
   public void testBurstyAndUpdate() {
-    RateLimiter rateLimiter = RateLimiter.create(ticker, 1.0);
+    RateLimiter rateLimiter = RateLimiter.create(stopwatch, 1.0);
     rateLimiter.acquire(1); // no wait
     rateLimiter.acquire(1); // R1.00, to repay previous
 
@@ -195,29 +245,42 @@
     assertEvents("R0.00", "R1.00", "R1.00", "R0.50", "R1.00", "R2.00");
   }
 
-  public void testTimeWrapping() {
-    ticker.instant = Long.MAX_VALUE - TimeUnit.SECONDS.toNanos(1); // 1 second before max value
-    RateLimiter limiter = RateLimiter.create(ticker, 1.0);
-    for (int i = 0; i < 4; i++) {
-      limiter.acquire();
-    }
-    // Without protection from overflow, the last wait value would have been huge,
-    // because "now" would have wrapped into a value near MIN_VALUE, and the limiter would think
-    // that the next request should be admitted far into the future
-    assertEvents("R0.00", "R1.00", "R1.00", "R1.00");
+  public void testTryAcquire_noWaitAllowed() {
+    RateLimiter limiter = RateLimiter.create(stopwatch, 5.0);
+    assertTrue(limiter.tryAcquire(0, SECONDS));
+    assertFalse(limiter.tryAcquire(0, SECONDS));
+    assertFalse(limiter.tryAcquire(0, SECONDS));
+    stopwatch.sleepMillis(100);
+    assertFalse(limiter.tryAcquire(0, SECONDS));
   }
 
-  public void testTryGate() {
-    RateLimiter limiter = RateLimiter.create(ticker, 5.0);
-    assertTrue(limiter.tryAcquire(0, TimeUnit.SECONDS));
-    assertFalse(limiter.tryAcquire(0, TimeUnit.SECONDS));
-    assertFalse(limiter.tryAcquire(0, TimeUnit.SECONDS));
-    ticker.sleepMillis(100);
-    assertFalse(limiter.tryAcquire(0, TimeUnit.SECONDS));
+  public void testTryAcquire_someWaitAllowed() {
+    RateLimiter limiter = RateLimiter.create(stopwatch, 5.0);
+    assertTrue(limiter.tryAcquire(0, SECONDS));
+    assertTrue(limiter.tryAcquire(200, MILLISECONDS));
+    assertFalse(limiter.tryAcquire(100, MILLISECONDS));
+    stopwatch.sleepMillis(100);
+    assertTrue(limiter.tryAcquire(100, MILLISECONDS));
+  }
+
+  public void testTryAcquire_overflow() {
+    RateLimiter limiter = RateLimiter.create(stopwatch, 5.0);
+    assertTrue(limiter.tryAcquire(0, MICROSECONDS));
+    stopwatch.sleepMillis(100);
+    assertTrue(limiter.tryAcquire(Long.MAX_VALUE, MICROSECONDS));
+  }
+
+  public void testTryAcquire_negative() {
+    RateLimiter limiter = RateLimiter.create(stopwatch, 5.0);
+    assertTrue(limiter.tryAcquire(5, 0, SECONDS));
+    stopwatch.sleepMillis(900);
+    assertFalse(limiter.tryAcquire(1, Long.MIN_VALUE, SECONDS));
+    stopwatch.sleepMillis(100);
+    assertTrue(limiter.tryAcquire(1, -1, SECONDS));
   }
 
   public void testSimpleWeights() {
-    RateLimiter rateLimiter = RateLimiter.create(ticker, 1.0);
+    RateLimiter rateLimiter = RateLimiter.create(stopwatch, 1.0);
     rateLimiter.acquire(1); // no wait
     rateLimiter.acquire(1); // R1.00, to repay previous
     rateLimiter.acquire(2); // R1.00, to repay previous
@@ -228,29 +291,51 @@
   }
 
   public void testInfinity_Bursty() {
-    RateLimiter limiter = RateLimiter.create(ticker, Double.POSITIVE_INFINITY);
+    RateLimiter limiter = RateLimiter.create(stopwatch, Double.POSITIVE_INFINITY);
     limiter.acquire(Integer.MAX_VALUE / 4);
     limiter.acquire(Integer.MAX_VALUE / 2);
     limiter.acquire(Integer.MAX_VALUE);
     assertEvents("R0.00", "R0.00", "R0.00"); // no wait, infinite rate!
 
-    limiter.setRate(1.0);
+    limiter.setRate(2.0);
     limiter.acquire();
     limiter.acquire();
     limiter.acquire();
-    assertEvents("R0.00", "R1.00", "R1.00"); // we repay the last request (but that had no cost)
-    // and then we go to 1 second per request mode
+    limiter.acquire();
+    limiter.acquire();
+    assertEvents(
+        "R0.00", // First comes the saved-up burst, which defaults to a 1-second burst (2 requests).
+        "R0.00",
+        "R0.00", // Now comes the free request.
+        "R0.50", // Now it's 0.5 seconds per request.
+        "R0.50");
 
     limiter.setRate(Double.POSITIVE_INFINITY);
     limiter.acquire();
     limiter.acquire();
     limiter.acquire();
-    assertEvents("R1.00", "R0.00", "R0.00"); // we repay the last request (1sec), then back to +oo
+    assertEvents("R0.50", "R0.00", "R0.00"); // we repay the last request (.5sec), then back to +oo
+  }
+
+  /** https://code.google.com/p/guava-libraries/issues/detail?id=1791 */
+  public void testInfinity_BustyTimeElapsed() {
+    RateLimiter limiter = RateLimiter.create(stopwatch, Double.POSITIVE_INFINITY);
+    stopwatch.instant += 1000000;
+    limiter.setRate(2.0);
+    for (int i = 0; i < 5; i++) {
+      limiter.acquire();
+    }
+    assertEvents(
+        "R0.00", // First comes the saved-up burst, which defaults to a 1-second burst (2 requests).
+        "R0.00",
+        "R0.00", // Now comes the free request.
+        "R0.50", // Now it's 0.5 seconds per request.
+        "R0.50");
   }
 
   public void testInfinity_WarmUp() {
     RateLimiter limiter = RateLimiter.create(
-        ticker, Double.POSITIVE_INFINITY, 10, TimeUnit.SECONDS);
+        stopwatch, Double.POSITIVE_INFINITY, 10, SECONDS);
     limiter.acquire(Integer.MAX_VALUE / 4);
     limiter.acquire(Integer.MAX_VALUE / 2);
     limiter.acquire(Integer.MAX_VALUE);
@@ -269,16 +354,26 @@
     assertEvents("R1.00", "R0.00", "R0.00");
   }
 
+  public void testInfinity_WarmUpTimeElapsed() {
+    RateLimiter limiter = RateLimiter.create(stopwatch, Double.POSITIVE_INFINITY, 10, SECONDS);
+    stopwatch.instant += 1000000;
+    limiter.setRate(1.0);
+    for (int i = 0; i < 5; i++) {
+      limiter.acquire();
+    }
+    assertEvents("R0.00", "R1.00", "R1.00", "R1.00", "R1.00");
+  }
+
   /**
    * Make sure that bursts can never go above 1-second-worth-of-work for the current
    * rate, even when we change the rate.
    */
   public void testWeNeverGetABurstMoreThanOneSec() {
-    RateLimiter limiter = RateLimiter.create(ticker, 1.0);
+    RateLimiter limiter = RateLimiter.create(stopwatch, 1.0);
     int[] rates = { 1000, 1, 10, 1000000, 10, 1};
     for (int rate : rates) {
       int oneSecWorthOfWork = rate;
-      ticker.sleepMillis(rate * 1000);
+      stopwatch.sleepMillis(rate * 1000);
       limiter.setRate(rate);
       long burst = measureTotalTimeMillis(limiter, oneSecWorthOfWork, new Random());
       // we allow one second worth of work to go in a burst (i.e. take less than a second)
@@ -307,7 +402,7 @@
         // warmupSeconds = 20 / qps
         long warmupMillis = (long) ((2 * maxPermits / qps) * 1000.0);
         RateLimiter rateLimiter = RateLimiter.create(
-            ticker, qps, warmupMillis, TimeUnit.MILLISECONDS);
+            stopwatch, qps, warmupMillis, MILLISECONDS);
         assertEquals(warmupMillis, measureTotalTimeMillis(rateLimiter, maxPermits, random));
       }
     }
@@ -315,41 +410,47 @@
 
   public void testNulls() {
     NullPointerTester tester = new NullPointerTester()
-        .setDefault(RateLimiter.SleepingTicker.class, ticker);
+        .setDefault(SleepingStopwatch.class, stopwatch)
+        .setDefault(int.class, 1);
     tester.testStaticMethods(RateLimiter.class, Visibility.PACKAGE);
-    tester.testInstanceMethods(RateLimiter.create(ticker, 5.0), Visibility.PACKAGE);
+    tester.testInstanceMethods(RateLimiter.create(stopwatch, 5.0), Visibility.PACKAGE);
   }
 
   private long measureTotalTimeMillis(RateLimiter rateLimiter, int permits, Random random) {
-    long startTime = ticker.instant;
+    long startTime = stopwatch.instant;
     while (permits > 0) {
       int nextPermitsToAcquire = Math.max(1, random.nextInt(permits));
       permits -= nextPermitsToAcquire;
       rateLimiter.acquire(nextPermitsToAcquire);
     }
     rateLimiter.acquire(1); // to repay for any pending debt
-    return TimeUnit.NANOSECONDS.toMillis(ticker.instant - startTime);
+    return NANOSECONDS.toMillis(stopwatch.instant - startTime);
   }
 
   private void assertEvents(String... events) {
-    assertEquals(Arrays.toString(events), ticker.readEventsAndClear());
+    assertEquals(Arrays.toString(events), stopwatch.readEventsAndClear());
   }
 
-  private static class FakeTicker extends RateLimiter.SleepingTicker {
+  /**
+   * The stopwatch gathers events and presents them as strings.
+   * R0.6 means a delay of 0.6 seconds caused by the (R)ateLimiter
+   * U1.0 means the (U)ser caused the stopwatch to sleep for a second.
+   */
+  static class FakeStopwatch extends SleepingStopwatch {
     long instant = 0L;
     final List<String> events = Lists.newArrayList();
 
     @Override
-    public long read() {
-      return instant;
+    public long readMicros() {
+      return NANOSECONDS.toMicros(instant);
     }
 
     void sleepMillis(int millis) {
-      sleepMicros("U", TimeUnit.MILLISECONDS.toMicros(millis));
+      sleepMicros("U", MILLISECONDS.toMicros(millis));
     }
 
     void sleepMicros(String caption, long micros) {
-      instant += TimeUnit.MICROSECONDS.toNanos(micros);
+      instant += MICROSECONDS.toNanos(micros);
       events.add(caption + String.format("%3.2f", (micros / 1000000.0)));
     }
 
@@ -371,4 +472,39 @@
       return events.toString();
     }
   }
+
+  public void testMocking() throws Exception {
+    RateLimiter mockito = Mockito.mock(RateLimiter.class);
+    RateLimiter easyMock = EasyMock.createNiceMock(RateLimiter.class);
+    EasyMock.replay(easyMock);
+    for (Method method : RateLimiter.class.getMethods()) {
+      if (!isStatic(method.getModifiers())
+          && !NOT_WORKING_ON_MOCKS.contains(method.getName())
+          && !method.getDeclaringClass().equals(Object.class)) {
+        method.invoke(mockito, arbitraryParameters(method));
+        method.invoke(easyMock, arbitraryParameters(method));
+      }
+    }
+  }
+
+  private static Object[] arbitraryParameters(Method method) {
+    Class<?>[] parameterTypes = method.getParameterTypes();
+    Object[] params = new Object[parameterTypes.length];
+    for (int i = 0; i < parameterTypes.length; i++) {
+      params[i] = PARAMETER_VALUES.get(parameterTypes[i]);
+    }
+    return params;
+  }
+
+  private static final ImmutableSet<String> NOT_WORKING_ON_MOCKS =
+      ImmutableSet.of("latestPermitAgeSec", "setRate");
+
+  // We would use ArbitraryInstances, but it returns 0, invalid for many RateLimiter methods.
+  private static final ImmutableClassToInstanceMap<Object> PARAMETER_VALUES =
+      ImmutableClassToInstanceMap.builder()
+          .put(int.class, 1)
+          .put(long.class, 1L)
+          .put(double.class, 1.0)
+          .put(TimeUnit.class, SECONDS)
+          .build();
 }
diff --git a/guava-tests/test/com/google/common/util/concurrent/SerializingExecutorTest.java b/guava-tests/test/com/google/common/util/concurrent/SerializingExecutorTest.java
index 01efd24..f055fe4 100644
--- a/guava-tests/test/com/google/common/util/concurrent/SerializingExecutorTest.java
+++ b/guava-tests/test/com/google/common/util/concurrent/SerializingExecutorTest.java
@@ -18,6 +18,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Queues;
 
 import junit.framework.TestCase;
 
@@ -39,7 +40,7 @@
  */
 public class SerializingExecutorTest extends TestCase {
   private static class FakeExecutor implements Executor {
-    Queue<Runnable> tasks = Lists.newLinkedList();
+    Queue<Runnable> tasks = Queues.newArrayDeque();
     @Override public void execute(Runnable command) {
       tasks.add(command);
     }
diff --git a/guava-tests/test/com/google/common/util/concurrent/ServiceManagerTest.java b/guava-tests/test/com/google/common/util/concurrent/ServiceManagerTest.java
index 147ed64..302b7d1 100644
--- a/guava-tests/test/com/google/common/util/concurrent/ServiceManagerTest.java
+++ b/guava-tests/test/com/google/common/util/concurrent/ServiceManagerTest.java
@@ -15,6 +15,7 @@
  */
 package com.google.common.util.concurrent;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Arrays.asList;
 
 import com.google.common.collect.ImmutableMap;
@@ -62,10 +63,10 @@
    * A NoOp service that will delay the startup and shutdown notification for a configurable amount
    * of time.
    */
-  private static class NoOpDelayedSerivce extends NoOpService {
+  private static class NoOpDelayedService extends NoOpService {
     private long delay;
 
-    public NoOpDelayedSerivce(long delay) {
+    public NoOpDelayedService(long delay) {
       this.delay = delay;
     }
 
@@ -108,14 +109,44 @@
   }
 
   public void testServiceStartupTimes() {
-    Service a = new NoOpDelayedSerivce(150);
-    Service b = new NoOpDelayedSerivce(353);
+    Service a = new NoOpDelayedService(150);
+    Service b = new NoOpDelayedService(353);
     ServiceManager serviceManager = new ServiceManager(asList(a, b));
     serviceManager.startAsync().awaitHealthy();
     ImmutableMap<Service, Long> startupTimes = serviceManager.startupTimes();
     assertEquals(2, startupTimes.size());
-    assertTrue(startupTimes.get(a) >= 150);
-    assertTrue(startupTimes.get(b) >= 353);
+    assertThat(startupTimes.get(a)).isInclusivelyInRange(150, Long.MAX_VALUE);
+    assertThat(startupTimes.get(b)).isInclusivelyInRange(353, Long.MAX_VALUE);
+  }
+
+  public void testServiceStartupTimes_selfStartingServices() {
+    // This tests to ensure that:
+    // 1. service times are accurate when the service is started by the manager
+    // 2. service times are recorded when the service is not started by the manager (but they may
+    // not be accurate).
+    final Service b = new NoOpDelayedService(353) {
+      @Override protected void doStart() {
+        super.doStart();
+        // This will delay service listener execution at least 150 milliseconds
+        Uninterruptibles.sleepUninterruptibly(150, TimeUnit.MILLISECONDS);
+      }
+    };
+    Service a = new NoOpDelayedService(150) {
+      @Override protected void doStart() {
+        b.startAsync();
+        super.doStart();
+      }
+    };
+    ServiceManager serviceManager = new ServiceManager(asList(a, b));
+    serviceManager.startAsync().awaitHealthy();
+    ImmutableMap<Service, Long> startupTimes = serviceManager.startupTimes();
+    assertEquals(2, startupTimes.size());
+    assertThat(startupTimes.get(a)).isInclusivelyInRange(150, Long.MAX_VALUE);
+    // Service b startup takes at least 353 millis, but starting the timer is delayed by at least
+    // 150 milliseconds. so in a perfect world the timing would be 353-150=203ms, but since either
+    // of our sleep calls can be arbitrarily delayed we should just assert that there is a time
+    // recorded.
+    assertThat(startupTimes.get(b)).isNotNull();
   }
 
   public void testServiceStartStop() {
@@ -217,7 +248,7 @@
   }
 
   public void testTimeouts() throws Exception {
-    Service a = new NoOpDelayedSerivce(50);
+    Service a = new NoOpDelayedService(50);
     ServiceManager manager = new ServiceManager(asList(a));
     manager.startAsync();
     try {
@@ -311,7 +342,7 @@
     logger.addHandler(logHandler);
     ServiceManager manager = new ServiceManager(Arrays.<Service>asList());
     RecordingListener listener = new RecordingListener();
-    manager.addListener(listener, MoreExecutors.sameThreadExecutor());
+    manager.addListener(listener);
     manager.startAsync().awaitHealthy();
     assertTrue(manager.isHealthy());
     assertTrue(listener.healthyCalled);
@@ -369,7 +400,7 @@
         // block until after the service manager is shutdown
         Uninterruptibles.awaitUninterruptibly(failLeave);
       }
-    }, MoreExecutors.sameThreadExecutor());
+    });
     manager.startAsync();
     afterStarted.countDown();
     // We do not call awaitHealthy because, due to races, that method may throw an exception.  But
@@ -433,22 +464,6 @@
         return delegate.stopAsync();
       }
 
-      @Override public final ListenableFuture<State> start() {
-        return delegate.start();
-      }
-
-      @Override public final ListenableFuture<State> stop() {
-        return delegate.stop();
-      }
-
-      @Override public State startAndWait() {
-        return delegate.startAndWait();
-      }
-
-      @Override public State stopAndWait() {
-        return delegate.stopAndWait();
-      }
-
       @Override public final void awaitRunning() {
         delegate.awaitRunning();
       }
diff --git a/guava-tests/test/com/google/common/util/concurrent/TestThread.java b/guava-tests/test/com/google/common/util/concurrent/TestThread.java
new file mode 100644
index 0000000..1a7c1a3
--- /dev/null
+++ b/guava-tests/test/com/google/common/util/concurrent/TestThread.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2010 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.util.concurrent;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertSame;
+
+import com.google.common.testing.TearDown;
+
+import junit.framework.AssertionFailedError;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import javax.annotation.Nullable;
+
+/**
+ * A helper for concurrency testing. One or more {@code TestThread} instances are instantiated
+ * in a test with reference to the same "lock-like object", and then their interactions with that
+ * object are choreographed via the various methods on this class.
+ * 
+ * <p>A "lock-like object" is really any object that may be used for concurrency control. If the
+ * {@link #callAndAssertBlocks} method is ever called in a test, the lock-like object must have a
+ * method equivalent to {@link java.util.concurrent.locks.ReentrantLock#hasQueuedThread(Thread)}. If
+ * the {@link #callAndAssertWaits} method is ever called in a test, the lock-like object must have a
+ * method equivalent to {@link
+ * java.util.concurrent.locks.ReentrantLock#hasWaiters(java.util.concurrent.locks.Condition)},
+ * except that the method parameter must accept whatever condition-like object is passed into
+ * {@code callAndAssertWaits} by the test.
+ *
+ * @param <L> the type of the lock-like object to be used
+ * @author Justin T. Sampson
+ */
+public final class TestThread<L> extends Thread implements TearDown {
+
+  private static final long DUE_DILIGENCE_MILLIS = 50;
+  private static final long TIMEOUT_MILLIS = 5000;
+
+  private final L lockLikeObject;
+
+  private final SynchronousQueue<Request> requestQueue = new SynchronousQueue<Request>();
+  private final SynchronousQueue<Response> responseQueue = new SynchronousQueue<Response>();
+  
+  private Throwable uncaughtThrowable = null;
+  
+  public TestThread(L lockLikeObject, String threadName) {
+    super(threadName);
+    this.lockLikeObject = checkNotNull(lockLikeObject);
+    start();
+  }
+
+  // Thread.stop() is okay because all threads started by a test are dying at the end of the test,
+  // so there is no object state put at risk by stopping the threads abruptly. In some cases a test
+  // may put a thread into an uninterruptible operation intentionally, so there is no other way to
+  // clean up these threads.
+  @SuppressWarnings("deprecation")
+  @Override public void tearDown() throws Exception {
+    stop();
+    join();
+
+    if (uncaughtThrowable != null) {
+      throw (AssertionFailedError) new AssertionFailedError("Uncaught throwable in " + getName())
+          .initCause(uncaughtThrowable);
+    }
+  }
+
+  /**
+   * Causes this thread to call the named void method, and asserts that the call returns normally.
+   */
+  public void callAndAssertReturns(String methodName, Object... arguments) throws Exception {
+    checkNotNull(methodName);
+    checkNotNull(arguments);
+    sendRequest(methodName, arguments);
+    assertSame(null, getResponse(methodName).getResult());
+  }
+  
+  /**
+   * Causes this thread to call the named method, and asserts that the call returns the expected
+   * boolean value.
+   */
+  public void callAndAssertReturns(boolean expected, String methodName, Object... arguments)
+      throws Exception {
+    checkNotNull(methodName);
+    checkNotNull(arguments);
+    sendRequest(methodName, arguments);
+    assertEquals(expected, getResponse(methodName).getResult());
+  }
+  
+  /**
+   * Causes this thread to call the named method, and asserts that the call returns the expected
+   * int value.
+   */
+  public void callAndAssertReturns(int expected, String methodName, Object... arguments)
+      throws Exception {
+    checkNotNull(methodName);
+    checkNotNull(arguments);
+    sendRequest(methodName, arguments);
+    assertEquals(expected, getResponse(methodName).getResult());
+  }
+  
+  /**
+   * Causes this thread to call the named method, and asserts that the call throws the expected
+   * type of throwable.
+   */
+  public void callAndAssertThrows(Class<? extends Throwable> expected,
+      String methodName, Object... arguments) throws Exception {
+    checkNotNull(expected);
+    checkNotNull(methodName);
+    checkNotNull(arguments);
+    sendRequest(methodName, arguments);
+    assertEquals(expected, getResponse(methodName).getThrowable().getClass());
+  }
+
+  /**
+   * Causes this thread to call the named method, and asserts that this thread becomes blocked on
+   * the lock-like object. The lock-like object must have a method equivalent to {@link
+   * java.util.concurrent.locks.ReentrantLock#hasQueuedThread(Thread)}.
+   */
+  public void callAndAssertBlocks(String methodName, Object... arguments) throws Exception {
+    checkNotNull(methodName);
+    checkNotNull(arguments);
+    assertEquals(false, invokeMethod("hasQueuedThread", this));
+    sendRequest(methodName, arguments);
+    Thread.sleep(DUE_DILIGENCE_MILLIS);
+    assertEquals(true, invokeMethod("hasQueuedThread", this));
+    assertNull(responseQueue.poll());
+  }
+
+  /**
+   * Causes this thread to call the named method, and asserts that this thread thereby waits on
+   * the given condition-like object. The lock-like object must have a method equivalent to {@link
+   * java.util.concurrent.locks.ReentrantLock#hasWaiters(java.util.concurrent.locks.Condition)},
+   * except that the method parameter must accept whatever condition-like object is passed into
+   * this method.
+   */
+  public void callAndAssertWaits(String methodName, Object conditionLikeObject)
+      throws Exception {
+    checkNotNull(methodName);
+    checkNotNull(conditionLikeObject);
+    // TODO: Restore the following line when Monitor.hasWaiters() no longer acquires the lock.
+    // assertEquals(false, invokeMethod("hasWaiters", conditionLikeObject));
+    sendRequest(methodName, conditionLikeObject);
+    Thread.sleep(DUE_DILIGENCE_MILLIS);
+    assertEquals(true, invokeMethod("hasWaiters", conditionLikeObject));
+    assertNull(responseQueue.poll());
+  }
+
+  /**
+   * Asserts that a prior call that had caused this thread to block or wait has since returned
+   * normally.
+   */
+  public void assertPriorCallReturns(@Nullable String methodName) throws Exception {
+    assertEquals(null, getResponse(methodName).getResult());
+  }
+  
+  /**
+   * Asserts that a prior call that had caused this thread to block or wait has since returned
+   * the expected boolean value.
+   */
+  public void assertPriorCallReturns(boolean expected, @Nullable String methodName)
+      throws Exception {
+    assertEquals(expected, getResponse(methodName).getResult());
+  }
+
+  /**
+   * Sends the given method call to this thread.
+   * 
+   * @throws TimeoutException if this thread does not accept the request within a resonable amount
+   *         of time
+   */
+  private void sendRequest(String methodName, Object... arguments) throws Exception {
+    if (!requestQueue.offer(
+        new Request(methodName, arguments), TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
+      throw new TimeoutException();
+    }
+  }
+
+  /**
+   * Receives a response from this thread.
+   * 
+   * @throws TimeoutException if this thread does not offer a response within a resonable amount of
+   *         time
+   * @throws AssertionFailedError if the given method name does not match the name of the method
+   *         this thread has called most recently
+   */
+  private Response getResponse(String methodName) throws Exception {
+    Response response = responseQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+    if (response == null) {
+      throw new TimeoutException();
+    }
+    assertEquals(methodName, response.methodName);
+    return response;
+  }
+
+  private Object invokeMethod(String methodName, Object... arguments) throws Exception {
+    return getMethod(methodName, arguments).invoke(lockLikeObject, arguments);
+  }
+  
+  private Method getMethod(String methodName, Object... arguments) throws Exception {
+    METHODS: for (Method method : lockLikeObject.getClass().getMethods()) {
+      Class<?>[] parameterTypes = method.getParameterTypes();
+      if (method.getName().equals(methodName) && (parameterTypes.length == arguments.length)) {
+        for (int i = 0; i < arguments.length; i++) {
+          if (!parameterTypes[i].isAssignableFrom(arguments[i].getClass())) {
+            continue METHODS;
+          }
+        }
+        return method;
+      }
+    }
+    throw new NoSuchMethodError(methodName);
+  }
+
+  @Override public void run() {
+    assertSame(this, Thread.currentThread());
+    try {
+      while (true) {
+        Request request = requestQueue.take();
+        Object result;
+        try {
+          result = invokeMethod(request.methodName, request.arguments);
+        } catch (ThreadDeath death) {
+          return;
+        } catch (InvocationTargetException exception) {
+          responseQueue.put(
+              new Response(request.methodName, null, exception.getTargetException()));
+          continue;
+        } catch (Throwable throwable) {
+          responseQueue.put(new Response(request.methodName, null, throwable));
+          continue;
+        }
+        responseQueue.put(new Response(request.methodName, result, null));
+      }
+    } catch (ThreadDeath death) {
+      return;
+    } catch (InterruptedException ignored) {
+      // SynchronousQueue sometimes throws InterruptedException while the threads are stopping.
+    } catch (Throwable uncaught) {
+      this.uncaughtThrowable = uncaught;
+    }
+  }
+
+  private static class Request {
+    final String methodName;
+    final Object[] arguments;
+    
+    Request(String methodName, Object[] arguments) {
+      this.methodName = checkNotNull(methodName);
+      this.arguments = checkNotNull(arguments);
+    }
+  }
+
+  private static class Response {
+    final String methodName;
+    final Object result;
+    final Throwable throwable;
+    
+    Response(String methodName, Object result, Throwable throwable) {
+      this.methodName = methodName;
+      this.result = result;
+      this.throwable = throwable;
+    }
+    
+    Object getResult() {
+      if (throwable != null) {
+        throw (AssertionFailedError) new AssertionFailedError().initCause(throwable);
+      }
+      return result;
+    }
+    
+    Throwable getThrowable() {
+      assertNotNull(throwable);
+      return throwable;
+    }
+  }
+}
diff --git a/guava-tests/test/com/google/common/util/concurrent/ThreadFactoryBuilderTest.java b/guava-tests/test/com/google/common/util/concurrent/ThreadFactoryBuilderTest.java
index d26ba63..3582415 100644
--- a/guava-tests/test/com/google/common/util/concurrent/ThreadFactoryBuilderTest.java
+++ b/guava-tests/test/com/google/common/util/concurrent/ThreadFactoryBuilderTest.java
@@ -16,7 +16,7 @@
 
 package com.google.common.util.concurrent;
 
-import static org.truth0.Truth.ASSERT;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.testing.NullPointerTester;
 
@@ -83,7 +83,7 @@
     ThreadFactory threadFactory2 = builder.build();
     Thread thread3 = threadFactory2.newThread(monitoredRunnable);
     checkThreadPoolName(thread3, 1);
-    ASSERT.that(
+    assertThat(
         thread2.getName().substring(0, thread.getName().lastIndexOf('-')))
         .isNotEqualTo(
             thread3.getName().substring(0, thread.getName().lastIndexOf('-')));
diff --git a/guava-tests/test/com/google/common/util/concurrent/UninterruptibleMonitorTest.java b/guava-tests/test/com/google/common/util/concurrent/UninterruptibleMonitorTest.java
new file mode 100644
index 0000000..17690ad
--- /dev/null
+++ b/guava-tests/test/com/google/common/util/concurrent/UninterruptibleMonitorTest.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2010 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.util.concurrent;
+
+/**
+ * Tests for {@link Monitor}'s uninterruptible methods.
+ *
+ * @author Justin T. Sampson
+ */
+
+public class UninterruptibleMonitorTest extends MonitorTestCase {
+
+  public UninterruptibleMonitorTest() {
+    super(false);
+  }
+
+}
diff --git a/guava-tests/test/com/google/common/util/concurrent/WrappingExecutorServiceTest.java b/guava-tests/test/com/google/common/util/concurrent/WrappingExecutorServiceTest.java
index 48e605d..900bd5d 100644
--- a/guava-tests/test/com/google/common/util/concurrent/WrappingExecutorServiceTest.java
+++ b/guava-tests/test/com/google/common/util/concurrent/WrappingExecutorServiceTest.java
@@ -16,6 +16,9 @@
 
 package com.google.common.util.concurrent;
 
+import static com.google.common.util.concurrent.MoreExecutors.newDirectExecutorService;
+import static com.google.common.util.concurrent.Runnables.doNothing;
+
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
@@ -40,12 +43,6 @@
  */
 public class WrappingExecutorServiceTest extends TestCase {
   private static final String RESULT_VALUE = "ran";
-  private static final Runnable DO_NOTHING = new Runnable() {
-    @Override
-    public void run() {
-    }
-  };
-
   // Uninteresting delegations
   public void testDelegations() throws InterruptedException {
     MockExecutor mock = new MockExecutor();
@@ -66,7 +63,7 @@
   public void testExecute() {
     MockExecutor mock = new MockExecutor();
     TestExecutor testExecutor = new TestExecutor(mock);
-    testExecutor.execute(DO_NOTHING);
+    testExecutor.execute(doNothing());
     mock.assertLastMethodCalled("execute");
   }
 
@@ -74,14 +71,14 @@
     {
       MockExecutor mock = new MockExecutor();
       TestExecutor testExecutor = new TestExecutor(mock);
-      Future<?> f = testExecutor.submit(DO_NOTHING);
+      Future<?> f = testExecutor.submit(doNothing());
       mock.assertLastMethodCalled("submit");
       f.get();
     }
     {
       MockExecutor mock = new MockExecutor();
       TestExecutor testExecutor = new TestExecutor(mock);
-      Future<String> f = testExecutor.submit(DO_NOTHING, RESULT_VALUE);
+      Future<String> f = testExecutor.submit(doNothing(), RESULT_VALUE);
       mock.assertLastMethodCalled("submit");
       assertEquals(RESULT_VALUE, f.get());
     }
@@ -195,7 +192,7 @@
   private static final class MockExecutor implements ExecutorService {
     private String lastMethodCalled = "";
     private long lastTimeoutInMillis = -1;
-    private ExecutorService inline = MoreExecutors.sameThreadExecutor();
+    private ExecutorService inline = newDirectExecutorService();
 
     public void assertLastMethodCalled(String method) {
       assertEquals(method, lastMethodCalled);
diff --git a/guava-tests/test/com/google/common/util/concurrent/WrappingScheduledExecutorServiceTest.java b/guava-tests/test/com/google/common/util/concurrent/WrappingScheduledExecutorServiceTest.java
index 479fa8c..9beadb4 100644
--- a/guava-tests/test/com/google/common/util/concurrent/WrappingScheduledExecutorServiceTest.java
+++ b/guava-tests/test/com/google/common/util/concurrent/WrappingScheduledExecutorServiceTest.java
@@ -45,8 +45,8 @@
     MockExecutor mock = new MockExecutor();
     TestExecutor testExecutor = new TestExecutor(mock);
     
-    testExecutor.schedule(DO_NOTHING, 10, TimeUnit.SECONDS);
-    mock.assertLastMethodCalled("scheduleRunnable", 10, TimeUnit.SECONDS);
+    testExecutor.schedule(DO_NOTHING, 10, TimeUnit.MINUTES);
+    mock.assertLastMethodCalled("scheduleRunnable", 10, TimeUnit.MINUTES);
     
     testExecutor.schedule(Executors.callable(DO_NOTHING), 5, TimeUnit.SECONDS);
     mock.assertLastMethodCalled("scheduleCallable", 5, TimeUnit.SECONDS);
@@ -55,8 +55,8 @@
   public void testSchedule_repeating() {
     MockExecutor mock = new MockExecutor();
     TestExecutor testExecutor = new TestExecutor(mock);
-    testExecutor.scheduleWithFixedDelay(DO_NOTHING, 100, 10, TimeUnit.SECONDS);
-    mock.assertLastMethodCalled("scheduleWithFixedDelay", 100, 10, TimeUnit.SECONDS);
+    testExecutor.scheduleWithFixedDelay(DO_NOTHING, 100, 10, TimeUnit.MINUTES);
+    mock.assertLastMethodCalled("scheduleWithFixedDelay", 100, 10, TimeUnit.MINUTES);
     
     testExecutor.scheduleAtFixedRate(DO_NOTHING, 3, 7, TimeUnit.SECONDS);
     mock.assertLastMethodCalled("scheduleAtFixedRate", 3, 7, TimeUnit.SECONDS);
diff --git a/guava/pom.xml b/guava/pom.xml
index 8a5d6a5..4cf038a 100644
--- a/guava/pom.xml
+++ b/guava/pom.xml
@@ -4,11 +4,11 @@
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>com.google.guava</groupId>
-    <artifactId>guava-parent-jdk5</artifactId>
-    <version>17.0</version>
+    <artifactId>guava-parent</artifactId>
+    <version>18.0</version>
   </parent>
-  <artifactId>guava-jdk5</artifactId>
-  <name>Guava: Google Core Libraries for Java (JDK5 Backport)</name>
+  <artifactId>guava</artifactId>
+  <name>Guava: Google Core Libraries for Java</name>
   <packaging>bundle</packaging>
   <description>
     Guava is a suite of core and expanded libraries that include
@@ -25,12 +25,6 @@
       <optional>true</optional><!-- needed only for annotations -->
     </dependency>
     <!-- TODO(cpovirk): want this only for dependency plugin but seems not to work there? Maven runs without failure, but the resulting Javadoc is missing the hoped-for inherited text -->
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>guava-bootstrap-jdk5</artifactId>
-      <version>${project.version}</version>
-      <scope>provided</scope>
-    </dependency>
   </dependencies>
   <build>
     <plugins>
@@ -53,18 +47,14 @@
             <Export-Package>!com.google.common.base.internal,com.google.common.*</Export-Package>
             <Import-Package>
               javax.annotation;resolution:=optional,
-              javax.inject;resolution:=optional,
               sun.misc.*;resolution:=optional
             </Import-Package>
+            <Bundle-DocURL>https://guava-libraries.googlecode.com/</Bundle-DocURL>
           </instructions>
         </configuration>
       </plugin>
       <plugin>
         <artifactId>maven-compiler-plugin</artifactId>
-        <configuration>
-          <!-- Prepend guava-bootstrap to avoid an API incompatibility between JDK5 and JDK6 -->
-          <compilerArgument>-Xbootclasspath/p:${project.build.directory}/dependency/guava-bootstrap-jdk5-${project.version}.jar</compilerArgument>
-        </configuration>
       </plugin>
       <plugin>
         <artifactId>maven-source-plugin</artifactId>
@@ -74,14 +64,6 @@
         <artifactId>maven-dependency-plugin</artifactId>
         <executions>
           <execution>
-            <id>prep-guava-bootstrap</id>
-            <phase>process-sources</phase>
-            <goals><goal>copy-dependencies</goal></goals>
-            <configuration>
-              <includeArtifactIds>guava-bootstrap-jdk5</includeArtifactIds>
-            </configuration>
-          </execution>
-          <execution>
             <id>unpack-jdk-sources</id>
             <phase>site</phase>
             <goals><goal>unpack-dependencies</goal></goals>
diff --git a/guava/src/com/google/common/base/CaseFormat.java b/guava/src/com/google/common/base/CaseFormat.java
index b950509..0b4cb5c 100644
--- a/guava/src/com/google/common/base/CaseFormat.java
+++ b/guava/src/com/google/common/base/CaseFormat.java
@@ -207,7 +207,7 @@
   }
 
   private static String firstCharOnlyToUpper(String word) {
-    return (word.length() == 0)
+    return (word.isEmpty())
         ? word
         : new StringBuilder(word.length())
             .append(Ascii.toUpperCase(word.charAt(0)))
diff --git a/guava/src/com/google/common/base/Charsets.java b/guava/src/com/google/common/base/Charsets.java
index 52b2d5d..37fc686 100644
--- a/guava/src/com/google/common/base/Charsets.java
+++ b/guava/src/com/google/common/base/Charsets.java
@@ -41,6 +41,9 @@
   /**
    * US-ASCII: seven-bit ASCII, the Basic Latin block of the Unicode character set (ISO646-US).
    *
+   * <p><b>Note for Java 7 and later:</b> this constant should be treated as deprecated; use
+   * {@link java.nio.charset.StandardCharsets#US_ASCII} instead.
+   *
    */
   @GwtIncompatible("Non-UTF-8 Charset")
   public static final Charset US_ASCII = Charset.forName("US-ASCII");
@@ -48,6 +51,9 @@
   /**
    * ISO-8859-1: ISO Latin Alphabet Number 1 (ISO-LATIN-1).
    *
+   * <p><b>Note for Java 7 and later:</b> this constant should be treated as deprecated; use
+   * {@link java.nio.charset.StandardCharsets#ISO_8859_1} instead.
+   *
    */
   @GwtIncompatible("Non-UTF-8 Charset")
   public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
@@ -55,12 +61,18 @@
   /**
    * UTF-8: eight-bit UCS Transformation Format.
    *
+   * <p><b>Note for Java 7 and later:</b> this constant should be treated as deprecated; use
+   * {@link java.nio.charset.StandardCharsets#UTF_8} instead.
+   *
    */
   public static final Charset UTF_8 = Charset.forName("UTF-8");
 
   /**
    * UTF-16BE: sixteen-bit UCS Transformation Format, big-endian byte order.
    *
+   * <p><b>Note for Java 7 and later:</b> this constant should be treated as deprecated; use
+   * {@link java.nio.charset.StandardCharsets#UTF_16BE} instead.
+   *
    */
   @GwtIncompatible("Non-UTF-8 Charset")
   public static final Charset UTF_16BE = Charset.forName("UTF-16BE");
@@ -68,6 +80,9 @@
   /**
    * UTF-16LE: sixteen-bit UCS Transformation Format, little-endian byte order.
    *
+   * <p><b>Note for Java 7 and later:</b> this constant should be treated as deprecated; use
+   * {@link java.nio.charset.StandardCharsets#UTF_16LE} instead.
+   *
    */
   @GwtIncompatible("Non-UTF-8 Charset")
   public static final Charset UTF_16LE = Charset.forName("UTF-16LE");
@@ -76,6 +91,9 @@
    * UTF-16: sixteen-bit UCS Transformation Format, byte order identified by an optional byte-order
    * mark.
    *
+   * <p><b>Note for Java 7 and later:</b> this constant should be treated as deprecated; use
+   * {@link java.nio.charset.StandardCharsets#UTF_16} instead.
+   *
    */
   @GwtIncompatible("Non-UTF-8 Charset")
   public static final Charset UTF_16 = Charset.forName("UTF-16");
diff --git a/guava/src/com/google/common/base/Converter.java b/guava/src/com/google/common/base/Converter.java
index 55f88b4..6c13776 100644
--- a/guava/src/com/google/common/base/Converter.java
+++ b/guava/src/com/google/common/base/Converter.java
@@ -284,7 +284,14 @@
    * <p>The returned converter is serializable if {@code this} converter and {@code secondConverter}
    * are.
    */
-  public <C> Converter<A, C> andThen(Converter<B, C> secondConverter) {
+  public final <C> Converter<A, C> andThen(Converter<B, C> secondConverter) {
+    return doAndThen(secondConverter);
+  }
+
+  /**
+   * Package-private non-final implementation of andThen() so only we can override it.
+   */
+  <C> Converter<A, C> doAndThen(Converter<B, C> secondConverter) {
     return new ConverterComposition<A, B, C>(this, checkNotNull(secondConverter));
   }
 
@@ -472,7 +479,7 @@
     }
 
     @Override
-    public <S> Converter<T, S> andThen(Converter<T, S> otherConverter) {
+    <S> Converter<T, S> doAndThen(Converter<T, S> otherConverter) {
       return checkNotNull(otherConverter, "otherConverter");
     }
 
diff --git a/guava/src/com/google/common/base/Defaults.java b/guava/src/com/google/common/base/Defaults.java
index f8bcce7..e07c75c 100644
--- a/guava/src/com/google/common/base/Defaults.java
+++ b/guava/src/com/google/common/base/Defaults.java
@@ -22,6 +22,8 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import javax.annotation.Nullable;
+
 /**
  * This class provides default values for all Java types, as defined by the JLS.
  *
@@ -56,6 +58,7 @@
    * false} for {@code boolean} and {@code '\0'} for {@code char}. For non-primitive types and
    * {@code void}, null is returned.
    */
+  @Nullable
   public static <T> T defaultValue(Class<T> type) {
     // Primitives.wrap(type).cast(...) would avoid the warning, but we can't use that from here
     @SuppressWarnings("unchecked") // the put method enforces this key-value relationship
diff --git a/guava/src/com/google/common/base/Enums.java b/guava/src/com/google/common/base/Enums.java
index 0c01d42..dbc3754 100644
--- a/guava/src/com/google/common/base/Enums.java
+++ b/guava/src/com/google/common/base/Enums.java
@@ -63,61 +63,6 @@
   }
 
   /**
-   * Returns a {@link Function} that maps an {@link Enum} name to the associated {@code Enum}
-   * constant. The {@code Function} will return {@code null} if the {@code Enum} constant
-   * does not exist.
-   *
-   * @param enumClass the {@link Class} of the {@code Enum} declaring the constant values
-   * @deprecated Use {@link Enums#stringConverter} instead. Note that the string converter has
-   *     slightly different behavior: it throws {@link IllegalArgumentException} if the enum
-   *     constant does not exist rather than returning {@code null}. It also converts {@code null}
-   *     to {@code null} rather than throwing {@link NullPointerException}. This method is
-   *     scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static <T extends Enum<T>> Function<String, T> valueOfFunction(
-      Class<T> enumClass) {
-    return new ValueOfFunction<T>(enumClass);
-  }
-
-  /**
-   * A {@link Function} that maps an {@link Enum} name to the associated constant, or {@code null}
-   * if the constant does not exist.
-   */
-  private static final class ValueOfFunction<T extends Enum<T>>
-      implements Function<String, T>, Serializable {
-
-    private final Class<T> enumClass;
-
-    private ValueOfFunction(Class<T> enumClass) {
-      this.enumClass = checkNotNull(enumClass);
-    }
-
-    @Override
-    public T apply(String value) {
-      try {
-        return Enum.valueOf(enumClass, value);
-      } catch (IllegalArgumentException e) {
-        return null;
-      }
-    }
-
-    @Override public boolean equals(@Nullable Object obj) {
-      return obj instanceof ValueOfFunction && enumClass.equals(((ValueOfFunction) obj).enumClass);
-    }
-
-    @Override public int hashCode() {
-      return enumClass.hashCode();
-    }
-
-    @Override public String toString() {
-      return "Enums.valueOf(" + enumClass + ")";
-    }
-
-    private static final long serialVersionUID = 0;
-  }
-
-  /**
    * Returns an optional enum constant for the given type, using {@link Enum#valueOf}. If the
    * constant does not exist, {@link Optional#absent} is returned. A common use case is for parsing
    * user input or falling back to a default enum constant. For example,
diff --git a/guava/src/com/google/common/base/Equivalence.java b/guava/src/com/google/common/base/Equivalence.java
index f620825..be654cf 100644
--- a/guava/src/com/google/common/base/Equivalence.java
+++ b/guava/src/com/google/common/base/Equivalence.java
@@ -326,7 +326,7 @@
     @Override protected boolean doEquivalent(Object a, Object b) {
       return a.equals(b);
     }
-    @Override public int doHash(Object o) {
+    @Override protected int doHash(Object o) {
       return o.hashCode();
     }
 
diff --git a/guava/src/com/google/common/base/FinalizableReferenceQueue.java b/guava/src/com/google/common/base/FinalizableReferenceQueue.java
index 71d1c84..ddd27fa 100644
--- a/guava/src/com/google/common/base/FinalizableReferenceQueue.java
+++ b/guava/src/com/google/common/base/FinalizableReferenceQueue.java
@@ -30,6 +30,8 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import javax.annotation.Nullable;
+
 /**
  * A reference queue with an associated background thread that dequeues references and invokes
  * {@link FinalizableReference#finalizeReferent()} on them.
@@ -228,6 +230,7 @@
      *
      * @throws SecurityException if we don't have the appropriate privileges
      */
+    @Nullable
     Class<?> loadFinalizer();
   }
 
diff --git a/guava/src/com/google/common/base/MoreObjects.java b/guava/src/com/google/common/base/MoreObjects.java
new file mode 100644
index 0000000..ef4f804
--- /dev/null
+++ b/guava/src/com/google/common/base/MoreObjects.java
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2014 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.base;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.GwtCompatible;
+
+import javax.annotation.Nullable;
+
+/**
+ * Helper functions that operate on any {@code Object}, and are not already provided in
+ * {@link java.util.Objects}.
+ *
+ * <p>See the Guava User Guide on <a
+ * href="http://code.google.com/p/guava-libraries/wiki/CommonObjectUtilitiesExplained">writing
+ * {@code Object} methods with {@code MoreObjects}</a>.
+ *
+ * @author Laurence Gonsalves
+ * @since 18.0 (since 2.0 as {@code Objects})
+ */
+@GwtCompatible
+public final class MoreObjects {
+  /**
+   * Returns the first of two given parameters that is not {@code null}, if either is, or otherwise
+   * throws a {@link NullPointerException}.
+   *
+   * <p><b>Note:</b> if {@code first} is represented as an {@link Optional}, this can be
+   * accomplished with {@link Optional#or(Object) first.or(second)}. That approach also allows for
+   * lazy evaluation of the fallback instance, using {@link Optional#or(Supplier)
+   * first.or(supplier)}.
+   *
+   * @return {@code first} if it is non-null; otherwise {@code second} if it is non-null
+   * @throws NullPointerException if both {@code first} and {@code second} are null
+   * @since 18.0 (since 3.0 as {@code Objects.firstNonNull()}.
+   */
+  public static <T> T firstNonNull(@Nullable T first, @Nullable T second) {
+    return first != null ? first : checkNotNull(second);
+  }
+
+  /**
+   * Creates an instance of {@link ToStringHelper}.
+   *
+   * <p>This is helpful for implementing {@link Object#toString()}.
+   * Specification by example: <pre>   {@code
+   *   // Returns "ClassName{}"
+   *   MoreObjects.toStringHelper(this)
+   *       .toString();
+   *
+   *   // Returns "ClassName{x=1}"
+   *   MoreObjects.toStringHelper(this)
+   *       .add("x", 1)
+   *       .toString();
+   *
+   *   // Returns "MyObject{x=1}"
+   *   MoreObjects.toStringHelper("MyObject")
+   *       .add("x", 1)
+   *       .toString();
+   *
+   *   // Returns "ClassName{x=1, y=foo}"
+   *   MoreObjects.toStringHelper(this)
+   *       .add("x", 1)
+   *       .add("y", "foo")
+   *       .toString();
+   *
+   *   // Returns "ClassName{x=1}"
+   *   MoreObjects.toStringHelper(this)
+   *       .omitNullValues()
+   *       .add("x", 1)
+   *       .add("y", null)
+   *       .toString();
+   *   }}</pre>
+   *
+   * <p>Note that in GWT, class names are often obfuscated.
+   *
+   * @param self the object to generate the string for (typically {@code this}), used only for its
+   *     class name
+   * @since 18.0 (since 2.0 as {@code Objects.toStringHelper()}.
+   */
+  public static ToStringHelper toStringHelper(Object self) {
+    return new ToStringHelper(simpleName(self.getClass()));
+  }
+
+  /**
+   * Creates an instance of {@link ToStringHelper} in the same manner as {@link
+   * #toStringHelper(Object)}, but using the simple name of {@code clazz} instead of using an
+   * instance's {@link Object#getClass()}.
+   *
+   * <p>Note that in GWT, class names are often obfuscated.
+   *
+   * @param clazz the {@link Class} of the instance
+   * @since 18.0 (since 7.0 as {@code Objects.toStringHelper()}.
+   */
+  public static ToStringHelper toStringHelper(Class<?> clazz) {
+    return new ToStringHelper(simpleName(clazz));
+  }
+
+  /**
+   * Creates an instance of {@link ToStringHelper} in the same manner as {@link
+   * #toStringHelper(Object)}, but using {@code className} instead of using an instance's {@link
+   * Object#getClass()}.
+   *
+   * @param className the name of the instance type
+   * @since 18.0 (since 7.0 as {@code Objects.toStringHelper()}.
+   */
+  public static ToStringHelper toStringHelper(String className) {
+    return new ToStringHelper(className);
+  }
+
+  /**
+   * {@link Class#getSimpleName()} is not GWT compatible yet, so we
+   * provide our own implementation.
+   */
+  // Package-private so Objects can call it.
+  static String simpleName(Class<?> clazz) {
+    String name = clazz.getName();
+
+    // the nth anonymous class has a class name ending in "Outer$n"
+    // and local inner classes have names ending in "Outer.$1Inner"
+    name = name.replaceAll("\\$[0-9]+", "\\$");
+
+    // we want the name of the inner class all by its lonesome
+    int start = name.lastIndexOf('$');
+
+    // if this isn't an inner class, just find the start of the
+    // top level class name.
+    if (start == -1) {
+      start = name.lastIndexOf('.');
+    }
+    return name.substring(start + 1);
+  }
+
+  /**
+   * Support class for {@link MoreObjects#toStringHelper}.
+   *
+   * @author Jason Lee
+   * @since 18.0 (since 2.0 as {@code Objects.ToStringHelper}.
+   */
+  public static final class ToStringHelper {
+    private final String className;
+    private ValueHolder holderHead = new ValueHolder();
+    private ValueHolder holderTail = holderHead;
+    private boolean omitNullValues = false;
+
+    /**
+     * Use {@link MoreObjects#toStringHelper(Object)} to create an instance.
+     */
+    private ToStringHelper(String className) {
+      this.className = checkNotNull(className);
+    }
+
+    /**
+     * Configures the {@link ToStringHelper} so {@link #toString()} will ignore
+     * properties with null value. The order of calling this method, relative
+     * to the {@code add()}/{@code addValue()} methods, is not significant.
+     *
+     * @since 18.0 (since 12.0 as {@code Objects.ToStringHelper.omitNullValues()}.
+     */
+    public ToStringHelper omitNullValues() {
+      omitNullValues = true;
+      return this;
+    }
+
+    /**
+     * Adds a name/value pair to the formatted output in {@code name=value}
+     * format. If {@code value} is {@code null}, the string {@code "null"}
+     * is used, unless {@link #omitNullValues()} is called, in which case this
+     * name/value pair will not be added.
+     */
+    public ToStringHelper add(String name, @Nullable Object value) {
+      return addHolder(name, value);
+    }
+
+    /**
+     * Adds a name/value pair to the formatted output in {@code name=value}
+     * format.
+     *
+     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
+     */
+    public ToStringHelper add(String name, boolean value) {
+      return addHolder(name, String.valueOf(value));
+    }
+
+    /**
+     * Adds a name/value pair to the formatted output in {@code name=value}
+     * format.
+     *
+     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
+     */
+    public ToStringHelper add(String name, char value) {
+      return addHolder(name, String.valueOf(value));
+    }
+
+    /**
+     * Adds a name/value pair to the formatted output in {@code name=value}
+     * format.
+     *
+     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
+     */
+    public ToStringHelper add(String name, double value) {
+      return addHolder(name, String.valueOf(value));
+    }
+
+    /**
+     * Adds a name/value pair to the formatted output in {@code name=value}
+     * format.
+     *
+     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
+     */
+    public ToStringHelper add(String name, float value) {
+      return addHolder(name, String.valueOf(value));
+    }
+
+    /**
+     * Adds a name/value pair to the formatted output in {@code name=value}
+     * format.
+     *
+     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
+     */
+    public ToStringHelper add(String name, int value) {
+      return addHolder(name, String.valueOf(value));
+    }
+
+    /**
+     * Adds a name/value pair to the formatted output in {@code name=value}
+     * format.
+     *
+     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
+     */
+    public ToStringHelper add(String name, long value) {
+      return addHolder(name, String.valueOf(value));
+    }
+
+    /**
+     * Adds an unnamed value to the formatted output.
+     *
+     * <p>It is strongly encouraged to use {@link #add(String, Object)} instead
+     * and give value a readable name.
+     *
+     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
+     */
+    public ToStringHelper addValue(@Nullable Object value) {
+      return addHolder(value);
+    }
+
+    /**
+     * Adds an unnamed value to the formatted output.
+     *
+     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
+     *
+     * <p>It is strongly encouraged to use {@link #add(String, boolean)} instead
+     * and give value a readable name.
+     *
+     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
+     */
+    public ToStringHelper addValue(boolean value) {
+      return addHolder(String.valueOf(value));
+    }
+
+    /**
+     * Adds an unnamed value to the formatted output.
+     *
+     * <p>It is strongly encouraged to use {@link #add(String, char)} instead
+     * and give value a readable name.
+     *
+     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
+     */
+    public ToStringHelper addValue(char value) {
+      return addHolder(String.valueOf(value));
+    }
+
+    /**
+     * Adds an unnamed value to the formatted output.
+     *
+     * <p>It is strongly encouraged to use {@link #add(String, double)} instead
+     * and give value a readable name.
+     *
+     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
+     */
+    public ToStringHelper addValue(double value) {
+      return addHolder(String.valueOf(value));
+    }
+
+    /**
+     * Adds an unnamed value to the formatted output.
+     *
+     * <p>It is strongly encouraged to use {@link #add(String, float)} instead
+     * and give value a readable name.
+     *
+     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
+     */
+    public ToStringHelper addValue(float value) {
+      return addHolder(String.valueOf(value));
+    }
+
+    /**
+     * Adds an unnamed value to the formatted output.
+     *
+     * <p>It is strongly encouraged to use {@link #add(String, int)} instead
+     * and give value a readable name.
+     *
+     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
+     */
+    public ToStringHelper addValue(int value) {
+      return addHolder(String.valueOf(value));
+    }
+
+    /**
+     * Adds an unnamed value to the formatted output.
+     *
+     * <p>It is strongly encouraged to use {@link #add(String, long)} instead
+     * and give value a readable name.
+     *
+     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
+     */
+    public ToStringHelper addValue(long value) {
+      return addHolder(String.valueOf(value));
+    }
+
+    /**
+     * Returns a string in the format specified by
+     * {@link MoreObjects#toStringHelper(Object)}.
+     *
+     * <p>After calling this method, you can keep adding more properties to later
+     * call toString() again and get a more complete representation of the
+     * same object; but properties cannot be removed, so this only allows
+     * limited reuse of the helper instance. The helper allows duplication of
+     * properties (multiple name/value pairs with the same name can be added).
+     */
+    @Override public String toString() {
+      // create a copy to keep it consistent in case value changes
+      boolean omitNullValuesSnapshot = omitNullValues;
+      String nextSeparator = "";
+      StringBuilder builder = new StringBuilder(32).append(className)
+          .append('{');
+      for (ValueHolder valueHolder = holderHead.next; valueHolder != null;
+          valueHolder = valueHolder.next) {
+        if (!omitNullValuesSnapshot || valueHolder.value != null) {
+          builder.append(nextSeparator);
+          nextSeparator = ", ";
+
+          if (valueHolder.name != null) {
+            builder.append(valueHolder.name).append('=');
+          }
+          builder.append(valueHolder.value);
+        }
+      }
+      return builder.append('}').toString();
+    }
+
+    private ValueHolder addHolder() {
+      ValueHolder valueHolder = new ValueHolder();
+      holderTail = holderTail.next = valueHolder;
+      return valueHolder;
+    }
+
+    private ToStringHelper addHolder(@Nullable Object value) {
+      ValueHolder valueHolder = addHolder();
+      valueHolder.value = value;
+      return this;
+    }
+
+    private ToStringHelper addHolder(String name, @Nullable Object value) {
+      ValueHolder valueHolder = addHolder();
+      valueHolder.value = value;
+      valueHolder.name = checkNotNull(name);
+      return this;
+    }
+
+    private static final class ValueHolder {
+      String name;
+      Object value;
+      ValueHolder next;
+    }
+  }
+
+  private MoreObjects() {}
+}
diff --git a/guava/src/com/google/common/base/Objects.java b/guava/src/com/google/common/base/Objects.java
index 0c83e7f..214ac55 100644
--- a/guava/src/com/google/common/base/Objects.java
+++ b/guava/src/com/google/common/base/Objects.java
@@ -51,6 +51,9 @@
    *
    * <p>This assumes that any non-null objects passed to this function conform
    * to the {@code equals()} contract.
+   *
+   * <p><b>Note for Java 7 and later:</b> This method should be treated as
+   * deprecated; use {@link java.util.Objects#equals} instead.
    */
   @CheckReturnValue
   public static boolean equal(@Nullable Object a, @Nullable Object b) {
@@ -71,8 +74,11 @@
    *     return Objects.hashCode(getX(), getY(), getZ());
    *   }}</pre>
    *
-   * <p><b>Warning</b>: When a single object is supplied, the returned hash code
+   * <p><b>Warning:</b> When a single object is supplied, the returned hash code
    * does not equal the hash code of that object.
+   *
+   * <p><b>Note for Java 7 and later:</b> This method should be treated as
+   * deprecated; use {@link java.util.Objects#hash} instead.
    */
   public static int hashCode(@Nullable Object... objects) {
     return Arrays.hashCode(objects);
@@ -116,9 +122,12 @@
    * @param self the object to generate the string for (typically {@code this}),
    *        used only for its class name
    * @since 2.0
+   * @deprecated Use {@link MoreObjects#toStringHelper(Object)} instead. This
+   *     method is scheduled for removal in June 2016.
    */
+  @Deprecated
   public static ToStringHelper toStringHelper(Object self) {
-    return new ToStringHelper(simpleName(self.getClass()));
+    return new ToStringHelper(MoreObjects.simpleName(self.getClass()));
   }
 
   /**
@@ -130,9 +139,12 @@
    *
    * @param clazz the {@link Class} of the instance
    * @since 7.0 (source-compatible since 2.0)
+   * @deprecated Use {@link MoreObjects#toStringHelper(Class)} instead. This
+   *     method is scheduled for removal in June 2016.
    */
+  @Deprecated
   public static ToStringHelper toStringHelper(Class<?> clazz) {
-    return new ToStringHelper(simpleName(clazz));
+    return new ToStringHelper(MoreObjects.simpleName(clazz));
   }
 
   /**
@@ -142,34 +154,15 @@
    *
    * @param className the name of the instance type
    * @since 7.0 (source-compatible since 2.0)
+   * @deprecated Use {@link MoreObjects#toStringHelper(String)} instead. This
+   *     method is scheduled for removal in June 2016.
    */
+  @Deprecated
   public static ToStringHelper toStringHelper(String className) {
     return new ToStringHelper(className);
   }
 
   /**
-   * {@link Class#getSimpleName()} is not GWT compatible yet, so we
-   * provide our own implementation.
-   */
-  private static String simpleName(Class<?> clazz) {
-    String name = clazz.getName();
-
-    // the nth anonymous class has a class name ending in "Outer$n"
-    // and local inner classes have names ending in "Outer.$1Inner"
-    name = name.replaceAll("\\$[0-9]+", "\\$");
-
-    // we want the name of the inner class all by its lonesome
-    int start = name.lastIndexOf('$');
-
-    // if this isn't an inner class, just find the start of the
-    // top level class name.
-    if (start == -1) {
-      start = name.lastIndexOf('.');
-    }
-    return name.substring(start + 1);
-  }
-
-  /**
    * Returns the first of two given parameters that is not {@code null}, if
    * either is, or otherwise throws a {@link NullPointerException}.
    *
@@ -185,9 +178,12 @@
    * @throws NullPointerException if both {@code first} and {@code second} were
    *     {@code null}
    * @since 3.0
+   * @deprecated Use {@link MoreObjects#firstNonNull} instead. This method is
+   *      scheduled for removal in June 2016.
    */
+  @Deprecated
   public static <T> T firstNonNull(@Nullable T first, @Nullable T second) {
-    return first != null ? first : checkNotNull(second);
+    return MoreObjects.firstNonNull(first, second);
   }
 
   /**
@@ -195,7 +191,10 @@
    *
    * @author Jason Lee
    * @since 2.0
+   * @deprecated Use {@link MoreObjects.ToStringHelper} instead. This class is
+   *      scheduled for removal in June 2016.
    */
+  @Deprecated
   public static final class ToStringHelper {
     private final String className;
     private ValueHolder holderHead = new ValueHolder();
diff --git a/guava/src/com/google/common/base/Preconditions.java b/guava/src/com/google/common/base/Preconditions.java
index 71e88b0..bd84f05 100644
--- a/guava/src/com/google/common/base/Preconditions.java
+++ b/guava/src/com/google/common/base/Preconditions.java
@@ -82,10 +82,7 @@
  * <h3>Only {@code %s} is supported</h3>
  *
  * <p>In {@code Preconditions} error message template strings, only the {@code "%s"} specifier is
- * supported, not the full range of {@link java.util.Formatter} specifiers. However, note that if
- * the number of arguments does not match the number of occurrences of {@code "%s"} in the format
- * string, {@code Preconditions} will still behave as expected, and will still include all argument
- * values in the error message; the message will simply not be formatted exactly as intended.
+ * supported, not the full range of {@link java.util.Formatter} specifiers.
  *
  * <h3>More information</h3>
  *
diff --git a/guava/src/com/google/common/base/StandardSystemProperty.java b/guava/src/com/google/common/base/StandardSystemProperty.java
index bd4e7cc..a3c1766 100644
--- a/guava/src/com/google/common/base/StandardSystemProperty.java
+++ b/guava/src/com/google/common/base/StandardSystemProperty.java
@@ -19,6 +19,8 @@
 import com.google.common.annotations.Beta;
 import com.google.common.annotations.GwtIncompatible;
 
+import javax.annotation.Nullable;
+
 /**
  * Represents a {@linkplain System#getProperties() standard system property}.
  *
@@ -130,6 +132,7 @@
    * Returns the current value for this system property by delegating to
    * {@link System#getProperty(String)}.
    */
+  @Nullable
   public String value() {
     return System.getProperty(key);
   }
diff --git a/guava/src/com/google/common/base/Stopwatch.java b/guava/src/com/google/common/base/Stopwatch.java
index 88e5543..f11fe62 100644
--- a/guava/src/com/google/common/base/Stopwatch.java
+++ b/guava/src/com/google/common/base/Stopwatch.java
@@ -18,8 +18,11 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
+import static java.util.concurrent.TimeUnit.DAYS;
+import static java.util.concurrent.TimeUnit.HOURS;
 import static java.util.concurrent.TimeUnit.MICROSECONDS;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.MINUTES;
 import static java.util.concurrent.TimeUnit.NANOSECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
 
@@ -120,11 +123,10 @@
    * Creates (but does not start) a new stopwatch using {@link System#nanoTime}
    * as its time source.
    *
-   * @deprecated Use {@link Stopwatch#createUnstarted()} instead. This
-   *     constructor is scheduled to be removed in Guava release 17.0.
+   * @deprecated Use {@link Stopwatch#createUnstarted()} instead.
    */
   @Deprecated
-  public Stopwatch() {
+  Stopwatch() {
     this(Ticker.systemTicker());
   }
 
@@ -132,11 +134,10 @@
    * Creates (but does not start) a new stopwatch, using the specified time
    * source.
    *
-   * @deprecated Use {@link Stopwatch#createUnstarted(Ticker)} instead. This
-   *     constructor is scheduled to be removed in Guava release 17.0.
+   * @deprecated Use {@link Stopwatch#createUnstarted(Ticker)} instead.
    */
   @Deprecated
-  public Stopwatch(Ticker ticker) {
+  Stopwatch(Ticker ticker) {
     this.ticker = checkNotNull(ticker, "ticker");
   }
 
@@ -222,6 +223,15 @@
   }
 
   private static TimeUnit chooseUnit(long nanos) {
+    if (DAYS.convert(nanos, NANOSECONDS) > 0) {
+      return DAYS;
+    }
+    if (HOURS.convert(nanos, NANOSECONDS) > 0) {
+      return HOURS;
+    }
+    if (MINUTES.convert(nanos, NANOSECONDS) > 0) {
+      return MINUTES;
+    }
     if (SECONDS.convert(nanos, NANOSECONDS) > 0) {
       return SECONDS;
     }
@@ -244,6 +254,12 @@
         return "ms";
       case SECONDS:
         return "s";
+      case MINUTES:
+        return "min";
+      case HOURS:
+        return "h";
+      case DAYS:
+        return "d";
       default:
         throw new AssertionError();
     }
diff --git a/guava/src/com/google/common/base/Strings.java b/guava/src/com/google/common/base/Strings.java
index 63eea14..fa4d0bd 100644
--- a/guava/src/com/google/common/base/Strings.java
+++ b/guava/src/com/google/common/base/Strings.java
@@ -54,7 +54,8 @@
    * @return {@code string} itself if it is nonempty; {@code null} if it is
    *     empty or null
    */
-  public static @Nullable String emptyToNull(@Nullable String string) {
+  @Nullable
+  public static String emptyToNull(@Nullable String string) {
     return isNullOrEmpty(string) ? null : string;
   }
 
diff --git a/guava/src/com/google/common/base/Verify.java b/guava/src/com/google/common/base/Verify.java
index e9bca76..d2c5615 100644
--- a/guava/src/com/google/common/base/Verify.java
+++ b/guava/src/com/google/common/base/Verify.java
@@ -49,7 +49,7 @@
  *     are for. Note that assertions are not enabled by default; they are essentially considered
  *     "compiled comments."
  *
- * <li>An explicit {@code if/throw} (as illustrated above) is always acceptable; we still recommend
+ * <li>An explicit {@code if/throw} (as illustrated below) is always acceptable; we still recommend
  *     using our {@link VerifyException} exception type. Throwing a plain {@link RuntimeException}
  *     is frowned upon.
  *
diff --git a/guava/src/com/google/common/cache/AbstractCache.java b/guava/src/com/google/common/cache/AbstractCache.java
index efe579e..7e54174 100644
--- a/guava/src/com/google/common/cache/AbstractCache.java
+++ b/guava/src/com/google/common/cache/AbstractCache.java
@@ -71,7 +71,10 @@
       if (!result.containsKey(key)) {
         @SuppressWarnings("unchecked")
         K castKey = (K) key;
-        result.put(castKey, getIfPresent(key));
+        V value = getIfPresent(key);
+        if (value != null) {
+          result.put(castKey, value);
+        }
       }
     }
     return ImmutableMap.copyOf(result);
diff --git a/guava/src/com/google/common/cache/CacheBuilder.java b/guava/src/com/google/common/cache/CacheBuilder.java
index ea99856..ba8ed11 100644
--- a/guava/src/com/google/common/cache/CacheBuilder.java
+++ b/guava/src/com/google/common/cache/CacheBuilder.java
@@ -16,7 +16,6 @@
 
 package com.google.common.cache;
 
-import static com.google.common.base.Objects.firstNonNull;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
@@ -26,7 +25,7 @@
 import com.google.common.annotations.GwtIncompatible;
 import com.google.common.base.Ascii;
 import com.google.common.base.Equivalence;
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Supplier;
 import com.google.common.base.Suppliers;
 import com.google.common.base.Ticker;
@@ -297,7 +296,7 @@
   }
 
   Equivalence<Object> getKeyEquivalence() {
-    return firstNonNull(keyEquivalence, getKeyStrength().defaultEquivalence());
+    return MoreObjects.firstNonNull(keyEquivalence, getKeyStrength().defaultEquivalence());
   }
 
   /**
@@ -316,7 +315,7 @@
   }
 
   Equivalence<Object> getValueEquivalence() {
-    return firstNonNull(valueEquivalence, getValueStrength().defaultEquivalence());
+    return MoreObjects.firstNonNull(valueEquivalence, getValueStrength().defaultEquivalence());
   }
 
   /**
@@ -498,7 +497,7 @@
   // Make a safe contravariant cast now so we don't have to do it over and over.
   @SuppressWarnings("unchecked")
   <K1 extends K, V1 extends V> Weigher<K1, V1> getWeigher() {
-    return (Weigher<K1, V1>) Objects.firstNonNull(weigher, OneWeigher.INSTANCE);
+    return (Weigher<K1, V1>) MoreObjects.firstNonNull(weigher, OneWeigher.INSTANCE);
   }
 
   /**
@@ -526,7 +525,7 @@
   }
 
   Strength getKeyStrength() {
-    return firstNonNull(keyStrength, Strength.STRONG);
+    return MoreObjects.firstNonNull(keyStrength, Strength.STRONG);
   }
 
   /**
@@ -581,7 +580,7 @@
   }
 
   Strength getValueStrength() {
-    return firstNonNull(valueStrength, Strength.STRONG);
+    return MoreObjects.firstNonNull(valueStrength, Strength.STRONG);
   }
 
   /**
@@ -747,7 +746,8 @@
   // Make a safe contravariant cast now so we don't have to do it over and over.
   @SuppressWarnings("unchecked")
   <K1 extends K, V1 extends V> RemovalListener<K1, V1> getRemovalListener() {
-    return (RemovalListener<K1, V1>) Objects.firstNonNull(removalListener, NullListener.INSTANCE);
+    return (RemovalListener<K1, V1>)
+        MoreObjects.firstNonNull(removalListener, NullListener.INSTANCE);
   }
 
   /**
@@ -831,7 +831,7 @@
    */
   @Override
   public String toString() {
-    Objects.ToStringHelper s = Objects.toStringHelper(this);
+    MoreObjects.ToStringHelper s = MoreObjects.toStringHelper(this);
     if (initialCapacity != UNSET_INT) {
       s.add("initialCapacity", initialCapacity);
     }
diff --git a/guava/src/com/google/common/cache/CacheBuilderSpec.java b/guava/src/com/google/common/cache/CacheBuilderSpec.java
index 3c003bd..919366e 100644
--- a/guava/src/com/google/common/cache/CacheBuilderSpec.java
+++ b/guava/src/com/google/common/cache/CacheBuilderSpec.java
@@ -20,6 +20,7 @@
 
 import com.google.common.annotations.Beta;
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 import com.google.common.base.Splitter;
 import com.google.common.cache.LocalCache.Strength;
@@ -135,7 +136,7 @@
    */
   public static CacheBuilderSpec parse(String cacheBuilderSpecification) {
     CacheBuilderSpec spec = new CacheBuilderSpec(cacheBuilderSpecification);
-    if (cacheBuilderSpecification.length() != 0) {
+    if (!cacheBuilderSpecification.isEmpty()) {
       for (String keyValuePair : KEYS_SPLITTER.split(cacheBuilderSpecification)) {
         List<String> keyAndValue = ImmutableList.copyOf(KEY_VALUE_SPLITTER.split(keyValuePair));
         checkArgument(!keyAndValue.isEmpty(), "blank key-value pair");
@@ -233,7 +234,7 @@
    */
   @Override
   public String toString() {
-    return Objects.toStringHelper(this).addValue(toParsableString()).toString();
+    return MoreObjects.toStringHelper(this).addValue(toParsableString()).toString();
   }
 
   @Override
@@ -289,7 +290,7 @@
 
     @Override
     public void parse(CacheBuilderSpec spec, String key, String value) {
-      checkArgument(value != null && value.length() != 0, "value of key %s omitted", key);
+      checkArgument(value != null && !value.isEmpty(), "value of key %s omitted", key);
       try {
         parseInteger(spec, Integer.parseInt(value));
       } catch (NumberFormatException e) {
@@ -305,7 +306,7 @@
 
     @Override
     public void parse(CacheBuilderSpec spec, String key, String value) {
-      checkArgument(value != null && value.length() != 0, "value of key %s omitted", key);
+      checkArgument(value != null && !value.isEmpty(), "value of key %s omitted", key);
       try {
         parseLong(spec, Long.parseLong(value));
       } catch (NumberFormatException e) {
@@ -413,18 +414,22 @@
 
     @Override
     public void parse(CacheBuilderSpec spec, String key, String value) {
-      checkArgument(value != null && value.length() != 0, "value of key %s omitted", key);
+      checkArgument(value != null && !value.isEmpty(), "value of key %s omitted", key);
       try {
         char lastChar = value.charAt(value.length() - 1);
-        long multiplier = 1;
+        TimeUnit timeUnit;
         switch (lastChar) {
           case 'd':
-            multiplier *= 24;
+            timeUnit = TimeUnit.DAYS;
+            break;
           case 'h':
-            multiplier *= 60;
+            timeUnit = TimeUnit.HOURS;
+            break;
           case 'm':
-            multiplier *= 60;
+            timeUnit = TimeUnit.MINUTES;
+            break;
           case 's':
+            timeUnit = TimeUnit.SECONDS;
             break;
           default:
             throw new IllegalArgumentException(
@@ -433,7 +438,7 @@
         }
 
         long duration = Long.parseLong(value.substring(0, value.length() - 1));
-        parseDuration(spec, duration * multiplier, TimeUnit.SECONDS);
+        parseDuration(spec, duration, timeUnit);
       } catch (NumberFormatException e) {
         throw new IllegalArgumentException(
             String.format("key %s value set to %s, must be integer", key, value));
diff --git a/guava/src/com/google/common/cache/CacheStats.java b/guava/src/com/google/common/cache/CacheStats.java
index d8c9eb7..c37c769 100644
--- a/guava/src/com/google/common/cache/CacheStats.java
+++ b/guava/src/com/google/common/cache/CacheStats.java
@@ -20,6 +20,7 @@
 
 import com.google.common.annotations.Beta;
 import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 
 import java.util.concurrent.Callable;
@@ -264,7 +265,7 @@
 
   @Override
   public String toString() {
-    return Objects.toStringHelper(this)
+    return MoreObjects.toStringHelper(this)
         .add("hitCount", hitCount)
         .add("missCount", missCount)
         .add("loadSuccessCount", loadSuccessCount)
diff --git a/guava/src/com/google/common/cache/LocalCache.java b/guava/src/com/google/common/cache/LocalCache.java
index 789e628..0c51d06 100644
--- a/guava/src/com/google/common/cache/LocalCache.java
+++ b/guava/src/com/google/common/cache/LocalCache.java
@@ -20,6 +20,7 @@
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.cache.CacheBuilder.NULL_TICKER;
 import static com.google.common.cache.CacheBuilder.UNSET_INT;
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
 import static com.google.common.util.concurrent.Uninterruptibles.getUninterruptibly;
 import static java.util.concurrent.TimeUnit.NANOSECONDS;
 
@@ -38,15 +39,13 @@
 import com.google.common.cache.CacheLoader.UnsupportedLoadingOperationException;
 import com.google.common.collect.AbstractSequentialIterator;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterators;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import com.google.common.primitives.Ints;
 import com.google.common.util.concurrent.ExecutionError;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
 import com.google.common.util.concurrent.SettableFuture;
 import com.google.common.util.concurrent.UncheckedExecutionException;
 import com.google.common.util.concurrent.Uninterruptibles;
@@ -157,8 +156,6 @@
 
   static final Logger logger = Logger.getLogger(LocalCache.class.getName());
 
-  static final ListeningExecutorService sameThreadExecutor = MoreExecutors.sameThreadExecutor();
-
   /**
    * Mask value for indexing into segments. The upper bits of a key's hash code are used to choose
    * the segment.
@@ -591,13 +588,13 @@
      * @param original the entry to copy
      * @param newNext entry in the same bucket
      */
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     <K, V> ReferenceEntry<K, V> copyEntry(
         Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
       return newEntry(segment, original.getKey(), original.getHash(), newNext);
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     <K, V> void copyAccessEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newEntry) {
       // TODO(fry): when we link values instead of entries this method can go
       // away, as can connectAccessOrder, nullifyAccessOrder.
@@ -609,7 +606,7 @@
       nullifyAccessOrder(original);
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     <K, V> void copyWriteEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newEntry) {
       // TODO(fry): when we link values instead of entries this method can go
       // away, as can connectWriteOrder, nullifyWriteOrder.
@@ -1041,7 +1038,7 @@
 
     @Override
     public Iterator<Object> iterator() {
-      return Iterators.emptyIterator();
+      return ImmutableSet.of().iterator();
     }
   };
 
@@ -1124,7 +1121,7 @@
       this.accessTime = time;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> nextAccess = nullEntry();
 
     @Override
@@ -1137,7 +1134,7 @@
       this.nextAccess = next;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> previousAccess = nullEntry();
 
     @Override
@@ -1170,7 +1167,7 @@
       this.writeTime = time;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> nextWrite = nullEntry();
 
     @Override
@@ -1183,7 +1180,7 @@
       this.nextWrite = next;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> previousWrite = nullEntry();
 
     @Override
@@ -1216,7 +1213,7 @@
       this.accessTime = time;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> nextAccess = nullEntry();
 
     @Override
@@ -1229,7 +1226,7 @@
       this.nextAccess = next;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> previousAccess = nullEntry();
 
     @Override
@@ -1256,7 +1253,7 @@
       this.writeTime = time;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> nextWrite = nullEntry();
 
     @Override
@@ -1269,7 +1266,7 @@
       this.nextWrite = next;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> previousWrite = nullEntry();
 
     @Override
@@ -1414,7 +1411,7 @@
       this.accessTime = time;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> nextAccess = nullEntry();
 
     @Override
@@ -1427,7 +1424,7 @@
       this.nextAccess = next;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> previousAccess = nullEntry();
 
     @Override
@@ -1461,7 +1458,7 @@
       this.writeTime = time;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> nextWrite = nullEntry();
 
     @Override
@@ -1474,7 +1471,7 @@
       this.nextWrite = next;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> previousWrite = nullEntry();
 
     @Override
@@ -1508,7 +1505,7 @@
       this.accessTime = time;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> nextAccess = nullEntry();
 
     @Override
@@ -1521,7 +1518,7 @@
       this.nextAccess = next;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> previousAccess = nullEntry();
 
     @Override
@@ -1548,7 +1545,7 @@
       this.writeTime = time;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> nextWrite = nullEntry();
 
     @Override
@@ -1561,7 +1558,7 @@
       this.nextWrite = next;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> previousWrite = nullEntry();
 
     @Override
@@ -1807,16 +1804,21 @@
   /**
    * This method is a convenience for testing. Code should call {@link Segment#newEntry} directly.
    */
-  @GuardedBy("Segment.this")
   @VisibleForTesting
   ReferenceEntry<K, V> newEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) {
-    return segmentFor(hash).newEntry(key, hash, next);
+    Segment<K, V> segment = segmentFor(hash);
+    segment.lock();
+    try {
+      return segment.newEntry(key, hash, next);
+    } finally {
+      segment.unlock();
+    }
   }
 
   /**
    * This method is a convenience for testing. Code should call {@link Segment#copyEntry} directly.
    */
-  @GuardedBy("Segment.this")
+  // Guarded By Segment.this
   @VisibleForTesting
   ReferenceEntry<K, V> copyEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
     int hash = original.getHash();
@@ -1826,7 +1828,7 @@
   /**
    * This method is a convenience for testing. Code should call {@link Segment#setValue} instead.
    */
-  @GuardedBy("Segment.this")
+  // Guarded By Segment.this
   @VisibleForTesting
   ValueReference<K, V> newValueReference(ReferenceEntry<K, V> entry, V value, int weight) {
     int hash = entry.getHash();
@@ -1916,26 +1918,26 @@
 
   // queues
 
-  @GuardedBy("Segment.this")
+  // Guarded By Segment.this
   static <K, V> void connectAccessOrder(ReferenceEntry<K, V> previous, ReferenceEntry<K, V> next) {
     previous.setNextInAccessQueue(next);
     next.setPreviousInAccessQueue(previous);
   }
 
-  @GuardedBy("Segment.this")
+  // Guarded By Segment.this
   static <K, V> void nullifyAccessOrder(ReferenceEntry<K, V> nulled) {
     ReferenceEntry<K, V> nullEntry = nullEntry();
     nulled.setNextInAccessQueue(nullEntry);
     nulled.setPreviousInAccessQueue(nullEntry);
   }
 
-  @GuardedBy("Segment.this")
+  // Guarded By Segment.this
   static <K, V> void connectWriteOrder(ReferenceEntry<K, V> previous, ReferenceEntry<K, V> next) {
     previous.setNextInWriteQueue(next);
     next.setPreviousInWriteQueue(previous);
   }
 
-  @GuardedBy("Segment.this")
+  // Guarded By Segment.this
   static <K, V> void nullifyWriteOrder(ReferenceEntry<K, V> nulled) {
     ReferenceEntry<K, V> nullEntry = nullEntry();
     nulled.setNextInWriteQueue(nullEntry);
@@ -2015,8 +2017,8 @@
     /**
      * The weight of the live elements in this segment's region.
      */
-    @GuardedBy("Segment.this")
-    int totalWeight;
+    @GuardedBy("this")
+    long totalWeight;
 
     /**
      * Number of updates that alter the size of the table. This is used during bulk-read methods to
@@ -2071,14 +2073,14 @@
      * A queue of elements currently in the map, ordered by write time. Elements are added to the
      * tail of the queue on write.
      */
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     final Queue<ReferenceEntry<K, V>> writeQueue;
 
     /**
      * A queue of elements currently in the map, ordered by access time. Elements are added to the
      * tail of the queue on access (note that writes count as accesses).
      */
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     final Queue<ReferenceEntry<K, V>> accessQueue;
 
     /** Accumulates cache statistics. */
@@ -2123,7 +2125,7 @@
       this.table = newTable;
     }
 
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     ReferenceEntry<K, V> newEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) {
       return map.entryFactory.newEntry(this, checkNotNull(key), hash, next);
     }
@@ -2132,7 +2134,7 @@
      * Copies {@code original} into a new entry chained to {@code newNext}. Returns the new entry,
      * or {@code null} if {@code original} was already garbage collected.
      */
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     ReferenceEntry<K, V> copyEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
       if (original.getKey() == null) {
         // key collected
@@ -2154,7 +2156,7 @@
     /**
      * Sets a new value of an entry. Adds newly created entries at the end of the access queue.
      */
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     void setValue(ReferenceEntry<K, V> entry, K key, V value, long now) {
       ValueReference<K, V> previous = entry.getValueReference();
       int weight = map.weigher.weigh(key, value);
@@ -2332,7 +2334,7 @@
                 loadingValueReference.setException(t);
               }
             }
-          }, sameThreadExecutor);
+          }, directExecutor());
       return loadingFuture;
     }
 
@@ -2468,7 +2470,7 @@
      * Drain the key and value reference queues, cleaning up internal entries containing garbage
      * collected keys or values.
      */
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     void drainReferenceQueues() {
       if (map.usesKeyReferences()) {
         drainKeyReferenceQueue();
@@ -2478,7 +2480,7 @@
       }
     }
 
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     void drainKeyReferenceQueue() {
       Reference<? extends K> ref;
       int i = 0;
@@ -2492,7 +2494,7 @@
       }
     }
 
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     void drainValueReferenceQueue() {
       Reference<? extends V> ref;
       int i = 0;
@@ -2549,7 +2551,7 @@
      * <p>Note: this method should only be called under lock, as it directly manipulates the
      * eviction queues. Unlocked reads should use {@link #recordRead}.
      */
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     void recordLockedRead(ReferenceEntry<K, V> entry, long now) {
       if (map.recordsAccess()) {
         entry.setAccessTime(now);
@@ -2561,7 +2563,7 @@
      * Updates eviction metadata that {@code entry} was just written. This currently amounts to
      * adding {@code entry} to relevant eviction lists.
      */
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     void recordWrite(ReferenceEntry<K, V> entry, int weight, long now) {
       // we are already under lock, so drain the recency queue immediately
       drainRecencyQueue();
@@ -2583,7 +2585,7 @@
      * lists (accounting for the fact that they could have been removed from the map since being
      * added to the recency queue).
      */
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     void drainRecencyQueue() {
       ReferenceEntry<K, V> e;
       while ((e = recencyQueue.poll()) != null) {
@@ -2613,7 +2615,7 @@
       }
     }
 
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     void expireEntries(long now) {
       drainRecencyQueue();
 
@@ -2632,12 +2634,12 @@
 
     // eviction
 
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     void enqueueNotification(ReferenceEntry<K, V> entry, RemovalCause cause) {
       enqueueNotification(entry.getKey(), entry.getHash(), entry.getValueReference(), cause);
     }
 
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     void enqueueNotification(@Nullable K key, int hash, ValueReference<K, V> valueReference,
         RemovalCause cause) {
       totalWeight -= valueReference.getWeight();
@@ -2655,7 +2657,7 @@
      * Performs eviction if the segment is full. This should only be called prior to adding a new
      * entry and increasing {@code count}.
      */
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     void evictEntries() {
       if (!map.evictsBySize()) {
         return;
@@ -2671,6 +2673,7 @@
     }
 
     // TODO(fry): instead implement this with an eviction head
+    @GuardedBy("this")
     ReferenceEntry<K, V> getNextEvictable() {
       for (ReferenceEntry<K, V> e : accessQueue) {
         int weight = e.getValueReference().getWeight();
@@ -2892,7 +2895,7 @@
     /**
      * Expands the table if possible.
      */
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     void expand() {
       AtomicReferenceArray<ReferenceEntry<K, V>> oldTable = table;
       int oldCapacity = oldTable.length();
@@ -3240,7 +3243,7 @@
       }
     }
 
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     @Nullable
     ReferenceEntry<K, V> removeValueFromChain(ReferenceEntry<K, V> first,
         ReferenceEntry<K, V> entry, @Nullable K key, int hash, ValueReference<K, V> valueReference,
@@ -3257,7 +3260,7 @@
       }
     }
 
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     @Nullable
     ReferenceEntry<K, V> removeEntryFromChain(ReferenceEntry<K, V> first,
         ReferenceEntry<K, V> entry) {
@@ -3276,7 +3279,7 @@
       return newFirst;
     }
 
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     void removeCollectedEntry(ReferenceEntry<K, V> entry) {
       enqueueNotification(entry, RemovalCause.COLLECTED);
       writeQueue.remove(entry);
@@ -3383,7 +3386,7 @@
       }
     }
 
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     boolean removeEntry(ReferenceEntry<K, V> entry, int hash, RemovalCause cause) {
       int newCount = this.count - 1;
       AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
@@ -3421,7 +3424,7 @@
      *
      * <p>Post-condition: expireEntries has been run.
      */
-    @GuardedBy("Segment.this")
+    @GuardedBy("this")
     void preWriteCleanup(long now) {
       runLockedCleanup(now);
     }
diff --git a/guava/src/com/google/common/cache/LongAdder.java b/guava/src/com/google/common/cache/LongAdder.java
index 60f7456..ffdd66b 100644
--- a/guava/src/com/google/common/cache/LongAdder.java
+++ b/guava/src/com/google/common/cache/LongAdder.java
@@ -6,7 +6,7 @@
 
 /*
  * Source:
- * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/LongAdder.java?revision=1.8
+ * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/LongAdder.java?revision=1.17
  */
 
 package com.google.common.cache;
@@ -27,7 +27,7 @@
  * #longValue}) returns the current total combined across the
  * variables maintaining the sum.
  *
- * <p> This class is usually preferable to {@link AtomicLong} when
+ * <p>This class is usually preferable to {@link AtomicLong} when
  * multiple threads update a common sum that is used for purposes such
  * as collecting statistics, not for fine-grained synchronization
  * control.  Under low update contention, the two classes have similar
@@ -36,12 +36,12 @@
  * consumption.
  *
  * <p>This class extends {@link Number}, but does <em>not</em> define
- * methods such as {@code hashCode} and {@code compareTo} because
- * instances are expected to be mutated, and so are not useful as
- * collection keys.
+ * methods such as {@code equals}, {@code hashCode} and {@code
+ * compareTo} because instances are expected to be mutated, and so are
+ * not useful as collection keys.
  *
  * <p><em>jsr166e note: This class is targeted to be placed in
- * java.util.concurrent.atomic<em>
+ * java.util.concurrent.atomic.</em>
  *
  * @since 1.8
  * @author Doug Lea
@@ -67,12 +67,12 @@
      * @param x the value to add
      */
     public void add(long x) {
-        Cell[] as; long b, v; HashCode hc; Cell a; int n;
+        Cell[] as; long b, v; int[] hc; Cell a; int n;
         if ((as = cells) != null || !casBase(b = base, b + x)) {
             boolean uncontended = true;
-            int h = (hc = threadHashCode.get()).code;
-            if (as == null || (n = as.length) < 1 ||
-                (a = as[(n - 1) & h]) == null ||
+            if ((hc = threadHashCode.get()) == null ||
+                as == null || (n = as.length) < 1 ||
+                (a = as[(n - 1) & hc[0]]) == null ||
                 !(uncontended = a.cas(v = a.value, v + x)))
                 retryUpdate(x, hc, uncontended);
         }
@@ -94,7 +94,7 @@
 
     /**
      * Returns the current sum.  The returned value is <em>NOT</em> an
-     * atomic snapshot: Invocation in the absence of concurrent
+     * atomic snapshot; invocation in the absence of concurrent
      * updates returns an accurate result, but concurrent updates that
      * occur while the sum is being calculated might not be
      * incorporated.
@@ -194,14 +194,13 @@
         return (double)sum();
     }
 
-    private void writeObject(ObjectOutputStream s)
-        throws java.io.IOException {
+    private void writeObject(ObjectOutputStream s) throws IOException {
         s.defaultWriteObject();
         s.writeLong(sum());
     }
 
     private void readObject(ObjectInputStream s)
-        throws IOException, ClassNotFoundException {
+            throws IOException, ClassNotFoundException {
         s.defaultReadObject();
         busy = 0;
         cells = null;
diff --git a/guava/src/com/google/common/cache/Striped64.java b/guava/src/com/google/common/cache/Striped64.java
index bb95eb9..9f415fd 100644
--- a/guava/src/com/google/common/cache/Striped64.java
+++ b/guava/src/com/google/common/cache/Striped64.java
@@ -6,7 +6,7 @@
 
 /*
  * Source:
- * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/Striped64.java?revision=1.7
+ * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/Striped64.java?revision=1.9
  */
 
 package com.google.common.cache;
@@ -48,7 +48,7 @@
      *
      * A single spinlock ("busy") is used for initializing and
      * resizing the table, as well as populating slots with new Cells.
-     * There is no need for a blocking lock: When the lock is not
+     * There is no need for a blocking lock; when the lock is not
      * available, threads try other slots (or the base).  During these
      * retries, there is increased contention and reduced locality,
      * which is still better than alternatives.
@@ -109,32 +109,17 @@
     }
 
     /**
-     * Holder for the thread-local hash code. The code is initially
-     * random, but may be set to a different value upon collisions.
+     * ThreadLocal holding a single-slot int array holding hash code.
+     * Unlike the JDK8 version of this class, we use a suboptimal
+     * int[] representation to avoid introducing a new type that can
+     * impede class-unloading when ThreadLocals are not removed.
      */
-    static final class HashCode {
-        static final Random rng = new Random();
-        int code;
-        HashCode() {
-            int h = rng.nextInt(); // Avoid zero to allow xorShift rehash
-            code = (h == 0) ? 1 : h;
-        }
-    }
+    static final ThreadLocal<int[]> threadHashCode = new ThreadLocal<int[]>();
 
     /**
-     * The corresponding ThreadLocal class
+     * Generator of new random hash codes
      */
-    static final class ThreadHashCode extends ThreadLocal<HashCode> {
-        public HashCode initialValue() { return new HashCode(); }
-    }
-
-    /**
-     * Static per-thread hash codes. Shared across all instances to
-     * reduce ThreadLocal pollution and because adjustments due to
-     * collisions in one table are likely to be appropriate for
-     * others.
-     */
-    static final ThreadHashCode threadHashCode = new ThreadHashCode();
+    static final Random rng = new Random();
 
     /** Number of CPUS, to place bound on table size */
     static final int NCPU = Runtime.getRuntime().availableProcessors();
@@ -197,8 +182,15 @@
      * @param hc the hash code holder
      * @param wasUncontended false if CAS failed before call
      */
-    final void retryUpdate(long x, HashCode hc, boolean wasUncontended) {
-        int h = hc.code;
+    final void retryUpdate(long x, int[] hc, boolean wasUncontended) {
+        int h;
+        if (hc == null) {
+            threadHashCode.set(hc = new int[1]); // Initialize randomly
+            int r = rng.nextInt(); // Avoid zero to allow xorShift rehash
+            h = hc[0] = (r == 0) ? 1 : r;
+        }
+        else
+            h = hc[0];
         boolean collide = false;                // True if last slot nonempty
         for (;;) {
             Cell[] as; Cell a; int n; long v;
@@ -250,6 +242,7 @@
                 h ^= h << 13;                   // Rehash
                 h ^= h >>> 17;
                 h ^= h << 5;
+                hc[0] = h;                      // Record index for next time
             }
             else if (busy == 0 && cells == as && casBusy()) {
                 boolean init = false;
@@ -269,7 +262,6 @@
             else if (casBase(v = base, fn(v, x)))
                 break;                          // Fall back on using base
         }
-        hc.code = h;                            // Record index for next time
     }
 
     /**
diff --git a/guava/src/com/google/common/collect/AbstractMapBasedMultimap.java b/guava/src/com/google/common/collect/AbstractMapBasedMultimap.java
index 7273453..c39faab 100644
--- a/guava/src/com/google/common/collect/AbstractMapBasedMultimap.java
+++ b/guava/src/com/google/common/collect/AbstractMapBasedMultimap.java
@@ -35,6 +35,8 @@
 import java.util.ListIterator;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
 import java.util.RandomAccess;
 import java.util.Set;
 import java.util.SortedMap;
@@ -624,7 +626,7 @@
   /**
    * SortedSet decorator that stays in sync with the multimap values for a key.
    */
-  protected class WrappedSortedSet extends WrappedCollection
+  private class WrappedSortedSet extends WrappedCollection
       implements SortedSet<V> {
     WrappedSortedSet(@Nullable K key, SortedSet<V> delegate,
         @Nullable WrappedCollection ancestor) {
@@ -677,6 +679,81 @@
     }
   }
 
+  @GwtIncompatible("NavigableSet")
+  class WrappedNavigableSet extends WrappedSortedSet implements NavigableSet<V> {
+    WrappedNavigableSet(
+        @Nullable K key, NavigableSet<V> delegate, @Nullable WrappedCollection ancestor) {
+      super(key, delegate, ancestor);
+    }
+
+    @Override
+    NavigableSet<V> getSortedSetDelegate() {
+      return (NavigableSet<V>) super.getSortedSetDelegate();
+    }
+
+    @Override
+    public V lower(V v) {
+      return getSortedSetDelegate().lower(v);
+    }
+
+    @Override
+    public V floor(V v) {
+      return getSortedSetDelegate().floor(v);
+    }
+
+    @Override
+    public V ceiling(V v) {
+      return getSortedSetDelegate().ceiling(v);
+    }
+
+    @Override
+    public V higher(V v) {
+      return getSortedSetDelegate().higher(v);
+    }
+
+    @Override
+    public V pollFirst() {
+      return Iterators.pollNext(iterator());
+    }
+
+    @Override
+    public V pollLast() {
+      return Iterators.pollNext(descendingIterator());
+    }
+
+    private NavigableSet<V> wrap(NavigableSet<V> wrapped) {
+      return new WrappedNavigableSet(key, wrapped,
+          (getAncestor() == null) ? this : getAncestor());
+    }
+
+    @Override
+    public NavigableSet<V> descendingSet() {
+      return wrap(getSortedSetDelegate().descendingSet());
+    }
+
+    @Override
+    public Iterator<V> descendingIterator() {
+      return new WrappedIterator(getSortedSetDelegate().descendingIterator());
+    }
+
+    @Override
+    public NavigableSet<V> subSet(
+        V fromElement, boolean fromInclusive, V toElement, boolean toInclusive) {
+      return wrap(
+          getSortedSetDelegate().subSet(fromElement, fromInclusive, toElement, toInclusive));
+    }
+
+    @Override
+    public NavigableSet<V> headSet(V toElement, boolean inclusive) {
+      return wrap(getSortedSetDelegate().headSet(toElement, inclusive));
+    }
+
+    @Override
+    public NavigableSet<V> tailSet(V fromElement, boolean inclusive) {
+      return wrap(getSortedSetDelegate().tailSet(fromElement, inclusive));
+    }
+  }
+
   /** List decorator that stays in sync with the multimap values for a key. */
   private class WrappedList extends WrappedCollection implements List<V> {
     WrappedList(@Nullable K key, List<V> delegate,
@@ -901,7 +978,7 @@
     }
   }
 
-  protected class SortedKeySet extends KeySet implements SortedSet<K> {
+  private class SortedKeySet extends KeySet implements SortedSet<K> {
 
     SortedKeySet(SortedMap<K, Collection<V>> subMap) {
       super(subMap);
@@ -942,6 +1019,90 @@
     }
   }
 
+  @GwtIncompatible("NavigableSet")
+  class NavigableKeySet extends SortedKeySet implements NavigableSet<K> {
+    NavigableKeySet(NavigableMap<K, Collection<V>> subMap) {
+      super(subMap);
+    }
+
+    @Override
+    NavigableMap<K, Collection<V>> sortedMap() {
+      return (NavigableMap<K, Collection<V>>) super.sortedMap();
+    }
+
+    @Override
+    public K lower(K k) {
+      return sortedMap().lowerKey(k);
+    }
+
+    @Override
+    public K floor(K k) {
+      return sortedMap().floorKey(k);
+    }
+
+    @Override
+    public K ceiling(K k) {
+      return sortedMap().ceilingKey(k);
+    }
+
+    @Override
+    public K higher(K k) {
+      return sortedMap().higherKey(k);
+    }
+
+    @Override
+    public K pollFirst() {
+      return Iterators.pollNext(iterator());
+    }
+
+    @Override
+    public K pollLast() {
+      return Iterators.pollNext(descendingIterator());
+    }
+
+    @Override
+    public NavigableSet<K> descendingSet() {
+      return new NavigableKeySet(sortedMap().descendingMap());
+    }
+
+    @Override
+    public Iterator<K> descendingIterator() {
+      return descendingSet().iterator();
+    }
+
+    @Override
+    public NavigableSet<K> headSet(K toElement) {
+      return headSet(toElement, false);
+    }
+
+    @Override
+    public NavigableSet<K> headSet(K toElement, boolean inclusive) {
+      return new NavigableKeySet(sortedMap().headMap(toElement, inclusive));
+    }
+
+    @Override
+    public NavigableSet<K> subSet(K fromElement, K toElement) {
+      return subSet(fromElement, true, toElement, false);
+    }
+
+    @Override
+    public NavigableSet<K> subSet(
+        K fromElement, boolean fromInclusive, K toElement, boolean toInclusive) {
+      return new NavigableKeySet(
+          sortedMap().subMap(fromElement, fromInclusive, toElement, toInclusive));
+    }
+
+    @Override
+    public NavigableSet<K> tailSet(K fromElement) {
+      return tailSet(fromElement, true);
+    }
+
+    @Override
+    public NavigableSet<K> tailSet(K fromElement, boolean inclusive) {
+      return new NavigableKeySet(sortedMap().tailMap(fromElement, inclusive));
+    }
+  }
+
   /**
    * Removes all values for the provided key. Unlike {@link #removeAll}, it
    * returns the number of removed mappings.
@@ -1199,7 +1360,7 @@
     }
   }
 
-  protected class SortedAsMap extends AsMap
+  private class SortedAsMap extends AsMap
       implements SortedMap<K, Collection<V>> {
     SortedAsMap(SortedMap<K, Collection<V>> submap) {
       super(submap);
@@ -1254,5 +1415,151 @@
     }
   }
 
+  @GwtIncompatible("NavigableAsMap")
+  class NavigableAsMap extends SortedAsMap implements NavigableMap<K, Collection<V>> {
+
+    NavigableAsMap(NavigableMap<K, Collection<V>> submap) {
+      super(submap);
+    }
+
+    @Override
+    NavigableMap<K, Collection<V>> sortedMap() {
+      return (NavigableMap<K, Collection<V>>) super.sortedMap();
+    }
+
+    @Override
+    public Entry<K, Collection<V>> lowerEntry(K key) {
+      Entry<K, Collection<V>> entry = sortedMap().lowerEntry(key);
+      return (entry == null) ? null : wrapEntry(entry);
+    }
+
+    @Override
+    public K lowerKey(K key) {
+      return sortedMap().lowerKey(key);
+    }
+
+    @Override
+    public Entry<K, Collection<V>> floorEntry(K key) {
+      Entry<K, Collection<V>> entry = sortedMap().floorEntry(key);
+      return (entry == null) ? null : wrapEntry(entry);
+    }
+
+    @Override
+    public K floorKey(K key) {
+      return sortedMap().floorKey(key);
+    }
+
+    @Override
+    public Entry<K, Collection<V>> ceilingEntry(K key) {
+      Entry<K, Collection<V>> entry = sortedMap().ceilingEntry(key);
+      return (entry == null) ? null : wrapEntry(entry);
+    }
+
+    @Override
+    public K ceilingKey(K key) {
+      return sortedMap().ceilingKey(key);
+    }
+
+    @Override
+    public Entry<K, Collection<V>> higherEntry(K key) {
+      Entry<K, Collection<V>> entry = sortedMap().higherEntry(key);
+      return (entry == null) ? null : wrapEntry(entry);
+    }
+
+    @Override
+    public K higherKey(K key) {
+      return sortedMap().higherKey(key);
+    }
+
+    @Override
+    public Entry<K, Collection<V>> firstEntry() {
+      Entry<K, Collection<V>> entry = sortedMap().firstEntry();
+      return (entry == null) ? null : wrapEntry(entry);
+    }
+
+    @Override
+    public Entry<K, Collection<V>> lastEntry() {
+      Entry<K, Collection<V>> entry = sortedMap().lastEntry();
+      return (entry == null) ? null : wrapEntry(entry);
+    }
+
+    @Override
+    public Entry<K, Collection<V>> pollFirstEntry() {
+      return pollAsMapEntry(entrySet().iterator());
+    }
+
+    @Override
+    public Entry<K, Collection<V>> pollLastEntry() {
+      return pollAsMapEntry(descendingMap().entrySet().iterator());
+    }
+
+    Map.Entry<K, Collection<V>> pollAsMapEntry(Iterator<Entry<K, Collection<V>>> entryIterator) {
+      if (!entryIterator.hasNext()) {
+        return null;
+      }
+      Entry<K, Collection<V>> entry = entryIterator.next();
+      Collection<V> output = createCollection();
+      output.addAll(entry.getValue());
+      entryIterator.remove();
+      return Maps.immutableEntry(entry.getKey(), unmodifiableCollectionSubclass(output));
+    }
+
+    @Override
+    public NavigableMap<K, Collection<V>> descendingMap() {
+      return new NavigableAsMap(sortedMap().descendingMap());
+    }
+
+    @Override
+    public NavigableSet<K> keySet() {
+      return (NavigableSet<K>) super.keySet();
+    }
+
+    @Override
+    NavigableSet<K> createKeySet() {
+      return new NavigableKeySet(sortedMap());
+    }
+
+    @Override
+    public NavigableSet<K> navigableKeySet() {
+      return keySet();
+    }
+
+    @Override
+    public NavigableSet<K> descendingKeySet() {
+      return descendingMap().navigableKeySet();
+    }
+
+    @Override
+    public NavigableMap<K, Collection<V>> subMap(K fromKey, K toKey) {
+      return subMap(fromKey, true, toKey, false);
+    }
+
+    @Override
+    public NavigableMap<K, Collection<V>> subMap(
+        K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+      return new NavigableAsMap(sortedMap().subMap(fromKey, fromInclusive, toKey, toInclusive));
+    }
+
+    @Override
+    public NavigableMap<K, Collection<V>> headMap(K toKey) {
+      return headMap(toKey, false);
+    }
+
+    @Override
+    public NavigableMap<K, Collection<V>> headMap(K toKey, boolean inclusive) {
+      return new NavigableAsMap(sortedMap().headMap(toKey, inclusive));
+    }
+
+    @Override
+    public NavigableMap<K, Collection<V>> tailMap(K fromKey) {
+      return tailMap(fromKey, true);
+    }
+
+    @Override
+    public NavigableMap<K, Collection<V>> tailMap(K fromKey, boolean inclusive) {
+      return new NavigableAsMap(sortedMap().tailMap(fromKey, inclusive));
+    }
+  }
+
   private static final long serialVersionUID = 2447537837011683357L;
 }
diff --git a/guava/src/com/google/common/collect/AbstractMultiset.java b/guava/src/com/google/common/collect/AbstractMultiset.java
index 20ea93f..a271e34 100644
--- a/guava/src/com/google/common/collect/AbstractMultiset.java
+++ b/guava/src/com/google/common/collect/AbstractMultiset.java
@@ -165,7 +165,10 @@
 
   @Override public Set<Entry<E>> entrySet() {
     Set<Entry<E>> result = entrySet;
-    return (result == null) ? entrySet = createEntrySet() : result;
+    if (result == null) {
+      entrySet = result = createEntrySet();
+    }
+    return result;
   }
 
   class EntrySet extends Multisets.EntrySet<E> {
diff --git a/guava/src/com/google/common/collect/AbstractNavigableMap.java b/guava/src/com/google/common/collect/AbstractNavigableMap.java
new file mode 100644
index 0000000..f6defe6
--- /dev/null
+++ b/guava/src/com/google/common/collect/AbstractNavigableMap.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2012 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import java.util.AbstractMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.SortedMap;
+
+import javax.annotation.Nullable;
+
+/**
+ * Skeletal implementation of {@link NavigableMap}.
+ * 
+ * @author Louis Wasserman
+ */
+abstract class AbstractNavigableMap<K, V> extends AbstractMap<K, V> implements NavigableMap<K, V> {
+
+  @Override
+  @Nullable
+  public abstract V get(@Nullable Object key);
+  
+  @Override
+  @Nullable
+  public Entry<K, V> firstEntry() {
+    return Iterators.getNext(entryIterator(), null);
+  }
+
+  @Override
+  @Nullable
+  public Entry<K, V> lastEntry() {
+    return Iterators.getNext(descendingEntryIterator(), null);
+  }
+
+  @Override
+  @Nullable
+  public Entry<K, V> pollFirstEntry() {
+    return Iterators.pollNext(entryIterator());
+  }
+
+  @Override
+  @Nullable
+  public Entry<K, V> pollLastEntry() {
+    return Iterators.pollNext(descendingEntryIterator());
+  }
+
+  @Override
+  public K firstKey() {
+    Entry<K, V> entry = firstEntry();
+    if (entry == null) {
+      throw new NoSuchElementException();
+    } else {
+      return entry.getKey();
+    }
+  }
+
+  @Override
+  public K lastKey() {
+    Entry<K, V> entry = lastEntry();
+    if (entry == null) {
+      throw new NoSuchElementException();
+    } else {
+      return entry.getKey();
+    }
+  }
+
+  @Override
+  @Nullable
+  public Entry<K, V> lowerEntry(K key) {
+    return headMap(key, false).lastEntry();
+  }
+
+  @Override
+  @Nullable
+  public Entry<K, V> floorEntry(K key) {
+    return headMap(key, true).lastEntry();
+  }
+
+  @Override
+  @Nullable
+  public Entry<K, V> ceilingEntry(K key) {
+    return tailMap(key, true).firstEntry();
+  }
+
+  @Override
+  @Nullable
+  public Entry<K, V> higherEntry(K key) {
+    return tailMap(key, false).firstEntry();
+  }
+
+  @Override
+  public K lowerKey(K key) {
+    return Maps.keyOrNull(lowerEntry(key));
+  }
+
+  @Override
+  public K floorKey(K key) {
+    return Maps.keyOrNull(floorEntry(key));
+  }
+
+  @Override
+  public K ceilingKey(K key) {
+    return Maps.keyOrNull(ceilingEntry(key));
+  }
+
+  @Override
+  public K higherKey(K key) {
+    return Maps.keyOrNull(higherEntry(key));
+  }
+
+  abstract Iterator<Entry<K, V>> entryIterator();
+
+  abstract Iterator<Entry<K, V>> descendingEntryIterator();
+
+  @Override
+  public SortedMap<K, V> subMap(K fromKey, K toKey) {
+    return subMap(fromKey, true, toKey, false);
+  }
+
+  @Override
+  public SortedMap<K, V> headMap(K toKey) {
+    return headMap(toKey, false);
+  }
+
+  @Override
+  public SortedMap<K, V> tailMap(K fromKey) {
+    return tailMap(fromKey, true);
+  }
+
+  @Override
+  public NavigableSet<K> navigableKeySet() {
+    return new Maps.NavigableKeySet<K, V>(this);
+  }
+
+  @Override
+  public Set<K> keySet() {
+    return navigableKeySet();
+  }
+
+  @Override
+  public abstract int size();
+
+  @Override
+  public Set<Entry<K, V>> entrySet() {
+    return new Maps.EntrySet<K, V>() {
+      @Override
+      Map<K, V> map() {
+        return AbstractNavigableMap.this;
+      }
+
+      @Override
+      public Iterator<Entry<K, V>> iterator() {
+        return entryIterator();
+      }
+    };
+  }
+
+  @Override
+  public NavigableSet<K> descendingKeySet() {
+    return descendingMap().navigableKeySet();
+  }
+
+  @Override
+  public NavigableMap<K, V> descendingMap() {
+    return new DescendingMap();
+  }
+  
+  private final class DescendingMap extends Maps.DescendingMap<K, V> {
+    @Override
+    NavigableMap<K, V> forward() {
+      return AbstractNavigableMap.this;
+    }
+
+    @Override
+    Iterator<Entry<K, V>> entryIterator() {
+      return descendingEntryIterator();
+    }
+  }
+
+}
diff --git a/guava/src/com/google/common/collect/AbstractRangeSet.java b/guava/src/com/google/common/collect/AbstractRangeSet.java
new file mode 100644
index 0000000..dff3547
--- /dev/null
+++ b/guava/src/com/google/common/collect/AbstractRangeSet.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import javax.annotation.Nullable;
+
+/**
+ * A skeletal implementation of {@code RangeSet}.
+ *
+ * @author Louis Wasserman
+ */
+abstract class AbstractRangeSet<C extends Comparable> implements RangeSet<C> {
+  AbstractRangeSet() {}
+
+  @Override
+  public boolean contains(C value) {
+    return rangeContaining(value) != null;
+  }
+
+  @Override
+  public abstract Range<C> rangeContaining(C value);
+
+  @Override
+  public boolean isEmpty() {
+    return asRanges().isEmpty();
+  }
+
+  @Override
+  public void add(Range<C> range) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public void remove(Range<C> range) {
+    throw new UnsupportedOperationException();
+  }
+  
+  @Override
+  public void clear() {
+    remove(Range.<C>all());
+  }
+
+  @Override
+  public boolean enclosesAll(RangeSet<C> other) {
+    for (Range<C> range : other.asRanges()) {
+      if (!encloses(range)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  @Override
+  public void addAll(RangeSet<C> other) {
+    for (Range<C> range : other.asRanges()) {
+      add(range);
+    }
+  }
+
+  @Override
+  public void removeAll(RangeSet<C> other) {
+    for (Range<C> range : other.asRanges()) {
+      remove(range);
+    }
+  }
+
+  @Override
+  public abstract boolean encloses(Range<C> otherRange);
+
+  @Override
+  public boolean equals(@Nullable Object obj) {
+    if (obj == this) {
+      return true;
+    } else if (obj instanceof RangeSet) {
+      RangeSet<?> other = (RangeSet<?>) obj;
+      return this.asRanges().equals(other.asRanges());
+    }
+    return false;
+  }
+
+  @Override
+  public final int hashCode() {
+    return asRanges().hashCode();
+  }
+
+  @Override
+  public final String toString() {
+    return asRanges().toString();
+  }
+}
diff --git a/guava/src/com/google/common/collect/AbstractSortedMultiset.java b/guava/src/com/google/common/collect/AbstractSortedMultiset.java
index 3eea734..7c277f8 100644
--- a/guava/src/com/google/common/collect/AbstractSortedMultiset.java
+++ b/guava/src/com/google/common/collect/AbstractSortedMultiset.java
@@ -20,7 +20,7 @@
 
 import java.util.Comparator;
 import java.util.Iterator;
-import java.util.SortedSet;
+import java.util.NavigableSet;
 
 import javax.annotation.Nullable;
 
@@ -48,13 +48,13 @@
   }
 
   @Override
-  public SortedSet<E> elementSet() {
-    return (SortedSet<E>) super.elementSet();
+  public NavigableSet<E> elementSet() {
+    return (NavigableSet<E>) super.elementSet();
   }
 
   @Override
-  SortedSet<E> createElementSet() {
-    return new SortedMultisets.ElementSet<E>(this);
+  NavigableSet<E> createElementSet() {
+    return new SortedMultisets.NavigableElementSet<E>(this);
   }
 
   @Override
diff --git a/guava/src/com/google/common/collect/BinaryTreeTraverser.java b/guava/src/com/google/common/collect/BinaryTreeTraverser.java
index 6e89aa3..d86d6a4 100644
--- a/guava/src/com/google/common/collect/BinaryTreeTraverser.java
+++ b/guava/src/com/google/common/collect/BinaryTreeTraverser.java
@@ -22,9 +22,10 @@
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Optional;
 
+import java.util.ArrayDeque;
 import java.util.BitSet;
+import java.util.Deque;
 import java.util.Iterator;
-import java.util.LinkedList;
 
 /**
  * A variant of {@link TreeTraverser} for binary trees, providing additional traversals specific to
@@ -36,7 +37,7 @@
 @Beta
 @GwtCompatible(emulated = true)
 public abstract class BinaryTreeTraverser<T> extends TreeTraverser<T> {
-  // TODO(user): make this GWT-compatible when we've checked in LinkedList and BitSet emulation
+  // TODO(user): make this GWT-compatible when we've checked in ArrayDeque and BitSet emulation
 
   /**
    * Returns the left child of the specified node, or {@link Optional#absent()} if the specified
@@ -96,10 +97,10 @@
    */
   private final class PreOrderIterator extends UnmodifiableIterator<T>
       implements PeekingIterator<T> {
-    private final LinkedList<T> stack;
+    private final Deque<T> stack;
 
     PreOrderIterator(T root) {
-      this.stack = new LinkedList<T>();
+      this.stack = new ArrayDeque<T>();
       stack.addLast(root);
     }
 
@@ -131,11 +132,11 @@
    * Optimized implementation of postOrderIterator for binary trees.
    */
   private final class PostOrderIterator extends UnmodifiableIterator<T> {
-    private final LinkedList<T> stack;
+    private final Deque<T> stack;
     private final BitSet hasExpanded;
 
     PostOrderIterator(T root) {
-      this.stack = new LinkedList<T>();
+      this.stack = new ArrayDeque<T>();
       stack.addLast(root);
       this.hasExpanded = new BitSet();
     }
@@ -176,11 +177,11 @@
   }
 
   private final class InOrderIterator extends AbstractIterator<T> {
-    private final LinkedList<T> stack;
+    private final Deque<T> stack;
     private final BitSet hasExpandedLeft;
 
     InOrderIterator(T root) {
-      this.stack = new LinkedList<T>();
+      this.stack = new ArrayDeque<T>();
       this.hasExpandedLeft = new BitSet();
       stack.addLast(root);
     }
@@ -203,7 +204,7 @@
     }
   }
 
-  private static <T> void pushIfPresent(LinkedList<T> stack, Optional<T> node) {
+  private static <T> void pushIfPresent(Deque<T> stack, Optional<T> node) {
     if (node.isPresent()) {
       stack.addLast(node.get());
     }
diff --git a/guava/src/com/google/common/collect/ConcurrentHashMultiset.java b/guava/src/com/google/common/collect/ConcurrentHashMultiset.java
index e862460..89afa4e 100644
--- a/guava/src/com/google/common/collect/ConcurrentHashMultiset.java
+++ b/guava/src/com/google/common/collect/ConcurrentHashMultiset.java
@@ -472,14 +472,8 @@
     };
   }
 
-  private transient EntrySet entrySet;
-
-  @Override public Set<Multiset.Entry<E>> entrySet() {
-    EntrySet result = entrySet;
-    if (result == null) {
-      entrySet = result = new EntrySet();
-    }
-    return result;
+  @Override public Set<Multiset.Entry<E>> createEntrySet() {
+    return new EntrySet();
   }
 
   @Override int distinctElements() {
diff --git a/guava/src/com/google/common/collect/Constraint.java b/guava/src/com/google/common/collect/Constraint.java
index 48b244b..d8f510a 100644
--- a/guava/src/com/google/common/collect/Constraint.java
+++ b/guava/src/com/google/common/collect/Constraint.java
@@ -16,9 +16,7 @@
 
 package com.google.common.collect;
 
-import com.google.common.annotations.Beta;
 import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Preconditions;
 
 /**
  * A constraint that an element must satisfy in order to be added to a
@@ -40,21 +38,9 @@
  * that all the collection's elements meet the constraint, since the constraint
  * is only enforced when elements are added.
  *
- * @see Constraints
- * @see MapConstraint
  * @author Mike Bostock
- * @since 3.0
- * @deprecated Use {@link Preconditions} for basic checks. In place of
- *     constrained collections, we encourage you to check your preconditions
- *     explicitly instead of leaving that work to the collection implementation.
- *     For the specific case of rejecting null, consider the immutable
- *     collections.
- *     This interface is scheduled for removal in Guava 16.0.
  */
-@Beta
-@Deprecated
 @GwtCompatible
-public
 interface Constraint<E> {
   /**
    * Throws a suitable {@code RuntimeException} if the specified element is
diff --git a/guava/src/com/google/common/collect/Constraints.java b/guava/src/com/google/common/collect/Constraints.java
index 169a40c..2b5da00 100644
--- a/guava/src/com/google/common/collect/Constraints.java
+++ b/guava/src/com/google/common/collect/Constraints.java
@@ -18,9 +18,7 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import com.google.common.annotations.Beta;
 import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Preconditions;
 
 import java.util.Collection;
 import java.util.List;
@@ -32,47 +30,13 @@
 /**
  * Factories and utilities pertaining to the {@link Constraint} interface.
  *
- * @see MapConstraints
  * @author Mike Bostock
  * @author Jared Levy
- * @since 3.0
- * @deprecated Use {@link Preconditions} for basic checks. In place of
- *     constrained collections, we encourage you to check your preconditions
- *     explicitly instead of leaving that work to the collection implementation.
- *     For the specific case of rejecting null, consider the immutable
- *     collections.
- *     This class is scheduled for removal in Guava 16.0.
  */
-@Beta
-@Deprecated
 @GwtCompatible
-public final class Constraints {
+final class Constraints {
   private Constraints() {}
 
-  // enum singleton pattern
-  private enum NotNullConstraint implements Constraint<Object> {
-    INSTANCE;
-
-    @Override
-    public Object checkElement(Object element) {
-      return checkNotNull(element);
-    }
-
-    @Override public String toString() {
-      return "Not null";
-    }
-  }
-
-  /**
-   * Returns a constraint that verifies that the element is not null. If the
-   * element is null, a {@link NullPointerException} is thrown.
-   */
-  // safe to narrow the type since checkElement returns its argument directly
-  @SuppressWarnings("unchecked")
-  public static <E> Constraint<E> notNull() {
-    return (Constraint<E>) NotNullConstraint.INSTANCE;
-  }
-
   /**
    * Returns a constrained view of the specified collection, using the specified
    * constraint. Any operations that add new elements to the collection will
@@ -324,56 +288,6 @@
     }
   }
 
-  /**
-   * Returns a constrained view of the specified multiset, using the specified
-   * constraint. Any operations that add new elements to the multiset will call
-   * the provided constraint. However, this method does not verify that
-   * existing elements satisfy the constraint.
-   *
-   * <p>The returned multiset is not serializable.
-   *
-   * @param multiset the multiset to constrain
-   * @param constraint the constraint that validates added elements
-   * @return a constrained view of the multiset
-   */
-  public static <E> Multiset<E> constrainedMultiset(
-      Multiset<E> multiset, Constraint<? super E> constraint) {
-    return new ConstrainedMultiset<E>(multiset, constraint);
-  }
-
-  /** @see Constraints#constrainedMultiset */
-  static class ConstrainedMultiset<E> extends ForwardingMultiset<E> {
-    private Multiset<E> delegate;
-    private final Constraint<? super E> constraint;
-
-    public ConstrainedMultiset(
-        Multiset<E> delegate, Constraint<? super E> constraint) {
-      this.delegate = checkNotNull(delegate);
-      this.constraint = checkNotNull(constraint);
-    }
-    @Override protected Multiset<E> delegate() {
-      return delegate;
-    }
-    @Override public boolean add(E element) {
-      return standardAdd(element);
-    }
-    @Override public boolean addAll(Collection<? extends E> elements) {
-      return delegate.addAll(checkElements(elements, constraint));
-    }
-    @Override public int add(E element, int occurrences) {
-      constraint.checkElement(element);
-      return delegate.add(element, occurrences);
-    }
-    @Override public int setCount(E element, int count) {
-      constraint.checkElement(element);
-      return delegate.setCount(element, count);
-    }
-    @Override public boolean setCount(E element, int oldCount, int newCount) {
-      constraint.checkElement(element);
-      return delegate.setCount(element, oldCount, newCount);
-    }
-  }
-
   /*
    * TODO(kevinb): For better performance, avoid making a copy of the elements
    * by having addAll() call add() repeatedly instead.
diff --git a/guava/src/com/google/common/collect/DescendingMultiset.java b/guava/src/com/google/common/collect/DescendingMultiset.java
index 95da0a8..d83f782 100644
--- a/guava/src/com/google/common/collect/DescendingMultiset.java
+++ b/guava/src/com/google/common/collect/DescendingMultiset.java
@@ -20,8 +20,8 @@
 
 import java.util.Comparator;
 import java.util.Iterator;
+import java.util.NavigableSet;
 import java.util.Set;
-import java.util.SortedSet;
 
 /**
  * A skeleton implementation of a descending multiset.  Only needs
@@ -45,12 +45,12 @@
     return result;
   }
 
-  private transient SortedSet<E> elementSet;
+  private transient NavigableSet<E> elementSet;
 
-  @Override public SortedSet<E> elementSet() {
-    SortedSet<E> result = elementSet;
+  @Override public NavigableSet<E> elementSet() {
+    NavigableSet<E> result = elementSet;
     if (result == null) {
-      return elementSet = new SortedMultisets.ElementSet<E>(this);
+      return elementSet = new SortedMultisets.NavigableElementSet<E>(this);
     }
     return result;
   }
@@ -137,4 +137,4 @@
   @Override public String toString() {
     return entrySet().toString();
   }
-}
+}
\ No newline at end of file
diff --git a/guava/src/com/google/common/collect/EvictingQueue.java b/guava/src/com/google/common/collect/EvictingQueue.java
index ae12b04..c124a0c 100644
--- a/guava/src/com/google/common/collect/EvictingQueue.java
+++ b/guava/src/com/google/common/collect/EvictingQueue.java
@@ -24,8 +24,8 @@
 import com.google.common.annotations.VisibleForTesting;
 
 import java.io.Serializable;
+import java.util.ArrayDeque;
 import java.util.Collection;
-import java.util.LinkedList;
 import java.util.Queue;
 
 /**
@@ -52,7 +52,7 @@
 
   private EvictingQueue(int maxSize) {
     checkArgument(maxSize >= 0, "maxSize (%s) must >= 0", maxSize);
-    this.delegate = new LinkedList<E>();
+    this.delegate = new ArrayDeque<E>(maxSize);
     this.maxSize = maxSize;
   }
 
diff --git a/guava/src/com/google/common/collect/FilteredEntryMultimap.java b/guava/src/com/google/common/collect/FilteredEntryMultimap.java
index d33e449..ebc3d4b 100644
--- a/guava/src/com/google/common/collect/FilteredEntryMultimap.java
+++ b/guava/src/com/google/common/collect/FilteredEntryMultimap.java
@@ -22,7 +22,7 @@
 import static com.google.common.collect.CollectPreconditions.checkNonnegative;
 
 import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Maps.ImprovedAbstractMap;
 
@@ -101,7 +101,7 @@
 
   @Override
   public Collection<V> removeAll(@Nullable Object key) {
-    return Objects.firstNonNull(asMap().remove(key), unmodifiableEmptyCollection());
+    return MoreObjects.firstNonNull(asMap().remove(key), unmodifiableEmptyCollection());
   }
 
   Collection<V> unmodifiableEmptyCollection() {
diff --git a/guava/src/com/google/common/collect/FluentIterable.java b/guava/src/com/google/common/collect/FluentIterable.java
index 7883763..e007ef7 100644
--- a/guava/src/com/google/common/collect/FluentIterable.java
+++ b/guava/src/com/google/common/collect/FluentIterable.java
@@ -22,9 +22,11 @@
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
 import com.google.common.base.Function;
+import com.google.common.base.Joiner;
 import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.Iterator;
@@ -110,6 +112,16 @@
   }
 
   /**
+   * Returns a fluent iterable containing {@code elements} in the specified order.
+   *
+   * @since 18.0
+   */
+  @Beta
+  public static <E> FluentIterable<E> of(E[] elements) {
+    return from(Lists.newArrayList(elements));
+  }
+
+  /**
    * Returns a string representation of this fluent iterable, with the format
    * {@code [e1, e2, ..., en]}.
    */
@@ -152,6 +164,33 @@
   }
 
   /**
+   * Returns a fluent iterable whose iterators traverse first the elements of this fluent iterable,
+   * followed by those of {@code other}. The iterators are not polled until necessary.
+   *
+   * <p>The returned iterable's {@code Iterator} supports {@code remove()} when the corresponding
+   * {@code Iterator} supports it.
+   *
+   * @since 18.0
+   */
+  @Beta
+  @CheckReturnValue
+  public final FluentIterable<E> append(Iterable<? extends E> other) {
+    return from(Iterables.concat(iterable, other));
+  }
+
+  /**
+   * Returns a fluent iterable whose iterators traverse first the elements of this fluent iterable,
+   * followed by {@code elements}.
+   *
+   * @since 18.0
+   */
+  @Beta
+  @CheckReturnValue
+  public final FluentIterable<E> append(E... elements) {
+    return from(Iterables.concat(iterable, Arrays.asList(elements)));
+  }
+
+  /**
    * Returns the elements from this fluent iterable that satisfy a predicate. The
    * resulting fluent iterable's iterator does not support {@code remove()}.
    */
@@ -343,7 +382,6 @@
    * @throws NullPointerException if any element is null
    * @since 14.0 (since 13.0 as {@code toSortedImmutableList()}).
    */
-  @Beta
   public final ImmutableList<E> toSortedList(Comparator<? super E> comparator) {
     return Ordering.from(comparator).immutableSortedCopy(iterable);
   }
@@ -425,64 +463,6 @@
   }
 
   /**
-   * Returns an {@code ImmutableList} containing all of the elements from this
-   * fluent iterable in proper sequence.
-   *
-   * @deprecated Use {@link #toList()} instead. This method is scheduled for removal in Guava 15.0.
-   */
-  @Deprecated
-  public final ImmutableList<E> toImmutableList() {
-    return toList();
-  }
-
-  /**
-   * Returns an {@code ImmutableList} containing all of the elements from this
-   * {@code FluentIterable} in the order specified by {@code comparator}.  To produce an
-   * {@code ImmutableList} sorted by its natural ordering, use
-   * {@code toSortedImmutableList(Ordering.natural())}.
-   *
-   * @param comparator the function by which to sort list elements
-   * @throws NullPointerException if any element is null
-   * @since 13.0
-   * @deprecated Use {@link #toSortedList(Comparator)} instead. This method is scheduled for removal
-   *     in Guava 15.0.
-   */
-  @Deprecated
-  public final ImmutableList<E> toSortedImmutableList(
-      Comparator<? super E> comparator) {
-    return toSortedList(comparator);
-  }
-
-  /**
-   * Returns an {@code ImmutableSet} containing all of the elements from this
-   * fluent iterable with duplicates removed.
-   *
-   * @deprecated Use {@link #toSet()} instead. This method is scheduled for removal in Guava 15.0.
-   */
-  @Deprecated
-  public final ImmutableSet<E> toImmutableSet() {
-    return toSet();
-  }
-
-  /**
-   * Returns an {@code ImmutableSortedSet} containing all of the elements from this
-   * {@code FluentIterable} in the order specified by {@code comparator}, with duplicates
-   * (determined by {@code comparator.compare(x, y) == 0}) removed. To produce an
-   * {@code ImmutableSortedSet} sorted by its natural ordering, use
-   * {@code toImmutableSortedSet(Ordering.natural())}.
-   *
-   * @param comparator the function by which to sort set elements
-   * @throws NullPointerException if any element is null
-   * @deprecated Use {@link #toSortedSet(Comparator)} instead. This method is scheduled for removal
-   *     in Guava 15.0.
-   */
-  @Deprecated
-  public final ImmutableSortedSet<E> toImmutableSortedSet(
-      Comparator<? super E> comparator) {
-    return toSortedSet(comparator);
-  }
-
-  /**
    * Returns an array containing all of the elements from this fluent iterable in iteration order.
    *
    * @param type the type of the elements
@@ -515,6 +495,17 @@
   }
 
   /**
+   * Returns a {@link String} containing all of the elements of this fluent iterable joined with
+   * {@code joiner}.
+   *
+   * @since 18.0
+   */
+  @Beta
+  public final String join(Joiner joiner) {
+    return joiner.join(this);
+  }
+
+  /**
    * Returns the element at the specified position in this fluent iterable.
    *
    * @param position position of the element to return
diff --git a/guava/src/com/google/common/collect/ForwardingBlockingDeque.java b/guava/src/com/google/common/collect/ForwardingBlockingDeque.java
new file mode 100644
index 0000000..a6fb43d
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingBlockingDeque.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2012 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import java.util.Collection;
+import java.util.concurrent.BlockingDeque;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A {@link BlockingDeque} which forwards all its method calls to another {@code BlockingDeque}.
+ * Subclasses should override one or more methods to modify the behavior of the backing deque as
+ * desired per the <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * <p><b>Warning:</b> The methods of {@code ForwardingBlockingDeque} forward
+ * <b>indiscriminately</b> to the methods of the delegate. For example, overriding {@link #add}
+ * alone <b>will not</b> change the behaviour of {@link #offer} which can lead to unexpected
+ * behaviour. In this case, you should override {@code offer} as well, either providing your own
+ * implementation, or delegating to the provided {@code standardOffer} method.
+ *
+ * <p>
+ * The {@code standard} methods are not guaranteed to be thread-safe, even when all of the methods
+ * that they depend on are thread-safe.
+ *
+ * @author Emily Soldal
+ * @since 14.0
+ */
+public abstract class ForwardingBlockingDeque<E>
+    extends ForwardingDeque<E> implements BlockingDeque<E> {
+
+  /** Constructor for use by subclasses. */
+  protected ForwardingBlockingDeque() {}
+
+  @Override protected abstract BlockingDeque<E> delegate();
+
+  @Override
+  public int remainingCapacity() {
+    return delegate().remainingCapacity();
+  }
+
+  @Override
+  public void putFirst(E e) throws InterruptedException {
+    delegate().putFirst(e);
+  }
+
+  @Override
+  public void putLast(E e) throws InterruptedException {
+    delegate().putLast(e);
+  }
+
+  @Override
+  public boolean offerFirst(E e, long timeout, TimeUnit unit) throws InterruptedException {
+    return delegate().offerFirst(e, timeout, unit);
+  }
+
+  @Override
+  public boolean offerLast(E e, long timeout, TimeUnit unit) throws InterruptedException {
+    return delegate().offerLast(e, timeout, unit);
+  }
+
+  @Override
+  public E takeFirst() throws InterruptedException {
+    return delegate().takeFirst();
+  }
+
+  @Override
+  public E takeLast() throws InterruptedException {
+    return delegate().takeLast();
+  }
+
+  @Override
+  public E pollFirst(long timeout, TimeUnit unit) throws InterruptedException {
+    return delegate().pollFirst(timeout, unit);
+  }
+
+  @Override
+  public E pollLast(long timeout, TimeUnit unit) throws InterruptedException {
+    return delegate().pollLast(timeout, unit);
+  }
+
+  @Override
+  public void put(E e) throws InterruptedException {
+    delegate().put(e);
+  }
+
+  @Override
+  public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
+    return delegate().offer(e, timeout, unit);
+  }
+
+  @Override
+  public E take() throws InterruptedException {
+    return delegate().take();
+  }
+
+  @Override
+  public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+    return delegate().poll(timeout, unit);
+  }
+
+  @Override
+  public int drainTo(Collection<? super E> c) {
+    return delegate().drainTo(c);
+  }
+
+  @Override
+  public int drainTo(Collection<? super E> c, int maxElements) {
+    return delegate().drainTo(c, maxElements);
+  }
+}
diff --git a/guava/src/com/google/common/collect/ForwardingDeque.java b/guava/src/com/google/common/collect/ForwardingDeque.java
new file mode 100644
index 0000000..070f622
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingDeque.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2012 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import java.util.Deque;
+import java.util.Iterator;
+
+/**
+ * A deque which forwards all its method calls to another deque. Subclasses
+ * should override one or more methods to modify the behavior of the backing
+ * deque as desired per the <a
+ * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * <p><b>Warning:</b> The methods of {@code ForwardingDeque} forward
+ * <b>indiscriminately</b> to the methods of the delegate. For example,
+ * overriding {@link #add} alone <b>will not</b> change the behavior of {@link
+ * #offer} which can lead to unexpected behavior. In this case, you should
+ * override {@code offer} as well.
+ *
+ * @author Kurt Alfred Kluever
+ * @since 12.0
+ */
+public abstract class ForwardingDeque<E> extends ForwardingQueue<E>
+    implements Deque<E> {
+
+  /** Constructor for use by subclasses. */
+  protected ForwardingDeque() {}
+
+  @Override protected abstract Deque<E> delegate();
+
+  @Override
+  public void addFirst(E e) {
+    delegate().addFirst(e);
+  }
+
+  @Override
+  public void addLast(E e) {
+    delegate().addLast(e);
+  }
+
+  @Override
+  public Iterator<E> descendingIterator() {
+    return delegate().descendingIterator();
+  }
+
+  @Override
+  public E getFirst() {
+    return delegate().getFirst();
+  }
+
+  @Override
+  public E getLast() {
+    return delegate().getLast();
+  }
+
+  @Override
+  public boolean offerFirst(E e) {
+    return delegate().offerFirst(e);
+  }
+
+  @Override
+  public boolean offerLast(E e) {
+    return delegate().offerLast(e);
+  }
+
+  @Override
+  public E peekFirst() {
+    return delegate().peekFirst();
+  }
+
+  @Override
+  public E peekLast() {
+    return delegate().peekLast();
+  }
+
+  @Override
+  public E pollFirst() {
+    return delegate().pollFirst();
+  }
+
+  @Override
+  public E pollLast() {
+    return delegate().pollLast();
+  }
+
+  @Override
+  public E pop() {
+    return delegate().pop();
+  }
+
+  @Override
+  public void push(E e) {
+    delegate().push(e);
+  }
+
+  @Override
+  public E removeFirst() {
+    return delegate().removeFirst();
+  }
+
+  @Override
+  public E removeLast() {
+    return delegate().removeLast();
+  }
+
+  @Override
+  public boolean removeFirstOccurrence(Object o) {
+    return delegate().removeFirstOccurrence(o);
+  }
+
+  @Override
+  public boolean removeLastOccurrence(Object o) {
+    return delegate().removeLastOccurrence(o);
+  }
+}
diff --git a/guava/src/com/google/common/collect/ForwardingNavigableMap.java b/guava/src/com/google/common/collect/ForwardingNavigableMap.java
new file mode 100644
index 0000000..3e11239
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingNavigableMap.java
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2012 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import static com.google.common.collect.CollectPreconditions.checkRemove;
+import static com.google.common.collect.Maps.keyOrNull;
+
+import com.google.common.annotations.Beta;
+
+import java.util.Iterator;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
+import java.util.NoSuchElementException;
+import java.util.SortedMap;
+
+/**
+ * A navigable map which forwards all its method calls to another navigable map. Subclasses should
+ * override one or more methods to modify the behavior of the backing map as desired per the <a
+ * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * <p><i>Warning:</i> The methods of {@code ForwardingNavigableMap} forward <i>indiscriminately</i>
+ * to the methods of the delegate. For example, overriding {@link #put} alone <i>will not</i>
+ * change the behavior of {@link #putAll}, which can lead to unexpected behavior. In this case, you
+ * should override {@code putAll} as well, either providing your own implementation, or delegating
+ * to the provided {@code standardPutAll} method.
+ *
+ * <p>Each of the {@code standard} methods uses the map's comparator (or the natural ordering of
+ * the elements, if there is no comparator) to test element equality. As a result, if the comparator
+ * is not consistent with equals, some of the standard implementations may violate the {@code Map}
+ * contract.
+ *
+ * <p>The {@code standard} methods and the collection views they return are not guaranteed to be
+ * thread-safe, even when all of the methods that they depend on are thread-safe.
+ *
+ * @author Louis Wasserman
+ * @since 12.0
+ */
+public abstract class ForwardingNavigableMap<K, V>
+    extends ForwardingSortedMap<K, V> implements NavigableMap<K, V> {
+
+  /** Constructor for use by subclasses. */
+  protected ForwardingNavigableMap() {}
+
+  @Override
+  protected abstract NavigableMap<K, V> delegate();
+
+  @Override
+  public Entry<K, V> lowerEntry(K key) {
+    return delegate().lowerEntry(key);
+  }
+
+  /**
+   * A sensible definition of {@link #lowerEntry} in terms of the {@code lastEntry()} of
+   * {@link #headMap(Object, boolean)}. If you override {@code headMap}, you may wish to override
+   * {@code lowerEntry} to forward to this implementation.
+   */
+  protected Entry<K, V> standardLowerEntry(K key) {
+    return headMap(key, false).lastEntry();
+  }
+
+  @Override
+  public K lowerKey(K key) {
+    return delegate().lowerKey(key);
+  }
+
+  /**
+   * A sensible definition of {@link #lowerKey} in terms of {@code lowerEntry}. If you override
+   * {@link #lowerEntry}, you may wish to override {@code lowerKey} to forward to this
+   * implementation.
+   */
+  protected K standardLowerKey(K key) {
+    return keyOrNull(lowerEntry(key));
+  }
+
+  @Override
+  public Entry<K, V> floorEntry(K key) {
+    return delegate().floorEntry(key);
+  }
+
+  /**
+   * A sensible definition of {@link #floorEntry} in terms of the {@code lastEntry()} of
+   * {@link #headMap(Object, boolean)}. If you override {@code headMap}, you may wish to override
+   * {@code floorEntry} to forward to this implementation.
+   */
+  protected Entry<K, V> standardFloorEntry(K key) {
+    return headMap(key, true).lastEntry();
+  }
+
+  @Override
+  public K floorKey(K key) {
+    return delegate().floorKey(key);
+  }
+
+  /**
+   * A sensible definition of {@link #floorKey} in terms of {@code floorEntry}. If you override
+   * {@code floorEntry}, you may wish to override {@code floorKey} to forward to this
+   * implementation.
+   */
+  protected K standardFloorKey(K key) {
+    return keyOrNull(floorEntry(key));
+  }
+
+  @Override
+  public Entry<K, V> ceilingEntry(K key) {
+    return delegate().ceilingEntry(key);
+  }
+
+  /**
+   * A sensible definition of {@link #ceilingEntry} in terms of the {@code firstEntry()} of
+   * {@link #tailMap(Object, boolean)}. If you override {@code tailMap}, you may wish to override
+   * {@code ceilingEntry} to forward to this implementation.
+   */
+  protected Entry<K, V> standardCeilingEntry(K key) {
+    return tailMap(key, true).firstEntry();
+  }
+
+  @Override
+  public K ceilingKey(K key) {
+    return delegate().ceilingKey(key);
+  }
+
+  /**
+   * A sensible definition of {@link #ceilingKey} in terms of {@code ceilingEntry}. If you override
+   * {@code ceilingEntry}, you may wish to override {@code ceilingKey} to forward to this
+   * implementation.
+   */
+  protected K standardCeilingKey(K key) {
+    return keyOrNull(ceilingEntry(key));
+  }
+
+  @Override
+  public Entry<K, V> higherEntry(K key) {
+    return delegate().higherEntry(key);
+  }
+
+  /**
+   * A sensible definition of {@link #higherEntry} in terms of the {@code firstEntry()} of
+   * {@link #tailMap(Object, boolean)}. If you override {@code tailMap}, you may wish to override
+   * {@code higherEntry} to forward to this implementation.
+   */
+  protected Entry<K, V> standardHigherEntry(K key) {
+    return tailMap(key, false).firstEntry();
+  }
+
+  @Override
+  public K higherKey(K key) {
+    return delegate().higherKey(key);
+  }
+
+  /**
+   * A sensible definition of {@link #higherKey} in terms of {@code higherEntry}. If you override
+   * {@code higherEntry}, you may wish to override {@code higherKey} to forward to this
+   * implementation.
+   */
+  protected K standardHigherKey(K key) {
+    return keyOrNull(higherEntry(key));
+  }
+
+  @Override
+  public Entry<K, V> firstEntry() {
+    return delegate().firstEntry();
+  }
+
+  /**
+   * A sensible definition of {@link #firstEntry} in terms of the {@code iterator()} of
+   * {@link #entrySet}. If you override {@code entrySet}, you may wish to override
+   * {@code firstEntry} to forward to this implementation.
+   */
+  protected Entry<K, V> standardFirstEntry() {
+    return Iterables.getFirst(entrySet(), null);
+  }
+
+  /**
+   * A sensible definition of {@link #firstKey} in terms of {@code firstEntry}. If you override
+   * {@code firstEntry}, you may wish to override {@code firstKey} to forward to this
+   * implementation.
+   */
+  protected K standardFirstKey() {
+    Entry<K, V> entry = firstEntry();
+    if (entry == null) {
+      throw new NoSuchElementException();
+    } else {
+      return entry.getKey();
+    }
+  }
+
+  @Override
+  public Entry<K, V> lastEntry() {
+    return delegate().lastEntry();
+  }
+
+  /**
+   * A sensible definition of {@link #lastEntry} in terms of the {@code iterator()} of the
+   * {@link #entrySet} of {@link #descendingMap}. If you override {@code descendingMap}, you may
+   * wish to override {@code lastEntry} to forward to this implementation.
+   */
+  protected Entry<K, V> standardLastEntry() {
+    return Iterables.getFirst(descendingMap().entrySet(), null);
+  }
+
+  /**
+   * A sensible definition of {@link #lastKey} in terms of {@code lastEntry}. If you override
+   * {@code lastEntry}, you may wish to override {@code lastKey} to forward to this implementation.
+   */
+  protected K standardLastKey() {
+    Entry<K, V> entry = lastEntry();
+    if (entry == null) {
+      throw new NoSuchElementException();
+    } else {
+      return entry.getKey();
+    }
+  }
+
+  @Override
+  public Entry<K, V> pollFirstEntry() {
+    return delegate().pollFirstEntry();
+  }
+
+  /**
+   * A sensible definition of {@link #pollFirstEntry} in terms of the {@code iterator} of
+   * {@code entrySet}. If you override {@code entrySet}, you may wish to override
+   * {@code pollFirstEntry} to forward to this implementation.
+   */
+  protected Entry<K, V> standardPollFirstEntry() {
+    return Iterators.pollNext(entrySet().iterator());
+  }
+
+  @Override
+  public Entry<K, V> pollLastEntry() {
+    return delegate().pollLastEntry();
+  }
+
+  /**
+   * A sensible definition of {@link #pollFirstEntry} in terms of the {@code iterator} of the
+   * {@code entrySet} of {@code descendingMap}. If you override {@code descendingMap}, you may wish
+   * to override {@code pollFirstEntry} to forward to this implementation.
+   */
+  protected Entry<K, V> standardPollLastEntry() {
+    return Iterators.pollNext(descendingMap().entrySet().iterator());
+  }
+
+  @Override
+  public NavigableMap<K, V> descendingMap() {
+    return delegate().descendingMap();
+  }
+
+  /**
+   * A sensible implementation of {@link NavigableMap#descendingMap} in terms of the methods of
+   * this {@code NavigableMap}. In many cases, you may wish to override
+   * {@link ForwardingNavigableMap#descendingMap} to forward to this implementation or a subclass
+   * thereof.
+   *
+   * <p>In particular, this map iterates over entries with repeated calls to
+   * {@link NavigableMap#lowerEntry}. If a more efficient means of iteration is available, you may
+   * wish to override the {@code entryIterator()} method of this class.
+   *
+   * @since 12.0
+   */
+  @Beta
+  protected class StandardDescendingMap extends Maps.DescendingMap<K, V> {
+    /** Constructor for use by subclasses. */
+    public StandardDescendingMap() {}
+
+    @Override
+    NavigableMap<K, V> forward() {
+      return ForwardingNavigableMap.this;
+    }
+
+    @Override
+    protected Iterator<Entry<K, V>> entryIterator() {
+      return new Iterator<Entry<K, V>>() {
+        private Entry<K, V> toRemove = null;
+        private Entry<K, V> nextOrNull = forward().lastEntry();
+
+        @Override
+        public boolean hasNext() {
+          return nextOrNull != null;
+        }
+
+        @Override
+        public java.util.Map.Entry<K, V> next() {
+          if (!hasNext()) {
+            throw new NoSuchElementException();
+          }
+          try {
+            return nextOrNull;
+          } finally {
+            toRemove = nextOrNull;
+            nextOrNull = forward().lowerEntry(nextOrNull.getKey());
+          }
+        }
+
+        @Override
+        public void remove() {
+          checkRemove(toRemove != null);
+          forward().remove(toRemove.getKey());
+          toRemove = null;
+        }
+      };
+    }
+  }
+
+  @Override
+  public NavigableSet<K> navigableKeySet() {
+    return delegate().navigableKeySet();
+  }
+
+  /**
+   * A sensible implementation of {@link NavigableMap#navigableKeySet} in terms of the methods of
+   * this {@code NavigableMap}. In many cases, you may wish to override
+   * {@link ForwardingNavigableMap#navigableKeySet} to forward to this implementation or a subclass
+   * thereof.
+   *
+   * @since 12.0
+   */
+  @Beta
+  protected class StandardNavigableKeySet extends Maps.NavigableKeySet<K, V> {
+    /** Constructor for use by subclasses. */
+    public StandardNavigableKeySet() {
+      super(ForwardingNavigableMap.this);
+    }
+  }
+
+  @Override
+  public NavigableSet<K> descendingKeySet() {
+    return delegate().descendingKeySet();
+  }
+
+  /**
+   * A sensible definition of {@link #descendingKeySet} as the {@code navigableKeySet} of
+   * {@link #descendingMap}. (The {@link StandardDescendingMap} implementation implements
+   * {@code navigableKeySet} on its own, so as not to cause an infinite loop.) If you override
+   * {@code descendingMap}, you may wish to override {@code descendingKeySet} to forward to this
+   * implementation.
+   */
+  @Beta
+  protected NavigableSet<K> standardDescendingKeySet() {
+    return descendingMap().navigableKeySet();
+  }
+
+  /**
+   * A sensible definition of {@link #subMap(Object, Object)} in terms of
+   * {@link #subMap(Object, boolean, Object, boolean)}. If you override
+   * {@code subMap(K, boolean, K, boolean)}, you may wish to override {@code subMap} to forward to
+   * this implementation.
+   */
+  @Override
+  protected SortedMap<K, V> standardSubMap(K fromKey, K toKey) {
+    return subMap(fromKey, true, toKey, false);
+  }
+
+  @Override
+  public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+    return delegate().subMap(fromKey, fromInclusive, toKey, toInclusive);
+  }
+
+  @Override
+  public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
+    return delegate().headMap(toKey, inclusive);
+  }
+
+  @Override
+  public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
+    return delegate().tailMap(fromKey, inclusive);
+  }
+
+  /**
+   * A sensible definition of {@link #headMap(Object)} in terms of
+   * {@link #headMap(Object, boolean)}. If you override {@code headMap(K, boolean)}, you may wish
+   * to override {@code headMap} to forward to this implementation.
+   */
+  protected SortedMap<K, V> standardHeadMap(K toKey) {
+    return headMap(toKey, false);
+  }
+
+  /**
+   * A sensible definition of {@link #tailMap(Object)} in terms of
+   * {@link #tailMap(Object, boolean)}. If you override {@code tailMap(K, boolean)}, you may wish
+   * to override {@code tailMap} to forward to this implementation.
+   */
+  protected SortedMap<K, V> standardTailMap(K fromKey) {
+    return tailMap(fromKey, true);
+  }
+}
diff --git a/guava/src/com/google/common/collect/ForwardingNavigableSet.java b/guava/src/com/google/common/collect/ForwardingNavigableSet.java
new file mode 100644
index 0000000..dff5ea0
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingNavigableSet.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2012 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import com.google.common.annotations.Beta;
+
+import java.util.Iterator;
+import java.util.NavigableSet;
+import java.util.SortedSet;
+
+/**
+ * A navigable set which forwards all its method calls to another navigable set. Subclasses should
+ * override one or more methods to modify the behavior of the backing set as desired per the <a
+ * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * <p><i>Warning:</i> The methods of {@code ForwardingNavigableSet} forward <i>indiscriminately</i>
+ * to the methods of the delegate. For example, overriding {@link #add} alone <i>will not</i>
+ * change the behavior of {@link #addAll}, which can lead to unexpected behavior. In this case, you
+ * should override {@code addAll} as well, either providing your own implementation, or delegating
+ * to the provided {@code standardAddAll} method.
+ *
+ * <p>Each of the {@code standard} methods uses the set's comparator (or the natural ordering of
+ * the elements, if there is no comparator) to test element equality. As a result, if the
+ * comparator is not consistent with equals, some of the standard implementations may violate the
+ * {@code Set} contract.
+ *
+ * <p>The {@code standard} methods and the collection views they return are not guaranteed to be
+ * thread-safe, even when all of the methods that they depend on are thread-safe.
+ *
+ * @author Louis Wasserman
+ * @since 12.0
+ */
+public abstract class ForwardingNavigableSet<E>
+    extends ForwardingSortedSet<E> implements NavigableSet<E> {
+
+  /** Constructor for use by subclasses. */
+  protected ForwardingNavigableSet() {}
+
+  @Override
+  protected abstract NavigableSet<E> delegate();
+
+  @Override
+  public E lower(E e) {
+    return delegate().lower(e);
+  }
+
+  /**
+   * A sensible definition of {@link #lower} in terms of the {@code descendingIterator} method of
+   * {@link #headSet(Object, boolean)}. If you override {@link #headSet(Object, boolean)}, you may
+   * wish to override {@link #lower} to forward to this implementation.
+   */
+  protected E standardLower(E e) {
+    return Iterators.getNext(headSet(e, false).descendingIterator(), null);
+  }
+
+  @Override
+  public E floor(E e) {
+    return delegate().floor(e);
+  }
+
+  /**
+   * A sensible definition of {@link #floor} in terms of the {@code descendingIterator} method of
+   * {@link #headSet(Object, boolean)}. If you override {@link #headSet(Object, boolean)}, you may
+   * wish to override {@link #floor} to forward to this implementation.
+   */
+  protected E standardFloor(E e) {
+    return Iterators.getNext(headSet(e, true).descendingIterator(), null);
+  }
+
+  @Override
+  public E ceiling(E e) {
+    return delegate().ceiling(e);
+  }
+
+  /**
+   * A sensible definition of {@link #ceiling} in terms of the {@code iterator} method of
+   * {@link #tailSet(Object, boolean)}. If you override {@link #tailSet(Object, boolean)}, you may
+   * wish to override {@link #ceiling} to forward to this implementation.
+   */
+  protected E standardCeiling(E e) {
+    return Iterators.getNext(tailSet(e, true).iterator(), null);
+  }
+
+  @Override
+  public E higher(E e) {
+    return delegate().higher(e);
+  }
+
+  /**
+   * A sensible definition of {@link #higher} in terms of the {@code iterator} method of
+   * {@link #tailSet(Object, boolean)}. If you override {@link #tailSet(Object, boolean)}, you may
+   * wish to override {@link #higher} to forward to this implementation.
+   */
+  protected E standardHigher(E e) {
+    return Iterators.getNext(tailSet(e, false).iterator(), null);
+  }
+
+  @Override
+  public E pollFirst() {
+    return delegate().pollFirst();
+  }
+
+  /**
+   * A sensible definition of {@link #pollFirst} in terms of the {@code iterator} method. If you
+   * override {@link #iterator} you may wish to override {@link #pollFirst} to forward to this
+   * implementation.
+   */
+  protected E standardPollFirst() {
+    return Iterators.pollNext(iterator());
+  }
+
+  @Override
+  public E pollLast() {
+    return delegate().pollLast();
+  }
+
+  /**
+   * A sensible definition of {@link #pollLast} in terms of the {@code descendingIterator} method.
+   * If you override {@link #descendingIterator} you may wish to override {@link #pollLast} to
+   * forward to this implementation.
+   */
+  protected E standardPollLast() {
+    return Iterators.pollNext(descendingIterator());
+  }
+
+  protected E standardFirst() {
+    return iterator().next();
+  }
+
+  protected E standardLast() {
+    return descendingIterator().next();
+  }
+
+  @Override
+  public NavigableSet<E> descendingSet() {
+    return delegate().descendingSet();
+  }
+
+  /**
+   * A sensible implementation of {@link NavigableSet#descendingSet} in terms of the other methods
+   * of {@link NavigableSet}, notably including {@link NavigableSet#descendingIterator}.
+   *
+   * <p>In many cases, you may wish to override {@link ForwardingNavigableSet#descendingSet} to
+   * forward to this implementation or a subclass thereof.
+   *
+   * @since 12.0
+   */
+  @Beta
+  protected class StandardDescendingSet extends Sets.DescendingSet<E> {
+    /** Constructor for use by subclasses. */
+    public StandardDescendingSet() {
+      super(ForwardingNavigableSet.this);
+    }
+  }
+
+  @Override
+  public Iterator<E> descendingIterator() {
+    return delegate().descendingIterator();
+  }
+
+  @Override
+  public NavigableSet<E> subSet(
+      E fromElement,
+      boolean fromInclusive,
+      E toElement,
+      boolean toInclusive) {
+    return delegate().subSet(fromElement, fromInclusive, toElement, toInclusive);
+  }
+
+  /**
+   * A sensible definition of {@link #subSet(Object, boolean, Object, boolean)} in terms of the
+   * {@code headSet} and {@code tailSet} methods. In many cases, you may wish to override
+   * {@link #subSet(Object, boolean, Object, boolean)} to forward to this implementation.
+   */
+  @Beta
+  protected NavigableSet<E> standardSubSet(
+      E fromElement,
+      boolean fromInclusive,
+      E toElement,
+      boolean toInclusive) {
+    return tailSet(fromElement, fromInclusive).headSet(toElement, toInclusive);
+  }
+
+  /**
+   * A sensible definition of {@link #subSet(Object, Object)} in terms of the
+   * {@link #subSet(Object, boolean, Object, boolean)} method. If you override
+   * {@link #subSet(Object, boolean, Object, boolean)}, you may wish to override
+   * {@link #subSet(Object, Object)} to forward to this implementation.
+   */
+  @Override
+  protected SortedSet<E> standardSubSet(E fromElement, E toElement) {
+    return subSet(fromElement, true, toElement, false);
+  }
+
+  @Override
+  public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+    return delegate().headSet(toElement, inclusive);
+  }
+
+  /**
+   * A sensible definition of {@link #headSet(Object)} in terms of the
+   * {@link #headSet(Object, boolean)} method. If you override
+   * {@link #headSet(Object, boolean)}, you may wish to override
+   * {@link #headSet(Object)} to forward to this implementation.
+   */
+  protected SortedSet<E> standardHeadSet(E toElement) {
+    return headSet(toElement, false);
+  }
+
+  @Override
+  public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+    return delegate().tailSet(fromElement, inclusive);
+  }
+
+  /**
+   * A sensible definition of {@link #tailSet(Object)} in terms of the
+   * {@link #tailSet(Object, boolean)} method. If you override
+   * {@link #tailSet(Object, boolean)}, you may wish to override
+   * {@link #tailSet(Object)} to forward to this implementation.
+   */
+  protected SortedSet<E> standardTailSet(E fromElement) {
+    return tailSet(fromElement, true);
+  }
+}
diff --git a/guava/src/com/google/common/collect/ForwardingSortedMap.java b/guava/src/com/google/common/collect/ForwardingSortedMap.java
index 55cd6ed..1235e56 100644
--- a/guava/src/com/google/common/collect/ForwardingSortedMap.java
+++ b/guava/src/com/google/common/collect/ForwardingSortedMap.java
@@ -22,7 +22,6 @@
 import com.google.common.annotations.GwtCompatible;
 
 import java.util.Comparator;
-import java.util.Iterator;
 import java.util.NoSuchElementException;
 import java.util.SortedMap;
 
@@ -144,43 +143,6 @@
   }
 
   /**
-   * A sensible definition of {@link #remove} in terms of the {@code
-   * iterator()} of the {@code entrySet()} of {@link #tailMap}. If you override
-   * {@link #tailMap}, you may wish to override {@link #remove} to forward
-   * to this implementation.
-   *
-   * @since 7.0
-   * @deprecated This implementation is extremely awkward, is rarely worthwhile,
-   * and has been discovered to interact badly with
-   * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6467933 in Java 6
-   * when used with certain null-friendly comparators.  It is scheduled for
-   * deletion in Guava 16.0.
-   */
-  @Deprecated
-  @Override @Beta protected V standardRemove(@Nullable Object key) {
-    try {
-      // any CCE will be caught
-      @SuppressWarnings("unchecked")
-      SortedMap<Object, V> self = (SortedMap<Object, V>) this;
-      Iterator<Entry<Object, V>> entryIterator =
-          self.tailMap(key).entrySet().iterator();
-      if (entryIterator.hasNext()) {
-        Entry<Object, V> ceilingEntry = entryIterator.next();
-        if (unsafeCompare(ceilingEntry.getKey(), key) == 0) {
-          V value = ceilingEntry.getValue();
-          entryIterator.remove();
-          return value;
-        }
-      }
-    } catch (ClassCastException e) {
-      return null;
-    } catch (NullPointerException e) {
-      return null;
-    }
-    return null;
-  }
-
-  /**
    * A sensible default implementation of {@link #subMap(Object, Object)} in
    * terms of {@link #headMap(Object)} and {@link #tailMap(Object)}. In some
    * situations, you may wish to override {@link #subMap(Object, Object)} to
diff --git a/guava/src/com/google/common/collect/ForwardingSortedMultiset.java b/guava/src/com/google/common/collect/ForwardingSortedMultiset.java
index f19b983..9ec79b8 100644
--- a/guava/src/com/google/common/collect/ForwardingSortedMultiset.java
+++ b/guava/src/com/google/common/collect/ForwardingSortedMultiset.java
@@ -19,7 +19,7 @@
 
 import java.util.Comparator;
 import java.util.Iterator;
-import java.util.SortedSet;
+import java.util.NavigableSet;
 
 /**
  * A sorted multiset which forwards all its method calls to another sorted multiset. Subclasses
@@ -50,8 +50,8 @@
   protected abstract SortedMultiset<E> delegate();
 
   @Override
-  public SortedSet<E> elementSet() {
-    return (SortedSet<E>) super.elementSet();
+  public NavigableSet<E> elementSet() {
+    return (NavigableSet<E>) super.elementSet();
   }
 
   /**
@@ -65,7 +65,7 @@
    * situations, you may wish to override {@link SortedMultiset#elementSet} to forward to this
    * implementation or a subclass thereof.
    */
-  protected class StandardElementSet extends SortedMultisets.ElementSet<E> {
+  protected class StandardElementSet extends SortedMultisets.NavigableElementSet<E> {
     /** Constructor for use by subclasses. */
     public StandardElementSet() {
       super(ForwardingSortedMultiset.this);
diff --git a/guava/src/com/google/common/collect/GenericMapMaker.java b/guava/src/com/google/common/collect/GenericMapMaker.java
index b7b5fe3..77ac673 100644
--- a/guava/src/com/google/common/collect/GenericMapMaker.java
+++ b/guava/src/com/google/common/collect/GenericMapMaker.java
@@ -21,7 +21,7 @@
 import com.google.common.annotations.GwtIncompatible;
 import com.google.common.base.Equivalence;
 import com.google.common.base.Function;
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
 import com.google.common.collect.MapMaker.RemovalListener;
 import com.google.common.collect.MapMaker.RemovalNotification;
 
@@ -42,12 +42,12 @@
  *     "Generic" equivalent; simple use {@code CacheBuilder} naturally. For general migration
  *     instructions, see the <a
  *     href="http://code.google.com/p/guava-libraries/wiki/MapMakerMigration">MapMaker Migration
- *     Guide</a>. This class is scheduled for removal in Guava 16.0.
+ *     Guide</a>.
  */
 @Beta
 @Deprecated
 @GwtCompatible(emulated = true)
-public abstract class GenericMapMaker<K0, V0> {
+abstract class GenericMapMaker<K0, V0> {
   @GwtIncompatible("To be supported")
   enum NullListener implements RemovalListener<Object, Object> {
     INSTANCE;
@@ -103,7 +103,7 @@
    *     com.google.common.cache.CacheBuilder}, with {@link #softValues} being replaced by {@link
    *     com.google.common.cache.CacheBuilder#softValues}. Note that {@code CacheBuilder} is simply
    *     an enhanced API for an implementation which was branched from {@code MapMaker}. <b>This
-   *     method is scheduled for deletion in August 2014.</b>
+   *     method is scheduled for removal in March 2015.</b>
    */
   @Deprecated
   @GwtIncompatible("java.lang.ref.SoftReference")
@@ -128,7 +128,7 @@
   @SuppressWarnings("unchecked") // safe covariant cast
   @GwtIncompatible("To be supported")
   <K extends K0, V extends V0> RemovalListener<K, V> getRemovalListener() {
-    return (RemovalListener<K, V>) Objects.firstNonNull(removalListener, NullListener.INSTANCE);
+    return (RemovalListener<K, V>) MoreObjects.firstNonNull(removalListener, NullListener.INSTANCE);
   }
 
   /**
@@ -146,6 +146,6 @@
    * See {@link MapMaker#makeComputingMap}.
    */
   @Deprecated
-  public abstract <K extends K0, V extends V0> ConcurrentMap<K, V> makeComputingMap(
+  abstract <K extends K0, V extends V0> ConcurrentMap<K, V> makeComputingMap(
       Function<? super K, ? extends V> computingFunction);
 }
diff --git a/guava/src/com/google/common/collect/ImmutableCollection.java b/guava/src/com/google/common/collect/ImmutableCollection.java
index 04ee241..1e9f629 100644
--- a/guava/src/com/google/common/collect/ImmutableCollection.java
+++ b/guava/src/com/google/common/collect/ImmutableCollection.java
@@ -61,7 +61,7 @@
     if (size == 0) {
       return ObjectArrays.EMPTY_ARRAY;
     }
-    Object[] result = new Object[size()];
+    Object[] result = new Object[size];
     copyIntoArray(result, 0);
     return result;
   }
diff --git a/guava/src/com/google/common/collect/ImmutableList.java b/guava/src/com/google/common/collect/ImmutableList.java
index 508eec7..501a41c 100644
--- a/guava/src/com/google/common/collect/ImmutableList.java
+++ b/guava/src/com/google/common/collect/ImmutableList.java
@@ -224,7 +224,7 @@
   public static <E> ImmutableList<E> copyOf(Iterable<? extends E> elements) {
     checkNotNull(elements); // TODO(kevinb): is this here only for GWT?
     return (elements instanceof Collection)
-      ? copyOf(Collections2.cast(elements))
+      ? copyOf((Collection<? extends E>) elements)
       : copyOf(elements.iterator());
   }
 
diff --git a/guava/src/com/google/common/collect/ImmutableRangeMap.java b/guava/src/com/google/common/collect/ImmutableRangeMap.java
new file mode 100644
index 0000000..49b3989
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableRangeMap.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2012 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.common.collect;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkElementIndex;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.collect.SortedLists.KeyAbsentBehavior;
+import com.google.common.collect.SortedLists.KeyPresentBehavior;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NoSuchElementException;
+
+import javax.annotation.Nullable;
+
+/**
+ * An immutable implementation of {@code RangeMap}, supporting all query operations efficiently.
+ *
+ * <p>Like all {@code RangeMap} implementations, this supports neither null keys nor null values.
+ *
+ * @author Louis Wasserman
+ * @since 14.0
+ */
+@Beta
+@GwtIncompatible("NavigableMap")
+public class ImmutableRangeMap<K extends Comparable<?>, V> implements RangeMap<K, V> {
+
+  private static final ImmutableRangeMap<Comparable<?>, Object> EMPTY =
+      new ImmutableRangeMap<Comparable<?>, Object>(
+          ImmutableList.<Range<Comparable<?>>>of(), ImmutableList.of());
+
+  /**
+   * Returns an empty immutable range map.
+   */
+  @SuppressWarnings("unchecked")
+  public static <K extends Comparable<?>, V> ImmutableRangeMap<K, V> of() {
+    return (ImmutableRangeMap<K, V>) EMPTY;
+  }
+
+  /**
+   * Returns an immutable range map mapping a single range to a single value.
+   */
+  public static <K extends Comparable<?>, V> ImmutableRangeMap<K, V> of(
+      Range<K> range, V value) {
+    return new ImmutableRangeMap<K, V>(ImmutableList.of(range), ImmutableList.of(value));
+  }
+
+  @SuppressWarnings("unchecked")
+  public static <K extends Comparable<?>, V> ImmutableRangeMap<K, V> copyOf(
+      RangeMap<K, ? extends V> rangeMap) {
+    if (rangeMap instanceof ImmutableRangeMap) {
+      return (ImmutableRangeMap<K, V>) rangeMap;
+    }
+    Map<Range<K>, ? extends V> map = rangeMap.asMapOfRanges();
+    ImmutableList.Builder<Range<K>> rangesBuilder = new ImmutableList.Builder<Range<K>>(map.size());
+    ImmutableList.Builder<V> valuesBuilder = new ImmutableList.Builder<V>(map.size());
+    for (Entry<Range<K>, ? extends V> entry : map.entrySet()) {
+      rangesBuilder.add(entry.getKey());
+      valuesBuilder.add(entry.getValue());
+    }
+    return new ImmutableRangeMap<K, V>(rangesBuilder.build(), valuesBuilder.build());
+  }
+
+  /**
+   * Returns a new builder for an immutable range map.
+   */
+  public static <K extends Comparable<?>, V> Builder<K, V> builder() {
+    return new Builder<K, V>();
+  }
+
+  /**
+   * A builder for immutable range maps. Overlapping ranges are prohibited.
+   */
+  public static final class Builder<K extends Comparable<?>, V> {
+    private final RangeSet<K> keyRanges;
+    private final RangeMap<K, V> rangeMap;
+
+    public Builder() {
+      this.keyRanges = TreeRangeSet.create();
+      this.rangeMap = TreeRangeMap.create();
+    }
+
+    /**
+     * Associates the specified range with the specified value.
+     *
+     * @throws IllegalArgumentException if {@code range} overlaps with any other ranges inserted
+     *         into this builder, or if {@code range} is empty
+     */
+    public Builder<K, V> put(Range<K> range, V value) {
+      checkNotNull(range);
+      checkNotNull(value);
+      checkArgument(!range.isEmpty(), "Range must not be empty, but was %s", range);
+      if (!keyRanges.complement().encloses(range)) {
+        // it's an error case; we can afford an expensive lookup
+        for (Entry<Range<K>, V> entry : rangeMap.asMapOfRanges().entrySet()) {
+          Range<K> key = entry.getKey();
+          if (key.isConnected(range) && !key.intersection(range).isEmpty()) {
+            throw new IllegalArgumentException(
+                "Overlapping ranges: range " + range + " overlaps with entry " + entry);
+          }
+        }
+      }
+      keyRanges.add(range);
+      rangeMap.put(range, value);
+      return this;
+    }
+
+    /**
+     * Copies all associations from the specified range map into this builder.
+     *
+     * @throws IllegalArgumentException if any of the ranges in {@code rangeMap} overlap with ranges
+     *         already in this builder
+     */
+    public Builder<K, V> putAll(RangeMap<K, ? extends V> rangeMap) {
+      for (Entry<Range<K>, ? extends V> entry : rangeMap.asMapOfRanges().entrySet()) {
+        put(entry.getKey(), entry.getValue());
+      }
+      return this;
+    }
+
+    /**
+     * Returns an {@code ImmutableRangeMap} containing the associations previously added to this
+     * builder.
+     */
+    public ImmutableRangeMap<K, V> build() {
+      Map<Range<K>, V> map = rangeMap.asMapOfRanges();
+      ImmutableList.Builder<Range<K>> rangesBuilder =
+          new ImmutableList.Builder<Range<K>>(map.size());
+      ImmutableList.Builder<V> valuesBuilder = new ImmutableList.Builder<V>(map.size());
+      for (Entry<Range<K>, V> entry : map.entrySet()) {
+        rangesBuilder.add(entry.getKey());
+        valuesBuilder.add(entry.getValue());
+      }
+      return new ImmutableRangeMap<K, V>(rangesBuilder.build(), valuesBuilder.build());
+    }
+  }
+
+  private final ImmutableList<Range<K>> ranges;
+  private final ImmutableList<V> values;
+
+  ImmutableRangeMap(ImmutableList<Range<K>> ranges, ImmutableList<V> values) {
+    this.ranges = ranges;
+    this.values = values;
+  }
+
+  @Override
+  @Nullable
+  public V get(K key) {
+    int index = SortedLists.binarySearch(ranges, Range.<K>lowerBoundFn(),
+        Cut.belowValue(key), KeyPresentBehavior.ANY_PRESENT, KeyAbsentBehavior.NEXT_LOWER);
+    if (index == -1) {
+      return null;
+    } else {
+      Range<K> range = ranges.get(index);
+      return range.contains(key) ? values.get(index) : null;
+    }
+  }
+
+  @Override
+  @Nullable
+  public Map.Entry<Range<K>, V> getEntry(K key) {
+    int index = SortedLists.binarySearch(ranges, Range.<K>lowerBoundFn(),
+        Cut.belowValue(key), KeyPresentBehavior.ANY_PRESENT, KeyAbsentBehavior.NEXT_LOWER);
+    if (index == -1) {
+      return null;
+    } else {
+      Range<K> range = ranges.get(index);
+      return range.contains(key) ? Maps.immutableEntry(range, values.get(index)) : null;
+    }
+  }
+
+  @Override
+  public Range<K> span() {
+    if (ranges.isEmpty()) {
+      throw new NoSuchElementException();
+    }
+    Range<K> firstRange = ranges.get(0);
+    Range<K> lastRange = ranges.get(ranges.size() - 1);
+    return Range.create(firstRange.lowerBound, lastRange.upperBound);
+  }
+
+  @Override
+  public void put(Range<K> range, V value) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public void putAll(RangeMap<K, V> rangeMap) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public void clear() {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public void remove(Range<K> range) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public ImmutableMap<Range<K>, V> asMapOfRanges() {
+    if (ranges.isEmpty()) {
+      return ImmutableMap.of();
+    }
+    RegularImmutableSortedSet<Range<K>> rangeSet =
+        new RegularImmutableSortedSet<Range<K>>(ranges, Range.RANGE_LEX_ORDERING);
+    return new RegularImmutableSortedMap<Range<K>, V>(rangeSet, values);
+  }
+  
+  @Override
+  public ImmutableRangeMap<K, V> subRangeMap(final Range<K> range) {
+    if (checkNotNull(range).isEmpty()) {
+      return ImmutableRangeMap.of();
+    } else if (ranges.isEmpty() || range.encloses(span())) {
+      return this;
+    }
+    int lowerIndex = SortedLists.binarySearch(
+        ranges, Range.<K>upperBoundFn(), range.lowerBound,
+        KeyPresentBehavior.FIRST_AFTER, KeyAbsentBehavior.NEXT_HIGHER);
+    int upperIndex = SortedLists.binarySearch(ranges, 
+        Range.<K>lowerBoundFn(), range.upperBound,
+        KeyPresentBehavior.ANY_PRESENT, KeyAbsentBehavior.NEXT_HIGHER);
+    if (lowerIndex >= upperIndex) {
+      return ImmutableRangeMap.of();
+    }
+    final int off = lowerIndex;
+    final int len = upperIndex - lowerIndex;
+    ImmutableList<Range<K>> subRanges = new ImmutableList<Range<K>>() {
+      @Override
+      public int size() {
+        return len;
+      }
+
+      @Override
+      public Range<K> get(int index) {
+        checkElementIndex(index, len);
+        if (index == 0 || index == len - 1) {
+          return ranges.get(index + off).intersection(range);
+        } else {
+          return ranges.get(index + off);
+        }
+      }
+
+      @Override
+      boolean isPartialView() {
+        return true;
+      }
+    };
+    final ImmutableRangeMap<K, V> outer = this;
+    return new ImmutableRangeMap<K, V>(
+        subRanges, values.subList(lowerIndex, upperIndex)) {
+          @Override
+          public ImmutableRangeMap<K, V> subRangeMap(Range<K> subRange) {
+            if (range.isConnected(subRange)) {
+              return outer.subRangeMap(subRange.intersection(range));
+            } else {
+              return ImmutableRangeMap.of();
+            }
+          }
+    };
+  }
+
+  @Override
+  public int hashCode() {
+    return asMapOfRanges().hashCode();
+  }
+
+  @Override
+  public boolean equals(@Nullable Object o) {
+    if (o instanceof RangeMap) {
+      RangeMap<?, ?> rangeMap = (RangeMap<?, ?>) o;
+      return asMapOfRanges().equals(rangeMap.asMapOfRanges());
+    }
+    return false;
+  }
+
+  @Override
+  public String toString() {
+    return asMapOfRanges().toString();
+  }
+}
diff --git a/guava/src/com/google/common/collect/ImmutableRangeSet.java b/guava/src/com/google/common/collect/ImmutableRangeSet.java
new file mode 100644
index 0000000..9e72b97
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableRangeSet.java
@@ -0,0 +1,614 @@
+/*
+ * Copyright (C) 2012 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.common.collect;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkElementIndex;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.SortedLists.KeyAbsentBehavior.NEXT_LOWER;
+import static com.google.common.collect.SortedLists.KeyPresentBehavior.ANY_PRESENT;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.collect.SortedLists.KeyAbsentBehavior;
+import com.google.common.collect.SortedLists.KeyPresentBehavior;
+import com.google.common.primitives.Ints;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * An efficient immutable implementation of a {@link RangeSet}.
+ *
+ * @author Louis Wasserman
+ * @since 14.0
+ */
+@Beta
+public final class ImmutableRangeSet<C extends Comparable> extends AbstractRangeSet<C>
+    implements Serializable {
+
+  private static final ImmutableRangeSet<Comparable<?>> EMPTY =
+      new ImmutableRangeSet<Comparable<?>>(ImmutableList.<Range<Comparable<?>>>of());
+
+  private static final ImmutableRangeSet<Comparable<?>> ALL =
+      new ImmutableRangeSet<Comparable<?>>(ImmutableList.of(Range.<Comparable<?>>all()));
+
+  /**
+   * Returns an empty immutable range set.
+   */
+  @SuppressWarnings("unchecked")
+  public static <C extends Comparable> ImmutableRangeSet<C> of() {
+    return (ImmutableRangeSet<C>) EMPTY;
+  }
+
+  /**
+   * Returns an immutable range set containing the single range {@link Range#all()}.
+   */
+  @SuppressWarnings("unchecked")
+  static <C extends Comparable> ImmutableRangeSet<C> all() {
+    return (ImmutableRangeSet<C>) ALL;
+  }
+
+  /**
+   * Returns an immutable range set containing the specified single range. If {@link Range#isEmpty()
+   * range.isEmpty()}, this is equivalent to {@link ImmutableRangeSet#of()}.
+   */
+  public static <C extends Comparable> ImmutableRangeSet<C> of(Range<C> range) {
+    checkNotNull(range);
+    if (range.isEmpty()) {
+      return of();
+    } else if (range.equals(Range.all())) {
+      return all();
+    } else {
+      return new ImmutableRangeSet<C>(ImmutableList.of(range));
+    }
+  }
+
+  /**
+   * Returns an immutable copy of the specified {@code RangeSet}.
+   */
+  public static <C extends Comparable> ImmutableRangeSet<C> copyOf(RangeSet<C> rangeSet) {
+    checkNotNull(rangeSet);
+    if (rangeSet.isEmpty()) {
+      return of();
+    } else if (rangeSet.encloses(Range.<C>all())) {
+      return all();
+    }
+
+    if (rangeSet instanceof ImmutableRangeSet) {
+      ImmutableRangeSet<C> immutableRangeSet = (ImmutableRangeSet<C>) rangeSet;
+      if (!immutableRangeSet.isPartialView()) {
+        return immutableRangeSet;
+      }
+    }
+    return new ImmutableRangeSet<C>(ImmutableList.copyOf(rangeSet.asRanges()));
+  }
+
+  ImmutableRangeSet(ImmutableList<Range<C>> ranges) {
+    this.ranges = ranges;
+  }
+
+  private ImmutableRangeSet(ImmutableList<Range<C>> ranges, ImmutableRangeSet<C> complement) {
+    this.ranges = ranges;
+    this.complement = complement;
+  }
+
+  private transient final ImmutableList<Range<C>> ranges;
+
+  @Override
+  public boolean encloses(Range<C> otherRange) {
+    int index = SortedLists.binarySearch(ranges,
+        Range.<C>lowerBoundFn(),
+        otherRange.lowerBound,
+        Ordering.natural(),
+        ANY_PRESENT,
+        NEXT_LOWER);
+    return index != -1 && ranges.get(index).encloses(otherRange);
+  }
+
+  @Override
+  public Range<C> rangeContaining(C value) {
+    int index = SortedLists.binarySearch(ranges,
+        Range.<C>lowerBoundFn(),
+        Cut.belowValue(value),
+        Ordering.natural(),
+        ANY_PRESENT,
+        NEXT_LOWER);
+    if (index != -1) {
+      Range<C> range = ranges.get(index);
+      return range.contains(value) ? range : null;
+    }
+    return null;
+  }
+
+  @Override
+  public Range<C> span() {
+    if (ranges.isEmpty()) {
+      throw new NoSuchElementException();
+    }
+    return Range.create(
+        ranges.get(0).lowerBound,
+        ranges.get(ranges.size() - 1).upperBound);
+  }
+
+  @Override
+  public boolean isEmpty() {
+    return ranges.isEmpty();
+  }
+
+  @Override
+  public void add(Range<C> range) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public void addAll(RangeSet<C> other) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public void remove(Range<C> range) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public void removeAll(RangeSet<C> other) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public ImmutableSet<Range<C>> asRanges() {
+    if (ranges.isEmpty()) {
+      return ImmutableSet.of();
+    }
+    return new RegularImmutableSortedSet<Range<C>>(ranges, Range.RANGE_LEX_ORDERING);
+  }
+
+  private transient ImmutableRangeSet<C> complement;
+
+  private final class ComplementRanges extends ImmutableList<Range<C>> {
+    // True if the "positive" range set is empty or bounded below.
+    private final boolean positiveBoundedBelow;
+
+    // True if the "positive" range set is empty or bounded above.
+    private final boolean positiveBoundedAbove;
+
+    private final int size;
+
+    ComplementRanges() {
+      this.positiveBoundedBelow = ranges.get(0).hasLowerBound();
+      this.positiveBoundedAbove = Iterables.getLast(ranges).hasUpperBound();
+
+      int size = ranges.size() - 1;
+      if (positiveBoundedBelow) {
+        size++;
+      }
+      if (positiveBoundedAbove) {
+        size++;
+      }
+      this.size = size;
+    }
+
+    @Override
+    public int size() {
+      return size;
+    }
+
+    @Override
+    public Range<C> get(int index) {
+      checkElementIndex(index, size);
+
+      Cut<C> lowerBound;
+      if (positiveBoundedBelow) {
+        lowerBound = (index == 0) ? Cut.<C>belowAll() : ranges.get(index - 1).upperBound;
+      } else {
+        lowerBound = ranges.get(index).upperBound;
+      }
+
+      Cut<C> upperBound;
+      if (positiveBoundedAbove && index == size - 1) {
+        upperBound = Cut.<C>aboveAll();
+      } else {
+        upperBound = ranges.get(index + (positiveBoundedBelow ? 0 : 1)).lowerBound;
+      }
+
+      return Range.create(lowerBound, upperBound);
+    }
+
+    @Override
+    boolean isPartialView() {
+      return true;
+    }
+  }
+
+  @Override
+  public ImmutableRangeSet<C> complement() {
+    ImmutableRangeSet<C> result = complement;
+    if (result != null) {
+      return result;
+    } else if (ranges.isEmpty()) {
+      return complement = all();
+    } else if (ranges.size() == 1 && ranges.get(0).equals(Range.all())) {
+      return complement = of();
+    } else {
+      ImmutableList<Range<C>> complementRanges = new ComplementRanges();
+      result = complement = new ImmutableRangeSet<C>(complementRanges, this);
+    }
+    return result;
+  }
+
+  /**
+   * Returns a list containing the nonempty intersections of {@code range}
+   * with the ranges in this range set.
+   */
+  private ImmutableList<Range<C>> intersectRanges(final Range<C> range) {
+    if (ranges.isEmpty() || range.isEmpty()) {
+      return ImmutableList.of();
+    } else if (range.encloses(span())) {
+      return ranges;
+    }
+
+    final int fromIndex;
+    if (range.hasLowerBound()) {
+      fromIndex = SortedLists.binarySearch(
+          ranges, Range.<C>upperBoundFn(), range.lowerBound, KeyPresentBehavior.FIRST_AFTER,
+          KeyAbsentBehavior.NEXT_HIGHER);
+    } else {
+      fromIndex = 0;
+    }
+
+    int toIndex;
+    if (range.hasUpperBound()) {
+      toIndex = SortedLists.binarySearch(
+          ranges, Range.<C>lowerBoundFn(), range.upperBound, KeyPresentBehavior.FIRST_PRESENT,
+          KeyAbsentBehavior.NEXT_HIGHER);
+    } else {
+      toIndex = ranges.size();
+    }
+    final int length = toIndex - fromIndex;
+    if (length == 0) {
+      return ImmutableList.of();
+    } else {
+      return new ImmutableList<Range<C>>() {
+        @Override
+        public int size() {
+          return length;
+        }
+
+        @Override
+        public Range<C> get(int index) {
+          checkElementIndex(index, length);
+          if (index == 0 || index == length - 1) {
+            return ranges.get(index + fromIndex).intersection(range);
+          } else {
+            return ranges.get(index + fromIndex);
+          }
+        }
+
+        @Override
+        boolean isPartialView() {
+          return true;
+        }
+      };
+    }
+  }
+  
+  /**
+   * Returns a view of the intersection of this range set with the given range.
+   */
+  @Override
+  public ImmutableRangeSet<C> subRangeSet(Range<C> range) {
+    if (!isEmpty()) {
+      Range<C> span = span();
+      if (range.encloses(span)) {
+        return this;
+      } else if (range.isConnected(span)) {
+        return new ImmutableRangeSet<C>(intersectRanges(range));
+      }
+    }
+    return of();
+  }
+
+  /**
+   * Returns an {@link ImmutableSortedSet} containing the same values in the given domain
+   * {@linkplain RangeSet#contains contained} by this range set.
+   *
+   * <p><b>Note:</b> {@code a.asSet(d).equals(b.asSet(d))} does not imply {@code a.equals(b)}! For
+   * example, {@code a} and {@code b} could be {@code [2..4]} and {@code (1..5)}, or the empty
+   * ranges {@code [3..3)} and {@code [4..4)}.
+   *
+   * <p><b>Warning:</b> Be extremely careful what you do with the {@code asSet} view of a large
+   * range set (such as {@code ImmutableRangeSet.of(Range.greaterThan(0))}). Certain operations on
+   * such a set can be performed efficiently, but others (such as {@link Set#hashCode} or
+   * {@link Collections#frequency}) can cause major performance problems.
+   *
+   * <p>The returned set's {@link Object#toString} method returns a short-hand form of the set's
+   * contents, such as {@code "[1..100]}"}.
+   *
+   * @throws IllegalArgumentException if neither this range nor the domain has a lower bound, or if
+   *         neither has an upper bound
+   */
+  public ImmutableSortedSet<C> asSet(DiscreteDomain<C> domain) {
+    checkNotNull(domain);
+    if (isEmpty()) {
+      return ImmutableSortedSet.of();
+    }
+    Range<C> span = span().canonical(domain);
+    if (!span.hasLowerBound()) {
+      // according to the spec of canonical, neither this ImmutableRangeSet nor
+      // the range have a lower bound
+      throw new IllegalArgumentException(
+          "Neither the DiscreteDomain nor this range set are bounded below");
+    } else if (!span.hasUpperBound()) {
+      try {
+        domain.maxValue();
+      } catch (NoSuchElementException e) {
+        throw new IllegalArgumentException(
+            "Neither the DiscreteDomain nor this range set are bounded above");
+      }
+    }
+
+    return new AsSet(domain);
+  }
+
+  private final class AsSet extends ImmutableSortedSet<C> {
+    private final DiscreteDomain<C> domain;
+
+    AsSet(DiscreteDomain<C> domain) {
+      super(Ordering.natural());
+      this.domain = domain;
+    }
+
+    private transient Integer size;
+
+    @Override
+    public int size() {
+      // racy single-check idiom
+      Integer result = size;
+      if (result == null) {
+        long total = 0;
+        for (Range<C> range : ranges) {
+          total += ContiguousSet.create(range, domain).size();
+          if (total >= Integer.MAX_VALUE) {
+            break;
+          }
+        }
+        result = size = Ints.saturatedCast(total);
+      }
+      return result.intValue();
+    }
+
+    @Override
+    public UnmodifiableIterator<C> iterator() {
+      return new AbstractIterator<C>() {
+        final Iterator<Range<C>> rangeItr = ranges.iterator();
+        Iterator<C> elemItr = Iterators.emptyIterator();
+
+        @Override
+        protected C computeNext() {
+          while (!elemItr.hasNext()) {
+            if (rangeItr.hasNext()) {
+              elemItr = ContiguousSet.create(rangeItr.next(), domain).iterator();
+            } else {
+              return endOfData();
+            }
+          }
+          return elemItr.next();
+        }
+      };
+    }
+
+    @Override
+    @GwtIncompatible("NavigableSet")
+    public UnmodifiableIterator<C> descendingIterator() {
+      return new AbstractIterator<C>() {
+        final Iterator<Range<C>> rangeItr = ranges.reverse().iterator();
+        Iterator<C> elemItr = Iterators.emptyIterator();
+
+        @Override
+        protected C computeNext() {
+          while (!elemItr.hasNext()) {
+            if (rangeItr.hasNext()) {
+              elemItr = ContiguousSet.create(rangeItr.next(), domain).descendingIterator();
+            } else {
+              return endOfData();
+            }
+          }
+          return elemItr.next();
+        }
+      };
+    }
+
+    ImmutableSortedSet<C> subSet(Range<C> range) {
+      return subRangeSet(range).asSet(domain);
+    }
+
+    @Override
+    ImmutableSortedSet<C> headSetImpl(C toElement, boolean inclusive) {
+      return subSet(Range.upTo(toElement, BoundType.forBoolean(inclusive)));
+    }
+
+    @Override
+    ImmutableSortedSet<C> subSetImpl(
+        C fromElement, boolean fromInclusive, C toElement, boolean toInclusive) {
+      if (!fromInclusive && !toInclusive && Range.compareOrThrow(fromElement, toElement) == 0) {
+        return ImmutableSortedSet.of();
+      }
+      return subSet(Range.range(
+          fromElement, BoundType.forBoolean(fromInclusive),
+          toElement, BoundType.forBoolean(toInclusive)));
+    }
+
+    @Override
+    ImmutableSortedSet<C> tailSetImpl(C fromElement, boolean inclusive) {
+      return subSet(Range.downTo(fromElement, BoundType.forBoolean(inclusive)));
+    }
+
+    @Override
+    public boolean contains(@Nullable Object o) {
+      if (o == null) {
+        return false;
+      }
+      try {
+        @SuppressWarnings("unchecked") // we catch CCE's
+        C c = (C) o;
+        return ImmutableRangeSet.this.contains(c);
+      } catch (ClassCastException e) {
+        return false;
+      }
+    }
+
+    @Override
+    int indexOf(Object target) {
+      if (contains(target)) {
+        @SuppressWarnings("unchecked") // if it's contained, it's definitely a C
+        C c = (C) target;
+        long total = 0;
+        for (Range<C> range : ranges) {
+          if (range.contains(c)) {
+            return Ints.saturatedCast(total + ContiguousSet.create(range, domain).indexOf(c));
+          } else {
+            total += ContiguousSet.create(range, domain).size();
+          }
+        }
+        throw new AssertionError("impossible");
+      }
+      return -1;
+    }
+
+    @Override
+    boolean isPartialView() {
+      return ranges.isPartialView();
+    }
+
+    @Override
+    public String toString() {
+      return ranges.toString();
+    }
+
+    @Override
+    Object writeReplace() {
+      return new AsSetSerializedForm<C>(ranges, domain);
+    }
+  }
+
+  private static class AsSetSerializedForm<C extends Comparable> implements Serializable {
+    private final ImmutableList<Range<C>> ranges;
+    private final DiscreteDomain<C> domain;
+
+    AsSetSerializedForm(ImmutableList<Range<C>> ranges, DiscreteDomain<C> domain) {
+      this.ranges = ranges;
+      this.domain = domain;
+    }
+
+    Object readResolve() {
+      return new ImmutableRangeSet<C>(ranges).asSet(domain);
+    }
+  }
+
+  /**
+   * Returns {@code true} if this immutable range set's implementation contains references to
+   * user-created objects that aren't accessible via this range set's methods. This is generally
+   * used to determine whether {@code copyOf} implementations should make an explicit copy to avoid
+   * memory leaks.
+   */
+  boolean isPartialView() {
+    return ranges.isPartialView();
+  }
+
+  /**
+   * Returns a new builder for an immutable range set.
+   */
+  public static <C extends Comparable<?>> Builder<C> builder() {
+    return new Builder<C>();
+  }
+
+  /**
+   * A builder for immutable range sets.
+   */
+  public static class Builder<C extends Comparable<?>> {
+    private final RangeSet<C> rangeSet;
+
+    public Builder() {
+      this.rangeSet = TreeRangeSet.create();
+    }
+
+    /**
+     * Add the specified range to this builder.  Adjacent/abutting ranges are permitted, but
+     * empty ranges, or ranges with nonempty overlap, are forbidden.
+     *
+     * @throws IllegalArgumentException if {@code range} is empty or has nonempty intersection with
+     *         any ranges already added to the builder
+     */
+    public Builder<C> add(Range<C> range) {
+      if (range.isEmpty()) {
+        throw new IllegalArgumentException("range must not be empty, but was " + range);
+      } else if (!rangeSet.complement().encloses(range)) {
+        for (Range<C> currentRange : rangeSet.asRanges()) {
+          checkArgument(
+              !currentRange.isConnected(range) || currentRange.intersection(range).isEmpty(),
+              "Ranges may not overlap, but received %s and %s", currentRange, range);
+        }
+        throw new AssertionError("should have thrown an IAE above");
+      }
+      rangeSet.add(range);
+      return this;
+    }
+
+    /**
+     * Add all ranges from the specified range set to this builder. Duplicate or connected ranges
+     * are permitted, and will be merged in the resulting immutable range set.
+     */
+    public Builder<C> addAll(RangeSet<C> ranges) {
+      for (Range<C> range : ranges.asRanges()) {
+        add(range);
+      }
+      return this;
+    }
+
+    /**
+     * Returns an {@code ImmutableRangeSet} containing the ranges added to this builder.
+     */
+    public ImmutableRangeSet<C> build() {
+      return copyOf(rangeSet);
+    }
+  }
+
+  private static final class SerializedForm<C extends Comparable> implements Serializable {
+    private final ImmutableList<Range<C>> ranges;
+
+    SerializedForm(ImmutableList<Range<C>> ranges) {
+      this.ranges = ranges;
+    }
+
+    Object readResolve() {
+      if (ranges.isEmpty()) {
+        return of();
+      } else if (ranges.equals(ImmutableList.of(Range.all()))) {
+        return all();
+      } else {
+        return new ImmutableRangeSet<C>(ranges);
+      }
+    }
+  }
+
+  Object writeReplace() {
+    return new SerializedForm<C>(ranges);
+  }
+}
diff --git a/guava/src/com/google/common/collect/ImmutableSet.java b/guava/src/com/google/common/collect/ImmutableSet.java
index 4343df8..c236182 100644
--- a/guava/src/com/google/common/collect/ImmutableSet.java
+++ b/guava/src/com/google/common/collect/ImmutableSet.java
@@ -298,7 +298,7 @@
    */
   public static <E> ImmutableSet<E> copyOf(Iterable<? extends E> elements) {
     return (elements instanceof Collection)
-        ? copyOf(Collections2.cast(elements))
+        ? copyOf((Collection<? extends E>) elements)
         : copyOf(elements.iterator());
   }
 
diff --git a/guava/src/com/google/common/collect/ImmutableSetMultimap.java b/guava/src/com/google/common/collect/ImmutableSetMultimap.java
index ca4ff5f..ce24af2 100644
--- a/guava/src/com/google/common/collect/ImmutableSetMultimap.java
+++ b/guava/src/com/google/common/collect/ImmutableSetMultimap.java
@@ -16,12 +16,12 @@
 
 package com.google.common.collect;
 
-import static com.google.common.base.Objects.firstNonNull;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static java.util.Arrays.asList;
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
+import com.google.common.base.MoreObjects;
 
 import java.io.IOException;
 import java.io.InvalidObjectException;
@@ -357,7 +357,7 @@
   @Override public ImmutableSet<V> get(@Nullable K key) {
     // This cast is safe as its type is known in constructor.
     ImmutableSet<V> set = (ImmutableSet<V>) map.get(key);
-    return firstNonNull(set, emptySet);
+    return MoreObjects.firstNonNull(set, emptySet);
   }
 
   private transient ImmutableSetMultimap<V, K> inverse;
diff --git a/guava/src/com/google/common/collect/ImmutableSortedMap.java b/guava/src/com/google/common/collect/ImmutableSortedMap.java
index 93b5a03..e796a5d 100644
--- a/guava/src/com/google/common/collect/ImmutableSortedMap.java
+++ b/guava/src/com/google/common/collect/ImmutableSortedMap.java
@@ -26,6 +26,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Map;
+import java.util.NavigableMap;
 import java.util.SortedMap;
 import java.util.TreeMap;
 
@@ -56,7 +57,7 @@
  */
 @GwtCompatible(serializable = true, emulated = true)
 public abstract class ImmutableSortedMap<K, V>
-    extends ImmutableSortedMapFauxverideShim<K, V> implements SortedMap<K, V> {
+    extends ImmutableSortedMapFauxverideShim<K, V> implements NavigableMap<K, V> {
   /*
    * TODO(kevinb): Confirm that ImmutableSortedMap is faster to construct and
    * uses less memory than TreeMap; then say so in the class Javadoc.
@@ -495,6 +496,7 @@
    *
    * @since 12.0
    */
+  @Override
   public abstract ImmutableSortedMap<K, V> headMap(K toKey, boolean inclusive);
 
   /**
@@ -530,6 +532,7 @@
    *
    * @since 12.0
    */
+  @Override
   public ImmutableSortedMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey,
       boolean toInclusive) {
     checkNotNull(fromKey);
@@ -567,44 +570,55 @@
    *
    * @since 12.0
    */
+  @Override
   public abstract ImmutableSortedMap<K, V> tailMap(K fromKey, boolean inclusive);
 
+  @Override
   public Entry<K, V> lowerEntry(K key) {
     return headMap(key, false).lastEntry();
   }
 
+  @Override
   public K lowerKey(K key) {
     return keyOrNull(lowerEntry(key));
   }
 
+  @Override
   public Entry<K, V> floorEntry(K key) {
     return headMap(key, true).lastEntry();
   }
 
+  @Override
   public K floorKey(K key) {
     return keyOrNull(floorEntry(key));
   }
 
+  @Override
   public Entry<K, V> ceilingEntry(K key) {
     return tailMap(key, true).firstEntry();
   }
 
+  @Override
   public K ceilingKey(K key) {
     return keyOrNull(ceilingEntry(key));
   }
 
+  @Override
   public Entry<K, V> higherEntry(K key) {
     return tailMap(key, false).firstEntry();
   }
 
+  @Override
   public K higherKey(K key) {
     return keyOrNull(higherEntry(key));
   }
 
+  @Override
   public Entry<K, V> firstEntry() {
     return isEmpty() ? null : entrySet().asList().get(0);
   }
 
+  @Override
   public Entry<K, V> lastEntry() {
     return isEmpty() ? null : entrySet().asList().get(size() - 1);
   }
@@ -616,6 +630,7 @@
    * @deprecated Unsupported operation.
    */
   @Deprecated
+  @Override
   public final Entry<K, V> pollFirstEntry() {
     throw new UnsupportedOperationException();
   }
@@ -627,12 +642,14 @@
    * @deprecated Unsupported operation.
    */
   @Deprecated
+  @Override
   public final Entry<K, V> pollLastEntry() {
     throw new UnsupportedOperationException();
   }
 
   private transient ImmutableSortedMap<K, V> descendingMap;
 
+  @Override
   public ImmutableSortedMap<K, V> descendingMap() {
     ImmutableSortedMap<K, V> result = descendingMap;
     if (result == null) {
@@ -643,10 +660,12 @@
 
   abstract ImmutableSortedMap<K, V> createDescendingMap();
 
+  @Override
   public ImmutableSortedSet<K> navigableKeySet() {
     return keySet();
   }
 
+  @Override
   public ImmutableSortedSet<K> descendingKeySet() {
     return keySet().descendingSet();
   }
diff --git a/guava/src/com/google/common/collect/ImmutableSortedSet.java b/guava/src/com/google/common/collect/ImmutableSortedSet.java
index e862ed6..c134890 100644
--- a/guava/src/com/google/common/collect/ImmutableSortedSet.java
+++ b/guava/src/com/google/common/collect/ImmutableSortedSet.java
@@ -31,6 +31,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
+import java.util.NavigableSet;
 import java.util.SortedSet;
 
 import javax.annotation.Nullable;
@@ -91,7 +92,7 @@
 @GwtCompatible(serializable = true, emulated = true)
 @SuppressWarnings("serial") // we're overriding default serialization
 public abstract class ImmutableSortedSet<E> extends ImmutableSortedSetFauxverideShim<E>
-    implements SortedSet<E>, SortedIterable<E> {
+    implements NavigableSet<E>, SortedIterable<E> {
 
   private static final Comparator<Comparable> NATURAL_ORDER =
       Ordering.natural();
@@ -619,6 +620,7 @@
    * @since 12.0
    */
   @GwtIncompatible("NavigableSet")
+  @Override
   public ImmutableSortedSet<E> headSet(E toElement, boolean inclusive) {
     return headSetImpl(checkNotNull(toElement), inclusive);
   }
@@ -645,6 +647,7 @@
    * @since 12.0
    */
   @GwtIncompatible("NavigableSet")
+  @Override
   public ImmutableSortedSet<E> subSet(
       E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
     checkNotNull(fromElement);
@@ -673,6 +676,7 @@
    * @since 12.0
    */
   @GwtIncompatible("NavigableSet")
+  @Override
   public ImmutableSortedSet<E> tailSet(E fromElement, boolean inclusive) {
     return tailSetImpl(checkNotNull(fromElement), inclusive);
   }
@@ -692,6 +696,7 @@
    * @since 12.0
    */
   @GwtIncompatible("NavigableSet")
+  @Override
   public E lower(E e) {
     return Iterators.getNext(headSet(e, false).descendingIterator(), null);
   }
@@ -700,6 +705,7 @@
    * @since 12.0
    */
   @GwtIncompatible("NavigableSet")
+  @Override
   public E floor(E e) {
     return Iterators.getNext(headSet(e, true).descendingIterator(), null);
   }
@@ -708,6 +714,7 @@
    * @since 12.0
    */
   @GwtIncompatible("NavigableSet")
+  @Override
   public E ceiling(E e) {
     return Iterables.getFirst(tailSet(e, true), null);
   }
@@ -716,6 +723,7 @@
    * @since 12.0
    */
   @GwtIncompatible("NavigableSet")
+  @Override
   public E higher(E e) {
     return Iterables.getFirst(tailSet(e, false), null);
   }
@@ -739,6 +747,7 @@
    */
   @Deprecated
   @GwtIncompatible("NavigableSet")
+  @Override
   public final E pollFirst() {
     throw new UnsupportedOperationException();
   }
@@ -752,6 +761,7 @@
    */
   @Deprecated
   @GwtIncompatible("NavigableSet")
+  @Override
   public final E pollLast() {
     throw new UnsupportedOperationException();
   }
@@ -763,6 +773,7 @@
    * @since 12.0
    */
   @GwtIncompatible("NavigableSet")
+  @Override
   public ImmutableSortedSet<E> descendingSet() {
     // racy single-check idiom
     ImmutableSortedSet<E> result = descendingSet;
@@ -782,6 +793,7 @@
    * @since 12.0
    */
   @GwtIncompatible("NavigableSet")
+  @Override
   public abstract UnmodifiableIterator<E> descendingIterator();
 
   /**
diff --git a/guava/src/com/google/common/collect/ImmutableTable.java b/guava/src/com/google/common/collect/ImmutableTable.java
index 7066348..3ed87be 100644
--- a/guava/src/com/google/common/collect/ImmutableTable.java
+++ b/guava/src/com/google/common/collect/ImmutableTable.java
@@ -19,7 +19,7 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
 
 import java.util.Comparator;
 import java.util.Iterator;
@@ -32,7 +32,7 @@
  * An immutable {@link Table} with reliable user-specified iteration order.
  * Does not permit null keys or values.
  *
- * <p><b>Note</b>: Although this class is not final, it cannot be subclassed as
+ * <p><b>Note:</b> Although this class is not final, it cannot be subclassed as
  * it has no public or protected constructors. Thus, instances of this class are
  * guaranteed to be immutable.
  *
@@ -281,7 +281,7 @@
    */
   @Override public ImmutableMap<R, V> column(C columnKey) {
     checkNotNull(columnKey);
-    return Objects.firstNonNull(
+    return MoreObjects.firstNonNull(
         (ImmutableMap<R, V>) columnMap().get(columnKey),
         ImmutableMap.<R, V>of());
   }
@@ -305,7 +305,7 @@
    */
   @Override public ImmutableMap<C, V> row(R rowKey) {
     checkNotNull(rowKey);
-    return Objects.firstNonNull(
+    return MoreObjects.firstNonNull(
         (ImmutableMap<C, V>) rowMap().get(rowKey),
         ImmutableMap.<C, V>of());
   }
diff --git a/guava/src/com/google/common/collect/Iterators.java b/guava/src/com/google/common/collect/Iterators.java
index 83e1704..229964b 100644
--- a/guava/src/com/google/common/collect/Iterators.java
+++ b/guava/src/com/google/common/collect/Iterators.java
@@ -102,7 +102,12 @@
    *
    * <p>The {@link Iterable} equivalent of this method is {@link
    * ImmutableSet#of()}.
+   *
+   * @deprecated Use {@code ImmutableSet.<T>of().iterator()} instead; or for
+   *     Java 7 or later, {@link Collections#emptyIterator}. This method is
+   *     scheduled for removal in May 2016.
    */
+  @Deprecated
   public static <T> UnmodifiableIterator<T> emptyIterator() {
     return emptyListIterator();
   }
diff --git a/guava/src/com/google/common/collect/Lists.java b/guava/src/com/google/common/collect/Lists.java
index 824dd2b..c77a5fc 100644
--- a/guava/src/com/google/common/collect/Lists.java
+++ b/guava/src/com/google/common/collect/Lists.java
@@ -72,12 +72,16 @@
   // ArrayList
 
   /**
-   * Creates a <i>mutable</i>, empty {@code ArrayList} instance.
+   * Creates a <i>mutable</i>, empty {@code ArrayList} instance (for Java 6 and
+   * earlier).
    *
    * <p><b>Note:</b> if mutability is not required, use {@link
    * ImmutableList#of()} instead.
    *
-   * @return a new, empty {@code ArrayList}
+   * <p><b>Note for Java 7 and later:</b> this method is now unnecessary and
+   * should be treated as deprecated. Instead, use the {@code ArrayList}
+   * {@linkplain ArrayList#ArrayList() constructor} directly, taking advantage
+   * of the new <a href="http://goo.gl/iz2Wi">"diamond" syntax</a>.
    */
   @GwtCompatible(serializable = true)
   public static <E> ArrayList<E> newArrayList() {
@@ -88,12 +92,18 @@
    * Creates a <i>mutable</i> {@code ArrayList} instance containing the given
    * elements.
    *
-   * <p><b>Note:</b> if mutability is not required and the elements are
-   * non-null, use an overload of {@link ImmutableList#of()} (for varargs) or
-   * {@link ImmutableList#copyOf(Object[])} (for an array) instead.
+   * <p><b>Note:</b> essentially the only reason to use this method is when you
+   * will need to add or remove elements later. Otherwise, for non-null elements
+   * use {@link ImmutableList#of()} (for varargs) or {@link
+   * ImmutableList#copyOf(Object[])} (for an array) instead. If any elements
+   * might be null, or you need support for {@link List#set(int, Object)}, use
+   * {@link Arrays#asList}.
    *
-   * @param elements the elements that the list should contain, in order
-   * @return a new {@code ArrayList} containing those elements
+   * <p>Note that even when you do need the ability to add or remove, this method
+   * provides only a tiny bit of syntactic sugar for {@code newArrayList(}{@link
+   * Arrays#asList asList}{@code (...))}, or for creating an empty list then
+   * calling {@link Collections#addAll}. This method is not actually very useful
+   * and will likely be deprecated in the future.
    */
   @GwtCompatible(serializable = true)
   public static <E> ArrayList<E> newArrayList(E... elements) {
@@ -114,13 +124,18 @@
 
   /**
    * Creates a <i>mutable</i> {@code ArrayList} instance containing the given
-   * elements.
+   * elements; a very thin shortcut for creating an empty list then calling
+   * {@link Iterables#addAll}.
    *
    * <p><b>Note:</b> if mutability is not required and the elements are
-   * non-null, use {@link ImmutableList#copyOf(Iterator)} instead.
+   * non-null, use {@link ImmutableList#copyOf(Iterable)} instead. (Or, change
+   * {@code elements} to be a {@link FluentIterable} and call
+   * {@code elements.toList()}.)
    *
-   * @param elements the elements that the list should contain, in order
-   * @return a new {@code ArrayList} containing those elements
+   * <p><b>Note for Java 7 and later:</b> if {@code elements} is a {@link
+   * Collection}, you don't need this method. Use the {@code ArrayList}
+   * {@linkplain ArrayList#ArrayList(Collection) constructor} directly, taking
+   * advantage of the new <a href="http://goo.gl/iz2Wi">"diamond" syntax</a>.
    */
   @GwtCompatible(serializable = true)
   public static <E> ArrayList<E> newArrayList(Iterable<? extends E> elements) {
@@ -133,13 +148,11 @@
 
   /**
    * Creates a <i>mutable</i> {@code ArrayList} instance containing the given
-   * elements.
+   * elements; a very thin shortcut for creating an empty list and then calling
+   * {@link Iterators#addAll}.
    *
    * <p><b>Note:</b> if mutability is not required and the elements are
    * non-null, use {@link ImmutableList#copyOf(Iterator)} instead.
-   *
-   * @param elements the elements that the list should contain, in order
-   * @return a new {@code ArrayList} containing those elements
    */
   @GwtCompatible(serializable = true)
   public static <E> ArrayList<E> newArrayList(Iterator<? extends E> elements) {
@@ -149,17 +162,15 @@
   }
 
   /**
-   * Creates an {@code ArrayList} instance backed by an array of the
-   * <i>exact</i> size specified; equivalent to
-   * {@link ArrayList#ArrayList(int)}.
+   * Creates an {@code ArrayList} instance backed by an array with the specified
+   * initial size; simply delegates to {@link ArrayList#ArrayList(int)}.
    *
-   * <p><b>Note:</b> if you know the exact size your list will be, consider
-   * using a fixed-size list ({@link Arrays#asList(Object[])}) or an {@link
-   * ImmutableList} instead of a growable {@link ArrayList}.
-   *
-   * <p><b>Note:</b> If you have only an <i>estimate</i> of the eventual size of
-   * the list, consider padding this estimate by a suitable amount, or simply
-   * use {@link #newArrayListWithExpectedSize(int)} instead.
+   * <p><b>Note for Java 7 and later:</b> this method is now unnecessary and
+   * should be treated as deprecated. Instead, use {@code new }{@link
+   * ArrayList#ArrayList(int) ArrayList}{@code <>(int)} directly, taking
+   * advantage of the new <a href="http://goo.gl/iz2Wi">"diamond" syntax</a>.
+   * (Unlike here, there is no risk of overload ambiguity, since the {@code
+   * ArrayList} constructors very wisely did not accept varargs.)
    *
    * @param initialArraySize the exact size of the initial backing array for
    *     the returned array list ({@code ArrayList} documentation calls this
@@ -176,13 +187,14 @@
   }
 
   /**
-   * Creates an {@code ArrayList} instance sized appropriately to hold an
-   * <i>estimated</i> number of elements without resizing. A small amount of
-   * padding is added in case the estimate is low.
+   * Creates an {@code ArrayList} instance to hold {@code estimatedSize}
+   * elements, <i>plus</i> an unspecified amount of padding; you almost
+   * certainly mean to call {@link #newArrayListWithCapacity} (see that method
+   * for further advice on usage).
    *
-   * <p><b>Note:</b> If you know the <i>exact</i> number of elements the list
-   * will hold, or prefer to calculate your own amount of padding, refer to
-   * {@link #newArrayListWithCapacity(int)}.
+   * <p><b>Note:</b> This method will soon be deprecated. Even in the rare case
+   * that you do want some amount of padding, it's best if you choose your
+   * desired amount explicitly.
    *
    * @param estimatedSize an estimate of the eventual {@link List#size()} of
    *     the new list
@@ -199,12 +211,21 @@
   // LinkedList
 
   /**
-   * Creates an empty {@code LinkedList} instance.
+   * Creates a <i>mutable</i>, empty {@code LinkedList} instance (for Java 6 and
+   * earlier).
    *
-   * <p><b>Note:</b> if you need an immutable empty {@link List}, use
-   * {@link ImmutableList#of()} instead.
+   * <p><b>Note:</b> if you won't be adding any elements to the list, use {@link
+   * ImmutableList#of()} instead.
    *
-   * @return a new, empty {@code LinkedList}
+   * <p><b>Performance note:</b> {@link ArrayList} and {@link
+   * java.util.ArrayDeque} consistently outperform {@code LinkedList} except in
+   * certain rare and specific situations. Unless you have spent a lot of time
+   * benchmarking your specific needs, use one of those instead.
+   *
+   * <p><b>Note for Java 7 and later:</b> this method is now unnecessary and
+   * should be treated as deprecated. Instead, use the {@code LinkedList}
+   * {@linkplain LinkedList#LinkedList() constructor} directly, taking advantage
+   * of the new <a href="http://goo.gl/iz2Wi">"diamond" syntax</a>.
    */
   @GwtCompatible(serializable = true)
   public static <E> LinkedList<E> newLinkedList() {
@@ -212,10 +233,24 @@
   }
 
   /**
-   * Creates a {@code LinkedList} instance containing the given elements.
+   * Creates a <i>mutable</i> {@code LinkedList} instance containing the given
+   * elements; a very thin shortcut for creating an empty list then calling
+   * {@link Iterables#addAll}.
    *
-   * @param elements the elements that the list should contain, in order
-   * @return a new {@code LinkedList} containing those elements
+   * <p><b>Note:</b> if mutability is not required and the elements are
+   * non-null, use {@link ImmutableList#copyOf(Iterable)} instead. (Or, change
+   * {@code elements} to be a {@link FluentIterable} and call
+   * {@code elements.toList()}.)
+   *
+   * <p><b>Performance note:</b> {@link ArrayList} and {@link
+   * java.util.ArrayDeque} consistently outperform {@code LinkedList} except in
+   * certain rare and specific situations. Unless you have spent a lot of time
+   * benchmarking your specific needs, use one of those instead.
+   *
+   * <p><b>Note for Java 7 and later:</b> if {@code elements} is a {@link
+   * Collection}, you don't need this method. Use the {@code LinkedList}
+   * {@linkplain LinkedList#LinkedList(Collection) constructor} directly, taking
+   * advantage of the new <a href="http://goo.gl/iz2Wi">"diamond" syntax</a>.
    */
   @GwtCompatible(serializable = true)
   public static <E> LinkedList<E> newLinkedList(
diff --git a/guava/src/com/google/common/collect/MapMaker.java b/guava/src/com/google/common/collect/MapMaker.java
index 82a66f9..0a71ad0 100644
--- a/guava/src/com/google/common/collect/MapMaker.java
+++ b/guava/src/com/google/common/collect/MapMaker.java
@@ -14,7 +14,6 @@
 
 package com.google.common.collect;
 
-import static com.google.common.base.Objects.firstNonNull;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
@@ -25,7 +24,7 @@
 import com.google.common.base.Ascii;
 import com.google.common.base.Equivalence;
 import com.google.common.base.Function;
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Throwables;
 import com.google.common.base.Ticker;
 import com.google.common.collect.MapMakerInternalMap.Strength;
@@ -153,7 +152,7 @@
   }
 
   Equivalence<Object> getKeyEquivalence() {
-    return firstNonNull(keyEquivalence, getKeyStrength().defaultEquivalence());
+    return MoreObjects.firstNonNull(keyEquivalence, getKeyStrength().defaultEquivalence());
   }
 
   /**
@@ -278,7 +277,7 @@
   }
 
   Strength getKeyStrength() {
-    return firstNonNull(keyStrength, Strength.STRONG);
+    return MoreObjects.firstNonNull(keyStrength, Strength.STRONG);
   }
 
   /**
@@ -327,7 +326,7 @@
    *     com.google.common.cache.CacheBuilder}, with {@link #softValues} being replaced by {@link
    *     com.google.common.cache.CacheBuilder#softValues}. Note that {@code CacheBuilder} is simply
    *     an enhanced API for an implementation which was branched from {@code MapMaker}. <b>This
-   *     method is scheduled for deletion in September 2014.</b>
+   *     method is scheduled for removal in March 2015.</b>
    */
   @Deprecated
   @GwtIncompatible("java.lang.ref.SoftReference")
@@ -347,7 +346,7 @@
   }
 
   Strength getValueStrength() {
-    return firstNonNull(valueStrength, Strength.STRONG);
+    return MoreObjects.firstNonNull(valueStrength, Strength.STRONG);
   }
 
   /**
@@ -445,7 +444,7 @@
   }
 
   Ticker getTicker() {
-    return firstNonNull(ticker, Ticker.systemTicker());
+    return MoreObjects.firstNonNull(ticker, Ticker.systemTicker());
   }
 
   /**
@@ -578,11 +577,10 @@
    *     by {@link com.google.common.cache.CacheBuilder#build}. See the
    *     <a href="http://code.google.com/p/guava-libraries/wiki/MapMakerMigration">MapMaker
    *     Migration Guide</a> for more details.
-   *     <b>This method is scheduled for deletion after upgrading Android to Guava 17.0.</b>
    */
   @Deprecated
   @Override
-  public <K, V> ConcurrentMap<K, V> makeComputingMap(
+  <K, V> ConcurrentMap<K, V> makeComputingMap(
       Function<? super K, ? extends V> computingFunction) {
     return (nullRemovalCause == null)
         ? new MapMaker.ComputingMapAdapter<K, V>(this, computingFunction)
@@ -595,7 +593,7 @@
    */
   @Override
   public String toString() {
-    Objects.ToStringHelper s = Objects.toStringHelper(this);
+    MoreObjects.ToStringHelper s = MoreObjects.toStringHelper(this);
     if (initialCapacity != UNSET_INT) {
       s.add("initialCapacity", initialCapacity);
     }
diff --git a/guava/src/com/google/common/collect/MapMakerInternalMap.java b/guava/src/com/google/common/collect/MapMakerInternalMap.java
index 494f7af..4232679 100644
--- a/guava/src/com/google/common/collect/MapMakerInternalMap.java
+++ b/guava/src/com/google/common/collect/MapMakerInternalMap.java
@@ -496,13 +496,13 @@
      * @param original the entry to copy
      * @param newNext entry in the same bucket
      */
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     <K, V> ReferenceEntry<K, V> copyEntry(
         Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
       return newEntry(segment, original.getKey(), original.getHash(), newNext);
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     <K, V> void copyExpirableEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newEntry) {
       // TODO(fry): when we link values instead of entries this method can go
       // away, as can connectExpirables, nullifyExpirable.
@@ -514,7 +514,7 @@
       nullifyExpirable(original);
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     <K, V> void copyEvictableEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newEntry) {
       // TODO(fry): when we link values instead of entries this method can go
       // away, as can connectEvictables, nullifyEvictable.
@@ -1028,7 +1028,7 @@
       this.time = time;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> nextExpirable = nullEntry();
 
     @Override
@@ -1041,7 +1041,7 @@
       this.nextExpirable = next;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> previousExpirable = nullEntry();
 
     @Override
@@ -1063,7 +1063,7 @@
 
     // The code below is exactly the same for each evictable entry type.
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> nextEvictable = nullEntry();
 
     @Override
@@ -1076,7 +1076,7 @@
       this.nextEvictable = next;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> previousEvictable = nullEntry();
 
     @Override
@@ -1110,7 +1110,7 @@
       this.time = time;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> nextExpirable = nullEntry();
 
     @Override
@@ -1123,7 +1123,7 @@
       this.nextExpirable = next;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> previousExpirable = nullEntry();
 
     @Override
@@ -1138,7 +1138,7 @@
 
     // The code below is exactly the same for each evictable entry type.
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> nextEvictable = nullEntry();
 
     @Override
@@ -1151,7 +1151,7 @@
       this.nextEvictable = next;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> previousEvictable = nullEntry();
 
     @Override
@@ -1283,7 +1283,7 @@
       this.time = time;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> nextExpirable = nullEntry();
 
     @Override
@@ -1296,7 +1296,7 @@
       this.nextExpirable = next;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> previousExpirable = nullEntry();
 
     @Override
@@ -1319,7 +1319,7 @@
 
     // The code below is exactly the same for each evictable entry type.
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> nextEvictable = nullEntry();
 
     @Override
@@ -1332,7 +1332,7 @@
       this.nextEvictable = next;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> previousEvictable = nullEntry();
 
     @Override
@@ -1367,7 +1367,7 @@
       this.time = time;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> nextExpirable = nullEntry();
 
     @Override
@@ -1380,7 +1380,7 @@
       this.nextExpirable = next;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> previousExpirable = nullEntry();
 
     @Override
@@ -1395,7 +1395,7 @@
 
     // The code below is exactly the same for each evictable entry type.
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> nextEvictable = nullEntry();
 
     @Override
@@ -1408,7 +1408,7 @@
       this.nextEvictable = next;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> previousEvictable = nullEntry();
 
     @Override
@@ -1541,7 +1541,7 @@
       this.time = time;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> nextExpirable = nullEntry();
 
     @Override
@@ -1554,7 +1554,7 @@
       this.nextExpirable = next;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> previousExpirable = nullEntry();
 
     @Override
@@ -1577,7 +1577,7 @@
 
     // The code below is exactly the same for each evictable entry type.
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> nextEvictable = nullEntry();
 
     @Override
@@ -1590,7 +1590,7 @@
       this.nextEvictable = next;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> previousEvictable = nullEntry();
 
     @Override
@@ -1625,7 +1625,7 @@
       this.time = time;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> nextExpirable = nullEntry();
 
     @Override
@@ -1638,7 +1638,7 @@
       this.nextExpirable = next;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> previousExpirable = nullEntry();
 
     @Override
@@ -1653,7 +1653,7 @@
 
     // The code below is exactly the same for each evictable entry type.
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> nextEvictable = nullEntry();
 
     @Override
@@ -1666,7 +1666,7 @@
       this.nextEvictable = next;
     }
 
-    @GuardedBy("Segment.this")
+    // Guarded By Segment.this
     ReferenceEntry<K, V> previousEvictable = nullEntry();
 
     @Override
@@ -1821,7 +1821,7 @@
   /**
    * This method is a convenience for testing. Code should call {@link Segment#newEntry} directly.
    */
-  @GuardedBy("Segment.this")
+  // Guarded By Segment.this
   @VisibleForTesting
   ReferenceEntry<K, V> newEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) {
     return segmentFor(hash).newEntry(key, hash, next);
@@ -1830,7 +1830,7 @@
   /**
    * This method is a convenience for testing. Code should call {@link Segment#copyEntry} directly.
    */
-  @GuardedBy("Segment.this")
+  // Guarded By Segment.this
   @VisibleForTesting
   ReferenceEntry<K, V> copyEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
     int hash = original.getHash();
@@ -1840,7 +1840,7 @@
   /**
    * This method is a convenience for testing. Code should call {@link Segment#setValue} instead.
    */
-  @GuardedBy("Segment.this")
+  // Guarded By Segment.this
   @VisibleForTesting
   ValueReference<K, V> newValueReference(ReferenceEntry<K, V> entry, V value) {
     int hash = entry.getHash();
@@ -1924,13 +1924,13 @@
     return now - entry.getExpirationTime() > 0;
   }
 
-  @GuardedBy("Segment.this")
+  // Guarded By Segment.this
   static <K, V> void connectExpirables(ReferenceEntry<K, V> previous, ReferenceEntry<K, V> next) {
     previous.setNextExpirable(next);
     next.setPreviousExpirable(previous);
   }
 
-  @GuardedBy("Segment.this")
+  // Guarded By Segment.this
   static <K, V> void nullifyExpirable(ReferenceEntry<K, V> nulled) {
     ReferenceEntry<K, V> nullEntry = nullEntry();
     nulled.setNextExpirable(nullEntry);
@@ -1956,13 +1956,13 @@
   }
 
   /** Links the evitables together. */
-  @GuardedBy("Segment.this")
+  // Guarded By Segment.this
   static <K, V> void connectEvictables(ReferenceEntry<K, V> previous, ReferenceEntry<K, V> next) {
     previous.setNextEvictable(next);
     next.setPreviousEvictable(previous);
   }
 
-  @GuardedBy("Segment.this")
+  // Guarded By Segment.this
   static <K, V> void nullifyEvictable(ReferenceEntry<K, V> nulled) {
     ReferenceEntry<K, V> nullEntry = nullEntry();
     nulled.setNextEvictable(nullEntry);
diff --git a/guava/src/com/google/common/collect/Maps.java b/guava/src/com/google/common/collect/Maps.java
index e56ff61..e8ab643 100644
--- a/guava/src/com/google/common/collect/Maps.java
+++ b/guava/src/com/google/common/collect/Maps.java
@@ -52,6 +52,8 @@
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
 import java.util.Properties;
 import java.util.Set;
 import java.util.SortedMap;
@@ -657,7 +659,7 @@
    * Removal operations write through to the backing set.  The returned map
    * does not support put operations.
    *
-   * <p><b>Warning</b>: If the function rejects {@code null}, caution is
+   * <p><b>Warning:</b> If the function rejects {@code null}, caution is
    * required to make sure the set does not contain {@code null}, because the
    * view cannot stop {@code null} from being added to the set.
    *
@@ -693,7 +695,7 @@
    * Removal operations write through to the backing set.  The returned map does
    * not support put operations.
    *
-   * <p><b>Warning</b>: If the function rejects {@code null}, caution is
+   * <p><b>Warning:</b> If the function rejects {@code null}, caution is
    * required to make sure the set does not contain {@code null}, because the
    * view cannot stop {@code null} from being added to the set.
    *
@@ -716,6 +718,39 @@
     return new SortedAsMapView<K, V>(set, function);
   }
 
+  /**
+   * Returns a view of the navigable set as a map, mapping keys from the set
+   * according to the specified function.
+   *
+   * <p>Specifically, for each {@code k} in the backing set, the returned map
+   * has an entry mapping {@code k} to {@code function.apply(k)}. The {@code
+   * keySet}, {@code values}, and {@code entrySet} views of the returned map
+   * iterate in the same order as the backing set.
+   *
+   * <p>Modifications to the backing set are read through to the returned map.
+   * The returned map supports removal operations if the backing set does.
+   * Removal operations write through to the backing set.  The returned map
+   * does not support put operations.
+   *
+   * <p><b>Warning:</b> If the function rejects {@code null}, caution is
+   * required to make sure the set does not contain {@code null}, because the
+   * view cannot stop {@code null} from being added to the set.
+   *
+   * <p><b>Warning:</b> This method assumes that for any instance {@code k} of
+   * key type {@code K}, {@code k.equals(k2)} implies that {@code k2} is also
+   * of type {@code K}. Using a key type for which this may not hold, such as
+   * {@code ArrayList}, may risk a {@code ClassCastException} when calling
+   * methods on the resulting map view.
+   *
+   * @since 14.0
+   */
+  @Beta
+  @GwtIncompatible("NavigableMap")
+  public static <K, V> NavigableMap<K, V> asMap(
+      NavigableSet<K> set, Function<? super K, V> function) {
+    return new NavigableAsMapView<K, V>(set, function);
+  }
+
   private static class AsMapView<K, V> extends ImprovedAbstractMap<K, V> {
 
     private final Set<K> set;
@@ -851,6 +886,86 @@
     }
   }
 
+  @GwtIncompatible("NavigableMap")
+  private static final class NavigableAsMapView<K, V>
+      extends AbstractNavigableMap<K, V> {
+    /*
+     * Using AbstractNavigableMap is simpler than extending SortedAsMapView and rewriting all the
+     * NavigableMap methods.
+     */
+
+    private final NavigableSet<K> set;
+    private final Function<? super K, V> function;
+
+    NavigableAsMapView(NavigableSet<K> ks, Function<? super K, V> vFunction) {
+      this.set = checkNotNull(ks);
+      this.function = checkNotNull(vFunction);
+    }
+
+    @Override
+    public NavigableMap<K, V> subMap(
+        K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+      return asMap(set.subSet(fromKey, fromInclusive, toKey, toInclusive), function);
+    }
+
+    @Override
+    public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
+      return asMap(set.headSet(toKey, inclusive), function);
+    }
+
+    @Override
+    public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
+      return asMap(set.tailSet(fromKey, inclusive), function);
+    }
+
+    @Override
+    public Comparator<? super K> comparator() {
+      return set.comparator();
+    }
+
+    @Override
+    @Nullable
+    public V get(@Nullable Object key) {
+      if (Collections2.safeContains(set, key)) {
+        @SuppressWarnings("unchecked") // unsafe, but Javadoc warns about it
+        K k = (K) key;
+        return function.apply(k);
+      } else {
+        return null;
+      }
+    }
+
+    @Override
+    public void clear() {
+      set.clear();
+    }
+
+    @Override
+    Iterator<Entry<K, V>> entryIterator() {
+      return asMapEntryIterator(set, function);
+    }
+
+    @Override
+    Iterator<Entry<K, V>> descendingEntryIterator() {
+      return descendingMap().entrySet().iterator();
+    }
+
+    @Override
+    public NavigableSet<K> navigableKeySet() {
+      return removeOnlyNavigableSet(set);
+    }
+
+    @Override
+    public int size() {
+      return set.size();
+    }
+
+    @Override
+    public NavigableMap<K, V> descendingMap() {
+      return asMap(set.descendingSet(), function);
+    }
+  }
+
   private static <E> Set<E> removeOnlySet(final Set<E> set) {
     return new ForwardingSet<E>() {
       @Override
@@ -902,7 +1017,65 @@
         return removeOnlySortedSet(super.tailSet(fromElement));
       }
     };
-  } 
+  }
+
+  @GwtIncompatible("NavigableSet")
+  private static <E> NavigableSet<E> removeOnlyNavigableSet(final NavigableSet<E> set) {
+    return new ForwardingNavigableSet<E>() {
+      @Override
+      protected NavigableSet<E> delegate() {
+        return set;
+      }
+
+      @Override
+      public boolean add(E element) {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public boolean addAll(Collection<? extends E> es) {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public SortedSet<E> headSet(E toElement) {
+        return removeOnlySortedSet(super.headSet(toElement));
+      }
+
+      @Override
+      public SortedSet<E> subSet(E fromElement, E toElement) {
+        return removeOnlySortedSet(
+            super.subSet(fromElement, toElement));
+      }
+
+      @Override
+      public SortedSet<E> tailSet(E fromElement) {
+        return removeOnlySortedSet(super.tailSet(fromElement));
+      }
+
+      @Override
+      public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+        return removeOnlyNavigableSet(super.headSet(toElement, inclusive));
+      }
+
+      @Override
+      public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+        return removeOnlyNavigableSet(super.tailSet(fromElement, inclusive));
+      }
+
+      @Override
+      public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
+          E toElement, boolean toInclusive) {
+        return removeOnlyNavigableSet(super.subSet(
+            fromElement, fromInclusive, toElement, toInclusive));
+      }
+
+      @Override
+      public NavigableSet<E> descendingSet() {
+        return removeOnlyNavigableSet(super.descendingSet());
+      }
+    };
+  }
 
   /**
    * Returns an immutable map whose keys are the distinct elements of {@code
@@ -1366,6 +1539,53 @@
   }
 
   /**
+   * Returns a view of a navigable map where each value is transformed by a
+   * function. All other properties of the map, such as iteration order, are
+   * left intact.  For example, the code: <pre>   {@code
+   *
+   *   NavigableMap<String, Integer> map = Maps.newTreeMap();
+   *   map.put("a", 4);
+   *   map.put("b", 9);
+   *   Function<Integer, Double> sqrt =
+   *       new Function<Integer, Double>() {
+   *         public Double apply(Integer in) {
+   *           return Math.sqrt((int) in);
+   *         }
+   *       };
+   *   NavigableMap<String, Double> transformed =
+   *        Maps.transformNavigableValues(map, sqrt);
+   *   System.out.println(transformed);}</pre>
+   *
+   * ... prints {@code {a=2.0, b=3.0}}.
+   *
+   * Changes in the underlying map are reflected in this view.
+   * Conversely, this view supports removal operations, and these are reflected
+   * in the underlying map.
+   *
+   * <p>It's acceptable for the underlying map to contain null keys, and even
+   * null values provided that the function is capable of accepting null input.
+   * The transformed map might contain null values, if the function sometimes
+   * gives a null result.
+   *
+   * <p>The returned map is not thread-safe or serializable, even if the
+   * underlying map is.
+   *
+   * <p>The function is applied lazily, invoked when needed. This is necessary
+   * for the returned map to be a view, but it means that the function will be
+   * applied many times for bulk operations like {@link Map#containsValue} and
+   * {@code Map.toString()}. For this to perform well, {@code function} should
+   * be fast. To avoid lazy evaluation when the returned map doesn't need to be
+   * a view, copy the returned map into a new map of your choosing.
+   *
+   * @since 13.0
+   */
+  @GwtIncompatible("NavigableMap")
+  public static <K, V1, V2> NavigableMap<K, V2> transformValues(
+      NavigableMap<K, V1> fromMap, Function<? super V1, V2> function) {
+    return transformEntries(fromMap, asEntryTransformer(function));
+  }
+
+  /**
    * Returns a view of a map whose values are derived from the original map's
    * entries. In contrast to {@link #transformValues}, this method's
    * entry-transformation logic may depend on the key as well as the value.
@@ -1483,6 +1703,66 @@
     return Platform.mapsTransformEntriesSortedMap(fromMap, transformer);
   }
 
+  /**
+   * Returns a view of a navigable map whose values are derived from the
+   * original navigable map's entries. In contrast to {@link
+   * #transformValues}, this method's entry-transformation logic may
+   * depend on the key as well as the value.
+   *
+   * <p>All other properties of the transformed map, such as iteration order,
+   * are left intact. For example, the code: <pre>   {@code
+   *
+   *   NavigableMap<String, Boolean> options = Maps.newTreeMap();
+   *   options.put("verbose", false);
+   *   options.put("sort", true);
+   *   EntryTransformer<String, Boolean, String> flagPrefixer =
+   *       new EntryTransformer<String, Boolean, String>() {
+   *         public String transformEntry(String key, Boolean value) {
+   *           return value ? key : ("yes" + key);
+   *         }
+   *       };
+   *   NavigableMap<String, String> transformed =
+   *       LabsMaps.transformNavigableEntries(options, flagPrefixer);
+   *   System.out.println(transformed);}</pre>
+   *
+   * ... prints {@code {sort=yessort, verbose=verbose}}.
+   *
+   * <p>Changes in the underlying map are reflected in this view.
+   * Conversely, this view supports removal operations, and these are reflected
+   * in the underlying map.
+   *
+   * <p>It's acceptable for the underlying map to contain null keys and null
+   * values provided that the transformer is capable of accepting null inputs.
+   * The transformed map might contain null values if the transformer sometimes
+   * gives a null result.
+   *
+   * <p>The returned map is not thread-safe or serializable, even if the
+   * underlying map is.
+   *
+   * <p>The transformer is applied lazily, invoked when needed. This is
+   * necessary for the returned map to be a view, but it means that the
+   * transformer will be applied many times for bulk operations like {@link
+   * Map#containsValue} and {@link Object#toString}. For this to perform well,
+   * {@code transformer} should be fast. To avoid lazy evaluation when the
+   * returned map doesn't need to be a view, copy the returned map into a new
+   * map of your choosing.
+   *
+   * <p><b>Warning:</b> This method assumes that for any instance {@code k} of
+   * {@code EntryTransformer} key type {@code K}, {@code k.equals(k2)} implies
+   * that {@code k2} is also of type {@code K}. Using an {@code
+   * EntryTransformer} key type for which this may not hold, such as {@code
+   * ArrayList}, may risk a {@code ClassCastException} when calling methods on
+   * the transformed map.
+   *
+   * @since 13.0
+   */
+  @GwtIncompatible("NavigableMap")
+  public static <K, V1, V2> NavigableMap<K, V2> transformEntries(
+      final NavigableMap<K, V1> fromMap,
+      EntryTransformer<? super K, ? super V1, V2> transformer) {
+    return new TransformedEntriesNavigableMap<K, V1, V2>(fromMap, transformer);
+  }
+
   static <K, V1, V2> SortedMap<K, V2> transformEntriesIgnoreNavigable(
       SortedMap<K, V1> fromMap,
       EntryTransformer<? super K, ? super V1, V2> transformer) {
@@ -1691,6 +1971,114 @@
     }
   }
 
+  @GwtIncompatible("NavigableMap")
+  private static class TransformedEntriesNavigableMap<K, V1, V2>
+      extends TransformedEntriesSortedMap<K, V1, V2>
+      implements NavigableMap<K, V2> {
+
+    TransformedEntriesNavigableMap(NavigableMap<K, V1> fromMap,
+        EntryTransformer<? super K, ? super V1, V2> transformer) {
+      super(fromMap, transformer);
+    }
+
+    @Override public Entry<K, V2> ceilingEntry(K key) {
+      return transformEntry(fromMap().ceilingEntry(key));
+    }
+
+    @Override public K ceilingKey(K key) {
+      return fromMap().ceilingKey(key);
+    }
+
+    @Override public NavigableSet<K> descendingKeySet() {
+      return fromMap().descendingKeySet();
+    }
+
+    @Override public NavigableMap<K, V2> descendingMap() {
+      return transformEntries(fromMap().descendingMap(), transformer);
+    }
+
+    @Override public Entry<K, V2> firstEntry() {
+      return transformEntry(fromMap().firstEntry());
+    }
+    @Override public Entry<K, V2> floorEntry(K key) {
+      return transformEntry(fromMap().floorEntry(key));
+    }
+
+    @Override public K floorKey(K key) {
+      return fromMap().floorKey(key);
+    }
+
+    @Override public NavigableMap<K, V2> headMap(K toKey) {
+      return headMap(toKey, false);
+    }
+
+    @Override public NavigableMap<K, V2> headMap(K toKey, boolean inclusive) {
+      return transformEntries(
+          fromMap().headMap(toKey, inclusive), transformer);
+    }
+
+    @Override public Entry<K, V2> higherEntry(K key) {
+      return transformEntry(fromMap().higherEntry(key));
+    }
+
+    @Override public K higherKey(K key) {
+      return fromMap().higherKey(key);
+    }
+
+    @Override public Entry<K, V2> lastEntry() {
+      return transformEntry(fromMap().lastEntry());
+    }
+
+    @Override public Entry<K, V2> lowerEntry(K key) {
+      return transformEntry(fromMap().lowerEntry(key));
+    }
+
+    @Override public K lowerKey(K key) {
+      return fromMap().lowerKey(key);
+    }
+
+    @Override public NavigableSet<K> navigableKeySet() {
+      return fromMap().navigableKeySet();
+    }
+
+    @Override public Entry<K, V2> pollFirstEntry() {
+      return transformEntry(fromMap().pollFirstEntry());
+    }
+
+    @Override public Entry<K, V2> pollLastEntry() {
+      return transformEntry(fromMap().pollLastEntry());
+    }
+
+    @Override public NavigableMap<K, V2> subMap(
+        K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+      return transformEntries(
+          fromMap().subMap(fromKey, fromInclusive, toKey, toInclusive),
+          transformer);
+    }
+
+    @Override public NavigableMap<K, V2> subMap(K fromKey, K toKey) {
+      return subMap(fromKey, true, toKey, false);
+    }
+
+    @Override public NavigableMap<K, V2> tailMap(K fromKey) {
+      return tailMap(fromKey, true);
+    }
+
+    @Override public NavigableMap<K, V2> tailMap(K fromKey, boolean inclusive) {
+      return transformEntries(
+          fromMap().tailMap(fromKey, inclusive), transformer);
+    }
+
+    @Nullable
+    private Entry<K, V2> transformEntry(@Nullable Entry<K, V1> entry) {
+      return (entry == null) ? null : Maps.transformEntry(transformer, entry);
+    }
+
+    @Override protected NavigableMap<K, V1> fromMap() {
+      return (NavigableMap<K, V1>) super.fromMap();
+    }
+  }
+
   static <K> Predicate<Entry<K, ?>> keyPredicateOnEntries(Predicate<? super K> keyPredicate) {
     return compose(keyPredicate, Maps.<K>keyFunction());
   }
@@ -1780,6 +2168,44 @@
   }
 
   /**
+   * Returns a navigable map containing the mappings in {@code unfiltered} whose
+   * keys satisfy a predicate. The returned map is a live view of {@code
+   * unfiltered}; changes to one affect the other.
+   *
+   * <p>The resulting map's {@code keySet()}, {@code entrySet()}, and {@code
+   * values()} views have iterators that don't support {@code remove()}, but all
+   * other methods are supported by the map and its views. When given a key that
+   * doesn't satisfy the predicate, the map's {@code put()} and {@code putAll()}
+   * methods throw an {@link IllegalArgumentException}.
+   *
+   * <p>When methods such as {@code removeAll()} and {@code clear()} are called
+   * on the filtered map or its views, only mappings whose keys satisfy the
+   * filter will be removed from the underlying map.
+   *
+   * <p>The returned map isn't threadsafe or serializable, even if {@code
+   * unfiltered} is.
+   *
+   * <p>Many of the filtered map's methods, such as {@code size()},
+   * iterate across every key/value mapping in the underlying map and determine
+   * which satisfy the filter. When a live view is <i>not</i> needed, it may be
+   * faster to copy the filtered map and use the copy.
+   *
+   * <p><b>Warning:</b> {@code keyPredicate} must be <i>consistent with
+   * equals</i>, as documented at {@link Predicate#apply}. Do not provide a
+   * predicate such as {@code Predicates.instanceOf(ArrayList.class)}, which is
+   * inconsistent with equals.
+   *
+   * @since 14.0
+   */
+  @GwtIncompatible("NavigableMap")
+  public static <K, V> NavigableMap<K, V> filterKeys(
+      NavigableMap<K, V> unfiltered, final Predicate<? super K> keyPredicate) {
+    // TODO(user): Return a subclass of Maps.FilteredKeyMap for slightly better
+    // performance.
+    return filterEntries(unfiltered, Maps.<K>keyPredicateOnEntries(keyPredicate));
+  }
+
+  /**
    * Returns a bimap containing the mappings in {@code unfiltered} whose keys satisfy a predicate.
    * The returned bimap is a live view of {@code unfiltered}; changes to one affect the other.
    *
@@ -1886,6 +2312,43 @@
   }
 
   /**
+   * Returns a navigable map containing the mappings in {@code unfiltered} whose
+   * values satisfy a predicate. The returned map is a live view of {@code
+   * unfiltered}; changes to one affect the other.
+   *
+   * <p>The resulting map's {@code keySet()}, {@code entrySet()}, and {@code
+   * values()} views have iterators that don't support {@code remove()}, but all
+   * other methods are supported by the map and its views. When given a value
+   * that doesn't satisfy the predicate, the map's {@code put()}, {@code
+   * putAll()}, and {@link Entry#setValue} methods throw an {@link
+   * IllegalArgumentException}.
+   *
+   * <p>When methods such as {@code removeAll()} and {@code clear()} are called
+   * on the filtered map or its views, only mappings whose values satisfy the
+   * filter will be removed from the underlying map.
+   *
+   * <p>The returned map isn't threadsafe or serializable, even if {@code
+   * unfiltered} is.
+   *
+   * <p>Many of the filtered map's methods, such as {@code size()},
+   * iterate across every key/value mapping in the underlying map and determine
+   * which satisfy the filter. When a live view is <i>not</i> needed, it may be
+   * faster to copy the filtered map and use the copy.
+   *
+   * <p><b>Warning:</b> {@code valuePredicate} must be <i>consistent with
+   * equals</i>, as documented at {@link Predicate#apply}. Do not provide a
+   * predicate such as {@code Predicates.instanceOf(ArrayList.class)}, which is
+   * inconsistent with equals.
+   *
+   * @since 14.0
+   */
+  @GwtIncompatible("NavigableMap")
+  public static <K, V> NavigableMap<K, V> filterValues(
+      NavigableMap<K, V> unfiltered, final Predicate<? super V> valuePredicate) {
+    return filterEntries(unfiltered, Maps.<V>valuePredicateOnEntries(valuePredicate));
+  }
+
+  /**
    * Returns a bimap containing the mappings in {@code unfiltered} whose values satisfy a
    * predicate. The returned bimap is a live view of {@code unfiltered}; changes to one affect the
    * other.
@@ -2007,6 +2470,47 @@
   }
 
   /**
+   * Returns a sorted map containing the mappings in {@code unfiltered} that
+   * satisfy a predicate. The returned map is a live view of {@code unfiltered};
+   * changes to one affect the other.
+   *
+   * <p>The resulting map's {@code keySet()}, {@code entrySet()}, and {@code
+   * values()} views have iterators that don't support {@code remove()}, but all
+   * other methods are supported by the map and its views. When given a
+   * key/value pair that doesn't satisfy the predicate, the map's {@code put()}
+   * and {@code putAll()} methods throw an {@link IllegalArgumentException}.
+   * Similarly, the map's entries have a {@link Entry#setValue} method that
+   * throws an {@link IllegalArgumentException} when the existing key and the
+   * provided value don't satisfy the predicate.
+   *
+   * <p>When methods such as {@code removeAll()} and {@code clear()} are called
+   * on the filtered map or its views, only mappings that satisfy the filter
+   * will be removed from the underlying map.
+   *
+   * <p>The returned map isn't threadsafe or serializable, even if {@code
+   * unfiltered} is.
+   *
+   * <p>Many of the filtered map's methods, such as {@code size()},
+   * iterate across every key/value mapping in the underlying map and determine
+   * which satisfy the filter. When a live view is <i>not</i> needed, it may be
+   * faster to copy the filtered map and use the copy.
+   *
+   * <p><b>Warning:</b> {@code entryPredicate} must be <i>consistent with
+   * equals</i>, as documented at {@link Predicate#apply}.
+   *
+   * @since 14.0
+   */
+  @GwtIncompatible("NavigableMap")
+  public static <K, V> NavigableMap<K, V> filterEntries(
+      NavigableMap<K, V> unfiltered,
+      Predicate<? super Entry<K, V>> entryPredicate) {
+    checkNotNull(entryPredicate);
+    return (unfiltered instanceof FilteredEntryNavigableMap)
+        ? filterFiltered((FilteredEntryNavigableMap<K, V>) unfiltered, entryPredicate)
+        : new FilteredEntryNavigableMap<K, V>(checkNotNull(unfiltered), entryPredicate);
+  }
+
+  /**
    * Returns a bimap containing the mappings in {@code unfiltered} that satisfy a predicate. The
    * returned bimap is a live view of {@code unfiltered}; changes to one affect the other.
    *
@@ -2365,6 +2869,154 @@
 
   /**
    * Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when
+   * filtering a filtered navigable map.
+   */
+  @GwtIncompatible("NavigableMap")
+  private static <K, V> NavigableMap<K, V> filterFiltered(
+      FilteredEntryNavigableMap<K, V> map,
+      Predicate<? super Entry<K, V>> entryPredicate) {
+    Predicate<Entry<K, V>> predicate
+        = Predicates.and(map.entryPredicate, entryPredicate);
+    return new FilteredEntryNavigableMap<K, V>(map.unfiltered, predicate);
+  }
+
+  @GwtIncompatible("NavigableMap")
+  private static class FilteredEntryNavigableMap<K, V> extends AbstractNavigableMap<K, V> {
+    /*
+     * It's less code to extend AbstractNavigableMap and forward the filtering logic to
+     * FilteredEntryMap than to extend FilteredEntrySortedMap and reimplement all the NavigableMap
+     * methods.
+     */
+
+    private final NavigableMap<K, V> unfiltered;
+    private final Predicate<? super Entry<K, V>> entryPredicate;
+    private final Map<K, V> filteredDelegate;
+
+    FilteredEntryNavigableMap(
+        NavigableMap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) {
+      this.unfiltered = checkNotNull(unfiltered);
+      this.entryPredicate = entryPredicate;
+      this.filteredDelegate = new FilteredEntryMap<K, V>(unfiltered, entryPredicate);
+    }
+
+    @Override
+    public Comparator<? super K> comparator() {
+      return unfiltered.comparator();
+    }
+
+    @Override
+    public NavigableSet<K> navigableKeySet() {
+      return new Maps.NavigableKeySet<K, V>(this) {
+        @Override
+        public boolean removeAll(Collection<?> c) {
+          return Iterators.removeIf(unfiltered.entrySet().iterator(),
+              Predicates.<Entry<K, V>>and(entryPredicate, Maps.<K>keyPredicateOnEntries(in(c))));
+        }
+
+        @Override
+        public boolean retainAll(Collection<?> c) {
+          return Iterators.removeIf(unfiltered.entrySet().iterator(), Predicates.<Entry<K, V>>and(
+              entryPredicate, Maps.<K>keyPredicateOnEntries(not(in(c)))));
+        }
+      };
+    }
+
+    @Override
+    public Collection<V> values() {
+      return new FilteredMapValues<K, V>(this, unfiltered, entryPredicate);
+    }
+
+    @Override
+    Iterator<Entry<K, V>> entryIterator() {
+      return Iterators.filter(unfiltered.entrySet().iterator(), entryPredicate);
+    }
+
+    @Override
+    Iterator<Entry<K, V>> descendingEntryIterator() {
+      return Iterators.filter(unfiltered.descendingMap().entrySet().iterator(), entryPredicate);
+    }
+
+    @Override
+    public int size() {
+      return filteredDelegate.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+      return !Iterables.any(unfiltered.entrySet(), entryPredicate);
+    }
+
+    @Override
+    @Nullable
+    public V get(@Nullable Object key) {
+      return filteredDelegate.get(key);
+    }
+
+    @Override
+    public boolean containsKey(@Nullable Object key) {
+      return filteredDelegate.containsKey(key);
+    }
+
+    @Override
+    public V put(K key, V value) {
+      return filteredDelegate.put(key, value);
+    }
+
+    @Override
+    public V remove(@Nullable Object key) {
+      return filteredDelegate.remove(key);
+    }
+
+    @Override
+    public void putAll(Map<? extends K, ? extends V> m) {
+      filteredDelegate.putAll(m);
+    }
+
+    @Override
+    public void clear() {
+      filteredDelegate.clear();
+    }
+
+    @Override
+    public Set<Entry<K, V>> entrySet() {
+      return filteredDelegate.entrySet();
+    }
+
+    @Override
+    public Entry<K, V> pollFirstEntry() {
+      return Iterables.removeFirstMatching(unfiltered.entrySet(), entryPredicate);
+    }
+
+    @Override
+    public Entry<K, V> pollLastEntry() {
+      return Iterables.removeFirstMatching(unfiltered.descendingMap().entrySet(), entryPredicate);
+    }
+
+    @Override
+    public NavigableMap<K, V> descendingMap() {
+      return filterEntries(unfiltered.descendingMap(), entryPredicate);
+    }
+
+    @Override
+    public NavigableMap<K, V> subMap(
+        K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+      return filterEntries(
+          unfiltered.subMap(fromKey, fromInclusive, toKey, toInclusive), entryPredicate);
+    }
+
+    @Override
+    public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
+      return filterEntries(unfiltered.headMap(toKey, inclusive), entryPredicate);
+    }
+
+    @Override
+    public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
+      return filterEntries(unfiltered.tailMap(fromKey, inclusive), entryPredicate);
+    }
+  }
+
+  /**
+   * Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when
    * filtering a filtered map.
    */
   private static <K, V> BiMap<K, V> filterFiltered(
@@ -2423,10 +3075,228 @@
     }
   }
 
+  /**
+   * Returns an unmodifiable view of the specified navigable map. Query operations on the returned
+   * map read through to the specified map, and attempts to modify the returned map, whether direct
+   * or via its views, result in an {@code UnsupportedOperationException}.
+   *
+   * <p>The returned navigable map will be serializable if the specified navigable map is
+   * serializable.
+   *
+   * @param map the navigable map for which an unmodifiable view is to be returned
+   * @return an unmodifiable view of the specified navigable map
+   * @since 12.0
+   */
+  @GwtIncompatible("NavigableMap")
+  public static <K, V> NavigableMap<K, V> unmodifiableNavigableMap(NavigableMap<K, V> map) {
+    checkNotNull(map);
+    if (map instanceof UnmodifiableNavigableMap) {
+      return map;
+    } else {
+      return new UnmodifiableNavigableMap<K, V>(map);
+    }
+  }
+
   @Nullable private static <K, V> Entry<K, V> unmodifiableOrNull(@Nullable Entry<K, V> entry) {
     return (entry == null) ? null : Maps.unmodifiableEntry(entry);
   }
 
+  @GwtIncompatible("NavigableMap")
+  static class UnmodifiableNavigableMap<K, V>
+      extends ForwardingSortedMap<K, V> implements NavigableMap<K, V>, Serializable {
+    private final NavigableMap<K, V> delegate;
+
+    UnmodifiableNavigableMap(NavigableMap<K, V> delegate) {
+      this.delegate = delegate;
+    }
+
+    UnmodifiableNavigableMap(
+        NavigableMap<K, V> delegate, UnmodifiableNavigableMap<K, V> descendingMap) {
+      this.delegate = delegate;
+      this.descendingMap = descendingMap;
+    }
+
+    @Override
+    protected SortedMap<K, V> delegate() {
+      return Collections.unmodifiableSortedMap(delegate);
+    }
+
+    @Override
+    public Entry<K, V> lowerEntry(K key) {
+      return unmodifiableOrNull(delegate.lowerEntry(key));
+    }
+
+    @Override
+    public K lowerKey(K key) {
+      return delegate.lowerKey(key);
+    }
+
+    @Override
+    public Entry<K, V> floorEntry(K key) {
+      return unmodifiableOrNull(delegate.floorEntry(key));
+    }
+
+    @Override
+    public K floorKey(K key) {
+      return delegate.floorKey(key);
+    }
+
+    @Override
+    public Entry<K, V> ceilingEntry(K key) {
+      return unmodifiableOrNull(delegate.ceilingEntry(key));
+    }
+
+    @Override
+    public K ceilingKey(K key) {
+      return delegate.ceilingKey(key);
+    }
+
+    @Override
+    public Entry<K, V> higherEntry(K key) {
+      return unmodifiableOrNull(delegate.higherEntry(key));
+    }
+
+    @Override
+    public K higherKey(K key) {
+      return delegate.higherKey(key);
+    }
+
+    @Override
+    public Entry<K, V> firstEntry() {
+      return unmodifiableOrNull(delegate.firstEntry());
+    }
+
+    @Override
+    public Entry<K, V> lastEntry() {
+      return unmodifiableOrNull(delegate.lastEntry());
+    }
+
+    @Override
+    public final Entry<K, V> pollFirstEntry() {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public final Entry<K, V> pollLastEntry() {
+      throw new UnsupportedOperationException();
+    }
+
+    private transient UnmodifiableNavigableMap<K, V> descendingMap;
+
+    @Override
+    public NavigableMap<K, V> descendingMap() {
+      UnmodifiableNavigableMap<K, V> result = descendingMap;
+      return (result == null)
+          ? descendingMap = new UnmodifiableNavigableMap<K, V>(delegate.descendingMap(), this)
+          : result;
+    }
+
+    @Override
+    public Set<K> keySet() {
+      return navigableKeySet();
+    }
+
+    @Override
+    public NavigableSet<K> navigableKeySet() {
+      return Sets.unmodifiableNavigableSet(delegate.navigableKeySet());
+    }
+
+    @Override
+    public NavigableSet<K> descendingKeySet() {
+      return Sets.unmodifiableNavigableSet(delegate.descendingKeySet());
+    }
+
+    @Override
+    public SortedMap<K, V> subMap(K fromKey, K toKey) {
+      return subMap(fromKey, true, toKey, false);
+    }
+
+    @Override
+    public SortedMap<K, V> headMap(K toKey) {
+      return headMap(toKey, false);
+    }
+
+    @Override
+    public SortedMap<K, V> tailMap(K fromKey) {
+      return tailMap(fromKey, true);
+    }
+
+    @Override
+    public
+        NavigableMap<K, V>
+        subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+      return Maps.unmodifiableNavigableMap(delegate.subMap(
+          fromKey,
+          fromInclusive,
+          toKey,
+          toInclusive));
+    }
+
+    @Override
+    public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
+      return Maps.unmodifiableNavigableMap(delegate.headMap(toKey, inclusive));
+    }
+
+    @Override
+    public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
+      return Maps.unmodifiableNavigableMap(delegate.tailMap(fromKey, inclusive));
+    }
+  }
+
+  /**
+   * Returns a synchronized (thread-safe) navigable map backed by the specified
+   * navigable map.  In order to guarantee serial access, it is critical that
+   * <b>all</b> access to the backing navigable map is accomplished
+   * through the returned navigable map (or its views).
+   *
+   * <p>It is imperative that the user manually synchronize on the returned
+   * navigable map when iterating over any of its collection views, or the
+   * collections views of any of its {@code descendingMap}, {@code subMap},
+   * {@code headMap} or {@code tailMap} views. <pre>   {@code
+   *
+   *   NavigableMap<K, V> map = synchronizedNavigableMap(new TreeMap<K, V>());
+   *
+   *   // Needn't be in synchronized block
+   *   NavigableSet<K> set = map.navigableKeySet();
+   *
+   *   synchronized (map) { // Synchronizing on map, not set!
+   *     Iterator<K> it = set.iterator(); // Must be in synchronized block
+   *     while (it.hasNext()) {
+   *       foo(it.next());
+   *     }
+   *   }}</pre>
+   *
+   * <p>or: <pre>   {@code
+   *
+   *   NavigableMap<K, V> map = synchronizedNavigableMap(new TreeMap<K, V>());
+   *   NavigableMap<K, V> map2 = map.subMap(foo, false, bar, true);
+   *
+   *   // Needn't be in synchronized block
+   *   NavigableSet<K> set2 = map2.descendingKeySet();
+   *
+   *   synchronized (map) { // Synchronizing on map, not map2 or set2!
+   *     Iterator<K> it = set2.iterator(); // Must be in synchronized block
+   *     while (it.hasNext()) {
+   *       foo(it.next());
+   *     }
+   *   }}</pre>
+   *
+   * <p>Failure to follow this advice may result in non-deterministic behavior.
+   *
+   * <p>The returned navigable map will be serializable if the specified
+   * navigable map is serializable.
+   *
+   * @param navigableMap the navigable map to be "wrapped" in a synchronized
+   *    navigable map.
+   * @return a synchronized view of the specified navigable map.
+   * @since 13.0
+   */
+  @GwtIncompatible("NavigableMap")
+  public static <K, V> NavigableMap<K, V> synchronizedNavigableMap(
+      NavigableMap<K, V> navigableMap) {
+    return Synchronized.navigableMap(navigableMap);
+  }
+
   /**
    * {@code AbstractMap} extension that implements {@link #isEmpty()} as {@code
    * entrySet().isEmpty()} instead of {@code size() == 0} to speed up
@@ -2699,6 +3569,92 @@
     }
   }
 
+  @GwtIncompatible("NavigableMap")
+  static class NavigableKeySet<K, V> extends SortedKeySet<K, V> implements NavigableSet<K> {
+    NavigableKeySet(NavigableMap<K, V> map) {
+      super(map);
+    }
+
+    @Override
+    NavigableMap<K, V> map() {
+      return (NavigableMap<K, V>) map;
+    }
+
+    @Override
+    public K lower(K e) {
+      return map().lowerKey(e);
+    }
+
+    @Override
+    public K floor(K e) {
+      return map().floorKey(e);
+    }
+
+    @Override
+    public K ceiling(K e) {
+      return map().ceilingKey(e);
+    }
+
+    @Override
+    public K higher(K e) {
+      return map().higherKey(e);
+    }
+
+    @Override
+    public K pollFirst() {
+      return keyOrNull(map().pollFirstEntry());
+    }
+
+    @Override
+    public K pollLast() {
+      return keyOrNull(map().pollLastEntry());
+    }
+
+    @Override
+    public NavigableSet<K> descendingSet() {
+      return map().descendingKeySet();
+    }
+
+    @Override
+    public Iterator<K> descendingIterator() {
+      return descendingSet().iterator();
+    }
+
+    @Override
+    public NavigableSet<K> subSet(
+        K fromElement,
+        boolean fromInclusive,
+        K toElement,
+        boolean toInclusive) {
+      return map().subMap(fromElement, fromInclusive, toElement, toInclusive).navigableKeySet();
+    }
+
+    @Override
+    public NavigableSet<K> headSet(K toElement, boolean inclusive) {
+      return map().headMap(toElement, inclusive).navigableKeySet();
+    }
+
+    @Override
+    public NavigableSet<K> tailSet(K fromElement, boolean inclusive) {
+      return map().tailMap(fromElement, inclusive).navigableKeySet();
+    }
+
+    @Override
+    public SortedSet<K> subSet(K fromElement, K toElement) {
+      return subSet(fromElement, true, toElement, false);
+    }
+
+    @Override
+    public SortedSet<K> headSet(K toElement) {
+      return headSet(toElement, false);
+    }
+
+    @Override
+    public SortedSet<K> tailSet(K fromElement) {
+      return tailSet(fromElement, true);
+    }
+  }
+
   static class Values<K, V> extends AbstractCollection<V> {
     final Map<K, V> map;
 
@@ -2833,4 +3789,196 @@
       }
     }
   }
+
+  @GwtIncompatible("NavigableMap")
+  abstract static class DescendingMap<K, V> extends ForwardingMap<K, V>
+      implements NavigableMap<K, V> {
+
+    abstract NavigableMap<K, V> forward();
+
+    @Override
+    protected final Map<K, V> delegate() {
+      return forward();
+    }
+
+    private transient Comparator<? super K> comparator;
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Comparator<? super K> comparator() {
+      Comparator<? super K> result = comparator;
+      if (result == null) {
+        Comparator<? super K> forwardCmp = forward().comparator();
+        if (forwardCmp == null) {
+          forwardCmp = (Comparator) Ordering.natural();
+        }
+        result = comparator = reverse(forwardCmp);
+      }
+      return result;
+    }
+
+    // If we inline this, we get a javac error.
+    private static <T> Ordering<T> reverse(Comparator<T> forward) {
+      return Ordering.from(forward).reverse();
+    }
+
+    @Override
+    public K firstKey() {
+      return forward().lastKey();
+    }
+
+    @Override
+    public K lastKey() {
+      return forward().firstKey();
+    }
+
+    @Override
+    public Entry<K, V> lowerEntry(K key) {
+      return forward().higherEntry(key);
+    }
+
+    @Override
+    public K lowerKey(K key) {
+      return forward().higherKey(key);
+    }
+
+    @Override
+    public Entry<K, V> floorEntry(K key) {
+      return forward().ceilingEntry(key);
+    }
+
+    @Override
+    public K floorKey(K key) {
+      return forward().ceilingKey(key);
+    }
+
+    @Override
+    public Entry<K, V> ceilingEntry(K key) {
+      return forward().floorEntry(key);
+    }
+
+    @Override
+    public K ceilingKey(K key) {
+      return forward().floorKey(key);
+    }
+
+    @Override
+    public Entry<K, V> higherEntry(K key) {
+      return forward().lowerEntry(key);
+    }
+
+    @Override
+    public K higherKey(K key) {
+      return forward().lowerKey(key);
+    }
+
+    @Override
+    public Entry<K, V> firstEntry() {
+      return forward().lastEntry();
+    }
+
+    @Override
+    public Entry<K, V> lastEntry() {
+      return forward().firstEntry();
+    }
+
+    @Override
+    public Entry<K, V> pollFirstEntry() {
+      return forward().pollLastEntry();
+    }
+
+    @Override
+    public Entry<K, V> pollLastEntry() {
+      return forward().pollFirstEntry();
+    }
+
+    @Override
+    public NavigableMap<K, V> descendingMap() {
+      return forward();
+    }
+
+    private transient Set<Entry<K, V>> entrySet;
+
+    @Override
+    public Set<Entry<K, V>> entrySet() {
+      Set<Entry<K, V>> result = entrySet;
+      return (result == null) ? entrySet = createEntrySet() : result;
+    }
+
+    abstract Iterator<Entry<K, V>> entryIterator();
+
+    Set<Entry<K, V>> createEntrySet() {
+      return new EntrySet<K, V>() {
+        @Override
+        Map<K, V> map() {
+          return DescendingMap.this;
+        }
+
+        @Override
+        public Iterator<Entry<K, V>> iterator() {
+          return entryIterator();
+        }
+      };
+    }
+
+    @Override
+    public Set<K> keySet() {
+      return navigableKeySet();
+    }
+
+    private transient NavigableSet<K> navigableKeySet;
+
+    @Override
+    public NavigableSet<K> navigableKeySet() {
+      NavigableSet<K> result = navigableKeySet;
+      return (result == null) ? navigableKeySet = new NavigableKeySet<K, V>(this) : result;
+    }
+
+    @Override
+    public NavigableSet<K> descendingKeySet() {
+      return forward().navigableKeySet();
+    }
+
+    @Override
+    public
+    NavigableMap<K, V>
+    subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+      return forward().subMap(toKey, toInclusive, fromKey, fromInclusive).descendingMap();
+    }
+
+    @Override
+    public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
+      return forward().tailMap(toKey, inclusive).descendingMap();
+    }
+
+    @Override
+    public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
+      return forward().headMap(fromKey, inclusive).descendingMap();
+    }
+
+    @Override
+    public SortedMap<K, V> subMap(K fromKey, K toKey) {
+      return subMap(fromKey, true, toKey, false);
+    }
+
+    @Override
+    public SortedMap<K, V> headMap(K toKey) {
+      return headMap(toKey, false);
+    }
+
+    @Override
+    public SortedMap<K, V> tailMap(K fromKey) {
+      return tailMap(fromKey, true);
+    }
+
+    @Override
+    public Collection<V> values() {
+      return new Values<K, V>(this);
+    }
+
+    @Override
+    public String toString() {
+      return standardToString();
+    }
+  }
 }
diff --git a/guava/src/com/google/common/collect/MinMaxPriorityQueue.java b/guava/src/com/google/common/collect/MinMaxPriorityQueue.java
index 60bad54..bb23f40 100644
--- a/guava/src/com/google/common/collect/MinMaxPriorityQueue.java
+++ b/guava/src/com/google/common/collect/MinMaxPriorityQueue.java
@@ -27,13 +27,13 @@
 import com.google.common.math.IntMath;
 
 import java.util.AbstractQueue;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.ConcurrentModificationException;
 import java.util.Iterator;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.PriorityQueue;
@@ -787,7 +787,7 @@
         MoveDesc<E> moved = removeAt(cursor);
         if (moved != null) {
           if (forgetMeNot == null) {
-            forgetMeNot = new LinkedList<E>();
+            forgetMeNot = new ArrayDeque<E>();
             skipMe = new ArrayList<E>(3);
           }
           forgetMeNot.add(moved.toTrickle);
diff --git a/guava/src/com/google/common/collect/Multimap.java b/guava/src/com/google/common/collect/Multimap.java
index 0d725de..074dc0d 100644
--- a/guava/src/com/google/common/collect/Multimap.java
+++ b/guava/src/com/google/common/collect/Multimap.java
@@ -106,9 +106,10 @@
  * chronological order.
  *
  * <p><b>Warning:</b> instances of type {@code Multimap} may not implement
- * {@link Object#equals} in the way you expect (multimaps containing the same
- * key-value pairs, even in the same order, may or may not be equal). The
- * recommended subinterfaces provide a much stronger guarantee.
+ * {@link Object#equals} in the way you expect.  Multimaps containing the same
+ * key-value pairs, even in the same order, may or may not be equal and may or
+ * may not have the same {@code hashCode}. The recommended subinterfaces
+ * provide much stronger guarantees.
  *
  * <h3>Comparison to a map of collections</h3>
  *
@@ -376,6 +377,13 @@
    *
    * <p>The hash code of a multimap is defined as the hash code of the map view,
    * as returned by {@link Multimap#asMap}.
+   *
+   * <p>In general, two multimaps with identical key-value mappings may or may
+   * not have the same hash codes, depending on the implementation. For
+   * example, two {@link SetMultimap} instances with the same key-value
+   * mappings will have the same {@code hashCode}, but the {@code hashCode}
+   * of {@link ListMultimap} instances depends on the ordering of the values 
+   * for each key.
    */
   @Override
   int hashCode();
diff --git a/guava/src/com/google/common/collect/Multisets.java b/guava/src/com/google/common/collect/Multisets.java
index adf7b2b..2ce27a5 100644
--- a/guava/src/com/google/common/collect/Multisets.java
+++ b/guava/src/com/google/common/collect/Multisets.java
@@ -715,7 +715,7 @@
    * {@link Multiset#removeAll removeAll}{@code (occurrencesToRemove)}, which
    * removes all occurrences of elements that appear in
    * {@code occurrencesToRemove}. However, this operation <i>is</i> equivalent
-   * to, albeit more efficient than, the following: <pre>   {@code
+   * to, albeit sometimes more efficient than, the following: <pre>   {@code
    *
    *   for (E e : occurrencesToRemove) {
    *     multisetToModify.remove(e);
@@ -723,15 +723,32 @@
    *
    * @return {@code true} if {@code multisetToModify} was changed as a result of
    *         this operation
-   * @since 10.0
+   * @since 18.0 (present in 10.0 with a requirement that the second parameter
+   *     be a {@code Multiset})
    */
   public static boolean removeOccurrences(
-      Multiset<?> multisetToModify, Multiset<?> occurrencesToRemove) {
-    return removeOccurrencesImpl(multisetToModify, occurrencesToRemove);
+      Multiset<?> multisetToModify, Iterable<?> occurrencesToRemove) {
+    if (occurrencesToRemove instanceof Multiset) {
+      return removeOccurrencesImpl(
+          multisetToModify, (Multiset<?>) occurrencesToRemove);
+    } else {
+      return removeOccurrencesImpl(multisetToModify, occurrencesToRemove);
+    }
+  }
+
+  private static boolean removeOccurrencesImpl(
+      Multiset<?> multisetToModify, Iterable<?> occurrencesToRemove) {
+    checkNotNull(multisetToModify);
+    checkNotNull(occurrencesToRemove);
+    boolean changed = false;
+    for (Object o : occurrencesToRemove) {
+      changed |= multisetToModify.remove(o);
+    }
+    return changed;
   }
 
   /**
-   * Delegate that cares about the element types in occurrencesToRemove.
+   * Delegate that cares about the element types in multisetToModify.
    */
   private static <E> boolean removeOccurrencesImpl(
       Multiset<E> multisetToModify, Multiset<?> occurrencesToRemove) {
diff --git a/guava/src/com/google/common/collect/Ordering.java b/guava/src/com/google/common/collect/Ordering.java
index 9e0bd58..8b15aef 100644
--- a/guava/src/com/google/common/collect/Ordering.java
+++ b/guava/src/com/google/common/collect/Ordering.java
@@ -216,6 +216,8 @@
    * is expected.
    *
    * <p>The returned comparator is serializable.
+   *
+   * @since 13.0
    */
   @GwtCompatible(serializable = true)
   @SuppressWarnings("unchecked")
diff --git a/guava/src/com/google/common/collect/Platform.java b/guava/src/com/google/common/collect/Platform.java
index 5ada40c..9fc907b 100644
--- a/guava/src/com/google/common/collect/Platform.java
+++ b/guava/src/com/google/common/collect/Platform.java
@@ -24,6 +24,8 @@
 import java.lang.reflect.Array;
 import java.util.Collections;
 import java.util.Map;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.SortedSet;
@@ -53,7 +55,7 @@
   }
   
   static <E> Set<E> newSetFromMap(Map<E, Boolean> map) {
-    return Sets.newSetFromMap(map);
+    return Collections.newSetFromMap(map);
   }
 
   /**
@@ -69,22 +71,30 @@
   static <K, V1, V2> SortedMap<K, V2> mapsTransformEntriesSortedMap(
       SortedMap<K, V1> fromMap,
       EntryTransformer<? super K, ? super V1, V2> transformer) {
-    return Maps.transformEntriesIgnoreNavigable(fromMap, transformer);
+    return (fromMap instanceof NavigableMap)
+        ? Maps.transformEntries((NavigableMap<K, V1>) fromMap, transformer)
+        : Maps.transformEntriesIgnoreNavigable(fromMap, transformer);
   }
 
   static <K, V> SortedMap<K, V> mapsAsMapSortedSet(SortedSet<K> set,
       Function<? super K, V> function) {
-    return Maps.asMapSortedIgnoreNavigable(set, function);
+    return (set instanceof NavigableSet)
+        ? Maps.asMap((NavigableSet<K>) set, function)
+        : Maps.asMapSortedIgnoreNavigable(set, function);
   }
 
   static <E> SortedSet<E> setsFilterSortedSet(SortedSet<E> set,
       Predicate<? super E> predicate) {
-    return Sets.filterSortedIgnoreNavigable(set, predicate);
+    return (set instanceof NavigableSet)
+        ? Sets.filter((NavigableSet<E>) set, predicate)
+        : Sets.filterSortedIgnoreNavigable(set, predicate);
   }
   
   static <K, V> SortedMap<K, V> mapsFilterSortedMap(SortedMap<K, V> map,
       Predicate<? super Map.Entry<K, V>> predicate) {
-    return Maps.filterSortedIgnoreNavigable(map, predicate);
+    return (map instanceof NavigableMap)
+        ? Maps.filterEntries((NavigableMap<K, V>) map, predicate)
+        : Maps.filterSortedIgnoreNavigable(map, predicate);
   }
 
   private Platform() {}
diff --git a/guava/src/com/google/common/collect/Queues.java b/guava/src/com/google/common/collect/Queues.java
index 81af809..1507838 100644
--- a/guava/src/com/google/common/collect/Queues.java
+++ b/guava/src/com/google/common/collect/Queues.java
@@ -17,19 +17,22 @@
 import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;
 
+import java.util.ArrayDeque;
 import java.util.Collection;
+import java.util.Deque;
 import java.util.PriorityQueue;
 import java.util.Queue;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.LinkedBlockingDeque;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.PriorityBlockingQueue;
 import java.util.concurrent.SynchronousQueue;
 import java.util.concurrent.TimeUnit;
 
 /**
- * Static utility methods pertaining to {@link Queue} instances.
+ * Static utility methods pertaining to {@link Queue} and {@link Deque} instances.
  * Also see this class's counterparts {@link Lists}, {@link Sets}, and {@link Maps}.
  *
  * @author Kurt Alfred Kluever
@@ -48,6 +51,32 @@
     return new ArrayBlockingQueue<E>(capacity);
   }
 
+  // ArrayDeque
+
+  /**
+   * Creates an empty {@code ArrayDeque}.
+   *
+   * @since 12.0
+   */
+  public static <E> ArrayDeque<E> newArrayDeque() {
+    return new ArrayDeque<E>();
+  }
+
+  /**
+   * Creates an {@code ArrayDeque} containing the elements of the specified iterable,
+   * in the order they are returned by the iterable's iterator.
+   *
+   * @since 12.0
+   */
+  public static <E> ArrayDeque<E> newArrayDeque(Iterable<? extends E> elements) {
+    if (elements instanceof Collection) {
+      return new ArrayDeque<E>(Collections2.cast(elements));
+    }
+    ArrayDeque<E> deque = new ArrayDeque<E>();
+    Iterables.addAll(deque, elements);
+    return deque;
+  }
+
   // ConcurrentLinkedQueue
 
   /**
@@ -71,6 +100,43 @@
     return queue;
   }
 
+  // LinkedBlockingDeque
+
+  /**
+   * Creates an empty {@code LinkedBlockingDeque} with a capacity of {@link Integer#MAX_VALUE}.
+   *
+   * @since 12.0
+   */
+  public static <E> LinkedBlockingDeque<E> newLinkedBlockingDeque() {
+    return new LinkedBlockingDeque<E>();
+  }
+
+  /**
+   * Creates an empty {@code LinkedBlockingDeque} with the given (fixed) capacity.
+   *
+   * @throws IllegalArgumentException if {@code capacity} is less than 1
+   * @since 12.0
+   */
+  public static <E> LinkedBlockingDeque<E> newLinkedBlockingDeque(int capacity) {
+    return new LinkedBlockingDeque<E>(capacity);
+  }
+
+  /**
+   * Creates a {@code LinkedBlockingDeque} with a capacity of {@link Integer#MAX_VALUE},
+   * containing the elements of the specified iterable,
+   * in the order they are returned by the iterable's iterator.
+   *
+   * @since 12.0
+   */
+  public static <E> LinkedBlockingDeque<E> newLinkedBlockingDeque(Iterable<? extends E> elements) {
+    if (elements instanceof Collection) {
+      return new LinkedBlockingDeque<E>(Collections2.cast(elements));
+    }
+    LinkedBlockingDeque<E> deque = new LinkedBlockingDeque<E>();
+    Iterables.addAll(deque, elements);
+    return deque;
+  }
+
   // LinkedBlockingQueue
 
   /**
@@ -294,8 +360,38 @@
    * @return a synchronized view of the specified queue
    * @since 14.0
    */
-  @Beta
   public static <E> Queue<E> synchronizedQueue(Queue<E> queue) {
     return Synchronized.queue(queue, null);
   }
+
+  /**
+   * Returns a synchronized (thread-safe) deque backed by the specified deque. In order to
+   * guarantee serial access, it is critical that <b>all</b> access to the backing deque is
+   * accomplished through the returned deque.
+   *
+   * <p>It is imperative that the user manually synchronize on the returned deque when accessing
+   * any of the deque's iterators: <pre>   {@code
+   *
+   *   Deque<E> deque = Queues.synchronizedDeque(Queues.<E>newArrayDeque());
+   *   ...
+   *   deque.add(element);  // Needn't be in synchronized block
+   *   ...
+   *   synchronized (deque) {  // Must synchronize on deque!
+   *     Iterator<E> i = deque.iterator(); // Must be in synchronized block
+   *     while (i.hasNext()) {
+   *       foo(i.next());
+   *     }
+   *   }}</pre>
+   *
+   * <p>Failure to follow this advice may result in non-deterministic behavior.
+   *
+   * <p>The returned deque will be serializable if the specified deque is serializable.
+   *
+   * @param deque the deque to be wrapped in a synchronized view
+   * @return a synchronized view of the specified deque
+   * @since 15.0
+   */
+  public static <E> Deque<E> synchronizedDeque(Deque<E> deque) {
+    return Synchronized.deque(deque, null);
+  }
 }
diff --git a/guava/src/com/google/common/collect/Range.java b/guava/src/com/google/common/collect/Range.java
index d5c1d21..bb81d7e 100644
--- a/guava/src/com/google/common/collect/Range.java
+++ b/guava/src/com/google/common/collect/Range.java
@@ -18,18 +18,15 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import com.google.common.annotations.Beta;
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.base.Equivalence;
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
 
 import java.io.Serializable;
-import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
-import java.util.Set;
 import java.util.SortedSet;
 
 import javax.annotation.Nullable;
@@ -599,33 +596,6 @@
   }
 
   /**
-   * Returns an {@link ContiguousSet} containing the same values in the given domain
-   * {@linkplain Range#contains contained} by this range.
-   *
-   * <p><b>Note:</b> {@code a.asSet(d).equals(b.asSet(d))} does not imply {@code a.equals(b)}! For
-   * example, {@code a} and {@code b} could be {@code [2..4]} and {@code (1..5)}, or the empty
-   * ranges {@code [3..3)} and {@code [4..4)}.
-   *
-   * <p><b>Warning:</b> Be extremely careful what you do with the {@code asSet} view of a large
-   * range (such as {@code Range.greaterThan(0)}). Certain operations on such a set can be
-   * performed efficiently, but others (such as {@link Set#hashCode} or {@link
-   * Collections#frequency}) can cause major performance problems.
-   *
-   * <p>The returned set's {@link Object#toString} method returns a short-hand form of the set's
-   * contents, such as {@code "[1..100]}"}.
-   *
-   * @throws IllegalArgumentException if neither this range nor the domain has a lower bound, or if
-   *     neither has an upper bound
-   * @deprecated Use {@code ContiguousSet.create(range, domain)}. To be removed in Guava 16.0.
-   */
-  @Beta
-  @GwtCompatible(serializable = false)
-  @Deprecated
-  public ContiguousSet<C> asSet(DiscreteDomain<C> domain) {
-    return ContiguousSet.create(this, domain);
-  }
-
-  /**
    * Returns the canonical form of this range in the given domain. The canonical form has the
    * following properties:
    *
diff --git a/guava/src/com/google/common/collect/RangeMap.java b/guava/src/com/google/common/collect/RangeMap.java
new file mode 100644
index 0000000..ba42985
--- /dev/null
+++ b/guava/src/com/google/common/collect/RangeMap.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2012 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import com.google.common.annotations.Beta;
+
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+/**
+ * A mapping from disjoint nonempty ranges to non-null values. Queries look up the value
+ * associated with the range (if any) that contains a specified key.
+ *
+ * <p>In contrast to {@link RangeSet}, no "coalescing" is done of {@linkplain
+ * Range#isConnected(Range) connected} ranges, even if they are mapped to the same value.
+ *
+ * @author Louis Wasserman
+ * @since 14.0
+ */
+@Beta
+public interface RangeMap<K extends Comparable, V> {
+  /**
+   * Returns the value associated with the specified key, or {@code null} if there is no
+   * such value.
+   *
+   * <p>Specifically, if any range in this range map contains the specified key, the value
+   * associated with that range is returned.
+   */
+  @Nullable
+  V get(K key);
+
+  /**
+   * Returns the range containing this key and its associated value, if such a range is present
+   * in the range map, or {@code null} otherwise.
+   */
+  @Nullable
+  Map.Entry<Range<K>, V> getEntry(K key);
+
+  /**
+   * Returns the minimal range {@linkplain Range#encloses(Range) enclosing} the ranges
+   * in this {@code RangeMap}.
+   *
+   * @throws NoSuchElementException if this range map is empty
+   */
+  Range<K> span();
+
+  /**
+   * Maps a range to a specified value (optional operation).
+   *
+   * <p>Specifically, after a call to {@code put(range, value)}, if
+   * {@link Range#contains(Comparable) range.contains(k)}, then {@link #get(Comparable) get(k)}
+   * will return {@code value}.
+   *
+   * <p>If {@code range} {@linkplain Range#isEmpty() is empty}, then this is a no-op.
+   */
+  void put(Range<K> range, V value);
+
+  /**
+   * Puts all the associations from {@code rangeMap} into this range map (optional operation).
+   */
+  void putAll(RangeMap<K, V> rangeMap);
+
+  /**
+   * Removes all associations from this range map (optional operation).
+   */
+  void clear();
+
+  /**
+   * Removes all associations from this range map in the specified range (optional operation).
+   *
+   * <p>If {@code !range.contains(k)}, {@link #get(Comparable) get(k)} will return the same result
+   * before and after a call to {@code remove(range)}.  If {@code range.contains(k)}, then
+   * after a call to {@code remove(range)}, {@code get(k)} will return {@code null}.
+   */
+  void remove(Range<K> range);
+
+  /**
+   * Returns a view of this range map as an unmodifiable {@code Map<Range<K>, V>}.
+   * Modifications to this range map are guaranteed to read through to the returned {@code Map}.
+   *
+   * <p>It is guaranteed that no empty ranges will be in the returned {@code Map}.
+   */
+  Map<Range<K>, V> asMapOfRanges();
+  
+  /**
+   * Returns a view of the part of this range map that intersects with {@code range}.
+   * 
+   * <p>For example, if {@code rangeMap} had the entries 
+   * {@code [1, 5] => "foo", (6, 8) => "bar", (10, \u2025) => "baz"}
+   * then {@code rangeMap.subRangeMap(Range.open(3, 12))} would return a range map
+   * with the entries {@code (3, 5) => "foo", (6, 8) => "bar", (10, 12) => "baz"}.
+   * 
+   * <p>The returned range map supports all optional operations that this range map supports,
+   * except for {@code asMapOfRanges().iterator().remove()}.
+   * 
+   * <p>The returned range map will throw an {@link IllegalArgumentException} on an attempt to 
+   * insert a range not {@linkplain Range#encloses(Range) enclosed} by {@code range}. 
+   */
+  RangeMap<K, V> subRangeMap(Range<K> range);
+
+  /**
+   * Returns {@code true} if {@code obj} is another {@code RangeMap} that has an equivalent
+   * {@link #asMapOfRanges()}.
+   */
+  @Override
+  boolean equals(@Nullable Object o);
+
+  /**
+   * Returns {@code asMapOfRanges().hashCode()}.
+   */
+  @Override
+  int hashCode();
+
+  /**
+   * Returns a readable string representation of this range map.
+   */
+  @Override
+  String toString();
+}
diff --git a/guava/src/com/google/common/collect/RangeSet.java b/guava/src/com/google/common/collect/RangeSet.java
new file mode 100644
index 0000000..910597f
--- /dev/null
+++ b/guava/src/com/google/common/collect/RangeSet.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import com.google.common.annotations.Beta;
+
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * A set comprising zero or more {@linkplain Range#isEmpty nonempty},
+ * {@linkplain Range#isConnected(Range) disconnected} ranges of type {@code C}.
+ *
+ * <p>Implementations that choose to support the {@link #add(Range)} operation are required to
+ * ignore empty ranges and coalesce connected ranges.  For example:  <pre>   {@code
+ *
+ *   RangeSet<Integer> rangeSet = TreeRangeSet.create();
+ *   rangeSet.add(Range.closed(1, 10)); // {[1, 10]}
+ *   rangeSet.add(Range.closedOpen(11, 15)); // disconnected range; {[1, 10], [11, 15)}
+ *   rangeSet.add(Range.closedOpen(15, 20)); // connected range; {[1, 10], [11, 20)}
+ *   rangeSet.add(Range.openClosed(0, 0)); // empty range; {[1, 10], [11, 20)}
+ *   rangeSet.remove(Range.open(5, 10)); // splits [1, 10]; {[1, 5], [10, 10], [11, 20)}}</pre>
+ *
+ * <p>Note that the behavior of {@link Range#isEmpty()} and {@link Range#isConnected(Range)} may
+ * not be as expected on discrete ranges.  See the Javadoc of those methods for details.
+ *
+ * <p>For a {@link Set} whose contents are specified by a {@link Range}, see {@link ContiguousSet}.
+ *
+ * @author Kevin Bourrillion
+ * @author Louis Wasserman
+ * @since 14.0
+ */
+@Beta
+public interface RangeSet<C extends Comparable> {
+  
+  // Query methods
+
+  /**
+   * Determines whether any of this range set's member ranges contains {@code value}.
+   */
+  boolean contains(C value);
+
+  /**
+   * Returns the unique range from this range set that {@linkplain Range#contains contains}
+   * {@code value}, or {@code null} if this range set does not contain {@code value}.
+   */
+  Range<C> rangeContaining(C value);
+
+  /**
+   * Returns {@code true} if there exists a member range in this range set which
+   * {@linkplain Range#encloses encloses} the specified range.
+   */
+  boolean encloses(Range<C> otherRange);
+
+  /**
+   * Returns {@code true} if for each member range in {@code other} there exists a member range in
+   * this range set which {@linkplain Range#encloses encloses} it. It follows that
+   * {@code this.contains(value)} whenever {@code other.contains(value)}. Returns {@code true} if
+   * {@code other} is empty.
+   *
+   * <p>This is equivalent to checking if this range set {@link #encloses} each of the ranges in
+   * {@code other}.
+   */
+  boolean enclosesAll(RangeSet<C> other);
+
+  /**
+   * Returns {@code true} if this range set contains no ranges.
+   */
+  boolean isEmpty();
+
+  /**
+   * Returns the minimal range which {@linkplain Range#encloses(Range) encloses} all ranges
+   * in this range set.
+   *
+   * @throws NoSuchElementException if this range set is {@linkplain #isEmpty() empty}
+   */
+  Range<C> span();
+
+  // Views
+  
+  /**
+   * Returns a view of the {@linkplain Range#isConnected disconnected} ranges that make up this
+   * range set.  The returned set may be empty. The iterators returned by its
+   * {@link Iterable#iterator} method return the ranges in increasing order of lower bound
+   * (equivalently, of upper bound).
+   */
+  Set<Range<C>> asRanges();
+
+  /**
+   * Returns a view of the complement of this {@code RangeSet}.
+   *
+   * <p>The returned view supports the {@link #add} operation if this {@code RangeSet} supports
+   * {@link #remove}, and vice versa.
+   */
+  RangeSet<C> complement();
+  
+  /**
+   * Returns a view of the intersection of this {@code RangeSet} with the specified range.
+   *
+   * <p>The returned view supports all optional operations supported by this {@code RangeSet}, with
+   * the caveat that an {@link IllegalArgumentException} is thrown on an attempt to
+   * {@linkplain #add(Range) add} any range not {@linkplain Range#encloses(Range) enclosed} by
+   * {@code view}.
+   */
+  RangeSet<C> subRangeSet(Range<C> view);
+  
+  // Modification
+
+  /**
+   * Adds the specified range to this {@code RangeSet} (optional operation). That is, for equal
+   * range sets a and b, the result of {@code a.add(range)} is that {@code a} will be the minimal
+   * range set for which both {@code a.enclosesAll(b)} and {@code a.encloses(range)}.
+   *
+   * <p>Note that {@code range} will be {@linkplain Range#span(Range) coalesced} with any ranges in
+   * the range set that are {@linkplain Range#isConnected(Range) connected} with it.  Moreover,
+   * if {@code range} is empty, this is a no-op.
+   *
+   * @throws UnsupportedOperationException if this range set does not support the {@code add}
+   *         operation
+   */
+  void add(Range<C> range);
+
+  /**
+   * Removes the specified range from this {@code RangeSet} (optional operation). After this
+   * operation, if {@code range.contains(c)}, {@code this.contains(c)} will return {@code false}.
+   *
+   * <p>If {@code range} is empty, this is a no-op.
+   *
+   * @throws UnsupportedOperationException if this range set does not support the {@code remove}
+   *         operation
+   */
+  void remove(Range<C> range);
+  
+  /**
+   * Removes all ranges from this {@code RangeSet} (optional operation).  After this operation,
+   * {@code this.contains(c)} will return false for all {@code c}.
+   * 
+   * <p>This is equivalent to {@code remove(Range.all())}.
+   * 
+   * @throws UnsupportedOperationException if this range set does not support the {@code clear}
+   *         operation
+   */
+  void clear();
+
+  /**
+   * Adds all of the ranges from the specified range set to this range set (optional operation).
+   * After this operation, this range set is the minimal range set that
+   * {@linkplain #enclosesAll(RangeSet) encloses} both the original range set and {@code other}.
+   *
+   * <p>This is equivalent to calling {@link #add} on each of the ranges in {@code other} in turn.
+   *
+   * @throws UnsupportedOperationException if this range set does not support the {@code addAll}
+   *         operation
+   */
+  void addAll(RangeSet<C> other);
+
+  /**
+   * Removes all of the ranges from the specified range set from this range set (optional
+   * operation). After this operation, if {@code other.contains(c)}, {@code this.contains(c)} will
+   * return {@code false}.
+   *
+   * <p>This is equivalent to calling {@link #remove} on each of the ranges in {@code other} in
+   * turn.
+   *
+   * @throws UnsupportedOperationException if this range set does not support the {@code removeAll}
+   *         operation
+   */
+  void removeAll(RangeSet<C> other);
+  
+  // Object methods
+
+  /**
+   * Returns {@code true} if {@code obj} is another {@code RangeSet} that contains the same ranges
+   * according to {@link Range#equals(Object)}.
+   */
+  @Override
+  boolean equals(@Nullable Object obj);
+  
+  /**
+   * Returns {@code asRanges().hashCode()}.
+   */
+  @Override
+  int hashCode();
+
+  /**
+   * Returns a readable string representation of this range set. For example, if this
+   * {@code RangeSet} consisted of {@code Range.closed(1, 3)} and {@code Range.greaterThan(4)},
+   * this might return {@code " [1‥3](4‥+∞)}"}.
+   */
+  @Override
+  String toString();
+}
diff --git a/guava/src/com/google/common/collect/Sets.java b/guava/src/com/google/common/collect/Sets.java
index 003a307..4218725 100644
--- a/guava/src/com/google/common/collect/Sets.java
+++ b/guava/src/com/google/common/collect/Sets.java
@@ -25,8 +25,6 @@
 import com.google.common.base.Predicates;
 import com.google.common.collect.Collections2.FilteredCollection;
 
-import java.io.IOException;
-import java.io.ObjectInputStream;
 import java.io.Serializable;
 import java.util.AbstractSet;
 import java.util.Arrays;
@@ -39,6 +37,7 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.NavigableSet;
 import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.SortedSet;
@@ -513,103 +512,7 @@
    * @throws IllegalArgumentException if {@code map} is not empty
    */
   public static <E> Set<E> newSetFromMap(Map<E, Boolean> map) {
-    return new SetFromMap<E>(map);
-  }
-
-  private static class SetFromMap<E> extends AbstractSet<E> implements Set<E>, Serializable {
-    private final Map<E, Boolean> m; // The backing map
-    private transient Set<E> s; // Its keySet
-
-    SetFromMap(Map<E, Boolean> map) {
-      checkArgument(map.isEmpty(), "Map is non-empty");
-      m = map;
-      s = map.keySet();
-    }
-
-    @Override
-    public void clear() {
-      m.clear();
-    }
-
-    @Override
-    public int size() {
-      return m.size();
-    }
-
-    @Override
-    public boolean isEmpty() {
-      return m.isEmpty();
-    }
-
-    @Override
-    public boolean contains(Object o) {
-      return m.containsKey(o);
-    }
-
-    @Override
-    public boolean remove(Object o) {
-      return m.remove(o) != null;
-    }
-
-    @Override
-    public boolean add(E e) {
-      return m.put(e, Boolean.TRUE) == null;
-    }
-
-    @Override
-    public Iterator<E> iterator() {
-      return s.iterator();
-    }
-
-    @Override
-    public Object[] toArray() {
-      return s.toArray();
-    }
-
-    @Override
-    public <T> T[] toArray(T[] a) {
-      return s.toArray(a);
-    }
-
-    @Override
-    public String toString() {
-      return s.toString();
-    }
-
-    @Override
-    public int hashCode() {
-      return s.hashCode();
-    }
-
-    @Override
-    public boolean equals(@Nullable Object object) {
-      return this == object || this.s.equals(object);
-    }
-
-    @Override
-    public boolean containsAll(Collection<?> c) {
-      return s.containsAll(c);
-    }
-
-    @Override
-    public boolean removeAll(Collection<?> c) {
-      return s.removeAll(c);
-    }
-
-    @Override
-    public boolean retainAll(Collection<?> c) {
-      return s.retainAll(c);
-    }
-
-    // addAll is the only inherited implementation
-    @GwtIncompatible("not needed in emulated source")
-    private static final long serialVersionUID = 0;
-
-    @GwtIncompatible("java.io.ObjectInputStream")
-    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
-      stream.defaultReadObject();
-      s = m.keySet();
-    }
+    return Platform.newSetFromMap(map);
   }
 
   /**
@@ -970,6 +873,129 @@
   }
 
   /**
+   * Returns the elements of a {@code NavigableSet}, {@code unfiltered}, that
+   * satisfy a predicate. The returned set is a live view of {@code unfiltered};
+   * changes to one affect the other.
+   *
+   * <p>The resulting set's iterator does not support {@code remove()}, but all
+   * other set methods are supported. When given an element that doesn't satisfy
+   * the predicate, the set's {@code add()} and {@code addAll()} methods throw
+   * an {@link IllegalArgumentException}. When methods such as
+   * {@code removeAll()} and {@code clear()} are called on the filtered set,
+   * only elements that satisfy the filter will be removed from the underlying
+   * set.
+   *
+   * <p>The returned set isn't threadsafe or serializable, even if
+   * {@code unfiltered} is.
+   *
+   * <p>Many of the filtered set's methods, such as {@code size()}, iterate across
+   * every element in the underlying set and determine which elements satisfy
+   * the filter. When a live view is <i>not</i> needed, it may be faster to copy
+   * {@code Iterables.filter(unfiltered, predicate)} and use the copy.
+   *
+   * <p><b>Warning:</b> {@code predicate} must be <i>consistent with equals</i>,
+   * as documented at {@link Predicate#apply}. Do not provide a predicate such as
+   * {@code Predicates.instanceOf(ArrayList.class)}, which is inconsistent with
+   * equals. (See {@link Iterables#filter(Iterable, Class)} for related
+   * functionality.)
+   *
+   * @since 14.0
+   */
+  @GwtIncompatible("NavigableSet")
+  @SuppressWarnings("unchecked")
+  public static <E> NavigableSet<E> filter(
+      NavigableSet<E> unfiltered, Predicate<? super E> predicate) {
+    if (unfiltered instanceof FilteredSet) {
+      // Support clear(), removeAll(), and retainAll() when filtering a filtered
+      // collection.
+      FilteredSet<E> filtered = (FilteredSet<E>) unfiltered;
+      Predicate<E> combinedPredicate
+          = Predicates.<E>and(filtered.predicate, predicate);
+      return new FilteredNavigableSet<E>(
+          (NavigableSet<E>) filtered.unfiltered, combinedPredicate);
+    }
+
+    return new FilteredNavigableSet<E>(
+        checkNotNull(unfiltered), checkNotNull(predicate));
+  }
+
+  @GwtIncompatible("NavigableSet")
+  private static class FilteredNavigableSet<E> extends FilteredSortedSet<E>
+      implements NavigableSet<E> {
+    FilteredNavigableSet(NavigableSet<E> unfiltered, Predicate<? super E> predicate) {
+      super(unfiltered, predicate);
+    }
+
+    NavigableSet<E> unfiltered() {
+      return (NavigableSet<E>) unfiltered;
+    }
+
+    @Override
+    @Nullable
+    public E lower(E e) {
+      return Iterators.getNext(headSet(e, false).descendingIterator(), null);
+    }
+
+    @Override
+    @Nullable
+    public E floor(E e) {
+      return Iterators.getNext(headSet(e, true).descendingIterator(), null);
+    }
+
+    @Override
+    public E ceiling(E e) {
+      return Iterables.getFirst(tailSet(e, true), null);
+    }
+
+    @Override
+    public E higher(E e) {
+      return Iterables.getFirst(tailSet(e, false), null);
+    }
+
+    @Override
+    public E pollFirst() {
+      return Iterables.removeFirstMatching(unfiltered(), predicate);
+    }
+
+    @Override
+    public E pollLast() {
+      return Iterables.removeFirstMatching(unfiltered().descendingSet(), predicate);
+    }
+
+    @Override
+    public NavigableSet<E> descendingSet() {
+      return Sets.filter(unfiltered().descendingSet(), predicate);
+    }
+
+    @Override
+    public Iterator<E> descendingIterator() {
+      return Iterators.filter(unfiltered().descendingIterator(), predicate);
+    }
+
+    @Override
+    public E last() {
+      return descendingIterator().next();
+    }
+
+    @Override
+    public NavigableSet<E> subSet(
+        E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+      return filter(
+          unfiltered().subSet(fromElement, fromInclusive, toElement, toInclusive), predicate);
+    }
+
+    @Override
+    public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+      return filter(unfiltered().headSet(toElement, inclusive), predicate);
+    }
+
+    @Override
+    public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+      return filter(unfiltered().tailSet(fromElement, inclusive), predicate);
+    }
+  }
+
+  /**
    * Returns every possible list that can be formed by choosing one element
    * from each of the given sets in order; the "n-ary
    * <a href="http://en.wikipedia.org/wiki/Cartesian_product">Cartesian
@@ -1343,6 +1369,170 @@
   }
 
   /**
+   * Returns an unmodifiable view of the specified navigable set. This method
+   * allows modules to provide users with "read-only" access to internal
+   * navigable sets. Query operations on the returned set "read through" to the
+   * specified set, and attempts to modify the returned set, whether direct or
+   * via its collection views, result in an
+   * {@code UnsupportedOperationException}.
+   *
+   * <p>The returned navigable set will be serializable if the specified
+   * navigable set is serializable.
+   *
+   * @param set the navigable set for which an unmodifiable view is to be
+   *        returned
+   * @return an unmodifiable view of the specified navigable set
+   * @since 12.0
+   */
+  @GwtIncompatible("NavigableSet")
+  public static <E> NavigableSet<E> unmodifiableNavigableSet(
+      NavigableSet<E> set) {
+    if (set instanceof ImmutableSortedSet
+        || set instanceof UnmodifiableNavigableSet) {
+      return set;
+    }
+    return new UnmodifiableNavigableSet<E>(set);
+  }
+
+  @GwtIncompatible("NavigableSet")
+  static final class UnmodifiableNavigableSet<E>
+      extends ForwardingSortedSet<E> implements NavigableSet<E>, Serializable {
+    private final NavigableSet<E> delegate;
+
+    UnmodifiableNavigableSet(NavigableSet<E> delegate) {
+      this.delegate = checkNotNull(delegate);
+    }
+
+    @Override
+    protected SortedSet<E> delegate() {
+      return Collections.unmodifiableSortedSet(delegate);
+    }
+
+    @Override
+    public E lower(E e) {
+      return delegate.lower(e);
+    }
+
+    @Override
+    public E floor(E e) {
+      return delegate.floor(e);
+    }
+
+    @Override
+    public E ceiling(E e) {
+      return delegate.ceiling(e);
+    }
+
+    @Override
+    public E higher(E e) {
+      return delegate.higher(e);
+    }
+
+    @Override
+    public E pollFirst() {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public E pollLast() {
+      throw new UnsupportedOperationException();
+    }
+
+    private transient UnmodifiableNavigableSet<E> descendingSet;
+
+    @Override
+    public NavigableSet<E> descendingSet() {
+      UnmodifiableNavigableSet<E> result = descendingSet;
+      if (result == null) {
+        result = descendingSet = new UnmodifiableNavigableSet<E>(
+            delegate.descendingSet());
+        result.descendingSet = this;
+      }
+      return result;
+    }
+
+    @Override
+    public Iterator<E> descendingIterator() {
+      return Iterators.unmodifiableIterator(delegate.descendingIterator());
+    }
+
+    @Override
+    public NavigableSet<E> subSet(
+        E fromElement,
+        boolean fromInclusive,
+        E toElement,
+        boolean toInclusive) {
+      return unmodifiableNavigableSet(delegate.subSet(
+          fromElement,
+          fromInclusive,
+          toElement,
+          toInclusive));
+    }
+
+    @Override
+    public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+      return unmodifiableNavigableSet(delegate.headSet(toElement, inclusive));
+    }
+
+    @Override
+    public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+      return unmodifiableNavigableSet(
+          delegate.tailSet(fromElement, inclusive));
+    }
+
+    private static final long serialVersionUID = 0;
+  }
+
+  /**
+   * Returns a synchronized (thread-safe) navigable set backed by the specified
+   * navigable set.  In order to guarantee serial access, it is critical that
+   * <b>all</b> access to the backing navigable set is accomplished
+   * through the returned navigable set (or its views).
+   *
+   * <p>It is imperative that the user manually synchronize on the returned
+   * sorted set when iterating over it or any of its {@code descendingSet},
+   * {@code subSet}, {@code headSet}, or {@code tailSet} views. <pre>   {@code
+   *
+   *   NavigableSet<E> set = synchronizedNavigableSet(new TreeSet<E>());
+   *    ...
+   *   synchronized (set) {
+   *     // Must be in the synchronized block
+   *     Iterator<E> it = set.iterator();
+   *     while (it.hasNext()) {
+   *       foo(it.next());
+   *     }
+   *   }}</pre>
+   *
+   * <p>or: <pre>   {@code
+   *
+   *   NavigableSet<E> set = synchronizedNavigableSet(new TreeSet<E>());
+   *   NavigableSet<E> set2 = set.descendingSet().headSet(foo);
+   *    ...
+   *   synchronized (set) { // Note: set, not set2!!!
+   *     // Must be in the synchronized block
+   *     Iterator<E> it = set2.descendingIterator();
+   *     while (it.hasNext())
+   *       foo(it.next());
+   *     }
+   *   }}</pre>
+   *
+   * <p>Failure to follow this advice may result in non-deterministic behavior.
+   *
+   * <p>The returned navigable set will be serializable if the specified
+   * navigable set is serializable.
+   *
+   * @param navigableSet the navigable set to be "wrapped" in a synchronized
+   *    navigable set.
+   * @return a synchronized view of the specified navigable set.
+   * @since 13.0
+   */
+  @GwtIncompatible("NavigableSet")
+  public static <E> NavigableSet<E> synchronizedNavigableSet(
+      NavigableSet<E> navigableSet) {
+    return Synchronized.navigableSet(navigableSet);
+  }
+
+  /**
    * Remove each element in an iterable from a set.
    */
   static boolean removeAllImpl(Set<?> set, Iterator<?> iterator) {
@@ -1371,4 +1561,138 @@
       return removeAllImpl(set, collection.iterator());
     }
   }
+
+  @GwtIncompatible("NavigableSet")
+  static class DescendingSet<E> extends ForwardingNavigableSet<E> {
+    private final NavigableSet<E> forward;
+
+    DescendingSet(NavigableSet<E> forward) {
+      this.forward = forward;
+    }
+
+    @Override
+    protected NavigableSet<E> delegate() {
+      return forward;
+    }
+
+    @Override
+    public E lower(E e) {
+      return forward.higher(e);
+    }
+
+    @Override
+    public E floor(E e) {
+      return forward.ceiling(e);
+    }
+
+    @Override
+    public E ceiling(E e) {
+      return forward.floor(e);
+    }
+
+    @Override
+    public E higher(E e) {
+      return forward.lower(e);
+    }
+
+    @Override
+    public E pollFirst() {
+      return forward.pollLast();
+    }
+
+    @Override
+    public E pollLast() {
+      return forward.pollFirst();
+    }
+
+    @Override
+    public NavigableSet<E> descendingSet() {
+      return forward;
+    }
+
+    @Override
+    public Iterator<E> descendingIterator() {
+      return forward.iterator();
+    }
+
+    @Override
+    public NavigableSet<E> subSet(
+        E fromElement,
+        boolean fromInclusive,
+        E toElement,
+        boolean toInclusive) {
+      return forward.subSet(toElement, toInclusive, fromElement, fromInclusive).descendingSet();
+    }
+
+    @Override
+    public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+      return forward.tailSet(toElement, inclusive).descendingSet();
+    }
+
+    @Override
+    public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+      return forward.headSet(fromElement, inclusive).descendingSet();
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Comparator<? super E> comparator() {
+      Comparator<? super E> forwardComparator = forward.comparator();
+      if (forwardComparator == null) {
+        return (Comparator) Ordering.natural().reverse();
+      } else {
+        return reverse(forwardComparator);
+      }
+    }
+
+    // If we inline this, we get a javac error.
+    private static <T> Ordering<T> reverse(Comparator<T> forward) {
+      return Ordering.from(forward).reverse();
+    }
+
+    @Override
+    public E first() {
+      return forward.last();
+    }
+
+    @Override
+    public SortedSet<E> headSet(E toElement) {
+      return standardHeadSet(toElement);
+    }
+
+    @Override
+    public E last() {
+      return forward.first();
+    }
+
+    @Override
+    public SortedSet<E> subSet(E fromElement, E toElement) {
+      return standardSubSet(fromElement, toElement);
+    }
+
+    @Override
+    public SortedSet<E> tailSet(E fromElement) {
+      return standardTailSet(fromElement);
+    }
+
+    @Override
+    public Iterator<E> iterator() {
+      return forward.descendingIterator();
+    }
+
+    @Override
+    public Object[] toArray() {
+      return standardToArray();
+    }
+
+    @Override
+    public <T> T[] toArray(T[] array) {
+      return standardToArray(array);
+    }
+
+    @Override
+    public String toString() {
+      return standardToString();
+    }
+  }
 }
diff --git a/guava/src/com/google/common/collect/SortedMultiset.java b/guava/src/com/google/common/collect/SortedMultiset.java
index 8303a0a..de1f3e0 100644
--- a/guava/src/com/google/common/collect/SortedMultiset.java
+++ b/guava/src/com/google/common/collect/SortedMultiset.java
@@ -22,7 +22,7 @@
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.Iterator;
-import java.util.SortedSet;
+import java.util.NavigableSet;
 import java.util.Set;
 
 /**
@@ -80,11 +80,11 @@
   Entry<E> pollLastEntry();
 
   /**
-   * Returns a {@link SortedSet} view of the distinct elements in this multiset.
+   * Returns a {@link NavigableSet} view of the distinct elements in this multiset.
    * 
-   * @since 14.0
+   * @since 14.0 (present with return type {@code SortedSet} since 11.0)
    */
-  @Override SortedSet<E> elementSet();
+  @Override NavigableSet<E> elementSet();
   
   /**
    * {@inheritDoc}
diff --git a/guava/src/com/google/common/collect/SortedMultisets.java b/guava/src/com/google/common/collect/SortedMultisets.java
index e0d2974..1055664 100644
--- a/guava/src/com/google/common/collect/SortedMultisets.java
+++ b/guava/src/com/google/common/collect/SortedMultisets.java
@@ -25,6 +25,7 @@
 
 import java.util.Comparator;
 import java.util.Iterator;
+import java.util.NavigableSet;
 import java.util.NoSuchElementException;
 import java.util.SortedSet;
 
@@ -81,6 +82,76 @@
     }
   }
 
+  /**
+   * A skeleton navigable implementation for {@link SortedMultiset#elementSet}.
+   */
+  @GwtIncompatible("Navigable")
+  static class NavigableElementSet<E> extends ElementSet<E> implements NavigableSet<E> {
+    NavigableElementSet(SortedMultiset<E> multiset) {
+      super(multiset);
+    }
+
+    @Override
+    public E lower(E e) {
+      return getElementOrNull(multiset().headMultiset(e, OPEN).lastEntry());
+    }
+
+    @Override
+    public E floor(E e) {
+      return getElementOrNull(multiset().headMultiset(e, CLOSED).lastEntry());
+    }
+
+    @Override
+    public E ceiling(E e) {
+      return getElementOrNull(multiset().tailMultiset(e, CLOSED).firstEntry());
+    }
+
+    @Override
+    public E higher(E e) {
+      return getElementOrNull(multiset().tailMultiset(e, OPEN).firstEntry());
+    }
+
+    @Override
+    public NavigableSet<E> descendingSet() {
+      return new NavigableElementSet<E>(multiset().descendingMultiset());
+    }
+
+    @Override
+    public Iterator<E> descendingIterator() {
+      return descendingSet().iterator();
+    }
+
+    @Override
+    public E pollFirst() {
+      return getElementOrNull(multiset().pollFirstEntry());
+    }
+
+    @Override
+    public E pollLast() {
+      return getElementOrNull(multiset().pollLastEntry());
+    }
+
+    @Override
+    public NavigableSet<E> subSet(
+        E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+      return new NavigableElementSet<E>(multiset().subMultiset(
+          fromElement, BoundType.forBoolean(fromInclusive),
+          toElement, BoundType.forBoolean(toInclusive)));
+    }
+
+    @Override
+    public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+      return new NavigableElementSet<E>(
+          multiset().headMultiset(toElement, BoundType.forBoolean(inclusive)));
+    }
+
+    @Override
+    public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+      return new NavigableElementSet<E>(
+          multiset().tailMultiset(fromElement, BoundType.forBoolean(inclusive)));
+    }
+  }
+
   private static <E> E getElementOrThrow(Entry<E> entry) {
     if (entry == null) {
       throw new NoSuchElementException();
diff --git a/guava/src/com/google/common/collect/Synchronized.java b/guava/src/com/google/common/collect/Synchronized.java
index 850c81a..f8633bd 100644
--- a/guava/src/com/google/common/collect/Synchronized.java
+++ b/guava/src/com/google/common/collect/Synchronized.java
@@ -27,11 +27,14 @@
 import java.io.Serializable;
 import java.util.Collection;
 import java.util.Comparator;
+import java.util.Deque;
 import java.util.Iterator;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
 import java.util.Queue;
 import java.util.RandomAccess;
 import java.util.Set;
@@ -1218,6 +1221,350 @@
     private static final long serialVersionUID = 0;
   }
 
+  @GwtIncompatible("NavigableSet")
+  @VisibleForTesting
+  static class SynchronizedNavigableSet<E> extends SynchronizedSortedSet<E>
+      implements NavigableSet<E> {
+    SynchronizedNavigableSet(NavigableSet<E> delegate, @Nullable Object mutex) {
+      super(delegate, mutex);
+    }
+
+    @Override NavigableSet<E> delegate() {
+      return (NavigableSet<E>) super.delegate();
+    }
+
+    @Override public E ceiling(E e) {
+      synchronized (mutex) {
+        return delegate().ceiling(e);
+      }
+    }
+
+    @Override public Iterator<E> descendingIterator() {
+      return delegate().descendingIterator(); // manually synchronized
+    }
+
+    transient NavigableSet<E> descendingSet;
+
+    @Override public NavigableSet<E> descendingSet() {
+      synchronized (mutex) {
+        if (descendingSet == null) {
+          NavigableSet<E> dS =
+              Synchronized.navigableSet(delegate().descendingSet(), mutex);
+          descendingSet = dS;
+          return dS;
+        }
+        return descendingSet;
+      }
+    }
+
+    @Override public E floor(E e) {
+      synchronized (mutex) {
+        return delegate().floor(e);
+      }
+    }
+
+    @Override public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+      synchronized (mutex) {
+        return Synchronized.navigableSet(
+            delegate().headSet(toElement, inclusive), mutex);
+      }
+    }
+
+    @Override public E higher(E e) {
+      synchronized (mutex) {
+        return delegate().higher(e);
+      }
+    }
+
+    @Override public E lower(E e) {
+      synchronized (mutex) {
+        return delegate().lower(e);
+      }
+    }
+
+    @Override public E pollFirst() {
+      synchronized (mutex) {
+        return delegate().pollFirst();
+      }
+    }
+
+    @Override public E pollLast() {
+      synchronized (mutex) {
+        return delegate().pollLast();
+      }
+    }
+
+    @Override public NavigableSet<E> subSet(E fromElement,
+        boolean fromInclusive, E toElement, boolean toInclusive) {
+      synchronized (mutex) {
+        return Synchronized.navigableSet(delegate().subSet(
+            fromElement, fromInclusive, toElement, toInclusive), mutex);
+      }
+    }
+
+    @Override public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+      synchronized (mutex) {
+        return Synchronized.navigableSet(
+            delegate().tailSet(fromElement, inclusive), mutex);
+      }
+    }
+
+    @Override public SortedSet<E> headSet(E toElement) {
+      return headSet(toElement, false);
+    }
+
+    @Override public SortedSet<E> subSet(E fromElement, E toElement) {
+      return subSet(fromElement, true, toElement, false);
+    }
+
+    @Override public SortedSet<E> tailSet(E fromElement) {
+      return tailSet(fromElement, true);
+    }
+
+    private static final long serialVersionUID = 0;
+  }
+
+  @GwtIncompatible("NavigableSet")
+  static <E> NavigableSet<E> navigableSet(
+      NavigableSet<E> navigableSet, @Nullable Object mutex) {
+    return new SynchronizedNavigableSet<E>(navigableSet, mutex);
+  }
+
+  @GwtIncompatible("NavigableSet")
+  static <E> NavigableSet<E> navigableSet(NavigableSet<E> navigableSet) {
+    return navigableSet(navigableSet, null);
+  }
+
+  @GwtIncompatible("NavigableMap")
+  static <K, V> NavigableMap<K, V> navigableMap(
+      NavigableMap<K, V> navigableMap) {
+    return navigableMap(navigableMap, null);
+  }
+
+  @GwtIncompatible("NavigableMap")
+  static <K, V> NavigableMap<K, V> navigableMap(
+      NavigableMap<K, V> navigableMap, @Nullable Object mutex) {
+    return new SynchronizedNavigableMap<K, V>(navigableMap, mutex);
+  }
+
+  @GwtIncompatible("NavigableMap")
+  @VisibleForTesting static class SynchronizedNavigableMap<K, V>
+      extends SynchronizedSortedMap<K, V> implements NavigableMap<K, V> {
+
+    SynchronizedNavigableMap(
+        NavigableMap<K, V> delegate, @Nullable Object mutex) {
+      super(delegate, mutex);
+    }
+
+    @Override NavigableMap<K, V> delegate() {
+      return (NavigableMap<K, V>) super.delegate();
+    }
+
+    @Override public Entry<K, V> ceilingEntry(K key) {
+      synchronized (mutex) {
+        return nullableSynchronizedEntry(delegate().ceilingEntry(key), mutex);
+      }
+    }
+
+    @Override public K ceilingKey(K key) {
+      synchronized (mutex) {
+        return delegate().ceilingKey(key);
+      }
+    }
+
+    transient NavigableSet<K> descendingKeySet;
+
+    @Override public NavigableSet<K> descendingKeySet() {
+      synchronized (mutex) {
+        if (descendingKeySet == null) {
+          return descendingKeySet =
+              Synchronized.navigableSet(delegate().descendingKeySet(), mutex);
+        }
+        return descendingKeySet;
+      }
+    }
+
+    transient NavigableMap<K, V> descendingMap;
+
+    @Override public NavigableMap<K, V> descendingMap() {
+      synchronized (mutex) {
+        if (descendingMap == null) {
+          return descendingMap =
+              navigableMap(delegate().descendingMap(), mutex);
+        }
+        return descendingMap;
+      }
+    }
+
+    @Override public Entry<K, V> firstEntry() {
+      synchronized (mutex) {
+        return nullableSynchronizedEntry(delegate().firstEntry(), mutex);
+      }
+    }
+
+    @Override public Entry<K, V> floorEntry(K key) {
+      synchronized (mutex) {
+        return nullableSynchronizedEntry(delegate().floorEntry(key), mutex);
+      }
+    }
+
+    @Override public K floorKey(K key) {
+      synchronized (mutex) {
+        return delegate().floorKey(key);
+      }
+    }
+
+    @Override public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
+      synchronized (mutex) {
+        return navigableMap(
+            delegate().headMap(toKey, inclusive), mutex);
+      }
+    }
+
+    @Override public Entry<K, V> higherEntry(K key) {
+      synchronized (mutex) {
+        return nullableSynchronizedEntry(delegate().higherEntry(key), mutex);
+      }
+    }
+
+    @Override public K higherKey(K key) {
+      synchronized (mutex) {
+        return delegate().higherKey(key);
+      }
+    }
+
+    @Override public Entry<K, V> lastEntry() {
+      synchronized (mutex) {
+        return nullableSynchronizedEntry(delegate().lastEntry(), mutex);
+      }
+    }
+
+    @Override public Entry<K, V> lowerEntry(K key) {
+      synchronized (mutex) {
+        return nullableSynchronizedEntry(delegate().lowerEntry(key), mutex);
+      }
+    }
+
+    @Override public K lowerKey(K key) {
+      synchronized (mutex) {
+        return delegate().lowerKey(key);
+      }
+    }
+
+    @Override public Set<K> keySet() {
+      return navigableKeySet();
+    }
+
+    transient NavigableSet<K> navigableKeySet;
+
+    @Override public NavigableSet<K> navigableKeySet() {
+      synchronized (mutex) {
+        if (navigableKeySet == null) {
+          return navigableKeySet =
+              Synchronized.navigableSet(delegate().navigableKeySet(), mutex);
+        }
+        return navigableKeySet;
+      }
+    }
+
+    @Override public Entry<K, V> pollFirstEntry() {
+      synchronized (mutex) {
+        return nullableSynchronizedEntry(delegate().pollFirstEntry(), mutex);
+      }
+    }
+
+    @Override public Entry<K, V> pollLastEntry() {
+      synchronized (mutex) {
+        return nullableSynchronizedEntry(delegate().pollLastEntry(), mutex);
+      }
+    }
+
+    @Override public NavigableMap<K, V> subMap(
+        K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+      synchronized (mutex) {
+        return navigableMap(
+            delegate().subMap(fromKey, fromInclusive, toKey, toInclusive),
+            mutex);
+      }
+    }
+
+    @Override public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
+      synchronized (mutex) {
+        return navigableMap(
+            delegate().tailMap(fromKey, inclusive), mutex);
+      }
+    }
+
+    @Override public SortedMap<K, V> headMap(K toKey) {
+      return headMap(toKey, false);
+    }
+
+    @Override public SortedMap<K, V> subMap(K fromKey, K toKey) {
+      return subMap(fromKey, true, toKey, false);
+    }
+
+    @Override public SortedMap<K, V> tailMap(K fromKey) {
+      return tailMap(fromKey, true);
+    }
+
+    private static final long serialVersionUID = 0;
+  }
+
+  @GwtIncompatible("works but is needed only for NavigableMap")
+  private static <K, V> Entry<K, V> nullableSynchronizedEntry(
+      @Nullable Entry<K, V> entry, @Nullable Object mutex) {
+    if (entry == null) {
+      return null;
+    }
+    return new SynchronizedEntry<K, V>(entry, mutex);
+  }
+
+  @GwtIncompatible("works but is needed only for NavigableMap")
+  private static class SynchronizedEntry<K, V> extends SynchronizedObject
+      implements Entry<K, V> {
+
+    SynchronizedEntry(Entry<K, V> delegate, @Nullable Object mutex) {
+      super(delegate, mutex);
+    }
+
+    @SuppressWarnings("unchecked") // guaranteed by the constructor
+    @Override Entry<K, V> delegate() {
+      return (Entry<K, V>) super.delegate();
+    }
+
+    @Override public boolean equals(Object obj) {
+      synchronized (mutex) {
+        return delegate().equals(obj);
+      }
+    }
+
+    @Override public int hashCode() {
+      synchronized (mutex) {
+        return delegate().hashCode();
+      }
+    }
+
+    @Override public K getKey() {
+      synchronized (mutex) {
+        return delegate().getKey();
+      }
+    }
+
+    @Override public V getValue() {
+      synchronized (mutex) {
+        return delegate().getValue();
+      }
+    }
+
+    @Override public V setValue(V value) {
+      synchronized (mutex) {
+        return delegate().setValue(value);
+      }
+    }
+
+    private static final long serialVersionUID = 0;
+  }
+
   static <E> Queue<E> queue(Queue<E> queue, @Nullable Object mutex) {
     return (queue instanceof SynchronizedQueue)
         ? queue
@@ -1272,4 +1619,143 @@
 
     private static final long serialVersionUID = 0;
   }
+
+  @GwtIncompatible("Deque")
+  static <E> Deque<E> deque(Deque<E> deque, @Nullable Object mutex) {
+    return new SynchronizedDeque<E>(deque, mutex);
+  }
+
+  @GwtIncompatible("Deque")
+  private static final class SynchronizedDeque<E>
+      extends SynchronizedQueue<E> implements Deque<E> {
+
+    SynchronizedDeque(Deque<E> delegate, @Nullable Object mutex) {
+      super(delegate, mutex);
+    }
+
+    @Override Deque<E> delegate() {
+      return (Deque<E>) super.delegate();
+    }
+
+    @Override
+    public void addFirst(E e) {
+      synchronized (mutex) {
+        delegate().addFirst(e);
+      }
+    }
+
+    @Override
+    public void addLast(E e) {
+      synchronized (mutex) {
+        delegate().addLast(e);
+      }
+    }
+
+    @Override
+    public boolean offerFirst(E e) {
+      synchronized (mutex) {
+        return delegate().offerFirst(e);
+      }
+    }
+
+    @Override
+    public boolean offerLast(E e) {
+      synchronized (mutex) {
+        return delegate().offerLast(e);
+      }
+    }
+
+    @Override
+    public E removeFirst() {
+      synchronized (mutex) {
+        return delegate().removeFirst();
+      }
+    }
+
+    @Override
+    public E removeLast() {
+      synchronized (mutex) {
+        return delegate().removeLast();
+      }
+    }
+
+    @Override
+    public E pollFirst() {
+      synchronized (mutex) {
+        return delegate().pollFirst();
+      }
+    }
+
+    @Override
+    public E pollLast() {
+      synchronized (mutex) {
+        return delegate().pollLast();
+      }
+    }
+
+    @Override
+    public E getFirst() {
+      synchronized (mutex) {
+        return delegate().getFirst();
+      }
+    }
+
+    @Override
+    public E getLast() {
+      synchronized (mutex) {
+        return delegate().getLast();
+      }
+    }
+
+    @Override
+    public E peekFirst() {
+      synchronized (mutex) {
+        return delegate().peekFirst();
+      }
+    }
+
+    @Override
+    public E peekLast() {
+      synchronized (mutex) {
+        return delegate().peekLast();
+      }
+    }
+
+    @Override
+    public boolean removeFirstOccurrence(Object o) {
+      synchronized (mutex) {
+        return delegate().removeFirstOccurrence(o);
+      }
+    }
+
+    @Override
+    public boolean removeLastOccurrence(Object o) {
+      synchronized (mutex) {
+        return delegate().removeLastOccurrence(o);
+      }
+    }
+
+    @Override
+    public void push(E e) {
+      synchronized (mutex) {
+        delegate().push(e);
+      }
+    }
+
+    @Override
+    public E pop() {
+      synchronized (mutex) {
+        return delegate().pop();
+      }
+    }
+
+    @Override
+    public Iterator<E> descendingIterator() {
+      synchronized (mutex) {
+        return delegate().descendingIterator();
+      }
+    }
+
+    private static final long serialVersionUID = 0;
+  }
 }
diff --git a/guava/src/com/google/common/collect/TreeMultimap.java b/guava/src/com/google/common/collect/TreeMultimap.java
index 8237493..433774d 100644
--- a/guava/src/com/google/common/collect/TreeMultimap.java
+++ b/guava/src/com/google/common/collect/TreeMultimap.java
@@ -25,9 +25,9 @@
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Comparator;
-import java.util.SortedMap;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
 import java.util.SortedSet;
 import java.util.TreeMap;
 import java.util.TreeSet;
@@ -169,64 +169,72 @@
    */
   
   @Override
-  SortedMap<K, Collection<V>> backingMap() {
-    return (SortedMap<K, Collection<V>>) super.backingMap();
+  @GwtIncompatible("NavigableMap")
+  NavigableMap<K, Collection<V>> backingMap() {
+    return (NavigableMap<K, Collection<V>>) super.backingMap();
   }
   
   /**
    * @since 14.0 (present with return type {@code SortedSet} since 2.0)
    */
   @Override
-  public SortedSet<V> get(@Nullable K key) {
-    return (SortedSet<V>) super.get(key);
+  @GwtIncompatible("NavigableSet")
+  public NavigableSet<V> get(@Nullable K key) {
+    return (NavigableSet<V>) super.get(key);
   }
 
   @Override
+  @GwtIncompatible("NavigableSet")
   Collection<V> unmodifiableCollectionSubclass(Collection<V> collection) {
-    return Collections.unmodifiableSortedSet((SortedSet<V>) collection);
+    return Sets.unmodifiableNavigableSet((NavigableSet<V>) collection);
   }
 
   @Override
+  @GwtIncompatible("NavigableSet")
   Collection<V> wrapCollection(K key, Collection<V> collection) {
-    return new WrappedSortedSet(key, (SortedSet<V>) collection, null);
+    return new WrappedNavigableSet(key, (NavigableSet<V>) collection, null);
   }
 
   /**
    * {@inheritDoc}
    *
    * <p>Because a {@code TreeMultimap} has unique sorted keys, this method
-   * returns a {@link SortedSet}, instead of the {@link java.util.Set} specified
+   * returns a {@link NavigableSet}, instead of the {@link java.util.Set} specified
    * in the {@link Multimap} interface.
    * 
    * @since 14.0 (present with return type {@code SortedSet} since 2.0)
    */
   @Override
-  public SortedSet<K> keySet() {
-    return (SortedSet<K>) super.keySet();
+  @GwtIncompatible("NavigableSet") 
+  public NavigableSet<K> keySet() {
+    return (NavigableSet<K>) super.keySet();
   }
 
   @Override
-  SortedSet<K> createKeySet() {
-    return new SortedKeySet(backingMap());
+  @GwtIncompatible("NavigableSet")
+  NavigableSet<K> createKeySet() {
+    return new NavigableKeySet(backingMap());
   }
 
   /**
    * {@inheritDoc}
    *
    * <p>Because a {@code TreeMultimap} has unique sorted keys, this method
-   * returns a {@link SortedMap}, instead of the {@link java.util.Map} specified
+   * returns a {@link NavigableMap}, instead of the {@link java.util.Map} specified
    * in the {@link Multimap} interface.
    * 
    * @since 14.0 (present with return type {@code SortedMap} since 2.0)
    */
   @Override 
-  public SortedMap<K, Collection<V>> asMap() {
-    return (SortedMap<K, Collection<V>>) super.asMap();
+  @GwtIncompatible("NavigableMap")
+  public NavigableMap<K, Collection<V>> asMap() {
+    return (NavigableMap<K, Collection<V>>) super.asMap();
   }
 
   @Override
-  SortedMap<K, Collection<V>> createAsMap() {
-    return new SortedAsMap(backingMap());
+  @GwtIncompatible("NavigableMap")
+  NavigableMap<K, Collection<V>> createAsMap() {
+    return new NavigableAsMap(backingMap());
   }
 
   /**
diff --git a/guava/src/com/google/common/collect/TreeMultiset.java b/guava/src/com/google/common/collect/TreeMultiset.java
index 39f967f..cd4c445 100644
--- a/guava/src/com/google/common/collect/TreeMultiset.java
+++ b/guava/src/com/google/common/collect/TreeMultiset.java
@@ -23,7 +23,7 @@
 
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.annotations.GwtIncompatible;
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
 import com.google.common.primitives.Ints;
 
 import java.io.IOException;
@@ -899,7 +899,7 @@
     @Nullable private AvlNode<E> ceiling(Comparator<? super E> comparator, E e) {
       int cmp = comparator.compare(e, elem);
       if (cmp < 0) {
-        return (left == null) ? this : Objects.firstNonNull(left.ceiling(comparator, e), this);
+        return (left == null) ? this : MoreObjects.firstNonNull(left.ceiling(comparator, e), this);
       } else if (cmp == 0) {
         return this;
       } else {
@@ -910,7 +910,7 @@
     @Nullable private AvlNode<E> floor(Comparator<? super E> comparator, E e) {
       int cmp = comparator.compare(e, elem);
       if (cmp > 0) {
-        return (right == null) ? this : Objects.firstNonNull(right.floor(comparator, e), this);
+        return (right == null) ? this : MoreObjects.firstNonNull(right.floor(comparator, e), this);
       } else if (cmp == 0) {
         return this;
       } else {
diff --git a/guava/src/com/google/common/collect/TreeRangeMap.java b/guava/src/com/google/common/collect/TreeRangeMap.java
new file mode 100644
index 0000000..82c3206
--- /dev/null
+++ b/guava/src/com/google/common/collect/TreeRangeMap.java
@@ -0,0 +1,607 @@
+/*
+ * Copyright (C) 2012 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Predicates.compose;
+import static com.google.common.base.Predicates.in;
+import static com.google.common.base.Predicates.not;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Predicate;
+
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NavigableMap;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * An implementation of {@code RangeMap} based on a {@code TreeMap}, supporting
+ * all optional operations.
+ *
+ * <p>Like all {@code RangeMap} implementations, this supports neither null
+ * keys nor null values.
+ *
+ * @author Louis Wasserman
+ * @since 14.0
+ */
+@Beta
+@GwtIncompatible("NavigableMap")
+public final class TreeRangeMap<K extends Comparable, V> implements RangeMap<K, V> {
+
+  private final NavigableMap<Cut<K>, RangeMapEntry<K, V>> entriesByLowerBound;
+
+  public static <K extends Comparable, V> TreeRangeMap<K, V> create() {
+    return new TreeRangeMap<K, V>();
+  }
+
+  private TreeRangeMap() {
+    this.entriesByLowerBound = Maps.newTreeMap();
+  }
+
+  private static final class RangeMapEntry<K extends Comparable, V>
+      extends AbstractMapEntry<Range<K>, V> {
+    private final Range<K> range;
+    private final V value;
+
+    RangeMapEntry(Cut<K> lowerBound, Cut<K> upperBound, V value) {
+      this(Range.create(lowerBound, upperBound), value);
+    }
+
+    RangeMapEntry(Range<K> range, V value) {
+      this.range = range;
+      this.value = value;
+    }
+
+    @Override
+    public Range<K> getKey() {
+      return range;
+    }
+
+    @Override
+    public V getValue() {
+      return value;
+    }
+
+    public boolean contains(K value) {
+      return range.contains(value);
+    }
+
+    Cut<K> getLowerBound() {
+      return range.lowerBound;
+    }
+
+    Cut<K> getUpperBound() {
+      return range.upperBound;
+    }
+  }
+
+  @Override
+  @Nullable
+  public V get(K key) {
+    Entry<Range<K>, V> entry = getEntry(key);
+    return (entry == null) ? null : entry.getValue();
+  }
+
+  @Override
+  @Nullable
+  public Entry<Range<K>, V> getEntry(K key) {
+    Map.Entry<Cut<K>, RangeMapEntry<K, V>> mapEntry =
+        entriesByLowerBound.floorEntry(Cut.belowValue(key));
+    if (mapEntry != null && mapEntry.getValue().contains(key)) {
+      return mapEntry.getValue();
+    } else {
+      return null;
+    }
+  }
+
+  @Override
+  public void put(Range<K> range, V value) {
+    if (!range.isEmpty()) {
+      checkNotNull(value);
+      remove(range);
+      entriesByLowerBound.put(range.lowerBound, new RangeMapEntry<K, V>(range, value));
+    }
+  }
+
+  @Override
+  public void putAll(RangeMap<K, V> rangeMap) {
+    for (Map.Entry<Range<K>, V> entry : rangeMap.asMapOfRanges().entrySet()) {
+      put(entry.getKey(), entry.getValue());
+    }
+  }
+
+  @Override
+  public void clear() {
+    entriesByLowerBound.clear();
+  }
+
+  @Override
+  public Range<K> span() {
+    Entry<Cut<K>, RangeMapEntry<K, V>> firstEntry = entriesByLowerBound.firstEntry();
+    Entry<Cut<K>, RangeMapEntry<K, V>> lastEntry = entriesByLowerBound.lastEntry();
+    if (firstEntry == null) {
+      throw new NoSuchElementException();
+    }
+    return Range.create(
+        firstEntry.getValue().getKey().lowerBound,
+        lastEntry.getValue().getKey().upperBound);
+  }
+
+  private void putRangeMapEntry(Cut<K> lowerBound, Cut<K> upperBound, V value) {
+    entriesByLowerBound.put(lowerBound, new RangeMapEntry<K, V>(lowerBound, upperBound, value));
+  }
+
+  @Override
+  public void remove(Range<K> rangeToRemove) {
+    if (rangeToRemove.isEmpty()) {
+      return;
+    }
+
+    /*
+     * The comments for this method will use [ ] to indicate the bounds of rangeToRemove and ( ) to
+     * indicate the bounds of ranges in the range map.
+     */
+    Map.Entry<Cut<K>, RangeMapEntry<K, V>> mapEntryBelowToTruncate =
+        entriesByLowerBound.lowerEntry(rangeToRemove.lowerBound);
+    if (mapEntryBelowToTruncate != null) {
+      // we know ( [
+      RangeMapEntry<K, V> rangeMapEntry = mapEntryBelowToTruncate.getValue();
+      if (rangeMapEntry.getUpperBound().compareTo(rangeToRemove.lowerBound) > 0) {
+        // we know ( [ )
+        if (rangeMapEntry.getUpperBound().compareTo(rangeToRemove.upperBound) > 0) {
+          // we know ( [ ] ), so insert the range ] ) back into the map --
+          // it's being split apart
+          putRangeMapEntry(rangeToRemove.upperBound, rangeMapEntry.getUpperBound(),
+              mapEntryBelowToTruncate.getValue().getValue());
+        }
+        // overwrite mapEntryToTruncateBelow with a truncated range
+        putRangeMapEntry(rangeMapEntry.getLowerBound(), rangeToRemove.lowerBound,
+            mapEntryBelowToTruncate.getValue().getValue());
+      }
+    }
+
+    Map.Entry<Cut<K>, RangeMapEntry<K, V>> mapEntryAboveToTruncate =
+        entriesByLowerBound.lowerEntry(rangeToRemove.upperBound);
+    if (mapEntryAboveToTruncate != null) {
+      // we know ( ]
+      RangeMapEntry<K, V> rangeMapEntry = mapEntryAboveToTruncate.getValue();
+      if (rangeMapEntry.getUpperBound().compareTo(rangeToRemove.upperBound) > 0) {
+        // we know ( ] ), and since we dealt with truncating below already,
+        // we know [ ( ] )
+        putRangeMapEntry(rangeToRemove.upperBound, rangeMapEntry.getUpperBound(),
+            mapEntryAboveToTruncate.getValue().getValue());
+        entriesByLowerBound.remove(rangeToRemove.lowerBound);
+      }
+    }
+    entriesByLowerBound.subMap(rangeToRemove.lowerBound, rangeToRemove.upperBound).clear();
+  }
+
+  @Override
+  public Map<Range<K>, V> asMapOfRanges() {
+    return new AsMapOfRanges();
+  }
+
+  private final class AsMapOfRanges extends AbstractMap<Range<K>, V> {
+
+    @Override
+    public boolean containsKey(@Nullable Object key) {
+      return get(key) != null;
+    }
+
+    @Override
+    public V get(@Nullable Object key) {
+      if (key instanceof Range) {
+        Range<?> range = (Range<?>) key;
+        RangeMapEntry<K, V> rangeMapEntry = entriesByLowerBound.get(range.lowerBound);
+        if (rangeMapEntry != null && rangeMapEntry.getKey().equals(range)) {
+          return rangeMapEntry.getValue();
+        }
+      }
+      return null;
+    }
+
+    @Override
+    public Set<Entry<Range<K>, V>> entrySet() {
+      return new AbstractSet<Entry<Range<K>, V>>() {
+
+        @SuppressWarnings("unchecked") // it's safe to upcast iterators
+        @Override
+        public Iterator<Entry<Range<K>, V>> iterator() {
+          return (Iterator) entriesByLowerBound.values().iterator();
+        }
+
+        @Override
+        public int size() {
+          return entriesByLowerBound.size();
+        }
+      };
+    }
+  }
+  
+  @Override
+  public RangeMap<K, V> subRangeMap(Range<K> subRange) {
+    if (subRange.equals(Range.all())) {
+      return this;
+    } else {
+      return new SubRangeMap(subRange);
+    }
+  }
+  
+  @SuppressWarnings("unchecked")
+  private RangeMap<K, V> emptySubRangeMap() {
+    return EMPTY_SUB_RANGE_MAP;
+  }
+  
+  private static final RangeMap EMPTY_SUB_RANGE_MAP = 
+      new RangeMap() {
+        @Override
+        @Nullable
+        public Object get(Comparable key) {
+          return null;
+        }
+
+        @Override
+        @Nullable
+        public Entry<Range, Object> getEntry(Comparable key) {
+          return null;
+        }
+
+        @Override
+        public Range span() {
+          throw new NoSuchElementException();
+        }
+
+        @Override
+        public void put(Range range, Object value) {
+          checkNotNull(range);
+          throw new IllegalArgumentException(
+              "Cannot insert range " + range + " into an empty subRangeMap");
+        }
+
+        @Override
+        public void putAll(RangeMap rangeMap) {
+          if (!rangeMap.asMapOfRanges().isEmpty()) {
+            throw new IllegalArgumentException(
+                "Cannot putAll(nonEmptyRangeMap) into an empty " + "subRangeMap");
+          }
+        }
+
+        @Override
+        public void clear() {}
+
+        @Override
+        public void remove(Range range) {
+          checkNotNull(range);
+        }
+
+        @Override
+        public Map<Range, Object> asMapOfRanges() {
+          return Collections.emptyMap();
+        }
+
+        @Override
+        public RangeMap subRangeMap(Range range) {
+          checkNotNull(range);
+          return this;
+        }
+      };
+  
+  private class SubRangeMap implements RangeMap<K, V> {
+
+    private final Range<K> subRange;
+    
+    SubRangeMap(Range<K> subRange) {
+      this.subRange = subRange;
+    }
+
+    @Override
+    @Nullable
+    public V get(K key) {
+      return subRange.contains(key)
+          ? TreeRangeMap.this.get(key)
+          : null;
+    }
+
+    @Override
+    @Nullable
+    public Entry<Range<K>, V> getEntry(K key) {
+      if (subRange.contains(key)) {
+        Entry<Range<K>, V> entry = TreeRangeMap.this.getEntry(key);
+        if (entry != null) {
+          return Maps.immutableEntry(entry.getKey().intersection(subRange), entry.getValue());
+        }
+      }
+      return null;
+    }
+
+    @Override
+    public Range<K> span() {
+      Cut<K> lowerBound;
+      Entry<Cut<K>, RangeMapEntry<K, V>> lowerEntry =
+          entriesByLowerBound.floorEntry(subRange.lowerBound);
+      if (lowerEntry != null && 
+          lowerEntry.getValue().getUpperBound().compareTo(subRange.lowerBound) > 0) {
+        lowerBound = subRange.lowerBound;
+      } else {
+        lowerBound = entriesByLowerBound.ceilingKey(subRange.lowerBound);
+        if (lowerBound == null || lowerBound.compareTo(subRange.upperBound) >= 0) {
+          throw new NoSuchElementException();
+        }
+      }
+      
+      Cut<K> upperBound;
+      Entry<Cut<K>, RangeMapEntry<K, V>> upperEntry = 
+          entriesByLowerBound.lowerEntry(subRange.upperBound);
+      if (upperEntry == null) {
+        throw new NoSuchElementException();
+      } else if (upperEntry.getValue().getUpperBound().compareTo(subRange.upperBound) >= 0) {
+        upperBound = subRange.upperBound;
+      } else {
+        upperBound = upperEntry.getValue().getUpperBound();
+      }
+      return Range.create(lowerBound, upperBound);
+    }
+
+    @Override
+    public void put(Range<K> range, V value) {
+      checkArgument(subRange.encloses(range), 
+          "Cannot put range %s into a subRangeMap(%s)", range, subRange);
+      TreeRangeMap.this.put(range, value);
+    }
+
+    @Override
+    public void putAll(RangeMap<K, V> rangeMap) {
+      if (rangeMap.asMapOfRanges().isEmpty()) {
+        return;
+      }
+      Range<K> span = rangeMap.span();
+      checkArgument(subRange.encloses(span), 
+          "Cannot putAll rangeMap with span %s into a subRangeMap(%s)", span, subRange);
+      TreeRangeMap.this.putAll(rangeMap);
+    }
+
+    @Override
+    public void clear() {
+      TreeRangeMap.this.remove(subRange);
+    }
+
+    @Override
+    public void remove(Range<K> range) {
+      if (range.isConnected(subRange)) {
+        TreeRangeMap.this.remove(range.intersection(subRange));
+      }
+    }
+
+    @Override
+    public RangeMap<K, V> subRangeMap(Range<K> range) {
+      if (!range.isConnected(subRange)) {
+        return emptySubRangeMap();
+      } else {
+        return TreeRangeMap.this.subRangeMap(range.intersection(subRange));
+      }
+    }
+
+    @Override
+    public Map<Range<K>, V> asMapOfRanges() {
+      return new SubRangeMapAsMap();
+    }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+      if (o instanceof RangeMap) {
+        RangeMap<?, ?> rangeMap = (RangeMap<?, ?>) o;
+        return asMapOfRanges().equals(rangeMap.asMapOfRanges());
+      }
+      return false;
+    }
+
+    @Override
+    public int hashCode() {
+      return asMapOfRanges().hashCode();
+    }
+
+    @Override
+    public String toString() {
+      return asMapOfRanges().toString();
+    }
+    
+    class SubRangeMapAsMap extends AbstractMap<Range<K>, V> {
+      
+      @Override
+      public boolean containsKey(Object key) {
+        return get(key) != null;
+      }
+
+      @Override
+      public V get(Object key) {
+        try {
+          if (key instanceof Range) {
+            @SuppressWarnings("unchecked") // we catch ClassCastExceptions
+            Range<K> r = (Range<K>) key;
+            if (!subRange.encloses(r) || r.isEmpty()) {
+              return null;
+            }
+            RangeMapEntry<K, V> candidate = null;
+            if (r.lowerBound.compareTo(subRange.lowerBound) == 0) {
+              // r could be truncated on the left
+              Entry<Cut<K>, RangeMapEntry<K, V>> entry = 
+                  entriesByLowerBound.floorEntry(r.lowerBound);
+              if (entry != null) {
+                candidate = entry.getValue();
+              }
+            } else {
+              candidate = entriesByLowerBound.get(r.lowerBound);
+            }
+            
+            if (candidate != null && candidate.getKey().isConnected(subRange)
+                && candidate.getKey().intersection(subRange).equals(r)) {
+              return candidate.getValue();
+            }
+          }
+        } catch (ClassCastException e) {
+          return null;
+        }
+        return null;
+      }
+
+      @Override
+      public V remove(Object key) {
+        V value = get(key);
+        if (value != null) {
+          @SuppressWarnings("unchecked") // it's definitely in the map, so safe
+          Range<K> range = (Range<K>) key;
+          TreeRangeMap.this.remove(range);
+          return value;
+        }
+        return null;
+      }
+
+      @Override
+      public void clear() {
+        SubRangeMap.this.clear();
+      }
+      
+      private boolean removeEntryIf(Predicate<? super Entry<Range<K>, V>> predicate) {
+        List<Range<K>> toRemove = Lists.newArrayList();
+        for (Entry<Range<K>, V> entry : entrySet()) {
+          if (predicate.apply(entry)) {
+            toRemove.add(entry.getKey());
+          }
+        }
+        for (Range<K> range : toRemove) {
+          TreeRangeMap.this.remove(range);
+        }
+        return !toRemove.isEmpty();
+      }
+
+      @Override
+      public Set<Range<K>> keySet() {
+        return new Maps.KeySet<Range<K>, V>(SubRangeMapAsMap.this) {
+          @Override
+          public boolean remove(@Nullable Object o) {
+            return SubRangeMapAsMap.this.remove(o) != null;
+          }
+          
+          @Override
+          public boolean retainAll(Collection<?> c) {
+            return removeEntryIf(compose(not(in(c)), Maps.<Range<K>>keyFunction()));
+          }
+        };
+      }
+
+      @Override
+      public Set<Entry<Range<K>, V>> entrySet() {
+        return new Maps.EntrySet<Range<K>, V>() {
+          @Override
+          Map<Range<K>, V> map() {
+            return SubRangeMapAsMap.this;
+          }
+
+          @Override
+          public Iterator<Entry<Range<K>, V>> iterator() {
+            if (subRange.isEmpty()) {
+              return Iterators.emptyIterator();
+            }
+            Cut<K> cutToStart = MoreObjects.firstNonNull(
+                entriesByLowerBound.floorKey(subRange.lowerBound), subRange.lowerBound);
+            final Iterator<RangeMapEntry<K, V>> backingItr = 
+                entriesByLowerBound.tailMap(cutToStart, true).values().iterator();
+            return new AbstractIterator<Entry<Range<K>, V>>() {
+
+              @Override
+              protected Entry<Range<K>, V> computeNext() {
+                while (backingItr.hasNext()) {
+                  RangeMapEntry<K, V> entry = backingItr.next();
+                  if (entry.getLowerBound().compareTo(subRange.upperBound) >= 0) {
+                    break;
+                  } else if (entry.getUpperBound().compareTo(subRange.lowerBound) > 0) {
+                    // this might not be true e.g. at the start of the iteration
+                    return Maps.immutableEntry(
+                        entry.getKey().intersection(subRange), entry.getValue());
+                  }
+                }
+                return endOfData();
+              }
+            };
+          }
+          
+          @Override
+          public boolean retainAll(Collection<?> c) {
+            return removeEntryIf(not(in(c)));
+          }
+          
+          @Override
+          public int size() {
+            return Iterators.size(iterator());
+          }
+          
+          @Override
+          public boolean isEmpty() {
+            return !iterator().hasNext();
+          }
+        };
+      }
+      
+      @Override
+      public Collection<V> values() {
+        return new Maps.Values<Range<K>, V>(this) {          
+          @Override
+          public boolean removeAll(Collection<?> c) {
+            return removeEntryIf(compose(in(c), Maps.<V>valueFunction()));            
+          }
+          
+          @Override
+          public boolean retainAll(Collection<?> c) {
+            return removeEntryIf(compose(not(in(c)), Maps.<V>valueFunction()));
+          }
+        };
+      }
+    }
+  }
+
+  @Override
+  public boolean equals(@Nullable Object o) {
+    if (o instanceof RangeMap) {
+      RangeMap<?, ?> rangeMap = (RangeMap<?, ?>) o;
+      return asMapOfRanges().equals(rangeMap.asMapOfRanges());
+    }
+    return false;
+  }
+
+  @Override
+  public int hashCode() {
+    return asMapOfRanges().hashCode();
+  }
+
+  @Override
+  public String toString() {
+    return entriesByLowerBound.values().toString();
+  }
+}
diff --git a/guava/src/com/google/common/collect/TreeRangeSet.java b/guava/src/com/google/common/collect/TreeRangeSet.java
new file mode 100644
index 0000000..606b3bc
--- /dev/null
+++ b/guava/src/com/google/common/collect/TreeRangeSet.java
@@ -0,0 +1,851 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.common.collect;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.MoreObjects;
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.NavigableMap;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.TreeMap;
+
+import javax.annotation.Nullable;
+
+/**
+ * An implementation of {@link RangeSet} backed by a {@link TreeMap}.
+ *
+ * @author Louis Wasserman
+ * @since 14.0
+ */
+@Beta
+@GwtIncompatible("uses NavigableMap")
+public class TreeRangeSet<C extends Comparable<?>>
+    extends AbstractRangeSet<C> {
+
+  @VisibleForTesting
+  final NavigableMap<Cut<C>, Range<C>> rangesByLowerBound;
+
+  /**
+   * Creates an empty {@code TreeRangeSet} instance.
+   */
+  public static <C extends Comparable<?>> TreeRangeSet<C> create() {
+    return new TreeRangeSet<C>(new TreeMap<Cut<C>, Range<C>>());
+  }
+  
+  /**
+   * Returns a {@code TreeRangeSet} initialized with the ranges in the specified range set.
+   */
+  public static <C extends Comparable<?>> TreeRangeSet<C> create(RangeSet<C> rangeSet) {
+    TreeRangeSet<C> result = create();
+    result.addAll(rangeSet);
+    return result;
+  }
+
+  private TreeRangeSet(NavigableMap<Cut<C>, Range<C>> rangesByLowerCut) {
+    this.rangesByLowerBound = rangesByLowerCut;
+  }
+
+  private transient Set<Range<C>> asRanges;
+
+  @Override
+  public Set<Range<C>> asRanges() {
+    Set<Range<C>> result = asRanges;
+    return (result == null) ? asRanges = new AsRanges() : result;
+  }
+
+  final class AsRanges extends ForwardingCollection<Range<C>> implements Set<Range<C>> {
+    @Override
+    protected Collection<Range<C>> delegate() {
+      return rangesByLowerBound.values();
+    }
+
+    @Override
+    public int hashCode() {
+      return Sets.hashCodeImpl(this);
+    }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+      return Sets.equalsImpl(this, o);
+    }
+  }
+
+  @Override
+  @Nullable
+  public Range<C> rangeContaining(C value) {
+    checkNotNull(value);
+    Entry<Cut<C>, Range<C>> floorEntry = rangesByLowerBound.floorEntry(Cut.belowValue(value));
+    if (floorEntry != null && floorEntry.getValue().contains(value)) {
+      return floorEntry.getValue();
+    } else {
+      // TODO(kevinb): revisit this design choice
+      return null;
+    }
+  }
+
+  @Override
+  public boolean encloses(Range<C> range) {
+    checkNotNull(range);
+    Entry<Cut<C>, Range<C>> floorEntry = rangesByLowerBound.floorEntry(range.lowerBound);
+    return floorEntry != null && floorEntry.getValue().encloses(range);
+  }
+  
+  @Nullable
+  private Range<C> rangeEnclosing(Range<C> range) {
+    checkNotNull(range);
+    Entry<Cut<C>, Range<C>> floorEntry = rangesByLowerBound.floorEntry(range.lowerBound);
+    return (floorEntry != null && floorEntry.getValue().encloses(range))
+        ? floorEntry.getValue()
+        : null;
+  }
+
+  @Override
+  public Range<C> span() {
+    Entry<Cut<C>, Range<C>> firstEntry = rangesByLowerBound.firstEntry();
+    Entry<Cut<C>, Range<C>> lastEntry = rangesByLowerBound.lastEntry();
+    if (firstEntry == null) {
+      throw new NoSuchElementException();
+    }
+    return Range.create(firstEntry.getValue().lowerBound, lastEntry.getValue().upperBound);
+  }
+
+  @Override
+  public void add(Range<C> rangeToAdd) {
+    checkNotNull(rangeToAdd);
+
+    if (rangeToAdd.isEmpty()) {
+      return;
+    }
+
+    // We will use { } to illustrate ranges currently in the range set, and < >
+    // to illustrate rangeToAdd.
+    Cut<C> lbToAdd = rangeToAdd.lowerBound;
+    Cut<C> ubToAdd = rangeToAdd.upperBound;
+
+    Entry<Cut<C>, Range<C>> entryBelowLB = rangesByLowerBound.lowerEntry(lbToAdd);
+    if (entryBelowLB != null) {
+      // { <
+      Range<C> rangeBelowLB = entryBelowLB.getValue();
+      if (rangeBelowLB.upperBound.compareTo(lbToAdd) >= 0) {
+        // { < }, and we will need to coalesce
+        if (rangeBelowLB.upperBound.compareTo(ubToAdd) >= 0) {
+          // { < > }
+          ubToAdd = rangeBelowLB.upperBound;
+          /*
+           * TODO(cpovirk): can we just "return;" here? Or, can we remove this if() entirely? If
+           * not, add tests to demonstrate the problem with each approach
+           */
+        }
+        lbToAdd = rangeBelowLB.lowerBound;
+      }
+    }
+
+    Entry<Cut<C>, Range<C>> entryBelowUB = rangesByLowerBound.floorEntry(ubToAdd);
+    if (entryBelowUB != null) {
+      // { >
+      Range<C> rangeBelowUB = entryBelowUB.getValue();
+      if (rangeBelowUB.upperBound.compareTo(ubToAdd) >= 0) {
+        // { > }, and we need to coalesce
+        ubToAdd = rangeBelowUB.upperBound;
+      }
+    }
+
+    // Remove ranges which are strictly enclosed.
+    rangesByLowerBound.subMap(lbToAdd, ubToAdd).clear();
+
+    replaceRangeWithSameLowerBound(Range.create(lbToAdd, ubToAdd));
+  }
+
+  @Override
+  public void remove(Range<C> rangeToRemove) {
+    checkNotNull(rangeToRemove);
+
+    if (rangeToRemove.isEmpty()) {
+      return;
+    }
+
+    // We will use { } to illustrate ranges currently in the range set, and < >
+    // to illustrate rangeToRemove.
+
+    Entry<Cut<C>, Range<C>> entryBelowLB = rangesByLowerBound.lowerEntry(rangeToRemove.lowerBound);
+    if (entryBelowLB != null) {
+      // { <
+      Range<C> rangeBelowLB = entryBelowLB.getValue();
+      if (rangeBelowLB.upperBound.compareTo(rangeToRemove.lowerBound) >= 0) {
+        // { < }, and we will need to subdivide
+        if (rangeToRemove.hasUpperBound()
+            && rangeBelowLB.upperBound.compareTo(rangeToRemove.upperBound) >= 0) {
+          // { < > }
+          replaceRangeWithSameLowerBound(
+              Range.create(rangeToRemove.upperBound, rangeBelowLB.upperBound));
+        }
+        replaceRangeWithSameLowerBound(
+            Range.create(rangeBelowLB.lowerBound, rangeToRemove.lowerBound));
+      }
+    }
+
+    Entry<Cut<C>, Range<C>> entryBelowUB = rangesByLowerBound.floorEntry(rangeToRemove.upperBound);
+    if (entryBelowUB != null) {
+      // { >
+      Range<C> rangeBelowUB = entryBelowUB.getValue();
+      if (rangeToRemove.hasUpperBound()
+          && rangeBelowUB.upperBound.compareTo(rangeToRemove.upperBound) >= 0) {
+        // { > }
+        replaceRangeWithSameLowerBound(
+            Range.create(rangeToRemove.upperBound, rangeBelowUB.upperBound));
+      }
+    }
+
+    rangesByLowerBound.subMap(rangeToRemove.lowerBound, rangeToRemove.upperBound).clear();
+  }
+
+  private void replaceRangeWithSameLowerBound(Range<C> range) {
+    if (range.isEmpty()) {
+      rangesByLowerBound.remove(range.lowerBound);
+    } else {
+      rangesByLowerBound.put(range.lowerBound, range);
+    }
+  }
+
+  private transient RangeSet<C> complement;
+
+  @Override
+  public RangeSet<C> complement() {
+    RangeSet<C> result = complement;
+    return (result == null) ? complement = new Complement() : result;
+  }
+  
+  @VisibleForTesting
+  static final class RangesByUpperBound<C extends Comparable<?>>
+      extends AbstractNavigableMap<Cut<C>, Range<C>> {
+    private final NavigableMap<Cut<C>, Range<C>> rangesByLowerBound;
+    
+    /**
+     * upperBoundWindow represents the headMap/subMap/tailMap view of the entire "ranges by upper
+     * bound" map; it's a constraint on the *keys*, and does not affect the values.
+     */
+    private final Range<Cut<C>> upperBoundWindow;
+    
+    RangesByUpperBound(NavigableMap<Cut<C>, Range<C>> rangesByLowerBound) {
+      this.rangesByLowerBound = rangesByLowerBound;
+      this.upperBoundWindow = Range.all();
+    }
+
+    private RangesByUpperBound(
+        NavigableMap<Cut<C>, Range<C>> rangesByLowerBound, Range<Cut<C>> upperBoundWindow) {
+      this.rangesByLowerBound = rangesByLowerBound;
+      this.upperBoundWindow = upperBoundWindow;
+    }
+
+    private NavigableMap<Cut<C>, Range<C>> subMap(Range<Cut<C>> window) {
+      if (window.isConnected(upperBoundWindow)) {
+        return new RangesByUpperBound<C>(rangesByLowerBound, window.intersection(upperBoundWindow));
+      } else {
+        return ImmutableSortedMap.of();
+      }
+    }
+
+    @Override
+    public NavigableMap<Cut<C>, Range<C>> subMap(
+        Cut<C> fromKey, boolean fromInclusive, Cut<C> toKey, boolean toInclusive) {
+      return subMap(Range.range(
+          fromKey, BoundType.forBoolean(fromInclusive),
+          toKey, BoundType.forBoolean(toInclusive)));
+    }
+
+    @Override
+    public NavigableMap<Cut<C>, Range<C>> headMap(Cut<C> toKey, boolean inclusive) {
+      return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive)));
+    }
+
+    @Override
+    public NavigableMap<Cut<C>, Range<C>> tailMap(Cut<C> fromKey, boolean inclusive) {
+      return subMap(Range.downTo(fromKey, BoundType.forBoolean(inclusive)));
+    }
+
+    @Override
+    public Comparator<? super Cut<C>> comparator() {
+      return Ordering.<Cut<C>>natural();
+    }
+
+    @Override
+    public boolean containsKey(@Nullable Object key) {
+      return get(key) != null;
+    }
+
+    @Override
+    public Range<C> get(@Nullable Object key) {
+      if (key instanceof Cut) {
+        try {
+          @SuppressWarnings("unchecked") // we catch CCEs
+          Cut<C> cut = (Cut<C>) key;
+          if (!upperBoundWindow.contains(cut)) {
+            return null;
+          }
+          Entry<Cut<C>, Range<C>> candidate = rangesByLowerBound.lowerEntry(cut);
+          if (candidate != null && candidate.getValue().upperBound.equals(cut)) {
+            return candidate.getValue();
+          }
+        } catch (ClassCastException e) {
+          return null;
+        }
+      }
+      return null;
+    }
+
+    @Override
+    Iterator<Entry<Cut<C>, Range<C>>> entryIterator() {
+      /*
+       * We want to start the iteration at the first range where the upper bound is in
+       * upperBoundWindow.
+       */
+      final Iterator<Range<C>> backingItr;
+      if (!upperBoundWindow.hasLowerBound()) {
+        backingItr = rangesByLowerBound.values().iterator();
+      } else {
+        Entry<Cut<C>, Range<C>> lowerEntry =
+            rangesByLowerBound.lowerEntry(upperBoundWindow.lowerEndpoint());
+        if (lowerEntry == null) {
+          backingItr = rangesByLowerBound.values().iterator();
+        } else if (upperBoundWindow.lowerBound.isLessThan(lowerEntry.getValue().upperBound)) {
+          backingItr = rangesByLowerBound.tailMap(lowerEntry.getKey(), true).values().iterator();
+        } else {
+          backingItr = rangesByLowerBound.tailMap(upperBoundWindow.lowerEndpoint(), true)
+              .values().iterator();
+        }
+      }
+      return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
+        @Override
+        protected Entry<Cut<C>, Range<C>> computeNext() {
+          if (!backingItr.hasNext()) {
+            return endOfData();
+          }
+          Range<C> range = backingItr.next();
+          if (upperBoundWindow.upperBound.isLessThan(range.upperBound)) {
+            return endOfData();
+          } else {
+            return Maps.immutableEntry(range.upperBound, range);
+          }
+        }
+      };
+    }
+
+    @Override
+    Iterator<Entry<Cut<C>, Range<C>>> descendingEntryIterator() {
+      Collection<Range<C>> candidates;
+      if (upperBoundWindow.hasUpperBound()) {
+        candidates = rangesByLowerBound.headMap(upperBoundWindow.upperEndpoint(), false)
+            .descendingMap().values();
+      } else {
+        candidates = rangesByLowerBound.descendingMap().values();
+      }
+      final PeekingIterator<Range<C>> backingItr = Iterators.peekingIterator(candidates.iterator());
+      if (backingItr.hasNext()
+          && upperBoundWindow.upperBound.isLessThan(backingItr.peek().upperBound)) {
+        backingItr.next();
+      }
+      return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
+        @Override
+        protected Entry<Cut<C>, Range<C>> computeNext() {
+          if (!backingItr.hasNext()) {
+            return endOfData();
+          }
+          Range<C> range = backingItr.next();
+          return upperBoundWindow.lowerBound.isLessThan(range.upperBound) 
+              ? Maps.immutableEntry(range.upperBound, range)
+              : endOfData();
+        }
+      };
+    }
+
+    @Override
+    public int size() {
+      if (upperBoundWindow.equals(Range.all())) {
+        return rangesByLowerBound.size();
+      }
+      return Iterators.size(entryIterator());
+    }
+    
+    @Override
+    public boolean isEmpty() {
+      return upperBoundWindow.equals(Range.all())
+          ? rangesByLowerBound.isEmpty()
+          : !entryIterator().hasNext();
+    }
+  }
+  
+  private static final class ComplementRangesByLowerBound<C extends Comparable<?>>
+      extends AbstractNavigableMap<Cut<C>, Range<C>> {
+    private final NavigableMap<Cut<C>, Range<C>> positiveRangesByLowerBound;
+    private final NavigableMap<Cut<C>, Range<C>> positiveRangesByUpperBound;
+    
+    /**
+     * complementLowerBoundWindow represents the headMap/subMap/tailMap view of the entire
+     * "complement ranges by lower bound" map; it's a constraint on the *keys*, and does not affect
+     * the values.
+     */
+    private final Range<Cut<C>> complementLowerBoundWindow;
+    
+    ComplementRangesByLowerBound(NavigableMap<Cut<C>, Range<C>> positiveRangesByLowerBound) {
+      this(positiveRangesByLowerBound, Range.<Cut<C>>all());
+    }
+
+    private ComplementRangesByLowerBound(NavigableMap<Cut<C>, Range<C>> positiveRangesByLowerBound,
+        Range<Cut<C>> window) {
+      this.positiveRangesByLowerBound = positiveRangesByLowerBound;
+      this.positiveRangesByUpperBound = new RangesByUpperBound<C>(positiveRangesByLowerBound);
+      this.complementLowerBoundWindow = window;
+    }
+
+    private NavigableMap<Cut<C>, Range<C>> subMap(Range<Cut<C>> subWindow) {
+      if (!complementLowerBoundWindow.isConnected(subWindow)) {
+        return ImmutableSortedMap.of(); 
+      } else {
+        subWindow = subWindow.intersection(complementLowerBoundWindow);
+        return new ComplementRangesByLowerBound<C>(positiveRangesByLowerBound, subWindow);
+      }
+    }
+
+    @Override
+    public NavigableMap<Cut<C>, Range<C>> subMap(
+        Cut<C> fromKey, boolean fromInclusive, Cut<C> toKey, boolean toInclusive) {
+      return subMap(Range.range(
+          fromKey, BoundType.forBoolean(fromInclusive),
+          toKey, BoundType.forBoolean(toInclusive)));
+    }
+
+    @Override
+    public NavigableMap<Cut<C>, Range<C>> headMap(Cut<C> toKey, boolean inclusive) {
+      return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive)));
+    }
+
+    @Override
+    public NavigableMap<Cut<C>, Range<C>> tailMap(Cut<C> fromKey, boolean inclusive) {
+      return subMap(Range.downTo(fromKey, BoundType.forBoolean(inclusive)));
+    }
+
+    @Override
+    public Comparator<? super Cut<C>> comparator() {
+      return Ordering.<Cut<C>>natural();
+    }
+
+    @Override
+    Iterator<Entry<Cut<C>, Range<C>>> entryIterator() {
+      /*
+       * firstComplementRangeLowerBound is the first complement range lower bound inside
+       * complementLowerBoundWindow. Complement range lower bounds are either positive range upper
+       * bounds, or Cut.belowAll().
+       *
+       * positiveItr starts at the first positive range with lower bound greater than
+       * firstComplementRangeLowerBound. (Positive range lower bounds correspond to complement range
+       * upper bounds.)
+       */
+      Collection<Range<C>> positiveRanges;
+      if (complementLowerBoundWindow.hasLowerBound()) {
+        positiveRanges = positiveRangesByUpperBound.tailMap(
+            complementLowerBoundWindow.lowerEndpoint(),
+            complementLowerBoundWindow.lowerBoundType() == BoundType.CLOSED).values();
+      } else {
+        positiveRanges = positiveRangesByUpperBound.values();
+      }
+      final PeekingIterator<Range<C>> positiveItr = Iterators.peekingIterator(
+          positiveRanges.iterator());
+      final Cut<C> firstComplementRangeLowerBound;
+      if (complementLowerBoundWindow.contains(Cut.<C>belowAll()) && 
+          (!positiveItr.hasNext() || positiveItr.peek().lowerBound != Cut.<C>belowAll())) {
+        firstComplementRangeLowerBound = Cut.belowAll();
+      } else if (positiveItr.hasNext()) {
+        firstComplementRangeLowerBound = positiveItr.next().upperBound;
+      } else {
+        return Iterators.emptyIterator();
+      }
+      return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
+        Cut<C> nextComplementRangeLowerBound = firstComplementRangeLowerBound;
+
+        @Override
+        protected Entry<Cut<C>, Range<C>> computeNext() {
+          if (complementLowerBoundWindow.upperBound.isLessThan(nextComplementRangeLowerBound)
+              || nextComplementRangeLowerBound == Cut.<C>aboveAll()) {
+            return endOfData();
+          }
+          Range<C> negativeRange;
+          if (positiveItr.hasNext()) {
+            Range<C> positiveRange = positiveItr.next();
+            negativeRange = Range.create(nextComplementRangeLowerBound, positiveRange.lowerBound);
+            nextComplementRangeLowerBound = positiveRange.upperBound;
+          } else {
+            negativeRange = Range.create(nextComplementRangeLowerBound, Cut.<C>aboveAll());
+            nextComplementRangeLowerBound = Cut.aboveAll();
+          }
+          return Maps.immutableEntry(negativeRange.lowerBound, negativeRange);
+        }
+      };
+    }
+
+    @Override
+    Iterator<Entry<Cut<C>, Range<C>>> descendingEntryIterator() {
+      /*
+       * firstComplementRangeUpperBound is the upper bound of the last complement range with lower
+       * bound inside complementLowerBoundWindow.
+       *
+       * positiveItr starts at the first positive range with upper bound less than
+       * firstComplementRangeUpperBound. (Positive range upper bounds correspond to complement range
+       * lower bounds.)
+       */
+      Cut<C> startingPoint = complementLowerBoundWindow.hasUpperBound()
+          ? complementLowerBoundWindow.upperEndpoint()
+          : Cut.<C>aboveAll();
+      boolean inclusive = complementLowerBoundWindow.hasUpperBound()
+          && complementLowerBoundWindow.upperBoundType() == BoundType.CLOSED;
+      final PeekingIterator<Range<C>> positiveItr =
+          Iterators.peekingIterator(positiveRangesByUpperBound.headMap(startingPoint, inclusive)
+              .descendingMap().values().iterator());
+      Cut<C> cut;
+      if (positiveItr.hasNext()) {
+        cut = (positiveItr.peek().upperBound == Cut.<C>aboveAll()) 
+            ? positiveItr.next().lowerBound 
+            : positiveRangesByLowerBound.higherKey(positiveItr.peek().upperBound);
+      } else if (!complementLowerBoundWindow.contains(Cut.<C>belowAll())
+          || positiveRangesByLowerBound.containsKey(Cut.belowAll())) {
+        return Iterators.emptyIterator();
+      } else {
+        cut = positiveRangesByLowerBound.higherKey(Cut.<C>belowAll());
+      }
+      final Cut<C> firstComplementRangeUpperBound =
+          MoreObjects.firstNonNull(cut, Cut.<C>aboveAll());
+      return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
+        Cut<C> nextComplementRangeUpperBound = firstComplementRangeUpperBound;
+
+        @Override
+        protected Entry<Cut<C>, Range<C>> computeNext() {
+          if (nextComplementRangeUpperBound == Cut.<C>belowAll()) {
+            return endOfData();
+          } else if (positiveItr.hasNext()) {
+            Range<C> positiveRange = positiveItr.next();
+            Range<C> negativeRange =
+                Range.create(positiveRange.upperBound, nextComplementRangeUpperBound);
+            nextComplementRangeUpperBound = positiveRange.lowerBound;
+            if (complementLowerBoundWindow.lowerBound.isLessThan(negativeRange.lowerBound)) {
+              return Maps.immutableEntry(negativeRange.lowerBound, negativeRange);
+            }
+          } else if (complementLowerBoundWindow.lowerBound.isLessThan(Cut.<C>belowAll())) {
+            Range<C> negativeRange =
+                Range.create(Cut.<C>belowAll(), nextComplementRangeUpperBound);
+            nextComplementRangeUpperBound = Cut.belowAll();
+            return Maps.immutableEntry(Cut.<C>belowAll(), negativeRange);
+          }
+          return endOfData();
+        }
+      };
+    }
+
+    @Override
+    public int size() {
+      return Iterators.size(entryIterator());
+    }
+
+    @Override
+    @Nullable
+    public Range<C> get(Object key) {
+      if (key instanceof Cut) {
+        try {
+          @SuppressWarnings("unchecked")
+          Cut<C> cut = (Cut<C>) key;
+          // tailMap respects the current window
+          Entry<Cut<C>, Range<C>> firstEntry = tailMap(cut, true).firstEntry();
+          if (firstEntry != null && firstEntry.getKey().equals(cut)) {
+            return firstEntry.getValue();
+          }
+        } catch (ClassCastException e) {
+          return null;
+        }
+      }
+      return null;
+    }
+
+    @Override
+    public boolean containsKey(Object key) {
+      return get(key) != null;
+    }
+  }
+
+  private final class Complement extends TreeRangeSet<C> {
+    Complement() {
+      super(new ComplementRangesByLowerBound<C>(TreeRangeSet.this.rangesByLowerBound));
+    }
+
+    @Override
+    public void add(Range<C> rangeToAdd) {
+      TreeRangeSet.this.remove(rangeToAdd);
+    }
+
+    @Override
+    public void remove(Range<C> rangeToRemove) {
+      TreeRangeSet.this.add(rangeToRemove);
+    }
+
+    @Override
+    public boolean contains(C value) {
+      return !TreeRangeSet.this.contains(value);
+    }
+    
+    @Override
+    public RangeSet<C> complement() {
+      return TreeRangeSet.this;
+    }
+  }
+
+  private static final class SubRangeSetRangesByLowerBound<C extends Comparable<?>>
+      extends AbstractNavigableMap<Cut<C>, Range<C>> {
+    /**
+     * lowerBoundWindow is the headMap/subMap/tailMap view; it only restricts the keys, and does not
+     * affect the values.
+     */
+    private final Range<Cut<C>> lowerBoundWindow;
+
+    /**
+     * restriction is the subRangeSet view; ranges are truncated to their intersection with
+     * restriction.
+     */
+    private final Range<C> restriction;
+
+    private final NavigableMap<Cut<C>, Range<C>> rangesByLowerBound;
+    private final NavigableMap<Cut<C>, Range<C>> rangesByUpperBound;
+
+    private SubRangeSetRangesByLowerBound(Range<Cut<C>> lowerBoundWindow, Range<C> restriction,
+        NavigableMap<Cut<C>, Range<C>> rangesByLowerBound) {
+      this.lowerBoundWindow = checkNotNull(lowerBoundWindow);
+      this.restriction = checkNotNull(restriction);
+      this.rangesByLowerBound = checkNotNull(rangesByLowerBound);
+      this.rangesByUpperBound = new RangesByUpperBound<C>(rangesByLowerBound);
+    }
+
+    private NavigableMap<Cut<C>, Range<C>> subMap(Range<Cut<C>> window) {
+      if (!window.isConnected(lowerBoundWindow)) {
+        return ImmutableSortedMap.of();
+      } else {
+        return new SubRangeSetRangesByLowerBound<C>(
+            lowerBoundWindow.intersection(window), restriction, rangesByLowerBound);
+      }
+    }
+
+    @Override
+    public NavigableMap<Cut<C>, Range<C>> subMap(
+        Cut<C> fromKey, boolean fromInclusive, Cut<C> toKey, boolean toInclusive) {
+      return subMap(Range.range(
+          fromKey, BoundType.forBoolean(fromInclusive), toKey, BoundType.forBoolean(toInclusive)));
+    }
+
+    @Override
+    public NavigableMap<Cut<C>, Range<C>> headMap(Cut<C> toKey, boolean inclusive) {
+      return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive)));
+    }
+
+    @Override
+    public NavigableMap<Cut<C>, Range<C>> tailMap(Cut<C> fromKey, boolean inclusive) {
+      return subMap(Range.downTo(fromKey, BoundType.forBoolean(inclusive)));
+    }
+
+    @Override
+    public Comparator<? super Cut<C>> comparator() {
+      return Ordering.<Cut<C>>natural();
+    }
+
+    @Override
+    public boolean containsKey(@Nullable Object key) {
+      return get(key) != null;
+    }
+
+    @Override
+    @Nullable
+    public Range<C> get(@Nullable Object key) {
+      if (key instanceof Cut) {
+        try {
+          @SuppressWarnings("unchecked") // we catch CCE's
+          Cut<C> cut = (Cut<C>) key;
+          if (!lowerBoundWindow.contains(cut) || cut.compareTo(restriction.lowerBound) < 0
+              || cut.compareTo(restriction.upperBound) >= 0) {
+            return null;
+          } else if (cut.equals(restriction.lowerBound)) {
+            // it might be present, truncated on the left
+            Range<C> candidate = Maps.valueOrNull(rangesByLowerBound.floorEntry(cut));
+            if (candidate != null && candidate.upperBound.compareTo(restriction.lowerBound) > 0) {
+              return candidate.intersection(restriction);
+            }
+          } else {
+            Range<C> result = rangesByLowerBound.get(cut);
+            if (result != null) {
+              return result.intersection(restriction);
+            }
+          }
+        } catch (ClassCastException e) {
+          return null;
+        }
+      }
+      return null;
+    }
+
+    @Override
+    Iterator<Entry<Cut<C>, Range<C>>> entryIterator() {
+      if (restriction.isEmpty()) {
+        return Iterators.emptyIterator();
+      }
+      final Iterator<Range<C>> completeRangeItr;
+      if (lowerBoundWindow.upperBound.isLessThan(restriction.lowerBound)) {
+        return Iterators.emptyIterator();
+      } else if (lowerBoundWindow.lowerBound.isLessThan(restriction.lowerBound)) {
+        // starts at the first range with upper bound strictly greater than restriction.lowerBound
+        completeRangeItr =
+            rangesByUpperBound.tailMap(restriction.lowerBound, false).values().iterator();
+      } else {
+        // starts at the first range with lower bound above lowerBoundWindow.lowerBound
+        completeRangeItr = rangesByLowerBound.tailMap(lowerBoundWindow.lowerBound.endpoint(),
+            lowerBoundWindow.lowerBoundType() == BoundType.CLOSED).values().iterator();
+      }
+      final Cut<Cut<C>> upperBoundOnLowerBounds = Ordering.natural()
+          .min(lowerBoundWindow.upperBound, Cut.belowValue(restriction.upperBound));
+      return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
+        @Override
+        protected Entry<Cut<C>, Range<C>> computeNext() {
+          if (!completeRangeItr.hasNext()) {
+            return endOfData();
+          }
+          Range<C> nextRange = completeRangeItr.next();
+          if (upperBoundOnLowerBounds.isLessThan(nextRange.lowerBound)) {
+            return endOfData();
+          } else {
+            nextRange = nextRange.intersection(restriction);
+            return Maps.immutableEntry(nextRange.lowerBound, nextRange);
+          }
+        }
+      };
+    }
+
+    @Override
+    Iterator<Entry<Cut<C>, Range<C>>> descendingEntryIterator() {
+      if (restriction.isEmpty()) {
+        return Iterators.emptyIterator();
+      }
+      Cut<Cut<C>> upperBoundOnLowerBounds = Ordering.natural()
+          .min(lowerBoundWindow.upperBound, Cut.belowValue(restriction.upperBound));
+      final Iterator<Range<C>> completeRangeItr = rangesByLowerBound.headMap(
+          upperBoundOnLowerBounds.endpoint(),
+          upperBoundOnLowerBounds.typeAsUpperBound() == BoundType.CLOSED)
+          .descendingMap().values().iterator();
+      return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
+        @Override
+        protected Entry<Cut<C>, Range<C>> computeNext() {
+          if (!completeRangeItr.hasNext()) {
+            return endOfData();
+          }
+          Range<C> nextRange = completeRangeItr.next();
+          if (restriction.lowerBound.compareTo(nextRange.upperBound) >= 0) {
+            return endOfData();
+          }
+          nextRange = nextRange.intersection(restriction);
+          if (lowerBoundWindow.contains(nextRange.lowerBound)) {
+            return Maps.immutableEntry(nextRange.lowerBound, nextRange);
+          } else {
+            return endOfData();
+          }
+        }
+      };
+    }
+
+    @Override
+    public int size() {
+      return Iterators.size(entryIterator());
+    }
+  }
+  
+  @Override
+  public RangeSet<C> subRangeSet(Range<C> view) {
+    return view.equals(Range.<C>all()) ? this : new SubRangeSet(view);
+  }
+  
+  private final class SubRangeSet extends TreeRangeSet<C> {
+    private final Range<C> restriction;
+
+    SubRangeSet(Range<C> restriction) {
+      super(new SubRangeSetRangesByLowerBound<C>(
+          Range.<Cut<C>>all(), restriction, TreeRangeSet.this.rangesByLowerBound));
+      this.restriction = restriction;
+    }
+
+    @Override
+    public boolean encloses(Range<C> range) {
+      if (!restriction.isEmpty() && restriction.encloses(range)) {
+        Range<C> enclosing = TreeRangeSet.this.rangeEnclosing(range);
+        return enclosing != null && !enclosing.intersection(restriction).isEmpty();
+      }
+      return false;
+    }
+
+    @Override
+    @Nullable
+    public Range<C> rangeContaining(C value) {
+      if (!restriction.contains(value)) {
+        return null;
+      }
+      Range<C> result = TreeRangeSet.this.rangeContaining(value);
+      return (result == null) ? null : result.intersection(restriction);
+    }
+
+    @Override
+    public void add(Range<C> rangeToAdd) {
+      checkArgument(restriction.encloses(rangeToAdd), "Cannot add range %s to subRangeSet(%s)",
+          rangeToAdd, restriction);
+      super.add(rangeToAdd);
+    }
+
+    @Override
+    public void remove(Range<C> rangeToRemove) {
+      if (rangeToRemove.isConnected(restriction)) {
+        TreeRangeSet.this.remove(rangeToRemove.intersection(restriction));
+      }
+    }
+
+    @Override
+    public boolean contains(C value) {
+      return restriction.contains(value) && TreeRangeSet.this.contains(value);
+    }
+
+    @Override
+    public void clear() {
+      TreeRangeSet.this.remove(restriction);
+    }
+
+    @Override
+    public RangeSet<C> subRangeSet(Range<C> view) {
+      if (view.encloses(restriction)) {
+        return this;
+      } else if (view.isConnected(restriction)) {
+        return new SubRangeSet(restriction.intersection(view));
+      } else {
+        return ImmutableRangeSet.of();
+      }
+    }
+  }
+}
diff --git a/guava/src/com/google/common/collect/TreeTraverser.java b/guava/src/com/google/common/collect/TreeTraverser.java
index 27e44d4..60459ae 100644
--- a/guava/src/com/google/common/collect/TreeTraverser.java
+++ b/guava/src/com/google/common/collect/TreeTraverser.java
@@ -21,8 +21,9 @@
 import com.google.common.annotations.Beta;
 import com.google.common.annotations.GwtCompatible;
 
+import java.util.ArrayDeque;
+import java.util.Deque;
 import java.util.Iterator;
-import java.util.LinkedList;
 import java.util.Queue;
 
 /**
@@ -51,7 +52,7 @@
 @Beta
 @GwtCompatible(emulated = true)
 public abstract class TreeTraverser<T> {
-  // TODO(user): make this GWT-compatible when we've checked in LinkedList emulation
+  // TODO(user): make this GWT-compatible when we've checked in ArrayDeque emulation
 
   /**
    * Returns the children of the specified node.  Must not contain null.
@@ -81,10 +82,10 @@
   }
 
   private final class PreOrderIterator extends UnmodifiableIterator<T> {
-    private final LinkedList<Iterator<T>> stack;
+    private final Deque<Iterator<T>> stack;
 
     PreOrderIterator(T root) {
-      this.stack = new LinkedList<Iterator<T>>();
+      this.stack = new ArrayDeque<Iterator<T>>();
       stack.addLast(Iterators.singletonIterator(checkNotNull(root)));
     }
 
@@ -141,10 +142,10 @@
   }
 
   private final class PostOrderIterator extends AbstractIterator<T> {
-    private final LinkedList<PostOrderNode<T>> stack;
+    private final ArrayDeque<PostOrderNode<T>> stack;
 
     PostOrderIterator(T root) {
-      this.stack = new LinkedList<PostOrderNode<T>>();
+      this.stack = new ArrayDeque<PostOrderNode<T>>();
       stack.addLast(expand(root));
     }
 
@@ -190,7 +191,7 @@
     private final Queue<T> queue;
 
     BreadthFirstIterator(T root) {
-      this.queue = new LinkedList<T>();
+      this.queue = new ArrayDeque<T>();
       queue.add(root);
     }
 
diff --git a/guava/src/com/google/common/collect/UnmodifiableSortedMultiset.java b/guava/src/com/google/common/collect/UnmodifiableSortedMultiset.java
index 3924c57..4b353cb 100644
--- a/guava/src/com/google/common/collect/UnmodifiableSortedMultiset.java
+++ b/guava/src/com/google/common/collect/UnmodifiableSortedMultiset.java
@@ -19,9 +19,8 @@
 import com.google.common.annotations.GwtCompatible;
 import com.google.common.collect.Multisets.UnmodifiableMultiset;
 
-import java.util.Collections;
 import java.util.Comparator;
-import java.util.SortedSet;
+import java.util.NavigableSet;
 
 /**
  * Implementation of {@link Multisets#unmodifiableSortedMultiset(SortedMultiset)},
@@ -48,13 +47,13 @@
   }
 
   @Override
-  SortedSet<E> createElementSet() {
-    return Collections.unmodifiableSortedSet(delegate().elementSet());
+  NavigableSet<E> createElementSet() {
+    return Sets.unmodifiableNavigableSet(delegate().elementSet());
   }
 
   @Override
-  public SortedSet<E> elementSet() {
-    return (SortedSet<E>) super.elementSet();
+  public NavigableSet<E> elementSet() {
+    return (NavigableSet<E>) super.elementSet();
   }
 
   private transient UnmodifiableSortedMultiset<E> descendingMultiset;
@@ -112,4 +111,4 @@
   }
 
   private static final long serialVersionUID = 0;
-}
+}
\ No newline at end of file
diff --git a/guava/src/com/google/common/eventbus/AnnotatedSubscriberFinder.java b/guava/src/com/google/common/eventbus/AnnotatedSubscriberFinder.java
index 66b384e..b1c38ff 100644
--- a/guava/src/com/google/common/eventbus/AnnotatedSubscriberFinder.java
+++ b/guava/src/com/google/common/eventbus/AnnotatedSubscriberFinder.java
@@ -85,21 +85,21 @@
       throw Throwables.propagate(e.getCause());
     }
   }
-  
+
   private static final class MethodIdentifier {
     private final String name;
     private final List<Class<?>> parameterTypes;
-    
+
     MethodIdentifier(Method method) {
       this.name = method.getName();
       this.parameterTypes = Arrays.asList(method.getParameterTypes());
     }
-    
+
     @Override
     public int hashCode() {
       return Objects.hashCode(name, parameterTypes);
     }
-    
+
     @Override
     public boolean equals(@Nullable Object o) {
       if (o instanceof MethodIdentifier) {
@@ -115,14 +115,15 @@
     Map<MethodIdentifier, Method> identifiers = Maps.newHashMap();
     for (Class<?> superClazz : supers) {
       for (Method superClazzMethod : superClazz.getMethods()) {
-        if (superClazzMethod.isAnnotationPresent(Subscribe.class)) {
+        if (superClazzMethod.isAnnotationPresent(Subscribe.class)
+            && !superClazzMethod.isBridge()) {
           Class<?>[] parameterTypes = superClazzMethod.getParameterTypes();
           if (parameterTypes.length != 1) {
             throw new IllegalArgumentException("Method " + superClazzMethod
                 + " has @Subscribe annotation, but requires " + parameterTypes.length
                 + " arguments.  Event subscriber methods must require a single argument.");
           }
-          
+
           MethodIdentifier ident = new MethodIdentifier(superClazzMethod);
           if (!identifiers.containsKey(ident)) {
             identifiers.put(ident, superClazzMethod);
diff --git a/guava/src/com/google/common/hash/AbstractCompositeHashFunction.java b/guava/src/com/google/common/hash/AbstractCompositeHashFunction.java
index c70422e..43d5fa9 100644
--- a/guava/src/com/google/common/hash/AbstractCompositeHashFunction.java
+++ b/guava/src/com/google/common/hash/AbstractCompositeHashFunction.java
@@ -122,14 +122,6 @@
         return this;
       }
 
-      /**
-       * @deprecated Use {@link Hasher#putUnencodedChars} instead.
-       */
-      @Deprecated
-      @Override public Hasher putString(CharSequence chars) {
-        return putUnencodedChars(chars);
-      }
-
       @Override public Hasher putUnencodedChars(CharSequence chars) {
         for (Hasher hasher : hashers) {
           hasher.putUnencodedChars(chars);
diff --git a/guava/src/com/google/common/hash/AbstractHasher.java b/guava/src/com/google/common/hash/AbstractHasher.java
index 60f4649..a23786f 100644
--- a/guava/src/com/google/common/hash/AbstractHasher.java
+++ b/guava/src/com/google/common/hash/AbstractHasher.java
@@ -14,7 +14,6 @@
 
 package com.google.common.hash;
 
-import java.io.UnsupportedEncodingException;
 import java.nio.charset.Charset;
 
 /**
@@ -37,14 +36,6 @@
     return putInt(Float.floatToRawIntBits(f));
   }
 
-  /**
-   * @deprecated Use {@link AbstractHasher#putUnencodedChars} instead.
-   */
-  @Deprecated
-  @Override public Hasher putString(CharSequence charSequence) {
-    return putUnencodedChars(charSequence);
-  }
-
   @Override public Hasher putUnencodedChars(CharSequence charSequence) {
     for (int i = 0, len = charSequence.length(); i < len; i++) {
       putChar(charSequence.charAt(i));
@@ -53,10 +44,6 @@
   }
 
   @Override public Hasher putString(CharSequence charSequence, Charset charset) {
-    try {
-      return putBytes(charSequence.toString().getBytes(charset.name()));
-    } catch (UnsupportedEncodingException e) {
-      throw new AssertionError(e);
-    }
+    return putBytes(charSequence.toString().getBytes(charset));
   }
 }
diff --git a/guava/src/com/google/common/hash/AbstractNonStreamingHashFunction.java b/guava/src/com/google/common/hash/AbstractNonStreamingHashFunction.java
index 1972759..7c08b70 100644
--- a/guava/src/com/google/common/hash/AbstractNonStreamingHashFunction.java
+++ b/guava/src/com/google/common/hash/AbstractNonStreamingHashFunction.java
@@ -20,7 +20,6 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.UnsupportedEncodingException;
 import java.nio.charset.Charset;
 
 /**
@@ -46,14 +45,6 @@
     return newHasher().putObject(instance, funnel).hash();
   }
 
-  /**
-   * @deprecated Use {@link AbstractNonStreamingHashFunction#hashUnencodedChars} instead.
-   */
-  @Deprecated
-  @Override public HashCode hashString(CharSequence input) {
-    return hashUnencodedChars(input);
-  }
-
   @Override public HashCode hashUnencodedChars(CharSequence input) {
     int len = input.length();
     Hasher hasher = newHasher(len * 2);
@@ -64,11 +55,7 @@
   }
 
   @Override public HashCode hashString(CharSequence input, Charset charset) {
-    try {
-      return hashBytes(input.toString().getBytes(charset.name()));
-    } catch (UnsupportedEncodingException e) {
-      throw new AssertionError(e);
-    }
+    return hashBytes(input.toString().getBytes(charset));
   }
 
   @Override public HashCode hashInt(int input) {
diff --git a/guava/src/com/google/common/hash/AbstractStreamingHashFunction.java b/guava/src/com/google/common/hash/AbstractStreamingHashFunction.java
index c34feaa..302399f 100644
--- a/guava/src/com/google/common/hash/AbstractStreamingHashFunction.java
+++ b/guava/src/com/google/common/hash/AbstractStreamingHashFunction.java
@@ -37,14 +37,6 @@
     return newHasher().putObject(instance, funnel).hash();
   }
 
-  /**
-   * @deprecated Use {@link AbstractStreamingHashFunction#hashUnencodedChars} instead.
-   */
-  @Deprecated
-  @Override public HashCode hashString(CharSequence input) {
-    return hashUnencodedChars(input);
-  }
-
   @Override public HashCode hashUnencodedChars(CharSequence input) {
     return newHasher().putUnencodedChars(input).hash();
   }
@@ -183,15 +175,6 @@
       return this;
     }
 
-    /**
-     * @deprecated Use {@link AbstractStreamingHasher#putUnencodedChars} instead.
-     */
-    @Deprecated
-    @Override
-    public final Hasher putString(CharSequence charSequence) {
-      return putUnencodedChars(charSequence);
-    }
-
     @Override
     public final Hasher putUnencodedChars(CharSequence charSequence) {
       for (int i = 0; i < charSequence.length(); i++) {
diff --git a/guava/src/com/google/common/hash/BloomFilter.java b/guava/src/com/google/common/hash/BloomFilter.java
index 4d0289e..1c04f8d 100644
--- a/guava/src/com/google/common/hash/BloomFilter.java
+++ b/guava/src/com/google/common/hash/BloomFilter.java
@@ -22,7 +22,14 @@
 import com.google.common.base.Objects;
 import com.google.common.base.Predicate;
 import com.google.common.hash.BloomFilterStrategies.BitArray;
+import com.google.common.primitives.SignedBytes;
+import com.google.common.primitives.UnsignedBytes;
 
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.io.Serializable;
 
 import javax.annotation.Nullable;
@@ -40,10 +47,11 @@
  * that {@linkplain #mightContain(Object)} will erroneously return {@code true} for an object that
  * has not actually been put in the {@code BloomFilter}.
  *
- * <p>Bloom filters are serializable.
- * However, serial forms generated by newer versions of the code may not be readable by older
- * versions of the code (e.g., a serialized bloom filter generated today may <i>not</i> be
- * readable by a binary that was compiled 6 months ago).
+ * <p>Bloom filters are serializable. They also support a more compact serial representation via
+ * the {@link #writeTo} and {@link #readFrom} methods. Both serialized forms will continue to be
+ * supported by future versions of this library. However, serial forms generated by newer versions
+ * of the code may not be readable by older versions of the code (e.g., a serialized bloom filter
+ * generated today may <i>not</i> be readable by a binary that was compiled 6 months ago).
  *
  * @param <T> the type of instances that the {@code BloomFilter} accepts
  * @author Dimitris Andreou
@@ -90,7 +98,7 @@
   private final int numHashFunctions;
 
   /** The funnel to translate Ts to bytes */
-  private final Funnel<T> funnel;
+  private final Funnel<? super T> funnel;
 
   /**
    * The strategy we employ to map an element T to {@code numHashFunctions} bit indexes.
@@ -100,7 +108,7 @@
   /**
    * Creates a BloomFilter.
    */
-  private BloomFilter(BitArray bits, int numHashFunctions, Funnel<T> funnel,
+  private BloomFilter(BitArray bits, int numHashFunctions, Funnel<? super T> funnel,
       Strategy strategy) {
     checkArgument(numHashFunctions > 0,
         "numHashFunctions (%s) must be > 0", numHashFunctions);
@@ -252,17 +260,7 @@
   }
 
   private static final Strategy DEFAULT_STRATEGY =
-      getDefaultStrategyFromSystemProperty();
-
-  @VisibleForTesting
-  static final String USE_MITZ32_PROPERTY = "com.google.common.hash.BloomFilter.useMitz32";
-
-  @VisibleForTesting
-  static Strategy getDefaultStrategyFromSystemProperty() {
-    return Boolean.parseBoolean(System.getProperty(USE_MITZ32_PROPERTY))
-        ? BloomFilterStrategies.MURMUR128_MITZ_32
-        : BloomFilterStrategies.MURMUR128_MITZ_64;
-  }
+      BloomFilterStrategies.MURMUR128_MITZ_64;
 
   /**
    * Creates a {@link BloomFilter BloomFilter<T>} with the expected number of
@@ -286,13 +284,13 @@
    * @return a {@code BloomFilter}
    */
   public static <T> BloomFilter<T> create(
-      Funnel<T> funnel, int expectedInsertions /* n */, double fpp) {
+      Funnel<? super T> funnel, int expectedInsertions /* n */, double fpp) {
     return create(funnel, expectedInsertions, fpp, DEFAULT_STRATEGY);
   }
 
   @VisibleForTesting
   static <T> BloomFilter<T> create(
-      Funnel<T> funnel, int expectedInsertions /* n */, double fpp, Strategy strategy) {
+      Funnel<? super T> funnel, int expectedInsertions /* n */, double fpp, Strategy strategy) {
     checkNotNull(funnel);
     checkArgument(expectedInsertions >= 0, "Expected insertions (%s) must be >= 0",
         expectedInsertions);
@@ -334,7 +332,8 @@
    *     {@code BloomFilter<T>}; must be positive
    * @return a {@code BloomFilter}
    */
-  public static <T> BloomFilter<T> create(Funnel<T> funnel, int expectedInsertions /* n */) {
+  public static <T> BloomFilter<T> create(
+      Funnel<? super T> funnel, int expectedInsertions /* n */) {
     return create(funnel, expectedInsertions, 0.03); // FYI, for 3%, we always get 5 hash functions
   }
 
@@ -363,7 +362,8 @@
    */
   @VisibleForTesting
   static int optimalNumOfHashFunctions(long n, long m) {
-    return Math.max(1, (int) Math.round(m / n * Math.log(2)));
+    // (m / n) * log(2), but avoid truncation due to division!
+    return Math.max(1, (int) Math.round((double) m / n * Math.log(2)));
   }
 
   /**
@@ -390,7 +390,7 @@
   private static class SerialForm<T> implements Serializable {
     final long[] data;
     final int numHashFunctions;
-    final Funnel<T> funnel;
+    final Funnel<? super T> funnel;
     final Strategy strategy;
 
     SerialForm(BloomFilter<T> bf) {
@@ -404,4 +404,72 @@
     }
     private static final long serialVersionUID = 1;
   }
+
+  /**
+   * Writes this {@code BloomFilter} to an output stream, with a custom format (not Java
+   * serialization). This has been measured to save at least 400 bytes compared to regular
+   * serialization.
+   *
+   * <p>Use {@linkplain #readFrom(InputStream, Funnel)} to reconstruct the written BloomFilter.
+   */
+  public void writeTo(OutputStream out) throws IOException {
+    /*
+     * Serial form:
+     * 1 signed byte for the strategy
+     * 1 unsigned byte for the number of hash functions
+     * 1 big endian int, the number of longs in our bitset
+     * N big endian longs of our bitset
+     */
+    DataOutputStream dout = new DataOutputStream(out);
+    dout.writeByte(SignedBytes.checkedCast(strategy.ordinal()));
+    dout.writeByte(UnsignedBytes.checkedCast(numHashFunctions)); // note: checked at the c'tor
+    dout.writeInt(bits.data.length);
+    for (long value : bits.data) {
+      dout.writeLong(value);
+    }
+  }
+
+  /**
+   * Reads a byte stream, which was written by {@linkplain #writeTo(OutputStream)}, into
+   * a {@code BloomFilter<T>}.
+   *
+   * The {@code Funnel} to be used is not encoded in the stream, so it must be provided here.
+   * <b>Warning:</b> the funnel provided <b>must</b> behave identically to the one used to
+   * populate the original Bloom filter!
+   *
+   * @throws IOException if the InputStream throws an {@code IOException}, or if its data does
+   *     not appear to be a BloomFilter serialized using the
+   *     {@linkplain #writeTo(OutputStream)} method.
+   */
+  public static <T> BloomFilter<T> readFrom(InputStream in, Funnel<T> funnel) throws IOException {
+    checkNotNull(in, "InputStream");
+    checkNotNull(funnel, "Funnel");
+    int strategyOrdinal = -1;
+    int numHashFunctions = -1;
+    int dataLength = -1;
+    try {
+      DataInputStream din = new DataInputStream(in);
+      // currently this assumes there is no negative ordinal; will have to be updated if we
+      // add non-stateless strategies (for which we've reserved negative ordinals; see
+      // Strategy.ordinal()).
+      strategyOrdinal = din.readByte();
+      numHashFunctions = UnsignedBytes.toInt(din.readByte());
+      dataLength = din.readInt();
+
+      Strategy strategy = BloomFilterStrategies.values()[strategyOrdinal];
+      long[] data = new long[dataLength];
+      for (int i = 0; i < data.length; i++) {
+        data[i] = din.readLong();
+      }
+      return new BloomFilter<T>(new BitArray(data), numHashFunctions, funnel, strategy);
+    } catch (RuntimeException e) {
+      IOException ioException = new IOException(
+          "Unable to deserialize BloomFilter from InputStream."
+          + " strategyOrdinal: " + strategyOrdinal
+          + " numHashFunctions: " + numHashFunctions
+          + " dataLength: " + dataLength);
+      ioException.initCause(e);
+      throw ioException;
+    }
+  }
 }
diff --git a/guava/src/com/google/common/hash/Crc32cHashFunction.java b/guava/src/com/google/common/hash/Crc32cHashFunction.java
new file mode 100644
index 0000000..dd9d7f3
--- /dev/null
+++ b/guava/src/com/google/common/hash/Crc32cHashFunction.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.common.hash;
+
+/**
+ * This class generates a CRC32C checksum, defined by RFC 3720, Section 12.1.
+ * The generator polynomial for this checksum is {@code 0x11EDC6F41}.
+ *
+ * @author Kurt Alfred Kluever
+ */
+final class Crc32cHashFunction extends AbstractStreamingHashFunction {
+
+  @Override
+  public int bits() {
+    return 32;
+  }
+
+  @Override
+  public Hasher newHasher() {
+    return new Crc32cHasher();
+  }
+
+  @Override
+  public String toString() {
+    return "Hashing.crc32c()";
+  }
+
+  static final class Crc32cHasher extends AbstractByteHasher {
+
+    // The CRC table, generated from the polynomial 0x11EDC6F41.
+    static final int[] CRC_TABLE = {
+      0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4,
+      0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb,
+      0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b,
+      0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24,
+      0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b,
+      0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,
+      0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54,
+      0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b,
+      0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a,
+      0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35,
+      0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5,
+      0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,
+      0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45,
+      0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a,
+      0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a,
+      0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595,
+      0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48,
+      0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,
+      0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687,
+      0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198,
+      0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927,
+      0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38,
+      0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8,
+      0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,
+      0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096,
+      0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789,
+      0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859,
+      0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46,
+      0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9,
+      0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,
+      0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36,
+      0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829,
+      0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c,
+      0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93,
+      0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043,
+      0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,
+      0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3,
+      0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc,
+      0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c,
+      0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033,
+      0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652,
+      0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,
+      0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d,
+      0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982,
+      0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d,
+      0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622,
+      0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2,
+      0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,
+      0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530,
+      0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f,
+      0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff,
+      0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0,
+      0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f,
+      0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,
+      0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90,
+      0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f,
+      0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee,
+      0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1,
+      0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321,
+      0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,
+      0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81,
+      0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e,
+      0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e,
+      0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351
+    };
+
+    private int crc = 0;
+
+    @Override
+    public void update(byte b) {
+      crc ^= 0xFFFFFFFF;
+      // See Hacker's Delight 2nd Edition, Figure 14-7.
+      crc = ~((crc >>> 8) ^ CRC_TABLE[(crc ^ b) & 0xFF]);
+    }
+
+    @Override
+    public HashCode hash() {
+      return HashCode.fromInt(crc);
+    }
+  }
+}
diff --git a/guava/src/com/google/common/hash/Funnels.java b/guava/src/com/google/common/hash/Funnels.java
index 9058916..08b814a 100644
--- a/guava/src/com/google/common/hash/Funnels.java
+++ b/guava/src/com/google/common/hash/Funnels.java
@@ -63,17 +63,6 @@
     return UnencodedCharsFunnel.INSTANCE;
   }
 
-  /**
-   * Returns a funnel that extracts the characters from a {@code CharSequence}.
-   *
-   * @deprecated Use {@link Funnels#unencodedCharsFunnel} instead. This method is scheduled for
-   *     removal in Guava 16.0.
-   */
-  @Deprecated
-  public static Funnel<CharSequence> stringFunnel() {
-    return unencodedCharsFunnel();
-  }
-
   private enum UnencodedCharsFunnel implements Funnel<CharSequence> {
     INSTANCE;
 
@@ -137,7 +126,7 @@
       private Object readResolve() {
         return stringFunnel(Charset.forName(charsetCanonicalName));
       }
-
+    
       private static final long serialVersionUID = 0;
     }
   }
@@ -205,45 +194,45 @@
 
   /**
    * Returns a funnel for longs.
-   *
+   * 
    * @since 13.0
    */
   public static Funnel<Long> longFunnel() {
     return LongFunnel.INSTANCE;
   }
-
+  
   private enum LongFunnel implements Funnel<Long> {
     INSTANCE;
-
+    
     public void funnel(Long from, PrimitiveSink into) {
       into.putLong(from);
     }
-
+    
     @Override public String toString() {
       return "Funnels.longFunnel()";
     }
   }
-
+  
   /**
    * Wraps a {@code PrimitiveSink} as an {@link OutputStream}, so it is easy to
    * {@link Funnel#funnel funnel} an object to a {@code PrimitiveSink}
-   * if there is already a way to write the contents of the object to an {@code OutputStream}.
-   *
+   * if there is already a way to write the contents of the object to an {@code OutputStream}.  
+   * 
    * <p>The {@code close} and {@code flush} methods of the returned {@code OutputStream}
    * do nothing, and no method throws {@code IOException}.
-   *
+   * 
    * @since 13.0
    */
   public static OutputStream asOutputStream(PrimitiveSink sink) {
     return new SinkAsStream(sink);
   }
-
+  
   private static class SinkAsStream extends OutputStream {
     final PrimitiveSink sink;
     SinkAsStream(PrimitiveSink sink) {
       this.sink = Preconditions.checkNotNull(sink);
     }
-
+    
     @Override public void write(int b) {
       sink.putByte((byte) b);
     }
@@ -255,7 +244,7 @@
     @Override public void write(byte[] bytes, int off, int len) {
       sink.putBytes(bytes, off, len);
     }
-
+    
     @Override public String toString() {
       return "Funnels.asOutputStream(" + sink + ")";
     }
diff --git a/guava/src/com/google/common/hash/HashCode.java b/guava/src/com/google/common/hash/HashCode.java
index 6fe665a..7ee228d 100644
--- a/guava/src/com/google/common/hash/HashCode.java
+++ b/guava/src/com/google/common/hash/HashCode.java
@@ -105,6 +105,12 @@
   }
 
   /**
+   * Returns whether this {@code HashCode} and that {@code HashCode} have the same value, given that
+   * they have the same number of bits.
+   */
+  abstract boolean equalsSameBits(HashCode that);
+
+  /**
    * Creates a 32-bit {@code HashCode} representation of the given int value. The underlying bytes
    * are interpreted in little endian order.
    *
@@ -157,6 +163,10 @@
       }
     }
 
+    @Override boolean equalsSameBits(HashCode that) {
+      return hash == that.asInt();
+    }
+
     private static final long serialVersionUID = 0;
   }
 
@@ -217,6 +227,11 @@
       }
     }
 
+    @Override
+    boolean equalsSameBits(HashCode that) {
+      return hash == that.asLong();
+    }
+
     private static final long serialVersionUID = 0;
   }
 
@@ -292,6 +307,11 @@
       return bytes;
     }
 
+    @Override
+    boolean equalsSameBits(HashCode that) {
+      return MessageDigest.isEqual(bytes, that.getBytesInternal());
+    }
+
     private static final long serialVersionUID = 0;
   }
 
@@ -334,9 +354,7 @@
   public final boolean equals(@Nullable Object object) {
     if (object instanceof HashCode) {
       HashCode that = (HashCode) object;
-      // Undocumented: this is a non-short-circuiting equals(), in case this is a cryptographic
-      // hash code, in which case we don't want to leak timing information
-      return MessageDigest.isEqual(this.asBytes(), that.asBytes());
+      return bits() == that.bits() && equalsSameBits(that);
     }
     return false;
   }
diff --git a/guava/src/com/google/common/hash/HashCodes.java b/guava/src/com/google/common/hash/HashCodes.java
deleted file mode 100644
index 8de5970..0000000
--- a/guava/src/com/google/common/hash/HashCodes.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2011 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.google.common.hash;
-
-import com.google.common.annotations.Beta;
-
-import java.io.Serializable;
-
-/**
- * Static factories for creating {@link HashCode} instances; most users should never have to use
- * this. All returned instances are {@link Serializable}.
- *
- * @author Dimitris Andreou
- * @since 12.0
- * @deprecated Use the duplicated methods in {@link HashCode} instead. This class is scheduled
- *     to be removed in Guava 16.0.
- */
-@Beta
-@Deprecated
-public final class HashCodes {
-  private HashCodes() {}
-
-  /**
-   * Creates a 32-bit {@code HashCode}, of which the bytes will form the passed int, interpreted
-   * in little endian order.
-   *
-   * @deprecated Use {@link HashCode#fromInt} instead. This method is scheduled to be removed in
-   *     Guava 16.0.
-   */
-  @Deprecated
-  public static HashCode fromInt(int hash) {
-    return HashCode.fromInt(hash);
-  }
-
-  /**
-   * Creates a 64-bit {@code HashCode}, of which the bytes will form the passed long, interpreted
-   * in little endian order.
-   *
-   * @deprecated Use {@link HashCode#fromLong} instead. This method is scheduled to be removed in
-   *     Guava 16.0.
-   */
-  @Deprecated
-  public static HashCode fromLong(long hash) {
-    return HashCode.fromLong(hash);
-  }
-
-  /**
-   * Creates a {@code HashCode} from a byte array. The array is defensively copied to preserve
-   * the immutability contract of {@code HashCode}. The array cannot be empty.
-   *
-   * @deprecated Use {@link HashCode#fromBytes} instead. This method is scheduled to be removed in
-   *     Guava 16.0.
-   */
-  @Deprecated
-  public static HashCode fromBytes(byte[] bytes) {
-    return HashCode.fromBytes(bytes);
-  }
-}
diff --git a/guava/src/com/google/common/hash/HashFunction.java b/guava/src/com/google/common/hash/HashFunction.java
index 46a6ed9..2007ba8 100644
--- a/guava/src/com/google/common/hash/HashFunction.java
+++ b/guava/src/com/google/common/hash/HashFunction.java
@@ -194,18 +194,6 @@
   HashCode hashUnencodedChars(CharSequence input);
 
   /**
-   * Shortcut for {@code newHasher().putUnencodedChars(input).hash()}. The implementation
-   * <i>might</i> perform better than its longhand equivalent, but should not perform worse.
-   * Note that no character encoding is performed; the low byte and high byte of each {@code char}
-   * are hashed directly (in that order).
-   *
-   * @deprecated Use {@link HashFunction#hashUnencodedChars} instead. This method is scheduled for
-   *     removal in Guava 16.0.
-   */
-  @Deprecated
-  HashCode hashString(CharSequence input);
-
-  /**
    * Shortcut for {@code newHasher().putString(input, charset).hash()}. Characters are encoded
    * using the given {@link Charset}. The implementation <i>might</i> perform better than its
    * longhand equivalent, but should not perform worse.
diff --git a/guava/src/com/google/common/hash/Hasher.java b/guava/src/com/google/common/hash/Hasher.java
index 1565bd4..2dd4a9a 100644
--- a/guava/src/com/google/common/hash/Hasher.java
+++ b/guava/src/com/google/common/hash/Hasher.java
@@ -83,16 +83,6 @@
   @Override Hasher putUnencodedChars(CharSequence charSequence);
 
   /**
-   * Equivalent to processing each {@code char} value in the {@code CharSequence}, in order.
-   * The input must not be updated while this method is in progress.
-   *
-   * @deprecated Use {@link Hasher#putUnencodedChars} instead. This method is scheduled for
-   *     removal in Guava 16.0.
-   */
-  @Deprecated
-  @Override Hasher putString(CharSequence charSequence);
-
-  /**
    * Equivalent to {@code putBytes(charSequence.toString().getBytes(charset))}.
    */
   @Override Hasher putString(CharSequence charSequence, Charset charset);
diff --git a/guava/src/com/google/common/hash/Hashing.java b/guava/src/com/google/common/hash/Hashing.java
index 9f926d2..74ab112 100644
--- a/guava/src/com/google/common/hash/Hashing.java
+++ b/guava/src/com/google/common/hash/Hashing.java
@@ -226,6 +226,20 @@
   }
 
   /**
+   * Returns a hash function implementing the CRC32C checksum algorithm (32 hash bits) as described
+   * by RFC 3720, Section 12.1.
+   *
+   * @since 18.0
+   */
+  public static HashFunction crc32c() {
+    return Crc32cHolder.CRC_32_C;
+  }
+
+  private static final class Crc32cHolder {
+    static final HashFunction CRC_32_C = new Crc32cHashFunction();
+  }
+
+  /**
    * Returns a hash function implementing the CRC-32 checksum algorithm (32 hash bits) by delegating
    * to the {@link CRC32} {@link Checksum}.
    *
@@ -290,19 +304,6 @@
   }
 
   /**
-   * If {@code hashCode} has enough bits, returns {@code hashCode.asLong()}, otherwise
-   * returns a {@code long} value with {@code hashCode.asInt()} as the least-significant
-   * four bytes and {@code 0x00} as each of the most-significant four bytes.
-   *
-   * @deprecated Use {@code HashCode.padToLong()} instead. This method is scheduled to be
-   *     removed in Guava 15.0.
-   */
-  @Deprecated
-  public static long padToLong(HashCode hashCode) {
-    return hashCode.padToLong();
-  }
-
-  /**
    * Assigns to {@code hashCode} a "bucket" in the range {@code [0, buckets)}, in a uniform
    * manner that minimizes the need for remapping as {@code buckets} grows. That is,
    * {@code consistentHash(h, n)} equals:
diff --git a/guava/src/com/google/common/hash/MessageDigestHashFunction.java b/guava/src/com/google/common/hash/MessageDigestHashFunction.java
index 07ff8e4..e160833 100644
--- a/guava/src/com/google/common/hash/MessageDigestHashFunction.java
+++ b/guava/src/com/google/common/hash/MessageDigestHashFunction.java
@@ -153,13 +153,7 @@
       done = true;
       return (bytes == digest.getDigestLength())
           ? HashCode.fromBytesNoCopy(digest.digest())
-          : HashCode.fromBytesNoCopy(copyOf(digest.digest(), bytes));
+          : HashCode.fromBytesNoCopy(Arrays.copyOf(digest.digest(), bytes));
     }
   }
-
-  private static byte[] copyOf(byte[] array, int length) {
-    byte[] newArray = new byte[length];
-    System.arraycopy(array, 0, newArray, 0, Math.min(length, array.length));
-    return newArray;
-  }
 }
diff --git a/guava/src/com/google/common/hash/Murmur3_32HashFunction.java b/guava/src/com/google/common/hash/Murmur3_32HashFunction.java
index 1c43d30..db6e673 100644
--- a/guava/src/com/google/common/hash/Murmur3_32HashFunction.java
+++ b/guava/src/com/google/common/hash/Murmur3_32HashFunction.java
@@ -102,7 +102,7 @@
   }
 
   // TODO(user): Maybe implement #hashBytes instead?
-  @Override public HashCode hashString(CharSequence input) {
+  @Override public HashCode hashUnencodedChars(CharSequence input) {
     int h1 = seed;
 
     // step through the CharSequence 2 chars at a time
diff --git a/guava/src/com/google/common/hash/PrimitiveSink.java b/guava/src/com/google/common/hash/PrimitiveSink.java
index 43a9cc1..d0f7af1 100644
--- a/guava/src/com/google/common/hash/PrimitiveSink.java
+++ b/guava/src/com/google/common/hash/PrimitiveSink.java
@@ -20,7 +20,7 @@
 
 /**
  * An object which can receive a stream of primitive values.
- * 
+ *
  * @author Kevin Bourrillion
  * @since 12.0 (in 11.0 as {@code Sink})
  */
@@ -41,15 +41,15 @@
    * @return this instance
    */
   PrimitiveSink putBytes(byte[] bytes);
-  
+
   /**
    * Puts a chunk of an array of bytes into this sink. {@code bytes[off]} is the first byte written,
-   * {@code bytes[off + len - 1]} is the last. 
-   * 
+   * {@code bytes[off + len - 1]} is the last.
+   *
    * @param bytes a byte array
    * @param off the start offset in the array
    * @param len the number of bytes to write
-   * @return this instance 
+   * @return this instance
    * @throws IndexOutOfBoundsException if {@code off < 0} or {@code off + len > bytes.length} or
    *   {@code len < 0}
    */
@@ -91,15 +91,6 @@
   PrimitiveSink putChar(char c);
 
   /**
-   * Puts a string into this sink.
-   *
-   * @deprecated Use {PrimitiveSink#putUnencodedChars} instead. This method is scheduled for
-   *     removal in Guava 16.0.
-   */
-  @Deprecated
-  PrimitiveSink putString(CharSequence charSequence);
-
-  /**
    * Puts each 16-bit code unit from the {@link CharSequence} into this sink.
    *
    * @since 15.0 (since 11.0 as putString(CharSequence))
diff --git a/guava/src/com/google/common/html/HtmlEscapers.java b/guava/src/com/google/common/html/HtmlEscapers.java
index ee2cd00..d96febf 100644
--- a/guava/src/com/google/common/html/HtmlEscapers.java
+++ b/guava/src/com/google/common/html/HtmlEscapers.java
@@ -49,7 +49,7 @@
    * other Unicode encodings can).
    *
    *
-   * <p><b>Note</b>: This escaper only performs minimal escaping to make content
+   * <p><b>Note:</b> This escaper only performs minimal escaping to make content
    * structurally compatible with HTML. Specifically, it does not perform entity
    * replacement (symbolic or numeric), so it does not replace non-ASCII code
    * points with character references. This escaper escapes only the following
diff --git a/guava/src/com/google/common/io/BaseEncoding.java b/guava/src/com/google/common/io/BaseEncoding.java
index fdde18e..13c3f55 100644
--- a/guava/src/com/google/common/io/BaseEncoding.java
+++ b/guava/src/com/google/common/io/BaseEncoding.java
@@ -147,7 +147,7 @@
     }
 
     DecodingException(Throwable cause) {
-      initCause(cause);
+      super(cause);
     }
   }
 
@@ -189,26 +189,6 @@
   }
 
   /**
-   * Returns an {@code OutputSupplier} that supplies streams that encode bytes using this encoding
-   * into writers from the specified {@code OutputSupplier}.
-   *
-   * @deprecated Use {@link #encodingSink(CharSink)} instead. This method is scheduled to be
-   *     removed in Guava 16.0.
-   */
-  @Deprecated
-  @GwtIncompatible("Writer,OutputStream")
-  public final OutputSupplier<OutputStream> encodingStream(
-      final OutputSupplier<? extends Writer> writerSupplier) {
-    checkNotNull(writerSupplier);
-    return new OutputSupplier<OutputStream>() {
-      @Override
-      public OutputStream getOutput() throws IOException {
-        return encodingStream(writerSupplier.getOutput());
-      }
-    };
-  }
-
-  /**
    * Returns a {@code ByteSink} that writes base-encoded bytes to the specified {@code CharSink}.
    */
   @GwtIncompatible("ByteSink,CharSink")
@@ -284,26 +264,6 @@
   }
 
   /**
-   * Returns an {@code InputSupplier} that supplies input streams that decode base-encoded input
-   * from readers from the specified supplier.
-   *
-   * @deprecated Use {@link #decodingSource(CharSource)} instead. This method is scheduled to be
-   *     removed in Guava 16.0.
-   */
-  @Deprecated
-  @GwtIncompatible("Reader,InputStream")
-  public final InputSupplier<InputStream> decodingStream(
-      final InputSupplier<? extends Reader> readerSupplier) {
-    checkNotNull(readerSupplier);
-    return new InputSupplier<InputStream>() {
-      @Override
-      public InputStream getInput() throws IOException {
-        return decodingStream(readerSupplier.getInput());
-      }
-    };
-  }
-
-  /**
    * Returns a {@code ByteSource} that reads base-encoded bytes from the specified
    * {@code CharSource}.
    */
diff --git a/guava/src/com/google/common/io/ByteSink.java b/guava/src/com/google/common/io/ByteSink.java
index e11b924..fcb6df2 100644
--- a/guava/src/com/google/common/io/ByteSink.java
+++ b/guava/src/com/google/common/io/ByteSink.java
@@ -44,7 +44,7 @@
  * @since 14.0
  * @author Colin Decker
  */
-public abstract class ByteSink implements OutputSupplier<OutputStream> {
+public abstract class ByteSink {
 
   /**
    * Constructor for use by subclasses.
@@ -70,21 +70,6 @@
   public abstract OutputStream openStream() throws IOException;
 
   /**
-   * This method is a temporary method provided for easing migration from suppliers to sources and
-   * sinks.
-   *
-   * @since 15.0
-   * @deprecated This method is only provided for temporary compatibility with the
-   *     {@link OutputSupplier} interface and should not be called directly. Use
-   *     {@link #openStream} instead. This method is scheduled for removal in Guava 18.0.
-   */
-  @Override
-  @Deprecated
-  public final OutputStream getOutput() throws IOException {
-    return openStream();
-  }
-
-  /**
    * Opens a new buffered {@link OutputStream} for writing to this sink. The returned stream is
    * not required to be a {@link BufferedOutputStream} in order to allow implementations to simply
    * delegate to {@link #openStream()} when the stream returned by that method does not benefit
diff --git a/guava/src/com/google/common/io/ByteSource.java b/guava/src/com/google/common/io/ByteSource.java
index 21937cc..4cddcdd 100644
--- a/guava/src/com/google/common/io/ByteSource.java
+++ b/guava/src/com/google/common/io/ByteSource.java
@@ -56,7 +56,7 @@
  * @since 14.0
  * @author Colin Decker
  */
-public abstract class ByteSource implements InputSupplier<InputStream> {
+public abstract class ByteSource {
 
   private static final int BUF_SIZE = 0x1000; // 4K
 
@@ -84,21 +84,6 @@
   public abstract InputStream openStream() throws IOException;
 
   /**
-   * This method is a temporary method provided for easing migration from suppliers to sources and
-   * sinks.
-   *
-   * @since 15.0
-   * @deprecated This method is only provided for temporary compatibility with the
-   *     {@link InputSupplier} interface and should not be called directly. Use {@link #openStream}
-   *     instead. This method is scheduled for removal in Guava 18.0.
-   */
-  @Override
-  @Deprecated
-  public final InputStream getInput() throws IOException {
-    return openStream();
-  }
-
-  /**
    * Opens a new buffered {@link InputStream} for reading from this source. The returned stream is
    * not required to be a {@link BufferedInputStream} in order to allow implementations to simply
    * delegate to {@link #openStream()} when the stream returned by that method does not benefit
diff --git a/guava/src/com/google/common/io/ByteStreams.java b/guava/src/com/google/common/io/ByteStreams.java
index 71c08fe..db83a7f 100644
--- a/guava/src/com/google/common/io/ByteStreams.java
+++ b/guava/src/com/google/common/io/ByteStreams.java
@@ -21,10 +21,6 @@
 import static com.google.common.base.Preconditions.checkPositionIndex;
 
 import com.google.common.annotations.Beta;
-import com.google.common.base.Function;
-import com.google.common.collect.Iterables;
-import com.google.common.hash.HashCode;
-import com.google.common.hash.HashFunction;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -41,7 +37,6 @@
 import java.nio.channels.ReadableByteChannel;
 import java.nio.channels.WritableByteChannel;
 import java.util.Arrays;
-import java.util.zip.Checksum;
 
 /**
  * Provides utility methods for working with byte arrays and I/O streams.
@@ -57,119 +52,6 @@
   private ByteStreams() {}
 
   /**
-   * Returns a factory that will supply instances of
-   * {@link ByteArrayInputStream} that read from the given byte array.
-   *
-   * @param b the input buffer
-   * @return the factory
-   * @deprecated Use {@link ByteSource#wrap(byte[])} instead. This method is
-   *     scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static InputSupplier<ByteArrayInputStream> newInputStreamSupplier(
-      byte[] b) {
-    return asInputSupplier(ByteSource.wrap(b));
-  }
-
-  /**
-   * Returns a factory that will supply instances of
-   * {@link ByteArrayInputStream} that read from the given byte array.
-   *
-   * @param b the input buffer
-   * @param off the offset in the buffer of the first byte to read
-   * @param len the maximum number of bytes to read from the buffer
-   * @return the factory
-   * @deprecated Use {@code ByteSource.wrap(b).slice(off, len)} instead. This
-   *     method is scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static InputSupplier<ByteArrayInputStream> newInputStreamSupplier(
-      final byte[] b, final int off, final int len) {
-    return asInputSupplier(ByteSource.wrap(b).slice(off, len));
-  }
-
-  /**
-   * Returns a new {@link ByteSource} that reads bytes from the given byte array.
-   *
-   * @since 14.0
-   * @deprecated Use {@link ByteSource#wrap(byte[])} instead. This method is
-   *     scheduled to be removed in Guava 16.0.
-   */
-  @Deprecated
-  public static ByteSource asByteSource(byte[] b) {
-    return ByteSource.wrap(b);
-  }
-
-  /**
-   * Writes a byte array to an output stream from the given supplier.
-   *
-   * @param from the bytes to write
-   * @param to the output supplier
-   * @throws IOException if an I/O error occurs
-   * @deprecated Use {@link ByteSink#write(byte[])} instead. This method is
-   *     scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static void write(byte[] from,
-      OutputSupplier<? extends OutputStream> to) throws IOException {
-    asByteSink(to).write(from);
-  }
-
-  /**
-   * Opens input and output streams from the given suppliers, copies all
-   * bytes from the input to the output, and closes the streams.
-   *
-   * @param from the input factory
-   * @param to the output factory
-   * @return the number of bytes copied
-   * @throws IOException if an I/O error occurs
-   * @deprecated Use {@link ByteSource#copyTo(ByteSink)} instead. This method
-   *     is scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static long copy(InputSupplier<? extends InputStream> from,
-      OutputSupplier<? extends OutputStream> to) throws IOException {
-    return asByteSource(from).copyTo(asByteSink(to));
-  }
-
-  /**
-   * Opens an input stream from the supplier, copies all bytes from the
-   * input to the output, and closes the input stream. Does not close
-   * or flush the output stream.
-   *
-   * @param from the input factory
-   * @param to the output stream to write to
-   * @return the number of bytes copied
-   * @throws IOException if an I/O error occurs
-   * @deprecated Use {@link ByteSource#copyTo(OutputStream)} instead. This
-   *      method is scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static long copy(InputSupplier<? extends InputStream> from,
-      OutputStream to) throws IOException {
-    return asByteSource(from).copyTo(to);
-  }
-
-  /**
-   * Opens an output stream from the supplier, copies all bytes from the input
-   * to the output, and closes the output stream. Does not close or flush the
-   * input stream.
-   *
-   * @param from the input stream to read from
-   * @param to the output factory
-   * @return the number of bytes copied
-   * @throws IOException if an I/O error occurs
-   * @since 10.0
-   * @deprecated Use {@link ByteSink#writeFrom(InputStream)} instead. This
-   *     method is scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static long copy(InputStream from,
-      OutputSupplier<? extends OutputStream> to) throws IOException {
-    return asByteSink(to).writeFrom(from);
-  }
-
-  /**
    * Copies all bytes from the input stream to the output stream.
    * Does not close or flush either stream.
    *
@@ -251,7 +133,7 @@
       if (read == -1) {
         // end of stream before reading expectedSize bytes
         // just return the bytes read so far
-        return copyOf(bytes, off);
+        return Arrays.copyOf(bytes, off);
       }
       remaining -= read;
     }
@@ -273,12 +155,6 @@
     return result;
   }
 
-  private static byte[] copyOf(byte[] array, int length) {
-    byte[] newArray = new byte[length];
-    System.arraycopy(array, 0, newArray, 0, length);
-    return newArray;
-  }
-
   /**
    * BAOS that provides limited access to its internal byte array.
    */
@@ -294,20 +170,6 @@
   }
 
   /**
-   * Returns the data from a {@link InputStream} factory as a byte array.
-   *
-   * @param supplier the factory
-   * @throws IOException if an I/O error occurs
-   * @deprecated Use {@link ByteSource#read()} instead. This method is
-   *     scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static byte[] toByteArray(
-      InputSupplier<? extends InputStream> supplier) throws IOException {
-    return asByteSource(supplier).read();
-  }
-
-  /**
    * Returns a new {@link ByteArrayDataInput} instance to read from the {@code
    * bytes} array from the beginning.
    */
@@ -746,31 +608,6 @@
   }
 
   /**
-   * Returns the length of a supplied input stream, in bytes.
-   *
-   * @deprecated Use {@link ByteSource#size()} instead. This method is
-   *     scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static long length(
-      InputSupplier<? extends InputStream> supplier) throws IOException {
-    return asByteSource(supplier).size();
-  }
-
-  /**
-   * Returns true if the supplied input streams contain the same bytes.
-   *
-   * @throws IOException if an I/O error occurs
-   * @deprecated Use {@link ByteSource#contentEquals(ByteSource)} instead. This
-   *     method is scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static boolean equal(InputSupplier<? extends InputStream> supplier1,
-      InputSupplier<? extends InputStream> supplier2) throws IOException {
-    return asByteSource(supplier1).contentEquals(asByteSource(supplier2));
-  }
-
-  /**
    * Attempts to read enough bytes from the stream to fill the given byte array,
    * with the same behavior as {@link DataInput#readFully(byte[])}.
    * Does not close the stream.
@@ -839,34 +676,6 @@
   }
 
   /**
-   * Process the bytes of a supplied stream
-   *
-   * @param supplier the input stream factory
-   * @param processor the object to which to pass the bytes of the stream
-   * @return the result of the byte processor
-   * @throws IOException if an I/O error occurs
-   * @deprecated Use {@link ByteSource#read(ByteProcessor)} instead. This
-   *     method is scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static <T> T readBytes(
-      InputSupplier<? extends InputStream> supplier,
-      ByteProcessor<T> processor) throws IOException {
-    checkNotNull(supplier);
-    checkNotNull(processor);
-
-    Closer closer = Closer.create();
-    try {
-      InputStream in = closer.register(supplier.getInput());
-      return readBytes(in, processor);
-    } catch (Throwable e) {
-      throw closer.rethrow(e);
-    } finally {
-      closer.close();
-    }
-  }
-
-  /**
    * Process the bytes of the given input stream using the given processor.
    *
    * @param input the input stream to process
@@ -889,58 +698,6 @@
   }
 
   /**
-   * Computes and returns the checksum value for a supplied input stream.
-   * The checksum object is reset when this method returns successfully.
-   *
-   * @param supplier the input stream factory
-   * @param checksum the checksum object
-   * @return the result of {@link Checksum#getValue} after updating the
-   *     checksum object with all of the bytes in the stream
-   * @throws IOException if an I/O error occurs
-   * @deprecated Use {@code hash} with the {@code Hashing.crc32()} or
-   *     {@code Hashing.adler32()} hash functions instead. This method is
-   *     scheduled to be removed in Guava 15.0.
-   */
-  @Deprecated
-  public static long getChecksum(
-      InputSupplier<? extends InputStream> supplier, final Checksum checksum)
-      throws IOException {
-    checkNotNull(checksum);
-    return readBytes(supplier, new ByteProcessor<Long>() {
-      @Override
-      public boolean processBytes(byte[] buf, int off, int len) {
-        checksum.update(buf, off, len);
-        return true;
-      }
-      @Override
-      public Long getResult() {
-        long result = checksum.getValue();
-        checksum.reset();
-        return result;
-      }
-    });
-  }
-
-  /**
-   * Computes the hash code of the data supplied by {@code supplier} using {@code
-   * hashFunction}.
-   *
-   * @param supplier the input stream factory
-   * @param hashFunction the hash function to use to hash the data
-   * @return the {@link HashCode} of all of the bytes in the input stream
-   * @throws IOException if an I/O error occurs
-   * @since 12.0
-   * @deprecated Use {@link ByteSource#hash(HashFunction)} instead. This method
-   *     is scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static HashCode hash(
-      InputSupplier<? extends InputStream> supplier, HashFunction hashFunction)
-      throws IOException {
-    return asByteSource(supplier).hash(hashFunction);
-  }
-
-  /**
    * Reads some bytes from an input stream and stores them into the buffer array
    * {@code b}. This method blocks until {@code len} bytes of input data have
    * been read into the array, or end of file is detected. The number of bytes
@@ -981,143 +738,4 @@
     }
     return total;
   }
-
-  /**
-   * Returns an {@link InputSupplier} that returns input streams from the
-   * an underlying supplier, where each stream starts at the given
-   * offset and is limited to the specified number of bytes.
-   *
-   * @param supplier the supplier from which to get the raw streams
-   * @param offset the offset in bytes into the underlying stream where
-   *     the returned streams will start
-   * @param length the maximum length of the returned streams
-   * @throws IllegalArgumentException if offset or length are negative
-   * @deprecated Use {@link ByteSource#slice(int, int)} instead. This method is
-   *     scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static InputSupplier<InputStream> slice(
-      final InputSupplier<? extends InputStream> supplier,
-      final long offset,
-      final long length) {
-    return asInputSupplier(asByteSource(supplier).slice(offset, length));
-  }
-
-  /**
-   * Joins multiple {@link InputStream} suppliers into a single supplier.
-   * Streams returned from the supplier will contain the concatenated data from
-   * the streams of the underlying suppliers.
-   *
-   * <p>Only one underlying input stream will be open at a time. Closing the
-   * joined stream will close the open underlying stream.
-   *
-   * <p>Reading from the joined stream will throw a {@link NullPointerException}
-   * if any of the suppliers are null or return null.
-   *
-   * @param suppliers the suppliers to concatenate
-   * @return a supplier that will return a stream containing the concatenated
-   *     stream data
-   * @deprecated Use {@link ByteSource#concat(Iterable)} instead. This method
-   *     is scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static InputSupplier<InputStream> join(
-      final Iterable<? extends InputSupplier<? extends InputStream>> suppliers) {
-    checkNotNull(suppliers);
-    Iterable<ByteSource> sources = Iterables.transform(suppliers,
-        new Function<InputSupplier<? extends InputStream>, ByteSource>() {
-          @Override
-          public ByteSource apply(InputSupplier<? extends InputStream> input) {
-            return asByteSource(input);
-          }
-        });
-    return asInputSupplier(ByteSource.concat(sources));
-  }
-
-  /**
-   * Varargs form of {@link #join(Iterable)}.
-   *
-   * @deprecated Use {@link ByteSource#concat(ByteSource[])} instead. This
-   *     method is scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  @SuppressWarnings("unchecked") // suppress "possible heap pollution" warning in JDK7
-  public static InputSupplier<InputStream> join(
-      InputSupplier<? extends InputStream>... suppliers) {
-    return join(Arrays.asList(suppliers));
-  }
-
-  // TODO(user): Remove these once Input/OutputSupplier methods are removed
-
-  /**
-   * Returns a view of the given {@code InputStream} supplier as a
-   * {@code ByteSource}.
-   *
-   * <p>This method is a temporary method provided for easing migration from
-   * suppliers to sources and sinks.
-   *
-   * @since 15.0
-   * @deprecated Convert all {@code InputSupplier<? extends InputStream>}
-   *     implementations to extend {@link ByteSource} or provide a method for
-   *     viewing the object as a {@code ByteSource}. This method is scheduled
-   *     for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static ByteSource asByteSource(
-      final InputSupplier<? extends InputStream> supplier) {
-    checkNotNull(supplier);
-    return new ByteSource() {
-      @Override
-      public InputStream openStream() throws IOException {
-        return supplier.getInput();
-      }
-
-      @Override
-      public String toString() {
-        return "ByteStreams.asByteSource(" + supplier + ")";
-      }
-    };
-  }
-
-  /**
-   * Returns a view of the given {@code OutputStream} supplier as a
-   * {@code ByteSink}.
-   *
-   * <p>This method is a temporary method provided for easing migration from
-   * suppliers to sources and sinks.
-   *
-   * @since 15.0
-   * @deprecated Convert all {@code OutputSupplier<? extends OutputStream>}
-   *     implementations to extend {@link ByteSink} or provide a method for
-   *     viewing the object as a {@code ByteSink}. This method is scheduled
-   *     for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static ByteSink asByteSink(
-      final OutputSupplier<? extends OutputStream> supplier) {
-    checkNotNull(supplier);
-    return new ByteSink() {
-      @Override
-      public OutputStream openStream() throws IOException {
-        return supplier.getOutput();
-      }
-
-      @Override
-      public String toString() {
-        return "ByteStreams.asByteSink(" + supplier + ")";
-      }
-    };
-  }
-
-  @SuppressWarnings("unchecked") // used internally where known to be safe
-  static <S extends InputStream> InputSupplier<S> asInputSupplier(
-      final ByteSource source) {
-    return (InputSupplier) checkNotNull(source);
-  }
-
-  @SuppressWarnings("unchecked") // used internally where known to be safe
-  static <S extends OutputStream> OutputSupplier<S> asOutputSupplier(
-      final ByteSink sink) {
-    return (OutputSupplier) checkNotNull(sink);
-  }
 }
diff --git a/guava/src/com/google/common/io/CharSink.java b/guava/src/com/google/common/io/CharSink.java
index 214c070..922c950 100644
--- a/guava/src/com/google/common/io/CharSink.java
+++ b/guava/src/com/google/common/io/CharSink.java
@@ -46,7 +46,7 @@
  * @since 14.0
  * @author Colin Decker
  */
-public abstract class CharSink implements OutputSupplier<Writer> {
+public abstract class CharSink {
 
   /**
    * Constructor for use by subclasses.
@@ -64,21 +64,6 @@
   public abstract Writer openStream() throws IOException;
 
   /**
-   * This method is a temporary method provided for easing migration from suppliers to sources and
-   * sinks.
-   *
-   * @since 15.0
-   * @deprecated This method is only provided for temporary compatibility with the
-   *     {@link OutputSupplier} interface and should not be called directly. Use
-   *     {@link #openStream} instead. This method is scheduled for removal in Guava 18.0.
-   */
-  @Override
-  @Deprecated
-  public final Writer getOutput() throws IOException {
-    return openStream();
-  }
-
-  /**
    * Opens a new buffered {@link Writer} for writing to this sink. The returned stream is not
    * required to be a {@link BufferedWriter} in order to allow implementations to simply delegate
    * to {@link #openStream()} when the stream returned by that method does not benefit from
diff --git a/guava/src/com/google/common/io/CharSource.java b/guava/src/com/google/common/io/CharSource.java
index 1554196..fd47bbf 100644
--- a/guava/src/com/google/common/io/CharSource.java
+++ b/guava/src/com/google/common/io/CharSource.java
@@ -62,7 +62,7 @@
  * @since 14.0
  * @author Colin Decker
  */
-public abstract class CharSource implements InputSupplier<Reader> {
+public abstract class CharSource {
 
   /**
    * Constructor for use by subclasses.
@@ -80,21 +80,6 @@
   public abstract Reader openStream() throws IOException;
 
   /**
-   * This method is a temporary method provided for easing migration from suppliers to sources and
-   * sinks.
-   *
-   * @since 15.0
-   * @deprecated This method is only provided for temporary compatibility with the
-   *     {@link InputSupplier} interface and should not be called directly. Use {@link #openStream}
-   *     instead. This method is scheduled for removal in Guava 18.0.
-   */
-  @Override
-  @Deprecated
-  public final Reader getInput() throws IOException {
-    return openStream();
-  }
-
-  /**
    * Opens a new {@link BufferedReader} for reading from this source. This method should return a
    * new, independent reader each time it is called.
    *
@@ -380,7 +365,7 @@
               if (lines.hasNext()) {
                 String next = lines.next();
                 // skip last line if it's empty
-                if (lines.hasNext() || next.length() != 0) {
+                if (lines.hasNext() || !next.isEmpty()) {
                   return next;
                 }
               }
diff --git a/guava/src/com/google/common/io/CharStreams.java b/guava/src/com/google/common/io/CharStreams.java
index 98f620a..8c8adce 100644
--- a/guava/src/com/google/common/io/CharStreams.java
+++ b/guava/src/com/google/common/io/CharStreams.java
@@ -20,24 +20,14 @@
 import static com.google.common.base.Preconditions.checkPositionIndexes;
 
 import com.google.common.annotations.Beta;
-import com.google.common.base.Charsets;
-import com.google.common.base.Function;
-import com.google.common.collect.Iterables;
 
 import java.io.Closeable;
 import java.io.EOFException;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
 import java.io.Reader;
-import java.io.StringReader;
 import java.io.Writer;
 import java.nio.CharBuffer;
-import java.nio.charset.Charset;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -62,122 +52,6 @@
   private CharStreams() {}
 
   /**
-   * Returns a factory that will supply instances of {@link StringReader} that
-   * read a string value.
-   *
-   * @param value the string to read
-   * @return the factory
-   * @deprecated Use {@link CharSource#wrap(CharSequence)} instead. This method
-   *     is scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static InputSupplier<StringReader> newReaderSupplier(
-      final String value) {
-    return asInputSupplier(CharSource.wrap(value));
-  }
-
-  /**
-   * Returns a {@link CharSource} that reads the given string value.
-   *
-   * @since 14.0
-   * @deprecated Use {@link CharSource#wrap(CharSequence)} instead. This method
-   *     is scheduled to be removed in Guava 16.0.
-   */
-  @Deprecated
-  public static CharSource asCharSource(String string) {
-    return CharSource.wrap(string);
-  }
-
-  /**
-   * Returns a factory that will supply instances of {@link InputStreamReader},
-   * using the given {@link InputStream} factory and character set.
-   *
-   * @param in the factory that will be used to open input streams
-   * @param charset the charset used to decode the input stream; see {@link
-   *     Charsets} for helpful predefined constants
-   * @return the factory
-   * @deprecated Use {@link ByteSource#asCharSource(Charset)} instead. This
-   *     method is scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static InputSupplier<InputStreamReader> newReaderSupplier(
-      final InputSupplier<? extends InputStream> in, final Charset charset) {
-    return asInputSupplier(
-        ByteStreams.asByteSource(in).asCharSource(charset));
-  }
-
-  /**
-   * Returns a factory that will supply instances of {@link OutputStreamWriter},
-   * using the given {@link OutputStream} factory and character set.
-   *
-   * @param out the factory that will be used to open output streams
-   * @param charset the charset used to encode the output stream; see {@link
-   *     Charsets} for helpful predefined constants
-   * @return the factory
-   * @deprecated Use {@link ByteSink#asCharSink(Charset)} instead. This method
-   *     is scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static OutputSupplier<OutputStreamWriter> newWriterSupplier(
-      final OutputSupplier<? extends OutputStream> out, final Charset charset) {
-    return asOutputSupplier(
-        ByteStreams.asByteSink(out).asCharSink(charset));
-  }
-
-  /**
-   * Writes a character sequence (such as a string) to an appendable
-   * object from the given supplier.
-   *
-   * @param from the character sequence to write
-   * @param to the output supplier
-   * @throws IOException if an I/O error occurs
-   * @deprecated Use {@link CharSink#write(CharSequence)} instead. This method
-   *     is scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static <W extends Appendable & Closeable> void write(CharSequence from,
-      OutputSupplier<W> to) throws IOException {
-    asCharSink(to).write(from);
-  }
-
-  /**
-   * Opens {@link Readable} and {@link Appendable} objects from the
-   * given factories, copies all characters between the two, and closes
-   * them.
-   *
-   * @param from the input factory
-   * @param to the output factory
-   * @return the number of characters copied
-   * @throws IOException if an I/O error occurs
-   * @deprecated Use {@link CharSource#copyTo(CharSink)} instead. This method is
-   *     scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static <R extends Readable & Closeable,
-      W extends Appendable & Closeable> long copy(InputSupplier<R> from,
-      OutputSupplier<W> to) throws IOException {
-    return asCharSource(from).copyTo(asCharSink(to));
-  }
-
-  /**
-   * Opens a {@link Readable} object from the supplier, copies all characters
-   * to the {@link Appendable} object, and closes the input. Does not close
-   * or flush the output.
-   *
-   * @param from the input factory
-   * @param to the object to write to
-   * @return the number of characters copied
-   * @throws IOException if an I/O error occurs
-   * @deprecated Use {@link CharSource#copyTo(Appendable)} instead. This method
-   *     is scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static <R extends Readable & Closeable> long copy(
-      InputSupplier<R> from, Appendable to) throws IOException {
-    return asCharSource(from).copyTo(to);
-  }
-
-  /**
    * Copies all characters between the {@link Readable} and {@link Appendable}
    * objects. Does not close or flush either object.
    *
@@ -213,22 +87,6 @@
   }
 
   /**
-   * Returns the characters from a {@link Readable} & {@link Closeable} object
-   * supplied by a factory as a {@link String}.
-   *
-   * @param supplier the factory to read from
-   * @return a string containing all the characters
-   * @throws IOException if an I/O error occurs
-   * @deprecated Use {@link CharSource#read()} instead. This method is
-   *     scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static <R extends Readable & Closeable> String toString(
-      InputSupplier<R> supplier) throws IOException {
-    return asCharSource(supplier).read();
-  }
-
-  /**
    * Reads all characters from a {@link Readable} object into a new
    * {@link StringBuilder} instance. Does not close the {@code Readable}.
    *
@@ -243,49 +101,6 @@
   }
 
   /**
-   * Reads the first line from a {@link Readable} & {@link Closeable} object
-   * supplied by a factory. The line does not include line-termination
-   * characters, but does include other leading and trailing whitespace.
-   *
-   * @param supplier the factory to read from
-   * @return the first line, or null if the reader is empty
-   * @throws IOException if an I/O error occurs
-   * @deprecated Use {@link CharSource#readFirstLine()} instead. This method is
-   *     scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static <R extends Readable & Closeable> String readFirstLine(
-      InputSupplier<R> supplier) throws IOException {
-    return asCharSource(supplier).readFirstLine();
-  }
-
-  /**
-   * Reads all of the lines from a {@link Readable} & {@link Closeable} object
-   * supplied by a factory. The lines do not include line-termination
-   * characters, but do include other leading and trailing whitespace.
-   *
-   * @param supplier the factory to read from
-   * @return a mutable {@link List} containing all the lines
-   * @throws IOException if an I/O error occurs
-   * @deprecated Use {@link CharSource#readLines()} instead, but note that it
-   *     returns an {@code ImmutableList}. This method is scheduled for removal
-   *     in Guava 18.0.
-   */
-  @Deprecated
-  public static <R extends Readable & Closeable> List<String> readLines(
-      InputSupplier<R> supplier) throws IOException {
-    Closer closer = Closer.create();
-    try {
-      R r = closer.register(supplier.getInput());
-      return readLines(r);
-    } catch (Throwable e) {
-      throw closer.rethrow(e);
-    } finally {
-      closer.close();
-    }
-  }
-
-  /**
    * Reads all of the lines from a {@link Readable} object. The lines do
    * not include line-termination characters, but do include other
    * leading and trailing whitespace.
@@ -334,79 +149,6 @@
   }
 
   /**
-   * Streams lines from a {@link Readable} and {@link Closeable} object
-   * supplied by a factory, stopping when our callback returns false, or we
-   * have read all of the lines.
-   *
-   * @param supplier the factory to read from
-   * @param callback the LineProcessor to use to handle the lines
-   * @return the output of processing the lines
-   * @throws IOException if an I/O error occurs
-   * @deprecated Use {@link CharSource#readLines(LineProcessor)} instead. This
-   *     method is scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static <R extends Readable & Closeable, T> T readLines(
-      InputSupplier<R> supplier, LineProcessor<T> callback) throws IOException {
-    checkNotNull(supplier);
-    checkNotNull(callback);
-
-    Closer closer = Closer.create();
-    try {
-      R r = closer.register(supplier.getInput());
-      return readLines(r, callback);
-    } catch (Throwable e) {
-      throw closer.rethrow(e);
-    } finally {
-      closer.close();
-    }
-  }
-
-  /**
-   * Joins multiple {@link Reader} suppliers into a single supplier.
-   * Reader returned from the supplier will contain the concatenated data
-   * from the readers of the underlying suppliers.
-   *
-   * <p>Reading from the joined reader will throw a {@link NullPointerException}
-   * if any of the suppliers are null or return null.
-   *
-   * <p>Only one underlying reader will be open at a time. Closing the
-   * joined reader will close the open underlying reader.
-   *
-   * @param suppliers the suppliers to concatenate
-   * @return a supplier that will return a reader containing the concatenated
-   *     data
-   * @deprecated Use {@link CharSource#concat(Iterable)} instead. This method
-   *     is scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static InputSupplier<Reader> join(
-      final Iterable<? extends InputSupplier<? extends Reader>> suppliers) {
-    checkNotNull(suppliers);
-    Iterable<CharSource> sources = Iterables.transform(suppliers,
-        new Function<InputSupplier<? extends Reader>, CharSource>() {
-          @Override
-          public CharSource apply(InputSupplier<? extends Reader> input) {
-            return asCharSource(input);
-          }
-        });
-    return asInputSupplier(CharSource.concat(sources));
-  }
-
-  /**
-   * Varargs form of {@link #join(Iterable)}.
-   *
-   * @deprecated Use {@link CharSource#concat(CharSource[])} instead. This
-   *     method is scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  @SuppressWarnings("unchecked") // suppress "possible heap pollution" warning in JDK7
-  public static InputSupplier<Reader> join(
-      InputSupplier<? extends Reader>... suppliers) {
-    return join(Arrays.asList(suppliers));
-  }
-
-  /**
    * Discards {@code n} characters of data from the reader. This method
    * will block until the full amount has been skipped. Does not close the
    * reader.
@@ -544,76 +286,4 @@
       }
     };
   }
-
-  /**
-   * Returns a view of the given {@code Readable} supplier as a
-   * {@code CharSource}.
-   *
-   * <p>This method is a temporary method provided for easing migration from
-   * suppliers to sources and sinks.
-   *
-   * @since 15.0
-   * @deprecated Convert all {@code InputSupplier<? extends Readable>}
-   *     implementations to extend {@link CharSource} or provide a method for
-   *     viewing the object as a {@code CharSource}. This method is scheduled
-   *     for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static CharSource asCharSource(
-      final InputSupplier<? extends Readable> supplier) {
-    checkNotNull(supplier);
-    return new CharSource() {
-      @Override
-      public Reader openStream() throws IOException {
-        return asReader(supplier.getInput());
-      }
-
-      @Override
-      public String toString() {
-        return "CharStreams.asCharSource(" + supplier + ")";
-      }
-    };
-  }
-
-  /**
-   * Returns a view of the given {@code Appendable} supplier as a
-   * {@code CharSink}.
-   *
-   * <p>This method is a temporary method provided for easing migration from
-   * suppliers to sources and sinks.
-   *
-   * @since 15.0
-   * @deprecated Convert all {@code OutputSupplier<? extends Appendable>}
-   *     implementations to extend {@link CharSink} or provide a method for
-   *     viewing the object as a {@code CharSink}. This method is scheduled
-   *     for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static CharSink asCharSink(
-      final OutputSupplier<? extends Appendable> supplier) {
-    checkNotNull(supplier);
-    return new CharSink() {
-      @Override
-      public Writer openStream() throws IOException {
-        return asWriter(supplier.getOutput());
-      }
-
-      @Override
-      public String toString() {
-        return "CharStreams.asCharSink(" + supplier + ")";
-      }
-    };
-  }
-
-  @SuppressWarnings("unchecked") // used internally where known to be safe
-  static <R extends Reader> InputSupplier<R> asInputSupplier(
-      CharSource source) {
-    return (InputSupplier) checkNotNull(source);
-  }
-
-  @SuppressWarnings("unchecked") // used internally where known to be safe
-  static <W extends Writer> OutputSupplier<W> asOutputSupplier(
-      CharSink sink) {
-    return (OutputSupplier) checkNotNull(sink);
-  }
 }
diff --git a/guava/src/com/google/common/io/Closer.java b/guava/src/com/google/common/io/Closer.java
index 8b87b72..67b6497 100644
--- a/guava/src/com/google/common/io/Closer.java
+++ b/guava/src/com/google/common/io/Closer.java
@@ -25,7 +25,8 @@
 import java.io.Closeable;
 import java.io.IOException;
 import java.lang.reflect.Method;
-import java.util.LinkedList;
+import java.util.ArrayDeque;
+import java.util.Deque;
 import java.util.logging.Level;
 
 import javax.annotation.Nullable;
@@ -106,7 +107,7 @@
   @VisibleForTesting final Suppressor suppressor;
 
   // only need space for 2 elements in most cases, so try to use the smallest array possible
-  private final LinkedList<Closeable> stack = new LinkedList<Closeable>();
+  private final Deque<Closeable> stack = new ArrayDeque<Closeable>(4);
   private Throwable thrown;
 
   @VisibleForTesting Closer(Suppressor suppressor) {
diff --git a/guava/src/com/google/common/io/FileBackedOutputStream.java b/guava/src/com/google/common/io/FileBackedOutputStream.java
index 8a0de58..cc1f7b6 100644
--- a/guava/src/com/google/common/io/FileBackedOutputStream.java
+++ b/guava/src/com/google/common/io/FileBackedOutputStream.java
@@ -119,19 +119,6 @@
   }
 
   /**
-   * Returns a supplier that may be used to retrieve the data buffered
-   * by this stream. This method returns the same object as
-   * {@link #asByteSource()}.
-   *
-   * @deprecated Use {@link #asByteSource()} instead. This method is scheduled
-   *     to be removed in Guava 16.0.
-   */
-  @Deprecated
-  public InputSupplier<InputStream> getSupplier() {
-    return asByteSource();
-  }
-
-  /**
    * Returns a readable {@link ByteSource} view of the data that has been
    * written to this stream.
    *
diff --git a/guava/src/com/google/common/io/Files.java b/guava/src/com/google/common/io/Files.java
index 86feac2..2eef50e 100644
--- a/guava/src/com/google/common/io/Files.java
+++ b/guava/src/com/google/common/io/Files.java
@@ -33,7 +33,6 @@
 
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
-import java.io.Closeable;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -52,7 +51,6 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import java.util.zip.Checksum;
 
 /**
  * Provides utility methods for working with files.
@@ -233,54 +231,6 @@
     return asByteSink(file, modes).asCharSink(charset);
   }
 
-  /**
-   * Returns a factory that will supply instances of {@link FileInputStream}
-   * that read from a file.
-   *
-   * @param file the file to read from
-   * @return the factory
-   * @deprecated Use {@link #asByteSource(File)}. This method is scheduled for
-   *     removal in Guava 18.0.
-   */
-  @Deprecated
-  public static InputSupplier<FileInputStream> newInputStreamSupplier(
-      final File file) {
-    return ByteStreams.asInputSupplier(asByteSource(file));
-  }
-
-  /**
-   * Returns a factory that will supply instances of {@link FileOutputStream}
-   * that write to a file.
-   *
-   * @param file the file to write to
-   * @return the factory
-   * @deprecated Use {@link #asByteSink(File)}. This method is scheduled for
-   *     removal in Guava 18.0.
-   */
-  @Deprecated
-  public static OutputSupplier<FileOutputStream> newOutputStreamSupplier(
-      File file) {
-    return newOutputStreamSupplier(file, false);
-  }
-
-  /**
-   * Returns a factory that will supply instances of {@link FileOutputStream}
-   * that write to or append to a file.
-   *
-   * @param file the file to write to
-   * @param append if true, the encoded characters will be appended to the file;
-   *     otherwise the file is overwritten
-   * @return the factory
-   * @deprecated Use {@link #asByteSink(File, FileWriteMode...)}, passing
-   *     {@link FileWriteMode#APPEND} for append. This method is scheduled for
-   *     removal in Guava 18.0.
-   */
-  @Deprecated
-  public static OutputSupplier<FileOutputStream> newOutputStreamSupplier(
-      final File file, final boolean append) {
-    return ByteStreams.asOutputSupplier(asByteSink(file, modes(append)));
-  }
-
   private static FileWriteMode[] modes(boolean append) {
     return append
         ? new FileWriteMode[]{ FileWriteMode.APPEND }
@@ -288,60 +238,6 @@
   }
 
   /**
-   * Returns a factory that will supply instances of
-   * {@link InputStreamReader} that read a file using the given character set.
-   *
-   * @param file the file to read from
-   * @param charset the charset used to decode the input stream; see {@link
-   *     Charsets} for helpful predefined constants
-   * @return the factory
-   * @deprecated Use {@link #asCharSource(File, Charset)}. This method is
-   *     scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static InputSupplier<InputStreamReader> newReaderSupplier(File file,
-      Charset charset) {
-    return CharStreams.asInputSupplier(asCharSource(file, charset));
-  }
-
-  /**
-   * Returns a factory that will supply instances of {@link OutputStreamWriter}
-   * that write to a file using the given character set.
-   *
-   * @param file the file to write to
-   * @param charset the charset used to encode the output stream; see {@link
-   *     Charsets} for helpful predefined constants
-   * @return the factory
-   * @deprecated Use {@link #asCharSink(File, Charset)}. This method is
-   *     scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static OutputSupplier<OutputStreamWriter> newWriterSupplier(File file,
-      Charset charset) {
-    return newWriterSupplier(file, charset, false);
-  }
-
-  /**
-   * Returns a factory that will supply instances of {@link OutputStreamWriter}
-   * that write to or append to a file using the given character set.
-   *
-   * @param file the file to write to
-   * @param charset the charset used to encode the output stream; see {@link
-   *     Charsets} for helpful predefined constants
-   * @param append if true, the encoded characters will be appended to the file;
-   *     otherwise the file is overwritten
-   * @return the factory
-   * @deprecated Use {@link #asCharSink(File, Charset, FileWriteMode...)},
-   *     passing {@link FileWriteMode#APPEND} for append. This method is
-   *     scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static OutputSupplier<OutputStreamWriter> newWriterSupplier(File file,
-      Charset charset, boolean append) {
-    return CharStreams.asOutputSupplier(asCharSink(file, charset, modes(append)));
-  }
-
-  /**
    * Reads all bytes from a file into a byte array.
    *
    * @param file the file to read from
@@ -369,23 +265,6 @@
   }
 
   /**
-   * Copies to a file all bytes from an {@link InputStream} supplied by a
-   * factory.
-   *
-   * @param from the input factory
-   * @param to the destination file
-   * @throws IOException if an I/O error occurs
-   * @deprecated Use {@code from.copyTo(Files.asByteSink(to))} after changing
-   *     {@code from} to a {@code ByteSource} if necessary. This method is
-   *     scheduled to be removed in Guava 18.0.
-   */
-  @Deprecated
-  public static void copy(InputSupplier<? extends InputStream> from, File to)
-      throws IOException {
-    ByteStreams.asByteSource(from).copyTo(asByteSink(to));
-  }
-
-  /**
    * Overwrites a file with the contents of a byte array.
    *
    * @param from the bytes to write
@@ -397,23 +276,6 @@
   }
 
   /**
-   * Copies all bytes from a file to an {@link OutputStream} supplied by
-   * a factory.
-   *
-   * @param from the source file
-   * @param to the output factory
-   * @throws IOException if an I/O error occurs
-   * @deprecated Use {@code Files.asByteSource(from).copyTo(to)} after changing
-   *     {@code to} to a {@code ByteSink} if necessary. This method is
-   *     scheduled to be removed in Guava 18.0.
-   */
-  @Deprecated
-  public static void copy(File from, OutputSupplier<? extends OutputStream> to)
-      throws IOException {
-    asByteSource(from).copyTo(ByteStreams.asByteSink(to));
-  }
-
-  /**
    * Copies all bytes from a file to an output stream.
    *
    * @param from the source file
@@ -444,26 +306,6 @@
   }
 
   /**
-   * Copies to a file all characters from a {@link Readable} and
-   * {@link Closeable} object supplied by a factory, using the given
-   * character set.
-   *
-   * @param from the readable supplier
-   * @param to the destination file
-   * @param charset the charset used to encode the output stream; see {@link
-   *     Charsets} for helpful predefined constants
-   * @throws IOException if an I/O error occurs
-   * @deprecated Use {@code from.copyTo(Files.asCharSink(to, charset))} after
-   *     changing {@code from} to a {@code CharSource} if necessary. This
-   *     method is scheduled to be removed in Guava 18.0.
-   */
-  @Deprecated
-  public static <R extends Readable & Closeable> void copy(
-      InputSupplier<R> from, File to, Charset charset) throws IOException {
-    CharStreams.asCharSource(from).copyTo(asCharSink(to, charset));
-  }
-
-  /**
    * Writes a character sequence (such as a string) to a file using the given
    * character set.
    *
@@ -510,26 +352,6 @@
   }
 
   /**
-   * Copies all characters from a file to a {@link Appendable} &
-   * {@link Closeable} object supplied by a factory, using the given
-   * character set.
-   *
-   * @param from the source file
-   * @param charset the charset used to decode the input stream; see {@link
-   *     Charsets} for helpful predefined constants
-   * @param to the appendable supplier
-   * @throws IOException if an I/O error occurs
-   * @deprecated Use {@code Files.asCharSource(from, charset).copyTo(to)} after
-   *     changing {@code to} to a {@code CharSink} if necessary. This method is
-   *     scheduled to be removed in Guava 18.0.
-   */
-  @Deprecated
-  public static <W extends Appendable & Closeable> void copy(File from,
-      Charset charset, OutputSupplier<W> to) throws IOException {
-    asCharSource(from, charset).copyTo(CharStreams.asCharSink(to));
-  }
-
-  /**
    * Copies all characters from a file to an appendable object,
    * using the given character set.
    *
@@ -739,7 +561,7 @@
    */
   public static <T> T readLines(File file, Charset charset,
       LineProcessor<T> callback) throws IOException {
-    return CharStreams.readLines(newReaderSupplier(file, charset), callback);
+    return asCharSource(file, charset).readLines(callback);
   }
 
   /**
@@ -755,26 +577,7 @@
    */
   public static <T> T readBytes(File file, ByteProcessor<T> processor)
       throws IOException {
-    return ByteStreams.readBytes(newInputStreamSupplier(file), processor);
-  }
-
-  /**
-   * Computes and returns the checksum value for a file.
-   * The checksum object is reset when this method returns successfully.
-   *
-   * @param file the file to read
-   * @param checksum the checksum object
-   * @return the result of {@link Checksum#getValue} after updating the
-   *     checksum object with all of the bytes in the file
-   * @throws IOException if an I/O error occurs
-   * @deprecated Use {@code hash} with the {@code Hashing.crc32()} or
-   *     {@code Hashing.adler32()} hash functions. This method is scheduled
-   *     to be removed in Guava 15.0.
-   */
-  @Deprecated
-  public static long getChecksum(File file, Checksum checksum)
-      throws IOException {
-    return ByteStreams.getChecksum(newInputStreamSupplier(file), checksum);
+    return asByteSource(file).read(processor);
   }
 
   /**
diff --git a/guava/src/com/google/common/io/InputSupplier.java b/guava/src/com/google/common/io/InputSupplier.java
index 3e3f25c..da1361f 100644
--- a/guava/src/com/google/common/io/InputSupplier.java
+++ b/guava/src/com/google/common/io/InputSupplier.java
@@ -28,7 +28,7 @@
  *     use {@link CharSource}. Implementations of {@code InputSupplier} that
  *     don't fall into one of those categories do not benefit from any of the
  *     methods in {@code common.io} and should use a different interface. This
- *     interface is scheduled for removal in June 2015.
+ *     interface is scheduled for removal in December 2015.
  */
 @Deprecated
 public interface InputSupplier<T> {
diff --git a/guava/src/com/google/common/io/OutputSupplier.java b/guava/src/com/google/common/io/OutputSupplier.java
index 327aaf8..456099f 100644
--- a/guava/src/com/google/common/io/OutputSupplier.java
+++ b/guava/src/com/google/common/io/OutputSupplier.java
@@ -28,7 +28,7 @@
  *     use {@link CharSink}. Implementations of {@code OutputSupplier} that
  *     don't fall into one of those categories do not benefit from any of the
  *     methods in {@code common.io} and should use a different interface. This
- *     interface is scheduled for removal in June 2015.
+ *     interface is scheduled for removal in December 2015.
  */
 @Deprecated
 public interface OutputSupplier<T> {
diff --git a/guava/src/com/google/common/io/Resources.java b/guava/src/com/google/common/io/Resources.java
index 5c2327d..c164611 100644
--- a/guava/src/com/google/common/io/Resources.java
+++ b/guava/src/com/google/common/io/Resources.java
@@ -21,12 +21,11 @@
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Charsets;
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
 import com.google.common.collect.Lists;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.net.URL;
 import java.nio.charset.Charset;
@@ -49,20 +48,6 @@
   private Resources() {}
 
   /**
-   * Returns a factory that will supply instances of {@link InputStream} that
-   * read from the given URL.
-   *
-   * @param url the URL to read from
-   * @return the factory
-   * @deprecated Use {@link #asByteSource(URL)} instead. This method is
-   *     scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static InputSupplier<InputStream> newInputStreamSupplier(URL url) {
-    return ByteStreams.asInputSupplier(asByteSource(url));
-  }
-
-  /**
    * Returns a {@link ByteSource} that reads from the given URL.
    *
    * @since 14.0
@@ -94,23 +79,6 @@
   }
 
   /**
-   * Returns a factory that will supply instances of
-   * {@link InputStreamReader} that read a URL using the given character set.
-   *
-   * @param url the URL to read from
-   * @param charset the charset used to decode the input stream; see {@link
-   *     Charsets} for helpful predefined constants
-   * @return the factory
-   * @deprecated Use {@link #asCharSource(URL, Charset)} instead. This method
-   *     is scheduled for removal in Guava 18.0.
-   */
-  @Deprecated
-  public static InputSupplier<InputStreamReader> newReaderSupplier(
-      URL url, Charset charset) {
-    return CharStreams.asInputSupplier(asCharSource(url, charset));
-  }
-
-  /**
    * Returns a {@link CharSource} that reads from the given URL using the given
    * character set.
    *
@@ -158,7 +126,7 @@
    */
   public static <T> T readLines(URL url, Charset charset,
       LineProcessor<T> callback) throws IOException {
-    return CharStreams.readLines(newReaderSupplier(url, charset), callback);
+    return asCharSource(url, charset).readLines(callback);
   }
 
   /**
@@ -222,7 +190,7 @@
    * @throws IllegalArgumentException if the resource is not found
    */
   public static URL getResource(String resourceName) {
-    ClassLoader loader = Objects.firstNonNull(
+    ClassLoader loader = MoreObjects.firstNonNull(
         Thread.currentThread().getContextClassLoader(),
         Resources.class.getClassLoader());
     URL url = loader.getResource(resourceName);
diff --git a/guava/src/com/google/common/math/BigIntegerMath.java b/guava/src/com/google/common/math/BigIntegerMath.java
index 0388b73..98e061f 100644
--- a/guava/src/com/google/common/math/BigIntegerMath.java
+++ b/guava/src/com/google/common/math/BigIntegerMath.java
@@ -261,7 +261,7 @@
      */
     BigInteger sqrt0;
     int log2 = log2(x, FLOOR);
-    if (log2 < DoubleUtils.MAX_EXPONENT) {
+    if (log2 < Double.MAX_EXPONENT) {
       sqrt0 = sqrtApproxWithDoubles(x);
     } else {
       int shift = (log2 - DoubleUtils.SIGNIFICAND_BITS) & ~1; // even!
@@ -305,7 +305,7 @@
    * Returns {@code n!}, that is, the product of the first {@code n} positive
    * integers, or {@code 1} if {@code n == 0}.
    *
-   * <p><b>Warning</b>: the result takes <i>O(n log n)</i> space, so use cautiously.
+   * <p><b>Warning:</b> the result takes <i>O(n log n)</i> space, so use cautiously.
    *
    * <p>This uses an efficient binary recursive algorithm to compute the factorial
    * with balanced multiplies.  It also removes all the 2s from the intermediate
@@ -393,7 +393,7 @@
    * Returns {@code n} choose {@code k}, also known as the binomial coefficient of {@code n} and
    * {@code k}, that is, {@code n! / (k! (n - k)!)}.
    *
-   * <p><b>Warning</b>: the result can take as much as <i>O(k log n)</i> space.
+   * <p><b>Warning:</b> the result can take as much as <i>O(k log n)</i> space.
    *
    * @throws IllegalArgumentException if {@code n < 0}, {@code k < 0}, or {@code k > n}
    */
diff --git a/guava/src/com/google/common/math/DoubleMath.java b/guava/src/com/google/common/math/DoubleMath.java
index 808ee59..66c5e8d 100644
--- a/guava/src/com/google/common/math/DoubleMath.java
+++ b/guava/src/com/google/common/math/DoubleMath.java
@@ -19,8 +19,6 @@
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.math.DoubleUtils.IMPLICIT_BIT;
 import static com.google.common.math.DoubleUtils.SIGNIFICAND_BITS;
-import static com.google.common.math.DoubleUtils.copySign;
-import static com.google.common.math.DoubleUtils.getExponent;
 import static com.google.common.math.DoubleUtils.getSignificand;
 import static com.google.common.math.DoubleUtils.isFinite;
 import static com.google.common.math.DoubleUtils.isNormal;
@@ -29,6 +27,8 @@
 import static com.google.common.math.MathPreconditions.checkNonNegative;
 import static com.google.common.math.MathPreconditions.checkRoundingUnnecessary;
 import static java.lang.Math.abs;
+import static java.lang.Math.copySign;
+import static java.lang.Math.getExponent;
 import static java.lang.Math.log;
 import static java.lang.Math.rint;
 
@@ -84,7 +84,7 @@
         if (isMathematicalInteger(x)) {
           return x;
         } else {
-          return x + copySign(1.0, x);
+          return x + Math.copySign(1.0, x);
         }
 
       case HALF_EVEN:
@@ -284,7 +284,7 @@
 
   /**
    * Returns {@code n!}, that is, the product of the first {@code n} positive
-   * integers, {@code 1} if {@code n == 0}, or e n!}, or
+   * integers, {@code 1} if {@code n == 0}, or {@code n!}, or
    * {@link Double#POSITIVE_INFINITY} if {@code n! > Double.MAX_VALUE}.
    *
    * <p>The result is within 1 ulp of the true value.
@@ -351,7 +351,7 @@
   public static boolean fuzzyEquals(double a, double b, double tolerance) {
     MathPreconditions.checkNonNegative("tolerance", tolerance);
     return
-          copySign(a - b, 1.0) <= tolerance
+          Math.copySign(a - b, 1.0) <= tolerance
            // copySign(x, 1.0) is a branch-free version of abs(x), but with different NaN semantics
           || (a == b) // needed to ensure that infinities equal themselves
           || (Double.isNaN(a) && Double.isNaN(b));
diff --git a/guava/src/com/google/common/math/DoubleUtils.java b/guava/src/com/google/common/math/DoubleUtils.java
index 1913b56..6cd94e3 100644
--- a/guava/src/com/google/common/math/DoubleUtils.java
+++ b/guava/src/com/google/common/math/DoubleUtils.java
@@ -17,10 +17,13 @@
 package com.google.common.math;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static java.lang.Double.MAX_EXPONENT;
+import static java.lang.Double.MIN_EXPONENT;
 import static java.lang.Double.POSITIVE_INFINITY;
 import static java.lang.Double.doubleToRawLongBits;
 import static java.lang.Double.isNaN;
 import static java.lang.Double.longBitsToDouble;
+import static java.lang.Math.getExponent;
 
 import java.math.BigInteger;
 
@@ -34,21 +37,7 @@
   }
 
   static double nextDown(double d) {
-    return -nextUp(-d);
-  }
-
-  static double nextUp(double d) {
-    if (Double.isNaN(d)) {
-      return d;
-    } else if (d == 0.0) {
-      return Double.MIN_VALUE;
-    } else if (d == Double.POSITIVE_INFINITY) {
-      return d;
-    } else {
-      long bits = Double.doubleToRawLongBits(d);
-      bits += (bits >> 63) | 1;
-      return Double.longBitsToDouble(bits);
-    }
+    return -Math.nextUp(-d);
   }
 
   // The mask for the significand, according to the {@link
@@ -67,20 +56,11 @@
 
   static final int EXPONENT_BIAS = 1023;
 
-  static final int MAX_EXPONENT = 1023;
-
-  static final int MIN_EXPONENT = -1022;
-
   /**
    * The implicit 1 bit that is omitted in significands of normal doubles.
    */
   static final long IMPLICIT_BIT = SIGNIFICAND_MASK + 1;
 
-  static int getExponent(double d) {
-    long bits = Double.doubleToRawLongBits(d) & EXPONENT_MASK;
-    return (int) (bits >>> SIGNIFICAND_BITS) - EXPONENT_BIAS;
-  }
-
   static long getSignificand(double d) {
     checkArgument(isFinite(d), "not a normal value");
     int exponent = getExponent(d);
@@ -91,12 +71,6 @@
         : bits | IMPLICIT_BIT;
   }
 
-  static double copySign(double mag, double sgn) {
-    long bits = Double.doubleToRawLongBits(mag) & ~SIGN_MASK;
-    bits |= Double.doubleToRawLongBits(sgn) & SIGN_MASK;
-    return Double.longBitsToDouble(bits);
-  }
-
   static boolean isFinite(double d) {
     return getExponent(d) <= MAX_EXPONENT;
   }
diff --git a/guava/src/com/google/common/math/IntMath.java b/guava/src/com/google/common/math/IntMath.java
index 5c9575d..0c5efe2 100644
--- a/guava/src/com/google/common/math/IntMath.java
+++ b/guava/src/com/google/common/math/IntMath.java
@@ -62,7 +62,7 @@
   public static boolean isPowerOfTwo(int x) {
     return x > 0 & (x & (x - 1)) == 0;
   }
-  
+
   /**
    * Returns 1 if {@code x < y} as unsigned integers, and 0 otherwise. Assumes that x - y fits into
    * a signed int. The implementation is branch-free, and benchmarks suggest it is measurably (if
@@ -248,7 +248,7 @@
          * We wish to test whether or not x <= (sqrtFloor + 0.5)^2 = halfSquare + 0.25. Since both
          * x and halfSquare are integers, this is equivalent to testing whether or not x <=
          * halfSquare. (We have to deal with overflow, though.)
-         * 
+         *
          * If we treat halfSquare as an unsigned int, we know that
          *            sqrtFloor^2 <= x < (sqrtFloor + 1)^2
          * halfSquare - sqrtFloor <= x < halfSquare + sqrtFloor + 1
diff --git a/guava/src/com/google/common/math/LongMath.java b/guava/src/com/google/common/math/LongMath.java
index 08043b2..425aac6 100644
--- a/guava/src/com/google/common/math/LongMath.java
+++ b/guava/src/com/google/common/math/LongMath.java
@@ -61,7 +61,7 @@
   public static boolean isPowerOfTwo(long x) {
     return x > 0 & (x & (x - 1)) == 0;
   }
-  
+
   /**
    * Returns 1 if {@code x < y} as unsigned longs, and 0 otherwise.  Assumes that x - y fits into a
    * signed long.  The implementation is branch-free, and benchmarks suggest it is measurably
@@ -279,9 +279,9 @@
     }
     /*
      * Let k be the true value of floor(sqrt(x)), so that
-     * 
+     *
      *            k * k <= x          <  (k + 1) * (k + 1)
-     * (double) (k * k) <= (double) x <= (double) ((k + 1) * (k + 1)) 
+     * (double) (k * k) <= (double) x <= (double) ((k + 1) * (k + 1))
      *          since casting to double is nondecreasing.
      *          Note that the right-hand inequality is no longer strict.
      * Math.sqrt(k * k) <= Math.sqrt(x) <= Math.sqrt((k + 1) * (k + 1))
@@ -315,14 +315,14 @@
         return guess;
       case HALF_DOWN:
       case HALF_UP:
-      case HALF_EVEN: 
-        long sqrtFloor = guess - ((x < guessSquared) ? 1 : 0); 
+      case HALF_EVEN:
+        long sqrtFloor = guess - ((x < guessSquared) ? 1 : 0);
         long halfSquare = sqrtFloor * sqrtFloor + sqrtFloor;
         /*
          * We wish to test whether or not x <= (sqrtFloor + 0.5)^2 = halfSquare + 0.25. Since both
          * x and halfSquare are integers, this is equivalent to testing whether or not x <=
          * halfSquare. (We have to deal with overflow, though.)
-         * 
+         *
          * If we treat halfSquare as an unsigned long, we know that
          *            sqrtFloor^2 <= x < (sqrtFloor + 1)^2
          * halfSquare - sqrtFloor <= x < halfSquare + sqrtFloor + 1
@@ -672,14 +672,14 @@
           return result;
         } else {
           int nBits = LongMath.log2(n, RoundingMode.CEILING);
-          
+
           long result = 1;
           long numerator = n--;
           long denominator = 1;
-          
+
           int numeratorBits = nBits;
           // This is an upper bound on log2(numerator, ceiling).
-          
+
           /*
            * We want to do this in long math for speed, but want to avoid overflow. We adapt the
            * technique previously used by BigIntegerMath: maintain separate numerator and
@@ -704,7 +704,7 @@
         }
     }
   }
-  
+
   /**
    * Returns (x * numerator / denominator), which is assumed to come out to an integral value.
    */
diff --git a/guava/src/com/google/common/net/HostAndPort.java b/guava/src/com/google/common/net/HostAndPort.java
index 04c9417..b4d3033 100644
--- a/guava/src/com/google/common/net/HostAndPort.java
+++ b/guava/src/com/google/common/net/HostAndPort.java
@@ -213,7 +213,6 @@
   private static String[] getHostAndPortFromBracketedHost(String hostPortString) {
     int colonIndex = 0;
     int closeBracketIndex = 0;
-    boolean hasPort = false;
     checkArgument(hostPortString.charAt(0) == '[',
         "Bracketed host-port string must start with a bracket: %s", hostPortString);
     colonIndex = hostPortString.indexOf(':');
diff --git a/guava/src/com/google/common/net/InetAddresses.java b/guava/src/com/google/common/net/InetAddresses.java
index 66c0c69..20eb18e 100644
--- a/guava/src/com/google/common/net/InetAddresses.java
+++ b/guava/src/com/google/common/net/InetAddresses.java
@@ -17,7 +17,7 @@
 package com.google.common.net;
 
 import com.google.common.annotations.Beta;
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Preconditions;
 import com.google.common.hash.Hashing;
 import com.google.common.io.ByteStreams;
@@ -570,7 +570,7 @@
     Preconditions.checkArgument(isCompatIPv4Address(ip),
         "Address '%s' is not IPv4-compatible.", toAddrString(ip));
 
-    return getInet4Address(copyOfRange(ip.getAddress(), 12, 16));
+    return getInet4Address(Arrays.copyOfRange(ip.getAddress(), 12, 16));
   }
 
   /**
@@ -603,7 +603,7 @@
     Preconditions.checkArgument(is6to4Address(ip),
         "Address '%s' is not a 6to4 address.", toAddrString(ip));
 
-    return getInet4Address(copyOfRange(ip.getAddress(), 2, 6));
+    return getInet4Address(Arrays.copyOfRange(ip.getAddress(), 2, 6));
   }
 
   /**
@@ -645,9 +645,9 @@
           "port '%s' is out of range (0 <= port <= 0xffff)", port);
       Preconditions.checkArgument((flags >= 0) && (flags <= 0xffff),
           "flags '%s' is out of range (0 <= flags <= 0xffff)", flags);
-      
-      this.server = Objects.firstNonNull(server, ANY4);
-      this.client = Objects.firstNonNull(client, ANY4);
+
+      this.server = MoreObjects.firstNonNull(server, ANY4);
+      this.client = MoreObjects.firstNonNull(client, ANY4);
       this.port = port;
       this.flags = flags;
     }
@@ -695,14 +695,14 @@
         "Address '%s' is not a Teredo address.", toAddrString(ip));
 
     byte[] bytes = ip.getAddress();
-    Inet4Address server = getInet4Address(copyOfRange(bytes, 4, 8));
+    Inet4Address server = getInet4Address(Arrays.copyOfRange(bytes, 4, 8));
 
     int flags = ByteStreams.newDataInput(bytes, 8).readShort() & 0xffff;
 
     // Teredo obfuscates the mapped client port, per section 4 of the RFC.
     int port = ~ByteStreams.newDataInput(bytes, 10).readShort() & 0xffff;
 
-    byte[] clientBytes = copyOfRange(bytes, 12, 16);
+    byte[] clientBytes = Arrays.copyOfRange(bytes, 12, 16);
     for (int i = 0; i < clientBytes.length; i++) {
       // Teredo obfuscates the mapped client IP, per section 4 of the RFC.
       clientBytes[i] = (byte) ~clientBytes[i];
@@ -759,7 +759,7 @@
     Preconditions.checkArgument(isIsatapAddress(ip),
         "Address '%s' is not an ISATAP address.", toAddrString(ip));
 
-    return getInet4Address(copyOfRange(ip.getAddress(), 12, 16));
+    return getInet4Address(Arrays.copyOfRange(ip.getAddress(), 12, 16));
   }
 
   /**
@@ -969,6 +969,29 @@
   }
 
   /**
+   * Returns a new InetAddress that is one less than the passed in address.
+   * This method works for both IPv4 and IPv6 addresses.
+   *
+   * @param address the InetAddress to decrement
+   * @return a new InetAddress that is one less than the passed in address
+   * @throws IllegalArgumentException if InetAddress is at the beginning of its range
+   * @since 18.0
+   */
+  public static InetAddress decrement(InetAddress address) {
+    byte[] addr = address.getAddress();
+    int i = addr.length - 1;
+    while (i >= 0 && addr[i] == (byte) 0x00) {
+      addr[i] = (byte) 0xff;
+      i--;
+    }
+
+    Preconditions.checkArgument(i >= 0, "Decrementing %s would wrap.", address);
+
+    addr[i]--;
+    return bytesToInetAddress(addr);
+  }
+
+  /**
    * Returns a new InetAddress that is one more than the passed in address.
    * This method works for both IPv4 and IPv6 addresses.
    *
@@ -1008,11 +1031,4 @@
     }
     return true;
   }
-
-  private static byte[] copyOfRange(byte[] array, int start, int end) {
-    int length = end - start;
-    byte[] newArray = new byte[length];
-    System.arraycopy(array, start, newArray, 0, length);
-    return newArray;
-  }
 }
diff --git a/guava/src/com/google/common/net/MediaType.java b/guava/src/com/google/common/net/MediaType.java
index 754482b..1cfd741 100644
--- a/guava/src/com/google/common/net/MediaType.java
+++ b/guava/src/com/google/common/net/MediaType.java
@@ -30,6 +30,7 @@
 import com.google.common.base.Function;
 import com.google.common.base.Joiner;
 import com.google.common.base.Joiner.MapJoiner;
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableListMultimap;
@@ -227,6 +228,7 @@
   public static final MediaType APPLICATION_XML_UTF_8 = createConstantUtf8(APPLICATION_TYPE, "xml");
   public static final MediaType ATOM_UTF_8 = createConstantUtf8(APPLICATION_TYPE, "atom+xml");
   public static final MediaType BZIP2 = createConstant(APPLICATION_TYPE, "x-bzip2");
+
   /**
    * Media type for <a href="http://en.wikipedia.org/wiki/Embedded_OpenType">Embedded OpenType</a>
    * fonts. This is
@@ -280,6 +282,15 @@
   public static final MediaType KML = createConstant(APPLICATION_TYPE, "vnd.google-earth.kml+xml");
   public static final MediaType KMZ = createConstant(APPLICATION_TYPE, "vnd.google-earth.kmz");
   public static final MediaType MBOX = createConstant(APPLICATION_TYPE, "mbox");
+
+  /**
+   * Media type for
+   * <a href="http://goo.gl/1pGBFm">Apple over-the-air mobile configuration profiles</a>.
+   *
+   * @since 18.0
+   */
+  public static final MediaType APPLE_MOBILE_CONFIG =
+      createConstant(APPLICATION_TYPE, "x-apple-aspen-config");
   public static final MediaType MICROSOFT_EXCEL = createConstant(APPLICATION_TYPE, "vnd.ms-excel");
   public static final MediaType MICROSOFT_POWERPOINT =
       createConstant(APPLICATION_TYPE, "vnd.ms-powerpoint");
@@ -439,7 +450,7 @@
     builder.put(normalizedAttribute, normalizeParameterValue(normalizedAttribute, value));
     MediaType mediaType = new MediaType(type, subtype, builder.build());
     // Return one of the constants if the media type is a known type.
-    return Objects.firstNonNull(KNOWN_TYPES.get(mediaType), mediaType);
+    return MoreObjects.firstNonNull(KNOWN_TYPES.get(mediaType), mediaType);
   }
 
   /**
@@ -564,7 +575,7 @@
     }
     MediaType mediaType = new MediaType(normalizedType, normalizedSubtype, builder.build());
     // Return one of the constants if the media type is a known type.
-    return Objects.firstNonNull(KNOWN_TYPES.get(mediaType), mediaType);
+    return MoreObjects.firstNonNull(KNOWN_TYPES.get(mediaType), mediaType);
   }
 
   private static String normalizeToken(String token) {
diff --git a/guava/src/com/google/common/net/PercentEscaper.java b/guava/src/com/google/common/net/PercentEscaper.java
index 53e60e4..1d4f568 100644
--- a/guava/src/com/google/common/net/PercentEscaper.java
+++ b/guava/src/com/google/common/net/PercentEscaper.java
@@ -46,7 +46,7 @@
  * <p>For performance reasons the only currently supported character encoding of
  * this class is UTF-8.
  *
- * <p><b>Note</b>: This escaper produces uppercase hexadecimal sequences. From
+ * <p><b>Note:</b> This escaper produces uppercase hexadecimal sequences. From
  * <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>:<br>
  * <i>"URI producers and normalizers should use uppercase hexadecimal digits
  * for all percent-encodings."</i>
diff --git a/guava/src/com/google/common/net/UrlEscapers.java b/guava/src/com/google/common/net/UrlEscapers.java
index c38e909..7b4ae4a 100644
--- a/guava/src/com/google/common/net/UrlEscapers.java
+++ b/guava/src/com/google/common/net/UrlEscapers.java
@@ -74,7 +74,7 @@
    * recommend using the ampersand unless you must interoperate with systems
    * that require semicolons.
    *
-   * <p><b>Note</b>: Unlike other escapers, URL escapers produce uppercase
+   * <p><b>Note:</b> Unlike other escapers, URL escapers produce uppercase
    * hexadecimal sequences. From <a href="http://www.ietf.org/rfc/rfc3986.txt">
    * RFC 3986</a>:<br>
    * <i>"URI producers and normalizers should use uppercase hexadecimal digits
@@ -116,7 +116,7 @@
    *     representation of the byte value.
    * </ul>
    *
-   * <p><b>Note</b>: Unlike other escapers, URL escapers produce uppercase
+   * <p><b>Note:</b> Unlike other escapers, URL escapers produce uppercase
    * hexadecimal sequences. From <a href="http://www.ietf.org/rfc/rfc3986.txt">
    * RFC 3986</a>:<br>
    * <i>"URI producers and normalizers should use uppercase hexadecimal digits
@@ -154,7 +154,7 @@
    *     representation of the byte value.
    * </ul>
    *
-   * <p><b>Note</b>: Unlike other escapers, URL escapers produce uppercase
+   * <p><b>Note:</b> Unlike other escapers, URL escapers produce uppercase
    * hexadecimal sequences. From <a href="http://www.ietf.org/rfc/rfc3986.txt">
    * RFC 3986</a>:<br>
    * <i>"URI producers and normalizers should use uppercase hexadecimal digits
diff --git a/guava/src/com/google/common/primitives/Booleans.java b/guava/src/com/google/common/primitives/Booleans.java
index 7a6575f..faef910 100644
--- a/guava/src/com/google/common/primitives/Booleans.java
+++ b/guava/src/com/google/common/primitives/Booleans.java
@@ -65,8 +65,8 @@
    * ({@code false} is considered less than {@code true}). The sign of the
    * value returned is the same as that of {@code ((Boolean) a).compareTo(b)}.
    *
-   * <p><b>Note:</b> projects using JDK 7 or later should use the equivalent
-   * {@link Boolean#compare} method instead.
+   * <p><b>Note for Java 7 and later:</b> this method should be treated as
+   * deprecated; use the equivalent {@link Boolean#compare} method instead.
    *
    * @param a the first {@code boolean} to compare
    * @param b the second {@code boolean} to compare
diff --git a/guava/src/com/google/common/primitives/Chars.java b/guava/src/com/google/common/primitives/Chars.java
index e1ae2e0..65fe8b1 100644
--- a/guava/src/com/google/common/primitives/Chars.java
+++ b/guava/src/com/google/common/primitives/Chars.java
@@ -107,8 +107,8 @@
    * Compares the two specified {@code char} values. The sign of the value
    * returned is the same as that of {@code ((Character) a).compareTo(b)}.
    *
-   * <p><b>Note:</b> projects using JDK 7 or later should use the equivalent
-   * {@link Character#compare} method instead.
+   * <p><b>Note for Java 7 and later:</b> this method should be treated as
+   * deprecated; use the equivalent {@link Character#compare} method instead.
    *
    * @param a the first {@code char} to compare
    * @param b the second {@code char} to compare
diff --git a/guava/src/com/google/common/primitives/Doubles.java b/guava/src/com/google/common/primitives/Doubles.java
index 8f74e62..8e86e8f 100644
--- a/guava/src/com/google/common/primitives/Doubles.java
+++ b/guava/src/com/google/common/primitives/Doubles.java
@@ -392,7 +392,7 @@
     public int compare(double[] left, double[] right) {
       int minLength = Math.min(left.length, right.length);
       for (int i = 0; i < minLength; i++) {
-        int result = Doubles.compare(left[i], right[i]);
+        int result = Double.compare(left[i], right[i]);
         if (result != 0) {
           return result;
         }
diff --git a/guava/src/com/google/common/primitives/Floats.java b/guava/src/com/google/common/primitives/Floats.java
index 8a2c648..167089e 100644
--- a/guava/src/com/google/common/primitives/Floats.java
+++ b/guava/src/com/google/common/primitives/Floats.java
@@ -388,7 +388,7 @@
     public int compare(float[] left, float[] right) {
       int minLength = Math.min(left.length, right.length);
       for (int i = 0; i < minLength; i++) {
-        int result = Floats.compare(left[i], right[i]);
+        int result = Float.compare(left[i], right[i]);
         if (result != 0) {
           return result;
         }
diff --git a/guava/src/com/google/common/primitives/Ints.java b/guava/src/com/google/common/primitives/Ints.java
index 66a3e9c..c0d0126 100644
--- a/guava/src/com/google/common/primitives/Ints.java
+++ b/guava/src/com/google/common/primitives/Ints.java
@@ -115,8 +115,8 @@
    * Compares the two specified {@code int} values. The sign of the value
    * returned is the same as that of {@code ((Integer) a).compareTo(b)}.
    *
-   * <p><b>Note:</b> projects using JDK 7 or later should use the equivalent
-   * {@link Integer#compare} method instead.
+   * <p><b>Note for Java 7 and later:</b> this method should be treated as
+   * deprecated; use the equivalent {@link Integer#compare} method instead.
    *
    * @param a the first {@code int} to compare
    * @param b the second {@code int} to compare
@@ -675,7 +675,6 @@
    */
   @Beta
   @CheckForNull
-  @GwtIncompatible("TODO")
   public static Integer tryParse(String string) {
     return tryParse(string, 10);
   }
@@ -702,10 +701,9 @@
    * @throws IllegalArgumentException if {@code radix < Character.MIN_RADIX} or
    *     {@code radix > Character.MAX_RADIX}
    */
-  @CheckForNull
-  @GwtIncompatible("TODO") static Integer tryParse(
+  @CheckForNull static Integer tryParse(
       String string, int radix) {
-    if (checkNotNull(string).length() == 0) {
+    if (checkNotNull(string).isEmpty()) {
       return null;
     }
     if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
diff --git a/guava/src/com/google/common/primitives/Longs.java b/guava/src/com/google/common/primitives/Longs.java
index d6d0e8d..1078850 100644
--- a/guava/src/com/google/common/primitives/Longs.java
+++ b/guava/src/com/google/common/primitives/Longs.java
@@ -82,8 +82,8 @@
    * Compares the two specified {@code long} values. The sign of the value
    * returned is the same as that of {@code ((Long) a).compareTo(b)}.
    *
-   * <p><b>Note:</b> projects using JDK 7 or later should use the equivalent
-   * {@link Long#compare} method instead.
+   * <p><b>Note for Java 7 and later:</b> this method should be treated as
+   * deprecated; use the equivalent {@link Long#compare} method instead.
    *
    * @param a the first {@code long} to compare
    * @param b the second {@code long} to compare
@@ -334,7 +334,7 @@
    */
   @Beta
   public static Long tryParse(String string) {
-    if (checkNotNull(string).length() == 0) {
+    if (checkNotNull(string).isEmpty()) {
       return null;
     }
     boolean negative = string.charAt(0) == '-';
diff --git a/guava/src/com/google/common/primitives/Shorts.java b/guava/src/com/google/common/primitives/Shorts.java
index d7d40be..1a4ba4c 100644
--- a/guava/src/com/google/common/primitives/Shorts.java
+++ b/guava/src/com/google/common/primitives/Shorts.java
@@ -114,8 +114,8 @@
    * Compares the two specified {@code short} values. The sign of the value
    * returned is the same as that of {@code ((Short) a).compareTo(b)}.
    *
-   * <p><b>Note:</b> projects using JDK 7 or later should use the equivalent
-   * {@link Short#compare} method instead.
+   * <p><b>Note for Java 7 and later:</b> this method should be treated as
+   * deprecated; use the equivalent {@link Short#compare} method instead.
    *
    * @param a the first {@code short} to compare
    * @param b the second {@code short} to compare
diff --git a/guava/src/com/google/common/reflect/ClassPath.java b/guava/src/com/google/common/reflect/ClassPath.java
index 398c2cc..cadb825 100644
--- a/guava/src/com/google/common/reflect/ClassPath.java
+++ b/guava/src/com/google/common/reflect/ClassPath.java
@@ -237,7 +237,7 @@
         return CharMatcher.DIGIT.trimLeadingFrom(innerClassName);
       }
       String packageName = getPackageName();
-      if (packageName.length() == 0) {
+      if (packageName.isEmpty()) {
         return className;
       }
 
diff --git a/guava/src/com/google/common/reflect/Invokable.java b/guava/src/com/google/common/reflect/Invokable.java
index 59541dc..b281faf 100644
--- a/guava/src/com/google/common/reflect/Invokable.java
+++ b/guava/src/com/google/common/reflect/Invokable.java
@@ -263,19 +263,12 @@
         if (types.length == rawParamTypes.length
             && rawParamTypes[0] == getDeclaringClass().getEnclosingClass()) {
           // first parameter is the hidden 'this'
-          return copyOfRange(types, 1, types.length);
+          return Arrays.copyOfRange(types, 1, types.length);
         }
       }
       return types;
     }
 
-    private static Type[] copyOfRange(Type[] array, int start, int end) {
-      int length = end - start;
-      Type[] newArray = new Type[length];
-      System.arraycopy(array, start, newArray, 0, length);
-      return newArray;
-    }
-
     @Override Type[] getGenericExceptionTypes() {
       return constructor.getGenericExceptionTypes();
     }
diff --git a/guava/src/com/google/common/reflect/Parameter.java b/guava/src/com/google/common/reflect/Parameter.java
index 977bc8d..f3ce165 100644
--- a/guava/src/com/google/common/reflect/Parameter.java
+++ b/guava/src/com/google/common/reflect/Parameter.java
@@ -19,6 +19,7 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableList;
 
 import java.lang.annotation.Annotation;
@@ -81,10 +82,46 @@
     return getDeclaredAnnotations();
   }
 
+  /**
+   * @since 18.0
+   */
+  // @Override on JDK8
+  public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
+    return getDeclaredAnnotationsByType(annotationType);
+  }
+
+  /**
+   * @since 18.0
+   */
+  // @Override on JDK8
   @Override public Annotation[] getDeclaredAnnotations() {
     return annotations.toArray(new Annotation[annotations.size()]);
   }
 
+  /**
+   * @since 18.0
+   */
+  // @Override on JDK8
+  @Nullable
+  public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationType) {
+    checkNotNull(annotationType);
+    return FluentIterable.from(annotations)
+        .filter(annotationType)
+        .first()
+        .orNull();
+  }
+
+  /**
+   * @since 18.0
+   */
+  // @Override on JDK8
+  public <A extends Annotation> A[]
+      getDeclaredAnnotationsByType(Class<A> annotationType) {
+    return FluentIterable.from(annotations)
+        .filter(annotationType)
+        .toArray(annotationType);
+  }
+
   @Override public boolean equals(@Nullable Object obj) {
     if (obj instanceof Parameter) {
       Parameter that = (Parameter) obj;
diff --git a/guava/src/com/google/common/reflect/TypeToken.java b/guava/src/com/google/common/reflect/TypeToken.java
index 55aa20a..bc33e8f 100644
--- a/guava/src/com/google/common/reflect/TypeToken.java
+++ b/guava/src/com/google/common/reflect/TypeToken.java
@@ -1089,7 +1089,7 @@
           }
 
           @Override Iterable<? extends Class<?>> getInterfaces(Class<?> type) {
-            return Arrays.<Class<?>>asList(type.getInterfaces());
+            return Arrays.asList(type.getInterfaces());
           }
 
           @Nullable
diff --git a/guava/src/com/google/common/reflect/Types.java b/guava/src/com/google/common/reflect/Types.java
index 0f05f78..a86e5a2 100644
--- a/guava/src/com/google/common/reflect/Types.java
+++ b/guava/src/com/google/common/reflect/Types.java
@@ -26,16 +26,23 @@
 import com.google.common.base.Objects;
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 
 import java.io.Serializable;
+import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.Array;
 import java.lang.reflect.GenericArrayType;
 import java.lang.reflect.GenericDeclaration;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Proxy;
 import java.lang.reflect.Type;
 import java.lang.reflect.TypeVariable;
 import java.lang.reflect.WildcardType;
+import java.security.AccessControlException;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.concurrent.atomic.AtomicReference;
@@ -50,10 +57,10 @@
 final class Types {
 
   /** Class#toString without the "class " and "interface " prefixes */
-  private static final Function<Type, String> TYPE_TO_STRING =
+  private static final Function<Type, String> TYPE_NAME =
       new Function<Type, String>() {
         @Override public String apply(Type from) {
-          return Types.toString(from);
+          return JavaVersion.CURRENT.typeName(from);
         }
       };
 
@@ -146,7 +153,7 @@
    */
   static <D extends GenericDeclaration> TypeVariable<D> newArtificialTypeVariable(
       D declaration, String name, Type... bounds) {
-    return new TypeVariableImpl<D>(
+    return newTypeVariableImpl(
         declaration,
         name,
         (bounds.length == 0)
@@ -286,11 +293,11 @@
     @Override public String toString() {
       StringBuilder builder = new StringBuilder();
       if (ownerType != null) {
-        builder.append(Types.toString(ownerType)).append('.');
+        builder.append(JavaVersion.CURRENT.typeName(ownerType)).append('.');
       }
       builder.append(rawType.getName())
           .append('<')
-          .append(COMMA_JOINER.join(transform(argumentsList, TYPE_TO_STRING)))
+          .append(COMMA_JOINER.join(transform(argumentsList, TYPE_NAME)))
           .append('>');
       return builder.toString();
     }
@@ -314,8 +321,76 @@
     private static final long serialVersionUID = 0;
   }
 
-  private static final class TypeVariableImpl<D extends GenericDeclaration>
-      implements TypeVariable<D> {
+  private static <D extends GenericDeclaration> TypeVariable<D> newTypeVariableImpl(
+      D genericDeclaration, String name, Type[] bounds) {
+    TypeVariableImpl<D> typeVariableImpl =
+        new TypeVariableImpl<D>(genericDeclaration, name, bounds);
+    @SuppressWarnings("unchecked")
+    TypeVariable<D> typeVariable = Reflection.newProxy(
+        TypeVariable.class, new TypeVariableInvocationHandler(typeVariableImpl));
+    return typeVariable;
+  }
+
+  /**
+   * Invocation handler to work around a compatibility problem between Java 7 and Java 8.
+   *
+   * <p>Java 8 introduced a new method {@code getAnnotatedBounds()} in the {@link TypeVariable}
+   * interface, whose return type {@code AnnotatedType[]} is also new in Java 8. That means that we
+   * cannot implement that interface in source code in a way that will compile on both Java 7 and
+   * Java 8. If we include the {@code getAnnotatedBounds()} method then its return type means
+   * it won't compile on Java 7, while if we don't include the method then the compiler will
+   * complain that an abstract method is unimplemented. So instead we use a dynamic proxy to
+   * get an implementation. If the method being called on the {@code TypeVariable} instance has
+   * the same name as one of the public methods of {@link TypeVariableImpl}, the proxy calls
+   * the same method on its instance of {@code TypeVariableImpl}. Otherwise it throws {@link
+   * UnsupportedOperationException}; this should only apply to {@code getAnnotatedBounds()}. This
+   * does mean that users on Java 8 who obtain an instance of {@code TypeVariable} from {@link
+   * TypeResolver#resolveType} will not be able to call {@code getAnnotatedBounds()} on it, but that
+   * should hopefully be rare.
+   *
+   * <p>This workaround should be removed at a distant future time when we no longer support Java
+   * versions earlier than 8.
+   */
+  private static final class TypeVariableInvocationHandler implements InvocationHandler {
+    private static final ImmutableMap<String, Method> typeVariableMethods;
+    static {
+      ImmutableMap.Builder<String, Method> builder = ImmutableMap.builder();
+      for (Method method : TypeVariableImpl.class.getMethods()) {
+        if (method.getDeclaringClass().equals(TypeVariableImpl.class)) {
+          try {
+            method.setAccessible(true);
+          } catch (AccessControlException e) {
+            // OK: the method is accessible to us anyway. The setAccessible call is only for
+            // unusual execution environments where that might not be true.
+          }
+          builder.put(method.getName(), method);
+        }
+      }
+      typeVariableMethods = builder.build();
+    }
+
+    private final TypeVariableImpl<?> typeVariableImpl;
+
+    TypeVariableInvocationHandler(TypeVariableImpl<?> typeVariableImpl) {
+      this.typeVariableImpl = typeVariableImpl;
+    }
+
+    @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+      String methodName = method.getName();
+      Method typeVariableMethod = typeVariableMethods.get(methodName);
+      if (typeVariableMethod == null) {
+        throw new UnsupportedOperationException(methodName);
+      } else {
+        try {
+          return typeVariableMethod.invoke(typeVariableImpl, args);
+        } catch (InvocationTargetException e) {
+          throw e.getCause();
+        }
+      }
+    }
+  }
+
+  private static final class TypeVariableImpl<D extends GenericDeclaration> {
 
     private final D genericDeclaration;
     private final String name;
@@ -328,15 +403,19 @@
       this.bounds = ImmutableList.copyOf(bounds);
     }
 
-    @Override public Type[] getBounds() {
+    public Type[] getBounds() {
       return toArray(bounds);
     }
 
-    @Override public D getGenericDeclaration() {
+    public D getGenericDeclaration() {
       return genericDeclaration;
     }
 
-    @Override public String getName() {
+    public String getName() {
+      return name;
+    }
+
+    public String getTypeName() {
       return name;
     }
 
@@ -351,8 +430,12 @@
     @Override public boolean equals(Object obj) {
       if (NativeTypeVariableEquals.NATIVE_TYPE_VARIABLE_ONLY) {
         // equal only to our TypeVariable implementation with identical bounds
-        if (obj instanceof TypeVariableImpl) {
-          TypeVariableImpl<?> that = (TypeVariableImpl<?>) obj;
+        if (obj != null
+            && Proxy.isProxyClass(obj.getClass())
+            && Proxy.getInvocationHandler(obj) instanceof TypeVariableInvocationHandler) {
+          TypeVariableInvocationHandler typeVariableInvocationHandler =
+              (TypeVariableInvocationHandler) Proxy.getInvocationHandler(obj);
+          TypeVariableImpl<?> that = typeVariableInvocationHandler.typeVariableImpl;
           return name.equals(that.getName())
               && genericDeclaration.equals(that.getGenericDeclaration())
               && bounds.equals(that.bounds);
@@ -406,10 +489,10 @@
     @Override public String toString() {
       StringBuilder builder = new StringBuilder("?");
       for (Type lowerBound : lowerBounds) {
-        builder.append(" super ").append(Types.toString(lowerBound));
+        builder.append(" super ").append(JavaVersion.CURRENT.typeName(lowerBound));
       }
       for (Type upperBound : filterUpperBounds(upperBounds)) {
-        builder.append(" extends ").append(Types.toString(upperBound));
+        builder.append(" extends ").append(JavaVersion.CURRENT.typeName(upperBound));
       }
       return builder.toString();
     }
@@ -444,7 +527,7 @@
     return Array.newInstance(componentType, 0).getClass();
   }
 
-  // TODO(benyu): Once we are on Java 7, delete this abstraction
+  // TODO(benyu): Once we are on Java 8, delete this abstraction
   enum JavaVersion {
 
     JAVA6 {
@@ -473,14 +556,45 @@
       @Override Type usedInGenericType(Type type) {
         return checkNotNull(type);
       }
+    },
+    JAVA8 {
+      @Override Type newArrayType(Type componentType) {
+        return JAVA7.newArrayType(componentType);
+      }
+      @Override Type usedInGenericType(Type type) {
+        return JAVA7.usedInGenericType(type);
+      }
+      @Override String typeName(Type type) {
+        try {
+          Method getTypeName = Type.class.getMethod("getTypeName");
+          return (String) getTypeName.invoke(type);
+        } catch (NoSuchMethodException e) {
+          throw new AssertionError("Type.getTypeName should be available in Java 8");
+        } catch (InvocationTargetException e) {
+          throw new RuntimeException(e);
+        } catch (IllegalAccessException e) {
+          throw new RuntimeException(e);
+        }
+      }
     }
     ;
 
-    static final JavaVersion CURRENT =
-        (new TypeCapture<int[]>() {}.capture() instanceof Class)
-        ? JAVA7 : JAVA6;
+    static final JavaVersion CURRENT;
+    static {
+      if (AnnotatedElement.class.isAssignableFrom(TypeVariable.class)) {
+        CURRENT = JAVA8;
+      } else if (new TypeCapture<int[]>() {}.capture() instanceof Class) {
+        CURRENT = JAVA7;
+      } else {
+        CURRENT = JAVA6;
+      }
+    }
+
     abstract Type newArrayType(Type componentType);
     abstract Type usedInGenericType(Type type);
+    String typeName(Type type) {
+      return Types.toString(type);
+    }
 
     final ImmutableList<Type> usedInGenericType(Type[] types) {
       ImmutableList.Builder<Type> builder = ImmutableList.builder();
diff --git a/guava/src/com/google/common/util/concurrent/AbstractExecutionThreadService.java b/guava/src/com/google/common/util/concurrent/AbstractExecutionThreadService.java
index 69d31ce..aefe27f 100644
--- a/guava/src/com/google/common/util/concurrent/AbstractExecutionThreadService.java
+++ b/guava/src/com/google/common/util/concurrent/AbstractExecutionThreadService.java
@@ -152,20 +152,6 @@
     return serviceName() + " [" + state() + "]";
   }
 
-  // We override instead of using ForwardingService so that these can be final.
-
-  @Deprecated
-  @Override
-  public final ListenableFuture<State> start() {
-    return delegate.start();
-  }
-
-  @Deprecated
-  @Override
-   public final State startAndWait() {
-    return delegate.startAndWait();
-  }
-
   @Override public final boolean isRunning() {
     return delegate.isRunning();
   }
@@ -174,18 +160,6 @@
     return delegate.state();
   }
 
-  @Deprecated
-  @Override
-   public final ListenableFuture<State> stop() {
-    return delegate.stop();
-  }
-
-  @Deprecated
-  @Override
-   public final State stopAndWait() {
-    return delegate.stopAndWait();
-  }
-
   /**
    * @since 13.0
    */
diff --git a/guava/src/com/google/common/util/concurrent/AbstractIdleService.java b/guava/src/com/google/common/util/concurrent/AbstractIdleService.java
index de120e1..23a56e1 100644
--- a/guava/src/com/google/common/util/concurrent/AbstractIdleService.java
+++ b/guava/src/com/google/common/util/concurrent/AbstractIdleService.java
@@ -106,20 +106,6 @@
     return serviceName() + " [" + state() + "]";
   }
 
-  // We override instead of using ForwardingService so that these can be final.
-
-  @Deprecated
-  @Override
-   public final ListenableFuture<State> start() {
-    return delegate.start();
-  }
-
-  @Deprecated
-  @Override
-   public final State startAndWait() {
-    return delegate.startAndWait();
-  }
-
   @Override public final boolean isRunning() {
     return delegate.isRunning();
   }
@@ -128,18 +114,6 @@
     return delegate.state();
   }
 
-  @Deprecated
-  @Override
-  public final ListenableFuture<State> stop() {
-    return delegate.stop();
-  }
-
-  @Deprecated
-  @Override
-  public final State stopAndWait() {
-    return delegate.stopAndWait();
-  }
-
   /**
    * @since 13.0
    */
diff --git a/guava/src/com/google/common/util/concurrent/AbstractListeningExecutorService.java b/guava/src/com/google/common/util/concurrent/AbstractListeningExecutorService.java
index 77b979d..1208153 100644
--- a/guava/src/com/google/common/util/concurrent/AbstractListeningExecutorService.java
+++ b/guava/src/com/google/common/util/concurrent/AbstractListeningExecutorService.java
@@ -1,170 +1,60 @@
 /*
- * This file is a modified version of
- * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/concurrent/AbstractExecutorService.java?revision=1.35
- * which contained the following notice:
+ * Copyright (C) 2011 The Guava Authors
  *
- * Written by Doug Lea with assistance from members of JCP JSR-166 Expert Group and released to the
- * public domain, as explained at http://creativecommons.org/publicdomain/zero/1.0/
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- * Rationale for copying:
- * Guava targets JDK5, whose AbstractExecutorService class lacks the newTaskFor protected
- * customization methods needed by MoreExecutors.listeningDecorator. This class is a copy of
- * AbstractExecutorService from the JSR166 CVS repository. It contains the desired methods.
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 package com.google.common.util.concurrent;
 
-import static com.google.common.util.concurrent.MoreExecutors.invokeAnyImpl;
-
 import com.google.common.annotations.Beta;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
+import java.util.concurrent.AbstractExecutorService;
 import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
 
 import javax.annotation.Nullable;
 
 /**
- * Implements {@link ListeningExecutorService} execution methods atop the abstract {@link #execute}
- * method. More concretely, the {@code submit}, {@code invokeAny} and {@code invokeAll} methods
- * create {@link ListenableFutureTask} instances and pass them to {@link #execute}.
+ * Abstract {@link ListeningExecutorService} implementation that creates
+ * {@link ListenableFutureTask} instances for each {@link Runnable} and {@link Callable} submitted
+ * to it. These tasks are run with the abstract {@link #execute execute(Runnable)} method.
  *
  * <p>In addition to {@link #execute}, subclasses must implement all methods related to shutdown and
  * termination.
  *
- * @author Doug Lea
+ * @author Chris Povirk
  * @since 14.0
  */
 @Beta
-public abstract class AbstractListeningExecutorService implements ListeningExecutorService {
-  @Override
-  public ListenableFuture<?> submit(Runnable task) {
-    ListenableFutureTask<Void> ftask = ListenableFutureTask.create(task, null);
-    execute(ftask);
-    return ftask;
+public abstract class AbstractListeningExecutorService
+    extends AbstractExecutorService implements ListeningExecutorService {
+
+  @Override protected final <T> ListenableFutureTask<T> newTaskFor(Runnable runnable, T value) {
+    return ListenableFutureTask.create(runnable, value);
   }
 
-  @Override
-  public <T> ListenableFuture<T> submit(Runnable task, @Nullable T result) {
-    ListenableFutureTask<T> ftask = ListenableFutureTask.create(task, result);
-    execute(ftask);
-    return ftask;
+  @Override protected final <T> ListenableFutureTask<T> newTaskFor(Callable<T> callable) {
+    return ListenableFutureTask.create(callable);
   }
 
-  @Override
-  public <T> ListenableFuture<T> submit(Callable<T> task) {
-    ListenableFutureTask<T> ftask = ListenableFutureTask.create(task);
-    execute(ftask);
-    return ftask;
+  @Override public ListenableFuture<?> submit(Runnable task) {
+    return (ListenableFuture<?>) super.submit(task);
   }
 
-  @Override
-  public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException,
-      ExecutionException {
-    try {
-      return invokeAnyImpl(this, tasks, false, 0);
-    } catch (TimeoutException cannotHappen) {
-      throw new AssertionError();
-    }
+  @Override public <T> ListenableFuture<T> submit(Runnable task, @Nullable T result) {
+    return (ListenableFuture<T>) super.submit(task, result);
   }
 
-  @Override
-  public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
-      throws InterruptedException, ExecutionException, TimeoutException {
-    return invokeAnyImpl(this, tasks, true, unit.toNanos(timeout));
-  }
-
-  @Override
-  public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
-      throws InterruptedException {
-    if (tasks == null) {
-      throw new NullPointerException();
-    }
-    List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
-    boolean done = false;
-    try {
-      for (Callable<T> t : tasks) {
-        ListenableFutureTask<T> f = ListenableFutureTask.create(t);
-        futures.add(f);
-        execute(f);
-      }
-      for (Future<T> f : futures) {
-        if (!f.isDone()) {
-          try {
-            f.get();
-          } catch (CancellationException ignore) {} catch (ExecutionException ignore) {}
-        }
-      }
-      done = true;
-      return futures;
-    } finally {
-      if (!done) {
-        for (Future<T> f : futures) {
-          f.cancel(true);
-        }
-      }
-    }
-  }
-
-  @Override
-  public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout,
-      TimeUnit unit) throws InterruptedException {
-    if (tasks == null || unit == null) {
-      throw new NullPointerException();
-    }
-    long nanos = unit.toNanos(timeout);
-    List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
-    boolean done = false;
-    try {
-      for (Callable<T> t : tasks) {
-        futures.add(ListenableFutureTask.create(t));
-      }
-
-      long lastTime = System.nanoTime();
-
-      // Interleave time checks and calls to execute in case
-      // executor doesn't have any/much parallelism.
-      Iterator<Future<T>> it = futures.iterator();
-      while (it.hasNext()) {
-        execute((Runnable) (it.next()));
-        long now = System.nanoTime();
-        nanos -= now - lastTime;
-        lastTime = now;
-        if (nanos <= 0) {
-          return futures;
-        }
-      }
-
-      for (Future<T> f : futures) {
-        if (!f.isDone()) {
-          if (nanos <= 0) {
-            return futures;
-          }
-          try {
-            f.get(nanos, TimeUnit.NANOSECONDS);
-          } catch (CancellationException ignore) {} catch (ExecutionException ignore) {} catch (TimeoutException toe) {
-            return futures;
-          }
-          long now = System.nanoTime();
-          nanos -= now - lastTime;
-          lastTime = now;
-        }
-      }
-      done = true;
-      return futures;
-    } finally {
-      if (!done) {
-        for (Future<T> f : futures) {
-          f.cancel(true);
-        }
-      }
-    }
+  @Override public <T> ListenableFuture<T> submit(Callable<T> task) {
+    return (ListenableFuture<T>) super.submit(task);
   }
 }
diff --git a/guava/src/com/google/common/util/concurrent/AbstractScheduledService.java b/guava/src/com/google/common/util/concurrent/AbstractScheduledService.java
index ce203bc..b45440e 100644
--- a/guava/src/com/google/common/util/concurrent/AbstractScheduledService.java
+++ b/guava/src/com/google/common/util/concurrent/AbstractScheduledService.java
@@ -16,6 +16,8 @@
 
 package com.google.common.util.concurrent;
 
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
+
 import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Supplier;
@@ -299,7 +301,8 @@
       }
       @Override public void failed(State from, Throwable failure) {
         executor.shutdown();
-      }}, MoreExecutors.sameThreadExecutor());
+      }
+    }, directExecutor());
     return executor;
   }
 
@@ -317,20 +320,6 @@
     return serviceName() + " [" + state() + "]";
   }
 
-  // We override instead of using ForwardingService so that these can be final.
-
-  @Deprecated
-  @Override
-   public final ListenableFuture<State> start() {
-    return delegate.start();
-  }
-
-  @Deprecated
-  @Override
-   public final State startAndWait() {
-    return delegate.startAndWait();
-  }
-
   @Override public final boolean isRunning() {
     return delegate.isRunning();
   }
@@ -339,18 +328,6 @@
     return delegate.state();
   }
 
-  @Deprecated
-  @Override
-   public final ListenableFuture<State> stop() {
-    return delegate.stop();
-  }
-
-  @Deprecated
-  @Override
-   public final State stopAndWait() {
-    return delegate.stopAndWait();
-  }
-
   /**
    * @since 13.0
    */
diff --git a/guava/src/com/google/common/util/concurrent/AbstractService.java b/guava/src/com/google/common/util/concurrent/AbstractService.java
index 0330cf4..0e996ed 100644
--- a/guava/src/com/google/common/util/concurrent/AbstractService.java
+++ b/guava/src/com/google/common/util/concurrent/AbstractService.java
@@ -34,7 +34,6 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -97,9 +96,6 @@
 
   private final Monitor monitor = new Monitor();
 
-  private final Transition startup = new Transition();
-  private final Transition shutdown = new Transition();
-
   private final Guard isStartable = new Guard(monitor) {
     @Override public boolean isSatisfied() {
       return state() == NEW;
@@ -144,52 +140,7 @@
   private volatile StateSnapshot snapshot = new StateSnapshot(NEW);
 
   /** Constructor for use by subclasses. */
-  protected AbstractService() {
-
-    // Add a listener to update the futures. This needs to be added first so that it is executed
-    // before the other listeners. This way the other listeners can access the completed futures.
-    addListener(
-        new Listener() {
-          @Override public void running() {
-            startup.set(RUNNING);
-          }
-
-          @Override public void stopping(State from) {
-            if (from == STARTING) {
-              startup.set(STOPPING);
-            }
-          }
-
-          @Override public void terminated(State from) {
-            if (from == NEW) {
-              startup.set(TERMINATED);
-            }
-            shutdown.set(TERMINATED);
-          }
-
-          @Override public void failed(State from, Throwable failure) {
-            switch (from) {
-              case STARTING:
-                startup.setException(failure);
-                shutdown.setException(new Exception("Service failed to start.", failure));
-                break;
-              case RUNNING:
-                shutdown.setException(new Exception("Service failed while running", failure));
-                break;
-              case STOPPING:
-                shutdown.setException(failure);
-                break;
-              case TERMINATED:  // fall-through
-              case FAILED:  // fall-through
-              case NEW:  // fall-through
-              default:
-                throw new AssertionError("Unexpected from state: " + from);
-            }
-          }
-        },
-        MoreExecutors.sameThreadExecutor());
-
-  }
+  protected AbstractService() {}
 
   /**
    * This method is called by {@link #startAsync} to initiate service startup. The invocation of
@@ -234,24 +185,6 @@
     return this;
   }
 
-  @Deprecated
-  @Override
-  public final ListenableFuture<State> start() {
-    if (monitor.enterIf(isStartable)) {
-      try {
-        snapshot = new StateSnapshot(STARTING);
-        starting();
-        doStart();
-      } catch (Throwable startupFailure) {
-        notifyFailed(startupFailure);
-      } finally {
-        monitor.leave();
-        executeListeners();
-      }
-    }
-    return startup;
-  }
-
   @Override public final Service stopAsync() {
     if (monitor.enterIf(isStoppable)) {
       try {
@@ -290,24 +223,6 @@
     return this;
   }
 
-  @Deprecated
-  @Override
-  public final ListenableFuture<State> stop() {
-    return shutdown;
-  }
-
-  @Deprecated
-  @Override
-  public State startAndWait() {
-    return Futures.getUnchecked(start());
-  }
-
-  @Deprecated
-  @Override
-  public State stopAndWait() {
-    return Futures.getUnchecked(stop());
-  }
-
   @Override public final void awaitRunning() {
     monitor.enterWhenUninterruptibly(hasReachedRunning);
     try {
@@ -507,19 +422,6 @@
     return getClass().getSimpleName() + " [" + state() + "]";
   }
 
-  // A change from one service state to another, plus the result of the change.
-  private class Transition extends AbstractFuture<State> {
-    @Override
-    public State get(long timeout, TimeUnit unit)
-        throws InterruptedException, TimeoutException, ExecutionException {
-      try {
-        return super.get(timeout, unit);
-      } catch (TimeoutException e) {
-        throw new TimeoutException(AbstractService.this.toString());
-      }
-    }
-  }
-
   /**
    * Attempts to execute all the listeners in {@link #listeners} while not holding the
    * {@link #monitor}.
diff --git a/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java b/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java
new file mode 100644
index 0000000..e438cec
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java
@@ -0,0 +1,1034 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.util.concurrent;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.MapMaker;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.ThreadSafe;
+
+/**
+ * The {@code CycleDetectingLockFactory} creates {@link ReentrantLock} instances and
+ * {@link ReentrantReadWriteLock} instances that detect potential deadlock by checking
+ * for cycles in lock acquisition order.
+ * <p>
+ * Potential deadlocks detected when calling the {@code lock()},
+ * {@code lockInterruptibly()}, or {@code tryLock()} methods will result in the
+ * execution of the {@link Policy} specified when creating the factory. The
+ * currently available policies are:
+ * <ul>
+ * <li>DISABLED
+ * <li>WARN
+ * <li>THROW
+ * </ul>
+ * <p>The locks created by a factory instance will detect lock acquisition cycles
+ * with locks created by other {@code CycleDetectingLockFactory} instances
+ * (except those with {@code Policy.DISABLED}). A lock's behavior when a cycle
+ * is detected, however, is defined by the {@code Policy} of the factory that
+ * created it. This allows detection of cycles across components while
+ * delegating control over lock behavior to individual components.
+ * <p>
+ * Applications are encouraged to use a {@code CycleDetectingLockFactory} to
+ * create any locks for which external/unmanaged code is executed while the lock
+ * is held. (See caveats under <strong>Performance</strong>).
+ * <p>
+ * <strong>Cycle Detection</strong>
+ * <p>
+ * Deadlocks can arise when locks are acquired in an order that forms a cycle.
+ * In a simple example involving two locks and two threads, deadlock occurs
+ * when one thread acquires Lock A, and then Lock B, while another thread
+ * acquires Lock B, and then Lock A:
+ * <pre>
+ * Thread1: acquire(LockA) --X acquire(LockB)
+ * Thread2: acquire(LockB) --X acquire(LockA)
+ * </pre>
+ * <p>Neither thread will progress because each is waiting for the other. In more
+ * complex applications, cycles can arise from interactions among more than 2
+ * locks:
+ * <pre>
+ * Thread1: acquire(LockA) --X acquire(LockB)
+ * Thread2: acquire(LockB) --X acquire(LockC)
+ * ...
+ * ThreadN: acquire(LockN) --X acquire(LockA)
+ * </pre>
+ * <p>The implementation detects cycles by constructing a directed graph in which
+ * each lock represents a node and each edge represents an acquisition ordering
+ * between two locks.
+ * <ul>
+ * <li>Each lock adds (and removes) itself to/from a ThreadLocal Set of acquired
+ *   locks when the Thread acquires its first hold (and releases its last
+ *   remaining hold).
+ * <li>Before the lock is acquired, the lock is checked against the current set
+ *   of acquired locks---to each of the acquired locks, an edge from the
+ *   soon-to-be-acquired lock is either verified or created.
+ * <li>If a new edge needs to be created, the outgoing edges of the acquired
+ *   locks are traversed to check for a cycle that reaches the lock to be
+ *   acquired. If no cycle is detected, a new "safe" edge is created.
+ * <li>If a cycle is detected, an "unsafe" (cyclic) edge is created to represent
+ *   a potential deadlock situation, and the appropriate Policy is executed.
+ * </ul>
+ * <p>Note that detection of potential deadlock does not necessarily indicate that
+ * deadlock will happen, as it is possible that higher level application logic
+ * prevents the cyclic lock acquisition from occurring. One example of a false
+ * positive is:
+ * <pre>
+ * LockA -&gt; LockB -&gt; LockC
+ * LockA -&gt; LockC -&gt; LockB
+ * </pre>
+ *
+ * <strong>ReadWriteLocks</strong>
+ * <p>
+ * While {@code ReadWriteLock} instances have different properties and can form cycles
+ * without potential deadlock, this class treats {@code ReadWriteLock} instances as
+ * equivalent to traditional exclusive locks. Although this increases the false
+ * positives that the locks detect (i.e. cycles that will not actually result in
+ * deadlock), it simplifies the algorithm and implementation considerably. The
+ * assumption is that a user of this factory wishes to eliminate any cyclic
+ * acquisition ordering.
+ * <p>
+ * <strong>Explicit Lock Acquisition Ordering</strong>
+ * <p>
+ * The {@link CycleDetectingLockFactory.WithExplicitOrdering} class can be used
+ * to enforce an application-specific ordering in addition to performing general
+ * cycle detection.
+ * <p>
+ * <strong>Garbage Collection</strong>
+ * <p>
+ * In order to allow proper garbage collection of unused locks, the edges of
+ * the lock graph are weak references.
+ * <p>
+ * <strong>Performance</strong>
+ * <p>
+ * The extra bookkeeping done by cycle detecting locks comes at some cost to
+ * performance. Benchmarks (as of December 2011) show that:
+ *
+ * <ul>
+ * <li>for an unnested {@code lock()} and {@code unlock()}, a cycle detecting
+ *   lock takes 38ns as opposed to the 24ns taken by a plain lock.
+ * <li>for nested locking, the cost increases with the depth of the nesting:
+ *   <ul>
+ *   <li> 2 levels: average of 64ns per lock()/unlock()
+ *   <li> 3 levels: average of 77ns per lock()/unlock()
+ *   <li> 4 levels: average of 99ns per lock()/unlock()
+ *   <li> 5 levels: average of 103ns per lock()/unlock()
+ *   <li>10 levels: average of 184ns per lock()/unlock()
+ *   <li>20 levels: average of 393ns per lock()/unlock()
+ *   </ul>
+ * </ul>
+ *
+ * <p>As such, the CycleDetectingLockFactory may not be suitable for
+ * performance-critical applications which involve tightly-looped or
+ * deeply-nested locking algorithms.
+ *
+ * @author Darick Tong
+ * @since 13.0
+ */
+@Beta
+@ThreadSafe
+public class CycleDetectingLockFactory {
+
+  /**
+   * Encapsulates the action to be taken when a potential deadlock is
+   * encountered. Clients can use one of the predefined {@link Policies} or
+   * specify a custom implementation. Implementations must be thread-safe.
+   *
+   * @since 13.0
+   */
+  @Beta
+  @ThreadSafe
+  public interface Policy {
+
+    /**
+     * Called when a potential deadlock is encountered. Implementations can
+     * throw the given {@code exception} and/or execute other desired logic.
+     * <p>
+     * Note that the method will be called even upon an invocation of
+     * {@code tryLock()}. Although {@code tryLock()} technically recovers from
+     * deadlock by eventually timing out, this behavior is chosen based on the
+     * assumption that it is the application's wish to prohibit any cyclical
+     * lock acquisitions.
+     */
+    void handlePotentialDeadlock(PotentialDeadlockException exception);
+  }
+
+  /**
+   * Pre-defined {@link Policy} implementations.
+   *
+   * @since 13.0
+   */
+  @Beta
+  public enum Policies implements Policy {
+    /**
+     * When potential deadlock is detected, this policy results in the throwing
+     * of the {@code PotentialDeadlockException} indicating the potential
+     * deadlock, which includes stack traces illustrating the cycle in lock
+     * acquisition order.
+     */
+    THROW {
+      @Override
+      public void handlePotentialDeadlock(PotentialDeadlockException e) {
+        throw e;
+      }
+    },
+
+    /**
+     * When potential deadlock is detected, this policy results in the logging
+     * of a {@link Level#SEVERE} message indicating the potential deadlock,
+     * which includes stack traces illustrating the cycle in lock acquisition
+     * order.
+     */
+    WARN {
+      @Override
+      public void handlePotentialDeadlock(PotentialDeadlockException e) {
+        logger.log(Level.SEVERE, "Detected potential deadlock", e);
+      }
+    },
+
+    /**
+     * Disables cycle detection. This option causes the factory to return
+     * unmodified lock implementations provided by the JDK, and is provided to
+     * allow applications to easily parameterize when cycle detection is
+     * enabled.
+     * <p>
+     * Note that locks created by a factory with this policy will <em>not</em>
+     * participate the cycle detection performed by locks created by other
+     * factories.
+     */
+    DISABLED {
+      @Override
+      public void handlePotentialDeadlock(PotentialDeadlockException e) {
+      }
+    };
+  }
+
+  /**
+   * Creates a new factory with the specified policy.
+   */
+  public static CycleDetectingLockFactory newInstance(Policy policy) {
+    return new CycleDetectingLockFactory(policy);
+  }
+
+  /**
+   * Equivalent to {@code newReentrantLock(lockName, false)}.
+   */
+  public ReentrantLock newReentrantLock(String lockName) {
+    return newReentrantLock(lockName, false);
+  }
+
+  /**
+   * Creates a {@link ReentrantLock} with the given fairness policy. The
+   * {@code lockName} is used in the warning or exception output to help
+   * identify the locks involved in the detected deadlock.
+   */
+  public ReentrantLock newReentrantLock(String lockName, boolean fair) {
+    return policy == Policies.DISABLED ? new ReentrantLock(fair)
+        : new CycleDetectingReentrantLock(
+            new LockGraphNode(lockName), fair);
+  }
+
+  /**
+   * Equivalent to {@code newReentrantReadWriteLock(lockName, false)}.
+   */
+  public ReentrantReadWriteLock newReentrantReadWriteLock(String lockName) {
+    return newReentrantReadWriteLock(lockName, false);
+  }
+
+  /**
+   * Creates a {@link ReentrantReadWriteLock} with the given fairness policy.
+   * The {@code lockName} is used in the warning or exception output to help
+   * identify the locks involved in the detected deadlock.
+   */
+  public ReentrantReadWriteLock newReentrantReadWriteLock(
+      String lockName, boolean fair) {
+    return policy == Policies.DISABLED ? new ReentrantReadWriteLock(fair)
+        : new CycleDetectingReentrantReadWriteLock(
+            new LockGraphNode(lockName), fair);
+  }
+
+  // A static mapping from an Enum type to its set of LockGraphNodes.
+  private static final ConcurrentMap<Class<? extends Enum>,
+      Map<? extends Enum, LockGraphNode>> lockGraphNodesPerType =
+          new MapMaker().weakKeys().makeMap();
+
+  /**
+   * Creates a {@code CycleDetectingLockFactory.WithExplicitOrdering<E>}.
+   */
+  public static <E extends Enum<E>> WithExplicitOrdering<E>
+      newInstanceWithExplicitOrdering(Class<E> enumClass, Policy policy) {
+    // createNodes maps each enumClass to a Map with the corresponding enum key
+    // type.
+    checkNotNull(enumClass);
+    checkNotNull(policy);
+    @SuppressWarnings("unchecked")
+    Map<E, LockGraphNode> lockGraphNodes =
+        (Map<E, LockGraphNode>) getOrCreateNodes(enumClass);
+    return new WithExplicitOrdering<E>(policy, lockGraphNodes);
+  }
+
+  private static Map<? extends Enum, LockGraphNode> getOrCreateNodes(
+      Class<? extends Enum> clazz) {
+    Map<? extends Enum, LockGraphNode> existing =
+        lockGraphNodesPerType.get(clazz);
+    if (existing != null) {
+      return existing;
+    }
+    Map<? extends Enum, LockGraphNode> created = createNodes(clazz);
+    existing = lockGraphNodesPerType.putIfAbsent(clazz, created);
+    return MoreObjects.firstNonNull(existing, created);
+  }
+
+  /**
+   * For a given Enum type, creates an immutable map from each of the Enum's
+   * values to a corresponding LockGraphNode, with the
+   * {@code allowedPriorLocks} and {@code disallowedPriorLocks} prepopulated
+   * with nodes according to the natural ordering of the associated Enum values.
+   */
+  @VisibleForTesting
+  static <E extends Enum<E>> Map<E, LockGraphNode> createNodes(Class<E> clazz) {
+    EnumMap<E, LockGraphNode> map = Maps.newEnumMap(clazz);
+    E[] keys = clazz.getEnumConstants();
+    final int numKeys = keys.length;
+    ArrayList<LockGraphNode> nodes =
+        Lists.newArrayListWithCapacity(numKeys);
+    // Create a LockGraphNode for each enum value.
+    for (E key : keys) {
+      LockGraphNode node = new LockGraphNode(getLockName(key));
+      nodes.add(node);
+      map.put(key, node);
+    }
+    // Pre-populate all allowedPriorLocks with nodes of smaller ordinal.
+    for (int i = 1; i < numKeys; i++) {
+      nodes.get(i).checkAcquiredLocks(Policies.THROW, nodes.subList(0, i));
+    }
+    // Pre-populate all disallowedPriorLocks with nodes of larger ordinal.
+    for (int i = 0; i < numKeys - 1; i++) {
+      nodes.get(i).checkAcquiredLocks(
+          Policies.DISABLED, nodes.subList(i + 1, numKeys));
+    }
+    return Collections.unmodifiableMap(map);
+  }
+
+  /**
+   * For the given Enum value {@code rank}, returns the value's
+   * {@code "EnumClass.name"}, which is used in exception and warning
+   * output.
+   */
+  private static String getLockName(Enum<?> rank) {
+    return rank.getDeclaringClass().getSimpleName() + "." + rank.name();
+  }
+
+  /**
+   * <p>A {@code CycleDetectingLockFactory.WithExplicitOrdering} provides the
+   * additional enforcement of an application-specified ordering of lock
+   * acquisitions. The application defines the allowed ordering with an
+   * {@code Enum} whose values each correspond to a lock type. The order in
+   * which the values are declared dictates the allowed order of lock
+   * acquisition. In other words, locks corresponding to smaller values of
+   * {@link Enum#ordinal()} should only be acquired before locks with larger
+   * ordinals. Example:
+   *
+   * <pre>   {@code
+   * enum MyLockOrder {
+   *   FIRST, SECOND, THIRD;
+   * }
+   *
+   * CycleDetectingLockFactory.WithExplicitOrdering<MyLockOrder> factory =
+   *   CycleDetectingLockFactory.newInstanceWithExplicitOrdering(Policies.THROW);
+   *
+   * Lock lock1 = factory.newReentrantLock(MyLockOrder.FIRST);
+   * Lock lock2 = factory.newReentrantLock(MyLockOrder.SECOND);
+   * Lock lock3 = factory.newReentrantLock(MyLockOrder.THIRD);
+   *
+   * lock1.lock();
+   * lock3.lock();
+   * lock2.lock();  // will throw an IllegalStateException}</pre>
+   *
+   * <p>As with all locks created by instances of {@code CycleDetectingLockFactory}
+   * explicitly ordered locks participate in general cycle detection with all
+   * other cycle detecting locks, and a lock's behavior when detecting a cyclic
+   * lock acquisition is defined by the {@code Policy} of the factory that
+   * created it.
+   *
+   * <p>Note, however, that although multiple locks can be created for a given Enum
+   * value, whether it be through separate factory instances or through multiple
+   * calls to the same factory, attempting to acquire multiple locks with the
+   * same Enum value (within the same thread) will result in an
+   * IllegalStateException regardless of the factory's policy. For example:
+   *
+   * <pre>   {@code
+   * CycleDetectingLockFactory.WithExplicitOrdering<MyLockOrder> factory1 =
+   *   CycleDetectingLockFactory.newInstanceWithExplicitOrdering(...);
+   * CycleDetectingLockFactory.WithExplicitOrdering<MyLockOrder> factory2 =
+   *   CycleDetectingLockFactory.newInstanceWithExplicitOrdering(...);
+   *
+   * Lock lockA = factory1.newReentrantLock(MyLockOrder.FIRST);
+   * Lock lockB = factory1.newReentrantLock(MyLockOrder.FIRST);
+   * Lock lockC = factory2.newReentrantLock(MyLockOrder.FIRST);
+   *
+   * lockA.lock();
+   *
+   * lockB.lock();  // will throw an IllegalStateException
+   * lockC.lock();  // will throw an IllegalStateException
+   *
+   * lockA.lock();  // reentrant acquisition is okay}</pre>
+   *
+   * <p>It is the responsibility of the application to ensure that multiple lock
+   * instances with the same rank are never acquired in the same thread.
+   *
+   * @param <E> The Enum type representing the explicit lock ordering.
+   * @since 13.0
+   */
+  @Beta
+  public static final class WithExplicitOrdering<E extends Enum<E>>
+      extends CycleDetectingLockFactory {
+
+    private final Map<E, LockGraphNode> lockGraphNodes;
+
+    @VisibleForTesting
+    WithExplicitOrdering(
+        Policy policy, Map<E, LockGraphNode> lockGraphNodes) {
+      super(policy);
+      this.lockGraphNodes = lockGraphNodes;
+    }
+
+    /**
+     * Equivalent to {@code newReentrantLock(rank, false)}.
+     */
+    public ReentrantLock newReentrantLock(E rank) {
+      return newReentrantLock(rank, false);
+    }
+
+    /**
+     * Creates a {@link ReentrantLock} with the given fairness policy and rank.
+     * The values returned by {@link Enum#getDeclaringClass()} and
+     * {@link Enum#name()} are used to describe the lock in warning or
+     * exception output.
+     *
+     * @throws IllegalStateException If the factory has already created a
+     *    {@code Lock} with the specified rank.
+     */
+    public ReentrantLock newReentrantLock(E rank, boolean fair) {
+      return policy == Policies.DISABLED ? new ReentrantLock(fair)
+          : new CycleDetectingReentrantLock(lockGraphNodes.get(rank), fair);
+    }
+
+    /**
+     * Equivalent to {@code newReentrantReadWriteLock(rank, false)}.
+     */
+    public ReentrantReadWriteLock newReentrantReadWriteLock(E rank) {
+      return newReentrantReadWriteLock(rank, false);
+    }
+
+    /**
+     * Creates a {@link ReentrantReadWriteLock} with the given fairness policy
+     * and rank. The values returned by {@link Enum#getDeclaringClass()} and
+     * {@link Enum#name()} are used to describe the lock in warning or exception
+     * output.
+     *
+     * @throws IllegalStateException If the factory has already created a
+     *    {@code Lock} with the specified rank.
+     */
+    public ReentrantReadWriteLock newReentrantReadWriteLock(
+        E rank, boolean fair) {
+      return policy == Policies.DISABLED ? new ReentrantReadWriteLock(fair)
+          : new CycleDetectingReentrantReadWriteLock(
+              lockGraphNodes.get(rank), fair);
+    }
+  }
+
+  //////// Implementation /////////
+
+  private static final Logger logger = Logger.getLogger(
+      CycleDetectingLockFactory.class.getName());
+
+  final Policy policy;
+
+  private CycleDetectingLockFactory(Policy policy) {
+    this.policy = checkNotNull(policy);
+  }
+
+  /**
+   * Tracks the currently acquired locks for each Thread, kept up to date by
+   * calls to {@link #aboutToAcquire(CycleDetectingLock)} and
+   * {@link #lockStateChanged(CycleDetectingLock)}.
+   */
+  // This is logically a Set, but an ArrayList is used to minimize the amount
+  // of allocation done on lock()/unlock().
+  private static final ThreadLocal<ArrayList<LockGraphNode>>
+      acquiredLocks = new ThreadLocal<ArrayList<LockGraphNode>>() {
+    @Override
+    protected ArrayList<LockGraphNode> initialValue() {
+      return Lists.<LockGraphNode>newArrayListWithCapacity(3);
+    }
+  };
+
+  /**
+   * A Throwable used to record a stack trace that illustrates an example of
+   * a specific lock acquisition ordering. The top of the stack trace is
+   * truncated such that it starts with the acquisition of the lock in
+   * question, e.g.
+   *
+   * <pre>
+   * com...ExampleStackTrace: LockB -&gt; LockC
+   *   at com...CycleDetectingReentrantLock.lock(CycleDetectingLockFactory.java:443)
+   *   at ...
+   *   at ...
+   *   at com...MyClass.someMethodThatAcquiresLockB(MyClass.java:123)
+   * </pre>
+   */
+  private static class ExampleStackTrace extends IllegalStateException {
+
+    static final StackTraceElement[] EMPTY_STACK_TRACE =
+        new StackTraceElement[0];
+
+    static Set<String> EXCLUDED_CLASS_NAMES = ImmutableSet.of(
+        CycleDetectingLockFactory.class.getName(),
+        ExampleStackTrace.class.getName(),
+        LockGraphNode.class.getName());
+
+    ExampleStackTrace(LockGraphNode node1, LockGraphNode node2) {
+      super(node1.getLockName() + " -> " + node2.getLockName());
+      StackTraceElement[] origStackTrace = getStackTrace();
+      for (int i = 0, n = origStackTrace.length; i < n; i++) {
+        if (WithExplicitOrdering.class.getName().equals(
+                origStackTrace[i].getClassName())) {
+          // For pre-populated disallowedPriorLocks edges, omit the stack trace.
+          setStackTrace(EMPTY_STACK_TRACE);
+          break;
+        }
+        if (!EXCLUDED_CLASS_NAMES.contains(origStackTrace[i].getClassName())) {
+          setStackTrace(Arrays.copyOfRange(origStackTrace, i, n));
+          break;
+        }
+      }
+    }
+  }
+
+  /**
+   * Represents a detected cycle in lock acquisition ordering. The exception
+   * includes a causal chain of {@code ExampleStackTrace} instances to illustrate the
+   * cycle, e.g.
+   *
+   * <pre>
+   * com....PotentialDeadlockException: Potential Deadlock from LockC -&gt; ReadWriteA
+   *   at ...
+   *   at ...
+   * Caused by: com...ExampleStackTrace: LockB -&gt; LockC
+   *   at ...
+   *   at ...
+   * Caused by: com...ExampleStackTrace: ReadWriteA -&gt; LockB
+   *   at ...
+   *   at ...
+   * </pre>
+   *
+   * <p>Instances are logged for the {@code Policies.WARN}, and thrown for
+   * {@code Policies.THROW}.
+   *
+   * @since 13.0
+   */
+  @Beta
+  public static final class PotentialDeadlockException
+      extends ExampleStackTrace {
+
+    private final ExampleStackTrace conflictingStackTrace;
+
+    private PotentialDeadlockException(
+        LockGraphNode node1,
+        LockGraphNode node2,
+        ExampleStackTrace conflictingStackTrace) {
+      super(node1, node2);
+      this.conflictingStackTrace = conflictingStackTrace;
+      initCause(conflictingStackTrace);
+    }
+
+    public ExampleStackTrace getConflictingStackTrace() {
+      return conflictingStackTrace;
+    }
+
+    /**
+     * Appends the chain of messages from the {@code conflictingStackTrace} to
+     * the original {@code message}.
+     */
+    @Override
+    public String getMessage() {
+      StringBuilder message = new StringBuilder(super.getMessage());
+      for (Throwable t = conflictingStackTrace; t != null; t = t.getCause()) {
+        message.append(", ").append(t.getMessage());
+      }
+      return message.toString();
+    }
+  }
+
+  /**
+   * Internal Lock implementations implement the {@code CycleDetectingLock}
+   * interface, allowing the detection logic to treat all locks in the same
+   * manner.
+   */
+  private interface CycleDetectingLock {
+
+    /** @return the {@link LockGraphNode} associated with this lock. */
+    LockGraphNode getLockGraphNode();
+
+    /** @return {@code true} if the current thread has acquired this lock. */
+    boolean isAcquiredByCurrentThread();
+  }
+
+  /**
+   * A {@code LockGraphNode} associated with each lock instance keeps track of
+   * the directed edges in the lock acquisition graph.
+   */
+  private static class LockGraphNode {
+
+    /**
+     * The map tracking the locks that are known to be acquired before this
+     * lock, each associated with an example stack trace. Locks are weakly keyed
+     * to allow proper garbage collection when they are no longer referenced.
+     */
+    final Map<LockGraphNode, ExampleStackTrace> allowedPriorLocks =
+        new MapMaker().weakKeys().makeMap();
+
+    /**
+     * The map tracking lock nodes that can cause a lock acquisition cycle if
+     * acquired before this node.
+     */
+    final Map<LockGraphNode, PotentialDeadlockException>
+        disallowedPriorLocks = new MapMaker().weakKeys().makeMap();
+
+    final String lockName;
+
+    LockGraphNode(String lockName) {
+      this.lockName = Preconditions.checkNotNull(lockName);
+    }
+
+    String getLockName() {
+      return lockName;
+    }
+
+    void checkAcquiredLocks(
+        Policy policy, List<LockGraphNode> acquiredLocks) {
+      for (int i = 0, size = acquiredLocks.size(); i < size; i++) {
+        checkAcquiredLock(policy, acquiredLocks.get(i));
+      }
+    }
+
+    /**
+     * Checks the acquisition-ordering between {@code this}, which is about to
+     * be acquired, and the specified {@code acquiredLock}.
+     * <p>
+     * When this method returns, the {@code acquiredLock} should be in either
+     * the {@code preAcquireLocks} map, for the case in which it is safe to
+     * acquire {@code this} after the {@code acquiredLock}, or in the
+     * {@code disallowedPriorLocks} map, in which case it is not safe.
+     */
+    void checkAcquiredLock(Policy policy, LockGraphNode acquiredLock) {
+      // checkAcquiredLock() should never be invoked by a lock that has already
+      // been acquired. For unordered locks, aboutToAcquire() ensures this by
+      // checking isAcquiredByCurrentThread(). For ordered locks, however, this
+      // can happen because multiple locks may share the same LockGraphNode. In
+      // this situation, throw an IllegalStateException as defined by contract
+      // described in the documentation of WithExplicitOrdering.
+      Preconditions.checkState(
+          this != acquiredLock,
+          "Attempted to acquire multiple locks with the same rank " +
+          acquiredLock.getLockName());
+
+      if (allowedPriorLocks.containsKey(acquiredLock)) {
+        // The acquisition ordering from "acquiredLock" to "this" has already
+        // been verified as safe. In a properly written application, this is
+        // the common case.
+        return;
+      }
+      PotentialDeadlockException previousDeadlockException =
+          disallowedPriorLocks.get(acquiredLock);
+      if (previousDeadlockException != null) {
+        // Previously determined to be an unsafe lock acquisition.
+        // Create a new PotentialDeadlockException with the same causal chain
+        // (the example cycle) as that of the cached exception.
+        PotentialDeadlockException exception = new PotentialDeadlockException(
+            acquiredLock, this,
+            previousDeadlockException.getConflictingStackTrace());
+        policy.handlePotentialDeadlock(exception);
+        return;
+      }
+      // Otherwise, it's the first time seeing this lock relationship. Look for
+      // a path from the acquiredLock to this.
+      Set<LockGraphNode> seen = Sets.newIdentityHashSet();
+      ExampleStackTrace path = acquiredLock.findPathTo(this, seen);
+
+      if (path == null) {
+        // this can be safely acquired after the acquiredLock.
+        //
+        // Note that there is a race condition here which can result in missing
+        // a cyclic edge: it's possible for two threads to simultaneous find
+        // "safe" edges which together form a cycle. Preventing this race
+        // condition efficiently without _introducing_ deadlock is probably
+        // tricky. For now, just accept the race condition---missing a warning
+        // now and then is still better than having no deadlock detection.
+        allowedPriorLocks.put(
+            acquiredLock, new ExampleStackTrace(acquiredLock, this));
+      } else {
+        // Unsafe acquisition order detected. Create and cache a
+        // PotentialDeadlockException.
+        PotentialDeadlockException exception =
+            new PotentialDeadlockException(acquiredLock, this, path);
+        disallowedPriorLocks.put(acquiredLock, exception);
+        policy.handlePotentialDeadlock(exception);
+      }
+    }
+
+    /**
+     * Performs a depth-first traversal of the graph edges defined by each
+     * node's {@code allowedPriorLocks} to find a path between {@code this} and
+     * the specified {@code lock}.
+     *
+     * @return If a path was found, a chained {@link ExampleStackTrace}
+     *     illustrating the path to the {@code lock}, or {@code null} if no path
+     *     was found.
+     */
+    @Nullable
+    private ExampleStackTrace findPathTo(
+        LockGraphNode node, Set<LockGraphNode> seen) {
+      if (!seen.add(this)) {
+        return null;  // Already traversed this node.
+      }
+      ExampleStackTrace found = allowedPriorLocks.get(node);
+      if (found != null) {
+        return found;  // Found a path ending at the node!
+      }
+      // Recurse the edges.
+      for (Map.Entry<LockGraphNode, ExampleStackTrace> entry :
+               allowedPriorLocks.entrySet()) {
+        LockGraphNode preAcquiredLock = entry.getKey();
+        found = preAcquiredLock.findPathTo(node, seen);
+        if (found != null) {
+          // One of this node's allowedPriorLocks found a path. Prepend an
+          // ExampleStackTrace(preAcquiredLock, this) to the returned chain of
+          // ExampleStackTraces.
+          ExampleStackTrace path =
+              new ExampleStackTrace(preAcquiredLock, this);
+          path.setStackTrace(entry.getValue().getStackTrace());
+          path.initCause(found);
+          return path;
+        }
+      }
+      return null;
+    }
+  }
+
+  /**
+   * CycleDetectingLock implementations must call this method before attempting
+   * to acquire the lock.
+   */
+  private void aboutToAcquire(CycleDetectingLock lock) {
+    if (!lock.isAcquiredByCurrentThread()) {
+      ArrayList<LockGraphNode> acquiredLockList = acquiredLocks.get();
+      LockGraphNode node = lock.getLockGraphNode();
+      node.checkAcquiredLocks(policy, acquiredLockList);
+      acquiredLockList.add(node);
+    }
+  }
+
+  /**
+   * CycleDetectingLock implementations must call this method in a
+   * {@code finally} clause after any attempt to change the lock state,
+   * including both lock and unlock attempts. Failure to do so can result in
+   * corrupting the acquireLocks set.
+   */
+  private void lockStateChanged(CycleDetectingLock lock) {
+    if (!lock.isAcquiredByCurrentThread()) {
+      ArrayList<LockGraphNode> acquiredLockList = acquiredLocks.get();
+      LockGraphNode node = lock.getLockGraphNode();
+      // Iterate in reverse because locks are usually locked/unlocked in a
+      // LIFO order.
+      for (int i = acquiredLockList.size() - 1; i >=0; i--) {
+        if (acquiredLockList.get(i) == node) {
+          acquiredLockList.remove(i);
+          break;
+        }
+      }
+    }
+  }
+
+  final class CycleDetectingReentrantLock
+      extends ReentrantLock implements CycleDetectingLock {
+
+    private final LockGraphNode lockGraphNode;
+
+    private CycleDetectingReentrantLock(
+        LockGraphNode lockGraphNode, boolean fair) {
+      super(fair);
+      this.lockGraphNode = Preconditions.checkNotNull(lockGraphNode);
+    }
+
+    ///// CycleDetectingLock methods. /////
+
+    @Override
+    public LockGraphNode getLockGraphNode() {
+      return lockGraphNode;
+    }
+
+    @Override
+    public boolean isAcquiredByCurrentThread() {
+      return isHeldByCurrentThread();
+    }
+
+    ///// Overridden ReentrantLock methods. /////
+
+    @Override
+    public void lock() {
+      aboutToAcquire(this);
+      try {
+        super.lock();
+      } finally {
+        lockStateChanged(this);
+      }
+    }
+
+    @Override
+    public void lockInterruptibly() throws InterruptedException {
+      aboutToAcquire(this);
+      try {
+        super.lockInterruptibly();
+      } finally {
+        lockStateChanged(this);
+      }
+    }
+
+    @Override
+    public boolean tryLock() {
+      aboutToAcquire(this);
+      try {
+        return super.tryLock();
+      } finally {
+        lockStateChanged(this);
+      }
+    }
+
+    @Override
+    public boolean tryLock(long timeout, TimeUnit unit)
+        throws InterruptedException {
+      aboutToAcquire(this);
+      try {
+        return super.tryLock(timeout, unit);
+      } finally {
+        lockStateChanged(this);
+      }
+    }
+
+    @Override
+    public void unlock() {
+      try {
+        super.unlock();
+      } finally {
+        lockStateChanged(this);
+      }
+    }
+  }
+
+  final class CycleDetectingReentrantReadWriteLock
+      extends ReentrantReadWriteLock implements CycleDetectingLock {
+
+    // These ReadLock/WriteLock implementations shadow those in the
+    // ReentrantReadWriteLock superclass. They are simply wrappers around the
+    // internal Sync object, so this is safe since the shadowed locks are never
+    // exposed or used.
+    private final CycleDetectingReentrantReadLock readLock;
+    private final CycleDetectingReentrantWriteLock writeLock;
+
+    private final LockGraphNode lockGraphNode;
+
+    private CycleDetectingReentrantReadWriteLock(
+        LockGraphNode lockGraphNode, boolean fair) {
+      super(fair);
+      this.readLock = new CycleDetectingReentrantReadLock(this);
+      this.writeLock = new CycleDetectingReentrantWriteLock(this);
+      this.lockGraphNode = Preconditions.checkNotNull(lockGraphNode);
+    }
+
+    ///// Overridden ReentrantReadWriteLock methods. /////
+
+    @Override
+    public ReadLock readLock() {
+      return readLock;
+    }
+
+    @Override
+    public WriteLock writeLock() {
+      return writeLock;
+    }
+
+    ///// CycleDetectingLock methods. /////
+
+    @Override
+    public LockGraphNode getLockGraphNode() {
+      return lockGraphNode;
+    }
+
+    @Override
+    public boolean isAcquiredByCurrentThread() {
+      return isWriteLockedByCurrentThread() || getReadHoldCount() > 0;
+    }
+  }
+
+  private class CycleDetectingReentrantReadLock
+      extends ReentrantReadWriteLock.ReadLock {
+
+    final CycleDetectingReentrantReadWriteLock readWriteLock;
+
+    CycleDetectingReentrantReadLock(
+        CycleDetectingReentrantReadWriteLock readWriteLock) {
+      super(readWriteLock);
+      this.readWriteLock = readWriteLock;
+    }
+
+    @Override
+    public void lock() {
+      aboutToAcquire(readWriteLock);
+      try {
+        super.lock();
+      } finally {
+        lockStateChanged(readWriteLock);
+      }
+    }
+
+    @Override
+    public void lockInterruptibly() throws InterruptedException {
+      aboutToAcquire(readWriteLock);
+      try {
+        super.lockInterruptibly();
+      } finally {
+        lockStateChanged(readWriteLock);
+      }
+    }
+
+    @Override
+    public boolean tryLock() {
+      aboutToAcquire(readWriteLock);
+      try {
+        return super.tryLock();
+      } finally {
+        lockStateChanged(readWriteLock);
+      }
+    }
+
+    @Override
+    public boolean tryLock(long timeout, TimeUnit unit)
+        throws InterruptedException {
+      aboutToAcquire(readWriteLock);
+      try {
+        return super.tryLock(timeout, unit);
+      } finally {
+        lockStateChanged(readWriteLock);
+      }
+    }
+
+    @Override
+    public void unlock() {
+      try {
+        super.unlock();
+      } finally {
+        lockStateChanged(readWriteLock);
+      }
+    }
+  }
+
+  private class CycleDetectingReentrantWriteLock
+      extends ReentrantReadWriteLock.WriteLock {
+
+    final CycleDetectingReentrantReadWriteLock readWriteLock;
+
+    CycleDetectingReentrantWriteLock(
+        CycleDetectingReentrantReadWriteLock readWriteLock) {
+      super(readWriteLock);
+      this.readWriteLock = readWriteLock;
+    }
+
+    @Override
+    public void lock() {
+      aboutToAcquire(readWriteLock);
+      try {
+        super.lock();
+      } finally {
+        lockStateChanged(readWriteLock);
+      }
+    }
+
+    @Override
+    public void lockInterruptibly() throws InterruptedException {
+      aboutToAcquire(readWriteLock);
+      try {
+        super.lockInterruptibly();
+      } finally {
+        lockStateChanged(readWriteLock);
+      }
+    }
+
+    @Override
+    public boolean tryLock() {
+      aboutToAcquire(readWriteLock);
+      try {
+        return super.tryLock();
+      } finally {
+        lockStateChanged(readWriteLock);
+      }
+    }
+
+    @Override
+    public boolean tryLock(long timeout, TimeUnit unit)
+        throws InterruptedException {
+      aboutToAcquire(readWriteLock);
+      try {
+        return super.tryLock(timeout, unit);
+      } finally {
+        lockStateChanged(readWriteLock);
+      }
+    }
+
+    @Override
+    public void unlock() {
+      try {
+        super.unlock();
+      } finally {
+        lockStateChanged(readWriteLock);
+      }
+    }
+  }
+}
diff --git a/guava/src/com/google/common/util/concurrent/ExecutionList.java b/guava/src/com/google/common/util/concurrent/ExecutionList.java
index dc0addb..cb9fc82 100644
--- a/guava/src/com/google/common/util/concurrent/ExecutionList.java
+++ b/guava/src/com/google/common/util/concurrent/ExecutionList.java
@@ -37,7 +37,7 @@
  * <p>Exceptions thrown by a listener will be propagated up to the executor.
  * Any exception thrown during {@code Executor.execute} (e.g., a {@code
  * RejectedExecutionException} or an exception thrown by {@linkplain
- * MoreExecutors#sameThreadExecutor inline execution}) will be caught and
+ * MoreExecutors#directExecutor direct execution}) will be caught and
  * logged.
  *
  * @author Nishant Thakkar
@@ -66,15 +66,15 @@
    * executed immediately.
    *
    * <p>Note: For fast, lightweight listeners that would be safe to execute in
-   * any thread, consider {@link MoreExecutors#sameThreadExecutor}. For heavier
-   * listeners, {@code sameThreadExecutor()} carries some caveats: First, the
+   * any thread, consider {@link MoreExecutors#directExecutor}. For heavier
+   * listeners, {@code directExecutor()} carries some caveats: First, the
    * thread that the listener runs in depends on whether the {@code
    * ExecutionList} has been executed at the time it is added. In particular,
    * listeners may run in the thread that calls {@code add}. Second, the thread
    * that calls {@link #execute} may be an internal implementation thread, such
-   * as an RPC network thread, and {@code sameThreadExecutor()} listeners may
+   * as an RPC network thread, and {@code directExecutor()} listeners may
    * run in this thread. Finally, during the execution of a {@code
-   * sameThreadExecutor} listener, all other registered but unexecuted
+   * directExecutor} listener, all other registered but unexecuted
    * listeners are prevented from running, even if those listeners are to run
    * in other executors.
    */
diff --git a/guava/src/com/google/common/util/concurrent/Futures.java b/guava/src/com/google/common/util/concurrent/Futures.java
index 1cbc05d..650ff26 100644
--- a/guava/src/com/google/common/util/concurrent/Futures.java
+++ b/guava/src/com/google/common/util/concurrent/Futures.java
@@ -19,7 +19,7 @@
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
 import static com.google.common.util.concurrent.Uninterruptibles.getUninterruptibly;
 import static java.lang.Thread.currentThread;
 import static java.util.Arrays.asList;
@@ -42,14 +42,16 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.Callable;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Future;
+import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -86,7 +88,7 @@
    * @since 9.0 (source-compatible since 1.0)
    */
   public static <V, X extends Exception> CheckedFuture<V, X> makeChecked(
-      ListenableFuture<V> future, Function<Exception, X> mapper) {
+      ListenableFuture<V> future, Function<? super Exception, X> mapper) {
     return new MappingCheckedFuture<V, X>(checkNotNull(future), mapper);
   }
 
@@ -347,9 +349,9 @@
    * (whether the {@code Future} itself is slow or heavyweight to complete is
    * irrelevant), consider {@linkplain #withFallback(ListenableFuture,
    * FutureFallback, Executor) supplying an executor}. If you do not supply an
-   * executor, {@code withFallback} will use {@link
-   * MoreExecutors#sameThreadExecutor sameThreadExecutor}, which carries some
-   * caveats for heavier operations. For example, the call to {@code
+   * executor, {@code withFallback} will use a
+   * {@linkplain MoreExecutors#directExecutor direct executor}, which carries
+   * some caveats for heavier operations. For example, the call to {@code
    * fallback.create} may run on an unpredictable or undesirable thread:
    *
    * <ul>
@@ -362,9 +364,9 @@
    * </ul>
    *
    * <p>Also note that, regardless of which thread executes the {@code
-   * sameThreadExecutor} {@code fallback.create}, all other registered but
-   * unexecuted listeners are prevented from running during its execution, even
-   * if those listeners are to run in other executors.
+   * fallback.create}, all other registered but unexecuted listeners are
+   * prevented from running during its execution, even if those listeners are
+   * to run in other executors.
    *
    * @param input the primary input {@code Future}
    * @param fallback the {@link FutureFallback} implementation to be called if
@@ -374,7 +376,7 @@
   public static <V> ListenableFuture<V> withFallback(
       ListenableFuture<? extends V> input,
       FutureFallback<? extends V> fallback) {
-    return withFallback(input, fallback, sameThreadExecutor());
+    return withFallback(input, fallback, directExecutor());
   }
 
   /**
@@ -401,7 +403,7 @@
    *           // exception happens.
    *           return immediateFuture(0);
    *         }
-   *       }, sameThreadExecutor());}</pre>
+   *       }, directExecutor());}</pre>
    *
    * <p>The fallback can also choose to propagate the original exception when
    * desired:
@@ -419,13 +421,13 @@
    *           }
    *           return immediateFailedFuture(t);
    *         }
-   *       }, sameThreadExecutor());}</pre>
+   *       }, directExecutor());}</pre>
    *
    * <p>When the execution of {@code fallback.create} is fast and lightweight
    * (though the {@code Future} it returns need not meet these criteria),
    * consider {@linkplain #withFallback(ListenableFuture, FutureFallback)
    * omitting the executor} or explicitly specifying {@code
-   * sameThreadExecutor}. However, be aware of the caveats documented in the
+   * directExecutor}. However, be aware of the caveats documented in the
    * link above.
    *
    * @param input the primary input {@code Future}
@@ -485,7 +487,7 @@
                   setException(t);
                 }
               }
-            }, sameThreadExecutor());
+            }, directExecutor());
           } catch (Throwable e) {
             setException(e);
           }
@@ -525,9 +527,9 @@
    * (whether the {@code Future} itself is slow or heavyweight to complete is
    * irrelevant), consider {@linkplain #transform(ListenableFuture,
    * AsyncFunction, Executor) supplying an executor}. If you do not supply an
-   * executor, {@code transform} will use {@link
-   * MoreExecutors#sameThreadExecutor sameThreadExecutor}, which carries some
-   * caveats for heavier operations. For example, the call to {@code
+   * executor, {@code transform} will use a
+   * {@linkplain MoreExecutors#directExecutor direct executor}, which carries
+   * some caveats for heavier operations. For example, the call to {@code
    * function.apply} may run on an unpredictable or undesirable thread:
    *
    * <ul>
@@ -540,9 +542,9 @@
    * </ul>
    *
    * <p>Also note that, regardless of which thread executes the {@code
-   * sameThreadExecutor} {@code function.apply}, all other registered but
-   * unexecuted listeners are prevented from running during its execution, even
-   * if those listeners are to run in other executors.
+   * function.apply}, all other registered but unexecuted listeners are
+   * prevented from running during its execution, even if those listeners are
+   * to run in other executors.
    *
    * <p>The returned {@code Future} attempts to keep its cancellation state in
    * sync with that of the input future and that of the future returned by the
@@ -560,7 +562,10 @@
    */
   public static <I, O> ListenableFuture<O> transform(ListenableFuture<I> input,
       AsyncFunction<? super I, ? extends O> function) {
-    return transform(input, function, MoreExecutors.sameThreadExecutor());
+    ChainingListenableFuture<I, O> output =
+        new ChainingListenableFuture<I, O>(function, input);
+    input.addListener(output, directExecutor());
+    return output;
   }
 
   /**
@@ -591,7 +596,7 @@
    * <p>When the execution of {@code function.apply} is fast and lightweight
    * (though the {@code Future} it returns need not meet these criteria),
    * consider {@linkplain #transform(ListenableFuture, AsyncFunction) omitting
-   * the executor} or explicitly specifying {@code sameThreadExecutor}.
+   * the executor} or explicitly specifying {@code directExecutor}.
    * However, be aware of the caveats documented in the link above.
    *
    * @param input The future to transform
@@ -605,13 +610,44 @@
   public static <I, O> ListenableFuture<O> transform(ListenableFuture<I> input,
       AsyncFunction<? super I, ? extends O> function,
       Executor executor) {
+    checkNotNull(executor);
     ChainingListenableFuture<I, O> output =
         new ChainingListenableFuture<I, O>(function, input);
-    input.addListener(output, executor);
+    input.addListener(rejectionPropagatingRunnable(output, output, executor), directExecutor());
     return output;
   }
 
   /**
+   * Returns a Runnable that will invoke the delegate Runnable on the delegate executor, but if the
+   * task is rejected, it will propagate that rejection to the output future.
+   */
+  private static Runnable rejectionPropagatingRunnable(
+      final AbstractFuture<?> outputFuture,
+      final Runnable delegateTask,
+      final Executor delegateExecutor) {
+    return new Runnable() {
+      @Override public void run() {
+        final AtomicBoolean thrownFromDelegate = new AtomicBoolean(true);
+        try {
+          delegateExecutor.execute(new Runnable() {
+            @Override public void run() {
+              thrownFromDelegate.set(false);
+              delegateTask.run();
+            }
+          });
+        } catch (RejectedExecutionException e) {
+          if (thrownFromDelegate.get()) {
+            // wrap exception?
+            outputFuture.setException(e);
+          }
+          // otherwise it must have been thrown from a transitive call and the delegate runnable
+          // should have handled it.
+        }
+      }
+    };
+  }
+
+  /**
    * Returns a new {@code ListenableFuture} whose result is the product of
    * applying the given {@code Function} to the result of the given {@code
    * Future}. Example:
@@ -629,10 +665,10 @@
    *
    * <p>Note: If the transformation is slow or heavyweight, consider {@linkplain
    * #transform(ListenableFuture, Function, Executor) supplying an executor}.
-   * If you do not supply an executor, {@code transform} will use {@link
-   * MoreExecutors#sameThreadExecutor sameThreadExecutor}, which carries some
-   * caveats for heavier operations.  For example, the call to {@code
-   * function.apply} may run on an unpredictable or undesirable thread:
+   * If you do not supply an executor, {@code transform} will use an inline
+   * executor, which carries some caveats for heavier operations.  For example,
+   * the call to {@code function.apply} may run on an unpredictable or
+   * undesirable thread:
    *
    * <ul>
    * <li>If the input {@code Future} is done at the time {@code transform} is
@@ -644,9 +680,9 @@
    * </ul>
    *
    * <p>Also note that, regardless of which thread executes the {@code
-   * sameThreadExecutor} {@code function.apply}, all other registered but
-   * unexecuted listeners are prevented from running during its execution, even
-   * if those listeners are to run in other executors.
+   * function.apply}, all other registered but unexecuted listeners are
+   * prevented from running during its execution, even if those listeners are
+   * to run in other executors.
    *
    * <p>The returned {@code Future} attempts to keep its cancellation state in
    * sync with that of the input future. That is, if the returned {@code Future}
@@ -666,7 +702,11 @@
    */
   public static <I, O> ListenableFuture<O> transform(ListenableFuture<I> input,
       final Function<? super I, ? extends O> function) {
-    return transform(input, function, MoreExecutors.sameThreadExecutor());
+    checkNotNull(function);
+    ChainingListenableFuture<I, O> output =
+        new ChainingListenableFuture<I, O>(asAsyncFunction(function), input);
+    input.addListener(output, directExecutor());
+    return output;
   }
 
   /**
@@ -696,7 +736,7 @@
    *
    * <p>When the transformation is fast and lightweight, consider {@linkplain
    * #transform(ListenableFuture, Function) omitting the executor} or
-   * explicitly specifying {@code sameThreadExecutor}. However, be aware of the
+   * explicitly specifying {@code directExecutor}. However, be aware of the
    * caveats documented in the link above.
    *
    * @param input The future to transform
@@ -709,14 +749,18 @@
   public static <I, O> ListenableFuture<O> transform(ListenableFuture<I> input,
       final Function<? super I, ? extends O> function, Executor executor) {
     checkNotNull(function);
-    AsyncFunction<I, O> wrapperFunction
-        = new AsyncFunction<I, O>() {
-            @Override public ListenableFuture<O> apply(I input) {
-              O output = function.apply(input);
-              return immediateFuture(output);
-            }
-        };
-    return transform(input, wrapperFunction, executor);
+    return transform(input, asAsyncFunction(function), executor);
+  }
+
+  /** Wraps the given function as an AsyncFunction. */
+  private static <I, O> AsyncFunction<I, O> asAsyncFunction(
+      final Function<? super I, ? extends O> function) {
+    return new AsyncFunction<I, O>() {
+      @Override public ListenableFuture<O> apply(I input) {
+        O output = function.apply(input);
+        return immediateFuture(output);
+      }
+    };
   }
 
   /**
@@ -810,7 +854,6 @@
     private AsyncFunction<? super I, ? extends O> function;
     private ListenableFuture<? extends I> inputFuture;
     private volatile ListenableFuture<? extends O> outputFuture;
-    private final CountDownLatch outputCreated = new CountDownLatch(1);
 
     private ChainingListenableFuture(
         AsyncFunction<? super I, ? extends O> function,
@@ -887,7 +930,7 @@
                 ChainingListenableFuture.this.outputFuture = null;
               }
             }
-          }, MoreExecutors.sameThreadExecutor());
+          }, directExecutor());
       } catch (UndeclaredThrowableException e) {
         // Set the cause of the exception as this future's exception
         setException(e.getCause());
@@ -899,8 +942,6 @@
         // Don't pin inputs beyond completion
         function = null;
         inputFuture = null;
-        // Allow our get routines to examine outputFuture now.
-        outputCreated.countDown();
       }
     }
   }
@@ -945,7 +986,7 @@
   /**
    * Creates a new {@code ListenableFuture} whose value is a list containing the
    * values of all its input futures, if all succeed. If any input fails, the
-   * returned future fails.
+   * returned future fails immediately.
    *
    * <p>The list of results is in the same order as the input list.
    *
@@ -961,14 +1002,13 @@
   @Beta
   public static <V> ListenableFuture<List<V>> allAsList(
       ListenableFuture<? extends V>... futures) {
-    return listFuture(ImmutableList.copyOf(futures), true,
-        MoreExecutors.sameThreadExecutor());
+    return listFuture(ImmutableList.copyOf(futures), true, directExecutor());
   }
 
   /**
    * Creates a new {@code ListenableFuture} whose value is a list containing the
    * values of all its input futures, if all succeed. If any input fails, the
-   * returned future fails.
+   * returned future fails immediately.
    *
    * <p>The list of results is in the same order as the input list.
    *
@@ -984,8 +1024,58 @@
   @Beta
   public static <V> ListenableFuture<List<V>> allAsList(
       Iterable<? extends ListenableFuture<? extends V>> futures) {
-    return listFuture(ImmutableList.copyOf(futures), true,
-        MoreExecutors.sameThreadExecutor());
+    return listFuture(ImmutableList.copyOf(futures), true, directExecutor());
+  }
+
+  private static final class WrappedCombiner<T> implements Callable<T> {
+    final Callable<T> delegate;
+    CombinerFuture<T> outputFuture;
+
+    WrappedCombiner(Callable<T> delegate) {
+      this.delegate = checkNotNull(delegate);
+    }
+
+    @Override public T call() throws Exception {
+      try {
+        return delegate.call();
+      } catch (ExecutionException e) {
+        outputFuture.setException(e.getCause());
+      } catch (CancellationException e) {
+        outputFuture.cancel(false);
+      }
+      // at this point the return value doesn't matter since we already called setException or
+      // cancel so the future is done.
+      return null;
+    }
+  }
+
+  private static final class CombinerFuture<V> extends ListenableFutureTask<V> {
+    ImmutableList<ListenableFuture<?>> futures;
+
+    CombinerFuture(Callable<V> callable, ImmutableList<ListenableFuture<?>> futures) {
+      super(callable);
+      this.futures = futures;
+    }
+
+    @Override public boolean cancel(boolean mayInterruptIfRunning) {
+      ImmutableList<ListenableFuture<?>> futures = this.futures;
+      if (super.cancel(mayInterruptIfRunning)) {
+        for (ListenableFuture<?> future : futures) {
+          future.cancel(mayInterruptIfRunning);
+        }
+        return true;
+      }
+      return false;
+    }
+
+    @Override protected void done() {
+      super.done();
+      futures = null;
+    }
+
+    @Override protected void setException(Throwable t) {
+      super.setException(t);
+    }
   }
 
   /**
@@ -1022,7 +1112,7 @@
             setException(t);
           }
         }
-      }, sameThreadExecutor());
+      }, directExecutor());
     }
   }
 
@@ -1044,8 +1134,7 @@
   @Beta
   public static <V> ListenableFuture<List<V>> successfulAsList(
       ListenableFuture<? extends V>... futures) {
-    return listFuture(ImmutableList.copyOf(futures), false,
-        MoreExecutors.sameThreadExecutor());
+    return listFuture(ImmutableList.copyOf(futures), false, directExecutor());
   }
 
   /**
@@ -1066,8 +1155,7 @@
   @Beta
   public static <V> ListenableFuture<List<V>> successfulAsList(
       Iterable<? extends ListenableFuture<? extends V>> futures) {
-    return listFuture(ImmutableList.copyOf(futures), false,
-        MoreExecutors.sameThreadExecutor());
+    return listFuture(ImmutableList.copyOf(futures), false, directExecutor());
   }
 
   /**
@@ -1095,13 +1183,13 @@
     // atomically and therefore that each returned future is guaranteed to be in completion order.
     // N.B. there are some cases where the use of this executor could have possibly surprising
     // effects when input futures finish at approximately the same time _and_ the output futures
-    // have sameThreadExecutor listeners. In this situation, the listeners may end up running on a
+    // have directExecutor listeners. In this situation, the listeners may end up running on a
     // different thread than if they were attached to the corresponding input future.  We believe
     // this to be a negligible cost since:
-    // 1. Using the sameThreadExecutor implies that your callback is safe to run on any thread.
+    // 1. Using the directExecutor implies that your callback is safe to run on any thread.
     // 2. This would likely only be noticeable if you were doing something expensive or blocking on
-    //    a sameThreadExecutor listener on one of the output futures which is an antipattern anyway.
-    SerializingExecutor executor = new SerializingExecutor(MoreExecutors.sameThreadExecutor());
+    //    a directExecutor listener on one of the output futures which is an antipattern anyway.
+    SerializingExecutor executor = new SerializingExecutor(directExecutor());
     for (final ListenableFuture<? extends T> future : futures) {
       AsyncSettableFuture<T> delegate = AsyncSettableFuture.create();
       // Must make sure to add the delegate to the queue first in case the future is already done
@@ -1140,7 +1228,7 @@
    * <p>Note: If the callback is slow or heavyweight, consider {@linkplain
    * #addCallback(ListenableFuture, FutureCallback, Executor) supplying an
    * executor}. If you do not supply an executor, {@code addCallback} will use
-   * {@link MoreExecutors#sameThreadExecutor sameThreadExecutor}, which carries
+   * a {@linkplain MoreExecutors#directExecutor direct executor}, which carries
    * some caveats for heavier operations. For example, the callback may run on
    * an unpredictable or undesirable thread:
    *
@@ -1153,10 +1241,10 @@
    * network thread.
    * </ul>
    *
-   * <p>Also note that, regardless of which thread executes the {@code
-   * sameThreadExecutor} callback, all other registered but unexecuted listeners
-   * are prevented from running during its execution, even if those listeners
-   * are to run in other executors.
+   * <p>Also note that, regardless of which thread executes the callback, all
+   * other registered but unexecuted listeners are prevented from running
+   * during its execution, even if those listeners are to run in other
+   * executors.
    *
    * <p>For a more general interface to attach a completion listener to a
    * {@code Future}, see {@link ListenableFuture#addListener addListener}.
@@ -1167,7 +1255,7 @@
    */
   public static <V> void addCallback(ListenableFuture<V> future,
       FutureCallback<? super V> callback) {
-    addCallback(future, callback, MoreExecutors.sameThreadExecutor());
+    addCallback(future, callback, directExecutor());
   }
 
   /**
@@ -1195,7 +1283,7 @@
    *
    * <p>When the callback is fast and lightweight, consider {@linkplain
    * #addCallback(ListenableFuture, FutureCallback) omitting the executor} or
-   * explicitly specifying {@code sameThreadExecutor}. However, be aware of the
+   * explicitly specifying {@code directExecutor}. However, be aware of the
    * caveats documented in the link above.
    *
    * <p>For a more general interface to attach a completion listener to a
@@ -1566,7 +1654,7 @@
           // The combiner may also hold state, so free that as well
           CombinedFuture.this.combiner = null;
         }
-      }, MoreExecutors.sameThreadExecutor());
+      }, directExecutor());
 
       // Now begin the "real" initialization.
 
@@ -1680,7 +1768,6 @@
         }
       }
     }
-
   }
 
   /** Used for {@link #allAsList} and {@link #successfulAsList}. */
@@ -1708,10 +1795,10 @@
   private static class MappingCheckedFuture<V, X extends Exception> extends
       AbstractCheckedFuture<V, X> {
 
-    final Function<Exception, X> mapper;
+    final Function<? super Exception, X> mapper;
 
     MappingCheckedFuture(ListenableFuture<V> delegate,
-        Function<Exception, X> mapper) {
+        Function<? super Exception, X> mapper) {
       super(delegate);
 
       this.mapper = checkNotNull(mapper);
diff --git a/guava/src/com/google/common/util/concurrent/ListenableFuture.java b/guava/src/com/google/common/util/concurrent/ListenableFuture.java
index 9fc6807..7d169ec 100644
--- a/guava/src/com/google/common/util/concurrent/ListenableFuture.java
+++ b/guava/src/com/google/common/util/concurrent/ListenableFuture.java
@@ -97,12 +97,12 @@
    * <p>Exceptions thrown by a listener will be propagated up to the executor.
    * Any exception thrown during {@code Executor.execute} (e.g., a {@code
    * RejectedExecutionException} or an exception thrown by {@linkplain
-   * MoreExecutors#sameThreadExecutor inline execution}) will be caught and
+   * MoreExecutors#directExecutor direct execution}) will be caught and
    * logged.
    *
    * <p>Note: For fast, lightweight listeners that would be safe to execute in
-   * any thread, consider {@link MoreExecutors#sameThreadExecutor}. For heavier
-   * listeners, {@code sameThreadExecutor()} carries some caveats.  For
+   * any thread, consider {@link MoreExecutors#directExecutor}. For heavier
+   * listeners, {@code directExecutor()} carries some caveats.  For
    * example, the listener may run on an unpredictable or undesirable thread:
    *
    * <ul>
@@ -115,7 +115,7 @@
    * </ul>
    *
    * <p>Also note that, regardless of which thread executes the
-   * {@code sameThreadExecutor()} listener, all other registered but unexecuted
+   * {@code directExecutor()} listener, all other registered but unexecuted
    * listeners are prevented from running during its execution, even if those
    * listeners are to run in other executors.
    *
diff --git a/guava/src/com/google/common/util/concurrent/ListenerCallQueue.java b/guava/src/com/google/common/util/concurrent/ListenerCallQueue.java
index 3cad41c..00c963c 100644
--- a/guava/src/com/google/common/util/concurrent/ListenerCallQueue.java
+++ b/guava/src/com/google/common/util/concurrent/ListenerCallQueue.java
@@ -19,7 +19,7 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
+import com.google.common.collect.Queues;
 
 import java.util.Queue;
 import java.util.concurrent.Executor;
@@ -59,7 +59,7 @@
   private final L listener;
   private final Executor executor;
 
-  @GuardedBy("this") private final Queue<Callback<L>> waitQueue = Lists.newLinkedList();
+  @GuardedBy("this") private final Queue<Callback<L>> waitQueue = Queues.newArrayDeque();
   @GuardedBy("this") private boolean isThreadScheduled;
 
   ListenerCallQueue(L listener, Executor executor) {
diff --git a/guava/src/com/google/common/util/concurrent/MoreExecutors.java b/guava/src/com/google/common/util/concurrent/MoreExecutors.java
index 5edbd68..e0b1045 100644
--- a/guava/src/com/google/common/util/concurrent/MoreExecutors.java
+++ b/guava/src/com/google/common/util/concurrent/MoreExecutors.java
@@ -263,13 +263,15 @@
    *
    * @since 10.0 (<a href="http://code.google.com/p/guava-libraries/wiki/Compatibility"
    *        >mostly source-compatible</a> since 3.0)
+   * @deprecated Use {@link #directExecutor()} if you only require an {@link Executor} and
+   *     {@link #newDirectExecutorService()} if you need a {@link ListeningExecutorService}.
    */
-  public static ListeningExecutorService sameThreadExecutor() {
-    return new SameThreadExecutorService();
+  @Deprecated public static ListeningExecutorService sameThreadExecutor() {
+    return new DirectExecutorService();
   }
 
   // See sameThreadExecutor javadoc for behavioral notes.
-  private static class SameThreadExecutorService
+  private static class DirectExecutorService
       extends AbstractListeningExecutorService {
     /**
      * Lock used whenever accessing the state variables
@@ -393,6 +395,70 @@
   }
 
   /**
+   * Creates an executor service that runs each task in the thread
+   * that invokes {@code execute/submit}, as in {@link CallerRunsPolicy}  This
+   * applies both to individually submitted tasks and to collections of tasks
+   * submitted via {@code invokeAll} or {@code invokeAny}.  In the latter case,
+   * tasks will run serially on the calling thread.  Tasks are run to
+   * completion before a {@code Future} is returned to the caller (unless the
+   * executor has been shutdown).
+   *
+   * <p>Although all tasks are immediately executed in the thread that
+   * submitted the task, this {@code ExecutorService} imposes a small
+   * locking overhead on each task submission in order to implement shutdown
+   * and termination behavior.
+   *
+   * <p>The implementation deviates from the {@code ExecutorService}
+   * specification with regards to the {@code shutdownNow} method.  First,
+   * "best-effort" with regards to canceling running tasks is implemented
+   * as "no-effort".  No interrupts or other attempts are made to stop
+   * threads executing tasks.  Second, the returned list will always be empty,
+   * as any submitted task is considered to have started execution.
+   * This applies also to tasks given to {@code invokeAll} or {@code invokeAny}
+   * which are pending serial execution, even the subset of the tasks that
+   * have not yet started execution.  It is unclear from the
+   * {@code ExecutorService} specification if these should be included, and
+   * it's much easier to implement the interpretation that they not be.
+   * Finally, a call to {@code shutdown} or {@code shutdownNow} may result
+   * in concurrent calls to {@code invokeAll/invokeAny} throwing
+   * RejectedExecutionException, although a subset of the tasks may already
+   * have been executed.
+   *
+   * @since 18.0 (present as MoreExecutors.sameThreadExecutor() since 10.0)
+   */
+  public static ListeningExecutorService newDirectExecutorService() {
+    return new DirectExecutorService();
+  }
+
+  /**
+   * Returns an {@link Executor} that runs each task in the thread that invokes
+   * {@link Executor#execute execute}, as in {@link CallerRunsPolicy}.
+   *
+   * <p>This instance is equivalent to: <pre>   {@code
+   *   final class DirectExecutor implements Executor {
+   *     public void execute(Runnable r) {
+   *       r.run();
+   *     }
+   *   }}</pre>
+   *
+   * <p>This should be preferred to {@link #newDirectExecutorService()} because the implementing the
+   * {@link ExecutorService} subinterface necessitates significant performance overhead.
+   *
+   * @since 18.0
+   */
+  public static Executor directExecutor() {
+    return DirectExecutor.INSTANCE;
+  }
+
+  /** See {@link #directExecutor} for behavioral notes. */
+  private enum DirectExecutor implements Executor {
+    INSTANCE;
+    @Override public void execute(Runnable command) {
+      command.run();
+    }
+  }
+
+  /**
    * Creates an {@link ExecutorService} whose {@code submit} and {@code
    * invokeAll} methods submit {@link ListenableFutureTask} instances to the
    * given delegate executor. Those methods, as well as {@code execute} and
@@ -684,7 +750,7 @@
       @Override public void run() {
         queue.add(future);
       }
-    }, MoreExecutors.sameThreadExecutor());
+    }, directExecutor());
     return future;
   }
 
@@ -859,12 +925,13 @@
    * </ol>
    *
    * <p>If, at any step of the process, the given executor is terminated or the calling thread is
-   * interrupted, the method may return without executing any remaining steps.
+   * interrupted, the method calls {@link ExecutorService#shutdownNow()}, cancelling
+   * pending tasks and interrupting running tasks.
    *
    * @param service the {@code ExecutorService} to shut down
    * @param timeout the maximum time to wait for the {@code ExecutorService} to terminate
    * @param unit the time unit of the timeout argument
-   * @return {@code true) if the pool was terminated successfully, {@code false} if the
+   * @return {@code true} if the pool was terminated successfully, {@code false} if the
    *     {@code ExecutorService} could not terminate <b>or</b> the thread running this method
    *     is interrupted while waiting for the {@code ExecutorService} to terminate
    * @since 17.0
diff --git a/guava/src/com/google/common/util/concurrent/RateLimiter.java b/guava/src/com/google/common/util/concurrent/RateLimiter.java
index 73cc95d..74290b0 100644
--- a/guava/src/com/google/common/util/concurrent/RateLimiter.java
+++ b/guava/src/com/google/common/util/concurrent/RateLimiter.java
@@ -16,10 +16,17 @@
 
 package com.google.common.util.concurrent;
 
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.lang.Math.max;
+import static java.util.concurrent.TimeUnit.MICROSECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
 import com.google.common.annotations.Beta;
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Ticker;
+import com.google.common.base.Stopwatch;
+import com.google.common.util.concurrent.SmoothRateLimiter.SmoothBursty;
+import com.google.common.util.concurrent.SmoothRateLimiter.SmoothWarmingUp;
 
 import java.util.concurrent.TimeUnit;
 
@@ -87,127 +94,6 @@
 @ThreadSafe
 @Beta
 public abstract class RateLimiter {
-  /*
-   * How is the RateLimiter designed, and why?
-   *
-   * The primary feature of a RateLimiter is its "stable rate", the maximum rate that
-   * is should allow at normal conditions. This is enforced by "throttling" incoming
-   * requests as needed, i.e. compute, for an incoming request, the appropriate throttle time,
-   * and make the calling thread wait as much.
-   *
-   * The simplest way to maintain a rate of QPS is to keep the timestamp of the last
-   * granted request, and ensure that (1/QPS) seconds have elapsed since then. For example,
-   * for a rate of QPS=5 (5 tokens per second), if we ensure that a request isn't granted
-   * earlier than 200ms after the last one, then we achieve the intended rate.
-   * If a request comes and the last request was granted only 100ms ago, then we wait for
-   * another 100ms. At this rate, serving 15 fresh permits (i.e. for an acquire(15) request)
-   * naturally takes 3 seconds.
-   *
-   * It is important to realize that such a RateLimiter has a very superficial memory
-   * of the past: it only remembers the last request. What if the RateLimiter was unused for
-   * a long period of time, then a request arrived and was immediately granted?
-   * This RateLimiter would immediately forget about that past underutilization. This may
-   * result in either underutilization or overflow, depending on the real world consequences
-   * of not using the expected rate.
-   *
-   * Past underutilization could mean that excess resources are available. Then, the RateLimiter
-   * should speed up for a while, to take advantage of these resources. This is important
-   * when the rate is applied to networking (limiting bandwidth), where past underutilization
-   * typically translates to "almost empty buffers", which can be filled immediately.
-   *
-   * On the other hand, past underutilization could mean that "the server responsible for
-   * handling the request has become less ready for future requests", i.e. its caches become
-   * stale, and requests become more likely to trigger expensive operations (a more extreme
-   * case of this example is when a server has just booted, and it is mostly busy with getting
-   * itself up to speed).
-   *
-   * To deal with such scenarios, we add an extra dimension, that of "past underutilization",
-   * modeled by "storedPermits" variable. This variable is zero when there is no
-   * underutilization, and it can grow up to maxStoredPermits, for sufficiently large
-   * underutilization. So, the requested permits, by an invocation acquire(permits),
-   * are served from:
-   * - stored permits (if available)
-   * - fresh permits (for any remaining permits)
-   *
-   * How this works is best explained with an example:
-   *
-   * For a RateLimiter that produces 1 token per second, every second
-   * that goes by with the RateLimiter being unused, we increase storedPermits by 1.
-   * Say we leave the RateLimiter unused for 10 seconds (i.e., we expected a request at time
-   * X, but we are at time X + 10 seconds before a request actually arrives; this is
-   * also related to the point made in the last paragraph), thus storedPermits
-   * becomes 10.0 (assuming maxStoredPermits >= 10.0). At that point, a request of acquire(3)
-   * arrives. We serve this request out of storedPermits, and reduce that to 7.0 (how this is
-   * translated to throttling time is discussed later). Immediately after, assume that an
-   * acquire(10) request arriving. We serve the request partly from storedPermits,
-   * using all the remaining 7.0 permits, and the remaining 3.0, we serve them by fresh permits
-   * produced by the rate limiter.
-   *
-   * We already know how much time it takes to serve 3 fresh permits: if the rate is
-   * "1 token per second", then this will take 3 seconds. But what does it mean to serve 7
-   * stored permits? As explained above, there is no unique answer. If we are primarily
-   * interested to deal with underutilization, then we want stored permits to be given out
-   * /faster/ than fresh ones, because underutilization = free resources for the taking.
-   * If we are primarily interested to deal with overflow, then stored permits could
-   * be given out /slower/ than fresh ones. Thus, we require a (different in each case)
-   * function that translates storedPermits to throtting time.
-   *
-   * This role is played by storedPermitsToWaitTime(double storedPermits, double permitsToTake).
-   * The underlying model is a continuous function mapping storedPermits
-   * (from 0.0 to maxStoredPermits) onto the 1/rate (i.e. intervals) that is effective at the given
-   * storedPermits. "storedPermits" essentially measure unused time; we spend unused time
-   * buying/storing permits. Rate is "permits / time", thus "1 / rate = time / permits".
-   * Thus, "1/rate" (time / permits) times "permits" gives time, i.e., integrals on this
-   * function (which is what storedPermitsToWaitTime() computes) correspond to minimum intervals
-   * between subsequent requests, for the specified number of requested permits.
-   *
-   * Here is an example of storedPermitsToWaitTime:
-   * If storedPermits == 10.0, and we want 3 permits, we take them from storedPermits,
-   * reducing them to 7.0, and compute the throttling for these as a call to
-   * storedPermitsToWaitTime(storedPermits = 10.0, permitsToTake = 3.0), which will
-   * evaluate the integral of the function from 7.0 to 10.0.
-   *
-   * Using integrals guarantees that the effect of a single acquire(3) is equivalent
-   * to { acquire(1); acquire(1); acquire(1); }, or { acquire(2); acquire(1); }, etc,
-   * since the integral of the function in [7.0, 10.0] is equivalent to the sum of the
-   * integrals of [7.0, 8.0], [8.0, 9.0], [9.0, 10.0] (and so on), no matter
-   * what the function is. This guarantees that we handle correctly requests of varying weight
-   * (permits), /no matter/ what the actual function is - so we can tweak the latter freely.
-   * (The only requirement, obviously, is that we can compute its integrals).
-   *
-   * Note well that if, for this function, we chose a horizontal line, at height of exactly
-   * (1/QPS), then the effect of the function is non-existent: we serve storedPermits at
-   * exactly the same cost as fresh ones (1/QPS is the cost for each). We use this trick later.
-   *
-   * If we pick a function that goes /below/ that horizontal line, it means that we reduce
-   * the area of the function, thus time. Thus, the RateLimiter becomes /faster/ after a
-   * period of underutilization. If, on the other hand, we pick a function that
-   * goes /above/ that horizontal line, then it means that the area (time) is increased,
-   * thus storedPermits are more costly than fresh permits, thus the RateLimiter becomes
-   * /slower/ after a period of underutilization.
-   *
-   * Last, but not least: consider a RateLimiter with rate of 1 permit per second, currently
-   * completely unused, and an expensive acquire(100) request comes. It would be nonsensical
-   * to just wait for 100 seconds, and /then/ start the actual task. Why wait without doing
-   * anything? A much better approach is to /allow/ the request right away (as if it was an
-   * acquire(1) request instead), and postpone /subsequent/ requests as needed. In this version,
-   * we allow starting the task immediately, and postpone by 100 seconds future requests,
-   * thus we allow for work to get done in the meantime instead of waiting idly.
-   *
-   * This has important consequences: it means that the RateLimiter doesn't remember the time
-   * of the _last_ request, but it remembers the (expected) time of the _next_ request. This
-   * also enables us to tell immediately (see tryAcquire(timeout)) whether a particular
-   * timeout is enough to get us to the point of the next scheduling time, since we always
-   * maintain that. And what we mean by "an unused RateLimiter" is also defined by that
-   * notion: when we observe that the "expected arrival time of the next request" is actually
-   * in the past, then the difference (now - past) is the amount of time that the RateLimiter
-   * was formally unused, and it is that amount of time which we translate to storedPermits.
-   * (We increase storedPermits with the amount of permits that would have been produced
-   * in that idle time). So, if rate == 1 permit per second, and arrivals come exactly
-   * one second after the previous, then storedPermits is _never_ increased -- we would only
-   * increase it for arrivals _later_ than the expected one second.
-   */
-
   /**
    * Creates a {@code RateLimiter} with the specified stable throughput, given as
    * "permits per second" (commonly referred to as <i>QPS</i>, queries per second).
@@ -221,30 +107,35 @@
    * requests being smoothly limited at the stable rate of {@code permitsPerSecond}.
    *
    * @param permitsPerSecond the rate of the returned {@code RateLimiter}, measured in
-   *        how many permits become available per second. Must be positive
+   *        how many permits become available per second
+   * @throws IllegalArgumentException if {@code permitsPerSecond} is negative or zero
    */
   // TODO(user): "This is equivalent to
   //                 {@code createWithCapacity(permitsPerSecond, 1, TimeUnit.SECONDS)}".
   public static RateLimiter create(double permitsPerSecond) {
     /*
-       * The default RateLimiter configuration can save the unused permits of up to one second.
-       * This is to avoid unnecessary stalls in situations like this: A RateLimiter of 1qps,
-       * and 4 threads, all calling acquire() at these moments:
-       *
-       * T0 at 0 seconds
-       * T1 at 1.05 seconds
-       * T2 at 2 seconds
-       * T3 at 3 seconds
-       *
-       * Due to the slight delay of T1, T2 would have to sleep till 2.05 seconds,
-       * and T3 would also have to sleep till 3.05 seconds.
+     * The default RateLimiter configuration can save the unused permits of up to one second.
+     * This is to avoid unnecessary stalls in situations like this: A RateLimiter of 1qps,
+     * and 4 threads, all calling acquire() at these moments:
+     *
+     * T0 at 0 seconds
+     * T1 at 1.05 seconds
+     * T2 at 2 seconds
+     * T3 at 3 seconds
+     *
+     * Due to the slight delay of T1, T2 would have to sleep till 2.05 seconds,
+     * and T3 would also have to sleep till 3.05 seconds.
      */
-    return create(SleepingTicker.SYSTEM_TICKER, permitsPerSecond);
+    return create(SleepingStopwatch.createFromSystemTimer(), permitsPerSecond);
   }
 
+  /*
+   * TODO(cpovirk): make SleepingStopwatch the last parameter throughout the class so that the
+   * overloads follow the usual convention: Foo(int), Foo(int, SleepingStopwatch)
+   */
   @VisibleForTesting
-  static RateLimiter create(SleepingTicker ticker, double permitsPerSecond) {
-    RateLimiter rateLimiter = new Bursty(ticker, 1.0 /* maxBurstSeconds */);
+  static RateLimiter create(SleepingStopwatch stopwatch, double permitsPerSecond) {
+    RateLimiter rateLimiter = new SmoothBursty(stopwatch, 1.0 /* maxBurstSeconds */);
     rateLimiter.setRate(permitsPerSecond);
     return rateLimiter;
   }
@@ -266,28 +157,22 @@
    * will follow), and if it is left unused for long enough, it will return to that state.
    *
    * @param permitsPerSecond the rate of the returned {@code RateLimiter}, measured in
-   *        how many permits become available per second. Must be positive
+   *        how many permits become available per second
    * @param warmupPeriod the duration of the period where the {@code RateLimiter} ramps up its
    *        rate, before reaching its stable (maximum) rate
    * @param unit the time unit of the warmupPeriod argument
+   * @throws IllegalArgumentException if {@code permitsPerSecond} is negative or zero or
+   *     {@code warmupPeriod} is negative
    */
   public static RateLimiter create(double permitsPerSecond, long warmupPeriod, TimeUnit unit) {
-    return create(SleepingTicker.SYSTEM_TICKER, permitsPerSecond, warmupPeriod, unit);
+    checkArgument(warmupPeriod >= 0, "warmupPeriod must not be negative: %s", warmupPeriod);
+    return create(SleepingStopwatch.createFromSystemTimer(), permitsPerSecond, warmupPeriod, unit);
   }
 
   @VisibleForTesting
   static RateLimiter create(
-      SleepingTicker ticker, double permitsPerSecond, long warmupPeriod, TimeUnit unit) {
-    RateLimiter rateLimiter = new WarmingUp(ticker, warmupPeriod, unit);
-    rateLimiter.setRate(permitsPerSecond);
-    return rateLimiter;
-  }
-
-  @VisibleForTesting
-  static RateLimiter createWithCapacity(
-      SleepingTicker ticker, double permitsPerSecond, long maxBurstBuildup, TimeUnit unit) {
-    double maxBurstSeconds = unit.toNanos(maxBurstBuildup) / 1E+9;
-    Bursty rateLimiter = new Bursty(ticker, maxBurstSeconds);
+      SleepingStopwatch stopwatch, double permitsPerSecond, long warmupPeriod, TimeUnit unit) {
+    RateLimiter rateLimiter = new SmoothWarmingUp(stopwatch, warmupPeriod, unit);
     rateLimiter.setRate(permitsPerSecond);
     return rateLimiter;
   }
@@ -296,41 +181,26 @@
    * The underlying timer; used both to measure elapsed time and sleep as necessary. A separate
    * object to facilitate testing.
    */
-  private final SleepingTicker ticker;
+  private final SleepingStopwatch stopwatch;
 
-  /**
-   * The timestamp when the RateLimiter was created; used to avoid possible overflow/time-wrapping
-   * errors.
-   */
-  private final long offsetNanos;
+  // Can't be initialized in the constructor because mocks don't call the constructor.
+  private volatile Object mutexDoNotUseDirectly;
 
-  /**
-   * The currently stored permits.
-   */
-  double storedPermits;
+  private Object mutex() {
+    Object mutex = mutexDoNotUseDirectly;
+    if (mutex == null) {
+      synchronized (this) {
+        mutex = mutexDoNotUseDirectly;
+        if (mutex == null) {
+          mutexDoNotUseDirectly = mutex = new Object();
+        }
+      }
+    }
+    return mutex;
+  }
 
-  /**
-   * The maximum number of stored permits.
-   */
-  double maxPermits;
-
-  /**
-   * The interval between two unit requests, at our stable rate. E.g., a stable rate of 5 permits
-   * per second has a stable interval of 200ms.
-   */
-  volatile double stableIntervalMicros;
-
-  private final Object mutex = new Object();
-
-  /**
-   * The time when the next request (no matter its size) will be granted. After granting a request,
-   * this is pushed further in the future. Large requests push this further than small requests.
-   */
-  private long nextFreeTicketMicros = 0L; // could be either in the past or future
-
-  private RateLimiter(SleepingTicker ticker) {
-    this.ticker = ticker;
-    this.offsetNanos = ticker.read();
+  RateLimiter(SleepingStopwatch stopwatch) {
+    this.stopwatch = checkNotNull(stopwatch);
   }
 
   /**
@@ -349,20 +219,18 @@
    * e.g. if the {@code RateLimiter} was configured with a warmup period of 20 seconds,
    * it still has a warmup period of 20 seconds after this method invocation.
    *
-   * @param permitsPerSecond the new stable rate of this {@code RateLimiter}. Must be positive
+   * @param permitsPerSecond the new stable rate of this {@code RateLimiter}
+   * @throws IllegalArgumentException if {@code permitsPerSecond} is negative or zero
    */
   public final void setRate(double permitsPerSecond) {
-    Preconditions.checkArgument(permitsPerSecond > 0.0
-        && !Double.isNaN(permitsPerSecond), "rate must be positive");
-    synchronized (mutex) {
-      resync(readSafeMicros());
-      double stableIntervalMicros = TimeUnit.SECONDS.toMicros(1L) / permitsPerSecond;
-      this.stableIntervalMicros = stableIntervalMicros;
-      doSetRate(permitsPerSecond, stableIntervalMicros);
+    checkArgument(
+        permitsPerSecond > 0.0 && !Double.isNaN(permitsPerSecond), "rate must be positive");
+    synchronized (mutex()) {
+      doSetRate(permitsPerSecond, stopwatch.readMicros());
     }
   }
 
-  abstract void doSetRate(double permitsPerSecond, double stableIntervalMicros);
+  abstract void doSetRate(double permitsPerSecond, long nowMicros);
 
   /**
    * Returns the stable rate (as {@code permits per seconds}) with which this
@@ -372,9 +240,13 @@
    * to {@linkplain #setRate}.
    */
   public final double getRate() {
-    return TimeUnit.SECONDS.toMicros(1L) / stableIntervalMicros;
+    synchronized (mutex()) {
+      return doGetRate();
+    }
   }
 
+  abstract double doGetRate();
+
   /**
    * Acquires a single permit from this {@code RateLimiter}, blocking until the
    * request can be granted. Tells the amount of time slept, if any.
@@ -394,36 +266,25 @@
    *
    * @param permits the number of permits to acquire
    * @return time spent sleeping to enforce rate, in seconds; 0.0 if not rate-limited
+   * @throws IllegalArgumentException if the requested number of permits is negative or zero
    * @since 16.0 (present in 13.0 with {@code void} return type})
    */
   public double acquire(int permits) {
     long microsToWait = reserve(permits);
-    ticker.sleepMicrosUninterruptibly(microsToWait);
-    return 1.0 * microsToWait / TimeUnit.SECONDS.toMicros(1L);
-  }
-
-  /**
-   * Reserves a single permit from this {@code RateLimiter} for future use, returning the number of
-   * microseconds until the reservation.
-   *
-   * <p>This method is equivalent to {@code reserve(1)}.
-   *
-   * @return time in microseconds to wait until the resource can be acquired.
-   */
-  long reserve() {
-    return reserve(1);
+    stopwatch.sleepMicrosUninterruptibly(microsToWait);
+    return 1.0 * microsToWait / SECONDS.toMicros(1L);
   }
 
   /**
    * Reserves the given number of permits from this {@code RateLimiter} for future use, returning
    * the number of microseconds until the reservation can be consumed.
    *
-   * @return time in microseconds to wait until the resource can be acquired.
+   * @return time in microseconds to wait until the resource can be acquired, never negative
    */
-  long reserve(int permits) {
+  final long reserve(int permits) {
     checkPermits(permits);
-    synchronized (mutex) {
-      return reserveNextTicket(permits, readSafeMicros());
+    synchronized (mutex()) {
+      return reserveAndGetWaitLength(permits, stopwatch.readMicros());
     }
   }
 
@@ -435,9 +296,10 @@
    *
    * <p>This method is equivalent to {@code tryAcquire(1, timeout, unit)}.
    *
-   * @param timeout the maximum time to wait for the permit
+   * @param timeout the maximum time to wait for the permit. Negative values are treated as zero.
    * @param unit the time unit of the timeout argument
    * @return {@code true} if the permit was acquired, {@code false} otherwise
+   * @throws IllegalArgumentException if the requested number of permits is negative or zero
    */
   public boolean tryAcquire(long timeout, TimeUnit unit) {
     return tryAcquire(1, timeout, unit);
@@ -451,10 +313,11 @@
    *
    * @param permits the number of permits to acquire
    * @return {@code true} if the permits were acquired, {@code false} otherwise
+   * @throws IllegalArgumentException if the requested number of permits is negative or zero
    * @since 14.0
    */
   public boolean tryAcquire(int permits) {
-    return tryAcquire(permits, 0, TimeUnit.MICROSECONDS);
+    return tryAcquire(permits, 0, MICROSECONDS);
   }
 
   /**
@@ -468,7 +331,7 @@
    * @since 14.0
    */
   public boolean tryAcquire() {
-    return tryAcquire(1, 0, TimeUnit.MICROSECONDS);
+    return tryAcquire(1, 0, MICROSECONDS);
   }
 
   /**
@@ -478,252 +341,95 @@
    * before the timeout expired.
    *
    * @param permits the number of permits to acquire
-   * @param timeout the maximum time to wait for the permits
+   * @param timeout the maximum time to wait for the permits. Negative values are treated as zero.
    * @param unit the time unit of the timeout argument
    * @return {@code true} if the permits were acquired, {@code false} otherwise
+   * @throws IllegalArgumentException if the requested number of permits is negative or zero
    */
   public boolean tryAcquire(int permits, long timeout, TimeUnit unit) {
-    long timeoutMicros = unit.toMicros(timeout);
+    long timeoutMicros = max(unit.toMicros(timeout), 0);
     checkPermits(permits);
     long microsToWait;
-    synchronized (mutex) {
-      long nowMicros = readSafeMicros();
-      if (nextFreeTicketMicros > nowMicros + timeoutMicros) {
+    synchronized (mutex()) {
+      long nowMicros = stopwatch.readMicros();
+      if (!canAcquire(nowMicros, timeoutMicros)) {
         return false;
       } else {
-        microsToWait = reserveNextTicket(permits, nowMicros);
+        microsToWait = reserveAndGetWaitLength(permits, nowMicros);
       }
     }
-    ticker.sleepMicrosUninterruptibly(microsToWait);
+    stopwatch.sleepMicrosUninterruptibly(microsToWait);
     return true;
   }
 
-  private static void checkPermits(int permits) {
-    Preconditions.checkArgument(permits > 0, "Requested permits must be positive");
+  private boolean canAcquire(long nowMicros, long timeoutMicros) {
+    return queryEarliestAvailable(nowMicros) - timeoutMicros <= nowMicros;
   }
 
   /**
    * Reserves next ticket and returns the wait time that the caller must wait for.
    *
-   * <p>The return value is guaranteed to be non-negative.
+   * @return the required wait time, never negative
    */
-  private long reserveNextTicket(double requiredPermits, long nowMicros) {
-    resync(nowMicros);
-    long microsToNextFreeTicket = Math.max(0, nextFreeTicketMicros - nowMicros);
-    double storedPermitsToSpend = Math.min(requiredPermits, this.storedPermits);
-    double freshPermits = requiredPermits - storedPermitsToSpend;
-
-    long waitMicros = storedPermitsToWaitTime(this.storedPermits, storedPermitsToSpend)
-        + (long) (freshPermits * stableIntervalMicros);
-
-    this.nextFreeTicketMicros = nextFreeTicketMicros + waitMicros;
-    this.storedPermits -= storedPermitsToSpend;
-    return microsToNextFreeTicket;
+  final long reserveAndGetWaitLength(int permits, long nowMicros) {
+    long momentAvailable = reserveEarliestAvailable(permits, nowMicros);
+    return max(momentAvailable - nowMicros, 0);
   }
 
   /**
-   * Translates a specified portion of our currently stored permits which we want to
-   * spend/acquire, into a throttling time. Conceptually, this evaluates the integral
-   * of the underlying function we use, for the range of
-   * [(storedPermits - permitsToTake), storedPermits].
+   * Returns the earliest time that permits are available (with one caveat).
    *
-   * This always holds: {@code 0 <= permitsToTake <= storedPermits}
+   * @return the time that permits are available, or, if permits are available immediately, an
+   *     arbitrary past or present time
    */
-  abstract long storedPermitsToWaitTime(double storedPermits, double permitsToTake);
+  abstract long queryEarliestAvailable(long nowMicros);
 
-  private void resync(long nowMicros) {
-    // if nextFreeTicket is in the past, resync to now
-    if (nowMicros > nextFreeTicketMicros) {
-      storedPermits = Math.min(maxPermits,
-          storedPermits + (nowMicros - nextFreeTicketMicros) / stableIntervalMicros);
-      nextFreeTicketMicros = nowMicros;
-    }
-  }
-
-  private long readSafeMicros() {
-    return TimeUnit.NANOSECONDS.toMicros(ticker.read() - offsetNanos);
-  }
+    /**
+   * Reserves the requested number of permits and returns the time that those permits can be used
+   * (with one caveat).
+     *
+   * @return the time that the permits may be used, or, if the permits may be used immediately, an
+   *     arbitrary past or present time
+     */
+  abstract long reserveEarliestAvailable(int permits, long nowMicros);
 
   @Override
   public String toString() {
-    return String.format("RateLimiter[stableRate=%3.1fqps]", 1000000.0 / stableIntervalMicros);
-  }
-
-  /**
-   * This implements the following function:
-   *
-   *          ^ throttling
-   *          |
-   * 3*stable +                  /
-   * interval |                 /.
-   *  (cold)  |                / .
-   *          |               /  .   <-- "warmup period" is the area of the trapezoid between
-   * 2*stable +              /   .       halfPermits and maxPermits
-   * interval |             /    .
-   *          |            /     .
-   *          |           /      .
-   *   stable +----------/  WARM . }
-   * interval |          .   UP  . } <-- this rectangle (from 0 to maxPermits, and
-   *          |          . PERIOD. }     height == stableInterval) defines the cooldown period,
-   *          |          .       . }     and we want cooldownPeriod == warmupPeriod
-   *          |---------------------------------> storedPermits
-   *              (halfPermits) (maxPermits)
-   *
-   * Before going into the details of this particular function, let's keep in mind the basics:
-   * 1) The state of the RateLimiter (storedPermits) is a vertical line in this figure.
-   * 2) When the RateLimiter is not used, this goes right (up to maxPermits)
-   * 3) When the RateLimiter is used, this goes left (down to zero), since if we have storedPermits,
-   *    we serve from those first
-   * 4) When _unused_, we go right at the same speed (rate)! I.e., if our rate is
-   *    2 permits per second, and 3 unused seconds pass, we will always save 6 permits
-   *    (no matter what our initial position was), up to maxPermits.
-   *    If we invert the rate, we get the "stableInterval" (interval between two requests
-   *    in a perfectly spaced out sequence of requests of the given rate). Thus, if you
-   *    want to see "how much time it will take to go from X storedPermits to X+K storedPermits?",
-   *    the answer is always stableInterval * K. In the same example, for 2 permits per second,
-   *    stableInterval is 500ms. Thus to go from X storedPermits to X+6 storedPermits, we
-   *    require 6 * 500ms = 3 seconds.
-   *
-   *    In short, the time it takes to move to the right (save K permits) is equal to the
-   *    rectangle of width == K and height == stableInterval.
-   * 4) When _used_, the time it takes, as explained in the introductory class note, is
-   *    equal to the integral of our function, between X permits and X-K permits, assuming
-   *    we want to spend K saved permits.
-   *
-   *    In summary, the time it takes to move to the left (spend K permits), is equal to the
-   *    area of the function of width == K.
-   *
-   * Let's dive into this function now:
-   *
-   * When we have storedPermits <= halfPermits (the left portion of the function), then
-   * we spend them at the exact same rate that
-   * fresh permits would be generated anyway (that rate is 1/stableInterval). We size
-   * this area to be equal to _half_ the specified warmup period. Why we need this?
-   * And why half? We'll explain shortly below (after explaining the second part).
-   *
-   * Stored permits that are beyond halfPermits, are mapped to an ascending line, that goes
-   * from stableInterval to 3 * stableInterval. The average height for that part is
-   * 2 * stableInterval, and is sized appropriately to have an area _equal_ to the
-   * specified warmup period. Thus, by point (4) above, it takes "warmupPeriod" amount of time
-   * to go from maxPermits to halfPermits.
-   *
-   * BUT, by point (3) above, it only takes "warmupPeriod / 2" amount of time to return back
-   * to maxPermits, from halfPermits! (Because the trapezoid has double the area of the rectangle
-   * of height stableInterval and equivalent width). We decided that the "cooldown period"
-   * time should be equivalent to "warmup period", thus a fully saturated RateLimiter
-   * (with zero stored permits, serving only fresh ones) can go to a fully unsaturated
-   * (with storedPermits == maxPermits) in the same amount of time it takes for a fully
-   * unsaturated RateLimiter to return to the stableInterval -- which happens in halfPermits,
-   * since beyond that point, we use a horizontal line of "stableInterval" height, simulating
-   * the regular rate.
-   *
-   * Thus, we have figured all dimensions of this shape, to give all the desired
-   * properties:
-   * - the width is warmupPeriod / stableInterval, to make cooldownPeriod == warmupPeriod
-   * - the slope starts at the middle, and goes from stableInterval to 3*stableInterval so
-   *   to have halfPermits being spend in double the usual time (half the rate), while their
-   *   respective rate is steadily ramping up
-   */
-  private static class WarmingUp extends RateLimiter {
-
-    final long warmupPeriodMicros;
-    /**
-     * The slope of the line from the stable interval (when permits == 0), to the cold interval
-     * (when permits == maxPermits)
-     */
-    private double slope;
-    private double halfPermits;
-
-    WarmingUp(SleepingTicker ticker, long warmupPeriod, TimeUnit timeUnit) {
-      super(ticker);
-      this.warmupPeriodMicros = timeUnit.toMicros(warmupPeriod);
-    }
-
-    @Override
-    void doSetRate(double permitsPerSecond, double stableIntervalMicros) {
-      double oldMaxPermits = maxPermits;
-      maxPermits = warmupPeriodMicros / stableIntervalMicros;
-      halfPermits = maxPermits / 2.0;
-      // Stable interval is x, cold is 3x, so on average it's 2x. Double the time -> halve the rate
-      double coldIntervalMicros = stableIntervalMicros * 3.0;
-      slope = (coldIntervalMicros - stableIntervalMicros) / halfPermits;
-      if (oldMaxPermits == Double.POSITIVE_INFINITY) {
-        // if we don't special-case this, we would get storedPermits == NaN, below
-        storedPermits = 0.0;
-      } else {
-        storedPermits = (oldMaxPermits == 0.0)
-            ? maxPermits // initial state is cold
-            : storedPermits * maxPermits / oldMaxPermits;
-      }
-    }
-
-    @Override
-    long storedPermitsToWaitTime(double storedPermits, double permitsToTake) {
-      double availablePermitsAboveHalf = storedPermits - halfPermits;
-      long micros = 0;
-      // measuring the integral on the right part of the function (the climbing line)
-      if (availablePermitsAboveHalf > 0.0) {
-        double permitsAboveHalfToTake = Math.min(availablePermitsAboveHalf, permitsToTake);
-        micros = (long) (permitsAboveHalfToTake * (permitsToTime(availablePermitsAboveHalf)
-            + permitsToTime(availablePermitsAboveHalf - permitsAboveHalfToTake)) / 2.0);
-        permitsToTake -= permitsAboveHalfToTake;
-      }
-      // measuring the integral on the left part of the function (the horizontal line)
-      micros += (stableIntervalMicros * permitsToTake);
-      return micros;
-    }
-
-    private double permitsToTime(double permits) {
-      return stableIntervalMicros + permits * slope;
-    }
-  }
-
-  /**
-   * This implements a "bursty" RateLimiter, where storedPermits are translated to
-   * zero throttling. The maximum number of permits that can be saved (when the RateLimiter is
-   * unused) is defined in terms of time, in this sense: if a RateLimiter is 2qps, and this
-   * time is specified as 10 seconds, we can save up to 2 * 10 = 20 permits.
-   */
-  private static class Bursty extends RateLimiter {
-    /** The work (permits) of how many seconds can be saved up if this RateLimiter is unused? */
-    final double maxBurstSeconds;
-
-    Bursty(SleepingTicker ticker, double maxBurstSeconds) {
-      super(ticker);
-      this.maxBurstSeconds = maxBurstSeconds;
-    }
-
-    @Override
-    void doSetRate(double permitsPerSecond, double stableIntervalMicros) {
-      double oldMaxPermits = this.maxPermits;
-      maxPermits = maxBurstSeconds * permitsPerSecond;
-      storedPermits = (oldMaxPermits == 0.0)
-          ? 0.0 // initial state
-          : storedPermits * maxPermits / oldMaxPermits;
-    }
-
-    @Override
-    long storedPermitsToWaitTime(double storedPermits, double permitsToTake) {
-      return 0L;
-    }
+    return String.format("RateLimiter[stableRate=%3.1fqps]", getRate());
   }
 
   @VisibleForTesting
-  static abstract class SleepingTicker extends Ticker {
+  abstract static class SleepingStopwatch {
+    /*
+     * We always hold the mutex when calling this. TODO(cpovirk): Is that important? Perhaps we need
+     * to guarantee that each call to reserveEarliestAvailable, etc. sees a value >= the previous?
+     * Also, is it OK that we don't hold the mutex when sleeping?
+     */
+    abstract long readMicros();
+
     abstract void sleepMicrosUninterruptibly(long micros);
 
-    static final SleepingTicker SYSTEM_TICKER = new SleepingTicker() {
-      @Override
-      public long read() {
-        return systemTicker().read();
-      }
+    static final SleepingStopwatch createFromSystemTimer() {
+      return new SleepingStopwatch() {
+        final Stopwatch stopwatch = Stopwatch.createStarted();
 
-      @Override
-      public void sleepMicrosUninterruptibly(long micros) {
-        if (micros > 0) {
-          Uninterruptibles.sleepUninterruptibly(micros, TimeUnit.MICROSECONDS);
+        @Override
+        long readMicros() {
+          return stopwatch.elapsed(MICROSECONDS);
         }
-      }
-    };
+
+        @Override
+        void sleepMicrosUninterruptibly(long micros) {
+          if (micros > 0) {
+            Uninterruptibles.sleepUninterruptibly(micros, MICROSECONDS);
+          }
+        }
+      };
+    }
+  }
+
+  private static int checkPermits(int permits) {
+    checkArgument(permits > 0, "Requested permits (%s) must be positive", permits);
+    return permits;
   }
 }
diff --git a/guava/src/com/google/common/util/concurrent/SerializingExecutor.java b/guava/src/com/google/common/util/concurrent/SerializingExecutor.java
index c36d6fa..47524eb 100644
--- a/guava/src/com/google/common/util/concurrent/SerializingExecutor.java
+++ b/guava/src/com/google/common/util/concurrent/SerializingExecutor.java
@@ -18,7 +18,7 @@
 
 import com.google.common.base.Preconditions;
 
-import java.util.LinkedList;
+import java.util.ArrayDeque;
 import java.util.Queue;
 import java.util.concurrent.Executor;
 import java.util.logging.Level;
@@ -52,7 +52,7 @@
 
   /** A list of Runnables to be run in order. */
   @GuardedBy("internalLock")
-  private final Queue<Runnable> waitQueue = new LinkedList<Runnable>();
+  private final Queue<Runnable> waitQueue = new ArrayDeque<Runnable>();
 
   /**
    * We explicitly keep track of if the TaskRunner is currently scheduled to
diff --git a/guava/src/com/google/common/util/concurrent/Service.java b/guava/src/com/google/common/util/concurrent/Service.java
index 3b4ea87..a898ea9 100644
--- a/guava/src/com/google/common/util/concurrent/Service.java
+++ b/guava/src/com/google/common/util/concurrent/Service.java
@@ -55,40 +55,6 @@
 public interface Service {
   /**
    * If the service state is {@link State#NEW}, this initiates service startup and returns
-   * immediately. If the service has already been started, this method returns immediately without
-   * taking action. A stopped service may not be restarted.
-   *
-   * @deprecated Use {@link #startAsync()} instead of this method to start the {@link Service} or
-   * use a {@link Listener} to asynchronously wait for service startup.
-   *
-   * @return a future for the startup result, regardless of whether this call initiated startup.
-   *         Calling {@link ListenableFuture#get} will block until the service has finished
-   *         starting, and returns one of {@link State#RUNNING}, {@link State#STOPPING} or
-   *         {@link State#TERMINATED}. If the service fails to start, {@link ListenableFuture#get}
-   *         will throw an {@link ExecutionException}, and the service's state will be
-   *         {@link State#FAILED}. If it has already finished starting, {@link ListenableFuture#get}
-   *         returns immediately. Cancelling this future has no effect on the service.
-   */
-
-  @Deprecated
-  ListenableFuture<State> start();
-
-  /**
-   * Initiates service startup (if necessary), returning once the service has finished starting.
-   * Unlike calling {@code start().get()}, this method throws no checked exceptions, and it cannot
-   * be {@linkplain Thread#interrupt interrupted}.
-   *
-   * @deprecated Use {@link #startAsync()} and {@link #awaitRunning} instead of this method.
-   *
-   * @throws UncheckedExecutionException if startup failed
-   * @return the state of the service when startup finished.
-   */
-
-  @Deprecated
-  State startAndWait();
-
-  /**
-   * If the service state is {@link State#NEW}, this initiates service startup and returns
    * immediately. A stopped service may not be restarted.
    * 
    * @return this
@@ -115,42 +81,6 @@
    * started nor stopped. If the service has already been stopped, this method returns immediately
    * without taking action.
    *
-   * @deprecated Use {@link #stopAsync} instead of this method to initiate service shutdown or use a
-   * service {@link Listener} to asynchronously wait for service shutdown.
-   *
-   * @return a future for the shutdown result, regardless of whether this call initiated shutdown.
-   *         Calling {@link ListenableFuture#get} will block until the service has finished shutting
-   *         down, and either returns {@link State#TERMINATED} or throws an
-   *         {@link ExecutionException}. If it has already finished stopping,
-   *         {@link ListenableFuture#get} returns immediately. Cancelling this future has no effect
-   *         on the service.
-   */
-
-  @Deprecated
-  ListenableFuture<State> stop();
-
-  /**
-   * Initiates service shutdown (if necessary), returning once the service has finished stopping. If
-   * this is {@link State#STARTING}, startup will be cancelled. If this is {@link State#NEW}, it is
-   * {@link State#TERMINATED terminated} without having been started nor stopped. Unlike calling
-   * {@code stop().get()}, this method throws no checked exceptions.
-   *
-   * @deprecated Use {@link #stopAsync} and {@link #awaitTerminated} instead of this method.
-   *
-   * @throws UncheckedExecutionException if the service has failed or fails during shutdown
-   * @return the state of the service when shutdown finished.
-   */
-
-  @Deprecated
-  State stopAndWait();
-
-  /**
-   * If the service is {@linkplain State#STARTING starting} or {@linkplain State#RUNNING running},
-   * this initiates service shutdown and returns immediately. If the service is
-   * {@linkplain State#NEW new}, it is {@linkplain State#TERMINATED terminated} without having been
-   * started nor stopped. If the service has already been stopped, this method returns immediately
-   * without taking action.
-   *
    * @return this
    * @since 15.0
    */
@@ -235,7 +165,7 @@
    * @param listener the listener to run when the service changes state is complete
    * @param executor the executor in which the listeners callback methods will be run. For fast,
    *     lightweight listeners that would be safe to execute in any thread, consider 
-   *     {@link MoreExecutors#sameThreadExecutor}.
+   *     {@link MoreExecutors#directExecutor}.
    * @since 13.0
    */
   void addListener(Listener listener, Executor executor);
diff --git a/guava/src/com/google/common/util/concurrent/ServiceManager.java b/guava/src/com/google/common/util/concurrent/ServiceManager.java
index 6382473..4f7d1d7 100644
--- a/guava/src/com/google/common/util/concurrent/ServiceManager.java
+++ b/guava/src/com/google/common/util/concurrent/ServiceManager.java
@@ -22,6 +22,7 @@
 import static com.google.common.base.Predicates.in;
 import static com.google.common.base.Predicates.instanceOf;
 import static com.google.common.base.Predicates.not;
+import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
 import static com.google.common.util.concurrent.Service.State.FAILED;
 import static com.google.common.util.concurrent.Service.State.NEW;
 import static com.google.common.util.concurrent.Service.State.RUNNING;
@@ -32,7 +33,7 @@
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Function;
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Stopwatch;
 import com.google.common.base.Supplier;
 import com.google.common.collect.Collections2;
@@ -98,11 +99,11 @@
  *           System.exit(1);
  *         }
  *       },
- *       MoreExecutors.sameThreadExecutor());
+ *       MoreExecutors.directExecutor());
  *
  *     Runtime.getRuntime().addShutdownHook(new Thread() {
  *       public void run() {
- *         // Give the services 5 seconds to stop to ensure that we are responsive to shutdown 
+ *         // Give the services 5 seconds to stop to ensure that we are responsive to shutdown
  *         // requests.
  *         try {
  *           manager.stopAsync().awaitStopped(5, TimeUnit.SECONDS);
@@ -140,79 +141,70 @@
    * that need to listen to more fine-grained events (such as when each particular {@linkplain
    * Service service} starts, or terminates), should attach {@linkplain Service.Listener service
    * listeners} to each individual service.
-   * 
+   *
    * @author Luke Sandberg
    * @since 15.0 (present as an interface in 14.0)
    */
   @Beta  // Should come out of Beta when ServiceManager does
   public abstract static class Listener {
-    /** 
+    /**
      * Called when the service initially becomes healthy.
-     * 
-     * <p>This will be called at most once after all the services have entered the 
-     * {@linkplain State#RUNNING running} state. If any services fail during start up or 
-     * {@linkplain State#FAILED fail}/{@linkplain State#TERMINATED terminate} before all other 
+     *
+     * <p>This will be called at most once after all the services have entered the
+     * {@linkplain State#RUNNING running} state. If any services fail during start up or
+     * {@linkplain State#FAILED fail}/{@linkplain State#TERMINATED terminate} before all other
      * services have started {@linkplain State#RUNNING running} then this method will not be called.
      */
     public void healthy() {}
-    
-    /** 
-     * Called when the all of the component services have reached a terminal state, either 
+
+    /**
+     * Called when the all of the component services have reached a terminal state, either
      * {@linkplain State#TERMINATED terminated} or {@linkplain State#FAILED failed}.
      */
     public void stopped() {}
-    
-    /** 
+
+    /**
      * Called when a component service has {@linkplain State#FAILED failed}.
-     * 
+     *
      * @param service The service that failed.
      */
     public void failure(Service service) {}
   }
-  
+
   /**
-   * An encapsulation of all of the state that is accessed by the {@linkplain ServiceListener 
-   * service listeners}.  This is extracted into its own object so that {@link ServiceListener} 
-   * could be made {@code static} and its instances can be safely constructed and added in the 
-   * {@link ServiceManager} constructor without having to close over the partially constructed 
+   * An encapsulation of all of the state that is accessed by the {@linkplain ServiceListener
+   * service listeners}.  This is extracted into its own object so that {@link ServiceListener}
+   * could be made {@code static} and its instances can be safely constructed and added in the
+   * {@link ServiceManager} constructor without having to close over the partially constructed
    * {@link ServiceManager} instance (i.e. avoid leaking a pointer to {@code this}).
    */
   private final ServiceManagerState state;
   private final ImmutableList<Service> services;
-  
+
   /**
    * Constructs a new instance for managing the given services.
-   * 
+   *
    * @param services The services to manage
-   * 
+   *
    * @throws IllegalArgumentException if not all services are {@linkplain State#NEW new} or if there
    * are any duplicate services.
    */
   public ServiceManager(Iterable<? extends Service> services) {
     ImmutableList<Service> copy = ImmutableList.copyOf(services);
     if (copy.isEmpty()) {
-      // Having no services causes the manager to behave strangely. Notably, listeners are never 
+      // Having no services causes the manager to behave strangely. Notably, listeners are never
       // fired.  To avoid this we substitute a placeholder service.
-      logger.log(Level.WARNING, 
-          "ServiceManager configured with no services.  Is your application configured properly?", 
+      logger.log(Level.WARNING,
+          "ServiceManager configured with no services.  Is your application configured properly?",
           new EmptyServiceManagerWarning());
       copy = ImmutableList.<Service>of(new NoOpService());
     }
     this.state = new ServiceManagerState(copy);
     this.services = copy;
-    WeakReference<ServiceManagerState> stateReference = 
+    WeakReference<ServiceManagerState> stateReference =
         new WeakReference<ServiceManagerState>(state);
-    Executor sameThreadExecutor = MoreExecutors.sameThreadExecutor();
     for (Service service : copy) {
-      // We give each listener its own SynchronizedExecutor to ensure that the state transitions
-      // are run in the same order that they occur.  The Service.Listener api guarantees us only
-      // that the transitions are submitted to the executor in the same order that they occur, so by
-      // synchronizing the executions of each listeners callbacks we can ensure that the entire
-      // execution of the listener occurs in the same order as the transitions themselves.
-      //
-      // This is necessary to prevent transitions being played back in the wrong order due to thread
-      // races to acquire the monitor in ServiceManagerState.
-      service.addListener(new ServiceListener(service, stateReference), sameThreadExecutor);
+      service.addListener(new ServiceListener(service, stateReference), directExecutor());
       // We check the state after adding the listener as a way to ensure that our listener was added
       // to a NEW service.
       checkArgument(service.state() == NEW, "Can only manage NEW services, %s", service);
@@ -223,9 +215,9 @@
   }
 
   /**
-   * Registers a {@link Listener} to be {@linkplain Executor#execute executed} on the given 
-   * executor. The listener will not have previous state changes replayed, so it is 
-   * suggested that listeners are added before any of the managed services are 
+   * Registers a {@link Listener} to be {@linkplain Executor#execute executed} on the given
+   * executor. The listener will not have previous state changes replayed, so it is
+   * suggested that listeners are added before any of the managed services are
    * {@linkplain Service#startAsync started}.
    *
    * <p>{@code addListener} guarantees execution ordering across calls to a given listener but not
@@ -235,13 +227,13 @@
    * may execute concurrently, and listeners may execute in an order different from the one in which
    * they were registered.
    *
-   * <p>RuntimeExceptions thrown by a listener will be caught and logged. Any exception thrown 
+   * <p>RuntimeExceptions thrown by a listener will be caught and logged. Any exception thrown
    * during {@code Executor.execute} (e.g., a {@code RejectedExecutionException}) will be caught and
    * logged.
-   * 
-   * <p> For fast, lightweight listeners that would be safe to execute in any thread, consider 
+   *
+   * <p> For fast, lightweight listeners that would be safe to execute in any thread, consider
    * calling {@link #addListener(Listener)}.
-   * 
+   *
    * @param listener the listener to run when the manager changes state
    * @param executor the executor in which the listeners callback methods will be run.
    */
@@ -250,8 +242,8 @@
   }
 
   /**
-   * Registers a {@link Listener} to be run when this {@link ServiceManager} changes state. The 
-   * listener will not have previous state changes replayed, so it is suggested that listeners are 
+   * Registers a {@link Listener} to be run when this {@link ServiceManager} changes state. The
+   * listener will not have previous state changes replayed, so it is suggested that listeners are
    * added before any of the managed services are {@linkplain Service#startAsync started}.
    *
    * <p>{@code addListener} guarantees execution ordering across calls to a given listener but not
@@ -262,19 +254,19 @@
    * they were registered.
    *
    * <p>RuntimeExceptions thrown by a listener will be caught and logged.
-   * 
+   *
    * @param listener the listener to run when the manager changes state
    */
   public void addListener(Listener listener) {
-    state.addListener(listener, MoreExecutors.sameThreadExecutor());
+    state.addListener(listener, directExecutor());
   }
 
   /**
-   * Initiates service {@linkplain Service#startAsync startup} on all the services being managed.  
+   * Initiates service {@linkplain Service#startAsync startup} on all the services being managed.
    * It is only valid to call this method if all of the services are {@linkplain State#NEW new}.
-   * 
+   *
    * @return this
-   * @throws IllegalStateException if any of the Services are not {@link State#NEW new} when the 
+   * @throws IllegalStateException if any of the Services are not {@link State#NEW new} when the
    *     method is called.
    */
   public ServiceManager startAsync() {
@@ -284,9 +276,10 @@
     }
     for (Service service : services) {
       try {
+        state.tryStartTiming(service);
         service.startAsync();
       } catch (IllegalStateException e) {
-        // This can happen if the service has already been started or stopped (e.g. by another 
+        // This can happen if the service has already been started or stopped (e.g. by another
         // service or listener). Our contract says it is safe to call this method if
         // all services were NEW when it was called, and this has already been verified above, so we
         // don't propagate the exception.
@@ -295,28 +288,28 @@
     }
     return this;
   }
-  
+
   /**
    * Waits for the {@link ServiceManager} to become {@linkplain #isHealthy() healthy}.  The manager
    * will become healthy after all the component services have reached the {@linkplain State#RUNNING
-   * running} state.  
-   * 
-   * @throws IllegalStateException if the service manager reaches a state from which it cannot 
+   * running} state.
+   *
+   * @throws IllegalStateException if the service manager reaches a state from which it cannot
    *     become {@linkplain #isHealthy() healthy}.
    */
   public void awaitHealthy() {
     state.awaitHealthy();
   }
-  
+
   /**
-   * Waits for the {@link ServiceManager} to become {@linkplain #isHealthy() healthy} for no more 
-   * than the given time.  The manager will become healthy after all the component services have 
-   * reached the {@linkplain State#RUNNING running} state. 
+   * Waits for the {@link ServiceManager} to become {@linkplain #isHealthy() healthy} for no more
+   * than the given time.  The manager will become healthy after all the component services have
+   * reached the {@linkplain State#RUNNING running} state.
    *
    * @param timeout the maximum time to wait
    * @param unit the time unit of the timeout argument
    * @throws TimeoutException if not all of the services have finished starting within the deadline
-   * @throws IllegalStateException if the service manager reaches a state from which it cannot 
+   * @throws IllegalStateException if the service manager reaches a state from which it cannot
    *     become {@linkplain #isHealthy() healthy}.
    */
   public void awaitHealthy(long timeout, TimeUnit unit) throws TimeoutException {
@@ -325,8 +318,8 @@
 
   /**
    * Initiates service {@linkplain Service#stopAsync shutdown} if necessary on all the services
-   * being managed. 
-   *    
+   * being managed.
+   *
    * @return this
    */
   public ServiceManager stopAsync() {
@@ -335,7 +328,7 @@
     }
     return this;
   }
- 
+
   /**
    * Waits for the all the services to reach a terminal state. After this method returns all
    * services will either be {@linkplain Service.State#TERMINATED terminated} or {@linkplain
@@ -344,7 +337,7 @@
   public void awaitStopped() {
     state.awaitStopped();
   }
-  
+
   /**
    * Waits for the all the services to reach a terminal state for no more than the given time. After
    * this method returns all services will either be {@linkplain Service.State#TERMINATED
@@ -357,11 +350,11 @@
   public void awaitStopped(long timeout, TimeUnit unit) throws TimeoutException {
     state.awaitStopped(timeout, unit);
   }
-  
+
   /**
-   * Returns true if all services are currently in the {@linkplain State#RUNNING running} state.  
-   * 
-   * <p>Users who want more detailed information should use the {@link #servicesByState} method to 
+   * Returns true if all services are currently in the {@linkplain State#RUNNING running} state.
+   *
+   * <p>Users who want more detailed information should use the {@link #servicesByState} method to
    * get detailed information about which services are not running.
    */
   public boolean isHealthy() {
@@ -372,7 +365,7 @@
     }
     return true;
   }
-  
+
   /**
    * Provides a snapshot of the current state of all the services under management.
    *
@@ -382,7 +375,7 @@
   public ImmutableMultimap<State, Service> servicesByState() {
     return state.servicesByState();
   }
-  
+
   /**
    * Returns the service load times. This value will only return startup times for services that
    * have finished starting.
@@ -393,15 +386,15 @@
   public ImmutableMap<Service, Long> startupTimes() {
     return state.startupTimes();
   }
-  
+
   @Override public String toString() {
-    return Objects.toStringHelper(ServiceManager.class)
+    return MoreObjects.toStringHelper(ServiceManager.class)
         .add("services", Collections2.filter(services, not(instanceOf(NoOpService.class))))
         .toString();
   }
-  
+
   /**
-   * An encapsulation of all the mutable state of the {@link ServiceManager} that needs to be 
+   * An encapsulation of all the mutable state of the {@link ServiceManager} that needs to be
    * accessed by instances of {@link ServiceListener}.
    */
   private static final class ServiceManagerState {
@@ -424,21 +417,21 @@
 
     /**
      * These two booleans are used to mark the state as ready to start.
-     * {@link #ready}: is set by {@link #markReady} to indicate that all listeners have been 
+     * {@link #ready}: is set by {@link #markReady} to indicate that all listeners have been
      *     correctly installed
-     * {@link #transitioned}: is set by {@link #transitionService} to indicate that some transition 
+     * {@link #transitioned}: is set by {@link #transitionService} to indicate that some transition
      *     has been performed.
-     * 
+     *
      * <p>Together, they allow us to enforce that all services have their listeners installed prior
      * to any service performing a transition, then we can fail in the ServiceManager constructor
      * rather than in a Service.Listener callback.
      */
     @GuardedBy("monitor")
     boolean ready;
-    
+
     @GuardedBy("monitor")
     boolean transitioned;
-    
+
     final int numberOfServices;
 
     /**
@@ -449,8 +442,8 @@
       @Override public boolean isSatisfied() {
         // All services have started or some service has terminated/failed.
         return states.count(RUNNING) == numberOfServices
-            || states.contains(STOPPING) 
-            || states.contains(TERMINATED) 
+            || states.contains(STOPPING)
+            || states.contains(TERMINATED)
             || states.contains(FAILED);
       }
     };
@@ -466,11 +459,11 @@
 
     /** The listeners to notify during a state transition. */
     @GuardedBy("monitor")
-    final List<ListenerCallQueue<Listener>> listeners = 
+    final List<ListenerCallQueue<Listener>> listeners =
         Collections.synchronizedList(new ArrayList<ListenerCallQueue<Listener>>());
 
     /**
-     * It is implicitly assumed that all the services are NEW and that they will all remain NEW 
+     * It is implicitly assumed that all the services are NEW and that they will all remain NEW
      * until all the Listeners are installed and {@link #markReady()} is called.  It is our caller's
      * responsibility to only call {@link #markReady()} if all services were new at the time this
      * method was called and when all the listeners were installed.
@@ -478,8 +471,21 @@
     ServiceManagerState(ImmutableCollection<Service> services) {
       this.numberOfServices = services.size();
       servicesByState.putAll(NEW, services);
-      for (Service service : services) {
-        startupTimers.put(service, Stopwatch.createUnstarted());
+    }
+
+    /**
+     * Attempts to start the timer immediately prior to the service being started via
+     * {@link Service#startAsync()}.
+     */
+    void tryStartTiming(Service service) {
+      monitor.enter();
+      try {
+        Stopwatch stopwatch = startupTimers.get(service);
+        if (stopwatch == null) {
+          startupTimers.put(service, Stopwatch.createStarted());
+        }
+      } finally {
+        monitor.leave();
       }
     }
 
@@ -522,7 +528,7 @@
         monitor.leave();
       }
     }
-    
+
     void awaitHealthy() {
       monitor.enterWhenUninterruptibly(awaitHealthGuard);
       try {
@@ -537,7 +543,7 @@
       try {
         if (!monitor.waitForUninterruptibly(awaitHealthGuard, timeout, unit)) {
           throw new TimeoutException("Timeout waiting for the services to become healthy. The "
-              + "following services have not started: " 
+              + "following services have not started: "
               + Multimaps.filterKeys(servicesByState, in(ImmutableSet.of(NEW, STARTING))));
         }
         checkHealthy();
@@ -545,20 +551,20 @@
         monitor.leave();
       }
     }
-    
+
     void awaitStopped() {
       monitor.enterWhenUninterruptibly(stoppedGuard);
       monitor.leave();
     }
-    
+
     void awaitStopped(long timeout, TimeUnit unit) throws TimeoutException {
       monitor.enter();
       try {
         if (!monitor.waitForUninterruptibly(stoppedGuard, timeout, unit)) {
           throw new TimeoutException("Timeout waiting for the services to stop. The following "
-              + "services have not stopped: " 
-              + Multimaps.filterKeys(servicesByState, 
-                  not(in(ImmutableSet.of(TERMINATED, FAILED))))); 
+              + "services have not stopped: "
+              + Multimaps.filterKeys(servicesByState,
+                  not(in(ImmutableSet.of(TERMINATED, FAILED)))));
         }
       } finally {
         monitor.leave();
@@ -579,22 +585,17 @@
       }
       return builder.build();
     }
-    
+
     ImmutableMap<Service, Long> startupTimes() {
       List<Entry<Service, Long>> loadTimes;
       monitor.enter();
       try {
-        loadTimes = Lists.newArrayListWithCapacity(
-            states.size() - states.count(NEW) + states.count(STARTING));
+        loadTimes = Lists.newArrayListWithCapacity(startupTimers.size());
+        // N.B. There will only be an entry in the map if the service has started
         for (Entry<Service, Stopwatch> entry : startupTimers.entrySet()) {
           Service service = entry.getKey();
           Stopwatch stopWatch = entry.getValue();
-          // N.B. we check the service state in the multimap rather than via Service.state() because
-          // the multimap is guaranteed to be in sync with our timers while the Service.state() is
-          // not.  Due to happens-before ness of the monitor this 'weirdness' will not be observable
-          // by our caller.
-          if (!stopWatch.isRunning() && !servicesByState.containsEntry(NEW, service) 
-              && !(service instanceof NoOpService)) {
+          if (!stopWatch.isRunning() && !(service instanceof NoOpService)) {
             loadTimes.add(Maps.immutableEntry(service, stopWatch.elapsed(MILLISECONDS)));
           }
         }
@@ -613,10 +614,10 @@
       }
       return builder.build();
     }
-    
-    /** 
+
+    /**
      * Updates the state with the given service transition.
-     * 
+     *
      * <p>This method performs the main logic of ServiceManager in the following steps.
      * <ol>
      *      <li>Update the {@link #servicesByState()}
@@ -641,26 +642,28 @@
             "Service %s in the state map unexpectedly at %s", service, to);
         // Update the timer
         Stopwatch stopwatch = startupTimers.get(service);
-        if (from == NEW) {
-          stopwatch.start();
+        if (stopwatch == null) {
+          // This means the service was started by some means other than ServiceManager.startAsync
+          stopwatch = Stopwatch.createStarted();
+          startupTimers.put(service, stopwatch);
         }
         if (to.compareTo(RUNNING) >= 0 && stopwatch.isRunning()) {
-          // N.B. if we miss the STARTING event then we will never record a startup time.
+          // N.B. if we miss the STARTING event then we may never record a startup time.
           stopwatch.stop();
           if (!(service instanceof NoOpService)) {
             logger.log(Level.FINE, "Started {0} in {1}.", new Object[] {service, stopwatch});
           }
         }
         // Queue our listeners
-        
+
         // Did a service fail?
         if (to == FAILED) {
           fireFailedListeners(service);
         }
-        
+
         if (states.count(RUNNING) == numberOfServices) {
-          // This means that the manager is currently healthy. N.B. If other threads call isHealthy 
-          // they are not guaranteed to get 'true', because any service could fail right now. 
+          // This means that the manager is currently healthy. N.B. If other threads call isHealthy
+          // they are not guaranteed to get 'true', because any service could fail right now.
           fireHealthyListeners();
         } else if (states.count(TERMINATED) + states.count(FAILED) == numberOfServices) {
           fireStoppedListeners();
@@ -693,7 +696,7 @@
 
     /** Attempts to execute all the listeners in {@link #listeners}. */
     void executeListeners() {
-      checkState(!monitor.isOccupiedByCurrentThread(), 
+      checkState(!monitor.isOccupiedByCurrentThread(),
           "It is incorrect to execute listeners with the monitor held.");
       // iterate by index to avoid concurrent modification exceptions
       for (int i = 0; i < listeners.size(); i++) {
@@ -704,9 +707,10 @@
     @GuardedBy("monitor")
     void checkHealthy() {
       if (states.count(RUNNING) != numberOfServices) {
-        throw new IllegalStateException("Expected to be healthy after starting. "
-            + "The following services are not running: " + 
-            Multimaps.filterKeys(servicesByState, not(equalTo(RUNNING))));
+        IllegalStateException exception = new IllegalStateException(
+            "Expected to be healthy after starting. The following services are not running: "
+                + Multimaps.filterKeys(servicesByState, not(equalTo(RUNNING))));
+        throw exception;
       }
     }
   }
@@ -718,15 +722,15 @@
    */
   private static final class ServiceListener extends Service.Listener {
     final Service service;
-    // We store the state in a weak reference to ensure that if something went wrong while 
+    // We store the state in a weak reference to ensure that if something went wrong while
     // constructing the ServiceManager we don't pointlessly keep updating the state.
     final WeakReference<ServiceManagerState> state;
-    
+
     ServiceListener(Service service, WeakReference<ServiceManagerState> state) {
       this.service = service;
       this.state = state;
     }
-    
+
     @Override public void starting() {
       ServiceManagerState state = this.state.get();
       if (state != null) {
@@ -743,25 +747,25 @@
         state.transitionService(service, STARTING, RUNNING);
       }
     }
-    
+
     @Override public void stopping(State from) {
       ServiceManagerState state = this.state.get();
       if (state != null) {
         state.transitionService(service, from, STOPPING);
       }
     }
-    
+
     @Override public void terminated(State from) {
       ServiceManagerState state = this.state.get();
       if (state != null) {
         if (!(service instanceof NoOpService)) {
-          logger.log(Level.FINE, "Service {0} has terminated. Previous state was: {1}", 
+          logger.log(Level.FINE, "Service {0} has terminated. Previous state was: {1}",
               new Object[] {service, from});
         }
         state.transitionService(service, from, TERMINATED);
       }
     }
-    
+
     @Override public void failed(State from, Throwable failure) {
       ServiceManagerState state = this.state.get();
       if (state != null) {
@@ -775,11 +779,11 @@
       }
     }
   }
-  
+
   /**
    * A {@link Service} instance that does nothing.  This is only useful as a placeholder to
    * ensure that the {@link ServiceManager} functions properly even when it is managing no services.
-   * 
+   *
    * <p>The use of this class is considered an implementation detail of ServiceManager and as such
    * it is excluded from {@link #servicesByState}, {@link #startupTimes}, {@link #toString} and all
    * logging statements.
@@ -788,7 +792,7 @@
     @Override protected void doStart() { notifyStarted(); }
     @Override protected void doStop() { notifyStopped(); }
   }
-  
+
   /** This is never thrown but only used for logging. */
   private static final class EmptyServiceManagerWarning extends Throwable {}
 }
diff --git a/guava/src/com/google/common/util/concurrent/SmoothRateLimiter.java b/guava/src/com/google/common/util/concurrent/SmoothRateLimiter.java
new file mode 100644
index 0000000..0d426cf
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/SmoothRateLimiter.java
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2012 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.util.concurrent;
+
+import static java.lang.Math.min;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import java.util.concurrent.TimeUnit;
+
+abstract class SmoothRateLimiter extends RateLimiter {
+  /*
+   * How is the RateLimiter designed, and why?
+   *
+   * The primary feature of a RateLimiter is its "stable rate", the maximum rate that
+   * is should allow at normal conditions. This is enforced by "throttling" incoming
+   * requests as needed, i.e. compute, for an incoming request, the appropriate throttle time,
+   * and make the calling thread wait as much.
+   *
+   * The simplest way to maintain a rate of QPS is to keep the timestamp of the last
+   * granted request, and ensure that (1/QPS) seconds have elapsed since then. For example,
+   * for a rate of QPS=5 (5 tokens per second), if we ensure that a request isn't granted
+   * earlier than 200ms after the last one, then we achieve the intended rate.
+   * If a request comes and the last request was granted only 100ms ago, then we wait for
+   * another 100ms. At this rate, serving 15 fresh permits (i.e. for an acquire(15) request)
+   * naturally takes 3 seconds.
+   *
+   * It is important to realize that such a RateLimiter has a very superficial memory
+   * of the past: it only remembers the last request. What if the RateLimiter was unused for
+   * a long period of time, then a request arrived and was immediately granted?
+   * This RateLimiter would immediately forget about that past underutilization. This may
+   * result in either underutilization or overflow, depending on the real world consequences
+   * of not using the expected rate.
+   *
+   * Past underutilization could mean that excess resources are available. Then, the RateLimiter
+   * should speed up for a while, to take advantage of these resources. This is important
+   * when the rate is applied to networking (limiting bandwidth), where past underutilization
+   * typically translates to "almost empty buffers", which can be filled immediately.
+   *
+   * On the other hand, past underutilization could mean that "the server responsible for
+   * handling the request has become less ready for future requests", i.e. its caches become
+   * stale, and requests become more likely to trigger expensive operations (a more extreme
+   * case of this example is when a server has just booted, and it is mostly busy with getting
+   * itself up to speed).
+   *
+   * To deal with such scenarios, we add an extra dimension, that of "past underutilization",
+   * modeled by "storedPermits" variable. This variable is zero when there is no
+   * underutilization, and it can grow up to maxStoredPermits, for sufficiently large
+   * underutilization. So, the requested permits, by an invocation acquire(permits),
+   * are served from:
+   * - stored permits (if available)
+   * - fresh permits (for any remaining permits)
+   *
+   * How this works is best explained with an example:
+   *
+   * For a RateLimiter that produces 1 token per second, every second
+   * that goes by with the RateLimiter being unused, we increase storedPermits by 1.
+   * Say we leave the RateLimiter unused for 10 seconds (i.e., we expected a request at time
+   * X, but we are at time X + 10 seconds before a request actually arrives; this is
+   * also related to the point made in the last paragraph), thus storedPermits
+   * becomes 10.0 (assuming maxStoredPermits >= 10.0). At that point, a request of acquire(3)
+   * arrives. We serve this request out of storedPermits, and reduce that to 7.0 (how this is
+   * translated to throttling time is discussed later). Immediately after, assume that an
+   * acquire(10) request arriving. We serve the request partly from storedPermits,
+   * using all the remaining 7.0 permits, and the remaining 3.0, we serve them by fresh permits
+   * produced by the rate limiter.
+   *
+   * We already know how much time it takes to serve 3 fresh permits: if the rate is
+   * "1 token per second", then this will take 3 seconds. But what does it mean to serve 7
+   * stored permits? As explained above, there is no unique answer. If we are primarily
+   * interested to deal with underutilization, then we want stored permits to be given out
+   * /faster/ than fresh ones, because underutilization = free resources for the taking.
+   * If we are primarily interested to deal with overflow, then stored permits could
+   * be given out /slower/ than fresh ones. Thus, we require a (different in each case)
+   * function that translates storedPermits to throtting time.
+   *
+   * This role is played by storedPermitsToWaitTime(double storedPermits, double permitsToTake).
+   * The underlying model is a continuous function mapping storedPermits
+   * (from 0.0 to maxStoredPermits) onto the 1/rate (i.e. intervals) that is effective at the given
+   * storedPermits. "storedPermits" essentially measure unused time; we spend unused time
+   * buying/storing permits. Rate is "permits / time", thus "1 / rate = time / permits".
+   * Thus, "1/rate" (time / permits) times "permits" gives time, i.e., integrals on this
+   * function (which is what storedPermitsToWaitTime() computes) correspond to minimum intervals
+   * between subsequent requests, for the specified number of requested permits.
+   *
+   * Here is an example of storedPermitsToWaitTime:
+   * If storedPermits == 10.0, and we want 3 permits, we take them from storedPermits,
+   * reducing them to 7.0, and compute the throttling for these as a call to
+   * storedPermitsToWaitTime(storedPermits = 10.0, permitsToTake = 3.0), which will
+   * evaluate the integral of the function from 7.0 to 10.0.
+   *
+   * Using integrals guarantees that the effect of a single acquire(3) is equivalent
+   * to { acquire(1); acquire(1); acquire(1); }, or { acquire(2); acquire(1); }, etc,
+   * since the integral of the function in [7.0, 10.0] is equivalent to the sum of the
+   * integrals of [7.0, 8.0], [8.0, 9.0], [9.0, 10.0] (and so on), no matter
+   * what the function is. This guarantees that we handle correctly requests of varying weight
+   * (permits), /no matter/ what the actual function is - so we can tweak the latter freely.
+   * (The only requirement, obviously, is that we can compute its integrals).
+   *
+   * Note well that if, for this function, we chose a horizontal line, at height of exactly
+   * (1/QPS), then the effect of the function is non-existent: we serve storedPermits at
+   * exactly the same cost as fresh ones (1/QPS is the cost for each). We use this trick later.
+   *
+   * If we pick a function that goes /below/ that horizontal line, it means that we reduce
+   * the area of the function, thus time. Thus, the RateLimiter becomes /faster/ after a
+   * period of underutilization. If, on the other hand, we pick a function that
+   * goes /above/ that horizontal line, then it means that the area (time) is increased,
+   * thus storedPermits are more costly than fresh permits, thus the RateLimiter becomes
+   * /slower/ after a period of underutilization.
+   *
+   * Last, but not least: consider a RateLimiter with rate of 1 permit per second, currently
+   * completely unused, and an expensive acquire(100) request comes. It would be nonsensical
+   * to just wait for 100 seconds, and /then/ start the actual task. Why wait without doing
+   * anything? A much better approach is to /allow/ the request right away (as if it was an
+   * acquire(1) request instead), and postpone /subsequent/ requests as needed. In this version,
+   * we allow starting the task immediately, and postpone by 100 seconds future requests,
+   * thus we allow for work to get done in the meantime instead of waiting idly.
+   *
+   * This has important consequences: it means that the RateLimiter doesn't remember the time
+   * of the _last_ request, but it remembers the (expected) time of the _next_ request. This
+   * also enables us to tell immediately (see tryAcquire(timeout)) whether a particular
+   * timeout is enough to get us to the point of the next scheduling time, since we always
+   * maintain that. And what we mean by "an unused RateLimiter" is also defined by that
+   * notion: when we observe that the "expected arrival time of the next request" is actually
+   * in the past, then the difference (now - past) is the amount of time that the RateLimiter
+   * was formally unused, and it is that amount of time which we translate to storedPermits.
+   * (We increase storedPermits with the amount of permits that would have been produced
+   * in that idle time). So, if rate == 1 permit per second, and arrivals come exactly
+   * one second after the previous, then storedPermits is _never_ increased -- we would only
+   * increase it for arrivals _later_ than the expected one second.
+   */
+
+  /**
+   * This implements the following function:
+   *
+   *          ^ throttling
+   *          |
+   * 3*stable +                  /
+   * interval |                 /.
+   *  (cold)  |                / .
+   *          |               /  .   <-- "warmup period" is the area of the trapezoid between
+   * 2*stable +              /   .       halfPermits and maxPermits
+   * interval |             /    .
+   *          |            /     .
+   *          |           /      .
+   *   stable +----------/  WARM . }
+   * interval |          .   UP  . } <-- this rectangle (from 0 to maxPermits, and
+   *          |          . PERIOD. }     height == stableInterval) defines the cooldown period,
+   *          |          .       . }     and we want cooldownPeriod == warmupPeriod
+   *          |---------------------------------> storedPermits
+   *              (halfPermits) (maxPermits)
+   *
+   * Before going into the details of this particular function, let's keep in mind the basics:
+   * 1) The state of the RateLimiter (storedPermits) is a vertical line in this figure.
+   * 2) When the RateLimiter is not used, this goes right (up to maxPermits)
+   * 3) When the RateLimiter is used, this goes left (down to zero), since if we have storedPermits,
+   *    we serve from those first
+   * 4) When _unused_, we go right at the same speed (rate)! I.e., if our rate is
+   *    2 permits per second, and 3 unused seconds pass, we will always save 6 permits
+   *    (no matter what our initial position was), up to maxPermits.
+   *    If we invert the rate, we get the "stableInterval" (interval between two requests
+   *    in a perfectly spaced out sequence of requests of the given rate). Thus, if you
+   *    want to see "how much time it will take to go from X storedPermits to X+K storedPermits?",
+   *    the answer is always stableInterval * K. In the same example, for 2 permits per second,
+   *    stableInterval is 500ms. Thus to go from X storedPermits to X+6 storedPermits, we
+   *    require 6 * 500ms = 3 seconds.
+   *
+   *    In short, the time it takes to move to the right (save K permits) is equal to the
+   *    rectangle of width == K and height == stableInterval.
+   * 4) When _used_, the time it takes, as explained in the introductory class note, is
+   *    equal to the integral of our function, between X permits and X-K permits, assuming
+   *    we want to spend K saved permits.
+   *
+   *    In summary, the time it takes to move to the left (spend K permits), is equal to the
+   *    area of the function of width == K.
+   *
+   * Let's dive into this function now:
+   *
+   * When we have storedPermits <= halfPermits (the left portion of the function), then
+   * we spend them at the exact same rate that
+   * fresh permits would be generated anyway (that rate is 1/stableInterval). We size
+   * this area to be equal to _half_ the specified warmup period. Why we need this?
+   * And why half? We'll explain shortly below (after explaining the second part).
+   *
+   * Stored permits that are beyond halfPermits, are mapped to an ascending line, that goes
+   * from stableInterval to 3 * stableInterval. The average height for that part is
+   * 2 * stableInterval, and is sized appropriately to have an area _equal_ to the
+   * specified warmup period. Thus, by point (4) above, it takes "warmupPeriod" amount of time
+   * to go from maxPermits to halfPermits.
+   *
+   * BUT, by point (3) above, it only takes "warmupPeriod / 2" amount of time to return back
+   * to maxPermits, from halfPermits! (Because the trapezoid has double the area of the rectangle
+   * of height stableInterval and equivalent width). We decided that the "cooldown period"
+   * time should be equivalent to "warmup period", thus a fully saturated RateLimiter
+   * (with zero stored permits, serving only fresh ones) can go to a fully unsaturated
+   * (with storedPermits == maxPermits) in the same amount of time it takes for a fully
+   * unsaturated RateLimiter to return to the stableInterval -- which happens in halfPermits,
+   * since beyond that point, we use a horizontal line of "stableInterval" height, simulating
+   * the regular rate.
+   *
+   * Thus, we have figured all dimensions of this shape, to give all the desired
+   * properties:
+   * - the width is warmupPeriod / stableInterval, to make cooldownPeriod == warmupPeriod
+   * - the slope starts at the middle, and goes from stableInterval to 3*stableInterval so
+   *   to have halfPermits being spend in double the usual time (half the rate), while their
+   *   respective rate is steadily ramping up
+   */
+  static final class SmoothWarmingUp extends SmoothRateLimiter {
+    private final long warmupPeriodMicros;
+    /**
+     * The slope of the line from the stable interval (when permits == 0), to the cold interval
+     * (when permits == maxPermits)
+     */
+    private double slope;
+    private double halfPermits;
+  
+    SmoothWarmingUp(SleepingStopwatch stopwatch, long warmupPeriod, TimeUnit timeUnit) {
+      super(stopwatch);
+      this.warmupPeriodMicros = timeUnit.toMicros(warmupPeriod);
+    }
+  
+    @Override
+    void doSetRate(double permitsPerSecond, double stableIntervalMicros) {
+      double oldMaxPermits = maxPermits;
+      maxPermits = warmupPeriodMicros / stableIntervalMicros;
+      halfPermits = maxPermits / 2.0;
+      // Stable interval is x, cold is 3x, so on average it's 2x. Double the time -> halve the rate
+      double coldIntervalMicros = stableIntervalMicros * 3.0;
+      slope = (coldIntervalMicros - stableIntervalMicros) / halfPermits;
+      if (oldMaxPermits == Double.POSITIVE_INFINITY) {
+        // if we don't special-case this, we would get storedPermits == NaN, below
+        storedPermits = 0.0;
+      } else {
+        storedPermits = (oldMaxPermits == 0.0)
+            ? maxPermits // initial state is cold
+            : storedPermits * maxPermits / oldMaxPermits;
+      }
+    }
+  
+    @Override
+    long storedPermitsToWaitTime(double storedPermits, double permitsToTake) {
+      double availablePermitsAboveHalf = storedPermits - halfPermits;
+      long micros = 0;
+      // measuring the integral on the right part of the function (the climbing line)
+      if (availablePermitsAboveHalf > 0.0) {
+        double permitsAboveHalfToTake = min(availablePermitsAboveHalf, permitsToTake);
+        micros = (long) (permitsAboveHalfToTake * (permitsToTime(availablePermitsAboveHalf)
+            + permitsToTime(availablePermitsAboveHalf - permitsAboveHalfToTake)) / 2.0);
+        permitsToTake -= permitsAboveHalfToTake;
+      }
+      // measuring the integral on the left part of the function (the horizontal line)
+      micros += (stableIntervalMicros * permitsToTake);
+      return micros;
+    }
+  
+    private double permitsToTime(double permits) {
+      return stableIntervalMicros + permits * slope;
+    }
+  }
+
+  /**
+   * This implements a "bursty" RateLimiter, where storedPermits are translated to
+   * zero throttling. The maximum number of permits that can be saved (when the RateLimiter is
+   * unused) is defined in terms of time, in this sense: if a RateLimiter is 2qps, and this
+   * time is specified as 10 seconds, we can save up to 2 * 10 = 20 permits. 
+   */
+  static final class SmoothBursty extends SmoothRateLimiter {
+    /** The work (permits) of how many seconds can be saved up if this RateLimiter is unused? */
+    final double maxBurstSeconds; 
+    
+    SmoothBursty(SleepingStopwatch stopwatch, double maxBurstSeconds) {
+      super(stopwatch);
+      this.maxBurstSeconds = maxBurstSeconds;
+    }
+  
+    @Override
+    void doSetRate(double permitsPerSecond, double stableIntervalMicros) {
+      double oldMaxPermits = this.maxPermits;
+      maxPermits = maxBurstSeconds * permitsPerSecond;
+      if (oldMaxPermits == Double.POSITIVE_INFINITY) {
+        // if we don't special-case this, we would get storedPermits == NaN, below
+        storedPermits = maxPermits;
+      } else {
+        storedPermits = (oldMaxPermits == 0.0)
+            ? 0.0 // initial state
+            : storedPermits * maxPermits / oldMaxPermits;
+      }
+    }
+  
+    @Override
+    long storedPermitsToWaitTime(double storedPermits, double permitsToTake) {
+      return 0L;
+    }
+  }
+
+  /**
+   * The currently stored permits.
+   */
+  double storedPermits;
+
+  /**
+   * The maximum number of stored permits.
+   */
+  double maxPermits;
+
+  /**
+   * The interval between two unit requests, at our stable rate. E.g., a stable rate of 5 permits
+   * per second has a stable interval of 200ms.
+   */
+  double stableIntervalMicros;
+
+  /**
+   * The time when the next request (no matter its size) will be granted. After granting a
+   * request, this is pushed further in the future. Large requests push this further than small
+   * requests.
+   */
+  private long nextFreeTicketMicros = 0L; // could be either in the past or future
+
+  private SmoothRateLimiter(SleepingStopwatch stopwatch) {
+    super(stopwatch);
+  }
+
+  @Override
+  final void doSetRate(double permitsPerSecond, long nowMicros) {
+    resync(nowMicros);
+    double stableIntervalMicros = SECONDS.toMicros(1L) / permitsPerSecond;
+    this.stableIntervalMicros = stableIntervalMicros;
+    doSetRate(permitsPerSecond, stableIntervalMicros);
+  }
+
+  abstract void doSetRate(double permitsPerSecond, double stableIntervalMicros);
+
+  @Override
+  final double doGetRate() {
+    return SECONDS.toMicros(1L) / stableIntervalMicros;
+  }
+
+  @Override
+  final long queryEarliestAvailable(long nowMicros) {
+    return nextFreeTicketMicros;
+  }
+
+  @Override
+  final long reserveEarliestAvailable(int requiredPermits, long nowMicros) {
+    resync(nowMicros);
+    long returnValue = nextFreeTicketMicros;
+    double storedPermitsToSpend = min(requiredPermits, this.storedPermits);
+    double freshPermits = requiredPermits - storedPermitsToSpend;
+
+    long waitMicros = storedPermitsToWaitTime(this.storedPermits, storedPermitsToSpend)
+        + (long) (freshPermits * stableIntervalMicros);
+
+    this.nextFreeTicketMicros = nextFreeTicketMicros + waitMicros;
+    this.storedPermits -= storedPermitsToSpend;
+    return returnValue;
+  }
+
+  /**
+   * Translates a specified portion of our currently stored permits which we want to
+   * spend/acquire, into a throttling time. Conceptually, this evaluates the integral
+   * of the underlying function we use, for the range of
+   * [(storedPermits - permitsToTake), storedPermits].
+   *
+   * <p>This always holds: {@code 0 <= permitsToTake <= storedPermits}
+   */
+  abstract long storedPermitsToWaitTime(double storedPermits, double permitsToTake);
+
+  private void resync(long nowMicros) {
+    // if nextFreeTicket is in the past, resync to now
+    if (nowMicros > nextFreeTicketMicros) {
+      storedPermits = min(maxPermits,
+          storedPermits + (nowMicros - nextFreeTicketMicros) / stableIntervalMicros);
+      nextFreeTicketMicros = nowMicros;
+    }
+  }
+}
diff --git a/guava/src/com/google/common/util/concurrent/Striped.java b/guava/src/com/google/common/util/concurrent/Striped.java
index 7459262..a8bc379 100644
--- a/guava/src/com/google/common/util/concurrent/Striped.java
+++ b/guava/src/com/google/common/util/concurrent/Striped.java
@@ -16,10 +16,9 @@
 
 package com.google.common.util.concurrent;
 
-import static com.google.common.base.Objects.firstNonNull;
-
 import com.google.common.annotations.Beta;
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableList;
@@ -430,7 +429,7 @@
       }
       L created = supplier.get();
       existing = locks.putIfAbsent(index, created);
-      return firstNonNull(existing, created);
+      return MoreObjects.firstNonNull(existing, created);
     }
 
     @Override public int size() {
diff --git a/guava/src/com/google/common/util/concurrent/Uninterruptibles.java b/guava/src/com/google/common/util/concurrent/Uninterruptibles.java
index 79d7598..d0f80d7 100644
--- a/guava/src/com/google/common/util/concurrent/Uninterruptibles.java
+++ b/guava/src/com/google/common/util/concurrent/Uninterruptibles.java
@@ -22,9 +22,11 @@
 import com.google.common.base.Preconditions;
 
 import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CancellationException;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
+import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
@@ -284,6 +286,46 @@
     }
   }
 
+  /**
+   * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit)
+   * tryAcquire(1, timeout, unit)} uninterruptibly.
+   *
+   * @since 18.0
+   */
+  public static boolean tryAcquireUninterruptibly(
+      Semaphore semaphore, long timeout, TimeUnit unit) {
+    return tryAcquireUninterruptibly(semaphore, 1, timeout, unit);
+  }
+
+  /**
+   * Invokes {@code semaphore.}{@link Semaphore#tryAcquire(int, long, TimeUnit)
+   * tryAcquire(permits, timeout, unit)} uninterruptibly.
+   *
+   * @since 18.0
+   */
+  public static boolean tryAcquireUninterruptibly(
+      Semaphore semaphore, int permits, long timeout, TimeUnit unit) {
+    boolean interrupted = false;
+    try {
+      long remainingNanos = unit.toNanos(timeout);
+      long end = System.nanoTime() + remainingNanos;
+
+      while (true) {
+        try {
+          // Semaphore treats negative timeouts just like zero.
+          return semaphore.tryAcquire(permits, remainingNanos, NANOSECONDS);
+        } catch (InterruptedException e) {
+          interrupted = true;
+          remainingNanos = end - System.nanoTime();
+        }
+      }
+    } finally {
+      if (interrupted) {
+        Thread.currentThread().interrupt();
+      }
+    }
+  }
+
   // TODO(user): Add support for waitUninterruptibly.
 
   private Uninterruptibles() {}
diff --git a/guava/src/com/google/common/xml/XmlEscapers.java b/guava/src/com/google/common/xml/XmlEscapers.java
index 357c417..563d620 100644
--- a/guava/src/com/google/common/xml/XmlEscapers.java
+++ b/guava/src/com/google/common/xml/XmlEscapers.java
@@ -28,7 +28,7 @@
  * autoescaping. For example, consider <a href="http://www.xom.nu/">XOM</a> or
  * <a href="http://www.jdom.org/">JDOM</a>.
  *
- * <p><b>Note</b>: Currently the escapers provided by this class do not escape
+ * <p><b>Note:</b> Currently the escapers provided by this class do not escape
  * any characters outside the ASCII character range. Unlike HTML escaping the
  * XML escapers will not escape non-ASCII characters to their numeric entity
  * replacements. These XML escapers provide the minimal level of escaping to
@@ -62,7 +62,7 @@
    * <a href="http://www.w3.org/TR/2008/REC-xml-20081126/#syntax">2.4</a> of the
    * XML specification.
    *
-   * <p><b>Note</b>: Double and single quotes are not escaped, so it is <b>not
+   * <p><b>Note:</b> Double and single quotes are not escaped, so it is <b>not
    * safe</b> to use this escaper to escape attribute values. Use
    * {@link #xmlContentEscaper} if the output can appear in element content or
    * {@link #xmlAttributeEscaper} in attribute values.
diff --git a/guava/src/com/google/thirdparty/publicsuffix/PublicSuffixPatterns.java b/guava/src/com/google/thirdparty/publicsuffix/PublicSuffixPatterns.java
index c231159..b12c150 100644
--- a/guava/src/com/google/thirdparty/publicsuffix/PublicSuffixPatterns.java
+++ b/guava/src/com/google/thirdparty/publicsuffix/PublicSuffixPatterns.java
@@ -42,7 +42,7 @@
 
   /** If a hostname is contained as a key in this map, it is a public suffix. */
   public static final ImmutableMap<String, PublicSuffixType> EXACT =
-      TrieParser.parseTrie("a&12oa08--nx?2eyh3la2ckx--nx?32wqq1--nx?6&1f4a3abgm--nx?lbgw--nx??883xnn--nx?b!.&asnu?gro?ibnu?lim?moc?oc?sr?ten?ude?vog???c!.&b&a?m?n??c&b?g?q??ep?fn?k&s?y??ln?no?oc,sn?t&n?opsgolb,?un??s??d&neit?om??g?hskihs?i&dem?sa??jnin?k&dov?usto??l!.&c,gro?moc?ofni?rep?t&en?ni??ude?vog???m!.&ca?gro?oc?sserp?ten?vog??ahokoy?e00sf7vqn--nx??n!.&ac?cc?eman?gro?ibom?loohcs?moc?ni?o&c?fni?rp??r&d?o??s&u?w??vt?xm???p!.&bog?ca?d&em?ls??g&ni?ro??mo&c?n??oba?ten?ude??g7hyabgm--nx?ra!.&461e?6pi?iru?nru?rdda-ni?siri????q!.&eman?gro?hcs?lim?moc?ten?ude?vog???r&emac?f4a3abgm--nx??s!.&bup?dem?gro?hcs?moc?ten?ude?vog??ac??u!.&a&cinniv?emirc?i&hzhziropaz?stynniv??s&edo?sedo??tlay?vatlop??bs?cinimod?d&argovorik?o!roghzu???e&hzhziropaz?nvir?t??fi?g&l?ro??hk?i&stvinrehc?ykstynlemhk??k&c?m?s&nagul?t&enod?ul??v&iknarf-onavi?orteporp&end?ind?????l&iponret?opotsa&bes?ves??p??m&k?oc?s?yrk??n&c?d?i?osrehk?v?ylov??o&c?nvor??p&d?p?z??r&c?imotihz?k?ymotyhz??sk?t&en?l?z??ude?v&c?e&alokin?ik??i&alokym?hinrehc?krahk?vl?yk??k?l?o&g!inrehc??krahk??r??y&ikstinlemhk?mus?s&akrehc?sakrehc?tvonrehc???zu???v?waniko?x&a?iacal??yogan??b&125qhx--nx?3jca1d--nx?4&6&1rfz--nx?qif--nx??96rzc--nx??a&0dc4xbgm--nx?c?her??b!.&erots?gro?moc?ofni?ten?ude?vog?zib???cs?dhesa08--nx?g?l!.&gro?moc?ten?ude?vog???s!.&gro?moc?ten?ude?vog???u&lc?p???c&1&1q54--nx?hbgw--nx??2e9c2czf--nx?4byj9q--nx?9jr&b&2h--nx?54--nx?9s--nx??ceg--nx??a!.&gro?lim?moc?ten?ude?vog??3a09--nx??bf76a0c7ylqbgm--nx?c!.&gnipparcs,revres-emag,s&otohpym,seccaptf,??0atf7b45--nx?a1l--nx??e!.&21k?bog?dem?gro?lim?moc?nif?o&fni?rp??ten?ude?vog??beuq??l!.&gro?moc?oc?ten?ude?vog???m!.&mt?ossa???n!.ossa??s!.&gro?moc?ten?ude?vog???t!w??v!.&gro?lim?moc?ten?ude?vog???yn??d&2urzc--nx?3&1wrpk--nx?c9jrcpf--nx??5xq55--nx?75yrpk--nx?a!.mon?d??b2babgm--nx?c!.vog?g9a2g2b0ae0chclc--nx??e&r!k??sopxe?timil?w??g?i!.&ased?bew?ca?hcs?lim?o&c?g??ro?ten?ym?zib??b??liub?m?nal!raas??orp?rk?s!.&dem?gro?moc?ofni?ten?ude?v&og?t????t!.topsgolb,?za5cbgn--nx??e&17a1hbbgm--nx?2a6a1b6b1i--nx?707b0e3--nx?a!.&ca?gro?hcs?lim?oc?ten?vog???b!.&ca?topsgolb,??c&nad?rofria??d!.&edaregtmueart,keegnietsi,moc,n&esgnutiel,iemtsi,?topsgolb,zten&mitbel,sadtretteuf,??art?iug?on--nx??e!.&bil?dem?eif?gro?irp?kiir?moc?pia?ude?vog??ffoc?gg?rged??fil?g!.&gro?lim?moc?t&en?vp??ude?vog??ayov?elloc?nahcxe??i!.&topsgolb,vog???j!.&gro?oc?ten???kib?luhcs?m!.&ca?gro?oc?sti?ten?ude?v&irp?og???an!.&reh.togrof,sih.togrof,??em?w??n!goloc?oz??om?p!.&bog?gro?lim?mo&c?n??ten?ude??irg??r!.&mo&c?n??ossa?topsgolb,?eh??s!.&a?b!ibnal?rofmok??c!a??d!b?n&arb?ubroflanummok???e?f?g!ro??h!f??i!trap??k!shf??l?m!t??n!mygskurbrutan??o?p!p??r?s!serp??t!opsgolb,?u?vhf?w?x!uvmok??y?z??ael?ier?roh?uoh??t&atse?ov?utitsni??u&lb?qituob??v!.&21e?bew?gro?lim?moc?o&c?fni??ten?ude?vog???xul??f&7vqn--nx?a!.&gro?moc?ten?ude?vog???b!.vog?wa9bgm--nx??c!.topsgolb,a1p--nx??g?n!.&bew?cer?erots?m&oc?rif??ofni?re&hto?p??stra?ten???p!.&gro?moc?ude???t!w??w??g&2&4wq55--nx?8zrf6--nx??3&44sd3--nx?91w6j--nx??455ses--nx?69vqhr--nx?78a4d5a4prebgm--nx?a!.&gro?mo&c?n??oc?ten???b!.&0?1?2?3?4?5?6?7?8?9?a?b?c?d?e?f?g?h?i?j?k?l?m?n?o?p?q?r?s?t?u?v?w?x?y?z???c!za9a0cbgm--nx??e!.&eman?gro?ics?lim?moc?nue?ten?ude?vog???g!.&gro?oc?ten???k!.&gro?lim?moc?ten?ude?vog???m!.&drp?gro?lim?m&o&c?n??t??ude?vog???n!.&eman?gro?hcs?ibom?lim?moc?ten?ude?vog??aw?i!bmulp?h&sif?tolc??kooc?n&aelc?iart??re&enigne?tac??t&ad?ekram?hgil?lusnoc?ov???o??r&o!.&az,d&ab-yrev-si,e&sufnocsim,vas-si,?nuof-si,oog-yrev-si,?e&a,cin-yrev-si,las-4-ffuts,m&-morf,agevres,ohruoyslles,?nozdop,rehwongniogyldlob,t&adidnac-a-si,is&-ybboh,golb,???fehc-a-si,golbymdaer,keeg-a&-si,si,?live-yrev-si,naf&s&citlec-a-si,niurb-a-si,tap-a-si,?xos-a-si,?ojodsnd,p&ifles,ohbew,tfe&moh,vres,??resu-xunil-a-si,s&aila&nyd,snd,?bbevres,nd&emoh,golb,mood,nyd:.&emoh,og,?,rvd,tog,?sa-skcik,u,?t&e&ews-yrev-si,nretni&ehtfodne,fodne,??hgink-a-si,s&ixetn&od,seod,?o&h-emag,l-si,???x&inuemoh,unilemoh,???ubmah??s!.&gro?moc?rep?t&en?opsgolb,?ude?vog???t?u!.&c&a?s??en?gro?moc?o&c?g??ro???v!a1c--nx??wsa08--nx??h&0ee5a3ld2ckx--nx?4wc3o--nx?8a7maabgm--nx?b!.&gro?moc?ten?ude?vog???c!.topsgolb,ir?ruhc?taw??d0sbgp--nx?g!.&gro?lim?moc?ude?vog???m!a1j--nx??p!.&gro?i?lim?moc?ogn?ten?ude?vog???s!.&gro?lim?moc?ten?vog??a&c?nom??if??t!.&ca?im?ni?o&c?g??ro?ten???vo?zb??i&3tupk--nx?7a0oi--nx?a!.&ffo?gro?moc?ten??1p--nx??b!.&gro?moc?oc?ro?ude??om??c!.&ayb-tropora--nx?ca?d&e?m??esserp?gro?moc?o&c?g?ssa??ro?t&en?ni?roporéa??ude?vuog???f!.&dnala?iki,topsgolb,??g!.&d&om?tl??gro?moc?ude?vog???hcra?k!.&gro?moc?ofni?ten?ude?vog?zib??b4gc--nx?iw?uzus??l?maim?nim?s!ed??v!.&21k?gro?moc?oc?ten???wik?xarp??j&8da1tabbgl--nx?b!.&ossa?topsgolb,uaerrab?vuog???d?s?t!.&bew?c&a?in??eman?gro?lim?moc?o&c?g??t&en?ni?set??ude?vog?zib????k&ca&bdeef?lb??d!.topsgolb,?h!.&a&4ya0cu--nx?5wqmg--nx??b3qa0do--nx?d&2&2svcw--nx?3rvcl--nx??5xq55--nx??g&a0nt--nx?la0do--nx?ro??i&050qmg--nx?7a0oi--nx?xa0km--nx??m&1qtxm--nx?oc??npqic--nx?t&en?opsgolb,?ude?v&di?og?ta0cu--nx??xva0fz--nx?人&个?個?箇??司公?府政?絡&網?网??織&組?组??织&組?组??络&網?网??育&敎?教???n??l!.&bew?cos?dtl?gro?hcs?letoh?moc?nssa?ogn?prg?t&en?ni??ude?vog???m!.&eman?fni?gro?moc?ten?ude?vog???ni!l?p??p!.&b&ew?og??gro?kog?m&af?oc??nog?ofni?pog?sog?ten?ude?vog?zib???row!ten??s!.topsgolb,?t?u.oc.topsgolb,?l&a!.&gro?lim?moc?ten?ude?vog??g?ic&nanif?os??noitanretni?ti&gid?pac???c!.&bog?lim?oc?vog???e&geips?t?vart??f8f&pbgo--nx?tbgm--nx??g?i&.oc.topsgolb,a&f?me??m??lihmailliw?m!.&esserp?gro?moc?ten?ude?v&og?uog????n!.&oc,topsgolb,vb??o??o&btuf?oc??p!.&a&cin&diws?gel??d&g?ortso?urawon??i&dem?mraw?nydg??k&elo&guld?rtso??slopolam?tsu?ytsyrut??l&ip?o&kzs?w&-awolats?oksnok????nimg?rog&-ai&bab?nelej??j?z??syn?tsaim?w&a&l&eib?i?o??zsraw??onamil??z&eiwolaib?mol???c&e&iw&alselob?o&nsos?rtso???le&im?zrogz???orw?p?ri??d&em?ia?ragrats??e&c&i&lrog?w&ilg?o&hc&arats?orp??klop?tak????ldeis?yzreibok??i&csjuoniws?ksromop?saldop??l&ahdop?opo??n&apokaz?ob&6?m???tatselaer?z&romop?swozam???g&alble?ezrbo&lok?nrat??ro??hcyzrblaw?i&csomohcurein?grat?klawus??k&e&rut?walcolw??inbyr?le?o&nas?tsylaib??rob&el?lam??s&als?jazel?nadg?puls?rowezrp???l&colw?e&r?vart??i&am?m???m&o&c?dar?n?tyb??s&g?iruot??t!a???n&a&gaz?nzop??i&bul?cezczs?molow?nok?zd&eb?obeiws???uleiw?y&tzslo?z&rtek?seic????o&c,fni?gn?k&celo?zdolk??lkan?n&leim?pek?t&uk?yzczs??z&copo?eing?rowaj???rga?tua?w&ejarg?ogarm???p&elks?klwwortso?ohs??romophcaz?sos?t&aiwop?en!esu??opos?ra?sezc??ude?v&irp?og!.&ap?gu?mu?o&p?s?wtsorats??rs?w&opu?u?????w&a&l&corw?sizdow??w??o&golg?k&ark?ul?zsurp??r&az?gew??tsugua?z&coks?sezr????xes?y&buzsak?d&azczseib?ikseb??hcyt?n&jes?lod-zreimizak??pal?r&ogt?uzam??walup?zutrak??z&am-awar?c&aprak?iwol?zsogdyb??dalezc?ib?s&i&lak?p??uklo?????s!.&gro?moc?ten?ude?vog???t!.vog??x3b689qq6--nx??m&00tsb3--nx?1qtxm--nx?a!cbew?rirhs??b!.&gro?moc?ten?ude?vog???c!.vog??d!.&gro?moc?ten?ude?vog???f!i??g?h?i!.&ca?gro?moc?oc!.&clp?dtl???t&en?t??vt??k?rbg4--nx??k!.&drp?e&rianiretev?sserp??gro?lim?m&o&c?n??t??nicedem?ossa?pooc?s&eriaton?neicamrahp?sa??ude?v&og?uog????o!.&dem?gro?m&oc?uesum??o&c?rp??ten?ude?vog??c!.&a&c&-morf,irfa,?g&-morf,oy-sehcaet,?i-morf,m&-morf,all&-a-si,amai,??p&-morf,c-a-si,?s,v-morf,w-morf,z,?b&ew-sndnyd,g,?c&d-morf,n-morf,q,s-morf,?d&e&ifitrec-&si,ton-si,?llortnocduolc,?i-morf,m-morf,n&-morf,abeht-htiw-si,?s-morf,uolc&hr,smetsystuo,??e&ciffo-sndnyd,d:-morf,ocelgoog,,erf-sndnyd,i&hcet-a-si,p-sekil,?lgooghtiw,m&ina-otni-si,oh-&sndnyd,ta-sndnyd,??n&-morf,og-si,?rihcec,s:run-a-si,,t&i&nuarepo,s-ybboh,?omer-sndnyd,?v&als-elcibuc-a-si,itavresnoc-a-si,??fehc-a-si,golb&-sndnyd,sihtsetirw,?h&n-morf,o-morf,?i&h-morf,kiw-sndnyd,m-morf,r-morf,w-morf,?jn-morf,k&a-morf,cils-si,eeg-a&-si,si,?latsnaebcitsale,o-morf,row-&sndnyd,ta-sndnyd,?u,?l&a&-morf,rebil-a-si,?f-morf,i&-morf,am-sndnyd,?ru-&elpmis,taen,?ssukoreh,?mn-morf,n&a&cilbuper-a-si,f&-sllub-a-si,racsan-a-si,?i&cisum-a-si,ratrebil-a-si,??c,eerg-a-si,i-morf,m-morf,o&isam-al-a-tse,rtap-el-tse,siam-al-a-tse,?pj,t-morf,?o&c,jodsnd,m-morf,n,r,?p&i&-sndnyd,fles,ymteg,?pa&lortnocduolc,ukoreh,??r&a:-morf,tskcor-a-si,,b,e&enigne-na-si,ggolb-a-si,h&caet-a-si,pargotohp-a-si,?krow-drah-a-si,n&gised-a-si,ia&rtlanosrep-a-si,tretne-na-si,??p&acsdnal-a-si,eekkoob-a-si,?retac-a-si,tn&iap-a-si,uh-a-si,?vres-sndnyd,y&alp-a-si,wal-a-si,??g,k,o&-morf,sivdalaicnanif-a-si,tc&a-na-si,od-a-si,??p-morf,u&as-o-nyd,eugolb-nom-tse,??s&aila&nyd,snd,?bbevres,cip-sndnyd,e&lahw-eht-sevas,mag-otni-si,?ipaelgoog,k-morf,m-morf,n&d&golb,mood,tog,?ootrac-otni-si,?r&ac-otni-si,etsohmaerd,?se&l-rof-slles,rtca-na-si,?u,wanozama.&1-&etupmoc:.&1-z,2-z,?,ts&ae&-&as-&3s,etisbew-3s,?su:-etisbew-3s,,?ht&ron-pa-&3s,etisbew-3s,?uos-pa-&3s,etisbew-3s,???ew-&su-&3s,etisbew-3s,?ue-&3s,etisbew-3s,?vog-su-&3s,etisbew-3s,spif-3s,????2-ts&aehtuos-pa-&3s,etisbew-3s,?ew-su-&3s,etisbew-3s,??3s,ble,etupmoc:.&1-ts&ae&-as,ht&ron-pa,uos-pa,??ew-&su,ue,vog-su,??2-ts&aehtuos-pa,ew-su,??,??t&arcomed-a-si,c-morf,eel&-si,rebu-si,?m-morf,n&atnuocca-na-si,e&duts-a-si,r-ot-ecaps,tnocresubuhtig,??ops&edoc,golb,ppa,?si&hcrana-&a-si,na-si,?laicos-a-si,pareht-a-si,tra-na-si,xetn&od,seod,??u&-morf,nyekcoh-asi,?v-morf,?u&-rof-slles,e,h,oynahtretramssi,r:ug-a-si,,?v&n-morf,w-morf,?x&em,inuemoh,obaniateb,t-morf,unilemoh,?y&dnacsekil,k-morf,u,w-morf,????p?raf?s?t!.&gro?lim?mo&c?n??oc?ten?ude?vog???uesum!.&a&92chg-seacinumocelet-e-soierroc--nx?atnav?c&i&aduj?rfatsae??rollam??d&anac?enomaledasac?irolf??e&raaihpledalihp?srednu??g&hannavas?oonattahc??hamo?i&auhsu?bmuloc!hsitirb??dem?groeg?hpledalihp?l&artsua?etalif??n&igriv?rofilac??ssur?tsonod??ksa&la?rben??l&lojal?q-snl--nx?uossim!trof???m&a&bala?nap??enic?o&m?r???n&a&cirema?idni??edasap?ilorachtuos?olecrab??r&abrabatnas?ezzivs??su?t&nalta?osennim??zalp??c&dnotgnihsaw?ebeuq?i&depolcycne?ficap?hpargonaeco?lbup?sum?t&carporihc?lec?naltadim??vu??yn??d&a&dhgab?etsmraf?m?orliar??i&rdam?ulegnedleeb??leif?n&a!l&gne?nif?ragyduj?t&ocs?rop??yram???u&brofsdgybmeh?osdnaegami???r&augria?ofxo???e&c&a&l&ap?phtrib??ps??n&a&lubma?tsiser??e&fedlatsaoc?gilletni?ics!foyrotsih????pein?rof??d&nukneklov?revasem??e&rt?tsurt??f&atnas?ildliw??g&a&lliv?tireh!lanoitan???dirbmac?rog??i&cnum?nollaw??koorbrehs?l&ab?bib?cycrotom?i&ssim?txet??oks?tsac??m&affollah?it!iram??utsoc??n&golos?ilno?recul??r&a&uqs?waled!foetats???i&hs&acnal?kroy?pmahwen??otsih??omitlab?ut&an?cetihcra?inruf?luc!irga?su???vuol??s&abatad?iacnarf?sius?uoh!lum???t&a&locohc?rak?ts!e!yrtnuoc!su?????imesoy?tevroc??u&qihpargonaeco?velleb??vit&caretni?omotua???f&iuj?ohgrub??g&n&i&dliub?ginerevmuesum?kiv?lahw?nim?peekemit?vil??ulmmastsnuk??orf?r&eb&merun?nr&ats?eun???u&b&ierf?le?m&ah?uan??ram?s&mailliw!lainoloc??naitsirhc?retepts??zlas??ob&irf?mexul?????h&atu?c&raeser?sirotsih?uot??g&ea1h--nx?rubsttip??si&tirb?wej??t&laeh?ro&n?wtrof??uo&mnom?y????i&d6glbhbd9--nx?iawah?k&nisleh?s??lad!rodavlas??sissa?tannicnic??k&c&nivleeg?olc!-dna-hctaw?dnahctaw???fj?inebis?l&is?ofron??na&rfenna?t??oorbnarc?r&am&ned?reiets??oy!wen????l&a&ci&dem?golo&eahcra?meg?oz??natob?rotsih??ertnom?iromem?noita&cude?n??oc?rutluc?trop?utriv?van??e&nurb?s&ab?surb??utriv??i&artnogero?sarb??l&a&besab?hsnoegrus??e&hs?rdnevle??i&b?m!dniw????o&bup?ohcs?tsirb???m&a&dretsma?ets?h&netlehc?rud???ct?elas!urej??l&if?ohkcots?u??raf?silanruoj?u&esumyrotsihlarutan?ira&tenalp?uqa??terobra???n&a&c!irema!evitan???gihcim?i&dni?tpyge??mfoelsi?wehctaksas??e&d&alokohcs?ews?rag!cinatob?lacinatob?s&nerdlihc?u????gahnepoc?hcneum?laftsew?ppahcsnetewruutan?r&dlihc?ednaalv?hu!dnutamieh???sseig??gised!dn&atra?utsnuk???h&ab!nesie??ojts??i&lreb?tsua??l&eok?ocnil??n&ob?urbneohcs??o&dnol?gero?i&s&iv&dnadnuos?elet??nam??t&a&c&inummoc?ude!tra???dnuof?erc?i&cossa?va??kinummokelet?nissassa?r&belectsevrah?oproc?tsulli??silivic?t&nalp?s??vres&erp?noclatnemnorivne??zilivic??c&elloc?if-ecneics??ibihxe???ri?s&dnah?imaj?reffej?sral??t&erbepac?nilc?sob???r&e&b?dom?tsew?uab?zul??obredap??vahnebeok?wot??o&2a6v-seacinumoc--nx?ablib?c&edtra?ixemwen?sicnarfnas??elap?g&a&cihc?to??eidnas??i&cadnuf?diserp?ratno??llecitnom?mitiram?nirot?r&htna?ienajedoir???pohskrow?qari?r&aw!dloc?livic??dd?e&b&ma?yc??irrac?llimsiwel?naksiznarf?papswen?t&aeht?exe?nec!ecneics?larutluc?muesum?tra??s&ehc&nam?or??neum??upmoc???ia!nepo??obal?u&asonid?obal?takirak???s&a&l&g?l&ad?eh???xet??di&k?pardnarg??e&cneics!larutan??dnal?hcsi&deuj?rotsih!nizidem?rutan??selhcs??itinamuh?l&aw?egnasol?l&e&rutansecneics?xurb??iasrev???r&e&em?ugif??tsac??suohcirotsih?u&en?q&adac?itna!nacirema?su????õçacinumoc!elet-e-soierroc???gnirpsmlap?htab?i&lopanaidni?rap?uoltnias?xa??l&essurb?lod??mraeriflanoitan?n&a&blats?l??erdlihc?oi&snam?tacinummoc!elet-dna-stsop???äl??re&dnalf?lttes?mraf?nim?tnececneics??s&alg?erp??t&farc!dnastra??nalp?olip?ra!e&nif?vitaroced!su???su?xuaeb???u&b!muloc??cric???t&agilltrop?cejorp?dats?e&esum?kramnaidni??iorted?ne&m&elttes?norivne?piuqemraf??vnoc??oped?r&a!drib?enif?gttuts?hsiwej?kcor?n&acirema?ootrac??tamsa?yraropmetnoc??op&aes?snart?wen??ufknarf??s&a&cdaorb?octsae??ewhtuos?ilayol?nuk?r&ohnemled?uhlyram??urt???u&a&bgreb?etalpodaroloc??rmyc??w&ocsom?rn??x&esse?ineohp?nam?tas??y&a&bekaepasehc?w&etag?liar???camrahp?doc?e&hsub?l&ekreb?l&av!eniwydnarb??ort???n&dys?om??rrus?s&nreug?rejwen???golo&e&ahcra?g??motne?nh&cet?te??oz?po&rhtna?t??roh??hpargotohp?l&etalihp?imaf??m&edaca?onortsa??n&atob?yn??ps?r&a&ropmetnoc?tilim??e&diorbme?llag!tra??vocsid??lewej?nosameerf?otsih!dnaecneics?ecneics?gnivil!su??la&col?rutan??retupmoc?su??tsudnidnaecneics??spelipe?t&eicos!lacirotsih??i&nummoc?srevinu??nuoc???z&arg?iewhcs?nil?ojadab?urcatnas??моки?םילשורי????n&a!.&gro?moc?ten?ude??f?varac??c!.&ah?bh?c&a?s??d&5xq55--nx?g?s??eh?g&la0do--nx?ro??h&a?q?s??i&7a0oi--nx?h??j&b?f?t?x?z??kh?l&h?im?j??m&n?oc??n&h?l?s?y??om?qc?s&g?j??ten?ude?vog?wt?x&g?j?n?s??z&g?x??司公?絡網?络网???e&fuak?hctik?i&libommi?w??r!ednaalv??sier??g!.&ca?gro?moc?ten?ude?vog???h!.&bog?gro?lim?moc?ten?ude???i!.&c&a?in??dni?gro?lim?mrif?neg?oc?ser?t&en?opsgolb,?ude?vog??lreb??k!.&gro?ten?ude?vog???leok?m!.&cyn,gro?ude?vog???o&dnol?i&siv?t&a&cude?dnuof??curtsnoc???mrom?pq?siam??p!.&gro?oc?ten?ude?vog???reyab?s!.&gro?moc?osrep?tra?ude?v&inu?uog????t!.&dni?esnefed?gro?ltni?m&oc!nim??siruot??n&erut?if??o&fni?srep??sn&e?r??t&an?en!irga?ude??rnr??unr?vog???v!.&ca?eman?gro?htlaeh?moc?o&fni?rp??t&en?ni??ude?vog?zib???wot??o&76i4orfy--nx?a!.&bp?de?go?oc?ti?vg???b!.&bog?gro?lim?moc?t&en?ni??ude?v&og?t???olg??c!.&bew?cer?gro?lim?m&o&c?n??rif??ofni?stra?t&en?ni??ude?vog???d!.&b&ew?og??dls?gro?lim?moc?t&en?ra??ude?vog???e&c?dor??f!ni!.&e&gdelwonk-fo-l&errab,lerrab,?ht-skorg,rom-rof-ereh,?llatiswonk,p&ifles,ohbew,?ruo-rof,s&iht-skorg,ndnyd,????gn!am??hwsohw?i!.&buhtig,moc??b?r??j!.&eman?gro?hcs?lim?moc?ten?ude?vog???m!.&gro?moc?ten?ude?vog??il??n!.&a&0&b-ekhgnark--nx?c-iehsrgev--nx?g-lksedlig--nx?k-negnanvk--nx??1&p-nedragy--nx?q-&asierrs--nx?grebsnt--nx?lado-rs--nx?n&egnidl--nx?orf-rs--nx??regnayh--nx?ssofenh--nx??r-datsgrt--nx?s-ladrjts--nx?v-y&senner--nx?vrejks--nx???3g-datsobegh--nx?4&5-&dnaleprj--nx?goksnerl--nx?tednalyh--nx??6-neladnjm--nx?s-&antouvachb--nx?impouvtalm--nx??y-&agrjnevvad--nx?ikhvlaraeb--nx???7k-antouvacchb--nx?8&k-rekie-erv--nx?l-ladrua-rs--nx?m-darehsdrk--nx??a!.sg??bct-eimeuvejsemn--nx?d&do?iisevvad?lov?narts?uas??f&1-&l--nx?s--nx??2-h--nx??g&10aq0-ineve--nx?av?ev?lot?r&ajn&evvad?u??ájn&evvad?u????h?iz-lf--nx?j&ddadab?sel??k&el?hoj&sarak?šárák??iiv&ag&na&el?g??ŋ&ael?ág???ran???l&f?lahrevo?o&ms?s??sennev?t-&ilm--nx?tom--nx??u&-edr--nx?s??øms??muar?n&0-tsr--nx?2-dob--nx?5-&asir--nx?tals--nx??a&r!-i-om?f?t??t??douvsatvid?kiv?m&os?øs??n&od?ød??ra?sen?t&aouvatheig?ouv&a&c&ch&ab?áb??h&ab?áb???n??i&ag?ág??sa&mo?ttvid??án???z-rey--nx?ær&f?t???o&p-&ladr--nx?sens--nx??q-nagv--nx?r-asns--nx?s-kjks--nx?v-murb--nx?w-&anr&f--nx?t--nx??ublk--nx???ppol?q&0-t&baol--nx?soum--nx?veib--nx??x-&ipphl--nx?r&embh--nx?imph--nx???y-tinks--nx??r&f-atsr--nx?g-&an&ms--nx?nd--nx??e&drf--nx?ngs--nx??murs--nx?netl--nx?olmb--nx?sorr--nx??h-&a&lms--nx?yrf--nx??emjt--nx??i&-&lboh--nx?rsir--nx?y&d&ar--nx?na--nx??ksa--nx?lem--nx?r&ul--nx?yd--nx????stu??j-&drav--nx?rolf--nx?sdav--nx??kua?l-&drojf--nx?lares--nx??m-tlohr--nx?n-esans--nx?olf?p-sdnil--nx?s-ladrl--nx?tih?v-rvsyt--nx??s&a&ns?ons??i&ar?er&dron?r&os?øs???ár??la&g?h??mor!t??sir?uf?åns??t&koulo&nka?ŋká??la?p-raddjb--nx?r-agrjnu--nx?s&aefr&ammah?ámmáh??orf?r&o?ø???u-vreiks--nx??u&h-dnusel--nx?i-&drojfk--nx?vleslm--nx??j-ekerom--nx?k-rekrem--nx?u-&dnalr--nx?goksr--nx?sensk--nx??v-nekyr--nx?w-&k&abrd--nx?ivjg--nx??oryso--nx??y-y&dnas--nx?mrak--nx?n&art--nx?nif--nx??reva--nx??z-smort--nx??v!.sg?ledatskork?reiks??wh-antouvn--nx?x&9-dlofts--nx.aoq-relv--nx?d-nmaherk--nx?f-dnalnks--nx?h-neltloh--nx?i-drgeppo--nx?j-gve&gnal--nx?lreb--nx??m-negnilr--nx?n-drojfvk--nx??y&7-ujdaehal--nx?8-antouvig--nx?b-&dlofrs--nx?goksmr--nx?kivryr--nx?retslj--nx??e-nejsom--nx?f-y&krajb--nx?re&dni--nx?tso--nx??stivk--nx??g-regark--nx?orf?ørf??z9-drojfstb--nx??b&25-akiivagael--nx?53ay7-olousech--nx?a&iy-gv--nx?le-tl&b--nx?s--nx??n0-ydr--nx??c&0-dnal-erdns--nx?z-netot-erts--nx??g&g-regnarav-rs--nx?o-nejssendnas--nx??ju-erdils-ertsy--nx?nj-dnalh-goksrua--nx?q&q-ladsmor-go-erm--nx.&ari-yreh--nx?ednas??s-neslahsladrjts--nx???ca&4s-atsaefrmmh--nx?8m-dnusynnrb--nx?il-tl--nx?le-slg--nx?n5-rdib--nx?op-drgl--nx?uw-ynnrb--nx??d&a&qx-tggrv--nx?reh!nnivk?sd&ork?ørk??uas??ts&e&bi?kkar?llyh?nnan??g&ort?ørt??k&alf?irderf??levev?mirg?obeg&ah?æh??r&ah?ejg????barm-jdddb--nx?ie!rah?s&etivk?ladman???lof&r&os?øs??ts&ev.ednas?o.relav?ø.relåv???n&a&l&-erd&n&os?øs??ron??adroh.so?dron.&a&g5-b--nx?ri-yreh--nx??ob?y&oreh?øreh??øb??e&m!lejh??pr&oj?øj??vi??gyb?n&aks?åks??o&h-goksrua?rf??r&o?ua?ø??tros?øh-goksrua??rts!e&devt?lab?mloh???s&ellil?naitsirk?rof???u&l!os??s!d&im?lejt??e&guah?l&a?å???kkoh?lavk?naitsirk?r&af?eg&e?ie???tef?y&onnorb?ønnørb?????r&a&blavs!.sg??g&eppo?la???o&j&f&a!dniv?k?vk??die?e&dnas?kkelf??llins?r&iel?ots??s&lab?t&ab?åb??yt??å!k??ævk??les??ts??åg&eppo?lå???ureksub.sen??e&ayb-yrettn--nx?d&ar?lom?r&of?øf??år??g&gyr?nats??i&meuv&ejsem&aan?åån??sekaal??rjea??j&d&ef?oks??les??k&er&aom?åom??hgna&ark?årk??iregnir?kot!s??s&ig?uaf???l&bmab?kyb?l&av?ehtats??oh??m&it?ojt?øjt??n&arg?g&os?øs??meh?reil?te?ummok?yrb??r&dils-erts&ev?y&o?ø???ua?vod??sa&ans?åns??t&robraa?spaav??urg??f&62ats-ugsrop--nx?a&10-ujvrekkhr--nx?7k-tajjrv-attm--nx??o!.sg?h??s!.sg??v!.sg???g&5aly-yr&n--nx?v--nx??a&llor?ve&gnal?lreb???n&av!snellu??org??oks&die?m&or?ør??ner&ol?øl??r&o?ø???r&eb!adnar?edyps?s&die?elf?gnok?n&ot?øt????obspras??uahatsla?åve&gnal?lreb???h&0alu-ysm--nx?7&4ay8-akiivagg--nx?5ay7-atkoulok--nx??a!.sg???i&e&hsr&agev?ågev??rf??k&h&avlaraeb?ávlaraeb??s??lm&a?å??mpouvtal&am?ám??pph&al?ál??rrounaddleid?ssaneve?ššáneve??j&0aoq-ysgv--nx?94bawh-akhojrk--nx??k&a&b&ord?ørd??jks?lleis??iv!aklejps?l&am?evs?u??mag?nel?ojg?r&a&l?n??epok?iel?y&or?ør???s&ah?kel?om??øjg??kabene?ojsarak?ram&deh.&aoq-relv--nx?rel&av?åv??so??e&let.&ag5-b--nx?ob?øb??ra???åjks??l&a!d&anrus?d&numurb?ron??e&gnard?nte?s&meh?sin??ttin??g&is?nyl??kro?l&em?l&ejfttah?of??u&ag-ertdim?s???n&am?era?gos?i&b?nroh?r??kos?nus?oj??o-&dron?r&os?øs???ppo?r&a!l?nram??e&gne?l?v??is?o&jts?ts??u&a-&dron?r&os?øs???h??å?æl?øjts??s&e&jg?nivk?ryf??kav?mor-go-er&om.&ednas?yoreh??øm.&ednas?yøreh???uag??t&las?rajh?suan??v&l&a?e-rots??u-go-eron??yt??ksedlig?res&a?å???bib&eklof?seklyf??es!dah??h!.sg??i&m?syrt??l&ejf?ov&etsua?gnit?ksa?sdie???n!.sg??o!.sg?boh?g?h??r!.sg??å!ksedlig??øboh??m&a&rah?vk??f!.sg??h!.sg??i&e&h&dnort?rtsua?ssej??rkrejb??ksa??ol?t!.sg??u&dom?esum?r&ab?drejg?evle?os?uh?æb?øs??ttals???n&a&g&av?okssman?åv??jlis?or?r&g?rev???e&d&do&sen?ton??lah?r&agy&o?ø??ojfsam???g&iets?n&a&l&as?lab??n&avk?ævk??t&arg?ddosen??v&al?essov???i&d&ol?øl??l&ar?ær???yl??reb??iks?k&srot?y&or?ør???l&a&d&gnos?n&er?ojm?øjm??om??tloh??ug?åtloh??mmard?ojs&om?sendnas??ppolg?s&lahsladr&ojts?øjts??o??t&o&l?t-erts&ev?o?ø???roh?øl??vly&kkys?nav??yam-naj!.sg??øjs&om?sendnas???g&orf?ujb??i&dnaort?vnarg??kob?ladendua?maherk&a?å??n&it?urgsrop??orf-&dron?r&os?øs???r&aieb?evats??sfev?uaks?yrts??o&6axi-ygvtsev--nx?c,d&ob?rav??ievs?kssouf?l&m&ob?øb??ous&adna?ech&ac?áč???so!.sg???msdeks?niekotuak?r&egark?olf?y&oso?øso???s&dav?mort???p&ed?p&akdron?elk???r&a&d&dj&ab?áb??iab??jtif?luag?mah?vsyt??e&gn&a&k&iel?ro??merb?n&at?mas??rav-r&os?øs??srop?talf?v&ats?el??y&oh?øh???ivsgnok??il?jkniets?k&a&nvej?rem?s&gnir?nellu???ie-er&den?v&o?ø???ram?sa?årem??la&jf?vh??m&b&ah?áh??mahellil??nnul?ts&l&oj?øj??ul??y&o?ø???imp&ah?áh??m!.sg??osir?t!.sg??ádiáb?ævsyt?øsir??s&adnil?en&dnas?e&dga?k&ri&b?k??som??ve??me&h?jg??nroh-go-ejve?s&a?ednil?k&o?ø??of?yt?å??tsev??gv?hf?igaval?o&r&or?ør??sman??so&fen&oh?øh??m?v??uh&lem?sreka.sen??å!dnil???t&a&baol?g&aov?grav??jjr&av-attam?áv-attám??l&a&b?s??ás??soum?ts?v&eib?our???e&dnaly&oh?øh??f?s&nyt?rokomsdeks?sen??vtpiks??in&aks?áks??loh&ar?år??n!.sg??o&m&a?å??psgolb,?s!.sg?efremmah?or?ør??terdi?á&baol?ggráv?lá&b?s??soum?veib???u&b!.sg?alk?e&dna?gnir?nner??les?ælk??dra&b?eb??g&nasrop?vi?ŋásrop??j&daehal&a?á??jedub?v&arekkhar?árekkhár???ksiouf?n&diaegadvoug?taed???v&irp?lesl&am?åm???y&b&essen?nart?sebel?tsev??o&d&ar?na!s??or??gavtsev?k&rajb?sa??lem?mrak?n&art?n&if?orb???r&a&mah?n?v??e&dni?t&so?ton??va??ul?yd??s&am?enner?gav?lrak?tivk??vrejks??ø&d&ar?na!s??ør??gåvtsev?k&rajb?sa??lem?mrak?n&art?n&if?ørb???r&e&dni?t&so?tøn??va??ul?yd?æ&n?v???s&enner?gåv?tivk?åm??vrejks???á&slág?tlá?vreiks??å&gåv?h?jddådåb?lf??ø&d&ob?rav??r&egark?olf??s&dav?mort????u??o&b?f?ttat??r!.&cer?erots?gro?m&o&c?n??rif?t??ofni?stra?t&n?opsgolb,?www??ea!.&a&ac?cgd?idem??bulc!orea??ci&ffartria?taborea??e&c&alptekram?n&a&l&lievrus-ria?ubma??netniam?rusni??erefnoc???gnahcxe?mordorea?ni&gne?lria?zagam??rawtfos??gni&d&art?ilg!arap?gnah???l&dnahdnuorg?ledom??noollab?retac?sael?t&lusnoc?uhcarap??vidyks??hcraeser?ixat?l&anruoj?euf?icnuoc?ortnoc!-ciffart-ria???n&gised?oi&nu?t&a&cifitrec?ercer?gi&tsevni-tnedicca?van??i&cossa!-regnessap??valivic??redef??cudorp?neverp-tnedicca????ograc?p&ihsnoipmahc?uorg!gnikrow???r&e&dart?enigne?korb?niart?trahc??o&htua?tacude???s&citsigol?e&civres?r??krow?serp!xe??tnega??t&farcr&ia?otor??hgi&erf?l&f?orcim???liubemoh?n&atlusnoc?e&duts?m&esuma?n&iatretne?revog??piuqe????olip?ropria?si&lanruoj?tneics???w&erc?ohs??y&cnegreme?dobper?tefas????p!.&a&ca?pc??dem?gne?r&ab?uj??wal????s!.&gro?moc?ten???t!.&gro?lim?moc?ten?ude?vog??o&hp?v???ykot??p&aehc?g!.&gro?ibom?moc?ossa?ten?ude???j!.&a&bihc!.&a&bihciakoy?don?ma&him?ye&ragan?tat???r&a&bom?gan?hihci??u&agedos?kas?ustak???s&os?ufomihs??t&amihcay?iran??w&a&g&im&anah?o??omak??kihci?zustum??ihsak??y&agamak?imonihci???e&akas?nagot??i&azni?esohc?h&asa?s&abanuf?ohc???ka&to?zok??musi?orihs?r&akihabihsokoy?o&dim?tak??ukujuk??usihs??nano&hc?yk??o&d&iakustoy?ustam??hsonhot?k&a&rihs?t??iba??nihsaran?sobimanim?tas&arihsimao?imot??uhc?yihcay??u&kujno?s&ayaru?t&imik?tuf???zarasik????g&as!.&a&gas?m&a&tamah?yik??ihsak??rat?t&a&gatik?hatik??ira!ihsin????e&kaira?nimimak??i&akneg?g&aruyk?o??h&c&amo?uo??siorihs??kaznak?modukuf?ra&gonihsoy?mi???nezih?u&k&at?ohuok??s&ot?tarak?????ihs!.&a&kok?m&a&hagan?yirom??ihsakat??rabiam?wagoton??e&miharot?nokih??houyr?i&azaihsin?esok?kustakat?moihsagih??na&mihcahimo?nok??o&hsia?mag?t&asoyot?ok?tir???us&ay?t&asuk?o??????k&aso!.&a&d&awihsik?eki??k&a&noyot?s&akaayahihc?oihsagih???oadat?uziak??m&ayas!akaso??odak??r&a&bustam?wihsak??ediijuf??t&akarih?i&k?us???wag&ayen?odoyihsagih???e&son?tawanojihs??honim?i&akas?h&cugirom?s&ayabadnot?i&a&kat?t??n??oyimusihsagih???k&a&rabi?sim??ustakat??muzi?r&ijat?otamuk???nan&ak?n&ah?es???o&ay?n&a&ganihcawak?simuzi?tak??eba?ikibah?oyot??t&anim?iad?omamihs??uhc??ust&oimuzi?tes????ou&kuf!.&a&d&amay?eos??g&no?ok?usak??hiku?k&awayim?uzii??ma&kan?y&asih?im???rawak?t&a&gon?ka&h?num?t???umo??wa&g&a&kan?nay?t??ias??ko!rih???y&ihsa?usak???e&m&ay?uruk??taruk?us??i&a&nohs?raihcat??goruk?h&cukuf?s&a&gih?hukuy??in???k&a&gako?muzim??iust?o?ustani??m&anim?otihsoynihs?u??r&ogo?ugasas??usu??ne&siek?zu&b?kihc???o&gukihc?h&ak?ot?ukihc??j&ono?ukihc??kayim?nihsukihc?to?uhc??u&fiazad?gnihs?stoyot????zihs!.&a&bmetog?d&amihs?eijuf?ihsoy?omihs??kouzihs?mihsim?ra&biah?honikam??tawi?wa&g&ekak?ukik??kijuf??yimonijuf??i&a&ra?sok??hcamirom?juf?kaz&eamo?ustam??ma&nnak?ta??nukonuzi?orukuf??nohenawak?o&nosus?ti??u&stamamah?z&a&mun?wak??i!ay?i&hs&agih?in??manim??mihs????????m&a&tias!.&a&d&ihsoy?ot?usah??k&a&dih?sa??o&arihs?s???m&a&tias?y&as?o&rom?tah??ustamihsagih???i&hsagurust?jawak??uri??ni?wa&g&e&ko?man??ikot?o??k&ara?i&hsoy?mak???ru?zorokot??y&a&g&amuk?ihsok?otah??kuf??imo??ziin??e&bakusak?ogawak?sogo?ttas?zokoy??i&baraw?h&cugawak?s&oyim?ubustam???iroy?k&ato?ihs?u&k?stawi???m&akoyr?i&hsoy?juf??uziimak???naznar?o&dakas?ihsay?jnoh?n&a&go?nim??imijuf?nah?oy??r&ihsayim?otagan??t&asim!ak??igus?omatik??zak??u&bihcihc!ihsagih??sonuok?ynah????y&ak&aw!.&a&d&ira?notimak??kadih?ma&h&arihs?im??y&a&kaw?tik??oduk???ru&ustakihcan?y??sauy?wa&g&a&dira?zok??orih??konik??yok?zok??e&banat?dawi??i&garustak?jiat?mani??naniak?o&bog?nimik?t&asim?omihs&ah?uk????ugnihs???o!.&a&jos?koasak?m&ay&ako?ust??ihsayah??r&abi?ukawaihsin??wi&aka?nam???e&gakay?kaw??i&gan?h&cu&kasa?otes??sahakat??k&asim?ihsaruk??miin??n&anemuk?ezib??o&hsotas?jnihs?n&amat?imagak??ohs?uhcibik?????ot!.&a&damay?got?koakat?may&etat?ot??nahoj?riat?waki&inakan?reman???eb&ayo?oruk??i&h&asa?ciimak?sahanuf??kuzanu?m&an&i?ot??ih???nezuyn?otnan?u&hcuf?stimukuf?z&imi?ou???????ihs&o&gak!.&a&m&ayuok?ihsogak??si?yonak??e&banawak?n&at&akan?imanim??uka??tomoonihsin??i&adnesamustas?k&azarukam?oih??m&ama?uzi??usuy??nesi?o&knik?os?tomustam??uzimurat???rih!.&a&ka&n?s??m&ayukuf?i&hsorihihsagih?j&ate?imakikaso????r&a&bohs?h&ekat?im???es??tiak?wiad??e&kato?ruk??i&h&ci&akustah?mono?nihs??s&inares?oyim???manimasa?uk??negokikesnij?o&gnoh?namuk??uhcuf????uk&ot!.&a&bihci?mi&hsu&kot?stamok??m??wagakan??egihsustam?i&gum?h&coganas?soyim??kijaw?m&anim?uzia??ukihsihs??nan&a?iak??o&nati?turan????uf!.&a&batuf?m&a&to?y&enak?irok???ihs&im?ukuf??os?uko??r&aboihsatik?uganat??ta&katik?mawak?rih??w&a&g&akus?emas?uy??k&a&mat?rihs?sa??ihsi??nah??ohs???e&gnabuzia?iman?ta&d?tii???i&adnab?enet?hs&agih?iimagak??k&a&wi?zimuzi??ubay??minuk?r&ook?ustamay???nihsiat?o&g&etomo?ihsin?nan?omihs??no!duruf?rih??rihsawani?ta&may?simuzia???u&rahim?stamakawuzia?zia&ihsin?nay???????nug!.&a&bawak?doyihc?k&anna?oi&hsoy?juf?mot???m&ayakat?ustagaihsagih??n&ihsatak?nak??r&ahonagan?nak?o?u&kati?mamat???t&amun?inomihs?o??w&akubihs?iem?ohs???i&hsa&beam?yabetat??kas&akat?esi??m&akanim?uzio??ogamust?rodim??o&jonakan?n&eu?oyikust??tnihs??u&komnan?stasuk?yrik?????ran!.&a&bihsak?d&akatotamay?u!o???guraki?m&ay&atik&imak?omihs??irokotamay??oki??ra&hihsak?n??wa&geson?knet???e&kayim?ozamay?sog?ustim??i&a&rukas?wak??garustak?h&ciomihs?sinawak??jo?ka&mnak?toruk??makawak?nos?r&net?otakat?ugeh???o&d&na?oyo??gnas?jnihs?nihsoy!ihsagih??tomarawat?yrok????t&ag&amay!.&a&dihsio?k&atarihs?ourust??may&a&kan?rum??enak?onimak??rukho?ta&ga&may?nuf??hakat?kas??wa&g&ekas?orumam??ki&hsin?m??z&anabo?enoy?ot???zuy??e&agas?bonamay?dii?nihsagih?o??i&a&gan?nohs??h&asa?sinawak??nugo??o&dnet?jnihs?ynan??ukohak???iin!.&a&ga?k&ium?oagan??munou!imanim??t&a&bihs?giin??ioy??w&a&gioti?kikes?zuy??irak??yijo??e&kustim?mabust??i&aniat?hcamakot?kaz&awihsak?omuzi??m&a&gat?karum??o???n&anust?esog??o&das?ihcot?jnas?k&ihay?oym??mak?naga?ries??u&ories?steoj?????i&ka!.&a&go?k&asok?oimak??t&ago!rihcah??ika!atik???w&aki?oyk???e&mojog?natim?suranihsagih?t&ado?okoy???i&hsoyirom?magatak?naokimak??nesiad?o&hakin?jnoh!iruy??nuzak?rihson?tasi&juf?m??yjnoh??u&kobmes?oppah????o!.&a&dakatognub?m&asah?ihsemih??su?t&ekat?i&h?o????e&onokok?ustimak??i&jih?k&asinuk?ias?usu??mukust??onoognub?u&fuy?juk?ppeb?suk??????wa&ga&k!.&a&mihsoan?rihotok?waga&kihsagih?ya???emaguram?i&j&nonak?ustnez??kunas?monihcu??o&hsonot?nnam?yotim??u&st&amakat?odat??zatu????nak!.&a&dustam?kus&okoy?tarih??maz?nibe?r&a&gihsaimanim?h&esi?imagas??wa&do?guy???u&im?kamak???tikamay?wa&k&ia?oyik?umas??sijuf??yimonin??e&nokah?saya??i&akan?esiak?gusta?hsuz?kasagihc?o?ukust??o&nadah?sio?tamay?????kihsi!.&a&danihcu?gak?kihs?mijaw?t&abust?ikawak??wazanak??i&gurust?hcionon?mon?ukah??nasukah?o&anan?ton!akan???u&kohak?stamok?z&imana?us?????niko!.&a&han?m&arat?ijemuk?uru??n&e&dak?zi??no??ra&hihsin?rih??wa&kihsi?niko??yehi?zonig??e&osaru?seay??i&hsagih?jomihs?k&a&gihsi?not??ihsakot??m&a&ginuk?kihsug?maz??igo?otekat??nuga!noy???n&a&moti?timoy?wonig??i&jikan?k???o&gan?jnan?tiad&atik?imanim???u&botom?kusug&akan!atik??imot??rab&anoy?eah???????ca?d&a?e??e&im!.&a&bot?k&asustam?uzus??m&a&him?y&emak?im???ihs??nawuk?wi&em?k???e&bani?ogawak?si!imanim???i&arataw?gusim?h&asa?ciakkoy??k&a&mat?sosik?t??iat??raban??o&dat?hik?n&amuk?ihseru?o&du?mok????ust???mihe!.&a&m&a&h&ataway?iin??yustam??ij&awu?imak???taki!man???ebot?i&anoh?kasam?rabami??n&ania?egokamuk?oot??o&jias?kihcu?nustam?uhcukokihs?yi!es???u&kohik?zo????n!amihs!.&a&d&amah?ho?usam??kustay?m&a?ihsoni&hsin?ko???wakih??e&namihs?ustam??i&g&aka?usay??konikak?mikih??nannu?o&mu&kay?zi!ihsagih?uko???nawust?tasim??u&stog?yamat?????tawi!.&a&bahay?d&amay?on??koirom?t&a&honat?katnezukir??imus??w&as&ijuf?uzim??ihs???e&hon&i&hci?n??uk??tawi??i&a&duf?murak?wak??h&custo?si&amak?ukuzihs???j&oboj?uk??k&a&m&anah?uzuk??sagenak??esonihci??m&akatik?uzia&rih?wi????o&kayim?no&rih?t??tanufo??uhso????gl?i&g&ayim!.&a&dukak?m&a&goihs?kihs??ihsustam!ihsagih??un&awi?nesek???r&awago?iho??ta&bihs?rum??w&a&gano?kuruf??iat??y&imot?ukaw???e&mot?nimes??i&hsiorihs?ka&monihsi?s&awak?o???mak?r&ataw?o&muram?tan????o&az?jagat?t&asim?omamay???u&fir?k&irnasimanim?uhsakihcihs?????ihcot!.&a&g&a&h?kihsa??ust??kom?m&ay&o?usarak??unak??r&a&boihsusan?watho??iho?ukas??t&akihsin?iay??wa&konimak?zenakat??y&imonustu?oihs???e&iiju?kustomihs?nufawi??i&akihci?g&etom?ihcot?on???o&k&ihsam?kin??nas?sioruk?tab??u&bim?san?????h&c&ia!.&a&dnah?m&a!h&akat?im??yuni??ihs&ibot?ust???r&a&hat?tihs??ik?u&ihsagih?kawi???t&ihc?o&k?yot???wa&koyot?zani??yi&monihci?rak???e&inak?k&aoyot?usa??manokot?noyot??i&a&gusak?kot?sia??eot?h&asairawo?cugo?s&ahoyot?oyim???k&a&mok?zako??ihssi??motay?rogamag??n&an&ikeh?ok??ihssin??o&got?ihsin?jna?rihsnihs?suf?tes??u&bo?raho?s&oyik?takihs??yrihc?zah????ok!.&a&dusay?kadih?mayotom?r&ah&im?usuy??umakan??sot!ihsin??wa&g&atik?odoyin??k&as?o????i&esieg?hco!k??jamu?k&a!sus??usto??ma&gak?k??rahan??o&mukus?n&i?ust!ihsagih???torum?yot!o???u&koknan?zimihsasot????ugamay!.&a&m&ayukot?ihso??toyot??e&bu?subat??i&gah?kesonomihs?nukawi?rakih??nanuhs?otagan?u&ba?foh?otim?stamaduk?uy?????sanamay!.&a&dihsoyijuf?mayabat?r&ahoneu?ustakihsin??w&a&k&ayah?ijuf??suran??ohs???egusok?i&ak?h&cimakan?s&anamay?od???k&asarin?u&feuf?sto????o&k&akanamay?ihcugawakijuf??nihso?t&asimawakihci?ukoh??uhc??spla-imanim?u&b&nan?onim??fok?hsok?rust?????ka&rabi!.&a&bukust?gok?kan!ihcatih??m&a&sak?timo?wi??ihsak?ustomihs??ni?r&a&hihcu?way??u&agimusak?ihcust???t&ag&amay?eman??oihcatih??w&ag&arukas?o??os??yi&moihcatih?rom???e&bomot?dirot?not?tadomihs??i&a&k&as?ot??rao??esukihc?gahakat?h&asa?catih??k&a&rabi?saguyr??ihsani?uy??ma?rukustamat??o&dnab?giad?him?kati?rihsijuf?soj?t&asorihs?im??yihcay??u&fius?kihsu?simak????sagan!.&a&m&abo?ihsust??natawak?r&abamihs?u&mo?ustam???wijihc?yahasi??i&akias?hies?k&asagan?i??masah??neznu?o&besas?darih?t&eso?og!imaknihs????ust&igot?onihcuk?uf????zayim!.&a&biihs?guyh?k&oebon?ustorom??mihsuk?r&emihsin?uatik??ta&katik?mim??wag&atik?odak??ya??e&banakat?sakog??i&hsayabok?kaza&kat?yim??m&animawak?ot&inuk?nihs????nanihcin?o&j&ik?onokayim??n&ibe?ust??tias??urahakat????ro&moa!.&a&dawot?turust?wasim??e&hon&ihc&ah?ihs??nas?og?ukor??sario??i&anarih?ganayati?hsioruk?jehon?kasorih?makihsah?nawo?r&amodakan?omoa???o&gnihs?kkat??u&ragust?stum????ttot!.&a&r&ahawak?uotok??sa&kaw?sim???egok?irottot?nanihcin?o&ganoy?nih?tanimiakas??u&bnan?z&ay?ihc??????ukuf!.&a&deki?gurust?ma&bo?h&akat?im??yustak??sakaw??eabas?i&akas?ho?jiehie?ukuf??nezihce!imanim??ono????o&c?diakkoh!.&a&deki?gakihset?hcebihs?k&adih?u&fib?narihs???m&ayiruk?hot?ihs&orihatik?ukuf??oras?usta??r&ib&a!ka??o?uruf??ozo?u&gakihsagih?oyot???sakim?ta&gikust?mun??w&a&ga&k&an?uf??nus!imak???k&aru?i&h&asa?sagih??kat?mak??omihs?um??zimawi??ine?oyk??yot??e&a&mustam?nan??b&a&kihs?yak??o&noroh?to???ian?k&ihsam?ufoto??nakami?ppoko!ihsin??sotihc?tad!okah??uonikat??i&a&bib?mokamot?n&a&k&kaw?oroh??wi??eomak?ihsatu?okik?usta&moruk?sakan????eib?h&c&ioy?u&bmek?irihs???s&ase?ekka?oknar?uesom???jufirihsir?k&amamihs?i&at?n???m&atik?otoyot??oa&kihs?rihs??r&a&hs?kihsi?mot??ihs&aba?ir??otarib???n&a&hctuk?rorum?se?tokahs??uber??o&kayot?m&ire?ukay??naruf!ima&k?nim???orih?r&ih&ibo?suk??o&bah?h&i&b?hsimak??sa??pnan?yan??umen??t&asoyik?eko?ukoh???u&bassa?kotnihs?m&assaw?uo??pp&akiin?en&ioto?nuk??ip??rato?s&akat?t&eb&e?i&a?hs!a??robon??m&e?o&m?takan???no&h?tamah??o&mik?s?t??u&kir?ppihc?st???onihsnihs?ufuras??uaru??yru!koh??zimihs!ok?????g!oyh!.&a&bmat?dnas?gusak?k&at?o&oyot?y??uzarakat??m&ayasas?irah??wa&g&ani?okak??k&i&hci?mak??oy???yi&hsa?monihsin???i&asak?hs&aka?i&at?nawak???j&awa!imanim??emih??k&a&goa?s&agama?ukuf??wihsin??i&hsog?m???mati?oia?rogimak??n&annas?esnonihs??o&gasa!kat??ka?n&ikat?o?ustat??rihsay?sihs?tomus?yas??u&bay?gnihs?????nagan!.&a&bukah?d&a&w?yim??e&ki?u??ii??k&a&s&ay?uki??zus??ihsoo?ousay??m&ay&akat?ii??i&hsukufosik?jii??ukihc??n&i!hsetat??uzii??r&ah?ugot??saim?t&agamay?oyim??w&a&g&a&kan?n??o??kustam?ziurak??onim!imanim??u&koo?s!omihs????ya&ko?rih???e&akas?nagamok?subo??i&gakat?h&asa?c&a!mo!nanihs???uonamay??sukagot??k&a&kas?mimanim?to??ia&atik?imanim??oa?uzihcom??m&akawak?ijuf?o!t???r&ato?ijoihs?omakat???n&ana?esnoawazon??o&hukas?n&a&gan?kan??i&hc?muza??ustat??romok?si&gan?k??tomustam??u&k&as?ohukihc??stamega????to&mamuk!.&a&gamay?mihsak?rahihsin?s&ok?ukama!imak???tamanim??enufim?i&h&cukik?soyotih??k&ihsam?u??nugo!imanim??romakat??o&ara?rihsustay?sa?t&amay?om&amuk?us??u!koyg???yohc??u&sagan?zo????yk!.&a&bmatoyk?k&ies?oemak?uzaw??mayi&h&cukuf?sagih??muk??nihsamay?rawatiju?t&away?ik???e&ba&nat!oyk??ya??di?ni??i&ju?kazamayo?manim??natnan?o&gnatoyk?kum?mak?rihsamayimanim?y&gakan?ka&koagan?s??oj???u&ruziam?z&ayim?ik??????ykot!.&a&d&i&hcam?mus??oyihc??k&atim?ihsustak??m&a&t!uko??yarumihsa&gih?sum???i&hs&agoa?ika?o!t??uzuok??ren???r&a&honih?wasago??iadok?umah??ssuf?t&ik?o??wa&g&anihs?ode??k&ara?ihcat???y&agates?ubihs???e&amok?donih?m&o?urukihsagih??soyik??i&enagok?gani?h&ca&da?tinuk??sabati??j&nubukok?oihcah??manigus??o&huzim?jihcah?n&akan?ih!sasum??urika??rugem?t&a&mayihsagih?nim??iat?ok??uhc?yknub??u&fohc?hcuf?kujnihs?????r&g?o??topsgolb,ufig!.&a&d&eki?ih??kimot?m&ayakat?ihsah??ne?raha&gi&kes?makak??sak??taga&may?tik??wa&g&ibi?ustakan??karihs!ihsagih????e&katim?uawak??i&gohakas?hc&apna?uonaw??k&ago?es?ot??m&anuzim?ijat??nak?urat??nanig?o&dog?jug?makonim?nim?roy?sihcih??u&fig?s&otom?t&amasak?oay????????k!.&art?gro?moc?per?ude?vog???m!ac??nd?o&g?hpih?oc??t??q&a?g?i!.&gro?lim?moc?ten?ude?vog???m??r&a!.&bog?gro?lim?moc!.topsgolb,?rut?t&en?ni??ude??4d5a4prebgm--nx?b?los?tsuen??b!.&21g?b!mi??c&er?sp?te??d&em?mb?n&f?i??rt??f&gg?ni??g&el?l&s?z??n&c?e??ol&b?f?v??pp?ro??i&kiw?sp?te?xat??l&el?im?sq??m&a?da?f?ic?o&c!.topsgolb,?n???nce?o&ce?do?et?i&b?dar??rp?ta??p&m!e?t??ooc?se??qra?r&af?ga?oj?tn?ut??su&j?m??t&am?e&n?v??nc?o&f?n??ra?sf??ude?v&da?og?rs?t????c!.&as?ca?de?if?o&c?g??ro???e&e&b?rac??t&nec?upmoc???f!.&aterg?cidessa?drp?e&citsuj-reissiuh?rianiretev?sserp??i&cc?rgabmahc??m&o&c?n??t??n&eicamrahp?icedem??ossa?se&lbatpmoc-strepxe?riaton?tsitned-sneigrurihc?uova??t&acova?opsgolb,r&epxe-ertemoeg?op!orea????vuog??avc7ylqbgm--nx??g!.&gro?moc?t&en?opsgolb,?ude?vog???h!.&eman?mo&c?rf??zi??ur??i!.&a&61f4a3abgm--nx?rf4a3abgm--nx??ca?di?gro?hcs?oc?ten?vog?نار&يا?یا???aper??k!.&c&a?s??e&n?p?r??gk?iggnoeyg?kub&gn&oeyg?uhc??noej??l&im?uoes??man&gn&oeyg?uhc??noej??n&as&lu?ub??o&e&hcni?jead??wgnag???o&c?g??ro?s&e?h?m??topsgolb,u&gead?j&ej?gnawg?????l!.&gro?moc?ten?ude?vog???m!.&topsgolb,vog???n!.&gro?moc?ofni?ten?ude?vog?zib???otca?p!.&alsi?ca?eman?forp?gro?moc?o&fni?rp??t&en?se??ude?vog?zib???s?t.cn.vog?ubad??s&8sqif--nx?9zqif--nx?a!.vog?gev?lliv?mtsirhc??b!.&gro?moc?ten?ude?vog??oj??ci&hparg?p??d&nomaid?rac??e!.&bog?gro?mo&c!.topsgolb,?n??ude??civres?d&d2bgm--nx?oc??i&lppus?rtsudni?treporp??jaiv?l&cycrotom?gnis??moh?ohs?picer?rut&cip?nev??si&rpretne?urc??taicossa?vig??g!nidloh??h5c822qif--nx?i!.&ekacpuc,gro?moc?t&en?ni??ude?vog??rap??k&cor?hxda08--nx?row??l!.&gro?oc??atner?essurb?oot??m!.&gro?moc?ten?ude?vog??etsys??n&agorf?ia&grab?mod??oit&acav?cudorp?ulos???o&dnoc?t&ohp?ua???p!.&ces?gro?moc?olp?ten?ude?vog??it??r!.&ca?gro?ni?oc?ude?vog??atiug?e&dliub?erac?ntrap??otcartnoc??s&alg?en&isub?tif???t&h&cay?gilf??neve?rap??u!.&a&c!.&21k?bil?cc???g!.&21k?bil?cc???i!.&21k?bil?cc???l!.&21k?bil?cc???m!.&21k!.&hcorap?rthc?tvp???bil?cc???p!.&21k?bil?cc???si?v!.&21k?bil?cc???w!.&21k?bil?cc????c&d!.&21k?bil?cc???n!.&21k?bil?cc???s!.&21k?bil?cc????d&ef?i!.&21k?bil?cc???m!.&21k?bil?cc???n!.&21k?bil?cc???s!.&bil?cc????e&d!.&21k?bil?cc???las-4-&dnal,ffuts,?m!.&21k?bil?cc???n!.&21k?bil?cc????h&n!.&21k?bil?cc???o!.&21k?bil?cc????i&h!.&bil?cc???m!.&21k?bil?cc???nd?r!.&21k?bil?cc???v!.&21k?bil?cc???w!.&21k?bil?cc????jn!.&21k?bil?cc???k&a!.&21k?bil?cc???o!.&21k?bil?cc????l&a!.&21k?bil?cc???f!.&21k?bil?cc???i!.&21k?bil?cc????mn!.&21k?bil?cc???n&i!.&21k?bil?cc???m!.&21k?bil?cc???sn?t!.&21k?bil?cc????o&c!.&21k?bil?cc???m!.&21k?bil?cc????r&a!.&21k?bil?cc???o!.&21k?bil?cc???p!.&21k?bil?cc????s&a!.&21k?bil?cc???dik?k!.&21k?bil?cc???m!.&21k?bil?cc????t&c!.&21k?bil?cc???m!.&21k?bil?cc???u!.&21k?bil?cc???v!.&21k?bil?cc????ug!.&21k?bil?cc???v&n!.&21k?bil?cc???w!.cc???xt!.&21k?bil?cc???y&b-si,k!.&21k?bil?cc???n!.&21k?bil?cc???w!.&21k?bil?cc????za!.&21k?bil?cc????ah?e??w!.&gro?moc?s&ndnyd,tepym,?ten?ude?vog??eiver??yot??t&0srzc--nx?a!.&ca?o&c!.topsgolb,?fni,?ro?v&g?irp,?zib,?c?e?rcomed??b!.&gro?moc?ten?ude?vog???e&em?kram?n!.&a&l-morf,z,?bg,dnab-eht-ni,e&ht-no-eciffo,libom-eruza,mohtanyd,nozdop,rehurht,s,tis-repparcs,?fehc-a-si,k&eeg-a&-si,si,?u,?ni,o&c-morf,jodsnd,?p&i&emoh,fles,?j,mac-dnab-ta,o&-oidar-mah,hbew,?paduolc,tfe&moh,vres,??s&aila&nyd,snd,?bbevres,e&suohsyub,tisbeweruza,?ndgolb,sa-skcik,?t&enretnifodne,i-&ekorb,s&eod,lles,teg,??norfduolc,sixetnod,?uh,x&inuemoh,unilemoh,?y&ltsaf.&dorp.&a,labolg,?lss.&a,b,labolg,??n-morf,?za-morf,??v??fig?g!.&bog?dni?gro?lim?moc?ten?ude???h!.&dem?gro?l&er?op??m&oc?rif??o&fni?rp?s&rep?sa???po&hs?oc??t&en?luda?ra??ude?vuog???i!.&a&at?b?c!cul??dv?i&blo&-oipmet?oipmet??cserb?drabmol?g&gof?urep??l&gup?i&cis?me&-oigger?oigger???uig&-&aizenev&-iluirf?iluirf??ev&-iluirf?iluirf??v&-iluirf?iluirf???aizenev&-iluirf?iluirf??ev&-iluirf?iluirf??v&-iluirf?iluirf????n&a&brev?cul?pmac?tac??idras?obrac&-saiselgi?saiselgi??resi??otsip?r&b&alac!-oigger?oigger??mu??dna&-&attelrab-inart?inart-attelrab??attelrabinart?inartattelrab?ssela??epmi?ugil??tnelav&-obiv?obiv??vap?z&e&nev?ps&-al?al???irog???l&iuqa!l??leib??m&or?rap??n!acsot?e&dom?is?sec&-ilrof?ilrof???g&amor&-ailime?ailime??edras?olob??i&ssem?tal??ne!var??o&cna?merc?rev?vas???oneg?p?r!a&csep?rr&ac&-assam?assam??ef??von??etam?tsailgo!-lled?lled???s!ip?sam&-ararrac?ararrac??u&caris?gar???t!a&cilisab?recam??resac?soa!-&d&-&ellav?lav??ellav?lav??ellav??d&-&ellav?lav??ellav?lav??ellav??te&lrab&-&airdna-inart?inart-airdna??airdnainart?inartairdna??ssinatlac???udap?v!o&dap?neg?tnam???zn&airb&-a&lled-e-aznom?znom??a&lledeaznom?znom??eaznom??e&c&aip?iv??soc?top??om???b&c?m!u??v??c&f?is?l?m?p?r?v??d&p?u??e&c!cel?inev?nerolf??f?g!ida&-&a&-onitnert?onitnert??otla!-onitnert?onitnert???a&-onitnert?onitnert??otla!-onitnert?onitnert????hcram?l?m!or??n&idu?o&n&edrop?isorf??torc???p?r?s&erav?ilom??t!nomeip?s&eirt?oa!-eellav?eellav????v?znerif??g&a?b?f?il?o?p?r?up?vf??hc?i&b?c?dol?f?l!lecrev?opan?rof&-anesec?anesec???m?n&a&part?rt&-attelrab-airdna?attelrabairdna???imir?ret??p?r!a&b?ilgac?ssas???s!idnirb??t&ei&hc?r??sa??v??l&a!c??b?c?o&m?rit&-&d&eus&-onitnert?onitnert??us&-onitnert?onitnert???s&-onitnert?onitnert???d&eus!-onitnert?onitnert??us&-onitnert?onitnert???s&-onitnert?onitnert?????m&ac?f?i?ol?r??n&a!lim?slab??b?c?e!v?zob??irut?m!p??p?r?t??o&a!v??b!retiv??c!cel??enuc?g!ivor??i&dem&-onadipmac?onadipmac??pmet&-aiblo?aiblo??rdnos?zal??l?m!a&greb?ret??oc?re&f?lap???n!a&dipmac&-oidem?oidem??lim?tsiro?zlob??ecip&-ilocsa?ilocsa??i&bru&-orasep?orasep??lleva?rot?tnert??r&elas?ovil??ulleb??p?r!a&sep&-onibru?onibru??znatac??oun??s!ivert?sabopmac??t!arp?e&nev?ssorg??n&arat?e&girga?rt?veneb????zz&era?urba???p&a?s?t??qa?r&a!m?s??b!a??c?f?g?k?me?o?p?s?t?v??s&a&b?iselgi&-ainobrac?ainobrac???b?c?elpan?i?m?ot?s?t?v??t&a?b?c?l?m?nomdeip?o!psgolb,?p?v??u&de?l?n?p??v&a?og?p?s?t?v??y&drabmol?ellav&-atsoa?atsoa??licis?nacsut??z&al?b?c?p????l!.vog??m!.&gro?moc?ten?ude???n&e&g?m&eganam?piuqe???i!.ue??uocsid??ocs?p!.&emon?gro?lbup?moc?t&en?ni?opsgolb,?ude?vog???r&epxe?op&er?pus???s!.&adaxiabme?e&motoas?picnirp?rots??gro?lim?moc?o&c?dalusnoc??ten?ude?vog??e&b?padub?r??irolf?op??t!.&eman?gro?ibom?levart?m&oc?uesum??o&c?fni?r&ea?p???pooc?sboj?t&en?ni??ude?vog?zib???y?ztej??u&a!.&a&s?w??civ?d&i?lq??fnoc?gro?moc!.topsgolb,?nsa?o&fni?risc??sat?t&ca?en?n??ude!.&a&s?w??civ?dlq?sat?t&ca?n??wsn???vog!.&a&s?w??civ?dlq?sat?tca???wsn?zo???c!.&fni?gro?moc?ten?ude?vog???de?e?h!.&0002?a&citore?idem?kitore??edszot?gro?ilus?letoh?m&alker?lif?t?urof??naltagni?o&c?ediv?fni?levynok?nisac??pohs?rarga?s&a&kal?zatu??emag?wen??t&lob?opsgolb,rops??virp?xe&s?zs??ytic?zsagoj??os??l?m!.&ca?gro?moc?oc?ro?ten?vog???n!.&eni&esrem,m,?tenkcahs,?em??r!.&a&dgolov?gulak?i&hsavuhc?kymlak?lerak?rikhsab?ssakahk?t&ayrub?rumdu?ukay??vodrom??k&dohkan?nidud?t&a&hcmak?yv??ingam?okuhc???l&o-rakhsoj?ut??mortsok?nalap?ramas?tihc?vut?yegyda?znep??bps?ca?d&arg&oglov?z??nr?orogleb??e&du-nalu?niram??g&bc?ersom?ineok?r&o?ub&-e?n&ero?iretakey?????hzenorov?i&a&natsuk?tla??mok?ram??k&ihclan?otsovidalv?s&l&aru-k?egnahkra?iron??m!o!t???n!a&mrum?yrb??eloms?i&baylehc?lahkas-onhzuy??odv??r&ayonsark?ib&isovon?mis??ogitayp?u&k?ma???t!epil?ukri??v&ehzi?o&rabahk?stbur?????l&a&kiab?ma&j?y???e&-iram?hc??im?o&kso?porvats?yro??valsoray??m&du?o&c?t??rep??n&a&buk?dagam?gruk?hkartsa?rzys?ts&egad?ratat??za&k?yr???emuyt?ilahkas?rv?ystirast??ovo&navi?remek??pp?r&aj?evt?hck?i&b?midalv??uma??s&itym?mk?sabzuk??t&en?ni?s&aeraf?et??ugrus??ude?v&hk?o&bmat?g?ksp?n!n??rik?taras??ts??wmc?ynzorg?z&akvakidalv?kn?ns?tp???ug??s?v?ykuyr??v&b?c!.topsgolb,?ih?l!.&di?fnoc?gro?lim?moc?nsa?ten?ude?vog???m!.&eman?gro?lim?m&oc?uesum??o&fni?r&ea?p???pooc?t&en?ni??ude?vog?zib???o&g?m??s!.&bog?der?gro?moc?ude???t!.&bew-eht-no,naht-&esrow,retteb,?sndnyd,??uqhv--nx??w&a!.moc??b!.&gro?oc???c!.&gro?moc?ten?ude???en?g?m!.&ca?gro?m&oc?uesum??oc?pooc?t&en?ni??ude?vog?zib???o&csom?h??p!.&de?en?o&c?g??ro?ualeb???r!.&ca?lim?moc?oc?t&en?ni??ude?v&og?uog???n??t!.&a46oa0fz--nx?b&82wrzc--nx?ulc??emag?gro?lim?moc?t&en?opsgolb,?ude?v&di?og?ta0cu--nx??zibe?業商?織組?路網????x&a?c!.&hta,vog???m!.&bog?gro?moc?t&en?opsgolb,?ude??ma2ibgy--nx??s!.vog??xx??y&4punu--nx?ad!i&loh?rfkcalb??ot??b!.&fo?lim?moc?vog???cnega?g!.&moc?oc?ten??olonhcet??hpargotohp?k!.&gro?moc?ten?ude?vog???l!.&clp?d&em?i??gro?hcs?moc?ten?ude?vog??ppus??m!.&eman?gro?lim?moc?ten?ude?vog??edaca?ra??napmoc?os?p!.&gro?lim?moc?pooc?ten?ude?vog???r&ellag?otcerid?tnuoc?uxul??s!.&gro?lim?moc?ten?ude?vog???ti&nummoc?srevinu??u!.&bug?gro?lim?moc?ten?ude???van?xes??z&a!.&eman?gro?lim?moc?o&fni?rp??pp?t&en?ni??ude?vog?zib???b!.&az,gro?moc?ten?ude?vog???c!.topsgolb,?d!.&gro?lop?moc?ossa?t&en?ra??ude?vog???ib!.&e&ht-rof,mos-rof,rom-rof,?p&ifles,ohbew,?retteb-rof,sndnyd,??k!.&gro?lim?moc?ten?ude?vog???n.oc.topsgolb,s!.&ca?gro?oc???t!.&c&a?s??e&m?n??ibom?l&etoh?im??o&c?fni?g??ro?vt???u!.&gro?moc?oc?ten???yx?zub??авксом?брс?гро?зақ?итед?н&йално?ом??рку?сур?тйас?фр?اي&روس?سيلم??برغملا?ة&كبش?ي&دوعسلا?روس??یدوعسلا??ت&اراما?راھب??ر&ئازجلا?ازاب?صم?طق??سنوت?عقوم?ن&ا&ر&يا?یا??مع??درالا?ميلا?يطسلف??هيدوعسلا?ۃیدوعسلا?तराभ?नठगंस?তরাভ?ালংাব?ਤਰਾਭ?તરાભ?ாயித்நஇ?ைக்ஙலஇ?்ரூப்பக்ஙிச?్తరాభ?ාකංල?ยทไ?ეგ?なんみ?业企?东广?你爱我?信中?务政?动移?卦八?司公?团集?国中?國中?址网?坡加新?城商?山佛?店商?府政?戏游?机手?构机!织组??标商?港香?湾台?灣&台?臺??界世?益公?线在?络网?网文中?국한?성삼??");
+      TrieParser.parseTrie("a&027qjf--nx?12oa08--nx?2eyh3la2ckx--nx?32wqq1--nx?6&1f4a3abgm--nx?lbgw--nx??883xnn--nx?b!.&asnu?gro?ibnu?lim?moc?oc?sr?ten?ude?vog??ihsot??c!.&b&a?m?n??c&b?g?q??ep?fn?k&s?y??ln?no?oc,sn?t&n?opsgolb,?un??irfa?s??d&neit?om?tl??g!oy??hskihs?i&dem?sa??jnin?k&dov?usto??l!.&c,gro?moc?ofni?rep?t&en?ni??ude?vog??lenisiuc??m!.&ca?gro?oc?sserp?ten?vog??ahokoy?e00sf7vqn--nx??n!.&ac?cc?eman?gro?ibom?loohcs?moc?ni?o&c?fni?rp??r&d?o??s&u?w??vt?xm???p!.&bog?ca?d&em?ls??g&ni?ro??mo&c?n??oba?ten?ude??g7hyabgm--nx?ra!.&461e?6pi?iru?nru?rdda-ni?siri????q!.&eman?gro?hcs?lim?moc?ten?ude?vog???r&emac?f4a3abgm--nx?n??s!.&bup?dem?gro?hcs?moc?ten?ude?vog??ac??u!.&a&cinniv?emirc?i&hzhziropaz?stynniv??s&edo?sedo??tlay?vatlop??bs?cinimod?d&argovorik?o!roghzu???e&hzhziropaz?nvir?t??fi?g&l?ro??hk?i&stvinrehc?ykstynlemhk??k&c?m?s&nagul?t&enod?ul??v&iknarf-onavi?orteporp&end?ind?????l&iponret?opotsa&bes?ves??p??m&k?oc?s?yrk??n&c?d?i?osrehk?v?ylov??o&c?nvor??p&d?p?z??r&c?imotihz?k?ymotyhz??sk?t&en?l?z??ude?v&c?e&alokin?ik??i&alokym?hinrehc?krahk?vl?yk??k?l?o&g!inrehc??krahk??r??y&ikstinlemhk?mus?s&akrehc?sakrehc?tvonrehc???zu???v?waniko?x&a?iacal??yogan??b&125qhx--nx?3jca1d--nx?4&6&1rfz--nx?qif--nx??96rzc--nx??a&0dc4xbgm--nx?c?her??b!.&erots?gro?moc?o&c?fni??ten?ude?v&og?t??zib???cs?dhesa08--nx?g?l!.&gro?moc?ten?ude?vog???s!.&gro?moc?ten?ude?vog???u&lc?p???c&1&1q54--nx?hbgw--nx??2e9c2czf--nx?4byj9q--nx?9jr&b&2h--nx?54--nx?9s--nx??ceg--nx??a!.&gro?lim?moc?ten?ude?vog??3a09--nx!.&ca1o--nx?gva1c--nx?h&ca1o--nx?za09--nx??ta1d--nx?ua08--nx????bf76a0c7ylqbgm--nx?c!.&gnipparcs,revres-emag,s&otohpym,seccaptf,??0atf7b45--nx?a1l--nx??e!.&21k?bog?dem?gro?lim?moc?nif?o&fni?rp??ten?ude?vog??beuq??i&n&agro?ilc??tic??l!.&gro?moc?oc?ten?ude?vog???m!.&mt?ossa???n!.ossa??s!.&gro?moc?ten?ude?vog???t!w??v!.&gro?lim?moc?ten?ude?vog???yn??d&2urzc--nx?3&1wrpk--nx?c9jrcpf--nx??5xq55--nx?75yrpk--nx?a!.mon?d??b2babgm--nx?c!.vog?g9a2g2b0ae0chclc--nx??e&r!k??sopxe?timil?w??g?i!.&ased?bew?ca?hcs?lim?o&c?g??ro?ten?ym?zib??b?rdam??liub?m?n&al!raas??ob?uf??orp?r&actiderc?k??s!.&dem?gro?moc?ofni?ten?ude?v&og?t????t!.topsgolb,?za5cbgn--nx??e&17a1hbbgm--nx?2a6a1b6b1i--nx?418txh--nx?707b0e3--nx?a!.&ca?gro?hcs?lim?oc?ten?vog???b!.&ca?topsgolb,?utuoy??c&a&lp?ps??na&d?nif??rofria??d!.&edaregtmueart,keegnietsi,moc,n&esgnutiel,iemtsi,?topsgolb,zten&mitbel,sadtretteuf,??art?iug?on--nx??e!.&bil?dem?eif?gro?irp?kiir?moc?pia?ude?vog??ffoc?gg?rged??fil?g!.&gro?lim?moc?t&en?vp??ude?vog??a&gtrom?yov??elloc?nahcxe??i!.&topsgolb,vog???j!.&gro?oc?ten???kib?l&a&dmrif?srof??uhcs??m!.&ca?gro?oc?sti?ten?ude?v&irp?og???an!.&reh.togrof,sih.togrof,??em?w??n!goloc?oz?ruoblem??om?p!.&bog?gro?lim?mo&c?n??ten?ude??irg??r!.&mo&c?n??ossa?topsgolb,?a&c?wtfos??eh?u&sni?tinruf???s!.&a?b!ibnal?rofmok??c!a??d!b?n&arb?ubroflanummok???e?f?g!ro??h!f??i!trap??k!shf??l?m!oc,t??n!mygskurbrutan??o?p!p??r?s!serp??t!opsgolb,?u?vhf?w?x!uvmok??y?z??ael?ier?roh?uoh??t&atse?isbew?ov?utitsni??u&lb?qituob??v!.&21e?b&ew?og??ce&r?t??erots?gro?lim?m&oc?rif??o&c?fni??stra?t&en?ni??ude?vog??itca??xul??f&7vqn--nx?a!.&gro?moc?ten?ude?vog???b!.vog?wa9bgm--nx??c!.topsgolb,a1p--nx??g?n!.&bew?cer?erots?m&oc?rif??ofni?re&hto?p??stra?ten???p!.&gro?moc?ude???rus?t!w??w??g&2&4wq55--nx?8zrf6--nx??3&44sd3--nx?91w6j--nx??455ses--nx?69vqhr--nx?78a4d5a4prebgm--nx?a!.&gro?mo&c?n??oc?ten???b!.&0?1?2?3?4?5?6?7?8?9?a?b?c?d?e?f?g?h?i?j?k?l?m?n?o?p?q?r?s?t?u?v?w?x?y?z???c!za9a0cbgm--nx??e!.&eman?gro?ics?lim?moc?nue?ten?ude?vog???g!.&gro?oc?ten???k!.&gro?lim?moc?ten?ude?vog???m!.&drp?gro?lim?m&o&c?n??t??ude?vog???n!.&eman?gro?hcs?ibom?lim?moc?ten?ude?vog??aw?i!bmulp?ddew?h&sif?tolc??kooc?n&aelc?iart??re&enigne?tac??t&ad?ekram?hgil?lusnoc?ov?soh???o?u&rehcisrev?smas???r&o!.&az,d&ab-yrev-si,e&sufnocsim,vas-si,?nuof-si,oog-yrev-si,?e&a,cin-yrev-si,las-4-ffuts,m&-morf,agevres,ohruoyslles,?nozdop,rehwongniogyldlob,t&adidnac-a-si,is&-ybboh,golb,???fehc-a-si,golbymdaer,keeg-a&-si,si,?live-yrev-si,naf&s&citlec-a-si,niurb-a-si,tap-a-si,?xos-a-si,?ojodsnd,p&ifles,ohbew,tfe&moh,vres,??resu-xunil-a-si,s&aila&nyd,snd,?bbevres,nd&emoh,golb,mood,nyd:.&emoh,og,?,rvd,tog,?sa-skcik,u,?t&e&ews-yrev-si,nretni&ehtfodne,fodne,??hgink-a-si,s&ixetn&od,seod,?o&h-emag,l-si,???x&inuemoh,unilemoh,???ub&mah?oj???s!.&gro?moc?rep?t&en?opsgolb,?ude?vog???t?u!.&c&a?s??en?gro?moc?o&c?g??ro???v!a1c--nx??wsa08--nx??h&0ee5a3ld2ckx--nx?4wc3o--nx?8a7maabgm--nx?b!.&gro?moc?ten?ude?vog???c!.topsgolb,ir?r&aeserrecnac?uhc??taw??d0sbgp--nx?g!.&gro?lim?moc?ude?vog???m!a1j--nx??p!.&gro?i?lim?moc?ogn?ten?ude?vog???s!.&gro?lim?moc?ten?vog??a&c?nom??if??t!.&ca?im?ni?o&c?g??ro?ten???vo?zb??i&3tupk--nx?7a0oi--nx?a!.&ffo?gro?moc?ten??1p--nx??b!.&gro?moc?oc?ro?ude??om??c!.&ayb-tropora--nx?ca?d&e?m??esserp?gro?moc?o&c?g?ssa??ro?t&en?ni?roporéa??ude?vuog???f!.&dnala?iki,topsgolb,??g!.&d&om?tl??gro?moc?ude?vog???hcra?k!.&gro?moc?ofni?ten?ude?vog?zib??b4gc--nx?iw?uzus??l?maim?n&im?re??s!ed??tinifni?v!.&21k?gro?moc?oc?ten???wik?xarp??j&8da1tabbgl--nx?b!.&ossa?topsgolb,uaerrab?vuog???d?s?t!.&bew?c&a?in??eman?gro?lim?moc?o&c?g??t&en?ni?set??ude?vog?zib????k&c&a&bdeef?lb??ilc?reme??d!.topsgolb,?h!.&a&4ya0cu--nx?5wqmg--nx??b3qa0do--nx?d&2&2svcw--nx?3rvcl--nx??5xq55--nx??g&a0nt--nx?la0do--nx?ro??i&050qmg--nx?7a0oi--nx?xa0km--nx??m&1qtxm--nx?oc??npqic--nx?t&en?opsgolb,?ude?v&di?og?ta0cu--nx??xva0fz--nx?人&个?個?箇??司公?府政?絡&網?网??織&組?组??织&組?组??络&網?网??育&敎?教???n??l!.&bew?cos?dtl?gro?hcs?letoh?moc?nssa?ogn?prg?t&en?ni??ude?vog???m!.&eman?fni?gro?moc?ten?ude?vog???n&abreve?i!l?p???p!.&b&ew?og??gro?kog?m&af?oc??nog?ofni?pog?sog?ten?ude?vog?zib???row!ten??s!.topsgolb,?t?u!.&c&a?lp??dtl?e&cilop?m??gro?oc!.topsgolb,?shn?ten?vog????l&a!.&gro?lim?moc?ten?ude?vog??bolg?g?ic&nanif?os??noitanretni?t&i&gid?pac??ned???c!.&bog?lim?oc?vog???e&geips?nnahc?t?vart??f8f&pbgo--nx?tbgm--nx??g?i&.oc.topsgolb,a&f?m&e?g???m??lihmailliw?m!.&esserp?gro?moc?ten?ude?v&og?uog????n!.&oc,topsgolb,vb??o??o&btuf?oc?rit?u??p!.&a&cin&diws?gel??d&g?ortso?urawon??i&dem?mraw?nydg??k&elo&guld?rtso??slopolam?tsu?ytsyrut??l&ip?o&kzs?w&-awolats?oksnok????nimg?rog&-ai&bab?nelej??j?z??syn?tsaim?w&a&l&eib?i?o??zsraw??onamil??z&eiwolaib?mol???c&e&iw&alselob?o&nsos?rtso???le&im?zrogz???orw?p?ri??d&em?ia?ragrats??e&c&i&lrog?w&ilg?o&hc&arats?orp??klop?tak????ldeis?yzreibok??i&csjuoniws?ksromop?saldop??l&ahdop?opo??n&apokaz?ob&6?m???tatselaer?z&romop?swozam???g&alble?ezrbo&lok?nrat??ro??hcyzrblaw?i&csomohcurein?grat?klawus??k&e&rut?walcolw??inbyr?le?o&nas?tsylaib??rob&el?lam??s&als?jazel?nadg?puls?rowezrp???l&colw?e&r?vart??i&am?m???m&o&c?dar?n?tyb??s&g?iruot??t!a???n&a&gaz?nzop??i&bul?cezczs?molow?nok?zd&eb?obeiws???uleiw?y&tzslo?z&rtek?seic????o&c,fni?gn?k&celo?zdolk??lkan?n&leim?pek?t&uk?yzczs??z&copo?eing?rowaj???rga?tua?w&ejarg?ogarm???p&elks?klwwortso?ohs??romophcaz?sos?t&aiwop?en!esu??opos?ra?sezc??ude?v&irp?og!.&ap?gu?mu?o&p?s?wtsorats??rs?w&opu?u?????w&a&l&corw?sizdow??w??o&golg?k&ark?ul?zsurp??r&az?gew??tsugua?z&coks?sezr????xes?y&buzsak?d&azczseib?ikseb??hcyt?n&jes?lod-zreimizak??pal?r&ogt?uzam??walup?zutrak??z&am-awar?c&aprak?iwol?zsogdyb??dalezc?ib?s&i&lak?p??uklo?????rf?s!.&gro?moc?ten?ude?vog???t!.vog??x3b689qq6--nx??m&00tsb3--nx?1qtxm--nx?a!cbew?rirhs??b!.&gro?moc?ten?ude?vog???c!.&moc?oc?ten?vog???d!.&gro?moc?ten?ude?vog???f!i??g?h?i!.&ca?gro?moc?oc!.&clp?dtl???t&en?t??vt??k?rbg4--nx??k!.&drp?e&rianiretev?sserp??gro?lim?m&o&c?n??t??nicedem?ossa?pooc?s&eriaton?neicamrahp?sa??ude?v&og?uog????o!.&dem?gro?m&oc?uesum??o&c?rp??ten?ude?vog??c!.&a&c&-morf,irfa,?g&-morf,oy-sehcaet,?i-morf,m&-morf,all&-a-si,amai,??p&-morf,c-a-si,?s,v-morf,w-morf,z,?b&ew-sndnyd,g,?c&d-morf,n-morf,q,s-morf,?d&e&ifitrec-&si,ton-si,?llortnocduolc,?i-morf,m-morf,n&-morf,abeht-htiw-si,?s-morf,uolc&hr,smetsystuo,??e&ciffo-sndnyd,d:-morf,ocelgoog,,erf-sndnyd,i&hcet-a-si,p-sekil,?lgooghtiw,m&ina-otni-si,oh-&sndnyd,ta-sndnyd,??n&-morf,og-si,?rihcec,s:run-a-si,,t&i&nuarepo,s-ybboh,?omer-sndnyd,?v&als-elcibuc-a-si,itavresnoc-a-si,??fehc-a-si,golb&-sndnyd,sihtsetirw,?h&n-morf,o-morf,?i&h-morf,kiw-sndnyd,m-morf,r-morf,w-morf,?jn-morf,k&a-morf,cils-si,eeg-a&-si,si,?latsnaebcitsale,o-morf,row-&sndnyd,ta-sndnyd,?u,?l&a&-morf,rebil-a-si,?f-morf,i&-morf,am-sndnyd,?ru-&elpmis,taen,?ssukoreh,?mn-morf,n&a&cilbuper-a-si,f&-sllub-a-si,racsan-a-si,?i&cisum-a-si,ratrebil-a-si,??c,eerg-a-si,i-morf,m-morf,o&isam-al-a-tse,rtap-el-tse,siam-al-a-tse,?pj,t-morf,?o&c,jodsnd,m-morf,n,r,?p&i&-sndnyd,fles,ymteg,?pa&esaberif,lortnocduolc,ukoreh,??r&a:-morf,tskcor-a-si,,b,e&enigne-na-si,ggolb-a-si,h&caet-a-si,pargotohp-a-si,?krow-drah-a-si,n&gised-a-si,ia&rtlanosrep-a-si,tretne-na-si,??p&acsdnal-a-si,eekkoob-a-si,?retac-a-si,tn&iap-a-si,uh-a-si,?vres-sndnyd,y&alp-a-si,wal-a-si,??g,k,o&-morf,sivdalaicnanif-a-si,tc&a-na-si,od-a-si,??p-morf,u&as-o-nyd,eugolb-nom-tse,??s&aila&nyd,snd,?bbevres,cip-sndnyd,e&lahw-eht-sevas,mag-otni-si,?ipaelgoog,k-morf,m-morf,n&d&golb,mood,tog,?ootrac-otni-si,?r&ac-otni-si,etsohmaerd,?se&l-rof-slles,rtca-na-si,?u,wanozama.&1-&etupmoc:.&1-z,2-z,?,ts&ae&-&as-&3s,etisbew-3s,?su:-etisbew-3s,,?ht&ron-pa-&3s,etisbew-3s,?uos-pa-&3s,etisbew-3s,???ew-&su-&3s,etisbew-3s,?ue-&3s,etisbew-3s,?vog-su-&3s,etisbew-3s,spif-3s,????2-ts&aehtuos-pa-&3s,etisbew-3s,?ew-su-&3s,etisbew-3s,??3s,ble,etupmoc:.&1-ts&ae&-as,ht&ron-pa,uos-pa,??ew-&su,ue,vog-su,??2-ts&aehtuos-pa,ew-su,??,??t&arcomed-a-si,c-morf,eel&-si,rebu-si,?m-morf,n&atnuocca-na-si,e&duts-a-si,r-ot-ecaps,tnocresubuhtig,??ops&edoc,golb,ppa,?s&i&hcrana-&a-si,na-si,?laicos-a-si,pareht-a-si,tra-na-si,xetn&od,seod,??ohsfn,?u&-morf,nyekcoh-asi,?v-morf,?u&-rof-slles,e,h,oynahtretramssi,r:ug-a-si,,?v&n-morf,w-morf,?x&em,inuemoh,obaniateb,t-morf,unilemoh,?y&dnacsekil,k-morf,u,w-morf,????p?raf?s?t!.&gro?lim?mo&c?n??oc?ten?ude?vog???uesum!.&a&92chg-seacinumocelet-e-soierroc--nx?atnav?c&i&aduj?rfatsae??rollam??d&anac?enomaledasac?irolf??e&raaihpledalihp?srednu??g&hannavas?oonattahc??hamo?i&auhsu?bmuloc!hsitirb??dem?groeg?hpledalihp?l&artsua?etalif??n&igriv?rofilac??ssur?tsonod??ksa&la?rben??l&lojal?q-snl--nx?uossim!trof???m&a&bala?nap??enic?o&m?r???n&a&cirema?idni??edasap?ilorachtuos?olecrab??r&abrabatnas?ezzivs??su?t&nalta?osennim??zalp??c&dnotgnihsaw?ebeuq?i&depolcycne?ficap?hpargonaeco?lbup?sum?t&carporihc?lec?naltadim??vu??yn??d&a&dhgab?etsmraf?m?orliar??i&rdam?ulegnedleeb??leif?n&a!l&gne?nif?ragyduj?t&ocs?rop??yram???u&brofsdgybmeh?osdnaegami???r&augria?ofxo???e&c&a&l&ap?phtrib??ps??n&a&lubma?tsiser??e&fedlatsaoc?gilletni?ics!foyrotsih????pein?rof??d&nukneklov?revasem??e&rt?tsurt??f&atnas?ildliw??g&a&lliv?tireh!lanoitan???dirbmac?rog??i&cnum?nollaw??koorbrehs?l&ab?bib?cycrotom?i&ssim?txet??oks?tsac??m&affollah?it!iram??utsoc??n&golos?ilno?recul??r&a&uqs?waled!foetats???i&hs&acnal?kroy?pmahwen??otsih??omitlab?ut&an?cetihcra?inruf?luc!irga?su???vuol??s&abatad?iacnarf?sius?uoh!lum???t&a&locohc?rak?ts!e!yrtnuoc!su?????imesoy?tevroc??u&qihpargonaeco?velleb??vit&caretni?omotua???f&iuj?ohgrub??g&n&i&dliub?ginerevmuesum?kiv?lahw?nim?peekemit?vil??ulmmastsnuk??orf?r&eb&merun?nr&ats?eun???u&b&ierf?le?m&ah?uan??ram?s&mailliw!lainoloc??naitsirhc?retepts??zlas??ob&irf?mexul?????h&atu?c&raeser?sirotsih?uot??g&ea1h--nx?rubsttip??si&tirb?wej??t&laeh?ro&n?wtrof??uo&mnom?y????i&d6glbhbd9--nx?iawah?k&nisleh?s??lad!rodavlas??sissa?tannicnic??k&c&nivleeg?olc!-dna-hctaw?dnahctaw???fj?inebis?l&is?ofron??na&rfenna?t??oorbnarc?r&am&ned?reiets??oy!wen????l&a&ci&dem?golo&eahcra?meg?oz??natob?rotsih??ertnom?iromem?noita&cude?n??oc?rutluc?trop?utriv?van??e&nurb?s&ab?surb??utriv??i&artnogero?sarb??l&a&besab?hsnoegrus??e&hs?rdnevle??i&b?m!dniw????o&bup?ohcs?tsirb???m&a&dretsma?ets?h&netlehc?rud???ct?elas!urej??l&if?ohkcots?u??raf?silanruoj?u&esumyrotsihlarutan?ira&tenalp?uqa??terobra???n&a&c!irema!evitan???gihcim?i&dni?tpyge??mfoelsi?wehctaksas??e&d&alokohcs?ews?rag!cinatob?lacinatob?s&nerdlihc?u????gahnepoc?hcneum?laftsew?ppahcsnetewruutan?r&dlihc?ednaalv?hu!dnutamieh???sseig??gised!dn&atra?utsnuk???h&ab!nesie??ojts??i&lreb?tsua??l&eok?ocnil??n&ob?urbneohcs??o&dnol?gero?i&s&iv&dnadnuos?elet??nam??t&a&c&inummoc?ude!tra???dnuof?erc?i&cossa?va??kinummokelet?nissassa?r&belectsevrah?oproc?tsulli??silivic?t&nalp?s??vres&erp?noclatnemnorivne??zilivic??c&elloc?if-ecneics??ibihxe???ri?s&dnah?imaj?reffej?sral??t&erbepac?nilc?sob???r&e&b?dom?tsew?uab?zul??obredap??vahnebeok?wot??o&2a6v-seacinumoc--nx?ablib?c&edtra?ixemwen?sicnarfnas??elap?g&a&cihc?to??eidnas??i&cadnuf?diserp?ratno??llecitnom?mitiram?nirot?r&htna?ienajedoir???pohskrow?qari?r&aw!dloc?livic??dd?e&b&ma?yc??irrac?llimsiwel?naksiznarf?papswen?t&aeht?exe?nec!ecneics?larutluc?muesum?tra??s&ehc&nam?or??neum??upmoc???ia!nepo??obal?u&asonid?obal?takirak???s&a&l&g?l&ad?eh???xet??di&k?pardnarg??e&cneics!larutan??dnal?hcsi&deuj?rotsih!nizidem?rutan??selhcs??itinamuh?l&aw?egnasol?l&e&rutansecneics?xurb??iasrev???r&e&em?ugif??tsac??suohcirotsih?u&en?q&adac?itna!nacirema?su????õçacinumoc!elet-e-soierroc???gnirpsmlap?htab?i&lopanaidni?rap?uoltnias?xa??l&essurb?lod??mraeriflanoitan?n&a&blats?l??erdlihc?oi&snam?tacinummoc!elet-dna-stsop???äl??re&dnalf?lttes?mraf?nim?tnececneics??s&alg?erp??t&farc!dnastra??nalp?olip?ra!e&nif?vitaroced!su???su?xuaeb???u&b!muloc??cric???t&agilltrop?cejorp?dats?e&esum?kramnaidni??iorted?ne&m&elttes?norivne?piuqemraf??vnoc??oped?r&a!drib?enif?gttuts?hsiwej?kcor?n&acirema?ootrac??tamsa?yraropmetnoc??op&aes?snart?wen??ufknarf??s&a&cdaorb?octsae??ewhtuos?ilayol?nuk?r&ohnemled?uhlyram??urt???u&a&bgreb?etalpodaroloc??rmyc??w&ocsom?rn??x&esse?ineohp?nam?tas??y&a&bekaepasehc?w&etag?liar???camrahp?doc?e&hsub?l&ekreb?l&av!eniwydnarb??ort???n&dys?om??rrus?s&nreug?rejwen???golo&e&ahcra?g??motne?nh&cet?te??oz?po&rhtna?t??roh??hpargotohp?l&etalihp?imaf??m&edaca?onortsa??n&atob?yn??ps?r&a&ropmetnoc?tilim??e&diorbme?llag!tra??vocsid??lewej?nosameerf?otsih!dnaecneics?ecneics?gnivil!su??la&col?rutan??retupmoc?su??tsudnidnaecneics??spelipe?t&eicos!lacirotsih??i&nummoc?srevinu??nuoc???z&arg?iewhcs?nil?ojadab?urcatnas??моки?םילשורי????n&a!.&gro?moc?ten?ude??brud?cilbuper?f?s&ood?sin??varac??c!.&ah?bh?c&a?s??d&5xq55--nx?g?s??eh?g&la0do--nx?ro??h&a?q?s??i&7a0oi--nx?h??j&b?f?t?x?z??kh?l&h?im?j??m&n?oc??n&h?l?s?y??om?qc?s&g?j?wanozama.etupmoc:.1-htron-nc,,?ten?ude?vog?wt?x&g?j?n?s??z&g?x??司公?絡網?络网???e&erg?fuak?hctik?i&libommi?w??r!ednaalv??sier??g!.&ca?gro?moc?ten?ude?vog???h!.&bog?gro?lim?moc?ten?ude???i!.&c&a?in??dni?gro?lim?mrif?neg?oc?ser?t&en?opsgolb,?ude?vog??lreb??k!.&gro?ten?ude?vog???leok?m!.&cyn,gro?ude?vog???o&dnol?i&siv!orue??t&a&cude?dnuof??cu&a?rtsnoc????mrom?pq?siam??p!.&gro?oc?ten?ude?vog???re&c?yab??s!.&gro?moc?osrep?tra?ude?v&inu?uog????t!.&dni?esnefed?gro?ltni?m&oc!nim??siruot??n&erut?if??o&fni?srep??sn&e?r??t&an?en!irga?ude??rnr??unr?vog???ustad?v!.&ca?eman?gro?htlaeh?moc?o&fni?rp??t&en?ni??ude?vog?zib???wot!epac???o&76i4orfy--nx?a!.&bp?de?go?oc?ti?vg???b!.&bog?gro?lim?moc?t&en?ni??ude?v&og?t???olg??c!.&bew?cer?gro?lim?m&o&c?n??rif??ofni?stra?t&en?ni??ude?vog???d!.&b&ew?og??dls?gro?lim?moc?t&en?ra??ude?vog??agoba??e&c?dor??f!ni!.&e&gdelwonk-fo-l&errab,lerrab,?ht-skorg,rom-rof-ereh,?llatiswonk,p&ifles,ohbew,?ruo-rof,s&iht-skorg,ndnyd,????gn!am??hwsohw?i!.&buhtig,din,moc??b?dua?r?syhp??j!.&eman?gro?hcs?lim?moc?ten?ude?vog???m!.&gro?moc?ten?ude?vog??g?il??n!.&a&0&b-ekhgnark--nx?c-iehsrgev--nx?g-lksedlig--nx?k-negnanvk--nx??1&p-nedragy--nx?q-&asierrs--nx?grebsnt--nx?lado-rs--nx?n&egnidl--nx?orf-rs--nx??regnayh--nx?ssofenh--nx??r-datsgrt--nx?s-ladrjts--nx?v-y&senner--nx?vrejks--nx???3g-datsobegh--nx?4&5-&dnaleprj--nx?goksnerl--nx?tednalyh--nx??6-neladnjm--nx?s-&antouvachb--nx?impouvtalm--nx??y-&agrjnevvad--nx?ikhvlaraeb--nx???7k-antouvacchb--nx?8&k-rekie-erv--nx?l-ladrua-rs--nx?m-darehsdrk--nx??a!.sg??bct-eimeuvejsemn--nx?d&do?iisevvad?lov?narts?uas??f&1-&l--nx?s--nx??2-h--nx??g&10aq0-ineve--nx?av?ev?lot?r&ajn&evvad?u??ájn&evvad?u????h?iz-lf--nx?j&ddadab?sel??k&el?hoj&sarak?šárák??iiv&ag&na&el?g??ŋ&ael?ág???ran???l&f?lahrevo?o&ms?s??sennev?t-&ilm--nx?tom--nx??u&-edr--nx?s??øms??muar?n&0-tsr--nx?2-dob--nx?5-&asir--nx?tals--nx??a&r!-i-om?f?t??t??douvsatvid?kiv?m&os?øs??n&od?ød??ra?sen?t&aouvatheig?ouv&a&c&ch&ab?áb??h&ab?áb???n??i&ag?ág??sa&mo?ttvid??án???z-rey--nx?ær&f?t???o&p-&ladr--nx?sens--nx??q-nagv--nx?r-asns--nx?s-kjks--nx?v-murb--nx?w-&anr&f--nx?t--nx??ublk--nx???ppol?q&0-t&baol--nx?soum--nx?veib--nx??x-&ipphl--nx?r&embh--nx?imph--nx???y-tinks--nx??r&f-atsr--nx?g-&an&ms--nx?nd--nx??e&drf--nx?ngs--nx??murs--nx?netl--nx?olmb--nx?sorr--nx??h-&a&lms--nx?yrf--nx??emjt--nx??i&-&lboh--nx?rsir--nx?y&d&ar--nx?na--nx??ksa--nx?lem--nx?r&ul--nx?yd--nx????stu??j-&drav--nx?rolf--nx?sdav--nx??kua?l-&drojf--nx?lares--nx??m-tlohr--nx?n-esans--nx?olf?p-sdnil--nx?s-ladrl--nx?tih?v-rvsyt--nx??s&a&ns?ons??i&ar?er&dron?r&os?øs???ár??la&g?h??mor!t??sir?uf?åns??t&koulo&nka?ŋká??la?p-raddjb--nx?r-agrjnu--nx?s&aefr&ammah?ámmáh??orf?r&o?ø???u-vreiks--nx??u&h-dnusel--nx?i-&drojfk--nx?vleslm--nx??j-ekerom--nx?k-rekrem--nx?u-&dnalr--nx?goksr--nx?sensk--nx??v-nekyr--nx?w-&k&abrd--nx?ivjg--nx??oryso--nx??y-y&dnas--nx?mrak--nx?n&art--nx?nif--nx??reva--nx??z-smort--nx??v!.sg?ledatskork?reiks??wh-antouvn--nx?x&9-dlofts--nx.aoq-relv--nx?d-nmaherk--nx?f-dnalnks--nx?h-neltloh--nx?i-drgeppo--nx?j-gve&gnal--nx?lreb--nx??m-negnilr--nx?n-drojfvk--nx??y&7-ujdaehal--nx?8-antouvig--nx?b-&dlofrs--nx?goksmr--nx?kivryr--nx?retslj--nx??e-nejsom--nx?f-y&krajb--nx?re&dni--nx?tso--nx??stivk--nx??g-regark--nx?orf?ørf??z9-drojfstb--nx??b&25-akiivagael--nx?53ay7-olousech--nx?a&iy-gv--nx?le-tl&b--nx?s--nx??n0-ydr--nx??c&0-dnal-erdns--nx?z-netot-erts--nx??g&g-regnarav-rs--nx?o-nejssendnas--nx??ju-erdils-ertsy--nx?nj-dnalh-goksrua--nx?q&q-ladsmor-go-erm--nx.&ari-yreh--nx?ednas??s-neslahsladrjts--nx???ca&4s-atsaefrmmh--nx?8m-dnusynnrb--nx?il-tl--nx?le-slg--nx?n5-rdib--nx?op-drgl--nx?uw-ynnrb--nx??d&a&qx-tggrv--nx?reh!nnivk?sd&ork?ørk??uas??ts&e&bi?kkar?llyh?nnan??g&ort?ørt??k&alf?irderf??levev?mirg?obeg&ah?æh??r&ah?ejg????barm-jdddb--nx?ie!rah?s&etivk?ladman???lof&r&os?øs??ts&ev.ednas?o.relav?ø.relåv???n&a&l&-erd&n&os?øs??ron??adroh.so?dron.&a&g5-b--nx?ri-yreh--nx??ob?y&oreh?øreh??øb??e&m!lejh??pr&oj?øj??vi??gyb?n&aks?åks??o&h-goksrua?rf??r&o?ua?ø??tros?øh-goksrua??rts!e&devt?lab?mloh???s&ellil?naitsirk?rof???u&l!os??s!d&im?lejt??e&guah?l&a?å???kkoh?lavk?naitsirk?r&af?eg&e?ie???tef?y&onnorb?ønnørb?????r&a&blavs!.sg??g&eppo?la???o&j&f&a!dniv?k?vk??die?e&dnas?kkelf??llins?r&iel?ots??s&lab?t&ab?åb??yt??å!k??ævk??les??ts??åg&eppo?lå???ureksub.sen??e&ayb-yrettn--nx?d&ar?lom?r&of?øf??år??g&gyr?nats??i&meuv&ejsem&aan?åån??sekaal??rjea??j&d&ef?oks??les??k&er&aom?åom??hgna&ark?årk??iregnir?kot!s??s&ig?uaf???l&bmab?kyb?l&av?ehtats??oh??m&it?ojt?øjt??n&arg?g&os?øs??meh?reil?te?ummok?yrb??r&dils-erts&ev?y&o?ø???ua?vod??sa&ans?åns??t&robraa?spaav??urg??f&62ats-ugsrop--nx?a&10-ujvrekkhr--nx?7k-tajjrv-attm--nx??o!.sg?h??s!.sg??v!.sg???g&5aly-yr&n--nx?v--nx??a&llor?ve&gnal?lreb???n&av!snellu??org??oks&die?m&or?ør??ner&ol?øl??r&o?ø???r&eb!adnar?edyps?s&die?elf?gnok?n&ot?øt????obspras??uahatsla?åve&gnal?lreb???h&0alu-ysm--nx?7&4ay8-akiivagg--nx?5ay7-atkoulok--nx??a!.sg???i&e&hsr&agev?ågev??rf??k&h&avlaraeb?ávlaraeb??s??lm&a?å??mpouvtal&am?ám??pph&al?ál??rrounaddleid?ssaneve?ššáneve??j&0aoq-ysgv--nx?94bawh-akhojrk--nx??k&a&b&ord?ørd??jks?lleis??iv!aklejps?l&am?evs?u??mag?nel?ojg?r&a&l?n??epok?iel?y&or?ør???s&ah?kel?om??øjg??kabene?ojsarak?ram&deh.&aoq-relv--nx?rel&av?åv??so??e&let.&ag5-b--nx?ob?øb??ra???åjks??l&a!d&anrus?d&numurb?ron??e&gnard?nte?s&meh?sin??ttin??g&is?nyl??kro?l&em?l&ejfttah?of??u&ag-ertdim?s???n&am?era?gos?i&b?nroh?r??kos?nus?oj??o-&dron?r&os?øs???ppo?r&a!l?nram??e&gne?l?v??is?o&jts?ts??u&a-&dron?r&os?øs???h??å?æl?øjts??s&e&jg?nivk?ryf??kav?mor-go-er&om.&ednas?yoreh??øm.&ednas?yøreh???uag??t&las?rajh?suan??v&l&a?e-rots??u-go-eron??yt??ksedlig?res&a?å???bib&eklof?seklyf??es!dah??h!.sg??i&m?syrt??l&ejf?ov&etsua?gnit?ksa?sdie???n!.sg??o!.sg?boh?g?h??r!.sg??å!ksedlig??øboh??m&a&rah?vk??f!.sg??h!.sg??i&e&h&dnort?rtsua?ssej??rkrejb??ksa??ol?t!.sg??u&dom?esum?r&ab?drejg?evle?os?uh?æb?øs??ttals???n&a&g&av?okssman?åv??jlis?or?r&g?rev???e&d&do&sen?ton??lah?r&agy&o?ø??ojfsam???g&iets?n&a&l&as?lab??n&avk?ævk??t&arg?ddosen??v&al?essov???i&d&ol?øl??l&ar?ær???yl??reb??iks?k&srot?y&or?ør???l&a&d&gnos?n&er?ojm?øjm??om??tloh??ug?åtloh??mmard?ojs&om?sendnas??ppolg?s&lahsladr&ojts?øjts??o??t&o&l?t-erts&ev?o?ø???roh?øl??vly&kkys?nav??yam-naj!.sg??øjs&om?sendnas???g&orf?ujb??i&dnaort?vnarg??kob?ladendua?maherk&a?å??n&it?urgsrop??orf-&dron?r&os?øs???r&aieb?evats??sfev?uaks?yrts??o&6axi-ygvtsev--nx?c,d&ob?rav??ievs?kssouf?l&m&ob?øb??ous&adna?ech&ac?áč???so!.sg???msdeks?niekotuak?r&egark?olf?y&oso?øso???s&dav?mort???p&ed?p&akdron?elk???r&a&d&dj&ab?áb??iab??jtif?luag?mah?vsyt??e&gn&a&k&iel?ro??merb?n&at?mas??rav-r&os?øs??srop?talf?v&ats?el??y&oh?øh???ivsgnok??il?jkniets?k&a&nvej?rem?s&gnir?nellu???ie-er&den?v&o?ø???ram?sa?årem??la&jf?vh??m&b&ah?áh??mahellil??nnul?ts&l&oj?øj??ul??y&o?ø???imp&ah?áh??m!.sg??osir?t!.sg??ádiáb?ævsyt?øsir??s&adnil?en&dnas?e&dga?k&ri&b?k??som??ve??me&h?jg??nroh-go-ejve?s&a?ednil?k&o?ø??of?yt?å??tsev??gv?hf?igaval?o&r&or?ør??sman??so&fen&oh?øh??m?v??uh&lem?sreka.sen??å!dnil???t&a&baol?g&aov?grav??jjr&av-attam?áv-attám??l&a&b?s??ás??soum?ts?v&eib?our???e&dnaly&oh?øh??f?s&nyt?rokomsdeks?sen??vtpiks??in&aks?áks??loh&ar?år??n!.sg??o&m&a?å??psgolb,?s!.sg?efremmah?or?ør??terdi?á&baol?ggráv?lá&b?s??soum?veib???u&b!.sg?alk?e&dna?gnir?nner??les?ælk??dra&b?eb??g&nasrop?vi?ŋásrop??j&daehal&a?á??jedub?v&arekkhar?árekkhár???ksiouf?n&diaegadvoug?taed???v&irp?lesl&am?åm???y&b&essen?nart?sebel?tsev??o&d&ar?na!s??or??gavtsev?k&rajb?sa??lem?mrak?n&art?n&if?orb???r&a&mah?n?v??e&dni?t&so?ton??va??ul?yd??s&am?enner?gav?lrak?tivk??vrejks??ø&d&ar?na!s??ør??gåvtsev?k&rajb?sa??lem?mrak?n&art?n&if?ørb???r&e&dni?t&so?tøn??va??ul?yd?æ&n?v???s&enner?gåv?tivk?åm??vrejks???á&slág?tlá?vreiks??å&gåv?h?jddådåb?lf??ø&d&ob?rav??r&egark?olf??s&dav?mort????u??o&b?f?ttat??r!.&cer?erots?gro?m&o&c?n??rif?t??ofni?stra?t&n?opsgolb,?www??ea!.&a&ac?cgd?idem??bulc!orea??ci&ffartria?taborea??e&c&alptekram?n&a&l&lievrus-ria?ubma??netniam?rusni??erefnoc???gnahcxe?mordorea?ni&gne?lria?zagam??rawtfos??gni&d&art?ilg!arap?gnah???l&dnahdnuorg?ledom??noollab?retac?sael?t&lusnoc?uhcarap??vidyks??hcraeser?ixat?l&anruoj?euf?icnuoc?ortnoc!-ciffart-ria???n&gised?oi&nu?t&a&cifitrec?ercer?gi&tsevni-tnedicca?van??i&cossa!-regnessap??valivic??redef??cudorp?neverp-tnedicca????ograc?p&ihsnoipmahc?uorg!gnikrow???r&e&dart?enigne?korb?niart?trahc??o&htua?tacude???s&citsigol?e&civres?r??krow?serp!xe??tnega??t&farcr&ia?otor??hgi&erf?l&f?orcim???liubemoh?n&atlusnoc?e&duts?m&esuma?n&iatretne?revog??piuqe????olip?ropria?si&lanruoj?tneics???w&erc?ohs??y&cnegreme?dobper?tefas????p!.&a&ca?pc??dem?gne?r&ab?uj??wal????s!.&gro?moc?ten???t!.&gro?lim?moc?ten?ude?vog??o&hp?v??tol??ykot??p&a&ehc?s??g!.&gro?ibom?moc?ossa?ten?ude???iz?j!.&a&bihc!.&a&bihciakoy?don?ma&him?ye&ragan?tat???r&a&bom?gan?hihci??u&agedos?kas?ustak???s&os?ufomihs??t&amihcay?iran??w&a&g&im&anah?o??omak??kihci?zustum??ihsak??y&agamak?imonihci???e&akas?nagot??i&azni?esohc?h&asa?s&abanuf?ohc???ka&to?zok??musi?orihs?r&akihabihsokoy?o&dim?tak??ukujuk??usihs??nano&hc?yk??o&d&iakustoy?ustam??hsonhot?k&a&rihs?t??iba??nihsaran?sobimanim?tas&arihsimao?imot??uhc?yihcay??u&kujno?s&ayaru?t&imik?tuf???zarasik????g&as!.&a&gas?m&a&tamah?yik??ihsak??rat?t&a&gatik?hatik??ira!ihsin????e&kaira?nimimak??i&akneg?g&aruyk?o??h&c&amo?uo??siorihs??kaznak?modukuf?ra&gonihsoy?mi???nezih?u&k&at?ohuok??s&ot?tarak?????ihs!.&a&kok?m&a&hagan?yirom??ihsakat??rabiam?wagoton??e&miharot?nokih??houyr?i&azaihsin?esok?kustakat?moihsagih??na&mihcahimo?nok??o&hsia?mag?t&asoyot?ok?tir???us&ay?t&asuk?o??????k&aso!.&a&d&awihsik?eki??k&a&noyot?s&akaayahihc?oihsagih???oadat?uziak??m&ayas!akaso??odak??r&a&bustam?wihsak??ediijuf??t&akarih?i&k?us???wag&ayen?odoyihsagih???e&son?tawanojihs??honim?i&akas?h&cugirom?s&ayabadnot?i&a&kat?t??n??oyimusihsagih???k&a&rabi?sim??ustakat??muzi?r&ijat?otamuk???nan&ak?n&ah?es???o&ay?n&a&ganihcawak?simuzi?tak??eba?ikibah?oyot??t&anim?iad?omamihs??uhc??ust&oimuzi?tes????ou&kuf!.&a&d&amay?eos??g&no?ok?usak??hiku?k&awayim?uzii??ma&kan?y&asih?im???rawak?t&a&gon?ka&h?num?t???umo??wa&g&a&kan?nay?t??ias??ko!rih???y&ihsa?usak???e&m&ay?uruk??taruk?us??i&a&nohs?raihcat??goruk?h&cukuf?s&a&gih?hukuy??in???k&a&gako?muzim??iust?o?ustani??m&anim?otihsoynihs?u??r&ogo?ugasas??usu??ne&siek?zu&b?kihc???o&gukihc?h&ak?ot?ukihc??j&ono?ukihc??kayim?nihsukihc?to?uhc??u&fiazad?gnihs?stoyot????zihs!.&a&bmetog?d&amihs?eijuf?ihsoy?omihs??kouzihs?mihsim?ra&biah?honikam??tawi?wa&g&ekak?ukik??kijuf??yimonijuf??i&a&ra?sok??hcamirom?juf?kaz&eamo?ustam??ma&nnak?ta??nukonuzi?orukuf??nohenawak?o&nosus?ti??u&stamamah?z&a&mun?wak??i!ay?i&hs&agih?in??manim??mihs????????m&a&tias!.&a&d&ihsoy?ot?usah??k&a&dih?sa??o&arihs?s???m&a&tias?y&as?o&rom?tah??ustamihsagih???i&hsagurust?jawak??uri??ni?wa&g&e&ko?man??ikot?o??k&ara?i&hsoy?mak???ru?zorokot??y&a&g&amuk?ihsok?otah??kuf??imo??ziin??e&bakusak?ogawak?sogo?ttas?zokoy??i&baraw?h&cugawak?s&oyim?ubustam???iroy?k&ato?ihs?u&k?stawi???m&akoyr?i&hsoy?juf??uziimak???naznar?o&dakas?ihsay?jnoh?n&a&go?nim??imijuf?nah?oy??r&ihsayim?otagan??t&asim!ak??igus?omatik??zak??u&bihcihc!ihsagih??sonuok?ynah????y&ak&aw!.&a&d&ira?notimak??kadih?ma&h&arihs?im??y&a&kaw?tik??oduk???ru&ustakihcan?y??sauy?wa&g&a&dira?zok??orih??konik??yok?zok??e&banat?dawi??i&garustak?jiat?mani??naniak?o&bog?nimik?t&asim?omihs&ah?uk????ugnihs???o!.&a&jos?koasak?m&ay&ako?ust??ihsayah??r&abi?ukawaihsin??wi&aka?nam???e&gakay?kaw??i&gan?h&cu&kasa?otes??sahakat??k&asim?ihsaruk??miin??n&anemuk?ezib??o&hsotas?jnihs?n&amat?imagak??ohs?uhcibik?????ot!.&a&damay?got?koakat?may&etat?ot??nahoj?riat?waki&inakan?reman???eb&ayo?oruk??i&h&asa?ciimak?sahanuf??kuzanu?m&an&i?ot??ih???nezuyn?otnan?u&hcuf?stimukuf?z&imi?ou???????ihs&o&gak!.&a&m&ayuok?ihsogak??si?yonak??e&banawak?n&at&akan?imanim??uka??tomoonihsin??i&adnesamustas?k&azarukam?oih??m&ama?uzi??usuy??nesi?o&knik?os?tomustam??uzimurat???rih!.&a&ka&n?s??m&ayukuf?i&hsorihihsagih?j&ate?imakikaso????r&a&bohs?h&ekat?im???es??tiak?wiad??e&kato?ruk??i&h&ci&akustah?mono?nihs??s&inares?oyim???manimasa?uk??negokikesnij?o&gnoh?namuk??uhcuf????uk&ot!.&a&bihci?mi&hsu&kot?stamok??m??wagakan??egihsustam?i&gum?h&coganas?soyim??kijaw?m&anim?uzia??ukihsihs??nan&a?iak??o&nati?turan????uf!.&a&batuf?m&a&to?y&enak?irok???ihs&im?ukuf??os?uko??r&aboihsatik?uganat??ta&katik?mawak?rih??w&a&g&akus?emas?uy??k&a&mat?rihs?sa??ihsi??nah??ohs???e&gnabuzia?iman?ta&d?tii???i&adnab?enet?hs&agih?iimagak??k&a&wi?zimuzi??ubay??minuk?r&ook?ustamay???nihsiat?o&g&etomo?ihsin?nan?omihs??no!duruf?rih??rihsawani?ta&may?simuzia???u&rahim?stamakawuzia?zia&ihsin?nay???????nug!.&a&bawak?doyihc?k&anna?oi&hsoy?juf?mot???m&ayakat?ustagaihsagih??n&ihsatak?nak??r&ahonagan?nak?o?u&kati?mamat???t&amun?inomihs?o??w&akubihs?iem?ohs???i&hsa&beam?yabetat??kas&akat?esi??m&akanim?uzio??ogamust?rodim??o&jonakan?n&eu?oyikust??tnihs??u&komnan?stasuk?yrik?????ran!.&a&bihsak?d&akatotamay?u!o???guraki?m&ay&atik&imak?omihs??irokotamay??oki??ra&hihsak?n??wa&geson?knet???e&kayim?ozamay?sog?ustim??i&a&rukas?wak??garustak?h&ciomihs?sinawak??jo?ka&mnak?toruk??makawak?nos?r&net?otakat?ugeh???o&d&na?oyo??gnas?jnihs?nihsoy!ihsagih??tomarawat?yrok????t&ag&amay!.&a&dihsio?k&atarihs?ourust??may&a&kan?rum??enak?onimak??rukho?ta&ga&may?nuf??hakat?kas??wa&g&ekas?orumam??ki&hsin?m??z&anabo?enoy?ot???zuy??e&agas?bonamay?dii?nihsagih?o??i&a&gan?nohs??h&asa?sinawak??nugo??o&dnet?jnihs?ynan??ukohak???iin!.&a&ga?k&ium?oagan??munou!imanim??t&a&bihs?giin??ioy??w&a&gioti?kikes?zuy??irak??yijo??e&kustim?mabust??i&aniat?hcamakot?kaz&awihsak?omuzi??m&a&gat?karum??o???n&anust?esog??o&das?ihcot?jnas?k&ihay?oym??mak?naga?ries??u&ories?steoj?????i&ka!.&a&go?k&asok?oimak??t&ago!rihcah??ika!atik???w&aki?oyk???e&mojog?natim?suranihsagih?t&ado?okoy???i&hsoyirom?magatak?naokimak??nesiad?o&hakin?jnoh!iruy??nuzak?rihson?tasi&juf?m??yjnoh??u&kobmes?oppah????o!.&a&dakatognub?m&asah?ihsemih??su?t&ekat?i&h?o????e&onokok?ustimak??i&jih?k&asinuk?ias?usu??mukust??onoognub?u&fuy?juk?ppeb?suk??????wa&ga&k!.&a&mihsoan?rihotok?waga&kihsagih?ya???emaguram?i&j&nonak?ustnez??kunas?monihcu??o&hsonot?nnam?yotim??u&st&amakat?odat??zatu????nak!.&a&dustam?kus&okoy?tarih??maz?nibe?r&a&gihsaimanim?h&esi?imagas??wa&do?guy???u&im?kamak???tikamay?wa&k&ia?oyik?umas??sijuf??yimonin??e&nokah?saya??i&akan?esiak?gusta?hsuz?kasagihc?o?ukust??o&nadah?sio?tamay?????kihsi!.&a&danihcu?gak?kihs?mijaw?t&abust?ikawak??wazanak??i&gurust?hcionon?mon?ukah??nasukah?o&anan?ton!akan???u&kohak?stamok?z&imana?us?????niko!.&a&han?m&arat?ijemuk?uru??n&e&dak?zi??no??ra&hihsin?rih??wa&kihsi?niko??yehi?zonig??e&osaru?seay??i&hsagih?jomihs?k&a&gihsi?not??ihsakot??m&a&ginuk?kihsug?maz??igo?otekat??nuga!noy???n&a&moti?timoy?wonig??i&jikan?k???o&gan?jnan?tiad&atik?imanim???u&botom?kusug&akan!atik??imot??rab&anoy?eah???????ca?d&a?e??e&im!.&a&bot?k&asustam?uzus??m&a&him?y&emak?im???ihs??nawuk?wi&em?k???e&bani?ogawak?si!imanim???i&arataw?gusim?h&asa?ciakkoy??k&a&mat?sosik?t??iat??raban??o&dat?hik?n&amuk?ihseru?o&du?mok????ust???mihe!.&a&m&a&h&ataway?iin??yustam??ij&awu?imak???taki!man???ebot?i&anoh?kasam?rabami??n&ania?egokamuk?oot??o&jias?kihcu?nustam?uhcukokihs?yi!es???u&kohik?zo????n!amihs!.&a&d&amah?ho?usam??kustay?m&a?ihsoni&hsin?ko???wakih??e&namihs?ustam??i&g&aka?usay??konikak?mikih??nannu?o&mu&kay?zi!ihsagih?uko???nawust?tasim??u&stog?yamat?????tawi!.&a&bahay?d&amay?on??koirom?t&a&honat?katnezukir??imus??w&as&ijuf?uzim??ihs???e&hon&i&hci?n??uk??tawi??i&a&duf?murak?wak??h&custo?si&amak?ukuzihs???j&oboj?uk??k&a&m&anah?uzuk??sagenak??esonihci??m&akatik?uzia&rih?wi????o&kayim?no&rih?t??tanufo??uhso????gl?i&g&ayim!.&a&dukak?m&a&goihs?kihs??ihsustam!ihsagih??un&awi?nesek???r&awago?iho??ta&bihs?rum??w&a&gano?kuruf??iat??y&imot?ukaw???e&mot?nimes??i&hsiorihs?ka&monihsi?s&awak?o???mak?r&ataw?o&muram?tan????o&az?jagat?t&asim?omamay???u&fir?k&irnasimanim?uhsakihcihs?????ihcot!.&a&g&a&h?kihsa??ust??kom?m&ay&o?usarak??unak??r&a&boihsusan?watho??iho?ukas??t&akihsin?iay??wa&konimak?zenakat??y&imonustu?oihs???e&iiju?kustomihs?nufawi??i&akihci?g&etom?ihcot?on???o&k&ihsam?kin??nas?sioruk?tab??u&bim?san?????h&c&ia!.&a&dnah?m&a!h&akat?im??yuni??ihs&ibot?ust???r&a&hat?tihs??ik?u&ihsagih?kawi???t&ihc?o&k?yot???wa&koyot?zani??yi&monihci?rak???e&inak?k&aoyot?usa??manokot?noyot??i&a&gusak?kot?sia??eot?h&asairawo?cugo?s&ahoyot?oyim???k&a&mok?zako??ihssi??motay?rogamag??n&an&ikeh?ok??ihssin??o&got?ihsin?jna?rihsnihs?suf?tes??u&bo?raho?s&oyik?takihs??yrihc?zah????ok!.&a&dusay?kadih?mayotom?r&ah&im?usuy??umakan??sot!ihsin??wa&g&atik?odoyin??k&as?o????i&esieg?hco!k??jamu?k&a!sus??usto??ma&gak?k??rahan??o&mukus?n&i?ust!ihsagih???torum?yot!o???u&koknan?zimihsasot????ugamay!.&a&m&ayukot?ihso??toyot??e&bu?subat??i&gah?kesonomihs?nukawi?rakih??nanuhs?otagan?u&ba?foh?otim?stamaduk?uy?????sanamay!.&a&dihsoyijuf?mayabat?r&ahoneu?ustakihsin??w&a&k&ayah?ijuf??suran??ohs???egusok?i&ak?h&cimakan?s&anamay?od???k&asarin?u&feuf?sto????o&k&akanamay?ihcugawakijuf??nihso?t&asimawakihci?ukoh??uhc??spla-imanim?u&b&nan?onim??fok?hsok?rust?????ka&rabi!.&a&bukust?gok?kan!ihcatih??m&a&sak?timo?wi??ihsak?ustomihs??ni?r&a&hihcu?way??u&agimusak?ihcust???t&ag&amay?eman??oihcatih??w&ag&arukas?o??os??yi&moihcatih?rom???e&bomot?dirot?not?tadomihs??i&a&k&as?ot??rao??esukihc?gahakat?h&asa?catih??k&a&rabi?saguyr??ihsani?uy??ma?rukustamat??o&dnab?giad?him?kati?rihsijuf?soj?t&asorihs?im??yihcay??u&fius?kihsu?simak????sagan!.&a&m&abo?ihsust??natawak?r&abamihs?u&mo?ustam???wijihc?yahasi??i&akias?hies?k&asagan?i??masah??neznu?o&besas?darih?t&eso?og!imaknihs????ust&igot?onihcuk?uf????zayim!.&a&biihs?guyh?k&oebon?ustorom??mihsuk?r&emihsin?uatik??ta&katik?mim??wag&atik?odak??ya??e&banakat?sakog??i&hsayabok?kaza&kat?yim??m&animawak?ot&inuk?nihs????nanihcin?o&j&ik?onokayim??n&ibe?ust??tias??urahakat????ro&moa!.&a&dawot?turust?wasim??e&hon&ihc&ah?ihs??nas?og?ukor??sario??i&anarih?ganayati?hsioruk?jehon?kasorih?makihsah?nawo?r&amodakan?omoa???o&gnihs?kkat??u&ragust?stum????ttot!.&a&r&ahawak?uotok??sa&kaw?sim???egok?irottot?nanihcin?o&ganoy?nih?tanimiakas??u&bnan?z&ay?ihc??????ukuf!.&a&deki?gurust?ma&bo?h&akat?im??yustak??sakaw??eabas?i&akas?ho?jiehie?ukuf??nezihce!imanim??ono????o&c?diakkoh!.&a&deki?gakihset?hcebihs?k&adih?u&fib?narihs???m&ayiruk?hot?ihs&orihatik?ukuf??oras?usta??r&ib&a!ka??o?uruf??ozo?u&gakihsagih?oyot???sakim?ta&gikust?mun??w&a&ga&k&an?uf??nus!imak???k&aru?i&h&asa?sagih??kat?mak??omihs?um??zimawi??ine?oyk??yot??e&a&mustam?nan??b&a&kihs?yak??o&noroh?to???ian?k&ihsam?ufoto??nakami?ppoko!ihsin??sotihc?tad!okah??uonikat??i&a&bib?mokamot?n&a&k&kaw?oroh??wi??eomak?ihsatu?okik?usta&moruk?sakan????eib?h&c&ioy?u&bmek?irihs???s&ase?ekka?oknar?uesom???jufirihsir?k&amamihs?i&at?n???m&atik?otoyot??oa&kihs?rihs??r&a&hs?kihsi?mot??ihs&aba?ir??otarib???n&a&hctuk?rorum?se?tokahs??uber??o&kayot?m&ire?ukay??naruf!ima&k?nim???orih?r&ih&ibo?suk??o&bah?h&i&b?hsimak??sa??pnan?yan??umen??t&asoyik?eko?ukoh???u&bassa?kotnihs?m&assaw?uo??pp&akiin?en&ioto?nuk??ip??rato?s&akat?t&eb&e?i&a?hs!a??robon??m&e?o&m?takan???no&h?tamah??o&mik?s?t??u&kir?ppihc?st???onihsnihs?ufuras??uaru??yru!koh??zimihs!ok?????g!oyh!.&a&bmat?dnas?gusak?k&at?o&oyot?y??uzarakat??m&ayasas?irah??wa&g&ani?okak??k&i&hci?mak??oy???yi&hsa?monihsin???i&asak?hs&aka?i&at?nawak???j&awa!imanim??emih??k&a&goa?s&agama?ukuf??wihsin??i&hsog?m???mati?oia?rogimak??n&annas?esnonihs??o&gasa!kat??ka?n&ikat?o?ustat??rihsay?sihs?tomus?yas??u&bay?gnihs?????nagan!.&a&bukah?d&a&w?yim??e&ki?u??ii??k&a&s&ay?uki??zus??ihsoo?ousay??m&ay&akat?ii??i&hsukufosik?jii??ukihc??n&i!hsetat??uzii??r&ah?ugot??saim?t&agamay?oyim??w&a&g&a&kan?n??o??kustam?ziurak??onim!imanim??u&koo?s!omihs????ya&ko?rih???e&akas?nagamok?subo??i&gakat?h&asa?c&a!mo!nanihs???uonamay??sukagot??k&a&kas?mimanim?to??ia&atik?imanim??oa?uzihcom??m&akawak?ijuf?o!t???r&ato?ijoihs?omakat???n&ana?esnoawazon??o&hukas?n&a&gan?kan??i&hc?muza??ustat??romok?si&gan?k??tomustam??u&k&as?ohukihc??stamega????to&mamuk!.&a&gamay?mihsak?rahihsin?s&ok?ukama!imak???tamanim??enufim?i&h&cukik?soyotih??k&ihsam?u??nugo!imanim??romakat??o&ara?rihsustay?sa?t&amay?om&amuk?us??u!koyg???yohc??u&sagan?zo????yk!.&a&bmatoyk?k&ies?oemak?uzaw??mayi&h&cukuf?sagih??muk??nihsamay?rawatiju?t&away?ik???e&ba&nat!oyk??ya??di?ni??i&ju?kazamayo?manim??natnan?o&gnatoyk?kum?mak?rihsamayimanim?y&gakan?ka&koagan?s??oj???u&ruziam?z&ayim?ik??????ykot!.&a&d&i&hcam?mus??oyihc??k&atim?ihsustak??m&a&t!uko??yarumihsa&gih?sum???i&hs&agoa?ika?o!t??uzuok??ren???r&a&honih?wasago??iadok?umah??ssuf?t&ik?o??wa&g&anihs?ode??k&ara?ihcat???y&agates?ubihs???e&amok?donih?m&o?urukihsagih??soyik??i&enagok?gani?h&ca&da?tinuk??sabati??j&nubukok?oihcah??manigus??o&huzim?jihcah?n&akan?ih!sasum??urika??rugem?t&a&mayihsagih?nim??iat?ok??uhc?yknub??u&fohc?hcuf?kujnihs?????r&g?o??topsgolb,ufig!.&a&d&eki?ih??kimot?m&ayakat?ihsah??ne?raha&gi&kes?makak??sak??taga&may?tik??wa&g&ibi?ustakan??karihs!ihsagih????e&katim?uawak??i&gohakas?hc&apna?uonaw??k&ago?es?ot??m&anuzim?ijat??nak?urat??nanig?o&dog?jug?makonim?nim?roy?sihcih??u&fig?s&otom?t&amasak?oay????????k!.&art?gro?moc?per?ude?vog???m!ac??nd?o&g?hpih?oc?t??rahs?t?vsr??q&a?g?i!.&gro?lim?moc?ten?ude?vog???m?se??r&a!.&bog?gro?lim?moc!.topsgolb,?rut?t&en?ni??ude?vog??4d5a4prebgm--nx?b?los?t&at?suen???b!.&21g?b!mi??c&er?sp?te??d&em?mb?n&f?i??rt??f&gg?ni??g&el?l&s?z??n&c?e??ol&b?f?v??pp?ro??i&kiw?sp?te?xat??l&el?im?sq??m&a?da?f?ic?o&c!.topsgolb,?n???nce?o&ce?do?et?i&b?dar??rp?ta??p&m!e?t??ooc?se??qra?r&af?ga?oj?tn?ut??su&j?m??t&am?e&n?v??nc?o&f?n??ra?sf??ude?v&da?og?rs?t????c!.&as?ca?de?if?o&c?g??ro???e&e&b?nigne?rac??t&nec?upmoc??ywal??f!.&aterg?cidessa?drp?e&citsuj-reissiuh?rianiretev?sserp??i&cc?rgabmahc??m&o&c?n??t??n&eicamrahp?icedem??ossa?se&lbatpmoc-strepxe?riaton?tsitned-sneigrurihc?uova??t&acova?opsgolb,r&epxe-ertemoeg?op!orea????vuog??avc7ylqbgm--nx??g!.&gro?moc?t&en?opsgolb,?ude?vog???h!.&eman?mo&c?rf??zi??ur??i!.&a&61f4a3abgm--nx?rf4a3abgm--nx??ca?di?gro?hcs?oc?ten?vog?نار&يا?یا???aper??k!.&c&a?s??e&n?p?r??gk?iggnoeyg?kub&gn&oeyg?uhc??noej??l&im?uoes??man&gn&oeyg?uhc??noej??n&as&lu?ub??o&e&hcni?jead??wgnag???o&c?g??ro?s&e?h?m??topsgolb,u&gead?j&ej?gnawg?????l!.&gro?moc?ten?ude?vog???m!.&topsgolb,vog???n!.&gro?moc?ofni?ten?ude?vog?zib???ot&ca?laer??p!.&alsi?ca?eman?forp?gro?moc?o&fni?rp??t&en?se??ude?vog?zib???s?t.cn.vog?ubad??s&8sqif--nx?9zqif--nx?a!.vog?birappnb?gev?lliv?mtsirhc??b!.&gro?moc?ten?ude?vog??oj??ci&hparg?p??d&l?nomaid?rac??e!.&bog?gro?mo&c!.topsgolb,?n??ude??civres?d&d2bgm--nx?oc??i&lppus?rtsudni?treporp??jaiv?l&aw?cycrotom?gnis??moh?ohs?picer?rut&cip?nev??si&rpretne?urc??taicossa?vig??g!nidloh??h5c822qif--nx?i!.&ekacpuc,gro?moc?t&en?ni??ude?vog??rap?targ??k&cor?hxda08--nx?row??l!.&gro?oc??a&ed?tner??essurb?oot??m!.&gro?moc?ten?ude?vog??etsys?ialc??n&a&gorf?ol??ia&grab?mod??oit&acav?cudorp?ulos???o&dnoc?geuj?t&ohp?ua???p!.&ces?gro?moc?olp?ten?ude?vog??i&hsralohcs?t???r!.&ca?gro?ni?oc?ude?vog??atiug?c?e&dliub?erac?ntrap??otcartnoc??s&alg?e&n&isub?tif??rp???t&h&cay?gilf??n&atnuocca?e&mtsevni?ve???rap??u!.&a&c!.&21k?bil?cc???g!.&21k?bil?cc???i!.&21k?bil?cc???l!.&21k?bil?cc???m!.&21k!.&hcorap?rthc?tvp???bil?cc???p!.&21k?bil?cc???si?v!.&21k?bil?cc???w!.&21k?bil?cc????c&d!.&21k?bil?cc???n!.&21k?bil?cc???s!.&21k?bil?cc????d&ef?i!.&21k?bil?cc???m!.&21k?bil?cc???n!.&21k?bil?cc???s!.&bil?cc????e&d!.&21k?bil?cc???las-4-&dnal,ffuts,?m!.&21k?bil?cc???n!.&21k?bil?cc????h&n!.&21k?bil?cc???o!.&21k?bil?cc????i&h!.&bil?cc???m!.&21k?bil?cc???nd?r!.&21k?bil?cc???v!.&21k?bil?cc???w!.&21k?bil?cc????jn!.&21k?bil?cc???k&a!.&21k?bil?cc???o!.&21k?bil?cc????l&a!.&21k?bil?cc???f!.&21k?bil?cc???i!.&21k?bil?cc????mn!.&21k?bil?cc???n&i!.&21k?bil?cc???m!.&21k?bil?cc???sn?t!.&21k?bil?cc????o&c!.&21k?bil?cc???m!.&21k?bil?cc????r&a!.&21k?bil?cc???o!.&21k?bil?cc???p!.&21k?bil?cc????s&a!.&21k?bil?cc???dik?k!.&21k?bil?cc???m!.&21k?bil?cc????t&c!.&21k?bil?cc???m!.&21k?bil?cc???u!.&21k?bil?cc???v!.&21k?bil?cc????ug!.&21k?bil?cc???v&n!.&21k?bil?cc???w!.cc???xt!.&21k?bil?cc???y&b-si,k!.&21k?bil?cc???n!.&21k?bil?cc???w!.&21k?bil?cc????za!.&21k?bil?cc????ah!uab??e??w!.&gro?moc?s&ndnyd,tepym,?ten?ude?vog??eiver??yot??t&0srzc--nx?a!.&ca?o&c!.topsgolb,?fni,?ro?v&g?irp,?zib,?c?e!s??rcomed??b!.&gro?moc?ten?ude?vog??gl??cerid?dimhcs?e!.&eman?gro?moc?ofni?ten?ude?vog?zib??em?kram?n!.&a&l-morf,z,?bg,dnab-eht-ni,e&ht-no-eciffo,libom-eruza,mohtanyd,nozdop,rehurht,s,tis-repparcs,?fehc-a-si,k&eeg-a&-si,si,?u,?ni,o&c-morf,jodsnd,?p&i&emoh,fles,?j,mac-dnab-ta,o&-oidar-mah,hbew,?paduolc,tfe&moh,vres,??s&aila&nyd,snd,?bbevres,e&suohsyub,tisbeweruza,?ndgolb,sa-skcik,?t&enretnifodne,i-&ekorb,s&eod,lles,teg,??norfduolc,sixetnod,?uh,x&inuemoh,unilemoh,?y&ltsaf.&dorp.&a,labolg,?lss.&a,b,labolg,??n-morf,?za-morf,??v??fig?g!.&bog?dni?gro?lim?moc?ten?ude???h!.&dem?gro?l&er?op??m&oc?rif??o&fni?rp?s&rep?sa???po&hs?oc??t&en?luda?ra??ude?vuog???i!.&a&at?b?c!cul??dv?i&blo&-oipmet?oipmet??cserb?drabmol?g&gof?urep??l&gup?i&cis?me&-oigger?oigger???uig&-&aizenev&-iluirf?iluirf??ev&-iluirf?iluirf??v&-iluirf?iluirf???aizenev&-iluirf?iluirf??ev&-iluirf?iluirf??v&-iluirf?iluirf????n&a&brev?cul?pmac?tac??idras?obrac&-saiselgi?saiselgi??resi??otsip?r&b&alac!-oigger?oigger??mu??dna&-&attelrab-inart?inart-attelrab??attelrabinart?inartattelrab?ssela??epmi?ugil??tnelav&-obiv?obiv??vap?z&e&nev?ps&-al?al???irog???l&iuqa!l??leib??m&or?rap??n!acsot?e&dom?is?sec&-ilrof?ilrof???g&amor&-ailime?ailime??edras?olob??i&ssem?tal??ne!var??o&cna?merc?rev?vas???oneg?p?r!a&csep?rr&ac&-assam?assam??ef??von??etam?tsailgo!-lled?lled???s!ip?sam&-ararrac?ararrac??u&caris?gar???t!a&cilisab?recam??resac?soa!-&d&-&ellav?lav??ellav?lav??ellav??d&-&ellav?lav??ellav?lav??ellav??te&lrab&-&airdna-inart?inart-airdna??airdnainart?inartairdna??ssinatlac???udap?v!o&dap?neg?tnam???zn&airb&-a&lled-e-aznom?znom??a&lledeaznom?znom??eaznom??e&c&aip?iv??soc?top??om???b&c?m!u??v??c&f?is?l?m?p?r?v??d&p?u??e&c!cel?inev?nerolf??f?g!ida&-&a&-onitnert?onitnert??otla!-onitnert?onitnert???a&-onitnert?onitnert??otla!-onitnert?onitnert????hcram?l?m!or??n&idu?o&n&edrop?isorf??torc???p?r?s&erav?ilom??t!nomeip?s&eirt?oa!-eellav?eellav????v?znerif??g&a?b?f?il?o?p?r?up?vf??hc?i&b?c?dol?f?l!lecrev?opan?rof&-anesec?anesec???m?n&a&part?rt&-attelrab-airdna?attelrabairdna???imir?ret??p?r!a&b?ilgac?ssas???s!idnirb??t&ei&hc?r??sa??v??l&a!c??b?c?o&m?rit&-&d&eus&-onitnert?onitnert??us&-onitnert?onitnert???s&-onitnert?onitnert???d&eus!-onitnert?onitnert??us&-onitnert?onitnert???s&-onitnert?onitnert?????m&ac?f?i?ol?r??n&a!lim?slab??b?c?e!v?zob??irut?m!p??p?r?t??o&a!v??b!retiv??c!cel??enuc?g!ivor??i&dem&-onadipmac?onadipmac??pmet&-aiblo?aiblo??rdnos?zal??l?m!a&greb?ret??oc?re&f?lap???n!a&dipmac&-oidem?oidem??lim?tsiro?zlob??ecip&-ilocsa?ilocsa??i&bru&-orasep?orasep??lleva?rot?tnert??r&elas?ovil??ulleb??p?r!a&sep&-onibru?onibru??znatac??oun??s!ivert?sabopmac??t!arp?e&nev?ssorg??n&arat?e&girga?rt?veneb????zz&era?urba???p&a?s?t??qa?r&a!m?s??b!a??c?f?g?k?me?o?p?s?t?v??s&a&b?iselgi&-ainobrac?ainobrac???b?c?elpan?i?m?ot?s?t?v??t&a?b?c?l?m?nomdeip?o!psgolb,?p?v??u&de?l?n?p??v&a?og?p?s?t?v??y&drabmol?ellav&-atsoa?atsoa??licis?nacsut??z&al?b?c?p???derc??l!.vog??m!.&gro?moc?ten?ude???n&e&g?m&eganam?piuqe???i!.ue??uocsid??ocs?p!.&emon?gro?lbup?moc?t&en?ni?opsgolb,?ude?vog???r&epxe?op&er?pus???s!.&adaxiabme?e&motoas?picnirp?rots??gro?lim?moc?o&c?dalusnoc??ten?ude?vog??e&b?padub?r??i&rolf?tned??o&h?p???t!.&eman?gro?ibom?levart?m&oc?uesum??o&c?fni?r&ea?p???pooc?sboj?t&en?ni??ude?vog?zib???y?ztej??u&a!.&a&s?w??civ?d&i?lq??fnoc?gro?moc!.topsgolb,?nsa?ofni?sat?t&ca?en?n??ude!.&a&s?w??civ?dlq?sat?t&ca?n??wsn???vog!.&a&s?w??civ?dlq?sat???wsn?zo???c!.&fni?gro?moc?ten?ude?vog???de?e?h!.&0002?a&citore?idem?kitore??edszot?gro?ilus?letoh?m&alker?lif?t?urof??naltagni?o&c?ediv?fni?levynok?nisac??pohs?rarga?s&a&kal?zatu??emag?wen??t&lob?opsgolb,rops??virp?xe&s?zs??ytic?zsagoj??os??l?m!.&ca?gro?moc?oc?ro?ten?vog???n!.&eni&esrem,m,?tenkcahs,?em??r!.&a&dgolov?gulak?i&hsavuhc?kymlak?lerak?rikhsab?ssakahk?t&ayrub?rumdu?ukay??vodrom??k&dohkan?nidud?t&a&hcmak?yv??ingam?okuhc???l&o-rakhsoj?ut??mortsok?nalap?ramas?tihc?vut?yegyda?znep??bps?ca?d&arg&oglov?z??nr?orogleb??e&du-nalu?niram??g&bc?ersom?ineok?r&o?ub&-e?n&ero?iretakey?????hzenorov?i&a&natsuk?tla??mok?ram??k&ihclan?otsovidalv?s&l&aru-k?egnahkra?iron??m!o!t???n!a&mrum?yrb??eloms?i&baylehc?lahkas-onhzuy??odv??r&ayonsark?ib&isovon?mis??ogitayp?u&k?ma???t!epil?ukri??v&ehzi?o&rabahk?stbur?????l&a&kiab?ma&j?y???e&-iram?hc??im?o&kso?porvats?yro??valsoray??m&du?o&c?t??rep??n&a&buk?dagam?gruk?hkartsa?rzys?ts&egad?ratat??za&k?yr???emuyt?ilahkas?rv?ystirast??ovo&navi?remek??pp?r&aj?evt?hck?i&b?midalv??uma??s&itym?mk?sabzuk??t&en?ni?s&aeraf?et??ugrus??ude?v&hk?o&bmat?g?n!n??rik?taras??ts??wmc?ynzorg?z&akvakidalv?kn?ns?tp???myc?ug??s?v!.&gro?moc?ten?ude???ykuyr??v&b?c!.topsgolb,?ih?l!.&di?fnoc?gro?lim?moc?nsa?ten?ude?vog???m!.&eman?gro?lim?m&oc?uesum??o&fni?r&ea?p???pooc?t&en?ni??ude?vog?zib???o&g?m??s!.&bog?der?gro?moc?ude???t!.&bew-eht-no,naht-&esrow,retteb,?sndnyd,??uqhv--nx??w&a!.moc??b!.&gro?oc???c!.&gro?moc?ten?ude???en?g?m!.&ca?gro?m&oc?uesum??oc?pooc?t&en?ni??ude?vog?zib??b??o&csom?h??p!.&de?en?o&c?g??ro?ualeb???r!.&ca?lim?moc?oc?t&en?ni??ude?v&og?uog???n??t!.&a46oa0fz--nx?b&82wrzc--nx?ulc??emag?gro?lim?moc?t&en?opsgolb,?ude?v&di?og?ta0cu--nx??zibe?業商?織組?路網????x&a!t??c!.&hta,vog???ednay?m!.&bog?gro?moc?t&en?opsgolb,?ude??g?ma2ibgy--nx??s!.vog??xx??y&4punu--nx?ad!i&loh?rfkcalb??ot??b!.&fo?lim?moc?vog???cnega?enrotta?g!.&moc?oc?ten??olonhcet??hpargotohp?k!.&gro?moc?ten?ude?vog???l!.&clp?d&em?i??gro?hcs?moc?ten?ude?vog??f?ppus??m!.&eman?gro?lim?moc?ten?ude?vog??edaca?ra??napmoc?os?p!.&gro?lim?moc?pooc?ten?ude?vog???r&e&grus?llag??otcerid?tnuoc?uxul??s!.&gro?lim?moc?ten?ude?vog???t&i&c?nummoc?srevinu??reporp??u!.&bug?gro?lim?moc?ten?ude???van?xes??z&a!.&eman?gro?lim?moc?o&fni?rp??pp?t&en?ni??ude?vog?zib???b!.&az,gro?moc?ten?ude?vog???c!.topsgolb,?d!.&gro?lop?moc?ossa?t&en?ra??ude?vog???ib!.&e&ht-rof,mos-rof,rom-rof,?p&ifles,ohbew,?retteb-rof,sndnyd,??k!.&gro?lim?moc?ten?ude?vog???n!.&asq-irom--nx?ca?gro?htlaeh?i&r&c?o&am?ām???wi!k???keeg?l&im?oohcs??neg?oc!.topsgolb,?t&en?nemailrap?vog????s!.&ca?gro?oc???t!.&c&a?s??e&m?n??ibom?l&etoh?im??o&c?fni?g??ro?vt???u!.&gro?moc?oc?ten???yx?zub??авксом?брс!.&гро?до?ка?р&бо?п!у?????гро?зақ?итед?н&йално?ом??рку?сур?тйас?фр?اي&روس?سيلم??برغملا?ة&كبش?ي&دوعسلا?روس??یدوعسلا??ت&اراما?راھب??ر&ئازجلا?ازاب?صم?طق??سنوت?عقوم?ن&ا&ر&يا?یا??مع??درالا?ميلا?يطسلف??هيدوعسلا?ۃیدوعسلا?तराभ?नठगंस?তরাভ?ালংাব?ਤਰਾਭ?તરાભ?ாயித்நஇ?ைக்ஙலஇ?்ரூப்பக்ஙிச?్తరాభ?ාකංල?ยทไ?ეგ?なんみ?业企?东广?乐娱?你爱我?信中?务政?动移?卦八?司公?团集?国中?國中?址网?坡加新?城商?山佛?店&商?网??府政?戏游?机手?构机!织组??标商?港香?湾台?灣&台?臺??界世?益公?线在?络网?网文中?국한?성삼??");
 
   /**
    * If a hostname is not a key in the EXCLUDE map, and if removing its
@@ -50,7 +50,7 @@
    * public suffix.
    */
   public static final ImmutableMap<String, PublicSuffixType> UNDER =
-      TrieParser.parseTrie("az?db?e&k?y??gp?hk?in?jf?k&c?f?u!.hcs???li?m&j?m?z??nb?p&j.&a&mahokoy?yogan??ebok?i&adnes?kasawak??oroppas?uhsuykatik??n??r&e?t??te?ug?w&k?z??yc?z&m?n???");
+      TrieParser.parseTrie("az?db?e&k?y??gp?hk?in?jf?k&c?f?u.hcs??li?m&j?m?z??nb?p&j.&a&mahokoy?yogan??ebok?i&adnes?kasawak??oroppas?uhsuykatik??n??r&e?t??ug?w&k?z??yc?zm??");
 
   /**
    * The elements in this map would pass the UNDER test, but are known not to
@@ -59,5 +59,5 @@
    * important here. The map is simply used for consistency reasons.
    */
   public static final ImmutableMap<String, PublicSuffixType> EXCLUDED =
-      TrieParser.parseTrie("k&c.www?u.&cin?d&naltocs-yrarbil-lanoitan?om??l&b?en??sln?t&ej?nemailrap??yrarbil-hsitirb???pj.&a&mahokoy.ytic?yogan.ytic??ebok.ytic?i&adnes.ytic?kasawak.ytic??oroppas.ytic?uhsuykatik.ytic??rt.cin?zm.atadelet??");
+      TrieParser.parseTrie("kc.www?pj.&a&mahokoy.ytic?yogan.ytic??ebok.ytic?i&adnes.ytic?kasawak.ytic??oroppas.ytic?uhsuykatik.ytic??rt.cin?zm.atadelet??");
 }
diff --git a/pom.xml b/pom.xml
index 9e5a19b..dac208f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,17 +10,16 @@
     <version>7</version>
   </parent>
   <groupId>com.google.guava</groupId>
-  <artifactId>guava-parent-jdk5</artifactId>
-  <version>17.0</version>
+  <artifactId>guava-parent</artifactId>
+  <version>18.0</version>
   <packaging>pom</packaging>
-  <name>Guava Maven Parent (JDK5 Backport)</name>
+  <name>Guava Maven Parent</name>
   <url>http://code.google.com/p/guava-libraries</url>
   <properties>
     <gpg.skip>true</gpg.skip>
     <!-- Override this with -Dtest.include="**/SomeTest.java" on the CLI -->
     <test.include>**/*Test.java</test.include>
-    <truth.version>0.13</truth.version>
-    <bootstrap.classes>${java.home}/lib/rt.jar</bootstrap.classes>
+    <truth.version>0.23</truth.version>
   </properties>
   <issueManagement>
     <system>code.google.com</system>
@@ -58,8 +57,7 @@
   </developers>
   <modules>
     <module>guava</module>
-    <module>guava-bootstrap</module>
-    <!-- guava-gwt not included for JDK5 backport -->
+    <module>guava-gwt</module>
     <module>guava-testlib</module>
     <module>guava-tests</module>
   </modules>
@@ -103,11 +101,8 @@
           <artifactId>maven-compiler-plugin</artifactId>
           <version>2.3.2</version>
           <configuration>
-            <source>1.5</source>
-            <target>1.5</target>
-            <compilerArguments>
-              <bootclasspath>${bootstrap.classes}</bootclasspath>
-            </compilerArguments>
+            <source>1.6</source>
+            <target>1.6</target>
           </configuration>
         </plugin>
         <plugin>
@@ -205,11 +200,6 @@
         <version>1.3.9</version>
       </dependency>
       <dependency>
-        <groupId>javax.inject</groupId>
-        <artifactId>javax.inject</artifactId>
-        <version>1</version>
-      </dependency>
-      <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.8.2</version>
@@ -228,7 +218,7 @@
         <scope>test</scope>
       </dependency>
       <dependency>
-        <groupId>org.truth0</groupId>
+        <groupId>com.google.truth</groupId>
         <artifactId>truth</artifactId>
         <version>${truth.version}</version>
         <scope>test</scope>