am 9dada6a9: am e26853a5: Removing com/android/mail/lib.

* commit '9dada6a9d6ddfa99b1f204239b080121001a1c36':
  Removing com/android/mail/lib.
diff --git a/src/com/android/mail/lib/base/ByteArrays.java b/src/com/android/mail/lib/base/ByteArrays.java
deleted file mode 100644
index da811f2..0000000
--- a/src/com/android/mail/lib/base/ByteArrays.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2008 Google Inc.
- *
- * 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.android.mail.lib.base;
-
-/**
- * Static utility methods pertaining especially to byte arrays. Note that I/O-related functionality
- * belongs in the {@code com.google.common.io} package.
- *
- * @author Chris Nokleberg
- * @author Hiroshi Yamauchi
- */
-public final class ByteArrays {
-  private ByteArrays() {}
-
-  private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray();
-
-  /**
-   * Returns the byte array formatted as a lowercase hexadecimal string. The string will be
-   * {@code 2 * bytes.length} characters long.
-   */
-  public static String toHexString(byte[] bytes) {
-    StringBuilder sb = new StringBuilder(2 * bytes.length);
-    for (byte b : bytes) {
-      sb.append(HEX_DIGITS[(b >> 4) & 0xf]).append(HEX_DIGITS[b & 0xf]);
-    }
-    return sb.toString();
-  }
-}
\ No newline at end of file
diff --git a/src/com/android/mail/lib/base/CharEscaper.java b/src/com/android/mail/lib/base/CharEscaper.java
deleted file mode 100644
index 63ee395..0000000
--- a/src/com/android/mail/lib/base/CharEscaper.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 2006 Google Inc.
- *
- * 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.android.mail.lib.base;
-
-import static com.android.mail.lib.base.Preconditions.checkNotNull;
-
-import java.io.IOException;
-
-/**
- * An object that converts literal text into a format safe for inclusion in a particular context
- * (such as an XML document). Typically (but not always), the inverse process of "unescaping" the
- * text is performed automatically by the relevant parser.
- *
- * <p>For example, an XML escaper would convert the literal string {@code "Foo<Bar>"} into {@code
- * "Foo&lt;Bar&gt;"} to prevent {@code "<Bar>"} from being confused with an XML tag. When the
- * resulting XML document is parsed, the parser API will return this text as the original literal
- * string {@code "Foo<Bar>"}.
- *
- * <p>A {@code CharEscaper} instance is required to be stateless, and safe when used concurrently by
- * multiple threads.
- *
- * <p>Several popular escapers are defined as constants in the class {@link CharEscapers}. To create
- * your own escapers, use {@link CharEscaperBuilder}, or extend this class and implement the {@link
- * #escape(char)} method.
- *
- * @author sven@google.com (Sven Mawson)
- */
-public abstract class CharEscaper extends Escaper {
-  /**
-   * Returns the escaped form of a given literal string.
-   *
-   * @param string the literal string to be escaped
-   * @return the escaped form of {@code string}
-   * @throws NullPointerException if {@code string} is null
-   */
-  @Override public String escape(String string) {
-    checkNotNull(string);
-    // Inlineable fast-path loop which hands off to escapeSlow() only if needed
-    int length = string.length();
-    for (int index = 0; index < length; index++) {
-      if (escape(string.charAt(index)) != null) {
-        return escapeSlow(string, index);
-      }
-    }
-    return string;
-  }
-
-  /**
-   * Returns an {@code Appendable} instance which automatically escapes all text appended to it
-   * before passing the resulting text to an underlying {@code Appendable}.
-   *
-   * <p>The methods of the returned object will propagate any exceptions thrown by the underlying
-   * {@code Appendable}, and will throw {@link NullPointerException} if asked to append {@code
-   * null}, but do not otherwise throw any exceptions.
-   *
-   * <p>The escaping behavior is identical to that of {@link #escape(String)}, so the following code
-   * is always equivalent to {@code escaper.escape(string)}: <pre>   {@code
-   *
-   *   StringBuilder sb = new StringBuilder();
-   *   escaper.escape(sb).append(string);
-   *   return sb.toString();}</pre>
-   *
-   * @param out the underlying {@code Appendable} to append escaped output to
-   * @return an {@code Appendable} which passes text to {@code out} after escaping it
-   * @throws NullPointerException if {@code out} is null.
-   */
-  @Override public Appendable escape(final Appendable out) {
-    checkNotNull(out);
-
-    return new Appendable() {
-      @Override public Appendable append(CharSequence csq) throws IOException {
-        out.append(escape(csq.toString()));
-        return this;
-      }
-
-      @Override public Appendable append(CharSequence csq, int start, int end) throws IOException {
-        out.append(escape(csq.subSequence(start, end).toString()));
-        return this;
-      }
-
-      @Override public Appendable append(char c) throws IOException {
-        char[] escaped = escape(c);
-        if (escaped == null) {
-          out.append(c);
-        } else {
-          for (char e : escaped) {
-            out.append(e);
-          }
-        }
-        return this;
-      }
-    };
-  }
-
-  /**
-   * Returns the escaped form of a given literal string, starting at the given index. This method is
-   * called by the {@link #escape(String)} method when it discovers that escaping is required. It is
-   * protected to allow subclasses to override the fastpath escaping function to inline their
-   * escaping test. See {@link CharEscaperBuilder} for an example usage.
-   *
-   * @param s the literal string to be escaped
-   * @param index the index to start escaping from
-   * @return the escaped form of {@code string}
-   * @throws NullPointerException if {@code string} is null
-   */
-  protected String escapeSlow(String s, int index) {
-    int slen = s.length();
-
-    // Get a destination buffer and setup some loop variables.
-    char[] dest = Platform.charBufferFromThreadLocal();
-    int destSize = dest.length;
-    int destIndex = 0;
-    int lastEscape = 0;
-
-    // Loop through the rest of the string, replacing when needed into the
-    // destination buffer, which gets grown as needed as well.
-    for (; index < slen; index++) {
-
-      // Get a replacement for the current character.
-      char[] r = escape(s.charAt(index));
-
-      // If no replacement is needed, just continue.
-      if (r == null) continue;
-
-      int rlen = r.length;
-      int charsSkipped = index - lastEscape;
-
-      // This is the size needed to add the replacement, not the full size needed by the string. We
-      // only regrow when we absolutely must.
-      int sizeNeeded = destIndex + charsSkipped + rlen;
-      if (destSize < sizeNeeded) {
-        destSize = sizeNeeded + (slen - index) + DEST_PAD;
-        dest = growBuffer(dest, destIndex, destSize);
-      }
-
-      // If we have skipped any characters, we need to copy them now.
-      if (charsSkipped > 0) {
-        s.getChars(lastEscape, index, dest, destIndex);
-        destIndex += charsSkipped;
-      }
-
-      // Copy the replacement string into the dest buffer as needed.
-      if (rlen > 0) {
-        System.arraycopy(r, 0, dest, destIndex, rlen);
-        destIndex += rlen;
-      }
-      lastEscape = index + 1;
-    }
-
-    // Copy leftover characters if there are any.
-    int charsLeft = slen - lastEscape;
-    if (charsLeft > 0) {
-      int sizeNeeded = destIndex + charsLeft;
-      if (destSize < sizeNeeded) {
-
-        // Regrow and copy, expensive! No padding as this is the final copy.
-        dest = growBuffer(dest, destIndex, sizeNeeded);
-      }
-      s.getChars(lastEscape, slen, dest, destIndex);
-      destIndex = sizeNeeded;
-    }
-    return new String(dest, 0, destIndex);
-  }
-
-  /**
-   * Returns the escaped form of the given character, or {@code null} if this character does not
-   * need to be escaped. If an empty array is returned, this effectively strips the input character
-   * from the resulting text.
-   *
-   * <p>If the character does not need to be escaped, this method should return {@code null}, rather
-   * than a one-character array containing the character itself. This enables the escaping algorithm
-   * to perform more efficiently.
-   *
-   * <p>An escaper is expected to be able to deal with any {@code char} value, so this method should
-   * not throw any exceptions.
-   *
-   * @param c the character to escape if necessary
-   * @return the replacement characters, or {@code null} if no escaping was needed
-   */
-  protected abstract char[] escape(char c);
-
-  /**
-   * Helper method to grow the character buffer as needed, this only happens once in a while so it's
-   * ok if it's in a method call. If the index passed in is 0 then no copying will be done.
-   */
-  private static char[] growBuffer(char[] dest, int index, int size) {
-    char[] copy = new char[size];
-    if (index > 0) {
-      System.arraycopy(dest, 0, copy, 0, index);
-    }
-    return copy;
-  }
-
-  /**
-   * The amount of padding to use when growing the escape buffer.
-   */
-  private static final int DEST_PAD = 32;
-}
\ No newline at end of file
diff --git a/src/com/android/mail/lib/base/CharEscaperBuilder.java b/src/com/android/mail/lib/base/CharEscaperBuilder.java
deleted file mode 100644
index a11eac2..0000000
--- a/src/com/android/mail/lib/base/CharEscaperBuilder.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2006-2007 Google Inc.
- *
- * 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.android.mail.lib.base;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Simple helper class to build a "sparse" array of objects based on the indexes that were added to
- * it. The array will be from 0 to the maximum index given. All non-set indexes will contain null
- * (so it's not really a sparse array, just a pseudo sparse array). The builder can also return a
- * CharEscaper based on the generated array.
- *
- * @author sven@google.com (Sven Mawson)
- */
-public class CharEscaperBuilder {
-  /**
-   * Simple decorator that turns an array of replacement char[]s into a CharEscaper, this results in
-   * a very fast escape method.
-   */
-  private static class CharArrayDecorator extends CharEscaper {
-    private final char[][] replacements;
-    private final int replaceLength;
-
-    CharArrayDecorator(char[][] replacements) {
-      this.replacements = replacements;
-      this.replaceLength = replacements.length;
-    }
-
-    /*
-     * Overriding escape method to be slightly faster for this decorator. We test the replacements
-     * array directly, saving a method call.
-     */
-    @Override public String escape(String s) {
-      int slen = s.length();
-      for (int index = 0; index < slen; index++) {
-        char c = s.charAt(index);
-        if (c < replacements.length && replacements[c] != null) {
-          return escapeSlow(s, index);
-        }
-      }
-      return s;
-    }
-
-    @Override protected char[] escape(char c) {
-      return c < replaceLength ? replacements[c] : null;
-    }
-  }
-
-  // Replacement mappings.
-  private final Map<Character, String> map;
-
-  // The highest index we've seen so far.
-  private int max = -1;
-
-  /**
-   * Construct a new sparse array builder.
-   */
-  public CharEscaperBuilder() {
-    this.map = new HashMap<Character, String>();
-  }
-
-  /**
-   * Add a new mapping from an index to an object to the escaping.
-   */
-  public CharEscaperBuilder addEscape(char c, String r) {
-    map.put(c, r);
-    if (c > max) {
-      max = c;
-    }
-    return this;
-  }
-
-  /**
-   * Add multiple mappings at once for a particular index.
-   */
-  public CharEscaperBuilder addEscapes(char[] cs, String r) {
-    for (char c : cs) {
-      addEscape(c, r);
-    }
-    return this;
-  }
-
-  /**
-   * Convert this builder into an array of char[]s where the maximum index is the value of the
-   * highest character that has been seen. The array will be sparse in the sense that any unseen
-   * index will default to null.
-   *
-   * @return a "sparse" array that holds the replacement mappings.
-   */
-  public char[][] toArray() {
-    char[][] result = new char[max + 1][];
-    for (Map.Entry<Character, String> entry : map.entrySet()) {
-      result[entry.getKey()] = entry.getValue().toCharArray();
-    }
-    return result;
-  }
-
-  /**
-   * Convert this builder into a char escaper which is just a decorator around the underlying array
-   * of replacement char[]s.
-   *
-   * @return an escaper that escapes based on the underlying array.
-   */
-  public CharEscaper toEscaper() {
-    return new CharArrayDecorator(toArray());
-  }
-}
\ No newline at end of file
diff --git a/src/com/android/mail/lib/base/CharEscapers.java b/src/com/android/mail/lib/base/CharEscapers.java
deleted file mode 100644
index 7a76ffe..0000000
--- a/src/com/android/mail/lib/base/CharEscapers.java
+++ /dev/null
@@ -1,1102 +0,0 @@
-/*
- * Copyright (C) 2006 Google Inc.
- *
- * 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.android.mail.lib.base;
-
-import static com.android.mail.lib.base.Preconditions.checkNotNull;
-
-import java.io.IOException;
-
-/**
- * Utility functions for dealing with {@code CharEscaper}s, and some commonly
- * used {@code CharEscaper} instances.
- *
- * @author sven@google.com (Sven Mawson)
- * @author laurence@google.com (Laurence Gonsalves)
- */
-public final class CharEscapers {
-  private CharEscapers() {}
-
-  // TODO(matevossian): To implementors of escapers --
-  //                    For each xxxEscaper method, please add links to external
-  //                    reference pages that we consider authoritative for what
-  //                    that escaper should exactly be doing.
-
-  /**
-   * Performs no escaping.
-   */
-  private static final CharEscaper NULL_ESCAPER = new CharEscaper() {
-      @Override
-    public String escape(String string) {
-        checkNotNull(string);
-        return string;
-      }
-
-      @Override
-      public Appendable escape(final Appendable out) {
-        checkNotNull(out);
-
-        // we can't simply return out because the CharEscaper contract says that
-        // the returned Appendable will throw a NullPointerException if asked to
-        // append null.
-        return new Appendable() {
-            @Override public Appendable append(CharSequence csq) throws IOException {
-              checkNotNull(csq);
-              out.append(csq);
-              return this;
-            }
-
-            @Override public Appendable append(CharSequence csq, int start, int end)
-                throws IOException {
-              checkNotNull(csq);
-              out.append(csq, start, end);
-              return this;
-            }
-
-            @Override public Appendable append(char c) throws IOException {
-              out.append(c);
-              return this;
-            }
-          };
-      }
-
-      @Override
-      protected char[] escape(char c) {
-        return null;
-      }
-    };
-
-  /**
-   * Returns a {@link CharEscaper} that does no escaping.
-   */
-  public static CharEscaper nullEscaper() {
-    return NULL_ESCAPER;
-  }
-
-  /**
-   * Returns a {@link CharEscaper} instance that escapes special characters in a
-   * string so it can safely be included in an XML document in either element
-   * content or attribute values.
-   *
-   * <p><b>Note</b></p>: silently removes null-characters and control
-   * characters, as there is no way to represent them in XML.
-   */
-  public static CharEscaper xmlEscaper() {
-    return XML_ESCAPER;
-  }
-
-  /**
-   * Escapes special characters from a string so it can safely be included in an
-   * XML document in either element content or attribute values.  Also removes
-   * null-characters and control characters, as there is no way to represent
-   * them in XML.
-   */
-  private static final CharEscaper XML_ESCAPER = newBasicXmlEscapeBuilder()
-      .addEscape('"', "&quot;")
-      .addEscape('\'', "&apos;")
-      .toEscaper();
-
-  /**
-   * Returns a {@link CharEscaper} instance that escapes special characters in a
-   * string so it can safely be included in an XML document in element content.
-   *
-   * <p><b>Note</b></p>: double and single quotes are not escaped, so it is not
-   * safe to use this escaper to escape attribute values. Use the
-   * {@link #xmlEscaper()} escaper to escape attribute values or if you are
-   * unsure. Also silently removes non-whitespace control characters, as there
-   * is no way to represent them in XML.
-   */
-  public static CharEscaper xmlContentEscaper() {
-    return XML_CONTENT_ESCAPER;
-  }
-
-  /**
-   * Escapes special characters from a string so it can safely be included in an
-   * XML document in element content.  Note that quotes are <em>not</em>
-   * escaped, so <em>this is not safe for use in attribute values</em>. Use
-   * {@link #XML_ESCAPER} for attribute values, or if you are unsure.  Also
-   * removes non-whitespace control characters, as there is no way to represent
-   * them in XML.
-   */
-  private static final CharEscaper XML_CONTENT_ESCAPER =
-      newBasicXmlEscapeBuilder().toEscaper();
-
-  /**
-   * Returns a {@link CharEscaper} instance that escapes special characters in a
-   * string so it can safely be included in an HTML document in either element
-   * content or attribute values.
-   *
-   * <p><b>Note</b></p>: alters non-ASCII and control characters.
-   *
-   * The entity list was taken from:
-   * <a href="http://www.w3.org/TR/html4/sgml/entities.html">here</a>
-   */
-  public static CharEscaper htmlEscaper() {
-    return HtmlEscaperHolder.HTML_ESCAPER;
-  }
-
-  /**
-   * A lazy initialization holder for HTML_ESCAPER.
-   */
-  private static class HtmlEscaperHolder {
-    private static final CharEscaper HTML_ESCAPER
-        = new HtmlCharEscaper(new CharEscaperBuilder()
-            .addEscape('"',      "&quot;")
-            .addEscape('\'',     "&#39;")
-            .addEscape('&',      "&amp;")
-            .addEscape('<',      "&lt;")
-            .addEscape('>',      "&gt;")
-            .addEscape('\u00A0', "&nbsp;")
-            .addEscape('\u00A1', "&iexcl;")
-            .addEscape('\u00A2', "&cent;")
-            .addEscape('\u00A3', "&pound;")
-            .addEscape('\u00A4', "&curren;")
-            .addEscape('\u00A5', "&yen;")
-            .addEscape('\u00A6', "&brvbar;")
-            .addEscape('\u00A7', "&sect;")
-            .addEscape('\u00A8', "&uml;")
-            .addEscape('\u00A9', "&copy;")
-            .addEscape('\u00AA', "&ordf;")
-            .addEscape('\u00AB', "&laquo;")
-            .addEscape('\u00AC', "&not;")
-            .addEscape('\u00AD', "&shy;")
-            .addEscape('\u00AE', "&reg;")
-            .addEscape('\u00AF', "&macr;")
-            .addEscape('\u00B0', "&deg;")
-            .addEscape('\u00B1', "&plusmn;")
-            .addEscape('\u00B2', "&sup2;")
-            .addEscape('\u00B3', "&sup3;")
-            .addEscape('\u00B4', "&acute;")
-            .addEscape('\u00B5', "&micro;")
-            .addEscape('\u00B6', "&para;")
-            .addEscape('\u00B7', "&middot;")
-            .addEscape('\u00B8', "&cedil;")
-            .addEscape('\u00B9', "&sup1;")
-            .addEscape('\u00BA', "&ordm;")
-            .addEscape('\u00BB', "&raquo;")
-            .addEscape('\u00BC', "&frac14;")
-            .addEscape('\u00BD', "&frac12;")
-            .addEscape('\u00BE', "&frac34;")
-            .addEscape('\u00BF', "&iquest;")
-            .addEscape('\u00C0', "&Agrave;")
-            .addEscape('\u00C1', "&Aacute;")
-            .addEscape('\u00C2', "&Acirc;")
-            .addEscape('\u00C3', "&Atilde;")
-            .addEscape('\u00C4', "&Auml;")
-            .addEscape('\u00C5', "&Aring;")
-            .addEscape('\u00C6', "&AElig;")
-            .addEscape('\u00C7', "&Ccedil;")
-            .addEscape('\u00C8', "&Egrave;")
-            .addEscape('\u00C9', "&Eacute;")
-            .addEscape('\u00CA', "&Ecirc;")
-            .addEscape('\u00CB', "&Euml;")
-            .addEscape('\u00CC', "&Igrave;")
-            .addEscape('\u00CD', "&Iacute;")
-            .addEscape('\u00CE', "&Icirc;")
-            .addEscape('\u00CF', "&Iuml;")
-            .addEscape('\u00D0', "&ETH;")
-            .addEscape('\u00D1', "&Ntilde;")
-            .addEscape('\u00D2', "&Ograve;")
-            .addEscape('\u00D3', "&Oacute;")
-            .addEscape('\u00D4', "&Ocirc;")
-            .addEscape('\u00D5', "&Otilde;")
-            .addEscape('\u00D6', "&Ouml;")
-            .addEscape('\u00D7', "&times;")
-            .addEscape('\u00D8', "&Oslash;")
-            .addEscape('\u00D9', "&Ugrave;")
-            .addEscape('\u00DA', "&Uacute;")
-            .addEscape('\u00DB', "&Ucirc;")
-            .addEscape('\u00DC', "&Uuml;")
-            .addEscape('\u00DD', "&Yacute;")
-            .addEscape('\u00DE', "&THORN;")
-            .addEscape('\u00DF', "&szlig;")
-            .addEscape('\u00E0', "&agrave;")
-            .addEscape('\u00E1', "&aacute;")
-            .addEscape('\u00E2', "&acirc;")
-            .addEscape('\u00E3', "&atilde;")
-            .addEscape('\u00E4', "&auml;")
-            .addEscape('\u00E5', "&aring;")
-            .addEscape('\u00E6', "&aelig;")
-            .addEscape('\u00E7', "&ccedil;")
-            .addEscape('\u00E8', "&egrave;")
-            .addEscape('\u00E9', "&eacute;")
-            .addEscape('\u00EA', "&ecirc;")
-            .addEscape('\u00EB', "&euml;")
-            .addEscape('\u00EC', "&igrave;")
-            .addEscape('\u00ED', "&iacute;")
-            .addEscape('\u00EE', "&icirc;")
-            .addEscape('\u00EF', "&iuml;")
-            .addEscape('\u00F0', "&eth;")
-            .addEscape('\u00F1', "&ntilde;")
-            .addEscape('\u00F2', "&ograve;")
-            .addEscape('\u00F3', "&oacute;")
-            .addEscape('\u00F4', "&ocirc;")
-            .addEscape('\u00F5', "&otilde;")
-            .addEscape('\u00F6', "&ouml;")
-            .addEscape('\u00F7', "&divide;")
-            .addEscape('\u00F8', "&oslash;")
-            .addEscape('\u00F9', "&ugrave;")
-            .addEscape('\u00FA', "&uacute;")
-            .addEscape('\u00FB', "&ucirc;")
-            .addEscape('\u00FC', "&uuml;")
-            .addEscape('\u00FD', "&yacute;")
-            .addEscape('\u00FE', "&thorn;")
-            .addEscape('\u00FF', "&yuml;")
-            .addEscape('\u0152', "&OElig;")
-            .addEscape('\u0153', "&oelig;")
-            .addEscape('\u0160', "&Scaron;")
-            .addEscape('\u0161', "&scaron;")
-            .addEscape('\u0178', "&Yuml;")
-            .addEscape('\u0192', "&fnof;")
-            .addEscape('\u02C6', "&circ;")
-            .addEscape('\u02DC', "&tilde;")
-            .addEscape('\u0391', "&Alpha;")
-            .addEscape('\u0392', "&Beta;")
-            .addEscape('\u0393', "&Gamma;")
-            .addEscape('\u0394', "&Delta;")
-            .addEscape('\u0395', "&Epsilon;")
-            .addEscape('\u0396', "&Zeta;")
-            .addEscape('\u0397', "&Eta;")
-            .addEscape('\u0398', "&Theta;")
-            .addEscape('\u0399', "&Iota;")
-            .addEscape('\u039A', "&Kappa;")
-            .addEscape('\u039B', "&Lambda;")
-            .addEscape('\u039C', "&Mu;")
-            .addEscape('\u039D', "&Nu;")
-            .addEscape('\u039E', "&Xi;")
-            .addEscape('\u039F', "&Omicron;")
-            .addEscape('\u03A0', "&Pi;")
-            .addEscape('\u03A1', "&Rho;")
-            .addEscape('\u03A3', "&Sigma;")
-            .addEscape('\u03A4', "&Tau;")
-            .addEscape('\u03A5', "&Upsilon;")
-            .addEscape('\u03A6', "&Phi;")
-            .addEscape('\u03A7', "&Chi;")
-            .addEscape('\u03A8', "&Psi;")
-            .addEscape('\u03A9', "&Omega;")
-            .addEscape('\u03B1', "&alpha;")
-            .addEscape('\u03B2', "&beta;")
-            .addEscape('\u03B3', "&gamma;")
-            .addEscape('\u03B4', "&delta;")
-            .addEscape('\u03B5', "&epsilon;")
-            .addEscape('\u03B6', "&zeta;")
-            .addEscape('\u03B7', "&eta;")
-            .addEscape('\u03B8', "&theta;")
-            .addEscape('\u03B9', "&iota;")
-            .addEscape('\u03BA', "&kappa;")
-            .addEscape('\u03BB', "&lambda;")
-            .addEscape('\u03BC', "&mu;")
-            .addEscape('\u03BD', "&nu;")
-            .addEscape('\u03BE', "&xi;")
-            .addEscape('\u03BF', "&omicron;")
-            .addEscape('\u03C0', "&pi;")
-            .addEscape('\u03C1', "&rho;")
-            .addEscape('\u03C2', "&sigmaf;")
-            .addEscape('\u03C3', "&sigma;")
-            .addEscape('\u03C4', "&tau;")
-            .addEscape('\u03C5', "&upsilon;")
-            .addEscape('\u03C6', "&phi;")
-            .addEscape('\u03C7', "&chi;")
-            .addEscape('\u03C8', "&psi;")
-            .addEscape('\u03C9', "&omega;")
-            .addEscape('\u03D1', "&thetasym;")
-            .addEscape('\u03D2', "&upsih;")
-            .addEscape('\u03D6', "&piv;")
-            .addEscape('\u2002', "&ensp;")
-            .addEscape('\u2003', "&emsp;")
-            .addEscape('\u2009', "&thinsp;")
-            .addEscape('\u200C', "&zwnj;")
-            .addEscape('\u200D', "&zwj;")
-            .addEscape('\u200E', "&lrm;")
-            .addEscape('\u200F', "&rlm;")
-            .addEscape('\u2013', "&ndash;")
-            .addEscape('\u2014', "&mdash;")
-            .addEscape('\u2018', "&lsquo;")
-            .addEscape('\u2019', "&rsquo;")
-            .addEscape('\u201A', "&sbquo;")
-            .addEscape('\u201C', "&ldquo;")
-            .addEscape('\u201D', "&rdquo;")
-            .addEscape('\u201E', "&bdquo;")
-            .addEscape('\u2020', "&dagger;")
-            .addEscape('\u2021', "&Dagger;")
-            .addEscape('\u2022', "&bull;")
-            .addEscape('\u2026', "&hellip;")
-            .addEscape('\u2030', "&permil;")
-            .addEscape('\u2032', "&prime;")
-            .addEscape('\u2033', "&Prime;")
-            .addEscape('\u2039', "&lsaquo;")
-            .addEscape('\u203A', "&rsaquo;")
-            .addEscape('\u203E', "&oline;")
-            .addEscape('\u2044', "&frasl;")
-            .addEscape('\u20AC', "&euro;")
-            .addEscape('\u2111', "&image;")
-            .addEscape('\u2118', "&weierp;")
-            .addEscape('\u211C', "&real;")
-            .addEscape('\u2122', "&trade;")
-            .addEscape('\u2135', "&alefsym;")
-            .addEscape('\u2190', "&larr;")
-            .addEscape('\u2191', "&uarr;")
-            .addEscape('\u2192', "&rarr;")
-            .addEscape('\u2193', "&darr;")
-            .addEscape('\u2194', "&harr;")
-            .addEscape('\u21B5', "&crarr;")
-            .addEscape('\u21D0', "&lArr;")
-            .addEscape('\u21D1', "&uArr;")
-            .addEscape('\u21D2', "&rArr;")
-            .addEscape('\u21D3', "&dArr;")
-            .addEscape('\u21D4', "&hArr;")
-            .addEscape('\u2200', "&forall;")
-            .addEscape('\u2202', "&part;")
-            .addEscape('\u2203', "&exist;")
-            .addEscape('\u2205', "&empty;")
-            .addEscape('\u2207', "&nabla;")
-            .addEscape('\u2208', "&isin;")
-            .addEscape('\u2209', "&notin;")
-            .addEscape('\u220B', "&ni;")
-            .addEscape('\u220F', "&prod;")
-            .addEscape('\u2211', "&sum;")
-            .addEscape('\u2212', "&minus;")
-            .addEscape('\u2217', "&lowast;")
-            .addEscape('\u221A', "&radic;")
-            .addEscape('\u221D', "&prop;")
-            .addEscape('\u221E', "&infin;")
-            .addEscape('\u2220', "&ang;")
-            .addEscape('\u2227', "&and;")
-            .addEscape('\u2228', "&or;")
-            .addEscape('\u2229', "&cap;")
-            .addEscape('\u222A', "&cup;")
-            .addEscape('\u222B', "&int;")
-            .addEscape('\u2234', "&there4;")
-            .addEscape('\u223C', "&sim;")
-            .addEscape('\u2245', "&cong;")
-            .addEscape('\u2248', "&asymp;")
-            .addEscape('\u2260', "&ne;")
-            .addEscape('\u2261', "&equiv;")
-            .addEscape('\u2264', "&le;")
-            .addEscape('\u2265', "&ge;")
-            .addEscape('\u2282', "&sub;")
-            .addEscape('\u2283', "&sup;")
-            .addEscape('\u2284', "&nsub;")
-            .addEscape('\u2286', "&sube;")
-            .addEscape('\u2287', "&supe;")
-            .addEscape('\u2295', "&oplus;")
-            .addEscape('\u2297', "&otimes;")
-            .addEscape('\u22A5', "&perp;")
-            .addEscape('\u22C5', "&sdot;")
-            .addEscape('\u2308', "&lceil;")
-            .addEscape('\u2309', "&rceil;")
-            .addEscape('\u230A', "&lfloor;")
-            .addEscape('\u230B', "&rfloor;")
-            .addEscape('\u2329', "&lang;")
-            .addEscape('\u232A', "&rang;")
-            .addEscape('\u25CA', "&loz;")
-            .addEscape('\u2660', "&spades;")
-            .addEscape('\u2663', "&clubs;")
-            .addEscape('\u2665', "&hearts;")
-            .addEscape('\u2666', "&diams;")
-            .toArray());
-  }
-
-  /**
-   * Returns a {@link CharEscaper} instance that escapes special characters in a
-   * string so it can safely be included in an HTML document in either element
-   * content or attribute values.
-   *
-   * <p><b>Note</b></p>: does not alter non-ASCII and control characters.
-   */
-  public static CharEscaper asciiHtmlEscaper() {
-    return ASCII_HTML_ESCAPER;
-  }
-
-  /**
-   * Escapes special characters from a string so it can safely be included in an
-   * HTML document in either element content or attribute values. Does
-   * <em>not</em> alter non-ASCII characters or control characters.
-   */
-  private static final CharEscaper ASCII_HTML_ESCAPER = new CharEscaperBuilder()
-      .addEscape('"', "&quot;")
-      .addEscape('\'', "&#39;")
-      .addEscape('&', "&amp;")
-      .addEscape('<', "&lt;")
-      .addEscape('>', "&gt;")
-      .toEscaper();
-
-  /**
-   * Returns an {@link Escaper} instance that escapes Java chars so they can be
-   * safely included in URIs. For details on escaping URIs, see section 2.4 of
-   * <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>.
-   *
-   * <p>When encoding a String, the following rules apply:
-   * <ul>
-   * <li>The alphanumeric characters "a" through "z", "A" through "Z" and "0"
-   *     through "9" remain the same.
-   * <li>The special characters ".", "-", "*", and "_" remain the same.
-   * <li>The space character " " is converted into a plus sign "+".
-   * <li>All other characters are converted into one or more bytes using UTF-8
-   *     encoding and each byte is then represented by the 3-character string
-   *     "%XY", where "XY" is the two-digit, uppercase, hexadecimal
-   *     representation of the byte value.
-   * <ul>
-   *
-   * <p><b>Note</b>: Unlike other escapers, URI 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
-   * for all percent-encodings."</i>
-   *
-   * <p>This escaper has identical behavior to (but is potentially much faster
-   * than):
-   * <ul>
-   * <li>{@link com.google.httputil.FastURLEncoder#encode(String)}
-   * <li>{@link com.google.httputil.FastURLEncoder#encode(String,String)}
-   *     with the encoding name "UTF-8"
-   * <li>{@link java.net.URLEncoder#encode(String, String)}
-   *     with the encoding name "UTF-8"
-   * </ul>
-   *
-   * <p>This method is equivalent to {@code uriEscaper(true)}.
-   */
-  public static Escaper uriEscaper() {
-    return uriEscaper(true);
-  }
-
-  /**
-   * Returns an {@link Escaper} instance that escapes Java chars so they can be
-   * safely included in URI path segments. For details on escaping URIs, see
-   * section 2.4 of <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
-   *
-   * <p>When encoding a String, the following rules apply:
-   * <ul>
-   * <li>The alphanumeric characters "a" through "z", "A" through "Z" and "0"
-   *     through "9" remain the same.
-   * <li>The unreserved characters ".", "-", "~", and "_" remain the same.
-   * <li>The general delimiters "@" and ":" remain the same.
-   * <li>The subdelimiters "!", "$", "&amp;", "'", "(", ")", "*", ",", ";",
-   *     and "=" remain the same.
-   * <li>The space character " " is converted into %20.
-   * <li>All other characters are converted into one or more bytes using UTF-8
-   *     encoding and each byte is then represented by the 3-character string
-   *     "%XY", where "XY" is the two-digit, uppercase, hexadecimal
-   *     representation of the byte value.
-   * </ul>
-   *
-   * <p><b>Note</b>: Unlike other escapers, URI 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
-   * for all percent-encodings."</i>
-   */
-  public static Escaper uriPathEscaper() {
-    return URI_PATH_ESCAPER;
-  }
-
-  /**
-   * Returns an {@link Escaper} instance that escapes Java chars so they can be
-   * safely included in URI query string segments. When the query string
-   * consists of a sequence of name=value pairs separated by &amp;, the names
-   * and values should be individually encoded. If you escape an entire query
-   * string in one pass with this escaper, then the "=" and "&amp;" characters
-   * used as separators will also be escaped.
-   *
-   * <p>This escaper is also suitable for escaping fragment identifiers.
-   *
-   * <p>For details on escaping URIs, see
-   * section 2.4 of <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
-   *
-   * <p>When encoding a String, the following rules apply:
-   * <ul>
-   * <li>The alphanumeric characters "a" through "z", "A" through "Z" and "0"
-   *     through "9" remain the same.
-   * <li>The unreserved characters ".", "-", "~", and "_" remain the same.
-   * <li>The general delimiters "@" and ":" remain the same.
-   * <li>The path delimiters "/" and "?" remain the same.
-   * <li>The subdelimiters "!", "$", "'", "(", ")", "*", ",", and ";",
-   *     remain the same.
-   * <li>The space character " " is converted into %20.
-   * <li>The equals sign "=" is converted into %3D.
-   * <li>The ampersand "&amp;" is converted into %26.
-   * <li>All other characters are converted into one or more bytes using UTF-8
-   *     encoding and each byte is then represented by the 3-character string
-   *     "%XY", where "XY" is the two-digit, uppercase, hexadecimal
-   *     representation of the byte value.
-   * </ul>
-   *
-   * <p><b>Note</b>: Unlike other escapers, URI 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
-   * for all percent-encodings."</i>
-   *
-   * <p>This method is equivalent to {@code uriQueryStringEscaper(false)}.
-   */
-  public static Escaper uriQueryStringEscaper() {
-    return uriQueryStringEscaper(false);
-  }
-
-  /**
-   * Returns a {@link Escaper} instance that escapes Java characters so they can
-   * be safely included in URIs. For details on escaping URIs, see section 2.4
-   * of <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>.
-   *
-   * <p>When encoding a String, the following rules apply:
-   * <ul>
-   * <li>The alphanumeric characters "a" through "z", "A" through "Z" and "0"
-   *     through "9" remain the same.
-   * <li>The special characters ".", "-", "*", and "_" remain the same.
-   * <li>If {@code plusForSpace} was specified, the space character " " is
-   *     converted into a plus sign "+". Otherwise it is converted into "%20".
-   * <li>All other characters are converted into one or more bytes using UTF-8
-   *     encoding and each byte is then represented by the 3-character string
-   *     "%XY", where "XY" is the two-digit, uppercase, hexadecimal
-   *     representation of the byte value.
-   * </ul>
-   *
-   * <p><b>Note</b>: Unlike other escapers, URI 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
-   * for all percent-encodings."</i>
-   *
-   * @param plusForSpace if {@code true} space is escaped to {@code +} otherwise
-   *        it is escaped to {@code %20}. Although common, the escaping of
-   *        spaces as plus signs has a very ambiguous status in the relevant
-   *        specifications. You should prefer {@code %20} unless you are doing
-   *        exact character-by-character comparisons of URLs and backwards
-   *        compatibility requires you to use plus signs.
-   *
-   * @see #uriEscaper()
-   */
-  public static Escaper uriEscaper(boolean plusForSpace) {
-    return plusForSpace ? URI_ESCAPER : URI_ESCAPER_NO_PLUS;
-  }
-
-  /**
-   * Returns an {@link Escaper} instance that escapes Java chars so they can be
-   * safely included in URI query string segments. When the query string
-   * consists of a sequence of name=value pairs separated by &amp;, the names
-   * and values should be individually encoded. If you escape an entire query
-   * string in one pass with this escaper, then the "=" and "&amp;" characters
-   * used as separators will also be escaped.
-   *
-   * <p>This escaper is also suitable for escaping fragment identifiers.
-   *
-   * <p>For details on escaping URIs, see
-   * section 2.4 of <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
-   *
-   * <p>When encoding a String, the following rules apply:
-   * <ul>
-   * <li>The alphanumeric characters "a" through "z", "A" through "Z" and "0"
-   *     through "9" remain the same.
-   * <li>The unreserved characters ".", "-", "~", and "_" remain the same.
-   * <li>The general delimiters "@" and ":" remain the same.
-   * <li>The path delimiters "/" and "?" remain the same.
-   * <li>The subdelimiters "!", "$", "'", "(", ")", "*", ",", and ";",
-   *     remain the same.
-   * <li>If {@code plusForSpace} was specified, the space character " " is
-   *     converted into a plus sign "+". Otherwise it is converted into "%20".
-   * <li>The equals sign "=" is converted into %3D.
-   * <li>The ampersand "&amp;" is converted into %26.
-   * <li>All other characters are converted into one or more bytes using UTF-8
-   *     encoding and each byte is then represented by the 3-character string
-   *     "%XY", where "XY" is the two-digit, uppercase, hexadecimal
-   *     representation of the byte value.
-   * </ul>
-   *
-   * <p><b>Note</b>: Unlike other escapers, URI 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
-   * for all percent-encodings."</i>
-   *
-   * @param plusForSpace if {@code true} space is escaped to {@code +} otherwise
-   *        it is escaped to {@code %20}. Although common, the escaping of
-   *        spaces as plus signs has a very ambiguous status in the relevant
-   *        specifications. You should prefer {@code %20} unless you are doing
-   *        exact character-by-character comparisons of URLs and backwards
-   *        compatibility requires you to use plus signs.
-   *
-   * @see #uriQueryStringEscaper()
-   */
-  public static Escaper uriQueryStringEscaper(boolean plusForSpace) {
-    return plusForSpace ?
-           URI_QUERY_STRING_ESCAPER_WITH_PLUS : URI_QUERY_STRING_ESCAPER;
-  }
-
-  private static final Escaper URI_ESCAPER =
-      new PercentEscaper(PercentEscaper.SAFECHARS_URLENCODER, true);
-
-  private static final Escaper URI_ESCAPER_NO_PLUS =
-      new PercentEscaper(PercentEscaper.SAFECHARS_URLENCODER, false);
-
-  private static final Escaper URI_PATH_ESCAPER =
-      new PercentEscaper(PercentEscaper.SAFEPATHCHARS_URLENCODER, false);
-
-  private static final Escaper URI_QUERY_STRING_ESCAPER =
-      new PercentEscaper(PercentEscaper.SAFEQUERYSTRINGCHARS_URLENCODER, false);
-
-  private static final Escaper URI_QUERY_STRING_ESCAPER_WITH_PLUS =
-      new PercentEscaper(PercentEscaper.SAFEQUERYSTRINGCHARS_URLENCODER, true);
-
-  /**
-   * Returns a {@link Escaper} instance that escapes Java characters in a manner
-   * compatible with the C++ webutil/url URL class (the {@code kGoogle1Escape}
-   * set).
-   *
-   * <p>When encoding a String, the following rules apply:
-   * <ul>
-   * <li>The alphanumeric characters "a" through "z", "A" through "Z" and "0"
-   * through "9" remain the same.
-   * <li>The special characters "!", "(", ")", "*", "-", ".", "_", "~", ",", "/"
-   * and ":" remain the same.
-   * <li>The space character " " is converted into a plus sign "+".
-   * <li>All other characters are converted into one or more bytes using UTF-8
-   *     encoding and each byte is then represented by the 3-character string
-   *     "%XY", where "XY" is the two-digit, uppercase, hexadecimal
-   *     representation of the byte value.
-   * </ul>
-   *
-   * <p><b>Note</b>: Unlike other escapers, URI 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
-   * for all percent-encodings."</i>
-   *
-   * <p><b>Note</b>: This escaper is a special case and is <em>not
-   * compliant</em> with <a href="http://www.ietf.org/rfc/rfc2396.txt">
-   * RFC 2396</a>. Specifically it will not escape "/", ":" and ",". This is
-   * only provided for certain limited use cases and you should favor using
-   * {@link #uriEscaper()} whenever possible.
-   */
-  public static Escaper cppUriEscaper() {
-    return CPP_URI_ESCAPER;
-  }
-
-  // Based on comments from FastURLEncoder:
-  // These octets mimic the ones escaped by the C++ webutil/url URL class --
-  // the kGoogle1Escape set.
-  // To produce the same escaping as C++, use this set with the plusForSpace
-  // option.
-  // WARNING: Contrary to RFC 2396 ",", "/" and ":" are listed as safe here.
-  private static final Escaper CPP_URI_ESCAPER =
-      new PercentEscaper("!()*-._~,/:", true);
-
-  /**
-   * Returns a {@link CharEscaper} instance that escapes special characters in a
-   * string so it can safely be included in a Java string literal.
-   *
-   * <p><b>Note</b></p>: does not escape single quotes, so use the escaper
-   * returned by {@link #javaCharEscaper()} if you are generating char
-   * literals or if you are unsure.
-   */
-  public static CharEscaper javaStringEscaper() {
-    return JAVA_STRING_ESCAPER;
-  }
-
-  /**
-   * Escapes special characters from a string so it can safely be included in a
-   * Java string literal. Does <em>not</em> escape single-quotes, so use
-   * JAVA_CHAR_ESCAPE if you are generating char literals, or if you are unsure.
-   *
-   * <p>Note that non-ASCII characters will be octal or Unicode escaped.
-   */
-  private static final CharEscaper JAVA_STRING_ESCAPER
-      = new JavaCharEscaper(new CharEscaperBuilder()
-          .addEscape('\b', "\\b")
-          .addEscape('\f', "\\f")
-          .addEscape('\n', "\\n")
-          .addEscape('\r', "\\r")
-          .addEscape('\t', "\\t")
-          .addEscape('\"', "\\\"")
-          .addEscape('\\', "\\\\")
-          .toArray());
-
-  /**
-   * Returns a {@link CharEscaper} instance that escapes special characters in a
-   * string so it can safely be included in a Java char or string literal. The
-   * behavior of this escaper is the same as that of the
-   * {@link #javaStringEscaper()}, except it also escapes single quotes.
-   */
-  public static CharEscaper javaCharEscaper() {
-    return JAVA_CHAR_ESCAPER;
-  }
-
-  /**
-   * Escapes special characters from a string so it can safely be included in a
-   * Java char literal or string literal.
-   *
-   * <p>Note that non-ASCII characters will be octal or Unicode escaped.
-   *
-   * <p>This is the same as {@link #JAVA_STRING_ESCAPER}, except that it escapes
-   * single quotes.
-   */
-  private static final CharEscaper JAVA_CHAR_ESCAPER
-      = new JavaCharEscaper(new CharEscaperBuilder()
-          .addEscape('\b', "\\b")
-          .addEscape('\f', "\\f")
-          .addEscape('\n', "\\n")
-          .addEscape('\r', "\\r")
-          .addEscape('\t', "\\t")
-          .addEscape('\'', "\\'")
-          .addEscape('\"', "\\\"")
-          .addEscape('\\', "\\\\")
-          .toArray());
-
-  /**
-   * Returns a {@link CharEscaper} instance that replaces non-ASCII characters
-   * in a string with their Unicode escape sequences ({@code \\uxxxx} where
-   * {@code xxxx} is a hex number). Existing escape sequences won't be affected.
-   */
-  public static CharEscaper javaStringUnicodeEscaper() {
-    return JAVA_STRING_UNICODE_ESCAPER;
-  }
-
-  /**
-   * Escapes each non-ASCII character in with its Unicode escape sequence
-   * {@code \\uxxxx} where {@code xxxx} is a hex number. Existing escape
-   * sequences won't be affected.
-   */
-  private static final CharEscaper JAVA_STRING_UNICODE_ESCAPER
-      = new CharEscaper() {
-          @Override protected char[] escape(char c) {
-            if (c <= 127) {
-              return null;
-            }
-
-            char[] r = new char[6];
-            r[5] = HEX_DIGITS[c & 15];
-            c >>>= 4;
-            r[4] = HEX_DIGITS[c & 15];
-            c >>>= 4;
-            r[3] = HEX_DIGITS[c & 15];
-            c >>>= 4;
-            r[2] = HEX_DIGITS[c & 15];
-            r[1] = 'u';
-            r[0] = '\\';
-            return r;
-          }
-        };
-
-  /**
-   * Returns a {@link CharEscaper} instance that escapes special characters from
-   * a string so it can safely be included in a Python string literal. Does not
-   * have any special handling for non-ASCII characters.
-   */
-  public static CharEscaper pythonEscaper() {
-    return PYTHON_ESCAPER;
-  }
-
-  /**
-   * Escapes special characters in a string so it can safely be included in a
-   * Python string literal. Does not have any special handling for non-ASCII
-   * characters.
-   */
-  private static final CharEscaper PYTHON_ESCAPER = new CharEscaperBuilder()
-      // TODO(laurence): perhaps this should escape non-ASCII characters?
-      .addEscape('\n', "\\n")
-      .addEscape('\r', "\\r")
-      .addEscape('\t', "\\t")
-      .addEscape('\\', "\\\\")
-      .addEscape('\"', "\\\"")
-      .addEscape('\'', "\\\'")
-      .toEscaper();
-
-  /**
-   * Returns a {@link CharEscaper} instance that escapes non-ASCII characters in
-   * a string so it can safely be included in a Javascript string literal.
-   * Non-ASCII characters are replaced with their ASCII javascript escape
-   * sequences (e.g., \\uhhhh or \xhh).
-   */
-  public static CharEscaper javascriptEscaper() {
-    return JAVASCRIPT_ESCAPER;
-  }
-
-  /**
-   * {@code CharEscaper} to escape javascript strings. Turns all non-ASCII
-   * characters into ASCII javascript escape sequences (e.g., \\uhhhh or \xhh).
-   */
-  private static final CharEscaper JAVASCRIPT_ESCAPER
-      = new JavascriptCharEscaper(new CharEscaperBuilder()
-          .addEscape('\'', "\\x27")
-          .addEscape('"',  "\\x22")
-          .addEscape('<',  "\\x3c")
-          .addEscape('=',  "\\x3d")
-          .addEscape('>',  "\\x3e")
-          .addEscape('&',  "\\x26")
-          .addEscape('\b', "\\b")
-          .addEscape('\t', "\\t")
-          .addEscape('\n', "\\n")
-          .addEscape('\f', "\\f")
-          .addEscape('\r', "\\r")
-          .addEscape('\\', "\\\\")
-          .toArray());
-
-  private static CharEscaperBuilder newBasicXmlEscapeBuilder() {
-    return new CharEscaperBuilder()
-        .addEscape('&', "&amp;")
-        .addEscape('<', "&lt;")
-        .addEscape('>', "&gt;")
-        .addEscapes(new char[] {
-            '\000', '\001', '\002', '\003', '\004',
-            '\005', '\006', '\007', '\010', '\013',
-            '\014', '\016', '\017', '\020', '\021',
-            '\022', '\023', '\024', '\025', '\026',
-            '\027', '\030', '\031', '\032', '\033',
-            '\034', '\035', '\036', '\037'}, "");
-  }
-
-  /**
-   * Returns a composite {@link CharEscaper} instance that tries to escape
-   * characters using a primary {@code CharEscaper} first and falls back to a
-   * secondary one if there is no escaping.
-   *
-   * <p>The returned escaper will attempt to escape each character using the
-   * primary escaper, and if the primary escaper has no escaping for that
-   * character, it will use the secondary escaper. If the secondary escaper has
-   * no escaping for a character either, the original character will be used.
-   * If the primary escaper has an escape for a character, the secondary escaper
-   * will not be used at all for that character; the escaped output of the
-   * primary is not run through the secondary. For a case where you would like
-   * to first escape with one escaper, and then with another, it is recommended
-   * that you call each escaper in order.
-   *
-   * @param primary The primary {@code CharEscaper} to use
-   * @param secondary The secondary {@code CharEscaper} to use if the first one
-   *     has no escaping rule for a character
-   * @throws NullPointerException if any of the arguments is null
-   */
-  public static CharEscaper fallThrough(CharEscaper primary,
-      CharEscaper secondary) {
-    checkNotNull(primary);
-    checkNotNull(secondary);
-    return new FallThroughCharEscaper(primary, secondary);
-  }
-
-  /**
-   * A fast {@link CharEscaper} that uses an array of replacement characters and
-   * a range of safe characters. It overrides {@link #escape(String)} to improve
-   * performance. Rough benchmarking shows that this almost doubles the speed
-   * when processing strings that do not require escaping (providing the escape
-   * test itself is efficient).
-   */
-  private static abstract class FastCharEscaper extends CharEscaper {
-
-    protected final char[][] replacements;
-    protected final int replacementLength;
-    protected final char safeMin;
-    protected final char safeMax;
-
-    public FastCharEscaper(char[][] replacements, char safeMin, char safeMax) {
-      this.replacements = replacements;
-      this.replacementLength = replacements.length;
-      this.safeMin = safeMin;
-      this.safeMax = safeMax;
-    }
-
-    /** Overridden for performance (see {@link FastCharEscaper}). */
-    @Override public String escape(String s) {
-      int slen = s.length();
-      for (int index = 0; index < slen; index++) {
-        char c = s.charAt(index);
-        if ((c < replacementLength && replacements[c] != null)
-            || c < safeMin || c > safeMax) {
-          return escapeSlow(s, index);
-        }
-      }
-      return s;
-    }
-  }
-
-  /**
-   * Escaper for Java character escaping, contains both an array and a
-   * backup function.  We're not overriding the array decorator because we
-   * want to keep this as fast as possible, so no calls to super.escape first.
-   */
-  private static class JavaCharEscaper extends FastCharEscaper {
-
-    public JavaCharEscaper(char[][] replacements) {
-      super(replacements, ' ', '~');
-    }
-
-    @Override protected char[] escape(char c) {
-      // First check if our array has a valid escaping.
-      if (c < replacementLength) {
-        char[] r = replacements[c];
-        if (r != null) {
-          return r;
-        }
-      }
-
-      // This range is un-escaped.
-      if (safeMin <= c && c <= safeMax) {
-        return null;
-      }
-
-      if (c <= 0xFF) {
-        // Convert c to an octal-escaped string.
-        // Equivalent to String.format("\\%03o", (int)c);
-        char[] r = new char[4];
-        r[0] = '\\';
-        r[3] = HEX_DIGITS[c & 7];
-        c >>>= 3;
-        r[2] = HEX_DIGITS[c & 7];
-        c >>>= 3;
-        r[1] = HEX_DIGITS[c & 7];
-        return r;
-      }
-
-      // Convert c to a hex-escaped string.
-      // Equivalent to String.format("\\u%04x", (int)c);
-      char[] r = new char[6];
-      r[0] = '\\';
-      r[1] = 'u';
-      r[5] = HEX_DIGITS[c & 15];
-      c >>>= 4;
-      r[4] = HEX_DIGITS[c & 15];
-      c >>>= 4;
-      r[3] = HEX_DIGITS[c & 15];
-      c >>>= 4;
-      r[2] = HEX_DIGITS[c & 15];
-      return r;
-    }
-  }
-
-  /**
-   * Escaper for javascript character escaping, contains both an array and a
-   * backup function. We're not overriding the array decorator because we
-   * want to keep this as fast as possible, so no calls to super.escape first.
-   */
-  private static class JavascriptCharEscaper extends FastCharEscaper {
-
-    public JavascriptCharEscaper(char[][] replacements) {
-      super(replacements, ' ', '~');
-    }
-
-    @Override protected char[] escape(char c) {
-      // First check if our array has a valid escaping.
-      if (c < replacementLength) {
-        char[] r = replacements[c];
-        if (r != null) {
-          return r;
-        }
-      }
-
-      // This range is unescaped.
-      if (safeMin <= c && c <= safeMax) {
-        return null;
-      }
-
-      // we can do a 2 digit hex escape for chars less that 0x100
-      if (c < 0x100) {
-        char[] r = new char[4];
-        r[3] = HEX_DIGITS[c & 0xf];
-        c >>>= 4;
-        r[2] = HEX_DIGITS[c & 0xf];
-        r[1] = 'x';
-        r[0] = '\\';
-        return r;
-      }
-
-      // 4 digit hex escape everything else
-      char[] r = new char[6];
-      r[5] = HEX_DIGITS[c & 0xf];
-      c >>>= 4;
-      r[4] = HEX_DIGITS[c & 0xf];
-      c >>>= 4;
-      r[3] = HEX_DIGITS[c & 0xf];
-      c >>>= 4;
-      r[2] = HEX_DIGITS[c & 0xf];
-      r[1] = 'u';
-      r[0] = '\\';
-      return r;
-    }
-  }
-
-  /**
-   * Escaper for HTML character escaping, contains both an array and a
-   * backup function.  We're not overriding the array decorator because we
-   * want to keep this as fast as possible, so no calls to super.escape first.
-   */
-  private static class HtmlCharEscaper extends FastCharEscaper {
-
-    public HtmlCharEscaper(char[][] replacements) {
-      super(replacements, Character.MIN_VALUE, '~');
-    }
-
-    @Override protected char[] escape(char c) {
-      // First check if our array has a valid escaping.
-      if (c < replacementLength) {
-        char[] r = replacements[c];
-        if (r != null) {
-          return r;
-        }
-      }
-
-      // ~ is ASCII 126, the highest value char that does not need
-      // to be escaped
-      if (c <= safeMax) {
-        return null;
-      }
-
-      int index;
-      if (c < 1000) {
-        index = 4;
-      } else if (c < 10000) {
-        index = 5;
-      } else {
-        index = 6;
-      }
-      char[] result = new char[index + 2];
-      result[0] = '&';
-      result[1] = '#';
-      result[index + 1] = ';';
-
-      // TODO(sven): Convert this to a sequence of shifts/additions
-      // to avoid the division and modulo operators.
-      int intValue = c;
-      for (; index > 1; index--) {
-        result[index] = HEX_DIGITS[intValue % 10];
-        intValue /= 10;
-      }
-      return result;
-    }
-  }
-
-  /**
-   * A composite {@code CharEscaper} object that tries to escape characters
-   * using a primary {@code CharEscaper} first and falls back to a secondary
-   * one if there is no escaping.
-   */
-  private static class FallThroughCharEscaper extends CharEscaper {
-
-    private final CharEscaper primary;
-    private final CharEscaper secondary;
-
-    public FallThroughCharEscaper(CharEscaper primary, CharEscaper secondary) {
-      this.primary = primary;
-      this.secondary = secondary;
-    }
-
-    @Override
-    protected char[] escape(char c) {
-      char result[] = primary.escape(c);
-      if (result == null) {
-        result = secondary.escape(c);
-      }
-      return result;
-    }
-  }
-
-  private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray();
-}
\ No newline at end of file
diff --git a/src/com/android/mail/lib/base/CharMatcher.java b/src/com/android/mail/lib/base/CharMatcher.java
deleted file mode 100644
index 9ff3161..0000000
--- a/src/com/android/mail/lib/base/CharMatcher.java
+++ /dev/null
@@ -1,1124 +0,0 @@
-/*
- * Copyright (C) 2008 Google Inc.
- *
- * 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.android.mail.lib.base;
-
-import static com.android.mail.lib.base.Preconditions.checkArgument;
-import static com.android.mail.lib.base.Preconditions.checkNotNull;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Determines a true or false value for any Java {@code char} value, just as
- * {@link Predicate} does for any {@link Object}. Also offers basic text
- * processing methods based on this function. Implementations are strongly
- * encouraged to be side-effect-free and immutable.
- *
- * <p>Throughout the documentation of this class, the phrase "matching
- * character" is used to mean "any character {@code c} for which {@code
- * this.matches(c)} returns {@code true}".
- *
- * <p><b>Note:</b> This class deals only with {@code char} values; it does not
- * understand supplementary Unicode code points in the range {@code 0x10000} to
- * {@code 0x10FFFF}. Such logical characters are encoded into a {@code String}
- * using surrogate pairs, and a {@code CharMatcher} treats these just as two
- * separate characters.
- *
- * @author Kevin Bourrillion
- * @since 2009.09.15 <b>tentative</b>
- */
-public abstract class CharMatcher implements Predicate<Character> {
-
-  // Constants
-
-  // Excludes 2000-2000a, which is handled as a range
-  private static final String BREAKING_WHITESPACE_CHARS =
-      "\t\n\013\f\r \u0085\u1680\u2028\u2029\u205f\u3000";
-
-  // Excludes 2007, which is handled as a gap in a pair of ranges
-  private static final String NON_BREAKING_WHITESPACE_CHARS =
-      "\u00a0\u180e\u202f";
-
-  /**
-   * Determines whether a character is whitespace according to the latest
-   * Unicode standard, as illustrated
-   * <a href="http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5Cp%7Bwhitespace%7D">here</a>.
-   * This is not the same definition used by other Java APIs. See a comparison
-   * of several definitions of "whitespace" at
-   * <a href="TODO">(TODO)</a>.
-   *
-   * <p><b>Note:</b> as the Unicode definition evolves, we will modify this
-   * constant to keep it up to date.
-   */
-  public static final CharMatcher WHITESPACE =
-      anyOf(BREAKING_WHITESPACE_CHARS + NON_BREAKING_WHITESPACE_CHARS)
-          .or(inRange('\u2000', '\u200a'));
-
-  /**
-   * Determines whether a character is a breaking whitespace (that is,
-   * a whitespace which can be interpreted as a break between words
-   * for formatting purposes).  See {@link #WHITESPACE} for a discussion
-   * of that term.
-   *
-   * @since 2010.01.04 <b>tentative</b>
-   */
-  public static final CharMatcher BREAKING_WHITESPACE =
-      anyOf(BREAKING_WHITESPACE_CHARS)
-          .or(inRange('\u2000', '\u2006'))
-          .or(inRange('\u2008', '\u200a'));
-
-  /**
-   * Determines whether a character is ASCII, meaning that its code point is
-   * less than 128.
-   */
-  public static final CharMatcher ASCII = inRange('\0', '\u007f');
-
-  /**
-   * Determines whether a character is a digit according to
-   * <a href="http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5Cp%7Bdigit%7D">Unicode</a>.
-   */
-  public static final CharMatcher DIGIT;
-
-  static {
-    CharMatcher digit = inRange('0', '9');
-    String zeroes =
-        "\u0660\u06f0\u07c0\u0966\u09e6\u0a66\u0ae6\u0b66\u0be6\u0c66"
-            + "\u0ce6\u0d66\u0e50\u0ed0\u0f20\u1040\u1090\u17e0\u1810\u1946"
-            + "\u19d0\u1b50\u1bb0\u1c40\u1c50\ua620\ua8d0\ua900\uaa50\uff10";
-    for (char base : zeroes.toCharArray()) {
-      digit = digit.or(inRange(base, (char) (base + 9)));
-    }
-    DIGIT = digit;
-  }
-
-  /**
-   * Determines whether a character is whitespace according to {@link
-   * Character#isWhitespace(char) Java's definition}; it is usually preferable
-   * to use {@link #WHITESPACE}. See a comparison of several definitions of
-   * "whitespace" at <a href="http://go/white+space">go/white+space</a>.
-   */
-  public static final CharMatcher JAVA_WHITESPACE
-      = inRange('\u0009', (char) 13)  // \\u000d doesn't work as a char literal
-      .or(inRange('\u001c', '\u0020'))
-      .or(is('\u1680'))
-      .or(is('\u180e'))
-      .or(inRange('\u2000', '\u2006'))
-      .or(inRange('\u2008', '\u200b'))
-      .or(inRange('\u2028', '\u2029'))
-      .or(is('\u205f'))
-      .or(is('\u3000'));
-
-  /**
-   * Determines whether a character is a digit according to {@link
-   * Character#isDigit(char) Java's definition}. If you only care to match
-   * ASCII digits, you can use {@code inRange('0', '9')}.
-   */
-  public static final CharMatcher JAVA_DIGIT = new CharMatcher() {
-    @Override public boolean matches(char c) {
-      return Character.isDigit(c);
-    }
-  };
-
-  /**
-   * Determines whether a character is a letter according to {@link
-   * Character#isLetter(char) Java's definition}. If you only care to match
-   * letters of the Latin alphabet, you can use {@code
-   * inRange('a', 'z').or(inRange('A', 'Z'))}.
-   */
-  public static final CharMatcher JAVA_LETTER = new CharMatcher() {
-    @Override public boolean matches(char c) {
-      return Character.isLetter(c);
-    }
-  };
-
-  /**
-   * Determines whether a character is a letter or digit according to {@link
-   * Character#isLetterOrDigit(char) Java's definition}.
-   */
-  public static final CharMatcher JAVA_LETTER_OR_DIGIT = new CharMatcher() {
-    @Override public boolean matches(char c) {
-      return Character.isLetterOrDigit(c);
-    }
-  };
-
-  /**
-   * Determines whether a character is upper case according to {@link
-   * Character#isUpperCase(char) Java's definition}.
-   */
-  public static final CharMatcher JAVA_UPPER_CASE = new CharMatcher() {
-    @Override public boolean matches(char c) {
-      return Character.isUpperCase(c);
-    }
-  };
-
-  /**
-   * Determines whether a character is lower case according to {@link
-   * Character#isLowerCase(char) Java's definition}.
-   */
-  public static final CharMatcher JAVA_LOWER_CASE = new CharMatcher() {
-    @Override public boolean matches(char c) {
-      return Character.isLowerCase(c);
-    }
-  };
-
-  /**
-   * Determines whether a character is an ISO control character according to
-   * {@link Character#isISOControl(char)}.
-   */
-  public static final CharMatcher JAVA_ISO_CONTROL = inRange('\u0000', '\u001f')
-      .or(inRange('\u007f', '\u009f'));
-
-  /**
-   * Determines whether a character is invisible; that is, if its Unicode
-   * category is any of SPACE_SEPARATOR, LINE_SEPARATOR,
-   * PARAGRAPH_SEPARATOR, CONTROL, FORMAT, SURROGATE, and PRIVATE_USE according
-   * to ICU4J.
-   */
-  public static final CharMatcher INVISIBLE = inRange('\u0000', '\u0020')
-      .or(inRange('\u007f', '\u00a0'))
-      .or(is('\u00ad'))
-      .or(inRange('\u0600', '\u0603'))
-      .or(anyOf("\u06dd\u070f\u1680\u17b4\u17b5\u180e"))
-      .or(inRange('\u2000', '\u200f'))
-      .or(inRange('\u2028', '\u202f'))
-      .or(inRange('\u205f', '\u2064'))
-      .or(inRange('\u206a', '\u206f'))
-      .or(is('\u3000'))
-      .or(inRange('\ud800', '\uf8ff'))
-      .or(anyOf("\ufeff\ufff9\ufffa\ufffb"));
-
-  /**
-   * Determines whether a character is single-width (not double-width).  When
-   * in doubt, this matcher errs on the side of returning {@code false} (that
-   * is, it tends to assume a character is double-width).
-   *
-   * <b>Note:</b> as the reference file evolves, we will modify this constant
-   * to keep it up to date.
-   */
-  public static final CharMatcher SINGLE_WIDTH = inRange('\u0000', '\u04f9')
-      .or(is('\u05be'))
-      .or(inRange('\u05d0', '\u05ea'))
-      .or(is('\u05f3'))
-      .or(is('\u05f4'))
-      .or(inRange('\u0600', '\u06ff'))
-      .or(inRange('\u0750', '\u077f'))
-      .or(inRange('\u0e00', '\u0e7f'))
-      .or(inRange('\u1e00', '\u20af'))
-      .or(inRange('\u2100', '\u213a'))
-      .or(inRange('\ufb50', '\ufdff'))
-      .or(inRange('\ufe70', '\ufeff'))
-      .or(inRange('\uff61', '\uffdc'));
-
-  /**
-   * Determines whether a character is whitespace according to an arbitrary definition used by
-   * {@link StringUtil} for years. Most likely you don't want to use this. See a comparison of
-   * several definitions of "whitespace" at <a href="http://goto/white space">goto/white space</a>.
-   *
-   * <p><b>To be deprecated.</b> use {@link #WHITESPACE} to switch to the Unicode definition, or
-   * create a matcher for the specific characters you want. Not deprecated yet because it is a
-   * stepping stone for getting off of many deprecated {@link StringUtil} methods.
-   */
-  @Deprecated
-  public static final CharMatcher LEGACY_WHITESPACE =
-      anyOf(" \r\n\t\u3000\u00A0\u2007\u202F").precomputed();
-
-
-  /** Matches any character. */
-  public static final CharMatcher ANY = new CharMatcher() {
-    @Override public boolean matches(char c) {
-      return true;
-    }
-
-    @Override public int indexIn(CharSequence sequence) {
-      return (sequence.length() == 0) ? -1 : 0;
-    }
-    @Override public int indexIn(CharSequence sequence, int start) {
-      int length = sequence.length();
-      Preconditions.checkPositionIndex(start, length);
-      return (start == length) ? -1 : start;
-    }
-    @Override public int lastIndexIn(CharSequence sequence) {
-      return sequence.length() - 1;
-    }
-    @Override public boolean matchesAllOf(CharSequence sequence) {
-      checkNotNull(sequence);
-      return true;
-    }
-    @Override public boolean matchesNoneOf(CharSequence sequence) {
-      return sequence.length() == 0;
-    }
-    @Override public String removeFrom(CharSequence sequence) {
-      checkNotNull(sequence);
-      return "";
-    }
-    @Override public String replaceFrom(
-        CharSequence sequence, char replacement) {
-      char[] array = new char[sequence.length()];
-      Arrays.fill(array, replacement);
-      return new String(array);
-    }
-    @Override public String replaceFrom(
-        CharSequence sequence, CharSequence replacement) {
-      StringBuilder retval = new StringBuilder(sequence.length() * replacement.length());
-      for (int i = 0; i < sequence.length(); i++) {
-        retval.append(replacement);
-      }
-      return retval.toString();
-    }
-    @Override public String collapseFrom(CharSequence sequence, char replacement) {
-      return (sequence.length() == 0) ? "" : String.valueOf(replacement);
-    }
-    @Override public String trimFrom(CharSequence sequence) {
-      checkNotNull(sequence);
-      return "";
-    }
-    @Override public int countIn(CharSequence sequence) {
-      return sequence.length();
-    }
-    @Override public CharMatcher and(CharMatcher other) {
-      return checkNotNull(other);
-    }
-    @Override public CharMatcher or(CharMatcher other) {
-      checkNotNull(other);
-      return this;
-    }
-    @Override public CharMatcher negate() {
-      return NONE;
-    }
-    @Override public CharMatcher precomputed() {
-      return this;
-    }
-  };
-
-  /** Matches no characters. */
-  public static final CharMatcher NONE = new CharMatcher() {
-    @Override public boolean matches(char c) {
-      return false;
-    }
-
-    @Override public int indexIn(CharSequence sequence) {
-      checkNotNull(sequence);
-      return -1;
-    }
-    @Override public int indexIn(CharSequence sequence, int start) {
-      int length = sequence.length();
-      Preconditions.checkPositionIndex(start, length);
-      return -1;
-    }
-    @Override public int lastIndexIn(CharSequence sequence) {
-      checkNotNull(sequence);
-      return -1;
-    }
-    @Override public boolean matchesAllOf(CharSequence sequence) {
-      return sequence.length() == 0;
-    }
-    @Override public boolean matchesNoneOf(CharSequence sequence) {
-      checkNotNull(sequence);
-      return true;
-    }
-    @Override public String removeFrom(CharSequence sequence) {
-      return sequence.toString();
-    }
-    @Override public String replaceFrom(
-        CharSequence sequence, char replacement) {
-      return sequence.toString();
-    }
-    @Override public String replaceFrom(
-        CharSequence sequence, CharSequence replacement) {
-      checkNotNull(replacement);
-      return sequence.toString();
-    }
-    @Override public String collapseFrom(
-        CharSequence sequence, char replacement) {
-      return sequence.toString();
-    }
-    @Override public String trimFrom(CharSequence sequence) {
-      return sequence.toString();
-    }
-    @Override public int countIn(CharSequence sequence) {
-      checkNotNull(sequence);
-      return 0;
-    }
-    @Override public CharMatcher and(CharMatcher other) {
-      checkNotNull(other);
-      return this;
-    }
-    @Override public CharMatcher or(CharMatcher other) {
-      return checkNotNull(other);
-    }
-    @Override public CharMatcher negate() {
-      return ANY;
-    }
-    @Override protected void setBits(LookupTable table) {
-    }
-    @Override public CharMatcher precomputed() {
-      return this;
-    }
-  };
-
-  // Static factories
-
-  /**
-   * Returns a {@code char} matcher that matches only one specified character.
-   */
-  public static CharMatcher is(final char match) {
-    return new CharMatcher() {
-      @Override public boolean matches(char c) {
-        return c == match;
-      }
-
-      @Override public String replaceFrom(
-          CharSequence sequence, char replacement) {
-        return sequence.toString().replace(match, replacement);
-      }
-      @Override public CharMatcher and(CharMatcher other) {
-        return other.matches(match) ? this : NONE;
-      }
-      @Override public CharMatcher or(CharMatcher other) {
-        return other.matches(match) ? other : super.or(other);
-      }
-      @Override public CharMatcher negate() {
-        return isNot(match);
-      }
-      @Override protected void setBits(LookupTable table) {
-        table.set(match);
-      }
-      @Override public CharMatcher precomputed() {
-        return this;
-      }
-    };
-  }
-
-  /**
-   * Returns a {@code char} matcher that matches any character except the one
-   * specified.
-   *
-   * <p>To negate another {@code CharMatcher}, use {@link #negate()}.
-   */
-  public static CharMatcher isNot(final char match) {
-    return new CharMatcher() {
-      @Override public boolean matches(char c) {
-        return c != match;
-      }
-
-      @Override public CharMatcher and(CharMatcher other) {
-        return other.matches(match) ? super.and(other) : other;
-      }
-      @Override public CharMatcher or(CharMatcher other) {
-        return other.matches(match) ? ANY : this;
-      }
-      @Override public CharMatcher negate() {
-        return is(match);
-      }
-    };
-  }
-
-  /**
-   * Returns a {@code char} matcher that matches any character present in the
-   * given character sequence.
-   */
-  public static CharMatcher anyOf(final CharSequence sequence) {
-    switch (sequence.length()) {
-      case 0:
-        return NONE;
-      case 1:
-        return is(sequence.charAt(0));
-      case 2:
-        final char match1 = sequence.charAt(0);
-        final char match2 = sequence.charAt(1);
-        return new CharMatcher() {
-          @Override public boolean matches(char c) {
-            return c == match1 || c == match2;
-          }
-          @Override protected void setBits(LookupTable table) {
-            table.set(match1);
-            table.set(match2);
-          }
-          @Override public CharMatcher precomputed() {
-            return this;
-          }
-        };
-    }
-
-    final char[] chars = sequence.toString().toCharArray();
-    Arrays.sort(chars); // not worth collapsing duplicates
-
-    return new CharMatcher() {
-      @Override public boolean matches(char c) {
-        return Arrays.binarySearch(chars, c) >= 0;
-      }
-      @Override protected void setBits(LookupTable table) {
-        for (char c : chars) {
-          table.set(c);
-        }
-      }
-    };
-  }
-
-  /**
-   * Returns a {@code char} matcher that matches any character not present in
-   * the given character sequence.
-   */
-  public static CharMatcher noneOf(CharSequence sequence) {
-    return anyOf(sequence).negate();
-  }
-
-  /**
-   * Returns a {@code char} matcher that matches any character in a given range
-   * (both endpoints are inclusive). For example, to match any lowercase letter
-   * of the English alphabet, use {@code CharMatcher.inRange('a', 'z')}.
-   *
-   * @throws IllegalArgumentException if {@code endInclusive < startInclusive}
-   */
-  public static CharMatcher inRange(
-      final char startInclusive, final char endInclusive) {
-    checkArgument(endInclusive >= startInclusive);
-    return new CharMatcher() {
-      @Override public boolean matches(char c) {
-        return startInclusive <= c && c <= endInclusive;
-      }
-      @Override protected void setBits(LookupTable table) {
-        char c = startInclusive;
-        while (true) {
-          table.set(c);
-          if (c++ == endInclusive) {
-            break;
-          }
-        }
-      }
-      @Override public CharMatcher precomputed() {
-        return this;
-      }
-    };
-  }
-
-  /**
-   * Returns a matcher with identical behavior to the given {@link
-   * Character}-based predicate, but which operates on primitive {@code char}
-   * instances instead.
-   */
-  public static CharMatcher forPredicate(
-      final Predicate<? super Character> predicate) {
-    checkNotNull(predicate);
-    if (predicate instanceof CharMatcher) {
-      return (CharMatcher) predicate;
-    }
-    return new CharMatcher() {
-      @Override public boolean matches(char c) {
-        return predicate.apply(c);
-      }
-      @Override public boolean apply(Character character) {
-        return predicate.apply(checkNotNull(character));
-      }
-    };
-  }
-
-  // Abstract methods
-
-  /** Determines a true or false value for the given character. */
-  public abstract boolean matches(char c);
-
-  // Non-static factories
-
-  /**
-   * Returns a matcher that matches any character not matched by this matcher.
-   */
-  public CharMatcher negate() {
-    final CharMatcher original = this;
-    return new CharMatcher() {
-      @Override public boolean matches(char c) {
-        return !original.matches(c);
-      }
-
-      @Override public boolean matchesAllOf(CharSequence sequence) {
-        return original.matchesNoneOf(sequence);
-      }
-      @Override public boolean matchesNoneOf(CharSequence sequence) {
-        return original.matchesAllOf(sequence);
-      }
-      @Override public int countIn(CharSequence sequence) {
-        return sequence.length() - original.countIn(sequence);
-      }
-      @Override public CharMatcher negate() {
-        return original;
-      }
-    };
-  }
-
-  /**
-   * Returns a matcher that matches any character matched by both this matcher
-   * and {@code other}.
-   */
-  public CharMatcher and(CharMatcher other) {
-    return new And(Arrays.asList(this, checkNotNull(other)));
-  }
-
-  private static class And extends CharMatcher {
-    List<CharMatcher> components;
-
-    And(List<CharMatcher> components) {
-      this.components = components; // Skip defensive copy (private)
-    }
-
-    @Override public boolean matches(char c) {
-      for (CharMatcher matcher : components) {
-        if (!matcher.matches(c)) {
-          return false;
-        }
-      }
-      return true;
-    }
-
-    @Override public CharMatcher and(CharMatcher other) {
-      List<CharMatcher> newComponents = new ArrayList<CharMatcher>(components);
-      newComponents.add(checkNotNull(other));
-      return new And(newComponents);
-    }
-  }
-
-  /**
-   * Returns a matcher that matches any character matched by either this matcher
-   * or {@code other}.
-   */
-  public CharMatcher or(CharMatcher other) {
-    return new Or(Arrays.asList(this, checkNotNull(other)));
-  }
-
-  private static class Or extends CharMatcher {
-    List<CharMatcher> components;
-
-    Or(List<CharMatcher> components) {
-      this.components = components; // Skip defensive copy (private)
-    }
-
-    @Override public boolean matches(char c) {
-      for (CharMatcher matcher : components) {
-        if (matcher.matches(c)) {
-          return true;
-        }
-      }
-      return false;
-    }
-
-    @Override public CharMatcher or(CharMatcher other) {
-      List<CharMatcher> newComponents = new ArrayList<CharMatcher>(components);
-      newComponents.add(checkNotNull(other));
-      return new Or(newComponents);
-    }
-
-    @Override protected void setBits(LookupTable table) {
-      for (CharMatcher matcher : components) {
-        matcher.setBits(table);
-      }
-    }
-  }
-
-  /**
-   * Returns a {@code char} matcher functionally equivalent to this one, but
-   * which may be faster to query than the original; your mileage may vary.
-   * Precomputation takes time and is likely to be worthwhile only if the
-   * precomputed matcher is queried many thousands of times.
-   *
-   * <p>This method has no effect (returns {@code this}) when called in GWT:
-   * it's unclear whether a precomputed matcher is faster, but it certainly
-   * consumes more memory, which doesn't seem like a worthwhile tradeoff in a
-   * browser.
-   */
-  public CharMatcher precomputed() {
-    return Platform.precomputeCharMatcher(this);
-  }
-
-  /**
-   * This is the actual implementation of {@link #precomputed}, but we bounce
-   * calls through a method on {@link Platform} so that we can have different
-   * behavior in GWT.
-   *
-   * <p>The default precomputation is to cache the configuration of the original
-   * matcher in an eight-kilobyte bit array. In some situations this produces a
-   * matcher which is faster to query than the original.
-   *
-   * <p>The default implementation creates a new bit array and passes it to
-   * {@link #setBits(LookupTable)}.
-   */
-  CharMatcher precomputedInternal() {
-    final LookupTable table = new LookupTable();
-    setBits(table);
-
-    return new CharMatcher() {
-      @Override public boolean matches(char c) {
-        return table.get(c);
-      }
-
-      // TODO: make methods like negate() smart
-
-      @Override public CharMatcher precomputed() {
-        return this;
-      }
-    };
-  }
-
-  /**
-   * For use by implementors; sets the bit corresponding to each character ('\0'
-   * to '{@literal \}uFFFF') that matches this matcher in the given bit array,
-   * leaving all other bits untouched.
-   *
-   * <p>The default implementation loops over every possible character value,
-   * invoking {@link #matches} for each one.
-   */
-  protected void setBits(LookupTable table) {
-    char c = Character.MIN_VALUE;
-    while (true) {
-      if (matches(c)) {
-        table.set(c);
-      }
-      if (c++ == Character.MAX_VALUE) {
-        break;
-      }
-    }
-  }
-
-  /**
-   * A bit array with one bit per {@code char} value, used by {@link
-   * CharMatcher#precomputed}.
-   *
-   * <p>TODO: possibly share a common BitArray class with BloomFilter
-   * and others... a simpler java.util.BitSet.
-   */
-  protected static class LookupTable {
-    int[] data = new int[2048];
-
-    void set(char index) {
-      data[index >> 5] |= (1 << index);
-    }
-    boolean get(char index) {
-      return (data[index >> 5] & (1 << index)) != 0;
-    }
-  }
-
-  // Text processing routines
-
-  /**
-   * Returns {@code true} if a character sequence contains only matching
-   * characters.
-   *
-   * <p>The default implementation iterates over the sequence, invoking {@link
-   * #matches} for each character, until this returns {@code false} or the end
-   * is reached.
-   *
-   * @param sequence the character sequence to examine, possibly empty
-   * @return {@code true} if this matcher matches every character in the
-   *     sequence, including when the sequence is empty
-   */
-  public boolean matchesAllOf(CharSequence sequence) {
-    for (int i = sequence.length() - 1; i >= 0; i--) {
-      if (!matches(sequence.charAt(i))) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  /**
-   * Returns {@code true} if a character sequence contains no matching
-   * characters.
-   *
-   * <p>The default implementation iterates over the sequence, invoking {@link
-   * #matches} for each character, until this returns {@code false} or the end is
-   * reached.
-   *
-   * @param sequence the character sequence to examine, possibly empty
-   * @return {@code true} if this matcher matches every character in the
-   *     sequence, including when the sequence is empty
-   */
-  public boolean matchesNoneOf(CharSequence sequence) {
-    return indexIn(sequence) == -1;
-  }
-
-  // TODO: perhaps add matchesAnyOf()
-
-  /**
-   * Returns the index of the first matching character in a character sequence,
-   * or {@code -1} if no matching character is present.
-   *
-   * <p>The default implementation iterates over the sequence in forward order
-   * calling {@link #matches} for each character.
-   *
-   * @param sequence the character sequence to examine from the beginning
-   * @return an index, or {@code -1} if no character matches
-   */
-  public int indexIn(CharSequence sequence) {
-    int length = sequence.length();
-    for (int i = 0; i < length; i++) {
-      if (matches(sequence.charAt(i))) {
-        return i;
-      }
-    }
-    return -1;
-  }
-
-  /**
-   * Returns the index of the first matching character in a character sequence,
-   * starting from a given position, or {@code -1} if no character matches after
-   * that position.
-   *
-   * <p>The default implementation iterates over the sequence in forward order,
-   * beginning at {@code start}, calling {@link #matches} for each character.
-   *
-   * @param sequence the character sequence to examine
-   * @param start the first index to examine; must be nonnegative and no
-   *     greater than {@code sequence.length()}
-   * @return the index of the first matching character, guaranteed to be no less
-   *     than {@code start}, or {@code -1} if no character matches
-   * @throws IndexOutOfBoundsException if start is negative or greater than
-   *     {@code sequence.length()}
-   */
-  public int indexIn(CharSequence sequence, int start) {
-    int length = sequence.length();
-    Preconditions.checkPositionIndex(start, length);
-    for (int i = start; i < length; i++) {
-      if (matches(sequence.charAt(i))) {
-        return i;
-      }
-    }
-    return -1;
-  }
-
-  /**
-   * Returns the index of the last matching character in a character sequence,
-   * or {@code -1} if no matching character is present.
-   *
-   * <p>The default implementation iterates over the sequence in reverse order
-   * calling {@link #matches} for each character.
-   *
-   * @param sequence the character sequence to examine from the end
-   * @return an index, or {@code -1} if no character matches
-   */
-  public int lastIndexIn(CharSequence sequence) {
-    for (int i = sequence.length() - 1; i >= 0; i--) {
-      if (matches(sequence.charAt(i))) {
-        return i;
-      }
-    }
-    return -1;
-  }
-
-  /**
-   * Returns the number of matching characters found in a character sequence.
-   */
-  public int countIn(CharSequence sequence) {
-    int count = 0;
-    for (int i = 0; i < sequence.length(); i++) {
-      if (matches(sequence.charAt(i))) {
-        count++;
-      }
-    }
-    return count;
-  }
-
-  /**
-   * Returns a string containing all non-matching characters of a character
-   * sequence, in order. For example: <pre>   {@code
-   *
-   *   CharMatcher.is('a').removeFrom("bazaar")}</pre>
-   *
-   * ... returns {@code "bzr"}.
-   */
-  public String removeFrom(CharSequence sequence) {
-    String string = sequence.toString();
-    int pos = indexIn(string);
-    if (pos == -1) {
-      return string;
-    }
-
-    char[] chars = string.toCharArray();
-    int spread = 1;
-
-    // This unusual loop comes from extensive benchmarking
-    OUT:
-    while (true) {
-      pos++;
-      while (true) {
-        if (pos == chars.length) {
-          break OUT;
-        }
-        if (matches(chars[pos])) {
-          break;
-        }
-        chars[pos - spread] = chars[pos];
-        pos++;
-      }
-      spread++;
-    }
-    return new String(chars, 0, pos - spread);
-  }
-
-  /**
-   * Returns a string containing all matching characters of a character
-   * sequence, in order. For example: <pre>   {@code
-   *
-   *   CharMatcher.is('a').retainFrom("bazaar")}</pre>
-   *
-   * ... returns {@code "aaa"}.
-   */
-  public String retainFrom(CharSequence sequence) {
-    return negate().removeFrom(sequence);
-  }
-
-  /**
-   * Returns a string copy of the input character sequence, with each character
-   * that matches this matcher replaced by a given replacement character. For
-   * example: <pre>   {@code
-   *
-   *   CharMatcher.is('a').replaceFrom("radar", 'o')}</pre>
-   *
-   * ... returns {@code "rodor"}.
-   *
-   * <p>The default implementation uses {@link #indexIn(CharSequence)} to find
-   * the first matching character, then iterates the remainder of the sequence
-   * calling {@link #matches(char)} for each character.
-   *
-   * @param sequence the character sequence to replace matching characters in
-   * @param replacement the character to append to the result string in place of
-   *     each matching character in {@code sequence}
-   * @return the new string
-   */
-  public String replaceFrom(CharSequence sequence, char replacement) {
-    String string = sequence.toString();
-    int pos = indexIn(string);
-    if (pos == -1) {
-      return string;
-    }
-    char[] chars = string.toCharArray();
-    chars[pos] = replacement;
-    for (int i = pos + 1; i < chars.length; i++) {
-      if (matches(chars[i])) {
-        chars[i] = replacement;
-      }
-    }
-    return new String(chars);
-  }
-
-  /**
-   * Returns a string copy of the input character sequence, with each character
-   * that matches this matcher replaced by a given replacement sequence. For
-   * example: <pre>   {@code
-   *
-   *   CharMatcher.is('a').replaceFrom("yaha", "oo")}</pre>
-   *
-   * ... returns {@code "yoohoo"}.
-   *
-   * <p><b>Note:</b> If the replacement is a fixed string with only one character,
-   * you are better off calling {@link #replaceFrom(CharSequence, char)} directly.
-   *
-   * @param sequence the character sequence to replace matching characters in
-   * @param replacement the characters to append to the result string in place
-   *     of each matching character in {@code sequence}
-   * @return the new string
-   */
-  public String replaceFrom(CharSequence sequence, CharSequence replacement) {
-    int replacementLen = replacement.length();
-    if (replacementLen == 0) {
-      return removeFrom(sequence);
-    }
-    if (replacementLen == 1) {
-      return replaceFrom(sequence, replacement.charAt(0));
-    }
-
-    String string = sequence.toString();
-    int pos = indexIn(string);
-    if (pos == -1) {
-      return string;
-    }
-
-    int len = string.length();
-    StringBuilder buf = new StringBuilder((int) (len * 1.5) + 16);
-
-    int oldpos = 0;
-    do {
-      buf.append(string, oldpos, pos);
-      buf.append(replacement);
-      oldpos = pos + 1;
-      pos = indexIn(string, oldpos);
-    } while (pos != -1);
-
-    buf.append(string, oldpos, len);
-    return buf.toString();
-  }
-
-  /**
-   * Returns a substring of the input character sequence that omits all
-   * characters this matcher matches from the beginning and from the end of the
-   * string. For example: <pre> {@code
-   *
-   *   CharMatcher.anyOf("ab").trimFrom("abacatbab")}</pre>
-   *
-   * ... returns {@code "cat"}.
-   *
-   * <p>Note that<pre>   {@code
-   *
-   *   CharMatcher.inRange('\0', ' ').trimFrom(str)}</pre>
-   *
-   * ... is equivalent to {@link String#trim()}.
-   */
-  public String trimFrom(CharSequence sequence) {
-    int len = sequence.length();
-    int first;
-    int last;
-
-    for (first = 0; first < len; first++) {
-      if (!matches(sequence.charAt(first))) {
-        break;
-      }
-    }
-    for (last = len - 1; last > first; last--) {
-      if (!matches(sequence.charAt(last))) {
-        break;
-      }
-    }
-
-    return sequence.subSequence(first, last + 1).toString();
-  }
-
-  /**
-   * Returns a substring of the input character sequence that omits all
-   * characters this matcher matches from the beginning of the
-   * string. For example: <pre> {@code
-   *
-   *   CharMatcher.anyOf("ab").trimLeadingFrom("abacatbab")}</pre>
-   *
-   * ... returns {@code "catbab"}.
-   */
-  public String trimLeadingFrom(CharSequence sequence) {
-    int len = sequence.length();
-    int first;
-
-    for (first = 0; first < len; first++) {
-      if (!matches(sequence.charAt(first))) {
-        break;
-      }
-    }
-
-    return sequence.subSequence(first, len).toString();
-  }
-
-  /**
-   * Returns a substring of the input character sequence that omits all
-   * characters this matcher matches from the end of the
-   * string. For example: <pre> {@code
-   *
-   *   CharMatcher.anyOf("ab").trimTrailingFrom("abacatbab")}</pre>
-   *
-   * ... returns {@code "abacat"}.
-   */
-  public String trimTrailingFrom(CharSequence sequence) {
-    int len = sequence.length();
-    int last;
-
-    for (last = len - 1; last >= 0; last--) {
-      if (!matches(sequence.charAt(last))) {
-        break;
-      }
-    }
-
-    return sequence.subSequence(0, last + 1).toString();
-  }
-
-  /**
-   * Returns a string copy of the input character sequence, with each group of
-   * consecutive characters that match this matcher replaced by a single
-   * replacement character. For example: <pre>   {@code
-   *
-   *   CharMatcher.anyOf("eko").collapseFrom("bookkeeper", '-')}</pre>
-   *
-   * ... returns {@code "b-p-r"}.
-   *
-   * <p>The default implementation uses {@link #indexIn(CharSequence)} to find
-   * the first matching character, then iterates the remainder of the sequence
-   * calling {@link #matches(char)} for each character.
-   *
-   * @param sequence the character sequence to replace matching groups of
-   *     characters in
-   * @param replacement the character to append to the result string in place of
-   *     each group of matching characters in {@code sequence}
-   * @return the new string
-   */
-  public String collapseFrom(CharSequence sequence, char replacement) {
-    int first = indexIn(sequence);
-    if (first == -1) {
-      return sequence.toString();
-    }
-
-    // TODO: this implementation can probably be made faster.
-
-    StringBuilder builder = new StringBuilder(sequence.length())
-        .append(sequence.subSequence(0, first))
-        .append(replacement);
-    boolean in = true;
-    for (int i = first + 1; i < sequence.length(); i++) {
-      char c = sequence.charAt(i);
-      if (apply(c)) {
-        if (!in) {
-          builder.append(replacement);
-          in = true;
-        }
-      } else {
-        builder.append(c);
-        in = false;
-      }
-    }
-    return builder.toString();
-  }
-
-  /**
-   * Collapses groups of matching characters exactly as {@link #collapseFrom}
-   * does, except that groups of matching characters at the start or end of the
-   * sequence are removed without replacement.
-   */
-  public String trimAndCollapseFrom(CharSequence sequence, char replacement) {
-    int first = negate().indexIn(sequence);
-    if (first == -1) {
-      return ""; // everything matches. nothing's left.
-    }
-    StringBuilder builder = new StringBuilder(sequence.length());
-    boolean inMatchingGroup = false;
-    for (int i = first; i < sequence.length(); i++) {
-      char c = sequence.charAt(i);
-      if (apply(c)) {
-        inMatchingGroup = true;
-      } else {
-        if (inMatchingGroup) {
-          builder.append(replacement);
-          inMatchingGroup = false;
-        }
-        builder.append(c);
-      }
-    }
-    return builder.toString();
-  }
-
-  // Predicate interface
-
-  /**
-   * Returns {@code true} if this matcher matches the given character.
-   *
-   * @throws NullPointerException if {@code character} is null
-   */
-  /*@Override*/ public boolean apply(Character character) {
-    return matches(character);
-  }
-}
\ No newline at end of file
diff --git a/src/com/android/mail/lib/base/Escaper.java b/src/com/android/mail/lib/base/Escaper.java
deleted file mode 100644
index 9f6b8f0..0000000
--- a/src/com/android/mail/lib/base/Escaper.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2008 Google Inc.
- *
- * 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.android.mail.lib.base;
-
-/**
- * An object that converts literal text into a format safe for inclusion in a particular context
- * (such as an XML document). Typically (but not always), the inverse process of "unescaping" the
- * text is performed automatically by the relevant parser.
- *
- * <p>For example, an XML escaper would convert the literal string {@code "Foo<Bar>"} into {@code
- * "Foo&lt;Bar&gt;"} to prevent {@code "<Bar>"} from being confused with an XML tag. When the
- * resulting XML document is parsed, the parser API will return this text as the original literal
- * string {@code "Foo<Bar>"}.
- *
- * <p>An {@code Escaper} instance is required to be stateless, and safe when used concurrently by
- * multiple threads.
- *
- * <p>The two primary implementations of this interface are {@link CharEscaper} and {@link
- * UnicodeEscaper}. They are heavily optimized for performance and greatly simplify the task of
- * implementing new escapers. It is strongly recommended that when implementing a new escaper you
- * extend one of these classes. If you find that you are unable to achieve the desired behavior
- * using either of these classes, please contact the Java libraries team for advice.
- *
- * <p>Several popular escapers are defined as constants in the class {@link CharEscapers}. To create
- * your own escapers, use {@link CharEscaperBuilder}, or extend {@link CharEscaper} or {@code
- * UnicodeEscaper}.
- *
- * @author dbeaumont@google.com (David Beaumont)
- */
-public abstract class Escaper {
-  /**
-   * Returns the escaped form of a given literal string.
-   *
-   * <p>Note that this method may treat input characters differently depending on the specific
-   * escaper implementation.
-   *
-   * <ul>
-   * <li>{@link UnicodeEscaper} handles <a href="http://en.wikipedia.org/wiki/UTF-16">UTF-16</a>
-   *     correctly, including surrogate character pairs. If the input is badly formed the escaper
-   *     should throw {@link IllegalArgumentException}.
-   * <li>{@link CharEscaper} handles Java characters independently and does not verify the input
-   *     for well formed characters. A CharEscaper should not be used in situations where input is
-   *     not guaranteed to be restricted to the Basic Multilingual Plane (BMP).
-   * </ul>
-   *
-   * @param string the literal string to be escaped
-   * @return the escaped form of {@code string}
-   * @throws NullPointerException if {@code string} is null
-   * @throws IllegalArgumentException if {@code string} contains badly formed UTF-16 or cannot be
-   *         escaped for any other reason
-   */
-  public abstract String escape(String string);
-
-  /**
-   * Returns an {@code Appendable} instance which automatically escapes all text appended to it
-   * before passing the resulting text to an underlying {@code Appendable}.
-   *
-   * <p>Note that the Appendable returned by this method may treat input characters differently
-   * depending on the specific escaper implementation.
-   *
-   * <ul>
-   * <li>{@link UnicodeEscaper} handles <a href="http://en.wikipedia.org/wiki/UTF-16">UTF-16</a>
-   *     correctly, including surrogate character pairs. If the input is badly formed the escaper
-   *     should throw {@link IllegalArgumentException}.
-   * <li>{@link CharEscaper} handles Java characters independently and does not verify the input
-   *     for well formed characters. A CharEscaper should not be used in situations where input is
-   *     not guaranteed to be restricted to the Basic Multilingual Plane (BMP).
-   * </ul>
-   *
-   * <p>In all implementations the escaped Appendable should throw {@code NullPointerException} if
-   * given a {@code null} {@link CharSequence}.
-   *
-   * @param out the underlying {@code Appendable} to append escaped output to
-   * @return an {@code Appendable} which passes text to {@code out} after escaping it
-   */
-  public abstract Appendable escape(Appendable out);
-
-  private final Function<String, String> asFunction =
-      new Function<String, String>() {
-        public String apply(String from) {
-          return escape(from);
-        }
-      };
-
-  /**
-   * Returns a {@link Function} that invokes {@link #escape(String)} on this escaper.
-   */
-  public Function<String, String> asFunction() {
-    return asFunction;
-  }
-}
\ No newline at end of file
diff --git a/src/com/android/mail/lib/base/Function.java b/src/com/android/mail/lib/base/Function.java
deleted file mode 100644
index 6df8289..0000000
--- a/src/com/android/mail/lib/base/Function.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2007 Google Inc.
- *
- * 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.android.mail.lib.base;
-
-/**
- * A transformation from one object to another. For example, a
- * {@code StringToIntegerFunction} may implement
- * <code>Function&lt;String,Integer&gt;</code> and transform integers in
- * {@code String} format to {@code Integer} format.
- *
- * <p>The transformation on the source object does not necessarily result in
- * an object of a different type.  For example, a
- * {@code FarenheitToCelsiusFunction} may implement
- * <code>Function&lt;Float,Float&gt;</code>.
- *
- * <p>Implementations which may cause side effects upon evaluation are strongly
- * encouraged to state this fact clearly in their API documentation.
- *
- * @param <F> the type of the function input
- * @param <T> the type of the function output
- * @author Kevin Bourrillion
- * @author Scott Bonneau
- * @since 2010.01.04 <b>stable</b> (imported from Google Collections Library)
- */
-public interface Function<F, T> {
-
-  /**
-   * Applies the function to an object of type {@code F}, resulting in an object
-   * of type {@code T}.  Note that types {@code F} and {@code T} may or may not
-   * be the same.
-   *
-   * @param from the source object
-   * @return the resulting object
-   */
-  T apply(F from);
-
-  /**
-   * Indicates whether some other object is equal to this {@code Function}.
-   * This method can return {@code true} <i>only</i> if the specified object is
-   * also a {@code Function} and, for every input object {@code o}, it returns
-   * exactly the same value.  Thus, {@code function1.equals(function2)} implies
-   * that either {@code function1.apply(o)} and {@code function2.apply(o)} are
-   * both null, or {@code function1.apply(o).equals(function2.apply(o))}.
-   *
-   * <p>Note that it is always safe <em>not</em> to override
-   * {@link Object#equals}.
-   */
-  boolean equals(Object obj);
-}
diff --git a/src/com/android/mail/lib/base/PercentEscaper.java b/src/com/android/mail/lib/base/PercentEscaper.java
deleted file mode 100644
index e7baa36..0000000
--- a/src/com/android/mail/lib/base/PercentEscaper.java
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright (C) 2008 Google Inc.
- *
- * 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.android.mail.lib.base;
-
-import static com.android.mail.lib.base.Preconditions.checkNotNull;
-
-/**
- * A {@code UnicodeEscaper} that escapes some set of Java characters using
- * the URI percent encoding scheme. The set of safe characters (those which
- * remain unescaped) can be specified on construction.
- *
- * <p>For details on escaping URIs for use in web pages, see section 2.4 of
- * <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
- *
- * <p>In most cases this class should not need to be used directly. If you
- * have no special requirements for escaping your URIs, you should use either
- * {@link CharEscapers#uriEscaper()} or
- * {@link CharEscapers#uriEscaper(boolean)}.
- *
- * <p>When encoding a String, the following rules apply:
- * <ul>
- * <li>The alphanumeric characters "a" through "z", "A" through "Z" and "0"
- * through "9" remain the same.
- * <li>Any additionally specified safe characters remain the same.
- * <li>If {@code plusForSpace} was specified, the space character " " is
- * converted into a plus sign "+".
- * <li>All other characters are converted into one or more bytes using UTF-8
- *     encoding and each byte is then represented by the 3-character string
- *     "%XY", where "XY" is the two-digit, uppercase, hexadecimal representation
- *     of the byte value.
- * </ul>
- *
- * <p>RFC 2396 specifies the set of unreserved characters as "-", "_", ".", "!",
- * "~", "*", "'", "(" and ")". It goes on to state:
- *
- * <p><i>Unreserved characters can be escaped without changing the semantics
- * of the URI, but this should not be done unless the URI is being used
- * in a context that does not allow the unescaped character to appear.</i>
- *
- * <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
- * <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>
- *
- * @author dbeaumont@google.com (David Beaumont)
- */
-public class PercentEscaper extends UnicodeEscaper {
-  /**
-   * A string of safe characters that mimics the behavior of
-   * {@link java.net.URLEncoder}.
-   *
-   * TODO(dbeaumont): Fix escapers to be compliant with RFC 3986
-   */
-  public static final String SAFECHARS_URLENCODER = "-_.*";
-
-  /**
-   * A string of characters that do not need to be encoded when used in URI
-   * path segments, as specified in RFC 3986. Note that some of these
-   * characters do need to be escaped when used in other parts of the URI.
-   */
-  public static final String SAFEPATHCHARS_URLENCODER = "-_.!~*'()@:$&,;=";
-
-  /**
-   * A string of characters that do not need to be encoded when used in URI
-   * query strings, as specified in RFC 3986. Note that some of these
-   * characters do need to be escaped when used in other parts of the URI.
-   */
-  public static final String SAFEQUERYSTRINGCHARS_URLENCODER
-      = "-_.!~*'()@:$,;/?:";
-
-  // In some uri escapers spaces are escaped to '+'
-  private static final char[] URI_ESCAPED_SPACE = { '+' };
-
-  // TODO(dbeaumont): Remove this once UriEscaper uses lower case
-  private static final char[] UPPER_HEX_DIGITS =
-      "0123456789ABCDEF".toCharArray();
-
-  /**
-   * If true we should convert space to the {@code +} character.
-   */
-  private final boolean plusForSpace;
-
-  /**
-   * An array of flags where for any {@code char c} if {@code safeOctets[c]} is
-   * true then {@code c} should remain unmodified in the output. If
-   * {@code c > safeOctets.length} then it should be escaped.
-   */
-  private final boolean[] safeOctets;
-
-  /**
-   * Constructs a URI escaper with the specified safe characters and optional
-   * handling of the space character.
-   *
-   * @param safeChars a non null string specifying additional safe characters
-   *        for this escaper (the ranges 0..9, a..z and A..Z are always safe and
-   *        should not be specified here)
-   * @param plusForSpace true if ASCII space should be escaped to {@code +}
-   *        rather than {@code %20}
-   * @throws IllegalArgumentException if any of the parameters were invalid
-   */
-  public PercentEscaper(String safeChars, boolean plusForSpace) {
-    checkNotNull(safeChars);  // eager for GWT.
-
-    // Avoid any misunderstandings about the behavior of this escaper
-    if (safeChars.matches(".*[0-9A-Za-z].*")) {
-      throw new IllegalArgumentException(
-          "Alphanumeric characters are always 'safe' and should not be " +
-          "explicitly specified");
-    }
-    // Avoid ambiguous parameters. Safe characters are never modified so if
-    // space is a safe character then setting plusForSpace is meaningless.
-    if (plusForSpace && safeChars.contains(" ")) {
-      throw new IllegalArgumentException(
-          "plusForSpace cannot be specified when space is a 'safe' character");
-    }
-    if (safeChars.contains("%")) {
-      throw new IllegalArgumentException(
-          "The '%' character cannot be specified as 'safe'");
-    }
-    this.plusForSpace = plusForSpace;
-    this.safeOctets = createSafeOctets(safeChars);
-  }
-
-  /**
-   * Creates a boolean[] with entries corresponding to the character values
-   * for 0-9, A-Z, a-z and those specified in safeChars set to true. The array
-   * is as small as is required to hold the given character information.
-   */
-  private static boolean[] createSafeOctets(String safeChars) {
-    int maxChar = 'z';
-    char[] safeCharArray = safeChars.toCharArray();
-    for (char c : safeCharArray) {
-      maxChar = Math.max(c, maxChar);
-    }
-    boolean[] octets = new boolean[maxChar + 1];
-    for (int c = '0'; c <= '9'; c++) {
-      octets[c] = true;
-    }
-    for (int c = 'A'; c <= 'Z'; c++) {
-      octets[c] = true;
-    }
-    for (int c = 'a'; c <= 'z'; c++) {
-      octets[c] = true;
-    }
-    for (char c : safeCharArray) {
-      octets[c] = true;
-    }
-    return octets;
-  }
-
-  /*
-   * Overridden for performance. For unescaped strings this improved the
-   * performance of the uri escaper from ~760ns to ~400ns as measured by
-   * {@link CharEscapersBenchmark}.
-   */
-  @Override
-  protected int nextEscapeIndex(CharSequence csq, int index, int end) {
-    for (; index < end; index++) {
-      char c = csq.charAt(index);
-      if (c >= safeOctets.length || !safeOctets[c]) {
-        break;
-      }
-    }
-    return index;
-  }
-
-  /*
-   * Overridden for performance. For unescaped strings this improved the
-   * performance of the uri escaper from ~400ns to ~170ns as measured by
-   * {@link CharEscapersBenchmark}.
-   */
-  @Override
-  public String escape(String s) {
-    checkNotNull(s);
-    int slen = s.length();
-    for (int index = 0; index < slen; index++) {
-      char c = s.charAt(index);
-      if (c >= safeOctets.length || !safeOctets[c]) {
-        return escapeSlow(s, index);
-      }
-    }
-    return s;
-  }
-
-  /**
-   * Escapes the given Unicode code point in UTF-8.
-   */
-  @Override
-  protected char[] escape(int cp) {
-    // We should never get negative values here but if we do it will throw an
-    // IndexOutOfBoundsException, so at least it will get spotted.
-    if (cp < safeOctets.length && safeOctets[cp]) {
-      return null;
-    } else if (cp == ' ' && plusForSpace) {
-      return URI_ESCAPED_SPACE;
-    } else if (cp <= 0x7F) {
-      // Single byte UTF-8 characters
-      // Start with "%--" and fill in the blanks
-      char[] dest = new char[3];
-      dest[0] = '%';
-      dest[2] = UPPER_HEX_DIGITS[cp & 0xF];
-      dest[1] = UPPER_HEX_DIGITS[cp >>> 4];
-      return dest;
-    } else if (cp <= 0x7ff) {
-      // Two byte UTF-8 characters [cp >= 0x80 && cp <= 0x7ff]
-      // Start with "%--%--" and fill in the blanks
-      char[] dest = new char[6];
-      dest[0] = '%';
-      dest[3] = '%';
-      dest[5] = UPPER_HEX_DIGITS[cp & 0xF];
-      cp >>>= 4;
-      dest[4] = UPPER_HEX_DIGITS[0x8 | (cp & 0x3)];
-      cp >>>= 2;
-      dest[2] = UPPER_HEX_DIGITS[cp & 0xF];
-      cp >>>= 4;
-      dest[1] = UPPER_HEX_DIGITS[0xC | cp];
-      return dest;
-    } else if (cp <= 0xffff) {
-      // Three byte UTF-8 characters [cp >= 0x800 && cp <= 0xffff]
-      // Start with "%E-%--%--" and fill in the blanks
-      char[] dest = new char[9];
-      dest[0] = '%';
-      dest[1] = 'E';
-      dest[3] = '%';
-      dest[6] = '%';
-      dest[8] = UPPER_HEX_DIGITS[cp & 0xF];
-      cp >>>= 4;
-      dest[7] = UPPER_HEX_DIGITS[0x8 | (cp & 0x3)];
-      cp >>>= 2;
-      dest[5] = UPPER_HEX_DIGITS[cp & 0xF];
-      cp >>>= 4;
-      dest[4] = UPPER_HEX_DIGITS[0x8 | (cp & 0x3)];
-      cp >>>= 2;
-      dest[2] = UPPER_HEX_DIGITS[cp];
-      return dest;
-    } else if (cp <= 0x10ffff) {
-      char[] dest = new char[12];
-      // Four byte UTF-8 characters [cp >= 0xffff && cp <= 0x10ffff]
-      // Start with "%F-%--%--%--" and fill in the blanks
-      dest[0] = '%';
-      dest[1] = 'F';
-      dest[3] = '%';
-      dest[6] = '%';
-      dest[9] = '%';
-      dest[11] = UPPER_HEX_DIGITS[cp & 0xF];
-      cp >>>= 4;
-      dest[10] = UPPER_HEX_DIGITS[0x8 | (cp & 0x3)];
-      cp >>>= 2;
-      dest[8] = UPPER_HEX_DIGITS[cp & 0xF];
-      cp >>>= 4;
-      dest[7] = UPPER_HEX_DIGITS[0x8 | (cp & 0x3)];
-      cp >>>= 2;
-      dest[5] = UPPER_HEX_DIGITS[cp & 0xF];
-      cp >>>= 4;
-      dest[4] = UPPER_HEX_DIGITS[0x8 | (cp & 0x3)];
-      cp >>>= 2;
-      dest[2] = UPPER_HEX_DIGITS[cp & 0x7];
-      return dest;
-    } else {
-      // If this ever happens it is due to bug in UnicodeEscaper, not bad input.
-      throw new IllegalArgumentException(
-          "Invalid unicode character value " + cp);
-    }
-  }
-}
\ No newline at end of file
diff --git a/src/com/android/mail/lib/base/Platform.java b/src/com/android/mail/lib/base/Platform.java
deleted file mode 100644
index 78e29f3..0000000
--- a/src/com/android/mail/lib/base/Platform.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc.
- *
- * 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.android.mail.lib.base;
-
-
-/**
- * Methods factored out so that they can be emulated differently in GWT.
- *
- * @author Jesse Wilson
- */
-final class Platform {
-  private Platform() {}
-
-  /**
-   * Calls {@link Class#isInstance(Object)}.
-   *
-   * <p>This method is not supported in GWT yet.
-   */
-  static boolean isInstance(Class<?> clazz, Object obj) {
-    return clazz.isInstance(obj);
-  }
-
-  /** Returns a thread-local 1024-char array. */
-  static char[] charBufferFromThreadLocal() {
-    return DEST_TL.get();
-  }
-
-  /**
-   * A thread-local destination buffer to keep us from creating new buffers.
-   * The starting size is 1024 characters.  If we grow past this we don't
-   * put it back in the threadlocal, we just keep going and grow as needed.
-   */
-  private static final ThreadLocal<char[]> DEST_TL = new ThreadLocal<char[]>() {
-    @Override
-    protected char[] initialValue() {
-      return new char[1024];
-    }
-  };
-
-  static CharMatcher precomputeCharMatcher(CharMatcher matcher) {
-    return matcher.precomputedInternal();
-  }
-}
diff --git a/src/com/android/mail/lib/base/Preconditions.java b/src/com/android/mail/lib/base/Preconditions.java
deleted file mode 100644
index ebf661a..0000000
--- a/src/com/android/mail/lib/base/Preconditions.java
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * Copyright (C) 2007 Google Inc.
- *
- * 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.android.mail.lib.base;
-
-import java.util.NoSuchElementException;
-
-/**
- * Simple static methods to be called at the start of your own methods to verify
- * correct arguments and state. This allows constructs such as
- * <pre>
- *     if (count <= 0) {
- *       throw new IllegalArgumentException("must be positive: " + count);
- *     }</pre>
- *
- * to be replaced with the more compact
- * <pre>
- *     checkArgument(count > 0, "must be positive: %s", count);</pre>
- *
- * Note that the sense of the expression is inverted; with {@code Preconditions}
- * you declare what you expect to be <i>true</i>, just as you do with an
- * <a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/assert.html">
- * {@code assert}</a> or a JUnit {@code assertTrue} call.
- *
- * <p><b>Warning:</b> only the {@code "%s"} specifier is recognized as a
- * placeholder in these messages, not the full range of {@link
- * String#format(String, Object[])} specifiers.
- *
- * <p>Take care not to confuse precondition checking with other similar types
- * of checks! Precondition exceptions -- including those provided here, but also
- * {@link IndexOutOfBoundsException}, {@link NoSuchElementException}, {@link
- * UnsupportedOperationException} and others -- are used to signal that the
- * <i>calling method</i> has made an error. This tells the caller that it should
- * not have invoked the method when it did, with the arguments it did, or
- * perhaps ever. Postcondition or other invariant failures should not throw
- * these types of exceptions.
- *
- * @author Kevin Bourrillion
- * @since 2010.01.04 <b>stable</b> (imported from Google Collections Library)
- */
-public class Preconditions {
-  private Preconditions() {}
-
-  /**
-   * Ensures the truth of an expression involving one or more parameters to the
-   * calling method.
-   *
-   * @param expression a boolean expression
-   * @throws IllegalArgumentException if {@code expression} is false
-   */
-  public static void checkArgument(boolean expression) {
-    if (!expression) {
-      throw new IllegalArgumentException();
-    }
-  }
-
-  /**
-   * Ensures the truth of an expression involving one or more parameters to the
-   * calling method.
-   *
-   * @param expression a boolean expression
-   * @param errorMessage the exception message to use if the check fails; will
-   *     be converted to a string using {@link String#valueOf(Object)}
-   * @throws IllegalArgumentException if {@code expression} is false
-   */
-  public static void checkArgument(boolean expression, Object errorMessage) {
-    if (!expression) {
-      throw new IllegalArgumentException(String.valueOf(errorMessage));
-    }
-  }
-
-  /**
-   * Ensures the truth of an expression involving one or more parameters to the
-   * calling method.
-   *
-   * @param expression a boolean expression
-   * @param errorMessageTemplate a template for the exception message should the
-   *     check fail. The message is formed by replacing each {@code %s}
-   *     placeholder in the template with an argument. These are matched by
-   *     position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
-   *     Unmatched arguments will be appended to the formatted message in square
-   *     braces. Unmatched placeholders will be left as-is.
-   * @param errorMessageArgs the arguments to be substituted into the message
-   *     template. Arguments are converted to strings using
-   *     {@link String#valueOf(Object)}.
-   * @throws IllegalArgumentException if {@code expression} is false
-   * @throws NullPointerException if the check fails and either {@code
-   *     errorMessageTemplate} or {@code errorMessageArgs} is null (don't let
-   *     this happen)
-   */
-  public static void checkArgument(boolean expression,
-      String errorMessageTemplate, Object... errorMessageArgs) {
-    if (!expression) {
-      throw new IllegalArgumentException(
-          format(errorMessageTemplate, errorMessageArgs));
-    }
-  }
-
-  /**
-   * Ensures the truth of an expression involving the state of the calling
-   * instance, but not involving any parameters to the calling method.
-   *
-   * @param expression a boolean expression
-   * @throws IllegalStateException if {@code expression} is false
-   */
-  public static void checkState(boolean expression) {
-    if (!expression) {
-      throw new IllegalStateException();
-    }
-  }
-
-  /**
-   * Ensures the truth of an expression involving the state of the calling
-   * instance, but not involving any parameters to the calling method.
-   *
-   * @param expression a boolean expression
-   * @param errorMessage the exception message to use if the check fails; will
-   *     be converted to a string using {@link String#valueOf(Object)}
-   * @throws IllegalStateException if {@code expression} is false
-   */
-  public static void checkState(boolean expression, Object errorMessage) {
-    if (!expression) {
-      throw new IllegalStateException(String.valueOf(errorMessage));
-    }
-  }
-
-  /**
-   * Ensures the truth of an expression involving the state of the calling
-   * instance, but not involving any parameters to the calling method.
-   *
-   * @param expression a boolean expression
-   * @param errorMessageTemplate a template for the exception message should the
-   *     check fail. The message is formed by replacing each {@code %s}
-   *     placeholder in the template with an argument. These are matched by
-   *     position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
-   *     Unmatched arguments will be appended to the formatted message in square
-   *     braces. Unmatched placeholders will be left as-is.
-   * @param errorMessageArgs the arguments to be substituted into the message
-   *     template. Arguments are converted to strings using
-   *     {@link String#valueOf(Object)}.
-   * @throws IllegalStateException if {@code expression} is false
-   * @throws NullPointerException if the check fails and either {@code
-   *     errorMessageTemplate} or {@code errorMessageArgs} is null (don't let
-   *     this happen)
-   */
-  public static void checkState(boolean expression,
-      String errorMessageTemplate, Object... errorMessageArgs) {
-    if (!expression) {
-      throw new IllegalStateException(
-          format(errorMessageTemplate, errorMessageArgs));
-    }
-  }
-
-  /**
-   * Ensures that an object reference passed as a parameter to the calling
-   * method is not null.
-   *
-   * @param reference an object reference
-   * @return the non-null reference that was validated
-   * @throws NullPointerException if {@code reference} is null
-   */
-  public static <T> T checkNotNull(T reference) {
-    if (reference == null) {
-      throw new NullPointerException();
-    }
-    return reference;
-  }
-
-  /**
-   * Ensures that an object reference passed as a parameter to the calling
-   * method is not null.
-   *
-   * @param reference an object reference
-   * @param errorMessage the exception message to use if the check fails; will
-   *     be converted to a string using {@link String#valueOf(Object)}
-   * @return the non-null reference that was validated
-   * @throws NullPointerException if {@code reference} is null
-   */
-  public static <T> T checkNotNull(T reference, Object errorMessage) {
-    if (reference == null) {
-      throw new NullPointerException(String.valueOf(errorMessage));
-    }
-    return reference;
-  }
-
-  /**
-   * Ensures that an object reference passed as a parameter to the calling
-   * method is not null.
-   *
-   * @param reference an object reference
-   * @param errorMessageTemplate a template for the exception message should the
-   *     check fail. The message is formed by replacing each {@code %s}
-   *     placeholder in the template with an argument. These are matched by
-   *     position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
-   *     Unmatched arguments will be appended to the formatted message in square
-   *     braces. Unmatched placeholders will be left as-is.
-   * @param errorMessageArgs the arguments to be substituted into the message
-   *     template. Arguments are converted to strings using
-   *     {@link String#valueOf(Object)}.
-   * @return the non-null reference that was validated
-   * @throws NullPointerException if {@code reference} is null
-   */
-  public static <T> T checkNotNull(T reference, String errorMessageTemplate,
-      Object... errorMessageArgs) {
-    if (reference == null) {
-      // If either of these parameters is null, the right thing happens anyway
-      throw new NullPointerException(
-          format(errorMessageTemplate, errorMessageArgs));
-    }
-    return reference;
-  }
-
-  /*
-   * All recent hotspots (as of 2009) *really* like to have the natural code
-   *
-   * if (guardExpression) {
-   *    throw new BadException(messageExpression);
-   * }
-   *
-   * refactored so that messageExpression is moved to a separate
-   * String-returning method.
-   *
-   * if (guardExpression) {
-   *    throw new BadException(badMsg(...));
-   * }
-   *
-   * The alternative natural refactorings into void or Exception-returning
-   * methods are much slower.  This is a big deal - we're talking factors of
-   * 2-8 in microbenchmarks, not just 10-20%.  (This is a hotspot optimizer
-   * bug, which should be fixed, but that's a separate, big project).
-   *
-   * The coding pattern above is heavily used in java.util, e.g. in ArrayList.
-   * There is a RangeCheckMicroBenchmark in the JDK that was used to test this.
-   *
-   * But the methods in this class want to throw different exceptions,
-   * depending on the args, so it appears that this pattern is not directly
-   * applicable.  But we can use the ridiculous, devious trick of throwing an
-   * exception in the middle of the construction of another exception.
-   * Hotspot is fine with that.
-   */
-
-  /**
-   * Ensures that {@code index} specifies a valid <i>element</i> in an array,
-   * list or string of size {@code size}. An element index may range from zero,
-   * inclusive, to {@code size}, exclusive.
-   *
-   * @param index a user-supplied index identifying an element of an array, list
-   *     or string
-   * @param size the size of that array, list or string
-   * @return the value of {@code index}
-   * @throws IndexOutOfBoundsException if {@code index} is negative or is not
-   *     less than {@code size}
-   * @throws IllegalArgumentException if {@code size} is negative
-   */
-  public static int checkElementIndex(int index, int size) {
-    return checkElementIndex(index, size, "index");
-  }
-
-  /**
-   * Ensures that {@code index} specifies a valid <i>element</i> in an array,
-   * list or string of size {@code size}. An element index may range from zero,
-   * inclusive, to {@code size}, exclusive.
-   *
-   * @param index a user-supplied index identifying an element of an array, list
-   *     or string
-   * @param size the size of that array, list or string
-   * @param desc the text to use to describe this index in an error message
-   * @return the value of {@code index}
-   * @throws IndexOutOfBoundsException if {@code index} is negative or is not
-   *     less than {@code size}
-   * @throws IllegalArgumentException if {@code size} is negative
-   */
-  public static int checkElementIndex(int index, int size, String desc) {
-    // Carefully optimized for execution by hotspot (explanatory comment above)
-    if (index < 0 || index >= size) {
-      throw new IndexOutOfBoundsException(badElementIndex(index, size, desc));
-    }
-    return index;
-  }
-
-  private static String badElementIndex(int index, int size, String desc) {
-    if (index < 0) {
-      return format("%s (%s) must not be negative", desc, index);
-    } else if (size < 0) {
-      throw new IllegalArgumentException("negative size: " + size);
-    } else { // index >= size
-      return format("%s (%s) must be less than size (%s)", desc, index, size);
-    }
-  }
-
-  /**
-   * Ensures that {@code index} specifies a valid <i>position</i> in an array,
-   * list or string of size {@code size}. A position index may range from zero
-   * to {@code size}, inclusive.
-   *
-   * @param index a user-supplied index identifying a position in an array, list
-   *     or string
-   * @param size the size of that array, list or string
-   * @return the value of {@code index}
-   * @throws IndexOutOfBoundsException if {@code index} is negative or is
-   *     greater than {@code size}
-   * @throws IllegalArgumentException if {@code size} is negative
-   */
-  public static int checkPositionIndex(int index, int size) {
-    return checkPositionIndex(index, size, "index");
-  }
-
-  /**
-   * Ensures that {@code index} specifies a valid <i>position</i> in an array,
-   * list or string of size {@code size}. A position index may range from zero
-   * to {@code size}, inclusive.
-   *
-   * @param index a user-supplied index identifying a position in an array, list
-   *     or string
-   * @param size the size of that array, list or string
-   * @param desc the text to use to describe this index in an error message
-   * @return the value of {@code index}
-   * @throws IndexOutOfBoundsException if {@code index} is negative or is
-   *     greater than {@code size}
-   * @throws IllegalArgumentException if {@code size} is negative
-   */
-  public static int checkPositionIndex(int index, int size, String desc) {
-    // Carefully optimized for execution by hotspot (explanatory comment above)
-    if (index < 0 || index > size) {
-      throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc));
-    }
-    return index;
-  }
-
-  private static String badPositionIndex(int index, int size, String desc) {
-    if (index < 0) {
-      return format("%s (%s) must not be negative", desc, index);
-    } else if (size < 0) {
-      throw new IllegalArgumentException("negative size: " + size);
-    } else { // index > size
-      return format("%s (%s) must not be greater than size (%s)",
-                    desc, index, size);
-    }
-  }
-
-  /**
-   * Ensures that {@code start} and {@code end} specify a valid <i>positions</i>
-   * in an array, list or string of size {@code size}, and are in order. A
-   * position index may range from zero to {@code size}, inclusive.
-   *
-   * @param start a user-supplied index identifying a starting position in an
-   *     array, list or string
-   * @param end a user-supplied index identifying a ending position in an array,
-   *     list or string
-   * @param size the size of that array, list or string
-   * @throws IndexOutOfBoundsException if either index is negative or is
-   *     greater than {@code size}, or if {@code end} is less than {@code start}
-   * @throws IllegalArgumentException if {@code size} is negative
-   */
-  public static void checkPositionIndexes(int start, int end, int size) {
-    // Carefully optimized for execution by hotspot (explanatory comment above)
-    if (start < 0 || end < start || end > size) {
-      throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size));
-    }
-  }
-
-  private static String badPositionIndexes(int start, int end, int size) {
-    if (start < 0 || start > size) {
-      return badPositionIndex(start, size, "start index");
-    }
-    if (end < 0 || end > size) {
-      return badPositionIndex(end, size, "end index");
-    }
-    // end < start
-    return format("end index (%s) must not be less than start index (%s)",
-                  end, start);
-  }
-
-  /**
-   * Substitutes each {@code %s} in {@code template} with an argument. These
-   * are matched by position - the first {@code %s} gets {@code args[0]}, etc.
-   * If there are more arguments than placeholders, the unmatched arguments will
-   * be appended to the end of the formatted message in square braces.
-   *
-   * @param template a non-null string containing 0 or more {@code %s}
-   *     placeholders.
-   * @param args the arguments to be substituted into the message
-   *     template. Arguments are converted to strings using
-   *     {@link String#valueOf(Object)}. Arguments can be null.
-   */
-  static String format(String template, Object... args) {
-    // start substituting the arguments into the '%s' placeholders
-    StringBuilder builder = new StringBuilder(
-        template.length() + 16 * args.length);
-    int templateStart = 0;
-    int i = 0;
-    while (i < args.length) {
-      int placeholderStart = template.indexOf("%s", templateStart);
-      if (placeholderStart == -1) {
-        break;
-      }
-      builder.append(template.substring(templateStart, placeholderStart));
-      builder.append(args[i++]);
-      templateStart = placeholderStart + 2;
-    }
-    builder.append(template.substring(templateStart));
-
-    // if we run out of placeholders, append the extra args in square braces
-    if (i < args.length) {
-      builder.append(" [");
-      builder.append(args[i++]);
-      while (i < args.length) {
-        builder.append(", ");
-        builder.append(args[i++]);
-      }
-      builder.append("]");
-    }
-
-    return builder.toString();
-  }
-}
diff --git a/src/com/android/mail/lib/base/Predicate.java b/src/com/android/mail/lib/base/Predicate.java
deleted file mode 100644
index 009f028..0000000
--- a/src/com/android/mail/lib/base/Predicate.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2007 Google Inc.
- *
- * 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.android.mail.lib.base;
-
-
-/**
- * Determines a true or false value for a given input. For example, a
- * {@code RegexPredicate} might implement {@code Predicate<String>}, and return
- * {@code true} for any string that matches its given regular expression.
- *
- * <p>Implementations which may cause side effects upon evaluation are strongly
- * encouraged to state this fact clearly in their API documentation.
- *
- * @author Kevin Bourrillion
- * @since 2010.01.04 <b>stable</b> (imported from Google Collections Library)
- */
-public interface Predicate<T> {
-
-  /*
-   * This interface does not extend Function<T, Boolean> because doing so would
-   * let predicates return null.
-   */
-
-  /**
-   * Applies this predicate to the given object.
-   *
-   * @param input the input that the predicate should act on
-   * @return the value of this predicate when applied to the input {@code t}
-   */
-  boolean apply(T input);
-
-  /**
-   * Indicates whether some other object is equal to this {@code Predicate}.
-   * This method can return {@code true} <i>only</i> if the specified object is
-   * also a {@code Predicate} and, for every input object {@code input}, it
-   * returns exactly the same value. Thus, {@code predicate1.equals(predicate2)}
-   * implies that either {@code predicate1.apply(input)} and
-   * {@code predicate2.apply(input)} are both {@code true} or both
-   * {@code false}.
-   *
-   * <p>Note that it is always safe <i>not</i> to override
-   * {@link Object#equals}.
-   */
-  boolean equals(Object obj);
-}
diff --git a/src/com/android/mail/lib/base/Splitter.java b/src/com/android/mail/lib/base/Splitter.java
deleted file mode 100644
index 205cd2c..0000000
--- a/src/com/android/mail/lib/base/Splitter.java
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc.
- *
- * 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.android.mail.lib.base;
-
-import static com.android.mail.lib.base.Preconditions.checkArgument;
-import static com.android.mail.lib.base.Preconditions.checkNotNull;
-import static com.android.mail.lib.base.Preconditions.checkState;
-
-import com.google.common.base.Joiner;
-
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import java.util.StringTokenizer;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
-
-/**
- * An object that divides strings (or other instances of {@code CharSequence})
- * into substrings, by recognizing a <i>separator</i> (a.k.a. "delimiter")
- * which can be expressed as a single character, literal string, regular
- * expression, {@code CharMatcher}, or by using a fixed substring length. This
- * class provides the complementary functionality to {@link Joiner}.
- *
- * <p>Here is the most basic example of {@code Splitter} usage: <pre>   {@code
- *
- *   Splitter.on(',').split("foo,bar")}</pre>
- *
- * This invocation returns an {@code Iterable<String>} containing {@code "foo"}
- * and {@code "bar"}, in that order.
- *
- * <p>By default {@code Splitter}'s behavior is very simplistic: <pre>   {@code
- *
- *   Splitter.on(',').split("foo,,bar,  quux")}</pre>
- *
- * This returns an iterable containing {@code ["foo", "", "bar", "  quux"]}.
- * Notice that the splitter does not assume that you want empty strings removed,
- * or that you wish to trim whitespace. If you want features like these, simply
- * ask for them: <pre> {@code
- *
- *   private static final Splitter MY_SPLITTER = Splitter.on(',')
- *       .trimResults()
- *       .omitEmptyStrings();}</pre>
- *
- * Now {@code MY_SPLITTER.split("foo, ,bar,  quux,")} returns an iterable
- * containing just {@code ["foo", "bar", "quux"]}. Note that the order in which
- * the configuration methods are called is never significant; for instance,
- * trimming is always applied first before checking for an empty result,
- * regardless of the order in which the {@link #trimResults()} and
- * {@link #omitEmptyStrings()} methods were invoked.
- *
- * <p><b>Warning: splitter instances are always immutable</b>; a configuration
- * method such as {@code omitEmptyStrings} has no effect on the instance it
- * is invoked on! You must store and use the new splitter instance returned by
- * the method. This makes splitters thread-safe, and safe to store as {@code
- * static final} constants (as illustrated above). <pre>   {@code
- *
- *   // Bad! Do not do this!
- *   Splitter splitter = Splitter.on('/');
- *   splitter.trimResults(); // does nothing!
- *   return splitter.split("wrong / wrong / wrong");}</pre>
- *
- * The separator recognized by the splitter does not have to be a single
- * literal character as in the examples above. See the methods {@link
- * #on(String)}, {@link #on(Pattern)} and {@link #on(CharMatcher)} for examples
- * of other ways to specify separators.
- *
- * <p><b>Note:</b> this class does not mimic any of the quirky behaviors of
- * similar JDK methods; for instance, it does not silently discard trailing
- * separators, as does {@link String#split(String)}, nor does it have a default
- * behavior of using five particular whitespace characters as separators, like
- * {@link StringTokenizer}.
- *
- * @author Julien Silland
- * @author Jesse Wilson
- * @author Kevin Bourrillion
- * @since 2009.09.15 <b>tentative</b>
- */
-public final class Splitter {
-  private final CharMatcher trimmer;
-  private final boolean omitEmptyStrings;
-  private final Strategy strategy;
-
-  private Splitter(Strategy strategy) {
-    this(strategy, false, CharMatcher.NONE);
-  }
-
-  private Splitter(Strategy strategy, boolean omitEmptyStrings,
-      CharMatcher trimmer) {
-    this.strategy = strategy;
-    this.omitEmptyStrings = omitEmptyStrings;
-    this.trimmer = trimmer;
-  }
-
-  /**
-   * Returns a splitter that uses the given single-character separator. For
-   * example, {@code Splitter.on(',').split("foo,,bar")} returns an iterable
-   * containing {@code ["foo", "", "bar"]}.
-   *
-   * @param separator the character to recognize as a separator
-   * @return a splitter, with default settings, that recognizes that separator
-   */
-  public static Splitter on(char separator) {
-    return on(CharMatcher.is(separator));
-  }
-
-  /**
-   * Returns a splitter that considers any single character matched by the
-   * given {@code CharMatcher} to be a separator. For example, {@code
-   * Splitter.on(CharMatcher.anyOf(";,")).split("foo,;bar,quux")} returns an
-   * iterable containing {@code ["foo", "", "bar", "quux"]}.
-   *
-   * @param separatorMatcher a {@link CharMatcher} that determines whether a
-   *     character is a separator
-   * @return a splitter, with default settings, that uses this matcher
-   */
-  public static Splitter on(final CharMatcher separatorMatcher) {
-    checkNotNull(separatorMatcher);
-
-    return new Splitter(new Strategy() {
-      /*@Override*/ public SplittingIterator iterator(
-          Splitter splitter, final CharSequence toSplit) {
-        return new SplittingIterator(splitter, toSplit) {
-          @Override int separatorStart(int start) {
-            return separatorMatcher.indexIn(toSplit, start);
-          }
-
-          @Override int separatorEnd(int separatorPosition) {
-            return separatorPosition + 1;
-          }
-        };
-      }
-    });
-  }
-
-  /**
-   * Returns a splitter that uses the given fixed string as a separator. For
-   * example, {@code Splitter.on(", ").split("foo, bar, baz,qux")} returns an
-   * iterable containing {@code ["foo", "bar", "baz,qux"]}.
-   *
-   * @param separator the literal, nonempty string to recognize as a separator
-   * @return a splitter, with default settings, that recognizes that separator
-   */
-  public static Splitter on(final String separator) {
-    checkArgument(separator.length() != 0,
-        "The separator may not be the empty string.");
-
-    return new Splitter(new Strategy() {
-      /*@Override*/ public SplittingIterator iterator(
-          Splitter splitter, CharSequence toSplit) {
-        return new SplittingIterator(splitter, toSplit) {
-          @Override public int separatorStart(int start) {
-            int delimeterLength = separator.length();
-
-            positions:
-            for (int p = start, last = toSplit.length() - delimeterLength;
-                p <= last; p++) {
-              for (int i = 0; i < delimeterLength; i++) {
-                if (toSplit.charAt(i + p) != separator.charAt(i)) {
-                  continue positions;
-                }
-              }
-              return p;
-            }
-            return -1;
-          }
-
-          @Override public int separatorEnd(int separatorPosition) {
-            return separatorPosition + separator.length();
-          }
-        };
-      }
-    });
-  }
-
-  /**
-   * Returns a splitter that considers any subsequence matching {@code
-   * pattern} to be a separator. For example, {@code
-   * Splitter.on(Pattern.compile("\r?\n")).split(entireFile)} splits a string
-   * into lines whether it uses DOS-style or UNIX-style line terminators.
-   *
-   * @param separatorPattern the pattern that determines whether a subsequence
-   *     is a separator. This pattern may not match the empty string.
-   * @return a splitter, with default settings, that uses this pattern
-   * @throws IllegalArgumentException if {@code separatorPattern} matches the
-   *     empty string
-   */
-  public static Splitter on(final Pattern separatorPattern) {
-    checkNotNull(separatorPattern);
-    checkArgument(!separatorPattern.matcher("").matches(),
-        "The pattern may not match the empty string: %s", separatorPattern);
-
-    return new Splitter(new Strategy() {
-      /*@Override*/ public SplittingIterator iterator(
-          final Splitter splitter, CharSequence toSplit) {
-        final Matcher matcher = separatorPattern.matcher(toSplit);
-        return new SplittingIterator(splitter, toSplit) {
-          @Override public int separatorStart(int start) {
-            return matcher.find(start) ? matcher.start() : -1;
-          }
-
-          @Override public int separatorEnd(int separatorPosition) {
-            return matcher.end();
-          }
-        };
-      }
-    });
-  }
-
-  /**
-   * Returns a splitter that considers any subsequence matching a given
-   * pattern (regular expression) to be a separator. For example, {@code
-   * Splitter.onPattern("\r?\n").split(entireFile)} splits a string into lines
-   * whether it uses DOS-style or UNIX-style line terminators. This is
-   * equivalent to {@code Splitter.on(Pattern.compile(pattern))}.
-   *
-   * @param separatorPattern the pattern that determines whether a subsequence
-   *     is a separator. This pattern may not match the empty string.
-   * @return a splitter, with default settings, that uses this pattern
-   * @throws PatternSyntaxException if {@code separatorPattern} is a malformed
-   *     expression
-   * @throws IllegalArgumentException if {@code separatorPattern} matches the
-   *     empty string
-   */
-  public static Splitter onPattern(String separatorPattern) {
-    return on(Pattern.compile(separatorPattern));
-  }
-
-  /**
-   * Returns a splitter that divides strings into pieces of the given length.
-   * For example, {@code Splitter.atEach(2).split("abcde")} returns an
-   * iterable containing {@code ["ab", "cd", "e"]}. The last piece can be
-   * smaller than {@code length} but will never be empty.
-   *
-   * @param length the desired length of pieces after splitting
-   * @return a splitter, with default settings, that can split into fixed sized
-   *     pieces
-   */
-  public static Splitter fixedLength(final int length) {
-    checkArgument(length > 0, "The length may not be less than 1");
-
-    return new Splitter(new Strategy() {
-      /*@Override*/ public SplittingIterator iterator(
-          final Splitter splitter, CharSequence toSplit) {
-        return new SplittingIterator(splitter, toSplit) {
-          @Override public int separatorStart(int start) {
-            int nextChunkStart = start + length;
-            return (nextChunkStart < toSplit.length() ? nextChunkStart : -1);
-          }
-
-          @Override public int separatorEnd(int separatorPosition) {
-            return separatorPosition;
-          }
-        };
-      }
-    });
-  }
-
-  /**
-   * Returns a splitter that behaves equivalently to {@code this} splitter, but
-   * automatically omits empty strings from the results. For example, {@code
-   * Splitter.on(',').omitEmptyStrings().split(",a,,,b,c,,")} returns an
-   * iterable containing only {@code ["a", "b", "c"]}.
-   *
-   * <p>If either {@code trimResults} option is also specified when creating a
-   * splitter, that splitter always trims results first before checking for
-   * emptiness. So, for example, {@code
-   * Splitter.on(':').omitEmptyStrings().trimResults().split(": : : ")} returns
-   * an empty iterable.
-   *
-   * <p>Note that it is ordinarily not possible for {@link #split(CharSequence)}
-   * to return an empty iterable, but when using this option, it can (if the
-   * input sequence consists of nothing but separators).
-   *
-   * @return a splitter with the desired configuration
-   */
-  public Splitter omitEmptyStrings() {
-    return new Splitter(strategy, true, trimmer);
-  }
-
-  /**
-   * Returns a splitter that behaves equivalently to {@code this} splitter, but
-   * automatically removes leading and trailing {@linkplain
-   * CharMatcher#WHITESPACE whitespace} from each returned substring; equivalent
-   * to {@code trimResults(CharMatcher.WHITESPACE)}. For example, {@code
-   * Splitter.on(',').trimResults().split(" a, b  ,c  ")} returns an iterable
-   * containing {@code ["a", "b", "c"]}.
-   *
-   * @return a splitter with the desired configuration
-   */
-  public Splitter trimResults() {
-    return trimResults(CharMatcher.WHITESPACE);
-  }
-
-  /**
-   * Returns a splitter that behaves equivalently to {@code this} splitter, but
-   * removes all leading or trailing characters matching the given {@code
-   * CharMatcher} from each returned substring. For example, {@code
-   * Splitter.on(',').trimResults(CharMatcher.is('_')).split("_a ,_b_ ,c__")}
-   * returns an iterable containing {@code ["a ", "b_ ", "c"]}.
-   *
-   * @param trimmer a {@link CharMatcher} that determines whether a character
-   *     should be removed from the beginning/end of a subsequence
-   * @return a splitter with the desired configuration
-   */
-  public Splitter trimResults(CharMatcher trimmer) {
-    checkNotNull(trimmer);
-    return new Splitter(strategy, omitEmptyStrings, trimmer);
-  }
-
-  /**
-   * Splits the {@link CharSequence} passed in parameter.
-   *
-   * @param sequence the sequence of characters to split
-   * @return an iteration over the segments split from the parameter.
-   */
-  public Iterable<String> split(final CharSequence sequence) {
-    checkNotNull(sequence);
-
-    return new Iterable<String>() {
-      /*@Override*/ public Iterator<String> iterator() {
-        return strategy.iterator(Splitter.this, sequence);
-      }
-    };
-  }
-
-  private interface Strategy {
-    Iterator<String> iterator(Splitter splitter, CharSequence toSplit);
-  }
-
-  private abstract static class SplittingIterator
-      extends AbstractIterator<String> {
-    final CharSequence toSplit;
-    final CharMatcher trimmer;
-    final boolean omitEmptyStrings;
-
-    /**
-     * Returns the first index in {@code toSplit} at or after {@code start}
-     * that contains the separator.
-     */
-    abstract int separatorStart(int start);
-
-    /**
-     * Returns the first index in {@code toSplit} after {@code
-     * separatorPosition} that does not contain a separator. This method is only
-     * invoked after a call to {@code separatorStart}.
-     */
-    abstract int separatorEnd(int separatorPosition);
-
-    int offset = 0;
-
-    protected SplittingIterator(Splitter splitter, CharSequence toSplit) {
-      this.trimmer = splitter.trimmer;
-      this.omitEmptyStrings = splitter.omitEmptyStrings;
-      this.toSplit = toSplit;
-    }
-
-    @Override protected String computeNext() {
-      while (offset != -1) {
-        int start = offset;
-        int end;
-
-        int separatorPosition = separatorStart(offset);
-        if (separatorPosition == -1) {
-          end = toSplit.length();
-          offset = -1;
-        } else {
-          end = separatorPosition;
-          offset = separatorEnd(separatorPosition);
-        }
-
-        while (start < end && trimmer.matches(toSplit.charAt(start))) {
-          start++;
-        }
-        while (end > start && trimmer.matches(toSplit.charAt(end - 1))) {
-          end--;
-        }
-
-        if (omitEmptyStrings && start == end) {
-          continue;
-        }
-
-        return toSplit.subSequence(start, end).toString();
-      }
-      return endOfData();
-    }
-  }
-
-  /*
-   * Copied from common.collect.AbstractIterator. TODO: un-fork once these
-   * packages have been combined into a single library.
-   */
-  private static abstract class AbstractIterator<T> implements Iterator<T> {
-    State state = State.NOT_READY;
-
-    enum State {
-      READY, NOT_READY, DONE, FAILED,
-    }
-
-    T next;
-
-    protected abstract T computeNext();
-
-    protected final T endOfData() {
-      state = State.DONE;
-      return null;
-    }
-
-    public final boolean hasNext() {
-      checkState(state != State.FAILED);
-      switch (state) {
-        case DONE:
-          return false;
-        case READY:
-          return true;
-        default:
-      }
-      return tryToComputeNext();
-    }
-
-    boolean tryToComputeNext() {
-      state = State.FAILED; // temporary pessimism
-      next = computeNext();
-      if (state != State.DONE) {
-        state = State.READY;
-        return true;
-      }
-      return false;
-    }
-
-    public final T next() {
-      if (!hasNext()) {
-        throw new NoSuchElementException();
-      }
-      state = State.NOT_READY;
-      return next;
-    }
-
-    /*@Override*/ public void remove() {
-      throw new UnsupportedOperationException();
-    }
-  }
-}
diff --git a/src/com/android/mail/lib/base/StringUtil.java b/src/com/android/mail/lib/base/StringUtil.java
deleted file mode 100644
index 5bfca7f..0000000
--- a/src/com/android/mail/lib/base/StringUtil.java
+++ /dev/null
@@ -1,3205 +0,0 @@
-/*
- * Copyright (C) 2000 Google Inc.
- *
- * 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.android.mail.lib.base;
-
-import static com.android.mail.lib.base.Preconditions.checkArgument;
-
-import com.google.common.base.Joiner;
-import com.google.common.base.Joiner.MapJoiner;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.StringTokenizer;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Static utility methods and constants pertaining to {@code String} or {@code
- * CharSequence} instances.
- */
-public final class StringUtil {
-  private StringUtil() {} // COV_NF_LINE
-
-  /**
-   * A completely arbitrary selection of eight whitespace characters. See
-   * <a href="http://go/white+space">this spreadsheet</a> for more details
-   * about whitespace characters.
-   *
-   * @deprecated Rewrite your code to use {@link CharMatcher#WHITESPACE}, or
-   *     consider the precise set of characters you want to match and construct
-   *     the right explicit {@link CharMatcher} or {@link String} for your own
-   *     purposes.
-   */
-  @Deprecated
-  public static final String WHITE_SPACES = " \r\n\t\u3000\u00A0\u2007\u202F";
-
-  /** A string containing the carriage return and linefeed characters. */
-  public static final String LINE_BREAKS = "\r\n";
-
-  /**
-   * Old location of {@link Strings#isNullOrEmpty}; this method will be
-   * deprecated soon.
-   */
-  public static boolean isEmpty(String string) {
-    return Strings.isNullOrEmpty(string);
-  }
-
-  /**
-   * Returns {@code true} if the given string is null, empty, or comprises only
-   * whitespace characters, as defined by {@link CharMatcher#WHITESPACE}.
-   *
-   * <p><b>Warning:</b> there are many competing definitions of "whitespace";
-   * please see <a href="http://go/white+space">this spreadsheet</a> for
-   * details.
-   *
-   * @param string the string reference to check
-   * @return {@code true} if {@code string} is null, empty, or consists of
-   *     whitespace characters only
-   */
-  public static boolean isEmptyOrWhitespace(String string) {
-    return string == null || CharMatcher.WHITESPACE.matchesAllOf(string);
-  }
-
-  /**
-   * Old location of {@link Strings#nullToEmpty}; this method will be
-   * deprecated soon.
-   */
-  public static String makeSafe(String string) {
-    return Strings.nullToEmpty(string);
-  }
-
-  /**
-   * Old location of {@link Strings#emptyToNull}; this method will be
-   * deprecated soon.
-   */
-  public static String toNullIfEmpty(String string) {
-    return Strings.emptyToNull(string);
-  }
-
-  /**
-   * Returns the given string if it is nonempty and contains at least one
-   * non-whitespace character; {@code null} otherwise. See comment in {@link
-   * #isEmptyOrWhitespace} on the definition of whitespace.
-   *
-   * @param string the string to test and possibly return
-   * @return {@code null} if {@code string} is null, empty, or contains only
-   *     whitespace characters; {@code string} itself otherwise
-   */
-  public static String toNullIfEmptyOrWhitespace(
-      String string) {
-    return isEmptyOrWhitespace(string) ? null : string;
-  }
-
-  /**
-   * Old location of {@link Strings#repeat}; this method will be deprecated
-   * soon.
-   */
-  public static String repeat(String string, int count) {
-    return Strings.repeat(string, count);
-  }
-
-  /**
-   * Return the first index in the string of any of the specified characters,
-   * starting at a given index, or {@code -1} if none of the characters is
-   * present.
-   *
-   * @param string the non-null character sequence to look in
-   * @param chars a non-null character sequence containing the set of characters
-   *     to look for. If empty, this method will find no matches and return
-   *     {@code -1}
-   * @param fromIndex the index of the first character to examine in the input
-   *     string. If negative, the entire string will be searched. If greater
-   *     than or equal to the string length, no characters will be searched and
-   *     {@code -1} will be returned.
-   * @return the index of the first match, or {@code -1} if no match was found.
-   *     Guaranteed to be either {@code -1} or a number greater than or equal to
-   *     {@code fromIndex}
-   * @throws NullPointerException if any argument is null
-   */
-  // author: pault
-  public static int indexOfChars(
-      CharSequence string, CharSequence chars, int fromIndex) {
-    if (fromIndex >= string.length()) {
-      return -1;
-    }
-
-    /*
-     * Prepare lookup structures for the characters. TODO(pault): This loop
-     * could be factored into another method to allow caching of the resulting
-     * struct if a use-case of very large character sets exists.
-     */
-    Set<Character> charSet = Collections.emptySet();
-    boolean[] charArray = new boolean[128];
-    for (int i = 0; i < chars.length(); i++) {
-      char c = chars.charAt(i);
-      if (c < 128) {
-        charArray[c] = true;
-      } else {
-        if (charSet.isEmpty()) {
-          charSet = new HashSet<Character>();
-        }
-        charSet.add(c);
-      }
-    }
-
-    // Scan the string for matches
-    for (int i = Math.max(fromIndex, 0); i < string.length(); i++) {
-      char c = string.charAt(i);
-      if (c < 128) {
-        if (charArray[c]) {
-          return i;
-        }
-      } else if (charSet.contains(c)) {
-        return i;
-      }
-    }
-    return -1;
-  }
-
-/*
- * -------------------------------------------------------------------
- * This marks the end of the code that has been written or rewritten
- * in 2008 to the quality standards of the Java core libraries group.
- * Code below this point is still awaiting cleanup (you can help!).
- * See http://wiki/Nonconf/JavaCoreLibrariesStandards.
- * -------------------------------------------------------------------
- */
-
-
-  /**
-   * @param str the string to split.  Must not be null.
-   * @param delims the delimiter characters. Each character in the
-   *        string is individually treated as a delimiter.
-   * @return an array of tokens. Will not return null. Individual tokens
-   *        do not have leading/trailing whitespace removed.
-   * @deprecated see the detailed instructions under
-   *     {@link #split(String, String, boolean)}
-   */
-  @Deprecated
-  public static String[] split(String str, String delims) {
-    return split(str, delims, false);
-  }
-
-  /**
-   * This method is deprecated because it is too inflexible, providing
-   * only a very specific set of behaviors that almost never matches exactly
-   * what you intend. Prefer using a {@link Splitter}, which is more flexible
-   * and consistent in the way it handles trimming and empty tokens.
-   *
-   * <ul>
-   * <li>Create a {@link Splitter} using {@link Splitter#on(CharMatcher)} such
-   *     as {@code Splitter.on(CharMatcher.anyOf(delims))}.
-   * <li><i>If</i> you need whitespace trimmed from the ends of each segment,
-   *     adding {@code .trimResults()} to your splitter definition should work
-   *     in most cases. To match the exact behavior of this method, use
-   *     {@code .trimResults(CharMatcher.inRange('\0', ' '))}.
-   * <li>This method silently ignores empty tokens in the input, but allows
-   *     empty tokens to appear in the output if {@code trimTokens} is
-   *     {@code true}. Adding {@code .omitEmptyStrings()} to your splitter
-   *     definition will filter empty tokens out but will do so <i>after</i>
-   *     having performed trimming. If you absolutely require this method's
-   *     behavior in this respect, Splitter is not able to match it.
-   * <li>If you need the result as an array, use {@link
-   *     com.google.common.collect.Iterables#toArray(Iterable, Class)} on the
-   *     {@code Iterable<String>} returned by {@link Splitter#split}.
-   * </ul>
-   *
-   * @param str the string to split.  Must not be null.
-   * @param delims the delimiter characters. Each character in the string
-   *        is individually treated as a delimiter.
-   * @param trimTokens if true, leading/trailing whitespace is removed
-   *        from the tokens
-   * @return an array of tokens. Will not return null.
-   * @deprecated
-   */
-  @Deprecated
-  public static String[] split(
-      String str, String delims, boolean trimTokens) {
-    StringTokenizer tokenizer = new StringTokenizer(str, delims);
-    int n = tokenizer.countTokens();
-    String[] list = new String[n];
-    for (int i = 0; i < n; i++) {
-      if (trimTokens) {
-        list[i] = tokenizer.nextToken().trim();
-      } else {
-        list[i] = tokenizer.nextToken();
-      }
-    }
-    return list;
-  }
-
-  /**
-   * Trim characters from only the beginning of a string.
-   * This is a convenience method, it simply calls trimStart(s, null).
-   *
-   * @param s String to be trimmed
-   * @return String with whitespace characters removed from the beginning
-   */
-  public static String trimStart(String s) {
-    return trimStart(s, null);
-  }
-
-  /**
-   * Trim characters from only the beginning of a string.
-   * This method will remove all whitespace characters
-   * (defined by Character.isWhitespace(char), in addition to the characters
-   * provided, from the end of the provided string.
-   *
-   * @param s String to be trimmed
-   * @param extraChars Characters in addition to whitespace characters that
-   *                   should be trimmed.  May be null.
-   * @return String with whitespace and characters in extraChars removed
-   *                   from the beginning
-   */
-  public static String trimStart(String s, String extraChars) {
-    int trimCount = 0;
-    while (trimCount < s.length()) {
-      char ch = s.charAt(trimCount);
-      if (Character.isWhitespace(ch)
-        || (extraChars != null && extraChars.indexOf(ch) >= 0)) {
-        trimCount++;
-      } else {
-        break;
-      }
-    }
-
-    if (trimCount == 0) {
-      return s;
-    }
-    return s.substring(trimCount);
-  }
-
-  /**
-   * Trim characters from only the end of a string.
-   * This is a convenience method, it simply calls trimEnd(s, null).
-   *
-   * @param s String to be trimmed
-   * @return String with whitespace characters removed from the end
-   */
-  public static String trimEnd(String s) {
-    return trimEnd(s, null);
-  }
-
-  /**
-   * Trim characters from only the end of a string.
-   * This method will remove all whitespace characters
-   * (defined by Character.isWhitespace(char), in addition to the characters
-   * provided, from the end of the provided string.
-   *
-   * @param s String to be trimmed
-   * @param extraChars Characters in addition to whitespace characters that
-   *                   should be trimmed.  May be null.
-   * @return String with whitespace and characters in extraChars removed
-   *                   from the end
-   */
-  public static String trimEnd(String s, String extraChars) {
-    int trimCount = 0;
-    while (trimCount < s.length()) {
-      char ch = s.charAt(s.length() - trimCount - 1);
-      if (Character.isWhitespace(ch)
-        || (extraChars != null && extraChars.indexOf(ch) >= 0)) {
-        trimCount++;
-      } else {
-        break;
-      }
-    }
-
-    if (trimCount == 0) {
-      return s;
-    }
-    return s.substring(0, s.length() - trimCount);
-  }
-
-  /**
-   * @param str the string to split.  Must not be null.
-   * @param delims the delimiter characters. Each character in the
-   *        string is individually treated as a delimiter.
-   * @return an array of tokens. Will not return null. Leading/trailing
-   *        whitespace is removed from the tokens.
-   * @deprecated see the detailed instructions under
-   *     {@link #split(String, String, boolean)}
-   */
-  @Deprecated
-  public static String[] splitAndTrim(String str, String delims) {
-    return split(str, delims, true);
-  }
-
-  /** Parse comma-separated list of ints and return as array. */
-  public static int[] splitInts(String str) throws IllegalArgumentException {
-    StringTokenizer tokenizer = new StringTokenizer(str, ",");
-    int n = tokenizer.countTokens();
-    int[] list = new int[n];
-    for (int i = 0; i < n; i++) {
-      String token = tokenizer.nextToken();
-      list[i] = Integer.parseInt(token);
-    }
-    return list;
-  }
-
-  /** Parse comma-separated list of longs and return as array. */
-  public static long[] splitLongs(String str) throws IllegalArgumentException {
-    StringTokenizer tokenizer = new StringTokenizer(str, ",");
-    int n = tokenizer.countTokens();
-    long[] list = new long[n];
-    for (int i = 0; i < n; i++) {
-      String token = tokenizer.nextToken();
-      list[i] = Long.parseLong(token);
-    }
-    return list;
-  }
-
-  /** This replaces the occurrences of 'what' in 'str' with 'with'
-   *
-   * @param str the string to process
-   * @param what to replace
-   * @param with replace with this
-   * @return String str where 'what' was replaced with 'with'
-   *
-   * @deprecated Please use {@link String#replace(CharSequence, CharSequence)}.
-   */
-  @Deprecated
-  public static String replace(
-      String str, CharSequence what, CharSequence with) {
-    // Have to check this argument, for compatibility with the old impl.
-    // For the record, String.replace() is capable of handling an empty target
-    // string... but it does something kind of weird in that case.
-    checkArgument(what.length() > 0);
-    return str.replace(what, with);
-  }
-
-  private static final Splitter NEWLINE_SPLITTER =
-      Splitter.on('\n').omitEmptyStrings();
-
-  /**
-   * Reformats the given string to a fixed width by inserting carriage returns
-   * and trimming unnecessary whitespace. See
-   * {@link #fixedWidth(String[], int)} for details. The {@code str} argument
-   * to this method will be split on newline characters ({@code '\n'}) only
-   * (regardless of platform).  An array of resulting non-empty strings is
-   * then passed to {@link #fixedWidth(String[], int)} as the {@code lines}
-   * parameter.
-   *
-   * @param str the string to format
-   * @param width the fixed width (in characters)
-   */
-  public static String fixedWidth(String str, int width) {
-    List<String> lines = new ArrayList<String>();
-
-    for (String line : NEWLINE_SPLITTER.split(str)) {
-      lines.add(line);
-    }
-
-    String[] lineArray = lines.toArray(new String[0]);
-    return fixedWidth(lineArray, width);
-  }
-
-  /**
-   * Reformats the given array of lines to a fixed width by inserting
-   * newlines and trimming unnecessary whitespace.  This uses simple
-   * whitespace-based splitting, not sophisticated internationalized
-   * line breaking.  Newlines within a line are treated like any other
-   * whitespace.  Lines which are already short enough will be passed
-   * through unmodified.
-   *
-   * <p>Only breaking whitespace characters (those which match
-   * {@link CharMatcher#BREAKING_WHITESPACE}) are treated as whitespace by
-   * this method. Non-breaking whitespace characters will be considered as
-   * ordinary characters which are connected to any other adjacent
-   * non-whitespace characters, and will therefore appear in the returned
-   * string in their original context.
-   *
-   * @param lines array of lines to format
-   * @param width the fixed width (in characters)
-   */
-  public static String fixedWidth(String[] lines, int width) {
-    List<String> formattedLines = new ArrayList<String>();
-
-    for (String line : lines) {
-      formattedLines.add(formatLineToFixedWidth(line, width));
-    }
-
-    return Joiner.on('\n').join(formattedLines);
-  }
-
-  private static final Splitter TO_WORDS =
-      Splitter.on(CharMatcher.BREAKING_WHITESPACE).omitEmptyStrings();
-
-  /**
-   * Helper method for {@link #fixedWidth(String[], int)}
-   */
-  private static String formatLineToFixedWidth(String line, int width) {
-    if (line.length() <= width) {
-      return line;
-    }
-
-    StringBuilder builder = new StringBuilder();
-    int col = 0;
-
-    for (String word : TO_WORDS.split(line)) {
-      if (col == 0) {
-        col = word.length();
-      } else {
-        int newCol = col + word.length() + 1;  // +1 for the space
-
-        if (newCol <= width) {
-          builder.append(' ');
-          col = newCol;
-        } else {
-          builder.append('\n');
-          col = word.length();
-        }
-      }
-
-      builder.append(word);
-    }
-
-    return builder.toString();
-  }
-
-  /**
-   * Splits the argument original into a list of substrings.  All the
-   * substrings in the returned list (except possibly the last) will
-   * have length lineLen.
-   *
-   * @param lineLen  the length of the substrings to put in the list
-   * @param original the original string
-   *
-   * @return a list of strings of length lineLen that together make up the
-   *     original string
-   * @deprecated use {@code Splitter.fixedLength(lineLen).split(original))}
-   *     (note that it returns an {@code Iterable}, not a {@code List})
-   */
-  @Deprecated
-  public static List<String> fixedSplit(String original, int lineLen) {
-    List<String> output = new ArrayList<String>();
-    for (String elem : Splitter.fixedLength(lineLen).split(original)) {
-      output.add(elem);
-    }
-    return output;
-  }
-
-  /**
-   * Indents the given String per line.
-   * @param iString the string to indent
-   * @param iIndentDepth the depth of the indentation
-   * @return the indented string
-   */
-  public static String indent(String iString, int iIndentDepth) {
-    StringBuilder spacer = new StringBuilder();
-    spacer.append("\n");
-    for (int i = 0; i < iIndentDepth; i++) {
-      spacer.append("  ");
-    }
-    return iString.replace("\n", spacer.toString());
-  }
-
-  /**
-   * This is a both way strip.
-   *
-   * @param str the string to strip
-   * @param left strip from left
-   * @param right strip from right
-   * @param what character(s) to strip
-   * @return the stripped string
-   * @deprecated ensure the string is not null and use
-   *  <ul>
-   *    <li> {@code CharMatcher.anyOf(what).trimFrom(str)}
-   *        if {@code left == true} and {@code right == true}
-   *    <li> {@code CharMatcher.anyOf(what).trimLeadingFrom(str)}
-   *        if {@code left == true} and {@code right == false}
-   *    <li> {@code CharMatcher.anyOf(what).trimTrailingFrom(str)}
-   *        if {@code left == false} and {@code right == true}
-   *  </ul>
-   */
-  @Deprecated
-  public static String megastrip(String str,
-                                 boolean left, boolean right,
-                                 String what) {
-    if (str == null) {
-      return null;
-    }
-
-    CharMatcher matcher = CharMatcher.anyOf(what);
-    if (left) {
-      if (right) {
-        return matcher.trimFrom(str);
-      }
-      return matcher.trimLeadingFrom(str);
-    }
-    if (right) {
-      return matcher.trimTrailingFrom(str);
-    }
-    return str;
-  }
-
-  /** strip - strips both ways
-   *
-   * @param str what to strip
-   * @return String the striped string
-   * @deprecated ensure the string is not null and use {@code
-   *     CharMatcher.LEGACY_WHITESPACE.trimFrom(str)}; also consider whether you
-   *     really want the legacy whitespace definition, or something more
-   *     standard like {@link CharMatcher#WHITESPACE}.
-   */
-  @SuppressWarnings("deprecation") // this is deprecated itself
-  @Deprecated public static String strip(String str) {
-    return (str == null) ? null : CharMatcher.LEGACY_WHITESPACE.trimFrom(str);
-  }
-
-  /** Strip white spaces from both end, and collapse white spaces
-   * in the middle.
-   *
-   * @param str what to strip
-   * @return String the striped and collapsed string
-   * @deprecated ensure the string is not null and use {@code
-   *     CharMatcher.LEGACY_WHITESPACE.trimAndCollapseFrom(str, ' ')}; also
-   *     consider whether you really want the legacy whitespace definition, or
-   *     something more standard like {@link CharMatcher#WHITESPACE}.
-   */
-  @SuppressWarnings("deprecation") // this is deprecated itself
-  @Deprecated public static String stripAndCollapse(String str) {
-    return (str == null) ? null
-        : CharMatcher.LEGACY_WHITESPACE.trimAndCollapseFrom(str, ' ');
-  }
-
-  /**
-   * Give me a string and a potential prefix, and I return the string
-   * following the prefix if the prefix matches, else null.
-   * Analogous to the c++ functions strprefix and var_strprefix.
-   *
-   * @param str the string to strip
-   * @param prefix the expected prefix
-   * @return the stripped string or <code>null</code> if the string
-   * does not start with the prefix
-   */
-  public static String stripPrefix(String str, String prefix) {
-    return str.startsWith(prefix)
-        ? str.substring(prefix.length())
-        : null;
-  }
-
-  /**
-   * Case insensitive version of stripPrefix. Strings are compared in
-   * the same way as in {@link String#equalsIgnoreCase}.
-   * Analogous to the c++ functions strcaseprefix and var_strcaseprefix.
-   *
-   * @param str the string to strip
-   * @param prefix the expected prefix
-   * @return the stripped string or <code>null</code> if the string
-   * does not start with the prefix
-   */
-  public static String stripPrefixIgnoreCase(String str, String prefix) {
-    return startsWithIgnoreCase(str, prefix)
-        ? str.substring(prefix.length())
-        : null;
-  }
-
-  /**
-   * Give me a string and a potential suffix, and I return the string
-   * before the suffix if the suffix matches, else null.
-   * Analogous to the c++ function strsuffix.
-   *
-   * @param str the string to strip
-   * @param suffix the expected suffix
-   * @return the stripped string or <code>null</code> if the string
-   * does not end with the suffix
-   */
-  public static String stripSuffix(String str, String suffix) {
-    return str.endsWith(suffix)
-        ? str.substring(0, str.length() - suffix.length())
-        : null;
-  }
-
-  /**
-   * Case insensitive version of stripSuffix. Strings are compared in
-   * the same way as in {@link String#equalsIgnoreCase}.
-   * Analogous to the c++ function strcasesuffix.
-   *
-   * @param str the string to strip
-   * @param suffix the expected suffix
-   * @return the stripped string or <code>null</code> if the string
-   * does not end with the suffix
-   */
-  public static String stripSuffixIgnoreCase(
-      String str, String suffix) {
-    return endsWithIgnoreCase(str, suffix)
-        ? str.substring(0, str.length() - suffix.length())
-        : null;
-  }
-
-  /**
-   * Strips all non-digit characters from a string.
-   *
-   * The resulting string will only contain characters for which isDigit()
-   * returns true.
-   *
-   * @param str the string to strip
-   * @return a string consisting of digits only, or an empty string
-   * @deprecated use {@code CharMatcher.JAVA_DIGIT.retainFrom(str)} (also
-   *     consider whether this is really the definition of "digit" you wish to
-   *     use)
-   */
-  @Deprecated public static String stripNonDigits(String str) {
-    return CharMatcher.JAVA_DIGIT.retainFrom(str);
-  }
-
-  /**
-   * Finds the last index in str of a character not in the characters
-   * in 'chars' (similar to ANSI string.find_last_not_of).
-   *
-   * Returns -1 if no such character can be found.
-   *
-   * <p><b>Note:</b> If {@code fromIndex} is zero, use {@link CharMatcher}
-   * instead for this: {@code CharMatcher.noneOf(chars).lastIndexIn(str)}.
-   */
-  // TODO(kevinb): after adding fromIndex versions of (last)IndexOf to
-  // CharMatcher, deprecate this
-  public static int lastIndexNotOf(String str, String chars, int fromIndex) {
-    fromIndex = Math.min(fromIndex, str.length() - 1);
-
-    for (int pos = fromIndex; pos >= 0; pos--) {
-      if (chars.indexOf(str.charAt(pos)) < 0) {
-        return pos;
-      }
-    }
-
-    return -1;
-  }
-
-  /**
-   * Like String.replace() except that it accepts any number of old chars.
-   * Replaces any occurrances of 'oldchars' in 'str' with 'newchar'.
-   * Example: replaceChars("Hello, world!", "H,!", ' ') returns " ello  world "
-   *
-   * @deprecated use {@code CharMatcher#replaceFrom(String, char)}, for example
-   *     {@code CharMatcher.anyOf(oldchars).replaceFrom(str, newchar)}
-   */
-  @Deprecated public static String replaceChars(
-      String str, CharSequence oldchars, char newchar) {
-    return CharMatcher.anyOf(oldchars).replaceFrom(str, newchar);
-  }
-
-  /**
-   * Remove any occurrances of 'oldchars' in 'str'.
-   * Example: removeChars("Hello, world!", ",!") returns "Hello world"
-   *
-   * @deprecated use {@link CharMatcher#removeFrom(CharSequence)}, for example
-   *     {@code CharMatcher.anyOf(oldchars).removeFrom(str)}
-   */
-  @Deprecated public static String removeChars(
-      String str, CharSequence oldchars) {
-    return CharMatcher.anyOf(oldchars).removeFrom(str);
-  }
-
-  // See http://www.microsoft.com/typography/unicode/1252.htm
-  private static final CharMatcher FANCY_SINGLE_QUOTE
-      = CharMatcher.anyOf("\u0091\u0092\u2018\u2019");
-  private static final CharMatcher FANCY_DOUBLE_QUOTE
-      = CharMatcher.anyOf("\u0093\u0094\u201c\u201d");
-
-  /**
-   * Replaces microsoft "smart quotes" (curly " and ') with their
-   * ascii counterparts.
-   */
-  public static String replaceSmartQuotes(String str) {
-    String tmp = FANCY_SINGLE_QUOTE.replaceFrom(str, '\'');
-    return FANCY_DOUBLE_QUOTE.replaceFrom(tmp, '"');
-  }
-
-  /**
-   * Convert a string of hex digits to a byte array, with the first
-   * byte in the array being the MSB. The string passed in should be
-   * just the raw digits (upper or lower case), with no leading
-   * or trailing characters (like '0x' or 'h').
-   * An odd number of characters is supported.
-   * If the string is empty, an empty array will be returned.
-   *
-   * This is significantly faster than using
-   *   new BigInteger(str, 16).toByteArray();
-   * especially with larger strings. Here are the results of some
-   * microbenchmarks done on a P4 2.8GHz 2GB RAM running
-   * linux 2.4.22-gg11 and JDK 1.5 with an optimized build:
-   *
-   * String length        hexToBytes (usec)   BigInteger
-   * -----------------------------------------------------
-   * 16                       0.570                 1.43
-   * 256                      8.21                 44.4
-   * 1024                    32.8                 526
-   * 16384                  546                121000
-   */
-  public static byte[] hexToBytes(CharSequence str) {
-    byte[] bytes = new byte[(str.length() + 1) / 2];
-    if (str.length() == 0) {
-      return bytes;
-    }
-    bytes[0] = 0;
-    int nibbleIdx = (str.length() % 2);
-    for (int i = 0; i < str.length(); i++) {
-      char c = str.charAt(i);
-      if (!isHex(c)) {
-        throw new IllegalArgumentException("string contains non-hex chars");
-      }
-      if ((nibbleIdx % 2) == 0) {
-        bytes[nibbleIdx >> 1] = (byte) (hexValue(c) << 4);
-      } else {
-        bytes[nibbleIdx >> 1] += (byte) hexValue(c);
-      }
-      nibbleIdx++;
-    }
-    return bytes;
-  }
-
-  /**
-   * Converts any instances of "\r" or "\r\n" style EOLs into "\n" (Line Feed).
-   */
-  public static String convertEOLToLF(String input) {
-    StringBuilder res = new StringBuilder(input.length());
-    char[] s = input.toCharArray();
-    int from = 0;
-    final int end = s.length;
-    for (int i = 0; i < end; i++) {
-      if (s[i] == '\r') {
-        res.append(s, from, i - from);
-        res.append('\n');
-        if (i + 1 < end && s[i + 1] == '\n') {
-          i++;
-        }
-
-        from = i + 1;
-      }
-    }
-
-    if (from == 0) {   // no \r!
-      return input;
-    }
-
-    res.append(s, from, end - from);
-    return res.toString();
-  }
-
-  /**
-   * Old location of {@link Strings#padStart}; this method will be deprecated
-   * soon.
-   */
-  public static String padLeft(String s, int len, char padChar) {
-    return Strings.padStart(s, len, padChar);
-  }
-
-  /**
-   * Old location of {@link Strings#padEnd}; this method will be deprecated
-   * soon.
-   */
-  public static String padRight(String s, int len, char padChar) {
-    return Strings.padEnd(s, len, padChar);
-  }
-
-  /**
-   * Returns a string consisting of "s", with each of the first "len" characters
-   * replaced by "maskChar" character.
-   */
-  public static String maskLeft(String s, int len, char maskChar) {
-    if (len <= 0) {
-      return s;
-    }
-    len = Math.min(len, s.length());
-    StringBuilder sb = new StringBuilder();
-    for (int i = 0; i < len; i++) {
-      sb.append(maskChar);
-    }
-    sb.append(s.substring(len));
-    return sb.toString();
-  }
-
-  private static boolean isOctal(char c) {
-    return (c >= '0') && (c <= '7');
-  }
-
-  private static boolean isHex(char c) {
-    return ((c >= '0') && (c <= '9')) ||
-           ((c >= 'a') && (c <= 'f')) ||
-           ((c >= 'A') && (c <= 'F'));
-  }
-
-  private static int hexValue(char c) {
-    if ((c >= '0') && (c <= '9')) {
-      return (c - '0');
-    } else if ((c >= 'a') && (c <= 'f')) {
-      return (c - 'a') + 10;
-    } else {
-      return (c - 'A') + 10;
-    }
-  }
-
-  /**
-   * Unescape any C escape sequences (\n, \r, \\, \ooo, etc) and return the
-   * resulting string.
-   */
-  public static String unescapeCString(String s) {
-    if (s.indexOf('\\') < 0) {
-      // Fast path: nothing to unescape
-      return s;
-    }
-
-    StringBuilder sb = new StringBuilder();
-    int len = s.length();
-    for (int i = 0; i < len;) {
-      char c = s.charAt(i++);
-      if (c == '\\' && (i < len)) {
-        c = s.charAt(i++);
-        switch (c) {
-          case 'a':  c = '\007';  break;
-          case 'b':  c = '\b';    break;
-          case 'f':  c = '\f';    break;
-          case 'n':  c = '\n';    break;
-          case 'r':  c = '\r';    break;
-          case 't':  c = '\t';    break;
-          case 'v':  c = '\013';  break;
-          case '\\': c = '\\';    break;
-          case '?':  c = '?';     break;
-          case '\'': c = '\'';    break;
-          case '"':  c = '\"';    break;
-
-          default: {
-            if ((c == 'x') && (i < len) && isHex(s.charAt(i))) {
-              // "\xXX"
-              int v = hexValue(s.charAt(i++));
-              if ((i < len) && isHex(s.charAt(i))) {
-                v = v * 16 + hexValue(s.charAt(i++));
-              }
-              c = (char) v;
-            } else if (isOctal(c)) {
-              // "\OOO"
-              int v = (c - '0');
-              if ((i < len) && isOctal(s.charAt(i))) {
-                v = v * 8 + (s.charAt(i++) - '0');
-              }
-              if ((i < len) && isOctal(s.charAt(i))) {
-                v = v * 8 + (s.charAt(i++) - '0');
-              }
-              c = (char) v;
-            } else {
-              // Propagate unknown escape sequences.
-              sb.append('\\');
-            }
-            break;
-          }
-        }
-      }
-      sb.append(c);
-    }
-    return sb.toString();
-  }
-
-  /**
-   * Unescape any MySQL escape sequences.
-   * See MySQL language reference Chapter 6 at
-   * <a href="http://www.mysql.com/doc/">http://www.mysql.com/doc/</a>.
-   * This function will <strong>not</strong> work for other SQL-like
-   * dialects.
-   * @param s string to unescape, with the surrounding quotes.
-   * @return unescaped string, without the surrounding quotes.
-   * @exception IllegalArgumentException if s is not a valid MySQL string.
-   */
-  public static String unescapeMySQLString(String s)
-      throws IllegalArgumentException {
-    // note: the same buffer is used for both reading and writing
-    // it works because the writer can never outrun the reader
-    char chars[] = s.toCharArray();
-
-    // the string must be quoted 'like this' or "like this"
-    if (chars.length < 2 || chars[0] != chars[chars.length - 1] ||
-        (chars[0] != '\'' && chars[0] != '"')) {
-      throw new IllegalArgumentException("not a valid MySQL string: " + s);
-    }
-
-    // parse the string and decode the backslash sequences; in addition,
-    // quotes can be escaped 'like this: ''', "like this: """, or 'like this: "'
-    int j = 1;  // write position in the string (never exceeds read position)
-    int f = 0;  // state: 0 (normal), 1 (backslash), 2 (quote)
-    for (int i = 1; i < chars.length - 1; i++) {
-      if (f == 0) {             // previous character was normal
-        if (chars[i] == '\\') {
-          f = 1;  // backslash
-        } else if (chars[i] == chars[0]) {
-          f = 2;  // quoting character
-        } else {
-          chars[j++] = chars[i];
-        }
-      } else if (f == 1) {      // previous character was a backslash
-        switch (chars[i]) {
-          case '0':   chars[j++] = '\0';   break;
-          case '\'':  chars[j++] = '\'';   break;
-          case '"':   chars[j++] = '"';    break;
-          case 'b':   chars[j++] = '\b';   break;
-          case 'n':   chars[j++] = '\n';   break;
-          case 'r':   chars[j++] = '\r';   break;
-          case 't':   chars[j++] = '\t';   break;
-          case 'z':   chars[j++] = '\032'; break;
-          case '\\':  chars[j++] = '\\';   break;
-          default:
-            // if the character is not special, backslash disappears
-            chars[j++] = chars[i];
-            break;
-        }
-        f = 0;
-      } else {                  // previous character was a quote
-        // quoting characters must be doubled inside a string
-        if (chars[i] != chars[0]) {
-          throw new IllegalArgumentException("not a valid MySQL string: " + s);
-        }
-        chars[j++] = chars[0];
-        f = 0;
-      }
-    }
-    // string contents cannot end with a special character
-    if (f != 0) {
-      throw new IllegalArgumentException("not a valid MySQL string: " + s);
-    }
-
-    // done
-    return new String(chars, 1, j - 1);
-  }
-
-  // TODO(pbarry): move all HTML methods to common.html package
-
-  static final Map<String, Character> ESCAPE_STRINGS;
-  static final Set<Character> HEX_LETTERS;
-
-  static {
-    // HTML character entity references as defined in HTML 4
-    // see http://www.w3.org/TR/REC-html40/sgml/entities.html
-    ESCAPE_STRINGS = new HashMap<String, Character>(252);
-
-    ESCAPE_STRINGS.put("&nbsp", '\u00A0');
-    ESCAPE_STRINGS.put("&iexcl", '\u00A1');
-    ESCAPE_STRINGS.put("&cent", '\u00A2');
-    ESCAPE_STRINGS.put("&pound", '\u00A3');
-    ESCAPE_STRINGS.put("&curren", '\u00A4');
-    ESCAPE_STRINGS.put("&yen", '\u00A5');
-    ESCAPE_STRINGS.put("&brvbar", '\u00A6');
-    ESCAPE_STRINGS.put("&sect", '\u00A7');
-    ESCAPE_STRINGS.put("&uml", '\u00A8');
-    ESCAPE_STRINGS.put("&copy", '\u00A9');
-    ESCAPE_STRINGS.put("&ordf", '\u00AA');
-    ESCAPE_STRINGS.put("&laquo", '\u00AB');
-    ESCAPE_STRINGS.put("&not", '\u00AC');
-    ESCAPE_STRINGS.put("&shy", '\u00AD');
-    ESCAPE_STRINGS.put("&reg", '\u00AE');
-    ESCAPE_STRINGS.put("&macr", '\u00AF');
-    ESCAPE_STRINGS.put("&deg", '\u00B0');
-    ESCAPE_STRINGS.put("&plusmn", '\u00B1');
-    ESCAPE_STRINGS.put("&sup2", '\u00B2');
-    ESCAPE_STRINGS.put("&sup3", '\u00B3');
-    ESCAPE_STRINGS.put("&acute", '\u00B4');
-    ESCAPE_STRINGS.put("&micro", '\u00B5');
-    ESCAPE_STRINGS.put("&para", '\u00B6');
-    ESCAPE_STRINGS.put("&middot", '\u00B7');
-    ESCAPE_STRINGS.put("&cedil", '\u00B8');
-    ESCAPE_STRINGS.put("&sup1", '\u00B9');
-    ESCAPE_STRINGS.put("&ordm", '\u00BA');
-    ESCAPE_STRINGS.put("&raquo", '\u00BB');
-    ESCAPE_STRINGS.put("&frac14", '\u00BC');
-    ESCAPE_STRINGS.put("&frac12", '\u00BD');
-    ESCAPE_STRINGS.put("&frac34", '\u00BE');
-    ESCAPE_STRINGS.put("&iquest", '\u00BF');
-    ESCAPE_STRINGS.put("&Agrave", '\u00C0');
-    ESCAPE_STRINGS.put("&Aacute", '\u00C1');
-    ESCAPE_STRINGS.put("&Acirc", '\u00C2');
-    ESCAPE_STRINGS.put("&Atilde", '\u00C3');
-    ESCAPE_STRINGS.put("&Auml", '\u00C4');
-    ESCAPE_STRINGS.put("&Aring", '\u00C5');
-    ESCAPE_STRINGS.put("&AElig", '\u00C6');
-    ESCAPE_STRINGS.put("&Ccedil", '\u00C7');
-    ESCAPE_STRINGS.put("&Egrave", '\u00C8');
-    ESCAPE_STRINGS.put("&Eacute", '\u00C9');
-    ESCAPE_STRINGS.put("&Ecirc", '\u00CA');
-    ESCAPE_STRINGS.put("&Euml", '\u00CB');
-    ESCAPE_STRINGS.put("&Igrave", '\u00CC');
-    ESCAPE_STRINGS.put("&Iacute", '\u00CD');
-    ESCAPE_STRINGS.put("&Icirc", '\u00CE');
-    ESCAPE_STRINGS.put("&Iuml", '\u00CF');
-    ESCAPE_STRINGS.put("&ETH", '\u00D0');
-    ESCAPE_STRINGS.put("&Ntilde", '\u00D1');
-    ESCAPE_STRINGS.put("&Ograve", '\u00D2');
-    ESCAPE_STRINGS.put("&Oacute", '\u00D3');
-    ESCAPE_STRINGS.put("&Ocirc", '\u00D4');
-    ESCAPE_STRINGS.put("&Otilde", '\u00D5');
-    ESCAPE_STRINGS.put("&Ouml", '\u00D6');
-    ESCAPE_STRINGS.put("&times", '\u00D7');
-    ESCAPE_STRINGS.put("&Oslash", '\u00D8');
-    ESCAPE_STRINGS.put("&Ugrave", '\u00D9');
-    ESCAPE_STRINGS.put("&Uacute", '\u00DA');
-    ESCAPE_STRINGS.put("&Ucirc", '\u00DB');
-    ESCAPE_STRINGS.put("&Uuml", '\u00DC');
-    ESCAPE_STRINGS.put("&Yacute", '\u00DD');
-    ESCAPE_STRINGS.put("&THORN", '\u00DE');
-    ESCAPE_STRINGS.put("&szlig", '\u00DF');
-    ESCAPE_STRINGS.put("&agrave", '\u00E0');
-    ESCAPE_STRINGS.put("&aacute", '\u00E1');
-    ESCAPE_STRINGS.put("&acirc", '\u00E2');
-    ESCAPE_STRINGS.put("&atilde", '\u00E3');
-    ESCAPE_STRINGS.put("&auml", '\u00E4');
-    ESCAPE_STRINGS.put("&aring", '\u00E5');
-    ESCAPE_STRINGS.put("&aelig", '\u00E6');
-    ESCAPE_STRINGS.put("&ccedil", '\u00E7');
-    ESCAPE_STRINGS.put("&egrave", '\u00E8');
-    ESCAPE_STRINGS.put("&eacute", '\u00E9');
-    ESCAPE_STRINGS.put("&ecirc", '\u00EA');
-    ESCAPE_STRINGS.put("&euml", '\u00EB');
-    ESCAPE_STRINGS.put("&igrave", '\u00EC');
-    ESCAPE_STRINGS.put("&iacute", '\u00ED');
-    ESCAPE_STRINGS.put("&icirc", '\u00EE');
-    ESCAPE_STRINGS.put("&iuml", '\u00EF');
-    ESCAPE_STRINGS.put("&eth", '\u00F0');
-    ESCAPE_STRINGS.put("&ntilde", '\u00F1');
-    ESCAPE_STRINGS.put("&ograve", '\u00F2');
-    ESCAPE_STRINGS.put("&oacute", '\u00F3');
-    ESCAPE_STRINGS.put("&ocirc", '\u00F4');
-    ESCAPE_STRINGS.put("&otilde", '\u00F5');
-    ESCAPE_STRINGS.put("&ouml", '\u00F6');
-    ESCAPE_STRINGS.put("&divide", '\u00F7');
-    ESCAPE_STRINGS.put("&oslash", '\u00F8');
-    ESCAPE_STRINGS.put("&ugrave", '\u00F9');
-    ESCAPE_STRINGS.put("&uacute", '\u00FA');
-    ESCAPE_STRINGS.put("&ucirc", '\u00FB');
-    ESCAPE_STRINGS.put("&uuml", '\u00FC');
-    ESCAPE_STRINGS.put("&yacute", '\u00FD');
-    ESCAPE_STRINGS.put("&thorn", '\u00FE');
-    ESCAPE_STRINGS.put("&yuml", '\u00FF');
-    ESCAPE_STRINGS.put("&fnof", '\u0192');
-    ESCAPE_STRINGS.put("&Alpha", '\u0391');
-    ESCAPE_STRINGS.put("&Beta", '\u0392');
-    ESCAPE_STRINGS.put("&Gamma", '\u0393');
-    ESCAPE_STRINGS.put("&Delta", '\u0394');
-    ESCAPE_STRINGS.put("&Epsilon", '\u0395');
-    ESCAPE_STRINGS.put("&Zeta", '\u0396');
-    ESCAPE_STRINGS.put("&Eta", '\u0397');
-    ESCAPE_STRINGS.put("&Theta", '\u0398');
-    ESCAPE_STRINGS.put("&Iota", '\u0399');
-    ESCAPE_STRINGS.put("&Kappa", '\u039A');
-    ESCAPE_STRINGS.put("&Lambda", '\u039B');
-    ESCAPE_STRINGS.put("&Mu", '\u039C');
-    ESCAPE_STRINGS.put("&Nu", '\u039D');
-    ESCAPE_STRINGS.put("&Xi", '\u039E');
-    ESCAPE_STRINGS.put("&Omicron", '\u039F');
-    ESCAPE_STRINGS.put("&Pi", '\u03A0');
-    ESCAPE_STRINGS.put("&Rho", '\u03A1');
-    ESCAPE_STRINGS.put("&Sigma", '\u03A3');
-    ESCAPE_STRINGS.put("&Tau", '\u03A4');
-    ESCAPE_STRINGS.put("&Upsilon", '\u03A5');
-    ESCAPE_STRINGS.put("&Phi", '\u03A6');
-    ESCAPE_STRINGS.put("&Chi", '\u03A7');
-    ESCAPE_STRINGS.put("&Psi", '\u03A8');
-    ESCAPE_STRINGS.put("&Omega", '\u03A9');
-    ESCAPE_STRINGS.put("&alpha", '\u03B1');
-    ESCAPE_STRINGS.put("&beta", '\u03B2');
-    ESCAPE_STRINGS.put("&gamma", '\u03B3');
-    ESCAPE_STRINGS.put("&delta", '\u03B4');
-    ESCAPE_STRINGS.put("&epsilon", '\u03B5');
-    ESCAPE_STRINGS.put("&zeta", '\u03B6');
-    ESCAPE_STRINGS.put("&eta", '\u03B7');
-    ESCAPE_STRINGS.put("&theta", '\u03B8');
-    ESCAPE_STRINGS.put("&iota", '\u03B9');
-    ESCAPE_STRINGS.put("&kappa", '\u03BA');
-    ESCAPE_STRINGS.put("&lambda", '\u03BB');
-    ESCAPE_STRINGS.put("&mu", '\u03BC');
-    ESCAPE_STRINGS.put("&nu", '\u03BD');
-    ESCAPE_STRINGS.put("&xi", '\u03BE');
-    ESCAPE_STRINGS.put("&omicron", '\u03BF');
-    ESCAPE_STRINGS.put("&pi", '\u03C0');
-    ESCAPE_STRINGS.put("&rho", '\u03C1');
-    ESCAPE_STRINGS.put("&sigmaf", '\u03C2');
-    ESCAPE_STRINGS.put("&sigma", '\u03C3');
-    ESCAPE_STRINGS.put("&tau", '\u03C4');
-    ESCAPE_STRINGS.put("&upsilon", '\u03C5');
-    ESCAPE_STRINGS.put("&phi", '\u03C6');
-    ESCAPE_STRINGS.put("&chi", '\u03C7');
-    ESCAPE_STRINGS.put("&psi", '\u03C8');
-    ESCAPE_STRINGS.put("&omega", '\u03C9');
-    ESCAPE_STRINGS.put("&thetasym", '\u03D1');
-    ESCAPE_STRINGS.put("&upsih", '\u03D2');
-    ESCAPE_STRINGS.put("&piv", '\u03D6');
-    ESCAPE_STRINGS.put("&bull", '\u2022');
-    ESCAPE_STRINGS.put("&hellip", '\u2026');
-    ESCAPE_STRINGS.put("&prime", '\u2032');
-    ESCAPE_STRINGS.put("&Prime", '\u2033');
-    ESCAPE_STRINGS.put("&oline", '\u203E');
-    ESCAPE_STRINGS.put("&frasl", '\u2044');
-    ESCAPE_STRINGS.put("&weierp", '\u2118');
-    ESCAPE_STRINGS.put("&image", '\u2111');
-    ESCAPE_STRINGS.put("&real", '\u211C');
-    ESCAPE_STRINGS.put("&trade", '\u2122');
-    ESCAPE_STRINGS.put("&alefsym", '\u2135');
-    ESCAPE_STRINGS.put("&larr", '\u2190');
-    ESCAPE_STRINGS.put("&uarr", '\u2191');
-    ESCAPE_STRINGS.put("&rarr", '\u2192');
-    ESCAPE_STRINGS.put("&darr", '\u2193');
-    ESCAPE_STRINGS.put("&harr", '\u2194');
-    ESCAPE_STRINGS.put("&crarr", '\u21B5');
-    ESCAPE_STRINGS.put("&lArr", '\u21D0');
-    ESCAPE_STRINGS.put("&uArr", '\u21D1');
-    ESCAPE_STRINGS.put("&rArr", '\u21D2');
-    ESCAPE_STRINGS.put("&dArr", '\u21D3');
-    ESCAPE_STRINGS.put("&hArr", '\u21D4');
-    ESCAPE_STRINGS.put("&forall", '\u2200');
-    ESCAPE_STRINGS.put("&part", '\u2202');
-    ESCAPE_STRINGS.put("&exist", '\u2203');
-    ESCAPE_STRINGS.put("&empty", '\u2205');
-    ESCAPE_STRINGS.put("&nabla", '\u2207');
-    ESCAPE_STRINGS.put("&isin", '\u2208');
-    ESCAPE_STRINGS.put("&notin", '\u2209');
-    ESCAPE_STRINGS.put("&ni", '\u220B');
-    ESCAPE_STRINGS.put("&prod", '\u220F');
-    ESCAPE_STRINGS.put("&sum", '\u2211');
-    ESCAPE_STRINGS.put("&minus", '\u2212');
-    ESCAPE_STRINGS.put("&lowast", '\u2217');
-    ESCAPE_STRINGS.put("&radic", '\u221A');
-    ESCAPE_STRINGS.put("&prop", '\u221D');
-    ESCAPE_STRINGS.put("&infin", '\u221E');
-    ESCAPE_STRINGS.put("&ang", '\u2220');
-    ESCAPE_STRINGS.put("&and", '\u2227');
-    ESCAPE_STRINGS.put("&or", '\u2228');
-    ESCAPE_STRINGS.put("&cap", '\u2229');
-    ESCAPE_STRINGS.put("&cup", '\u222A');
-    ESCAPE_STRINGS.put("&int", '\u222B');
-    ESCAPE_STRINGS.put("&there4", '\u2234');
-    ESCAPE_STRINGS.put("&sim", '\u223C');
-    ESCAPE_STRINGS.put("&cong", '\u2245');
-    ESCAPE_STRINGS.put("&asymp", '\u2248');
-    ESCAPE_STRINGS.put("&ne", '\u2260');
-    ESCAPE_STRINGS.put("&equiv", '\u2261');
-    ESCAPE_STRINGS.put("&le", '\u2264');
-    ESCAPE_STRINGS.put("&ge", '\u2265');
-    ESCAPE_STRINGS.put("&sub", '\u2282');
-    ESCAPE_STRINGS.put("&sup", '\u2283');
-    ESCAPE_STRINGS.put("&nsub", '\u2284');
-    ESCAPE_STRINGS.put("&sube", '\u2286');
-    ESCAPE_STRINGS.put("&supe", '\u2287');
-    ESCAPE_STRINGS.put("&oplus", '\u2295');
-    ESCAPE_STRINGS.put("&otimes", '\u2297');
-    ESCAPE_STRINGS.put("&perp", '\u22A5');
-    ESCAPE_STRINGS.put("&sdot", '\u22C5');
-    ESCAPE_STRINGS.put("&lceil", '\u2308');
-    ESCAPE_STRINGS.put("&rceil", '\u2309');
-    ESCAPE_STRINGS.put("&lfloor", '\u230A');
-    ESCAPE_STRINGS.put("&rfloor", '\u230B');
-    ESCAPE_STRINGS.put("&lang", '\u2329');
-    ESCAPE_STRINGS.put("&rang", '\u232A');
-    ESCAPE_STRINGS.put("&loz", '\u25CA');
-    ESCAPE_STRINGS.put("&spades", '\u2660');
-    ESCAPE_STRINGS.put("&clubs", '\u2663');
-    ESCAPE_STRINGS.put("&hearts", '\u2665');
-    ESCAPE_STRINGS.put("&diams", '\u2666');
-    ESCAPE_STRINGS.put("&quot", '\u0022');
-    ESCAPE_STRINGS.put("&amp", '\u0026');
-    ESCAPE_STRINGS.put("&lt", '\u003C');
-    ESCAPE_STRINGS.put("&gt", '\u003E');
-    ESCAPE_STRINGS.put("&OElig", '\u0152');
-    ESCAPE_STRINGS.put("&oelig", '\u0153');
-    ESCAPE_STRINGS.put("&Scaron", '\u0160');
-    ESCAPE_STRINGS.put("&scaron", '\u0161');
-    ESCAPE_STRINGS.put("&Yuml", '\u0178');
-    ESCAPE_STRINGS.put("&circ", '\u02C6');
-    ESCAPE_STRINGS.put("&tilde", '\u02DC');
-    ESCAPE_STRINGS.put("&ensp", '\u2002');
-    ESCAPE_STRINGS.put("&emsp", '\u2003');
-    ESCAPE_STRINGS.put("&thinsp", '\u2009');
-    ESCAPE_STRINGS.put("&zwnj", '\u200C');
-    ESCAPE_STRINGS.put("&zwj", '\u200D');
-    ESCAPE_STRINGS.put("&lrm", '\u200E');
-    ESCAPE_STRINGS.put("&rlm", '\u200F');
-    ESCAPE_STRINGS.put("&ndash", '\u2013');
-    ESCAPE_STRINGS.put("&mdash", '\u2014');
-    ESCAPE_STRINGS.put("&lsquo", '\u2018');
-    ESCAPE_STRINGS.put("&rsquo", '\u2019');
-    ESCAPE_STRINGS.put("&sbquo", '\u201A');
-    ESCAPE_STRINGS.put("&ldquo", '\u201C');
-    ESCAPE_STRINGS.put("&rdquo", '\u201D');
-    ESCAPE_STRINGS.put("&bdquo", '\u201E');
-    ESCAPE_STRINGS.put("&dagger", '\u2020');
-    ESCAPE_STRINGS.put("&Dagger", '\u2021');
-    ESCAPE_STRINGS.put("&permil", '\u2030');
-    ESCAPE_STRINGS.put("&lsaquo", '\u2039');
-    ESCAPE_STRINGS.put("&rsaquo", '\u203A');
-    ESCAPE_STRINGS.put("&euro", '\u20AC');
-
-    HEX_LETTERS = new HashSet<Character>(12);
-
-    HEX_LETTERS.add('a');
-    HEX_LETTERS.add('A');
-    HEX_LETTERS.add('b');
-    HEX_LETTERS.add('B');
-    HEX_LETTERS.add('c');
-    HEX_LETTERS.add('C');
-    HEX_LETTERS.add('d');
-    HEX_LETTERS.add('D');
-    HEX_LETTERS.add('e');
-    HEX_LETTERS.add('E');
-    HEX_LETTERS.add('f');
-    HEX_LETTERS.add('F');
-  }
-
-  /**
-   * <p>
-   * Replace all the occurences of HTML escape strings with the
-   * respective characters.
-   * </p>
-   * <p>
-   * The default mode is strict (requiring semicolons).
-   * </p>
-   *
-   * @param s a <code>String</code> value
-   * @return a <code>String</code> value
-   * @throws NullPointerException if the input string is null.
-   */
-  public static final String unescapeHTML(String s) {
-    return unescapeHTML(s, false);
-  }
-
-  /**
-   * Replace all the occurences of HTML escape strings with the
-   * respective characters.
-   *
-   * @param s a <code>String</code> value
-   * @param emulateBrowsers a <code>Boolean</code> value that tells the method
-   *     to allow entity refs not terminated with a semicolon to be unescaped.
-   *     (a quirk of this feature, and some browsers, is that an explicit
-   *     terminating character is needed - e.g., &lt$ would be unescaped, but
-   *     not &ltab - see the tests for a more in-depth description of browsers)
-   * @return a <code>String</code> value
-   * @throws NullPointerException if the input string is null.
-   */
-  public static final String unescapeHTML(String s, boolean emulateBrowsers) {
-
-    // See if there are any '&' in the string since that is what we look
-    // for to escape. If there isn't, then we don't need to escape this string
-    // Based on similar technique used in the escape function.
-    int index = s.indexOf('&');
-    if (index == -1) {
-      // Nothing to escape. Return the original string.
-      return s;
-    }
-
-    // We found an escaped character. Start slow escaping from there.
-    char[] chars = s.toCharArray();
-    char[] escaped = new char[chars.length];
-    System.arraycopy(chars, 0, escaped, 0, index);
-
-    // Note: escaped[pos] = end of the escaped char array.
-    int pos = index;
-
-    for (int i = index; i < chars.length;) {
-      if (chars[i] != '&') {
-        escaped[pos++] = chars[i++];
-        continue;
-      }
-
-      // Allow e.g. &#123;
-      int j = i + 1;
-      boolean isNumericEntity = false;
-      if (j < chars.length && chars[j] == '#') {
-        j++;
-        isNumericEntity = true;
-      }
-
-      // if it's numeric, also check for hex
-      boolean isHexEntity = false;
-      if (j < chars.length && (chars[j] == 'x' || chars[j] == 'X')) {
-        j++;
-        isHexEntity = true;
-      }
-
-      // Scan until we find a char that is not valid for this sequence.
-      for (; j < chars.length; j++) {
-        char ch = chars[j];
-        boolean isDigit = Character.isDigit(ch);
-        if (isNumericEntity) {
-          // non-hex numeric sequence end condition
-          if (!isHexEntity && !isDigit) {
-            break;
-          }
-          // hex sequence end contition
-          if (isHexEntity && !isDigit && !HEX_LETTERS.contains(ch)) {
-            break;
-          }
-        }
-        // anything other than a digit or letter is always an end condition
-        if (!isDigit && !Character.isLetter(ch)) {
-          break;
-        }
-      }
-
-      boolean replaced = false;
-      if ((j <= chars.length && emulateBrowsers) ||
-          (j < chars.length && chars[j] == ';')) {
-        // Check for &#D; and &#xD; pattern
-        if (i + 2 < chars.length && s.charAt(i + 1) == '#') {
-          try {
-            long charcode = 0;
-            char ch = s.charAt(i + 2);
-            if (isHexEntity) {
-              charcode = Long.parseLong(
-                  new String(chars, i + 3, j - i - 3), 16);
-            } else if (Character.isDigit(ch)) {
-              charcode = Long.parseLong(
-                  new String(chars, i + 2, j - i - 2));
-            }
-            if (charcode > 0 && charcode < 65536) {
-              escaped[pos++] = (char) charcode;
-              replaced = true;
-            }
-          } catch (NumberFormatException ex) {
-            // Failed, not replaced.
-          }
-        } else {
-          String key = new String(chars, i, j - i);
-          Character repl = ESCAPE_STRINGS.get(key);
-          if (repl != null) {
-            escaped[pos++] = repl;
-            replaced = true;
-          }
-        }
-        // Skip over ';'
-        if (j < chars.length && chars[j] == ';') {
-          j++;
-        }
-      }
-
-      if (!replaced) {
-        // Not a recognized escape sequence, leave as-is
-        System.arraycopy(chars, i, escaped, pos, j - i);
-        pos += j - i;
-      }
-      i = j;
-    }
-    return new String(escaped, 0, pos);
-  }
-
-  // Escaper for < and > only.
-  private static final CharEscaper LT_GT_ESCAPE =
-      new CharEscaperBuilder()
-        .addEscape('<', "&lt;")
-        .addEscape('>', "&gt;")
-        .toEscaper();
-
-  private static final Pattern htmlTagPattern =
-      Pattern.compile("</?[a-zA-Z][^>]*>");
-
-  /**
-   * Given a <code>String</code>, returns an equivalent <code>String</code> with
-   * all HTML tags stripped. Note that HTML entities, such as "&amp;amp;" will
-   * still be preserved.
-   */
-  public static String stripHtmlTags(String string) {
-    if ((string == null) || "".equals(string)) {
-      return string;
-    }
-    String stripped = htmlTagPattern.matcher(string).replaceAll("");
-    /*
-     * Certain inputs result in a well-formed HTML:
-     * <<X>script>alert(0)<</X>/script> results in <script>alert(0)</script>
-     * The following step ensures that no HTML can slip through by replacing all
-     * < and > characters with &lt; and &gt; after HTML tags were stripped.
-     */
-    return LT_GT_ESCAPE.escape(stripped);
-  }
-
-  /**
-   * We escape some characters in s to be able to insert strings into JavaScript
-   * code. Also, make sure that we don't write out {@code -->} or
-   * {@code </script>}, which may close a script tag, or any char in ["'>] which
-   * might close a tag or attribute if seen inside an attribute.
-   */
-  public static String javaScriptEscape(CharSequence s) {
-    return javaScriptEscapeHelper(s, false);
-  }
-
-  /**
-   * We escape some characters in s to be able to insert strings into JavaScript
-   * code. Also, make sure that we don't write out {@code -->} or
-   * {@code </script>}, which may close a script tag, or any char in ["'>] which
-   * might close a tag or attribute if seen inside an attribute.
-   * Turns all non-ascii characters into ASCII javascript escape sequences
-   * (eg \\uhhhh or \ooo).
-   */
-  public static String javaScriptEscapeToAscii(CharSequence s) {
-    return javaScriptEscapeHelper(s, true);
-  }
-
-  /**
-   * Represents the type of javascript escaping to perform.  Each enum below
-   * determines whether to use octal escapes and how to handle quotes.
-   */
-  public static enum JsEscapingMode {
-    /** No octal escapes, pass-through ', and escape " as \". */
-    JSON,
-
-    /** Octal escapes, escapes ' and " to \42 and \47, respectively. */
-    EMBEDDABLE_JS,
-
-    /** Octal escapes, escapes ' and " to \' and \". */
-    MINIMAL_JS
-  }
-
-  /**
-   * Helper for javaScriptEscape and javaScriptEscapeToAscii
-   */
-  private static String javaScriptEscapeHelper(CharSequence s,
-                                               boolean escapeToAscii) {
-    StringBuilder sb = new StringBuilder(s.length() * 9 / 8);
-    try {
-      escapeStringBody(s, escapeToAscii, JsEscapingMode.EMBEDDABLE_JS, sb);
-    } catch (IOException ex) {
-      // StringBuilder.append does not throw IOExceptions.
-      throw new RuntimeException(ex);
-    }
-    return sb.toString();
-  }
-
-  /**
-   * Appends the javascript string literal equivalent of plainText to the given
-   * out buffer.
-   * @param plainText the string to escape.
-   * @param escapeToAscii true to encode all characters not in ascii [\x20-\x7e]
-   *   <br>
-   *   Full escaping of unicode entites isn't required but this makes
-   *   sure that unicode strings will survive regardless of the
-   *   content-encoding of the javascript file which is important when
-   *   we use this function to autogenerated javascript source files.
-   *   This is disabled by default because it makes non-latin strings very long.
-   *   <br>
-   *   If you seem to have trouble with character-encodings, maybe
-   *   turn this on to see if the problem goes away.  If so, you need
-   *   to specify a character encoding for your javascript somewhere.
-   * @param jsEscapingMode determines the type of escaping to perform.
-   * @param out the buffer to append output to.
-   */
-  /*
-   * To avoid fallthrough, we would have to either use a hybrid switch-case/if
-   * approach (which would obscure our special handling for ' and "), duplicate
-   * the content of the default case, or pass a half-dozen parameters to a
-   * helper method containing the code from the default case.
-   */
-  @SuppressWarnings("fallthrough")
-  public static void escapeStringBody(
-      CharSequence plainText, boolean escapeToAscii,
-      JsEscapingMode jsEscapingMode, Appendable out)
-      throws IOException {
-    int pos = 0;  // Index just past the last char in plainText written to out.
-    int len = plainText.length();
-    for (int codePoint, charCount, i = 0; i < len; i += charCount) {
-      codePoint = Character.codePointAt(plainText, i);
-      charCount = Character.charCount(codePoint);
-
-      if (!shouldEscapeChar(codePoint, escapeToAscii, jsEscapingMode)) {
-        continue;
-      }
-
-      out.append(plainText, pos, i);
-      pos = i + charCount;
-      switch (codePoint) {
-        case '\b': out.append("\\b"); break;
-        case '\t': out.append("\\t"); break;
-        case '\n': out.append("\\n"); break;
-        case '\f': out.append("\\f"); break;
-        case '\r': out.append("\\r"); break;
-        case '\\': out.append("\\\\"); break;
-        case '"': case '\'':
-          if (jsEscapingMode == JsEscapingMode.JSON && '\'' == codePoint) {
-            // JSON does not escape a single quote (and it should be surrounded
-            // by double quotes).
-            out.append((char) codePoint);
-            break;
-          } else if (jsEscapingMode != JsEscapingMode.EMBEDDABLE_JS) {
-            out.append('\\').append((char) codePoint);
-            break;
-          }
-          // fall through
-        default:
-          if (codePoint >= 0x100 || jsEscapingMode == JsEscapingMode.JSON) {
-            appendHexJavaScriptRepresentation(codePoint, out);
-          } else {
-            // Output the minimal octal encoding.  We can't use an encoding
-            // shorter than three digits if the next digit is a valid octal
-            // digit.
-            boolean pad = i + charCount >= len
-                || isOctal(plainText.charAt(i + charCount));
-            appendOctalJavaScriptRepresentation((char) codePoint, pad, out);
-          }
-          break;
-      }
-    }
-    out.append(plainText, pos, len);
-  }
-
-  /**
-   * Helper for escapeStringBody, which decides whether to escape a character.
-   */
-  private static boolean shouldEscapeChar(int codePoint,
-      boolean escapeToAscii, JsEscapingMode jsEscapingMode) {
-    // If non-ASCII chars should be escaped, identify non-ASCII code points.
-    if (escapeToAscii && (codePoint < 0x20 || codePoint > 0x7e)) {
-      return true;
-    }
-
-    // If in JSON escaping mode, check JSON *and* JS escaping rules. The JS
-    // escaping rules will escape more characters than needed for JSON,
-    // but it is safe to escape any character in JSON.
-    // TODO(bbavar): Remove unnecessary escaping for JSON, as long as it can be
-    //               shown that this change in legacy behavior is safe.
-    if (jsEscapingMode == JsEscapingMode.JSON) {
-      return mustEscapeCharInJsonString(codePoint)
-          || mustEscapeCharInJsString(codePoint);
-    }
-
-    // Finally, just check the default JS escaping rules.
-    return mustEscapeCharInJsString(codePoint);
-  }
-
-  /**
-   * Returns a javascript representation of the character in a hex escaped
-   * format.
-   *
-   * @param codePoint The codepoint to append.
-   * @param out The buffer to which the hex representation should be appended.
-   */
-  private static void appendHexJavaScriptRepresentation(
-      int codePoint, Appendable out)
-      throws IOException {
-    if (Character.isSupplementaryCodePoint(codePoint)) {
-      // Handle supplementary unicode values which are not representable in
-      // javascript.  We deal with these by escaping them as two 4B sequences
-      // so that they will round-trip properly when sent from java to javascript
-      // and back.
-      char[] surrogates = Character.toChars(codePoint);
-      appendHexJavaScriptRepresentation(surrogates[0], out);
-      appendHexJavaScriptRepresentation(surrogates[1], out);
-      return;
-    }
-    out.append("\\u")
-        .append(HEX_CHARS[(codePoint >>> 12) & 0xf])
-        .append(HEX_CHARS[(codePoint >>> 8) & 0xf])
-        .append(HEX_CHARS[(codePoint >>> 4) & 0xf])
-        .append(HEX_CHARS[codePoint & 0xf]);
-  }
-
-  /**
-   * Returns a javascript representation of the character in a hex escaped
-   * format. Although this is a rather specific method, it is made public
-   * because it is also used by the JSCompiler.
-   *
-   * @param ch The character to append.
-   * @param pad true to force use of the full 3 digit representation.
-   * @param out The buffer to which the hex representation should be appended.
-   */
-  private static void appendOctalJavaScriptRepresentation(
-      char ch, boolean pad, Appendable out) throws IOException {
-    if (ch >= 0100
-        // Be paranoid at the end of a string since someone might call
-        // this method again with another string segment.
-        || pad) {
-      out.append('\\')
-          .append(OCTAL_CHARS[(ch >>> 6) & 0x7])
-          .append(OCTAL_CHARS[(ch >>> 3) & 0x7])
-          .append(OCTAL_CHARS[ch & 0x7]);
-    } else if (ch >= 010) {
-      out.append('\\')
-          .append(OCTAL_CHARS[(ch >>> 3) & 0x7])
-          .append(OCTAL_CHARS[ch & 0x7]);
-    } else {
-      out.append('\\')
-          .append(OCTAL_CHARS[ch & 0x7]);
-    }
-  }
-
-  /**
-   * Although this is a rather specific method, it is made public
-   * because it is also used by the JSCompiler.
-   *
-   * @see #appendHexJavaScriptRepresentation(int, Appendable)
-   */
-  public static void appendHexJavaScriptRepresentation(StringBuilder sb,
-                                                       char c) {
-    try {
-      appendHexJavaScriptRepresentation(c, sb);
-    } catch (IOException ex) {
-      // StringBuilder does not throw IOException.
-      throw new RuntimeException(ex);
-    }
-  }
-
-  /**
-   * Undo escaping as performed in javaScriptEscape(.)
-   * Throws an IllegalArgumentException if the string contains
-   * bad escaping.
-   */
-  public static String javaScriptUnescape(String s) {
-    StringBuilder sb = new StringBuilder(s.length());
-    for (int i = 0; i < s.length(); ) {
-      char c = s.charAt(i);
-      if (c == '\\') {
-        i = javaScriptUnescapeHelper(s, i + 1, sb);
-      } else {
-        sb.append(c);
-        i++;
-      }
-    }
-    return sb.toString();
-  }
-
-  /**
-   * Looks for an escape code starting at index i of s,
-   * and appends it to sb.
-   * @return the index of the first character in s
-   * after the escape code.
-   * @throws IllegalArgumentException if the escape code
-   * is invalid
-   */
-  private static int javaScriptUnescapeHelper(String s, int i,
-                                              StringBuilder sb) {
-    if (i >= s.length()) {
-      throw new IllegalArgumentException(
-          "End-of-string after escape character in [" + s + "]");
-    }
-
-    char c = s.charAt(i++);
-    switch (c) {
-      case 'n': sb.append('\n'); break;
-      case 'r': sb.append('\r'); break;
-      case 't': sb.append('\t'); break;
-      case 'b': sb.append('\b'); break;
-      case 'f': sb.append('\f'); break;
-      case '\\':
-      case '\"':
-      case '\'':
-      case '>':
-        sb.append(c);
-        break;
-      case '0': case '1': case '2': case '3':
-      case '4': case '5': case '6': case '7':
-        --i;  // backup to first octal digit
-        int nOctalDigits = 1;
-        int digitLimit = c < '4' ? 3 : 2;
-        while (nOctalDigits < digitLimit && i + nOctalDigits < s.length()
-               && isOctal(s.charAt(i + nOctalDigits))) {
-          ++nOctalDigits;
-        }
-        sb.append(
-            (char) Integer.parseInt(s.substring(i, i + nOctalDigits), 8));
-        i += nOctalDigits;
-        break;
-      case 'x':
-      case 'u':
-        String hexCode;
-        int nHexDigits = (c == 'u' ? 4 : 2);
-        try {
-          hexCode = s.substring(i, i + nHexDigits);
-        } catch (IndexOutOfBoundsException ioobe) {
-          throw new IllegalArgumentException(
-              "Invalid unicode sequence [" + s.substring(i) + "] at index " + i
-              + " in [" + s + "]");
-        }
-        int unicodeValue;
-        try {
-          unicodeValue = Integer.parseInt(hexCode, 16);
-        } catch (NumberFormatException nfe) {
-          throw new IllegalArgumentException(
-              "Invalid unicode sequence [" + hexCode + "] at index " + i +
-              " in [" + s + "]");
-        }
-        sb.append((char) unicodeValue);
-        i += nHexDigits;
-        break;
-      default:
-        throw new IllegalArgumentException(
-            "Unknown escape code [" + c + "] at index " + i + " in [" + s + "]"
-            );
-    }
-
-    return i;
-  }
-
-  // C0 control characters except \t, \n, and \r and 0xFFFE and 0xFFFF
-  private static final CharMatcher CONTROL_MATCHER = CharMatcher.anyOf(
-      "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007" +
-      "\u0008\u000B\u000C\u000E\u000F" +
-      "\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017" +
-      "\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F" +
-      "\uFFFE\uFFFF");
-
-  /**
-   * Escape a string that is meant to be embedded in a CDATA section.
-   * The returned string is guaranteed to be valid CDATA content.
-   * The syntax of CDATA sections is the following:
-   * <blockquote>
-   *   <code>&lt;[!CDATA[...]]&gt;</code>
-   * </blockquote>
-   * The only invalid character sequence in a CDATA tag is "]]&gt;".
-   * If this sequence is present in the input string, we replace
-   * it by closing the current CDATA field, then write ']]&amp;gt;',
-   * then reopen a new CDATA section.
-   */
-  public static String xmlCDataEscape(String s) {
-     // Make sure there are no illegal control characters.
-     s = CONTROL_MATCHER.removeFrom(s);
-    // Return the original reference if the string doesn't have a match.
-    int found = s.indexOf("]]>");
-    if (found == -1) {
-      return s;
-    }
-
-    // For each occurrence of "]]>", append a string that adds "]]&gt;" after
-    // the end of the CDATA which has just been closed, then opens a new CDATA.
-    StringBuilder sb = new StringBuilder();
-    int prev = 0;
-    do {
-      sb.append(s.substring(prev, found + 3));
-      sb.append("]]&gt;<![CDATA[");
-      prev = found + 3;
-    } while ((found = s.indexOf("]]>", prev)) != -1);
-    sb.append(s.substring(prev));
-    return sb.toString();
-  }
-
-  /**
-   * We escape some characters in s to be able to insert strings into Java code
-   *
-   * @deprecated Use {@link CharEscapers#asciiHtmlEscaper()} and {@link
-   * CharEscapers#javaCharEscaper()} or {@link CharEscapers#javaStringEscaper()}
-   * instead. This method combines two forms of escaping in a way that's rarely
-   * desired.
-   */
-  @Deprecated
-  public static String javaEscape(String s) {
-    return JAVA_ESCAPE.escape(s);
-  }
-
-  // Java escaper.
-  private static final CharEscaper JAVA_ESCAPE =
-      new CharEscaperBuilder()
-        .addEscape('\n', "\\n")
-        .addEscape('\r', "\\r")
-        .addEscape('\t', "\\t")
-        .addEscape('\\', "\\\\")
-        .addEscape('\"', "\\\"")
-        .addEscape('&', "&amp;")
-        .addEscape('<', "&lt;")
-        .addEscape('>', "&gt;")
-        .addEscape('\'', "\\\'")
-        .toEscaper();
-
-  /**
-   * Escapes the special characters from a string so it can be used as part of
-   * a regex pattern. This method is for use on gnu.regexp style regular
-   * expressions.
-   *
-   * @deprecated Use {@link Pattern#quote(String)} instead. Note that it may not
-   * be compatible with gnu.regexp style regular expressions.
-   */
-  @Deprecated
-  public static String regexEscape(String s) {
-    return REGEX_ESCAPE.escape(s);
-  }
-
-  // Regex escaper escapes all regex characters.
-  private static final CharEscaper REGEX_ESCAPE =
-      new CharEscaperBuilder()
-        .addEscape('(', "\\(")
-        .addEscape(')', "\\)")
-        .addEscape('|', "\\|")
-        .addEscape('*', "\\*")
-        .addEscape('+', "\\+")
-        .addEscape('?', "\\?")
-        .addEscape('.', "\\.")
-        .addEscape('{', "\\{")
-        .addEscape('}', "\\}")
-        .addEscape('[', "\\[")
-        .addEscape(']', "\\]")
-        .addEscape('$', "\\$")
-        .addEscape('^', "\\^")
-        .addEscape('\\', "\\\\")
-        .toEscaper();
-
-  /**
-   *  If you want to preserve the exact
-   * current (odd) behavior when {@code doStrip} is {@code true}, use
-   * {@code .trimResults(CharMatcher.LEGACY_WHITESPACE).omitEmptyStrings()} on
-   * the splitter.
-   *
-   * @param in what to process
-   * @param delimiter the delimiting string
-   * @return the tokens
-   * @deprecated see the detailed instructions under
-   *     {@link #split(String, String, boolean)}
-   */
-  @Deprecated
-  public static LinkedList<String> string2List(
-      String in, String delimiter, boolean doStrip) {
-    if (in == null) {
-      return null;
-    }
-
-    LinkedList<String> out = new LinkedList<String>();
-    string2Collection(in, delimiter, doStrip, out);
-    return out;
-  }
-
-  /**
-   * See the detailed instructions under {@link
-   * #split(String, String, boolean)}. Pass the resulting {@code Iterable} to
-   * {@link com.google.common.collect.Sets#newHashSet(Iterable)}. If you want to
-   * preserve the exact current (odd) behavior when {@code doStrip} is {@code
-   * true}, use {@code
-   * .trimResults(CharMatcher.LEGACY_WHITESPACE).omitEmptyStrings()} on the
-   * splitter.
-   *
-   * @param in what to process
-   * @param delimiter the delimiting string
-   * @param doStrip to strip the substrings before adding to the list
-   * @return the tokens
-   * @deprecated see the detailed instructions under
-   *     {@link #split(String, String, boolean)}
-   */
-  @Deprecated
-  public static Set<String> string2Set(
-       String in, String delimiter, boolean doStrip) {
-    if (in == null) {
-      return null;
-    }
-
-    HashSet<String> out = new HashSet<String>();
-    string2Collection(in, delimiter, doStrip, out);
-    return out;
-  }
-
-  /**
-   * See the detailed instructions under {@link
-   * #split(String, String, boolean)}. If you want to preserve the exact current
-   * (odd) behavior when {@code doStrip} is {@code true}, use {@code
-   * .trimResults(CharMatcher.LEGACY_WHITESPACE).omitEmptyStrings()} on the
-   * splitter.
-   *
-   * @param in The delimited input string to process
-   * @param delimiter The string delimiting entries in the input string.
-   * @param doStrip whether to strip the substrings before adding to the
-   *          collection
-   * @param collection The collection to which the strings will be added. If
-   *          <code>null</code>, a new <code>List</code> will be created.
-   * @return The collection to which the substrings were added. This is
-   *         syntactic sugar to allow call chaining.
-   * @deprecated see the detailed instructions under
-   *     {@link #split(String, String, boolean)}
-   */
-  @Deprecated
-  public static Collection<String> string2Collection(
-      String in,
-      String delimiter,
-      boolean doStrip,
-      Collection<String> collection) {
-    if (in == null) {
-      return null;
-    }
-    if (collection == null) {
-      collection = new ArrayList<String>();
-    }
-    if (delimiter == null || delimiter.length() == 0) {
-      collection.add(in);
-      return collection;
-    }
-
-    int fromIndex = 0;
-    int pos;
-    while ((pos = in.indexOf(delimiter, fromIndex)) >= 0) {
-      String interim = in.substring(fromIndex, pos);
-      if (doStrip) {
-        interim = strip(interim);
-      }
-      if (!doStrip || interim.length() > 0) {
-        collection.add(interim);
-      }
-
-      fromIndex = pos + delimiter.length();
-    }
-
-    String interim = in.substring(fromIndex);
-    if (doStrip) {
-      interim = strip(interim);
-    }
-    if (!doStrip || interim.length() > 0) {
-      collection.add(interim);
-    }
-
-    return collection;
-  }
-
-  /**
-   * This converts a string to a Map. It will first split the string into
-   * entries using delimEntry. Then each entry is split into a key and a value
-   * using delimKey. By default we strip the keys. Use doStripEntry to strip
-   * also the entries.
-   *
-   * Note that this method returns a {@link HashMap}, which means that entries
-   * will be in no particular order. See {@link #stringToOrderedMap}.
-   *
-   * @param in the string to be processed
-   * @param delimEntry delimiter for the entries
-   * @param delimKey delimiter between keys and values
-   * @param doStripEntry strip entries before inserting in the map
-   *
-   * @return HashMap
-   */
-  public static HashMap<String, String> string2Map(
-      String in, String delimEntry, String delimKey,
-      boolean doStripEntry) {
-    if (in == null) {
-      return null;
-    }
-
-    return stringToMapImpl(new HashMap<String, String>(), in, delimEntry,
-        delimKey, doStripEntry);
-  }
-
-  /**
-   * This converts a string to a Map, with entries in the same order as the
-   * key/value pairs in the input string. It will first split the string into
-   * entries using delimEntry. Then each entry is split into a key and a value
-   * using delimKey. By default we strip the keys. Use doStripEntry to strip
-   * also the entries.
-   *
-   * @param in the string to be processed
-   * @param delimEntry delimiter for the entries
-   * @param delimKey delimiter between keys and values
-   * @param doStripEntry strip entries before inserting in the map
-   *
-   * @return key/value pairs as a Map, in order
-   */
-  public static Map<String, String> stringToOrderedMap(
-      String in, String delimEntry, String delimKey,
-      boolean doStripEntry) {
-    if (in == null) {
-      return null;
-    }
-
-    return stringToMapImpl(new LinkedHashMap<String, String>(), in, delimEntry,
-        delimKey, doStripEntry);
-  }
-
-  /**
-   * This adds key/value pairs from the given string to the given Map.
-   * It will first split the string into entries using delimEntry. Then each
-   * entry is split into a key and a value using delimKey. By default we
-   * strip the keys. Use doStripEntry to strip also the entries.
-   *
-   * @param out - Map to output into
-   * @param in - the string to be processed
-   * @param delimEntry - delimiter for the entries
-   * @param delimKey - delimiter between keys and values
-   * @param doStripEntry - strip entries before inserting in the map
-   * @return out, for caller's convenience
-   */
-  private static <T extends Map<String, String>> T stringToMapImpl(T out,
-      String in, String delimEntry, String delimKey, boolean doStripEntry) {
-
-    if (isEmpty(delimEntry) || isEmpty(delimKey)) {
-      out.put(strip(in), "");
-      return out;
-    }
-
-    Iterator<String> it = string2List(in, delimEntry, false).iterator();
-    int len = delimKey.length();
-    while (it.hasNext()) {
-      String entry = it.next();
-      int pos = entry.indexOf(delimKey);
-      if (pos > 0) {
-        String value = entry.substring(pos + len);
-        if (doStripEntry) {
-          value = strip(value);
-        }
-        out.put(strip(entry.substring(0, pos)), value);
-      } else {
-        out.put(strip(entry), "");
-      }
-    }
-
-    return out;
-  }
-
-  /**
-   * This function concatenates the elements of a Map in a string with form
-   *  "<key1><sepKey><value1><sepEntry>...<keyN><sepKey><valueN>"
-   *
-   * @param in - the map to be converted
-   * @param sepKey - the separator to put between key and value
-   * @param sepEntry - the separator to put between map entries
-   * @return String
-   * @deprecated create a {@link MapJoiner}, for example {@code
-   *     Joiner.on(sepEntry).withKeyValueSeparator(sepKey)}. Ensure that your
-   *     map is non-null and use this map joiner's {@link MapJoiner#join(Map)}
-   *     method. To preserve behavior exactly, just in-line this method call.
-   */
-  @Deprecated public static <K, V> String map2String(
-      Map<K, V> in, String sepKey, String sepEntry) {
-    return (in == null) ? null : Joiner
-        .on(sepEntry)
-        .useForNull("null")
-        .withKeyValueSeparator(sepKey)
-        .join(in);
-  }
-
-  /**
-   * Given a map, creates and returns a new map in which all keys are the
-   * lower-cased version of each key.
-   *
-   * @param map A map containing String keys to be lowercased
-   * @throws IllegalArgumentException if the map contains duplicate string keys
-   *           after lower casing
-   */
-  public static <V> Map<String, V> lowercaseKeys(Map<String, V> map) {
-    Map<String, V> result = new HashMap<String, V>(map.size());
-    for (Map.Entry<String, V> entry : map.entrySet()) {
-      String key = entry.getKey();
-      if (result.containsKey(key.toLowerCase())) {
-        throw new IllegalArgumentException(
-            "Duplicate string key in map when lower casing");
-      }
-      result.put(key.toLowerCase(), entry.getValue());
-    }
-    return result;
-  }
-
-  /**
-   * Replaces any string of adjacent whitespace characters with the whitespace
-   * character " ".
-   *
-   * @param str the string you want to munge
-   * @return String with no more excessive whitespace!
-   * @deprecated ensure the string is not null and use {@code
-   *     CharMatcher.LEGACY_WHITESPACE.collapseFrom(str, ' ')}; also consider
-   *     whether you really want the legacy whitespace definition, or something
-   *     more standard like {@link CharMatcher#WHITESPACE}.
-   */
-  @Deprecated public static String collapseWhitespace(String str) {
-    return (str == null) ? null
-        : CharMatcher.LEGACY_WHITESPACE.collapseFrom(str, ' ');
-  }
-
-  /**
-   * Replaces any string of matched characters with the supplied string.<p>
-   *
-   * This is a more general version of collapseWhitespace.
-   *
-   * <pre>
-   *   E.g. collapse("hello     world", " ", "::")
-   *   will return the following string: "hello::world"
-   * </pre>
-   *
-   * @param str the string you want to munge
-   * @param chars all of the characters to be considered for munge
-   * @param replacement the replacement string
-   * @return munged and replaced string.
-   * @deprecated if {@code replacement} is the empty string, use {@link
-   *     CharMatcher#removeFrom(CharSequence)}; if it is a single character,
-   *     use {@link CharMatcher#collapseFrom(CharSequence, char)}; for longer
-   *     replacement strings use {@link String#replaceAll(String, String)} with
-   *     a regular expression that matches one or more occurrences of {@code
-   *     chars}. In all cases you must first ensure that {@code str} is not
-   *     null.
-   */
-  @Deprecated public static String collapse(
-      String str, String chars, String replacement) {
-    if (str == null) {
-      return null;
-    }
-
-    StringBuilder newStr = new StringBuilder();
-
-    boolean prevCharMatched = false;
-    char c;
-    for (int i = 0; i < str.length(); i++) {
-      c = str.charAt(i);
-      if (chars.indexOf(c) != -1) {
-        // this character is matched
-        if (prevCharMatched) {
-          // apparently a string of matched chars, so don't append anything
-          // to the string
-          continue;
-        }
-        prevCharMatched = true;
-        newStr.append(replacement);
-      } else {
-        prevCharMatched = false;
-        newStr.append(c);
-      }
-    }
-
-    return newStr.toString();
-  }
-
-  /**
-   * Returns a string with all sequences of ISO control chars (0x00 to 0x1F and
-   * 0x7F to 0x9F) replaced by the supplied string.  ISO control characters are
-   * identified via {@link Character#isISOControl(char)}.
-   *
-   * @param str the string you want to strip of ISO control chars
-   * @param replacement the replacement string
-   * @return a String with all control characters replaced by the replacement
-   * string, or null if input is null.
-   * @deprecated use {@link CharMatcher#JAVA_ISO_CONTROL}. If {@code
-   *     replacement} is the empty string, use {@link
-   *     CharMatcher#removeFrom(CharSequence)}; if it is a single character,
-   *     use {@link CharMatcher#collapseFrom(CharSequence, char)}; for longer
-   *     replacement strings use
-   *     {@code str.replaceAll("\p{Cntrl}+", replacement)}.
-   *     In all cases you must first ensure that {@code str} is not null.
-   */
-  @Deprecated public static String collapseControlChars(
-      String str, String replacement) {
-    /*
-     * We re-implement the StringUtil.collapse() loop here rather than call
-     * collapse() with an input String of control chars, because matching via
-     * isISOControl() is about 10x faster.
-     */
-    if (str == null) {
-      return null;
-    }
-
-    StringBuilder newStr = new StringBuilder();
-
-    boolean prevCharMatched = false;
-    char c;
-    for (int i = 0; i < str.length(); i++) {
-      c = str.charAt(i);
-      if (Character.isISOControl(c)) {
-        // this character is matched
-        if (prevCharMatched) {
-          // apparently a string of matched chars, so don't append anything
-          // to the string
-          continue;
-        }
-        prevCharMatched = true;
-        newStr.append(replacement);
-      } else {
-        prevCharMatched = false;
-        newStr.append(c);
-      }
-    }
-
-    return newStr.toString();
-  }
-
-  /**
-   * Read a String of up to maxLength bytes from an InputStream.
-   *
-   * <p>Note that this method uses the default platform encoding, and expects
-   * that encoding to be single-byte, which is not always the case. Its use
-   * is discouraged. For reading the entire stream (maxLength == -1) you can use:
-   * <pre>
-   *   CharStreams.toString(new InputStreamReader(is, Charsets.ISO_8859_1))
-   * </pre>
-   * {@code CharStreams} is in the {@code com.google.common.io} package.
-   *
-   * <p>For maxLength >= 0 a literal translation would be
-   * <pre>
-   *   CharStreams.toString(new InputStreamReader(
-   *       new LimitInputStream(is, maxLength), Charsets.ISO_8859_1))
-   * </pre>
-   * For multi-byte encodings that is broken because the limit could end in
-   * the middle of the character--it would be better to limit the reader than
-   * the underlying stream.
-   *
-   * @param is input stream
-   * @param maxLength max number of bytes to read from "is". If this is -1, we
-   *          read everything.
-   *
-   * @return String up to maxLength bytes, read from "is"
-   * @deprecated see the advice above
-   */
-  @Deprecated public static String stream2String(InputStream is, int maxLength)
-      throws IOException {
-    byte[] buffer = new byte[4096];
-    StringWriter sw = new StringWriter();
-    int totalRead = 0;
-    int read = 0;
-
-    do {
-      sw.write(new String(buffer, 0, read));
-      totalRead += read;
-      read = is.read(buffer, 0, buffer.length);
-    } while (((-1 == maxLength) || (totalRead < maxLength)) && (read != -1));
-
-    return sw.toString();
-  }
-
-  /**
-   * Parse a list of substrings separated by a given delimiter. The delimiter
-   * can also appear in substrings (just double them):
-   *
-   * parseDelimitedString("this|is", '|') returns ["this","is"]
-   * parseDelimitedString("this||is", '|') returns ["this|is"]
-   *
-   * @param list String containing delimited substrings
-   * @param delimiter Delimiter (anything except ' ' is allowed)
-   *
-   * @return String[] A String array of parsed substrings
-   */
-  public static String[] parseDelimitedList(String list,
-                                            char delimiter) {
-    String delim = "" + delimiter;
-    // Append a sentinel of delimiter + space
-    // (see comments below for more info)
-    StringTokenizer st = new StringTokenizer(list + delim + " ",
-                                             delim,
-                                             true);
-    ArrayList<String> v = new ArrayList<String>();
-    String lastToken = "";
-    StringBuilder word = new StringBuilder();
-
-    // We keep a sliding window of 2 tokens
-    //
-    // delimiter : delimiter -> append delimiter to current word
-    //                          and clear most recent token
-    //                          (so delim : delim : delim will not
-    //                          be treated as two escaped delims.)
-    //
-    // tok : delimiter -> append tok to current word
-    //
-    // delimiter : tok -> add current word to list, and clear it.
-    //                    (We append a sentinel that conforms to this
-    //                    pattern to make sure we've pushed every parsed token)
-    while (st.hasMoreTokens()) {
-      String tok = st.nextToken();
-      if (lastToken != null) {
-        if (tok.equals(delim)) {
-          word.append(lastToken);
-          if (lastToken.equals(delim)) { tok = null; }
-        } else {
-          if (word.length() != 0) {
-            v.add(word.toString());
-          }
-          word.setLength(0);
-        }
-      }
-      lastToken = tok;
-    }
-
-    return v.toArray(new String[0]);
-  }
-
-  /**
-   * Compares two strings, guarding against nulls.
-   *
-   * @param nullsAreGreater true if nulls should be greater than any string,
-   *  false is less than.
-   * @deprecated use {@link String#CASE_INSENSITIVE_ORDER}, together with
-   *     {@link com.google.common.collect.Ordering#nullsFirst()} or
-   *     {@link com.google.common.collect.Ordering#nullsLast()} if
-   *     needed
-   */
-  @Deprecated public static int compareToIgnoreCase(String s1, String s2,
-      boolean nullsAreGreater) {
-    if (s1 == s2) {
-      return 0; // Either both the same String, or both null
-    }
-    if (s1 == null) {
-      return nullsAreGreater ? 1 : -1;
-    }
-    if (s2 == null) {
-      return nullsAreGreater ? -1 : 1;
-    }
-    return s1.compareToIgnoreCase(s2);
-  }
-
-  /**
-   * Splits s with delimiters in delimiter and returns the last token
-   */
-  public static String lastToken(String s, String delimiter) {
-    return s.substring(CharMatcher.anyOf(delimiter).lastIndexIn(s) + 1);
-  }
-
-  private static final Pattern characterReferencePattern =
-      Pattern.compile("&#?[a-zA-Z0-9]{1,8};");
-
-  /**
-   * Determines if a string contains what looks like an html character
-   * reference. Useful for deciding whether unescaping is necessary.
-   */
-  public static boolean containsCharRef(String s) {
-    return characterReferencePattern.matcher(s).find();
-  }
-
-  /**
-   * Determines if a string is a Hebrew word. A string is considered to be
-   * a Hebrew word if {@link #isHebrew(int)} is true for any of its characters.
-   */
-  public static boolean isHebrew(String s) {
-    int len = s.length();
-    for (int i = 0; i < len; ++i) {
-      if (isHebrew(s.codePointAt(i))) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /**
-   * Determines if a character is a Hebrew character.
-   */
-  public static boolean isHebrew(int codePoint) {
-    return Character.UnicodeBlock.HEBREW.equals(
-               Character.UnicodeBlock.of(codePoint));
-  }
-
-  /**
-   * Determines if a string is a CJK word. A string is considered to be CJK
-   * if {@link #isCjk(char)} is true for any of its characters.
-   */
-  public static boolean isCjk(String s) {
-    int len = s.length();
-    for (int i = 0; i < len; ++i) {
-      if (isCjk(s.codePointAt(i))) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /**
-   * Unicode code blocks containing CJK characters.
-   */
-  private static final Set<Character.UnicodeBlock> CJK_BLOCKS;
-  static {
-    Set<Character.UnicodeBlock> set = new HashSet<Character.UnicodeBlock>();
-    set.add(Character.UnicodeBlock.HANGUL_JAMO);
-    set.add(Character.UnicodeBlock.CJK_RADICALS_SUPPLEMENT);
-    set.add(Character.UnicodeBlock.KANGXI_RADICALS);
-    set.add(Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION);
-    set.add(Character.UnicodeBlock.HIRAGANA);
-    set.add(Character.UnicodeBlock.KATAKANA);
-    set.add(Character.UnicodeBlock.BOPOMOFO);
-    set.add(Character.UnicodeBlock.HANGUL_COMPATIBILITY_JAMO);
-    set.add(Character.UnicodeBlock.KANBUN);
-    set.add(Character.UnicodeBlock.BOPOMOFO_EXTENDED);
-    set.add(Character.UnicodeBlock.KATAKANA_PHONETIC_EXTENSIONS);
-    set.add(Character.UnicodeBlock.ENCLOSED_CJK_LETTERS_AND_MONTHS);
-    set.add(Character.UnicodeBlock.CJK_COMPATIBILITY);
-    set.add(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A);
-    set.add(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS);
-    set.add(Character.UnicodeBlock.HANGUL_SYLLABLES);
-    set.add(Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS);
-    set.add(Character.UnicodeBlock.CJK_COMPATIBILITY_FORMS);
-    set.add(Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS);
-    set.add(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B);
-    set.add(Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT);
-    CJK_BLOCKS = Collections.unmodifiableSet(set);
-  }
-
-  /**
-   * Determines if a character is a CJK ideograph or a character typically
-   * used only in CJK text.
-   *
-   * Note: This function cannot handle supplementary characters. To handle all
-   * Unicode characters, including supplementary characters, use the function
-   * {@link #isCjk(int)}.
-   */
-  public static boolean isCjk(char ch) {
-    return isCjk((int) ch);
-  }
-
-  /**
-   * Determines if a character is a CJK ideograph or a character typically
-   * used only in CJK text.
-   */
-  public static boolean isCjk(int codePoint) {
-    // Time-saving early exit for all Latin-1 characters.
-    if ((codePoint & 0xFFFFFF00) == 0) {
-      return false;
-    }
-
-    return CJK_BLOCKS.contains(Character.UnicodeBlock.of(codePoint));
-  }
-
-  /**
-   * Returns the approximate display width of the string, measured in units of
-   * ascii characters.
-   *
-   * @see StringUtil#displayWidth(char)
-   */
-  public static int displayWidth(String s) {
-    // TODO(kevinb): could reimplement this as
-    // return s.length() * 2 - CharMatcher.SINGLE_WIDTH.countIn(s);
-    int width = 0;
-    int len = s.length();
-    for (int i = 0; i < len; ++i) {
-      width += displayWidth(s.charAt(i));
-    }
-    return width;
-  }
-
-  /**
-   * Returns the approximate display width of the character, measured
-   * in units of ascii characters.
-   *
-   * This method should err on the side of caution. By default, characters
-   * are assumed to have width 2; this covers CJK ideographs, various
-   * symbols and miscellaneous weird scripts. Given below are some Unicode
-   * ranges for which it seems safe to assume that no character is
-   * substantially wider than an ascii character:
-   *   - Latin, extended Latin, even more extended Latin.
-   *   - Greek, extended Greek, Cyrillic.
-   *   - Some symbols (including currency symbols) and punctuation.
-   *   - Half-width Katakana and Hangul.
-   *   - Hebrew
-   *   - Arabic
-   *   - Thai
-   * Characters in these ranges are given a width of 1.
-   *
-   * IMPORTANT: this function has analogs in C++ (encodingutils.cc,
-   * named UnicodeCharWidth) and JavaScript
-   * (java/com/google/ads/common/frontend/adwordsbase/resources/CreateAdUtil.js),
-   * which need to be updated if you change the implementation here.
-   */
-  public static int displayWidth(char ch) {
-    if (ch <= '\u04f9' ||   // CYRILLIC SMALL LETTER YERU WITH DIAERESIS
-        ch == '\u05be' ||   // HEBREW PUNCTUATION MAQAF
-        (ch >= '\u05d0' && ch <= '\u05ea') ||  // HEBREW LETTER ALEF ... TAV
-        ch == '\u05F3' ||   // HEBREW PUNCTUATION GERESH
-        ch == '\u05f4' ||   // HEBREW PUNCTUATION GERSHAYIM
-        (ch >= '\u0600' && ch <= '\u06ff') || // Block=Arabic
-        (ch >= '\u0750' && ch <= '\u077f') || // Block=Arabic_Supplement
-        (ch >= '\ufb50' && ch <= '\ufdff') || // Block=Arabic_Presentation_Forms-A
-        (ch >= '\ufe70' && ch <= '\ufeff') || // Block=Arabic_Presentation_Forms-B
-        (ch >= '\u1e00' && ch <= '\u20af') || /* LATIN CAPITAL LETTER A WITH RING BELOW
-                                                 ... DRACHMA SIGN */
-        (ch >= '\u2100' && ch <= '\u213a') || // ACCOUNT OF ... ROTATED CAPITAL Q
-        (ch >= '\u0e00' && ch <= '\u0e7f') || // Thai
-        (ch >= '\uff61' && ch <= '\uffdc')) { /* HALFWIDTH IDEOGRAPHIC FULL STOP
-                                                 ... HALFWIDTH HANGUL LETTER I */
-      return 1;
-    }
-    return 2;
-  }
-
-  /**
-   * @return a string representation of the given native array.
-   */
-  public static String toString(float[] iArray) {
-    if (iArray == null) {
-      return "NULL";
-    }
-
-    StringBuilder buffer = new StringBuilder();
-    buffer.append("[");
-    for (int i = 0; i < iArray.length; i++) {
-      buffer.append(iArray[i]);
-      if (i != (iArray.length - 1)) {
-        buffer.append(", ");
-      }
-    }
-    buffer.append("]");
-    return buffer.toString();
-  }
-
-  /**
-   * @return a string representation of the given native array.
-   */
-  public static String toString(long[] iArray) {
-    if (iArray == null) {
-      return "NULL";
-    }
-
-    StringBuilder buffer = new StringBuilder();
-    buffer.append("[");
-    for (int i = 0; i < iArray.length; i++) {
-      buffer.append(iArray[i]);
-      if (i != (iArray.length - 1)) {
-        buffer.append(", ");
-      }
-    }
-    buffer.append("]");
-    return buffer.toString();
-  }
-
-  /**
-   * @return a string representation of the given native array
-   */
-  public static String toString(int[] iArray) {
-    if (iArray == null) {
-      return "NULL";
-    }
-
-    StringBuilder buffer = new StringBuilder();
-    buffer.append("[");
-    for (int i = 0; i < iArray.length; i++) {
-      buffer.append(iArray[i]);
-      if (i != (iArray.length - 1)) {
-        buffer.append(", ");
-      }
-    }
-    buffer.append("]");
-    return buffer.toString();
-  }
-
-  /**
-   * @return a string representation of the given array.
-   */
-  public static String toString(String[] iArray) {
-    if (iArray == null) { return "NULL"; }
-
-    StringBuilder buffer = new StringBuilder();
-    buffer.append("[");
-    for (int i = 0; i < iArray.length; i++) {
-      buffer.append("'").append(iArray[i]).append("'");
-      if (i != iArray.length - 1) {
-        buffer.append(", ");
-      }
-    }
-    buffer.append("]");
-
-    return buffer.toString();
-  }
-
-  /**
-   * Returns the string, in single quotes, or "NULL". Intended only for
-   * logging.
-   *
-   * @param s the string
-   * @return the string, in single quotes, or the string "null" if it's null.
-   */
-  public static String toString(String s) {
-    if (s == null) {
-      return "NULL";
-    } else {
-      return new StringBuilder(s.length() + 2).append("'").append(s)
-                                              .append("'").toString();
-    }
-  }
-
-  /**
-   * @return a string representation of the given native array
-   */
-  public static String toString(int[][] iArray) {
-    if (iArray == null) {
-      return "NULL";
-    }
-
-    StringBuilder buffer = new StringBuilder();
-    buffer.append("[");
-    for (int i = 0; i < iArray.length; i++) {
-      buffer.append("[");
-      for (int j = 0; j < iArray[i].length; j++) {
-        buffer.append(iArray[i][j]);
-        if (j != (iArray[i].length - 1)) {
-          buffer.append(", ");
-        }
-      }
-      buffer.append("]");
-      if (i != iArray.length - 1) {
-        buffer.append(" ");
-      }
-    }
-    buffer.append("]");
-    return buffer.toString();
-  }
-
-  /**
-   * @return a string representation of the given native array.
-   */
-  public static String toString(long[][] iArray) {
-    if (iArray == null) { return "NULL"; }
-
-    StringBuilder buffer = new StringBuilder();
-    buffer.append("[");
-    for (int i = 0; i < iArray.length; i++) {
-      buffer.append("[");
-      for (int j = 0; j < iArray[i].length; j++) {
-        buffer.append(iArray[i][j]);
-        if (j != (iArray[i].length - 1)) {
-          buffer.append(", ");
-        }
-      }
-      buffer.append("]");
-      if (i != iArray.length - 1) {
-        buffer.append(" ");
-      }
-    }
-    buffer.append("]");
-    return buffer.toString();
-  }
-
-  /**
-   * @return a String representation of the given object array.
-   * The strings are obtained by calling toString() on the
-   * underlying objects.
-   */
-  public static String toString(Object[] obj) {
-    if (obj == null) { return "NULL"; }
-    StringBuilder tmp = new StringBuilder();
-    tmp.append("[");
-    for (int i = 0; i < obj.length; i++) {
-      tmp.append(obj[i].toString());
-      if (i != obj.length - 1) {
-        tmp.append(",");
-      }
-    }
-    tmp.append("]");
-    return tmp.toString();
-  }
-
-  private static final char[] HEX_CHARS
-      = { '0', '1', '2', '3', '4', '5', '6', '7',
-          '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-  private static final char[] OCTAL_CHARS = HEX_CHARS;  // ignore the last 8 :)
-
-  /**
-   * Convert a byte array to a hex-encoding string: "a33bff00..."
-   *
-   * @deprecated Use {@link ByteArrays#toHexString}.
-   */
-  @Deprecated public static String bytesToHexString(final byte[] bytes) {
-    return ByteArrays.toHexString(bytes);
-  }
-
-  /**
-   * Convert a byte array to a hex-encoding string with the specified
-   * delimiter: "a3&lt;delimiter&gt;3b&lt;delimiter&gt;ff..."
-   */
-  public static String bytesToHexString(final byte[] bytes,
-      Character delimiter) {
-    StringBuilder hex =
-      new StringBuilder(bytes.length * (delimiter == null ? 2 : 3));
-    int nibble1, nibble2;
-    for (int i = 0; i < bytes.length; i++) {
-      nibble1 = (bytes[i] >>> 4) & 0xf;
-      nibble2 = bytes[i] & 0xf;
-      if (i > 0 && delimiter != null) { hex.append(delimiter.charValue()); }
-      hex.append(HEX_CHARS[nibble1]);
-      hex.append(HEX_CHARS[nibble2]);
-    }
-    return hex.toString();
-  }
-
-  /**
-   * Safely convert the string to uppercase.
-   * @return upper case representation of the String; or null if
-   * the input string is null.
-   */
-  public static String toUpperCase(String src) {
-    if (src == null) {
-      return null;
-    } else {
-      return src.toUpperCase();
-    }
-  }
-
-  /**
-   * Safely convert the string to lowercase.
-   * @return lower case representation of the String; or null if
-   * the input string is null.
-   */
-  public static String toLowerCase(String src) {
-    if (src == null) {
-      return null;
-    } else {
-      return src.toLowerCase();
-    }
-  }
-
-  private static final Pattern dbSpecPattern =
-      Pattern.compile("(.*)\\{(\\d+),(\\d+)\\}(.*)");
-
-  /**
-   * @param dbSpecComponent a single component of a DBDescriptor spec
-   * (e.g. the host or database component). The expected format of the string is:
-   * <br>
-   *             <center>(prefix){(digits),(digits)}(suffix)</center>
-   * </br>
-   * @return a shard expansion of the given String.
-   * Note that unless the pattern is matched exactly, no expansion is
-   * performed and the original string is returned unaltered.
-   * For example, 'db{0,1}.adz' is expanded into 'db0.adz, db1.adz'.
-   * Note that this method is added to StringUtil instead of
-   * DBDescriptor to better encapsulate the choice of regexp implementation.
-   * @throws IllegalArgumentException if the string does not parse.
-   */
-  public static String expandShardNames(String dbSpecComponent)
-      throws IllegalArgumentException, IllegalStateException {
-
-    Matcher matcher = dbSpecPattern.matcher(dbSpecComponent);
-    if (matcher.find()) {
-      try {
-        String prefix = dbSpecComponent.substring(
-          matcher.start(1), matcher.end(1));
-        int minShard =
-          Integer.parseInt(
-            dbSpecComponent.substring(
-              matcher.start(2), matcher.end(2)));
-        int maxShard =
-          Integer.parseInt(
-            dbSpecComponent.substring(
-              matcher.start(3), matcher.end(3)));
-        String suffix = dbSpecComponent.substring(
-          matcher.start(4), matcher.end(4));
-        //Log2.logEvent(prefix + " " + minShard + " " + maxShard + " " + suffix);
-        if (minShard > maxShard) {
-          throw new IllegalArgumentException(
-            "Maximum shard must be greater than or equal to " +
-            "the minimum shard");
-        }
-        StringBuilder tmp = new StringBuilder();
-        for (int shard = minShard; shard <= maxShard; shard++) {
-          tmp.append(prefix).append(shard).append(suffix);
-          if (shard != maxShard) {
-            tmp.append(",");
-          }
-        }
-        return tmp.toString();
-      } catch (NumberFormatException nfex) {
-        throw new IllegalArgumentException(
-          "Malformed DB specification component: " + dbSpecComponent);
-      }
-    } else {
-      return dbSpecComponent;
-    }
-  }
-
-
-  /**
-  * Returns a string that is equivalent to the specified string with its
-  * first character converted to uppercase as by {@link String#toUpperCase()}.
-  * The returned string will have the same value as the specified string if
-  * its first character is non-alphabetic, if its first character is already
-  * uppercase, or if the specified string is of length 0.
-  *
-  * <p>For example:
-  * <pre>
-  *    capitalize("foo bar").equals("Foo bar");
-  *    capitalize("2b or not 2b").equals("2b or not 2b")
-  *    capitalize("Foo bar").equals("Foo bar");
-  *    capitalize("").equals("");
-  * </pre>
-  *
-  * @param s the string whose first character is to be uppercased
-  * @return a string equivalent to <tt>s</tt> with its first character
-  *     converted to uppercase
-  * @throws NullPointerException if <tt>s</tt> is null
-  */
-  public static String capitalize(String s) {
-    if (s.length() == 0) {
-      return s;
-    }
-    char first = s.charAt(0);
-    char capitalized = Character.toUpperCase(first);
-    return (first == capitalized)
-        ? s
-        : capitalized + s.substring(1);
-  }
-
-  /**
-   * Examine a string to see if it starts with a given prefix (case
-   * insensitive). Just like String.startsWith() except doesn't
-   * respect case. Strings are compared in the same way as in
-   * {@link String#equalsIgnoreCase}.
-   *
-   * @param str the string to examine
-   * @param prefix the prefix to look for
-   * @return a boolean indicating if str starts with prefix (case insensitive)
-   */
-  public static boolean startsWithIgnoreCase(String str, String prefix) {
-    return str.regionMatches(true, 0, prefix, 0, prefix.length());
-  }
-
-  /**
-   * Examine a string to see if it ends with a given suffix (case
-   * insensitive). Just like String.endsWith() except doesn't respect
-   * case. Strings are compared in the same way as in
-   * {@link String#equalsIgnoreCase}.
-   *
-   * @param str the string to examine
-   * @param suffix the suffix to look for
-   * @return a boolean indicating if str ends with suffix (case insensitive)
-   */
-  public static boolean endsWithIgnoreCase(String str, String suffix) {
-    int len = suffix.length();
-    return str.regionMatches(true, str.length() - len, suffix, 0, len);
-  }
-
-  /**
-   * @param c one codePoint
-   * @return the number of bytes needed to encode this codePoint in UTF-8
-   */
-  private static int bytesUtf8(int c) {
-    if (c < 0x80) {
-      return 1;
-    } else if (c < 0x00800) {
-      return 2;
-    } else if (c < 0x10000) {
-      return 3;
-    } else if (c < 0x200000) {
-      return 4;
-
-    // RFC 3629 forbids the use of UTF-8 for codePoint greater than 0x10FFFF,
-    // so if the caller respects this RFC, this should not happen
-    } else if (c < 0x4000000) {
-      return 5;
-    } else {
-      return 6;
-    }
-  }
-
-  /**
-   * @param str a string
-   * @return the number of bytes required to represent this string in UTF-8
-   */
-  public static int bytesStorage(String str) {
-    // offsetByCodePoint has a bug if its argument is the result of a
-    // call to substring. To avoid this, we create a new String
-    // See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6242664
-    String s = new String(str);
-
-    int len = 0;
-    for (int i = 0; i < s.length(); i = s.offsetByCodePoints(i, 1)) {
-      len += bytesUtf8(s.codePointAt(i));
-    }
-    return len;
-  }
-
-  /**
-   * @param str a string
-   * @param maxbytes
-   * @return the beginning of the string, so that it uses less than
-   *     maxbytes bytes in UTF-8
-   * @throws IndexOutOfBoundsException if maxbytes is negative
-   */
-  public static String truncateStringForUtf8Storage(String str, int maxbytes) {
-    if (maxbytes < 0) {
-      throw new IndexOutOfBoundsException();
-    }
-
-    // offsetByCodePoint has a bug if its argument is the result of a
-    // call to substring. To avoid this, we create a new String
-    // See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6242664
-    // TODO(cquinn): should be fixed as of 1.5.0_01
-    String s = new String(str);
-
-    int codepoints = 0;
-    int bytesUsed = 0;
-    for (codepoints = 0; codepoints < s.length();
-        codepoints = s.offsetByCodePoints(codepoints, 1)) {
-      int glyphBytes = StringUtil.bytesUtf8(s.codePointAt(codepoints));
-      if (bytesUsed + glyphBytes > maxbytes) {
-        break;
-      }
-      bytesUsed += glyphBytes;
-    }
-    return s.substring(0, codepoints);
-  }
-
-  /**
-   * If the given string is of length {@code maxLength} or less, then it is
-   * returned as is.
-   * If the string is longer than {@code maxLength}, the returned string is
-   * truncated before the last space character on or before
-   * {@code source.charAt(maxLength)}. If the string has no spaces, the
-   * returned string is truncated to {@code maxLength}.
-   *
-   * @param source the string to truncate if necessary
-   * @param maxLength
-   * @return the original string if its length is less than or equal to
-   *     maxLength, otherwise a truncated string as mentioned above
-   */
-  public static String truncateIfNecessary(String source, int maxLength) {
-    if (source.length() <= maxLength) {
-      return source;
-    }
-    String str = unicodePreservingSubstring(source, 0, maxLength);
-
-    @SuppressWarnings("deprecation") // we'll make this go away before that does
-    CharMatcher whitespaceMatcher = CharMatcher.LEGACY_WHITESPACE;
-    String truncated = whitespaceMatcher.trimTrailingFrom(str);
-
-    // We may have had multiple spaces at maxLength, which were stripped away
-    if (truncated.length() < maxLength) {
-      return truncated;
-    }
-    // We have a truncated string of length maxLength. If the next char was a
-    // space, we truncated at a word boundary, so we can return immediately
-    if (Character.isSpaceChar(source.charAt(maxLength))) {
-      return truncated;
-    }
-    // We truncated in the middle of the word. Try to truncate before
-    // the last space, if it exists. Otherwise, return the truncated string
-    for (int i = truncated.length() - 1; i >= 0; --i) {
-      if (Character.isSpaceChar(truncated.charAt(i))) {
-        String substr = truncated.substring(0, i);
-        return whitespaceMatcher.trimTrailingFrom(substr);
-      }
-    }
-    return truncated;
-  }
-
-  /**
-   * If this given string is of length {@code maxLength} or less, it will
-   * be returned as-is.
-   * Otherwise it will be trucated to {@code maxLength}, regardless of whether
-   * there are any space characters in the String. If an ellipsis is requested
-   * to be appended to the truncated String, the String will be truncated so
-   * that the ellipsis will also fit within maxLength.
-   * If no truncation was necessary, no ellipsis will be added.
-   *
-   * @param source the String to truncate if necessary
-   * @param maxLength the maximum number of characters to keep
-   * @param addEllipsis if true, and if the String had to be truncated,
-   *     add "..." to the end of the String before returning. Additionally,
-   *     the ellipsis will only be added if maxLength is greater than 3.
-   * @return the original string if its length is less than or equal to
-   *     maxLength, otherwise a truncated string as mentioned above
-   */
-  public static String truncateAtMaxLength(String source, int maxLength,
-      boolean addEllipsis) {
-
-    if (source.length() <= maxLength) {
-      return source;
-    }
-    if (addEllipsis && maxLength > 3) {
-      return unicodePreservingSubstring(source, 0, maxLength - 3) + "...";
-    }
-    return unicodePreservingSubstring(source, 0, maxLength);
-  }
-
-  /**
-   * Normalizes {@code index} such that it respects Unicode character
-   * boundaries in {@code str}.
-   *
-   * <p>If {@code index} is the low surrogate of a unicode character,
-   * the method returns {@code index - 1}. Otherwise, {@code index} is
-   * returned.
-   *
-   * <p>In the case in which {@code index} falls in an invalid surrogate pair
-   * (e.g. consecutive low surrogates, consecutive high surrogates), or if
-   * if it is not a valid index into {@code str}, the original value of
-   * {@code index} is returned.
-   *
-   * @param str the String
-   * @param index the index to be normalized
-   * @return a normalized index that does not split a Unicode character
-   */
-  public static int unicodePreservingIndex(String str, int index) {
-    if (index > 0 && index < str.length()) {
-      if (Character.isHighSurrogate(str.charAt(index - 1)) &&
-          Character.isLowSurrogate(str.charAt(index))) {
-        return index - 1;
-      }
-    }
-    return index;
-  }
-
-  /**
-   * Returns a substring of {@code str} that respects Unicode character
-   * boundaries.
-   *
-   * <p>The string will never be split between a [high, low] surrogate pair,
-   * as defined by {@link Character#isHighSurrogate} and
-   * {@link Character#isLowSurrogate}.
-   *
-   * <p>If {@code begin} or {@code end} are the low surrogate of a unicode
-   * character, it will be offset by -1.
-   *
-   * <p>This behavior guarantees that
-   * {@code str.equals(StringUtil.unicodePreservingSubstring(str, 0, n) +
-   *     StringUtil.unicodePreservingSubstring(str, n, str.length())) } is
-   * true for all {@code n}.
-   * </pre>
-   *
-   * <p>This means that unlike {@link String#substring(int, int)}, the length of
-   * the returned substring may not necessarily be equivalent to
-   * {@code end - begin}.
-   *
-   * @param str the original String
-   * @param begin the beginning index, inclusive
-   * @param end the ending index, exclusive
-   * @return the specified substring, possibly adjusted in order to not
-   *   split unicode surrogate pairs
-   * @throws IndexOutOfBoundsException if the {@code begin} is negative,
-   *   or {@code end} is larger than the length of {@code str}, or
-   *   {@code begin} is larger than {@code end}
-   */
-  public static String unicodePreservingSubstring(
-      String str, int begin, int end) {
-    return str.substring(unicodePreservingIndex(str, begin),
-        unicodePreservingIndex(str, end));
-  }
-
-  /**
-   * Equivalent to:
-   *
-   * <pre>
-   * {@link #unicodePreservingSubstring(String, int, int)}(
-   *     str, begin, str.length())
-   * </pre>
-   */
-  public static String unicodePreservingSubstring(String str, int begin) {
-    return unicodePreservingSubstring(str, begin, str.length());
-  }
-
-  /**
-   * True iff the given character needs to be escaped in a javascript string
-   * literal.
-   * <p>
-   * We need to escape the following characters in javascript string literals.
-   * <dl>
-   * <dt> \           <dd> the escape character
-   * <dt> ', "        <dd> string delimiters.
-   *                       TODO(msamuel): what about backticks (`) which are
-   *                       non-standard but recognized as attribute delimiters.
-   * <dt> &, <, >, =  <dd> so that a string literal can be embedded in XHTML
-   *                       without further escaping.
-   * </dl>
-   * TODO(msamuel): If we're being paranoid, should we escape + to avoid UTF-7
-   * attacks?
-   * <p>
-   * Unicode format control characters (category Cf) must be escaped since they
-   * are removed by javascript parser in a pre-lex pass.
-   * <br>According to EcmaScript 262 Section 7.1:
-   * <blockquote>
-   *     The format control characters can occur anywhere in the source text of
-   *     an ECMAScript program. These characters are removed from the source
-   *     text before applying the lexical grammar.
-   * </blockquote>
-   * <p>
-   * Additionally, line terminators are not allowed to appear inside strings
-   * and Section 7.3 says
-   * <blockquote>
-   *     The following characters are considered to be line terminators:<pre>
-   *         Code Point Value   Name                  Formal Name
-   *         \u000A             Line Feed             [LF]
-   *         \u000D             Carriage Return       [CR]
-   *         \u2028             Line separator        [LS]
-   *         \u2029             Paragraph separator   [PS]
-   * </pre></blockquote>
-   *
-   * @param codepoint a char instead of an int since the javascript language
-   *    does not support extended unicode.
-   */
-  static boolean mustEscapeCharInJsString(int codepoint) {
-    return JS_ESCAPE_CHARS.contains(codepoint);
-  }
-
-  /**
-   * True iff the given character needs to be escaped in a JSON string literal.
-   * <p>
-   * We need to escape the following characters in JSON string literals.
-   * <dl>
-   * <dt> \           <dd> the escape character
-   * <dt> "           <dd> string delimiter
-   * <dt> 0x00 - 0x1F <dd> control characters
-   * </dl>
-   * <p>
-   * See EcmaScript 262 Section 15.12.1 for the full JSON grammar.
-   */
-  static boolean mustEscapeCharInJsonString(int codepoint) {
-    return JSON_ESCAPE_CHARS.contains(codepoint);
-  }
-
-  /**
-   * Builds a small set of code points.
-   * {@code com.google.common.base} cannot depend on ICU4J, thus avoiding ICU's
-   * {@code UnicodeSet}.
-   * For all other purposes, please use {@code com.ibm.icu.text.UnicodeSet}.
-   */
-  private static class UnicodeSetBuilder {
-    Set<Integer> codePointSet = new HashSet<Integer>();
-
-    UnicodeSetBuilder addCodePoint(int c) {
-      codePointSet.add(c);
-      return this;
-    }
-
-    UnicodeSetBuilder addRange(int from, int to) {
-      for (int i = from; i <= to; i++) {
-        codePointSet.add(i);
-      }
-      return this;
-    }
-
-    Set<Integer> create() {
-      return codePointSet;
-    }
-  }
-
-  private static final Set<Integer> JS_ESCAPE_CHARS = new UnicodeSetBuilder()
-      // All characters in the class of format characters, [:Cf:].
-      // Source: http://unicode.org/cldr/utility/list-unicodeset.jsp.
-      .addCodePoint(0xAD)
-      .addRange(0x600, 0x603)
-      .addCodePoint(0x6DD)
-      .addCodePoint(0x070F)
-      .addRange(0x17B4, 0x17B5)
-      .addRange(0x200B, 0x200F)
-      .addRange(0x202A, 0x202E)
-      .addRange(0x2060, 0x2064)
-      .addRange(0x206A, 0x206F)
-      .addCodePoint(0xFEFF)
-      .addRange(0xFFF9, 0xFFFB)
-      .addRange(0x0001D173, 0x0001D17A)
-      .addCodePoint(0x000E0001)
-      .addRange(0x000E0020, 0x000E007F)
-      // Plus characters mentioned in the docs of mustEscapeCharInJsString().
-      .addCodePoint(0x0000)
-      .addCodePoint(0x000A)
-      .addCodePoint(0x000D)
-      .addRange(0x2028, 0x2029)
-      .addCodePoint(0x0085)
-      .addCodePoint(Character.codePointAt("'", 0))
-      .addCodePoint(Character.codePointAt("\"", 0))
-      .addCodePoint(Character.codePointAt("&", 0))
-      .addCodePoint(Character.codePointAt("<", 0))
-      .addCodePoint(Character.codePointAt(">", 0))
-      .addCodePoint(Character.codePointAt("=", 0))
-      .addCodePoint(Character.codePointAt("\\", 0))
-      .create();
-
-  private static final Set<Integer> JSON_ESCAPE_CHARS = new UnicodeSetBuilder()
-      .addCodePoint(Character.codePointAt("\"", 0))
-      .addCodePoint(Character.codePointAt("\\", 0))
-      .addRange(0x0000, 0x001F)
-      .create();
-
-  /**
-   * <b>To be deprecated:</b> use {@link CharEscapers#xmlEscaper()} instead.
-   */
-  public static String xmlEscape(String s) {
-    return CharEscapers.xmlEscaper().escape(s);
-  }
-
-  /**
-   * <b>To be deprecated:</b> use {@link CharEscapers#asciiHtmlEscaper()} instead.
-   */
-  public static String htmlEscape(String s) {
-    return CharEscapers.asciiHtmlEscaper().escape(s);
-  }
-}
\ No newline at end of file
diff --git a/src/com/android/mail/lib/base/Strings.java b/src/com/android/mail/lib/base/Strings.java
deleted file mode 100644
index 2fd6a97..0000000
--- a/src/com/android/mail/lib/base/Strings.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2010 Google Inc.
- *
- * 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.android.mail.lib.base;
-
-import static com.android.mail.lib.base.Preconditions.checkArgument;
-import static com.android.mail.lib.base.Preconditions.checkNotNull;
-
-import java.util.Formatter;
-
-/**
- * Static utility methods pertaining to {@code String} or {@code CharSequence}
- * instances.
- *
- * @author Kevin Bourrillion
- * @since 3
- */
-public final class Strings {
-  private Strings() {}
-
-  /**
-   * Returns the given string if it is non-null; the empty string otherwise.
-   *
-   * @param string the string to test and possibly return
-   * @return {@code string} itself if it is non-null; {@code ""} if it is null
-   */
-  public static String nullToEmpty(String string) {
-    return (string == null) ? "" : string;
-  }
-
-  /**
-   * Returns the given string if it is nonempty; {@code null} otherwise.
-   *
-   * @param string the string to test and possibly return
-   * @return {@code string} itself if it is nonempty; {@code null} if it is
-   *     empty or null
-   */
-  public static String emptyToNull(String string) {
-    return isNullOrEmpty(string) ? null : string;
-  }
-
-  /**
-   * Returns {@code true} if the given string is null or is the empty string.
-   *
-   * <p>Consider normalizing your string references with {@link #nullToEmpty}.
-   * If you do, you can use {@link String#isEmpty()} instead of this
-   * method, and you won't need special null-safe forms of methods like {@link
-   * String#toUpperCase} either. Or, if you'd like to normalize "in the other
-   * direction," converting empty strings to {@code null}, you can use {@link
-   * #emptyToNull}.
-   *
-   * @param string a string reference to check
-   * @return {@code true} if the string is null or is the empty string
-   */
-  public static boolean isNullOrEmpty(String string) {
-    return string == null || string.length() == 0; // string.isEmpty() in Java 6
-  }
-
-  /**
-   * Returns a string, of length at least {@code minLength}, consisting of
-   * {@code string} prepended with as many copies of {@code padChar} as are
-   * necessary to reach that length. For example,
-   *
-   * <ul>
-   * <li>{@code padStart("7", 3, '0')} returns {@code "007"}
-   * <li>{@code padStart("2010", 3, '0')} returns {@code "2010"}
-   * </ul>
-   *
-   * <p>See {@link Formatter} for a richer set of formatting capabilities.
-   *
-   * @param string the string which should appear at the end of the result
-   * @param minLength the minimum length the resulting string must have. Can be
-   *     zero or negative, in which case the input string is always returned.
-   * @param padChar the character to insert at the beginning of the result until
-   *     the minimum length is reached
-   * @return the padded string
-   */
-  public static String padStart(String string, int minLength, char padChar) {
-    checkNotNull(string);  // eager for GWT.
-    if (string.length() >= minLength) {
-      return string;
-    }
-    StringBuilder sb = new StringBuilder(minLength);
-    for (int i = string.length(); i < minLength; i++) {
-      sb.append(padChar);
-    }
-    sb.append(string);
-    return sb.toString();
-  }
-
-  /**
-   * Returns a string, of length at least {@code minLength}, consisting of
-   * {@code string} appended with as many copies of {@code padChar} as are
-   * necessary to reach that length. For example,
-   *
-   * <ul>
-   * <li>{@code padEnd("4.", 5, '0')} returns {@code "4.000"}
-   * <li>{@code padEnd("2010", 3, '!')} returns {@code "2010"}
-   * </ul>
-   *
-   * <p>See {@link Formatter} for a richer set of formatting capabilities.
-   *
-   * @param string the string which should appear at the beginning of the result
-   * @param minLength the minimum length the resulting string must have. Can be
-   *     zero or negative, in which case the input string is always returned.
-   * @param padChar the character to append to the end of the result until the
-   *     minimum length is reached
-   * @return the padded string
-   */
-  public static String padEnd(String string, int minLength, char padChar) {
-    checkNotNull(string);  // eager for GWT.
-    if (string.length() >= minLength) {
-      return string;
-    }
-    StringBuilder sb = new StringBuilder(minLength);
-    sb.append(string);
-    for (int i = string.length(); i < minLength; i++) {
-      sb.append(padChar);
-    }
-    return sb.toString();
-  }
-
-  /**
-   * Returns a string consisting of a specific number of concatenated copies of
-   * an input string. For example, {@code repeat("hey", 3)} returns the string
-   * {@code "heyheyhey"}.
-   *
-   * @param string any non-null string
-   * @param count the number of times to repeat it; a nonnegative integer
-   * @return a string containing {@code string} repeated {@code count} times
-   *     (the empty string if {@code count} is zero)
-   * @throws IllegalArgumentException if {@code count} is negative
-   */
-  public static String repeat(String string, int count) {
-    checkNotNull(string);  // eager for GWT.
-    checkArgument(count >= 0, "invalid count: %s", count);
-
-    // If this multiplication overflows, a NegativeArraySizeException or
-    // OutOfMemoryError is not far behind
-    StringBuilder builder = new StringBuilder(string.length() * count);
-    for (int i = 0; i < count; i++) {
-      builder.append(string);
-    }
-    return builder.toString();
-  }
-}
diff --git a/src/com/android/mail/lib/base/UnicodeEscaper.java b/src/com/android/mail/lib/base/UnicodeEscaper.java
deleted file mode 100644
index 95eb06e..0000000
--- a/src/com/android/mail/lib/base/UnicodeEscaper.java
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- * Copyright (C) 2008 Google Inc.
- *
- * 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.android.mail.lib.base;
-
-import static com.android.mail.lib.base.Preconditions.checkNotNull;
-import static com.android.mail.lib.base.Preconditions.checkPositionIndexes;
-
-import java.io.IOException;
-
-/**
- * An {@link Escaper} that converts literal text into a format safe for
- * inclusion in a particular context (such as an XML document). Typically (but
- * not always), the inverse process of "unescaping" the text is performed
- * automatically by the relevant parser.
- *
- * <p>For example, an XML escaper would convert the literal string {@code
- * "Foo<Bar>"} into {@code "Foo&lt;Bar&gt;"} to prevent {@code "<Bar>"} from
- * being confused with an XML tag. When the resulting XML document is parsed,
- * the parser API will return this text as the original literal string {@code
- * "Foo<Bar>"}.
- *
- * <p><b>Note:</b> This class is similar to {@link CharEscaper} but with one
- * very important difference. A CharEscaper can only process Java
- * <a href="http://en.wikipedia.org/wiki/UTF-16">UTF16</a> characters in
- * isolation and may not cope when it encounters surrogate pairs. This class
- * facilitates the correct escaping of all Unicode characters.
- *
- * <p>As there are important reasons, including potential security issues, to
- * handle Unicode correctly if you are considering implementing a new escaper
- * you should favor using UnicodeEscaper wherever possible.
- *
- * <p>A {@code UnicodeEscaper} instance is required to be stateless, and safe
- * when used concurrently by multiple threads.
- *
- * <p>Several popular escapers are defined as constants in the class {@link
- * CharEscapers}. To create your own escapers extend this class and implement
- * the {@link #escape(int)} method.
- *
- * @author dbeaumont@google.com (David Beaumont)
- */
-public abstract class UnicodeEscaper extends Escaper {
-  /** The amount of padding (chars) to use when growing the escape buffer. */
-  private static final int DEST_PAD = 32;
-
-  /**
-   * Returns the escaped form of the given Unicode code point, or {@code null}
-   * if this code point does not need to be escaped. When called as part of an
-   * escaping operation, the given code point is guaranteed to be in the range
-   * {@code 0 <= cp <= Character#MAX_CODE_POINT}.
-   *
-   * <p>If an empty array is returned, this effectively strips the input
-   * character from the resulting text.
-   *
-   * <p>If the character does not need to be escaped, this method should return
-   * {@code null}, rather than an array containing the character representation
-   * of the code point. This enables the escaping algorithm to perform more
-   * efficiently.
-   *
-   * <p>If the implementation of this method cannot correctly handle a
-   * particular code point then it should either throw an appropriate runtime
-   * exception or return a suitable replacement character. It must never
-   * silently discard invalid input as this may constitute a security risk.
-   *
-   * @param cp the Unicode code point to escape if necessary
-   * @return the replacement characters, or {@code null} if no escaping was
-   *     needed
-   */
-  protected abstract char[] escape(int cp);
-
-  /**
-   * Scans a sub-sequence of characters from a given {@link CharSequence},
-   * returning the index of the next character that requires escaping.
-   *
-   * <p><b>Note:</b> When implementing an escaper, it is a good idea to override
-   * this method for efficiency. The base class implementation determines
-   * successive Unicode code points and invokes {@link #escape(int)} for each of
-   * them. If the semantics of your escaper are such that code points in the
-   * supplementary range are either all escaped or all unescaped, this method
-   * can be implemented more efficiently using {@link CharSequence#charAt(int)}.
-   *
-   * <p>Note however that if your escaper does not escape characters in the
-   * supplementary range, you should either continue to validate the correctness
-   * of any surrogate characters encountered or provide a clear warning to users
-   * that your escaper does not validate its input.
-   *
-   * <p>See {@link PercentEscaper} for an example.
-   *
-   * @param csq a sequence of characters
-   * @param start the index of the first character to be scanned
-   * @param end the index immediately after the last character to be scanned
-   * @throws IllegalArgumentException if the scanned sub-sequence of {@code csq}
-   *     contains invalid surrogate pairs
-   */
-  protected int nextEscapeIndex(CharSequence csq, int start, int end) {
-    int index = start;
-    while (index < end) {
-      int cp = codePointAt(csq, index, end);
-      if (cp < 0 || escape(cp) != null) {
-        break;
-      }
-      index += Character.isSupplementaryCodePoint(cp) ? 2 : 1;
-    }
-    return index;
-  }
-
-  /**
-   * Returns the escaped form of a given literal string.
-   *
-   * <p>If you are escaping input in arbitrary successive chunks, then it is not
-   * generally safe to use this method. If an input string ends with an
-   * unmatched high surrogate character, then this method will throw
-   * {@link IllegalArgumentException}. You should either ensure your input is
-   * valid <a href="http://en.wikipedia.org/wiki/UTF-16">UTF-16</a> before
-   * calling this method or use an escaped {@link Appendable} (as returned by
-   * {@link #escape(Appendable)}) which can cope with arbitrarily split input.
-   *
-   * <p><b>Note:</b> When implementing an escaper it is a good idea to override
-   * this method for efficiency by inlining the implementation of
-   * {@link #nextEscapeIndex(CharSequence, int, int)} directly. Doing this for
-   * {@link PercentEscaper} more than doubled the performance for unescaped
-   * strings (as measured by {@link CharEscapersBenchmark}).
-   *
-   * @param string the literal string to be escaped
-   * @return the escaped form of {@code string}
-   * @throws NullPointerException if {@code string} is null
-   * @throws IllegalArgumentException if invalid surrogate characters are
-   *         encountered
-   */
-  @Override
-  public String escape(String string) {
-    checkNotNull(string);
-    int end = string.length();
-    int index = nextEscapeIndex(string, 0, end);
-    return index == end ? string : escapeSlow(string, index);
-  }
-
-  /**
-   * Returns the escaped form of a given literal string, starting at the given
-   * index.  This method is called by the {@link #escape(String)} method when it
-   * discovers that escaping is required.  It is protected to allow subclasses
-   * to override the fastpath escaping function to inline their escaping test.
-   * See {@link CharEscaperBuilder} for an example usage.
-   *
-   * <p>This method is not reentrant and may only be invoked by the top level
-   * {@link #escape(String)} method.
-   *
-   * @param s the literal string to be escaped
-   * @param index the index to start escaping from
-   * @return the escaped form of {@code string}
-   * @throws NullPointerException if {@code string} is null
-   * @throws IllegalArgumentException if invalid surrogate characters are
-   *         encountered
-   */
-  protected final String escapeSlow(String s, int index) {
-    int end = s.length();
-
-    // Get a destination buffer and setup some loop variables.
-    char[] dest = Platform.charBufferFromThreadLocal();
-    int destIndex = 0;
-    int unescapedChunkStart = 0;
-
-    while (index < end) {
-      int cp = codePointAt(s, index, end);
-      if (cp < 0) {
-        throw new IllegalArgumentException(
-            "Trailing high surrogate at end of input");
-      }
-      // It is possible for this to return null because nextEscapeIndex() may
-      // (for performance reasons) yield some false positives but it must never
-      // give false negatives.
-      char[] escaped = escape(cp);
-      int nextIndex = index + (Character.isSupplementaryCodePoint(cp) ? 2 : 1);
-      if (escaped != null) {
-        int charsSkipped = index - unescapedChunkStart;
-
-        // This is the size needed to add the replacement, not the full
-        // size needed by the string.  We only regrow when we absolutely must.
-        int sizeNeeded = destIndex + charsSkipped + escaped.length;
-        if (dest.length < sizeNeeded) {
-          int destLength = sizeNeeded + (end - index) + DEST_PAD;
-          dest = growBuffer(dest, destIndex, destLength);
-        }
-        // If we have skipped any characters, we need to copy them now.
-        if (charsSkipped > 0) {
-          s.getChars(unescapedChunkStart, index, dest, destIndex);
-          destIndex += charsSkipped;
-        }
-        if (escaped.length > 0) {
-          System.arraycopy(escaped, 0, dest, destIndex, escaped.length);
-          destIndex += escaped.length;
-        }
-        // If we dealt with an escaped character, reset the unescaped range.
-        unescapedChunkStart = nextIndex;
-      }
-      index = nextEscapeIndex(s, nextIndex, end);
-    }
-
-    // Process trailing unescaped characters - no need to account for escaped
-    // length or padding the allocation.
-    int charsSkipped = end - unescapedChunkStart;
-    if (charsSkipped > 0) {
-      int endIndex = destIndex + charsSkipped;
-      if (dest.length < endIndex) {
-        dest = growBuffer(dest, destIndex, endIndex);
-      }
-      s.getChars(unescapedChunkStart, end, dest, destIndex);
-      destIndex = endIndex;
-    }
-    return new String(dest, 0, destIndex);
-  }
-
-  /**
-   * Returns an {@code Appendable} instance which automatically escapes all
-   * text appended to it before passing the resulting text to an underlying
-   * {@code Appendable}.
-   *
-   * <p>Unlike {@link #escape(String)} it is permitted to append arbitrarily
-   * split input to this Appendable, including input that is split over a
-   * surrogate pair. In this case the pending high surrogate character will not
-   * be processed until the corresponding low surrogate is appended. This means
-   * that a trailing high surrogate character at the end of the input cannot be
-   * detected and will be silently ignored. This is unavoidable since the
-   * Appendable interface has no {@code close()} method, and it is impossible to
-   * determine when the last characters have been appended.
-   *
-   * <p>The methods of the returned object will propagate any exceptions thrown
-   * by the underlying {@code Appendable}.
-   *
-   * <p>For well formed <a href="http://en.wikipedia.org/wiki/UTF-16">UTF-16</a>
-   * the escaping behavior is identical to that of {@link #escape(String)} and
-   * the following code is equivalent to (but much slower than)
-   * {@code escaper.escape(string)}: <pre>{@code
-   *
-   *   StringBuilder sb = new StringBuilder();
-   *   escaper.escape(sb).append(string);
-   *   return sb.toString();}</pre>
-   *
-   * @param out the underlying {@code Appendable} to append escaped output to
-   * @return an {@code Appendable} which passes text to {@code out} after
-   *     escaping it
-   * @throws NullPointerException if {@code out} is null
-   * @throws IllegalArgumentException if invalid surrogate characters are
-   *         encountered
-   *
-   * TODO(dbeaumont): Maybe return a Writer here so we have a close() method
-   */
-  @Override
-  public Appendable escape(final Appendable out) {
-    checkNotNull(out);
-
-    return new Appendable() {
-      char pendingHighSurrogate = 0;
-
-      @Override
-      public Appendable append(CharSequence csq) throws IOException {
-        return append(csq, 0, csq.length());
-      }
-
-      @Override
-      public Appendable append(CharSequence csq, int start, int end)
-          throws IOException {
-        checkNotNull(csq);
-        checkPositionIndexes(start, end, csq.length());
-
-        // If there is a pending high surrogate, handle it and start at the
-        // next character.
-        if (pendingHighSurrogate != 0 && start < end) {
-          completeSurrogatePair(csq.charAt(start++));
-        }
-
-        if (start < end) {
-          // If the string ends with a high surrogate, store it for the next
-          // append, and skip that character from the current escaping.
-          char last = csq.charAt(end - 1);
-          if (Character.isHighSurrogate(last)) {
-            pendingHighSurrogate = last;
-            end--;
-          }
-
-          // Escape the subsequence from start to end, which cannot legally
-          // contain an unpaired surrogate
-          out.append(escape(csq.subSequence(start, end).toString()));
-        }
-        return this;
-      }
-
-      @Override
-      public Appendable append(char c) throws IOException {
-        if (pendingHighSurrogate != 0) {
-          completeSurrogatePair(c);
-        } else if (Character.isHighSurrogate(c)) {
-          pendingHighSurrogate = c;
-        } else {
-          if (Character.isLowSurrogate(c)) {
-            throw new IllegalArgumentException(
-                "Unexpected low surrogate character '" + c +
-                "' with value " + (int) c);
-          }
-          // This is a normal (non surrogate) char.
-          char[] escaped = escape(c);
-          if (escaped != null) {
-            outputChars(escaped);
-          } else {
-            out.append(c);
-          }
-        }
-        return this;
-      }
-
-      /**
-       * Our last append operation ended halfway through a surrogate pair so we
-       * complete the surrogate pair using {@code c}, which must be a low
-       * surrogate.
-       */
-      private void completeSurrogatePair(char c) throws IOException {
-        if (!Character.isLowSurrogate(c)) {
-          throw new IllegalArgumentException(
-              "Expected low surrogate character but got '" + c +
-              "' with value " + (int) c);
-        }
-        char[] escaped = escape(
-            Character.toCodePoint(pendingHighSurrogate, c));
-        if (escaped != null) {
-          outputChars(escaped);
-        } else {
-          out.append(pendingHighSurrogate);
-          out.append(c);
-        }
-        pendingHighSurrogate = 0;
-      }
-
-      /**
-       * Output some characters to the underlying appendable.
-       */
-      private void outputChars(char[] chars) throws IOException {
-        for (int n = 0; n < chars.length; n++) {
-          out.append(chars[n]);
-        }
-      }
-    };
-  }
-
-  /**
-   * Returns the Unicode code point of the character at the given index.
-   *
-   * <p>Unlike {@link Character#codePointAt(CharSequence, int)} or
-   * {@link String#codePointAt(int)} this method will never fail silently when
-   * encountering an invalid surrogate pair.
-   *
-   * <p>The behaviour of this method is as follows:
-   * <ol>
-   * <li>If {@code index >= end}, {@link IndexOutOfBoundsException} is thrown.
-   * <li><b>If the character at the specified index is not a surrogate, it is
-   *     returned.</b>
-   * <li>If the first character was a high surrogate value, then an attempt is
-   *     made to read the next character.
-   *     <ol>
-   *     <li><b>If the end of the sequence was reached, the negated value of
-   *         the trailing high surrogate is returned.</b>
-   *     <li><b>If the next character was a valid low surrogate, the code point
-   *         value of the high/low surrogate pair is returned.</b>
-   *     <li>If the next character was not a low surrogate value, then
-   *         {@link IllegalArgumentException} is thrown.
-   *     </ol>
-   * <li>If the first character was a low surrogate value,
-   *     {@link IllegalArgumentException} is thrown.
-   * </ol>
-   *
-   * @param seq the sequence of characters from which to decode the code point
-   * @param index the index of the first character to decode
-   * @param end the index beyond the last valid character to decode
-   * @return the Unicode code point for the given index or the negated value of
-   *         the trailing high surrogate character at the end of the sequence
-   */
-  protected static final int codePointAt(CharSequence seq, int index, int end) {
-    if (index < end) {
-      char c1 = seq.charAt(index++);
-      if (c1 < Character.MIN_HIGH_SURROGATE ||
-          c1 > Character.MAX_LOW_SURROGATE) {
-        // Fast path (first test is probably all we need to do)
-        return c1;
-      } else if (c1 <= Character.MAX_HIGH_SURROGATE) {
-        // If the high surrogate was the last character, return its inverse
-        if (index == end) {
-          return -c1;
-        }
-        // Otherwise look for the low surrogate following it
-        char c2 = seq.charAt(index);
-        if (Character.isLowSurrogate(c2)) {
-          return Character.toCodePoint(c1, c2);
-        }
-        throw new IllegalArgumentException(
-            "Expected low surrogate but got char '" + c2 +
-            "' with value " + (int) c2 + " at index " + index);
-      } else {
-        throw new IllegalArgumentException(
-            "Unexpected low surrogate character '" + c1 +
-            "' with value " + (int) c1 + " at index " + (index - 1));
-      }
-    }
-    throw new IndexOutOfBoundsException("Index exceeds specified range");
-  }
-
-  /**
-   * Helper method to grow the character buffer as needed, this only happens
-   * once in a while so it's ok if it's in a method call.  If the index passed
-   * in is 0 then no copying will be done.
-   */
-  private static final char[] growBuffer(char[] dest, int index, int size) {
-    char[] copy = new char[size];
-    if (index > 0) {
-      System.arraycopy(dest, 0, copy, 0, index);
-    }
-    return copy;
-  }
-}
\ No newline at end of file
diff --git a/src/com/android/mail/lib/base/X.java b/src/com/android/mail/lib/base/X.java
deleted file mode 100644
index 62bf032..0000000
--- a/src/com/android/mail/lib/base/X.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2000 Google Inc.
- *
- * 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.android.mail.lib.base;
-
-/**
- * A utility class that contains some very widely used functionality.
- * This class is named "X" just to get a short name that can be typed
- * everywhere without cluttering up the code.  For example, it
- * seems a lot less verbose to say: "X.assertTrue(empty())" instead of
- * "Assert.assertTrue(empty())".
- *
- * <p>Consider using {@link Preconditions} instead though.
- *
- * <p>If your application is using JDK 1.4, feel free to use the built-in
- * assert() methods instead. <b>NOTE:</b> Except remember that JDK assertions
- * are not normally enabled unless you pass the -ea flag to the jvm.
- */
-public final class X {
-
-  /**
-   * This class should not be instantiated. It provides static methods
-   * only.
-   */
-  private X() {}
-
-  /**
-   * Raise a runtime exception if the supplied argument is false (note: if you
-   * are checking a precondition, please use {@link Preconditions} instead).
-   */
-  public static void assertTrue(boolean b) {
-    if (!b)
-      throw new RuntimeException("Assertion failed");
-  }
-
-  /**
-   * Raise a runtime exception if the supplied argument is false and print
-   * out the error message (note: if you are checking a precondition, please use
-   * {@link Preconditions} instead).
-   */
-  public static void assertTrue(boolean b, String msg) {
-    if (!b)
-      throw new RuntimeException("Assertion failed: " + msg);
-  }
-}
\ No newline at end of file
diff --git a/src/com/android/mail/lib/html/parser/HTML.java b/src/com/android/mail/lib/html/parser/HTML.java
deleted file mode 100644
index 0ed05f7..0000000
--- a/src/com/android/mail/lib/html/parser/HTML.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/**
- * Copyright (c) 2004, Google Inc.
- *
- * 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.android.mail.lib.html.parser;
-
-import com.android.mail.lib.base.Preconditions;
-
-import java.util.Set;
-
-/**
- * HTML class defines Element and Attribute classes.
- *
- * @author jlim@google.com (Jing Yee Lim)
- */
-public final class HTML {
-
-  /**
-   * Html element
-   */
-  public static final class Element {
-
-    // TODO(ptucker) other candidate types are list and form elements. Better for this to be
-    // enumerated type.
-    /** Types */
-    public static final int NO_TYPE = 0;
-    public static final int TABLE_TYPE = 1;
-
-    /**
-     * INLINE - charater level elements and text strings
-     * BLOCK  - block-like elements; e.g., paragraphs and lists
-     * NONE   - everything else
-     */
-    public enum Flow {
-      INLINE,
-      BLOCK,
-      NONE
-    }
-
-    private final String name;
-    private final int type;
-    private final boolean empty;
-    private final boolean optionalEndTag;
-    private final boolean breaksFlow;
-    private final Flow flow;
-
-    /**
-     * Construct an Element.
-     *
-     * NOTE: Even though breaksFlow and flow are named similarly, they're not quite the same thing.
-     * Flow refers to whether the element is inherently character or block level. Breaks flow
-     * refers to whether it forces a line break.
-     *
-     * @throws IllegalArgumentException if name or flow is null.
-     */
-    public Element(String name, int type, boolean empty,
-                   boolean optionalEndTag, boolean breaksFlow, Flow flow) {
-      Preconditions.checkNotNull(name, "Element name can not be null");
-      Preconditions.checkNotNull(flow, "Element flow can not be null");
-      this.name = name;
-      this.type = type;
-      this.empty = empty;
-      this.optionalEndTag = optionalEndTag;
-      this.breaksFlow = breaksFlow;
-      this.flow = flow;
-    }
-
-    /**
-     * Construct an Element with inline=true.
-     */
-    public Element(String name, int type, boolean empty,
-                   boolean optionalEndTag, boolean breaksFlow) {
-      this(name, type, empty, optionalEndTag, breaksFlow, Flow.NONE);
-    }
-
-    /** Name of the element, in lowercase, e.g. "a", "br" */
-    public String getName() {
-      return name;
-    }
-
-    /** Type, e.g. TABLE_TYPE */
-    public int getType() {
-      return type;
-    }
-
-    /** True if it's empty, has no inner elements or end tag */
-    public boolean isEmpty() {
-      return empty;
-    }
-
-    /** True if the end tag is optional */
-    public boolean isEndTagOptional() {
-      return optionalEndTag;
-    }
-
-    /**
-     * True if it breaks the flow, and may force a new line before/after the
-     * tag.
-     */
-    public boolean breaksFlow() {
-      return breaksFlow;
-    }
-
-    /** Flow type. */
-    public Flow getFlow() {
-      return flow;
-    }
-
-    /**
-     * @return just name, not proper HTML
-     */
-    @Override
-    public String toString() {
-      return name;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (o == this) {
-        return true;
-      }
-      if (o instanceof HTML.Element) {
-        HTML.Element that = (HTML.Element) o;
-        return this.name.equals(that.name);
-      }
-      return false;
-    }
-
-    @Override
-    public int hashCode() {
-      return this.name.hashCode();
-    }
-  }
-
-  /**
-   * Html attribute
-   */
-  public static final class Attribute {
-    /** Value types */
-    public static final int NO_TYPE = 0;
-    public static final int URI_TYPE = 1;
-    public static final int SCRIPT_TYPE = 2;
-    public static final int ENUM_TYPE = 3;
-    public static final int BOOLEAN_TYPE = 4;
-
-    /** Name of the element, e.g. "HREF" */
-    private final String name;
-
-    /** Type of the attribute value, e.g. URI_TYPE */
-    private final int type;
-
-    /** The list of allowed values, or null if any value is allowed */
-    private final Set<String> values;
-
-    /**
-     * Construct an Attribute
-     * @throws IllegalArgumentException if name is null
-     */
-    public Attribute(String name, int type) {
-      this(name, type, null);
-    }
-
-    /**
-     * Construct an Attribute
-     * @throws IllegalArgumentException if name is null
-     * or if Attribute is of type ENUM_TYPE and the values are null
-     */
-    public Attribute(String name, int type, Set<String> values) {
-      Preconditions.checkNotNull(name, "Attribute name can not be null");
-      Preconditions.checkArgument((values == null) ^ (type == ENUM_TYPE),
-          "Only ENUM_TYPE can have values != null");
-      this.name = name;
-      this.type = type;
-      this.values = values;
-    }
-
-    /** Gets the name of the attribute, in lowercase */
-    public String getName() {
-      return name;
-    }
-
-    /** Gets the type, e.g. URI_TYPE */
-    public int getType() {
-      return type;
-    }
-
-    /**
-     * When called on an attribute of ENUM_TYPE, returns a Set of Strings
-     * containing the allowed attribute values. The return set is guaranteed to
-     * only contain lower case Strings.
-     *
-     * @return a Set of Strings, in lower case, for the allowed attribute
-     *         values.
-     * @throws IllegalStateException if attribute type is not ENUM_TYPE
-     */
-    public Set<String> getEnumValues() {
-      Preconditions.checkState(type == ENUM_TYPE);
-      return values;
-    }
-
-    /**
-     * @return Element name (name only, not proper HTML).
-     */
-    @Override
-    public String toString() {
-      return name;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (o == this) {
-        return true;
-      }
-      if (o instanceof HTML.Attribute) {
-        HTML.Attribute that = (HTML.Attribute) o;
-        return this.name.equals(that.name);
-      }
-      return false;
-    }
-
-    @Override
-    public int hashCode() {
-      return this.name.hashCode();
-    }
-  }
-}
\ No newline at end of file
diff --git a/src/com/android/mail/lib/html/parser/HTML4.java b/src/com/android/mail/lib/html/parser/HTML4.java
deleted file mode 100644
index 9101fa2..0000000
--- a/src/com/android/mail/lib/html/parser/HTML4.java
+++ /dev/null
@@ -1,399 +0,0 @@
-/**
- * Copyright (c) 2004, Google Inc.
- *
- * 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.android.mail.lib.html.parser;
-
-import com.google.common.collect.Maps;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * HTML4 contains HTML 4.0 definitions and specifications
- * See http://www.w3.org/TR/html401/
- * See http://www.w3.org/TR/html401/index/elements.html
- * See http://www.w3.org/TR/html401/index/attributes.html
- *
- * @author jlim@google.com (Jing Yee Lim)
- */
-public final class HTML4 {
-
-  /** Map of all elements */
-  private static final HashMap<String,HTML.Element> elements = Maps.newHashMap();
-
-  /** Map of all attributes */
-  private static final HashMap<String,HTML.Attribute> attributes = Maps.newHashMap();
-
-  /** Default Whitelist */
-  private static final HtmlWhitelist defaultWhitelist = new HtmlWhitelist() {
-    /**
-     * @see com.google.common.html.parser.HtmlWhitelist#lookupElement(String)
-     */
-    public HTML.Element lookupElement(String name) {
-      return HTML4.lookupElement(name);
-    }
-
-    /**
-     * @see com.google.common.html.parser.HtmlWhitelist#lookupAttribute(String)
-     */
-    public HTML.Attribute lookupAttribute(String name) {
-      return HTML4.lookupAttribute(name);
-    }
-  };
-
-  /** Gets the default Whitelist */
-  public static HtmlWhitelist getWhitelist() {
-    return HTML4.defaultWhitelist;
-  }
-
-  /** Looks for a HTML4 element */
-  public static HTML.Element lookupElement(String name) {
-    return elements.get(name.toLowerCase());
-  }
-
-  /** Looks for a HTML4 attribute */
-  public static HTML.Attribute lookupAttribute(String name) {
-    return attributes.get(name.toLowerCase());
-  }
-
-  /**
-   * @return Unmodifiable Map of all valid HTML4 elements.  Key is lowercase
-   * element name.
-   */
-  public static Map<String, HTML.Element> getAllElements() {
-    return Collections.unmodifiableMap(elements);
-  }
-
-  /**
-   * @return Unmodifiable Map of all valid HTML4 attributes.  Key is lowercase
-   * attribute name.
-   */
-  public static Map<String, HTML.Attribute> getAllAttributes() {
-    return Collections.unmodifiableMap(attributes);
-  }
-
-  /** Creates and adds a element to the map */
-  private static HTML.Element addElement(String tag, String flags) {
-    return addElement(tag, flags, HTML.Element.Flow.NONE);
-  }
-
-  /** Creates and adds a element to the map */
-  private static HTML.Element addElement(String tag, String flags, HTML.Element.Flow flow) {
-    return addElement(tag, flags, flow, HTML.Element.NO_TYPE);
-  }
-
-  /** Creates and adds a element to the map */
-  private static HTML.Element addTableElement(String tag, String flags, HTML.Element.Flow flow) {
-    return addElement(tag, flags, flow, HTML.Element.TABLE_TYPE);
-  }
-
-  /** Creates and adds a element to the map */
-  private static HTML.Element addElement(String tag, String flags, HTML.Element.Flow flow,
-      int type) {
-    tag = tag.toLowerCase();
-
-    boolean empty = false;
-    boolean optionalEndTag = false;
-    boolean breaksFlow = false;
-    for (int i = 0; i < flags.length(); i++) {
-      switch (flags.charAt(i)) {
-        case 'E': empty = true; break;
-        case 'O': optionalEndTag = true; break;
-        case 'B': breaksFlow = true; break;
-        default: throw new Error("Unknown element flag");
-      }
-    }
-    HTML.Element element = new HTML.Element(tag, type, empty, optionalEndTag, breaksFlow, flow);
-    elements.put(tag, element);
-    return element;
-  }
-
-  /** Creates and add an attribute to the map */
-  private static HTML.Attribute addAttribute(String attribute) {
-    return addAttribute(attribute, HTML.Attribute.NO_TYPE);
-  }
-
-  private static HTML.Attribute addAttribute(String attribute, int type) {
-    return addAttribute(attribute, type, null);
-  }
-
-  private static HTML.Attribute addAttribute(String attribute,
-                                             int type,
-                                             String[] values) {
-    attribute = attribute.toLowerCase();
-    Set<String> valueSet = null;
-    if (values != null) {
-      valueSet = new HashSet<String>();
-      for (String x : values) {
-        valueSet.add(x.toLowerCase());
-      }
-      valueSet = Collections.unmodifiableSet(valueSet);
-    }
-    HTML.Attribute attr = new HTML.Attribute(attribute, type, valueSet);
-    attributes.put(attribute, attr);
-    return attr;
-  }
-
-  /**
-   * All HTML4 elements.
-   *
-   * Block vs inline flow:
-   * http://www.w3.org/TR/REC-html40/sgml/dtd.html#block
-   * http://www.w3.org/TR/REC-html40/sgml/dtd.html#inline
-   * Some deprecated elements aren't listed there so we make an educated guess:
-   * - CENTER is equivalent to DIV align=center, so we make it BLOCK.
-   * - S, STRIKE and FONT are clearly inline like U, I, etc.
-   * - MENU and DIR are like OL and UL, so we make them block.
-   *
-   * Optional end tag and empty:
-   * http://www.w3.org/TR/REC-html40/index/elements.html
-   */
-  public static final HTML.Element
-    A_ELEMENT          = addElement("A", "", HTML.Element.Flow.INLINE),
-    ABBR_ELEMENT       = addElement("ABBR", "", HTML.Element.Flow.INLINE),
-    ACRONYM_ELEMENT    = addElement("ACRONYM", "", HTML.Element.Flow.INLINE),
-    ADDRESS_ELEMENT    = addElement("ADDRESS", "", HTML.Element.Flow.BLOCK),
-    APPLET_ELEMENT     = addElement("APPLET", ""),
-    AREA_ELEMENT       = addElement("AREA", "E"),
-    B_ELEMENT          = addElement("B", "", HTML.Element.Flow.INLINE),
-    BASE_ELEMENT       = addElement("BASE", "E"),
-    BASEFONT_ELEMENT   = addElement("BASEFONT", "E"),
-    BDO_ELEMENT        = addElement("BDO", "", HTML.Element.Flow.INLINE),
-    BIG_ELEMENT        = addElement("BIG", "", HTML.Element.Flow.INLINE),
-    BLOCKQUOTE_ELEMENT = addElement("BLOCKQUOTE", "B", HTML.Element.Flow.BLOCK),
-    BODY_ELEMENT       = addElement("BODY", "O"),
-    BR_ELEMENT         = addElement("BR", "EB", HTML.Element.Flow.INLINE),
-    BUTTON_ELEMENT     = addElement("BUTTON", "", HTML.Element.Flow.INLINE),
-    CAPTION_ELEMENT    = addTableElement("CAPTION", "", HTML.Element.Flow.NONE),
-    CENTER_ELEMENT     = addElement("CENTER", "B", HTML.Element.Flow.BLOCK),
-    CITE_ELEMENT       = addElement("CITE", "", HTML.Element.Flow.INLINE),
-    CODE_ELEMENT       = addElement("CODE", "", HTML.Element.Flow.INLINE),
-    COL_ELEMENT        = addTableElement("COL", "E", HTML.Element.Flow.NONE),
-    COLGROUP_ELEMENT   = addTableElement("COLGROUP", "O", HTML.Element.Flow.NONE),
-    DD_ELEMENT         = addElement("DD", "OB"),
-    DEL_ELEMENT        = addElement("DEL", ""),
-    DFN_ELEMENT        = addElement("DFN", "", HTML.Element.Flow.INLINE),
-    DIR_ELEMENT        = addElement("DIR", "B", HTML.Element.Flow.BLOCK),
-    DIV_ELEMENT        = addElement("DIV", "B", HTML.Element.Flow.BLOCK),
-    DL_ELEMENT         = addElement("DL", "B", HTML.Element.Flow.BLOCK),
-    DT_ELEMENT         = addElement("DT", "OB"),
-    EM_ELEMENT         = addElement("EM", "", HTML.Element.Flow.INLINE),
-    FIELDSET_ELEMENT   = addElement("FIELDSET", "", HTML.Element.Flow.BLOCK),
-    FONT_ELEMENT       = addElement("FONT", "", HTML.Element.Flow.INLINE),
-    FORM_ELEMENT       = addElement("FORM", "B", HTML.Element.Flow.BLOCK),
-    FRAME_ELEMENT      = addElement("FRAME", "E"),
-    FRAMESET_ELEMENT   = addElement("FRAMESET", ""),
-    H1_ELEMENT         = addElement("H1", "B", HTML.Element.Flow.BLOCK),
-    H2_ELEMENT         = addElement("H2", "B", HTML.Element.Flow.BLOCK),
-    H3_ELEMENT         = addElement("H3", "B", HTML.Element.Flow.BLOCK),
-    H4_ELEMENT         = addElement("H4", "B", HTML.Element.Flow.BLOCK),
-    H5_ELEMENT         = addElement("H5", "B", HTML.Element.Flow.BLOCK),
-    H6_ELEMENT         = addElement("H6", "B", HTML.Element.Flow.BLOCK),
-    HEAD_ELEMENT       = addElement("HEAD", "OB"),
-    HR_ELEMENT         = addElement("HR", "EB", HTML.Element.Flow.BLOCK),
-    HTML_ELEMENT       = addElement("HTML", "OB"),
-    I_ELEMENT          = addElement("I", "", HTML.Element.Flow.INLINE),
-    IFRAME_ELEMENT     = addElement("IFRAME", ""),
-    IMG_ELEMENT        = addElement("IMG", "E", HTML.Element.Flow.INLINE),
-    INPUT_ELEMENT      = addElement("INPUT", "E", HTML.Element.Flow.INLINE),
-    INS_ELEMENT        = addElement("INS", ""),
-    ISINDEX_ELEMENT    = addElement("ISINDEX", "EB"),
-    KBD_ELEMENT        = addElement("KBD", "", HTML.Element.Flow.INLINE),
-    LABEL_ELEMENT      = addElement("LABEL", "", HTML.Element.Flow.INLINE),
-    LEGEND_ELEMENT     = addElement("LEGEND", ""),
-    LI_ELEMENT         = addElement("LI", "OB"),
-    LINK_ELEMENT       = addElement("LINK", "E"),
-    MAP_ELEMENT        = addElement("MAP", "", HTML.Element.Flow.INLINE),
-    MENU_ELEMENT       = addElement("MENU", "B", HTML.Element.Flow.BLOCK),
-    META_ELEMENT       = addElement("META", "E"),
-    NOFRAMES_ELEMENT   = addElement("NOFRAMES", "B"),
-    NOSCRIPT_ELEMENT   = addElement("NOSCRIPT", "", HTML.Element.Flow.BLOCK),
-    OBJECT_ELEMENT     = addElement("OBJECT", "", HTML.Element.Flow.INLINE),
-    OL_ELEMENT         = addElement("OL", "B", HTML.Element.Flow.BLOCK),
-    OPTGROUP_ELEMENT   = addElement("OPTGROUP", ""),
-    OPTION_ELEMENT     = addElement("OPTION", "O"),
-    P_ELEMENT          = addElement("P", "OB", HTML.Element.Flow.BLOCK),
-    PARAM_ELEMENT      = addElement("PARAM", "E"),
-    PRE_ELEMENT        = addElement("PRE", "B", HTML.Element.Flow.BLOCK),
-    Q_ELEMENT          = addElement("Q", "", HTML.Element.Flow.INLINE),
-    S_ELEMENT          = addElement("S", "", HTML.Element.Flow.INLINE),
-    SAMP_ELEMENT       = addElement("SAMP", "", HTML.Element.Flow.INLINE),
-    SCRIPT_ELEMENT     = addElement("SCRIPT", "", HTML.Element.Flow.INLINE),
-    SELECT_ELEMENT     = addElement("SELECT", "", HTML.Element.Flow.INLINE),
-    SMALL_ELEMENT      = addElement("SMALL", "", HTML.Element.Flow.INLINE),
-    SPAN_ELEMENT       = addElement("SPAN", "", HTML.Element.Flow.INLINE),
-    STRIKE_ELEMENT     = addElement("STRIKE", "", HTML.Element.Flow.INLINE),
-    STRONG_ELEMENT     = addElement("STRONG", "", HTML.Element.Flow.INLINE),
-    STYLE_ELEMENT      = addElement("STYLE", ""),
-    SUB_ELEMENT        = addElement("SUB", "", HTML.Element.Flow.INLINE),
-    SUP_ELEMENT        = addElement("SUP", "", HTML.Element.Flow.INLINE),
-    TABLE_ELEMENT      = addTableElement("TABLE", "B", HTML.Element.Flow.BLOCK),
-    TBODY_ELEMENT      = addTableElement("TBODY", "O", HTML.Element.Flow.NONE),
-    TD_ELEMENT         = addTableElement("TD", "OB", HTML.Element.Flow.NONE),
-    TEXTAREA_ELEMENT   = addElement("TEXTAREA", "", HTML.Element.Flow.INLINE),
-    TFOOT_ELEMENT      = addTableElement("TFOOT", "O", HTML.Element.Flow.NONE),
-    TH_ELEMENT         = addTableElement("TH", "OB", HTML.Element.Flow.NONE),
-    THEAD_ELEMENT      = addTableElement("THEAD", "O", HTML.Element.Flow.NONE),
-    TITLE_ELEMENT      = addElement("TITLE", "B"),
-    TR_ELEMENT         = addTableElement("TR", "OB", HTML.Element.Flow.NONE),
-    TT_ELEMENT         = addElement("TT", "", HTML.Element.Flow.INLINE),
-    U_ELEMENT          = addElement("U", "", HTML.Element.Flow.INLINE),
-    UL_ELEMENT         = addElement("UL", "B", HTML.Element.Flow.BLOCK),
-    VAR_ELEMENT        = addElement("VAR", "", HTML.Element.Flow.INLINE);
-
-  /**
-   * All the HTML4 attributes
-   */
-  public static final HTML.Attribute
-    ABBR_ATTRIBUTE           = addAttribute("ABBR"),
-    ACCEPT_ATTRIBUTE         = addAttribute("ACCEPT"),
-    ACCEPT_CHARSET_ATTRIBUTE = addAttribute("ACCEPT-CHARSET"),
-    ACCESSKEY_ATTRIBUTE      = addAttribute("ACCESSKEY"),
-    ACTION_ATTRIBUTE         = addAttribute("ACTION", HTML.Attribute.URI_TYPE),
-    ALIGN_ATTRIBUTE          = addAttribute("ALIGN",
-        HTML.Attribute.ENUM_TYPE,
-        new String[] {"left", "center", "right", "justify",
-            "char", "top", "bottom", "middle"}),
-    ALINK_ATTRIBUTE          = addAttribute("ALINK"),
-    ALT_ATTRIBUTE            = addAttribute("ALT"),
-    ARCHIVE_ATTRIBUTE        = addAttribute("ARCHIVE", HTML.Attribute.URI_TYPE),
-    AXIS_ATTRIBUTE           = addAttribute("AXIS"),
-    BACKGROUND_ATTRIBUTE     = addAttribute("BACKGROUND", HTML.Attribute.URI_TYPE),
-    BGCOLOR_ATTRIBUTE        = addAttribute("BGCOLOR"),
-    BORDER_ATTRIBUTE         = addAttribute("BORDER"),
-    CELLPADDING_ATTRIBUTE    = addAttribute("CELLPADDING"),
-    CELLSPACING_ATTRIBUTE    = addAttribute("CELLSPACING"),
-    CHAR_ATTRIBUTE           = addAttribute("CHAR"),
-    CHAROFF_ATTRIBUTE        = addAttribute("CHAROFF"),
-    CHARSET_ATTRIBUTE        = addAttribute("CHARSET"),
-    CHECKED_ATTRIBUTE        = addAttribute("CHECKED", HTML.Attribute.BOOLEAN_TYPE),
-    CITE_ATTRIBUTE           = addAttribute("CITE", HTML.Attribute.URI_TYPE),
-    CLASS_ATTRIBUTE          = addAttribute("CLASS"),
-    CLASSID_ATTRIBUTE        = addAttribute("CLASSID", HTML.Attribute.URI_TYPE),
-    CLEAR_ATTRIBUTE          = addAttribute("CLEAR",
-        HTML.Attribute.ENUM_TYPE,
-        new String[] {"left", "all", "right", "none"}),
-    CODE_ATTRIBUTE           = addAttribute("CODE"),
-    CODEBASE_ATTRIBUTE       = addAttribute("CODEBASE", HTML.Attribute.URI_TYPE),
-    CODETYPE_ATTRIBUTE       = addAttribute("CODETYPE"),
-    COLOR_ATTRIBUTE          = addAttribute("COLOR"),
-    COLS_ATTRIBUTE           = addAttribute("COLS"),
-    COLSPAN_ATTRIBUTE        = addAttribute("COLSPAN"),
-    COMPACT_ATTRIBUTE        = addAttribute("COMPACT", HTML.Attribute.BOOLEAN_TYPE),
-    CONTENT_ATTRIBUTE        = addAttribute("CONTENT"),
-    COORDS_ATTRIBUTE         = addAttribute("COORDS"),
-    DATA_ATTRIBUTE           = addAttribute("DATA", HTML.Attribute.URI_TYPE),
-    DATETIME_ATTRIBUTE       = addAttribute("DATETIME"),
-    DECLARE_ATTRIBUTE        = addAttribute("DECLARE", HTML.Attribute.BOOLEAN_TYPE),
-    DEFER_ATTRIBUTE          = addAttribute("DEFER", HTML.Attribute.BOOLEAN_TYPE),
-    DIR_ATTRIBUTE            = addAttribute("DIR",
-        HTML.Attribute.ENUM_TYPE,
-        new String[] {"ltr", "rtl"}),
-    DISABLED_ATTRIBUTE       = addAttribute("DISABLED", HTML.Attribute.BOOLEAN_TYPE),
-    ENCTYPE_ATTRIBUTE        = addAttribute("ENCTYPE"),
-    FACE_ATTRIBUTE           = addAttribute("FACE"),
-    FOR_ATTRIBUTE            = addAttribute("FOR"),
-    FRAME_ATTRIBUTE          = addAttribute("FRAME"),
-    FRAMEBORDER_ATTRIBUTE    = addAttribute("FRAMEBORDER",
-        HTML.Attribute.ENUM_TYPE,
-        new String[] {"1", "0"}),
-    HEADERS_ATTRIBUTE        = addAttribute("HEADERS"),
-    HEIGHT_ATTRIBUTE         = addAttribute("HEIGHT"),
-    HREF_ATTRIBUTE           = addAttribute("HREF", HTML.Attribute.URI_TYPE),
-    HREFLANG_ATTRIBUTE       = addAttribute("HREFLANG"),
-    HSPACE_ATTRIBUTE         = addAttribute("HSPACE"),
-    HTTP_EQUIV_ATTRIBUTE     = addAttribute("HTTP-EQUIV"),
-    ID_ATTRIBUTE             = addAttribute("ID"),
-    ISMAP_ATTRIBUTE          = addAttribute("ISMAP", HTML.Attribute.BOOLEAN_TYPE),
-    LABEL_ATTRIBUTE          = addAttribute("LABEL"),
-    LANG_ATTRIBUTE           = addAttribute("LANG"),
-    LANGUAGE_ATTRIBUTE       = addAttribute("LANGUAGE"),
-    LINK_ATTRIBUTE           = addAttribute("LINK"),
-    LONGDESC_ATTRIBUTE       = addAttribute("LONGDESC", HTML.Attribute.URI_TYPE),
-    MARGINHEIGHT_ATTRIBUTE   = addAttribute("MARGINHEIGHT"),
-    MARGINWIDTH_ATTRIBUTE    = addAttribute("MARGINWIDTH"),
-    MAXLENGTH_ATTRIBUTE      = addAttribute("MAXLENGTH"),
-    MEDIA_ATTRIBUTE          = addAttribute("MEDIA"),
-    METHOD_ATTRIBUTE         = addAttribute("METHOD",
-        HTML.Attribute.ENUM_TYPE,
-        new String[] {"get", "post"}),
-    MULTIPLE_ATTRIBUTE       = addAttribute("MULTIPLE", HTML.Attribute.BOOLEAN_TYPE),
-    NAME_ATTRIBUTE           = addAttribute("NAME"),
-    NOHREF_ATTRIBUTE         = addAttribute("NOHREF", HTML.Attribute.BOOLEAN_TYPE),
-    NORESIZE_ATTRIBUTE       = addAttribute("NORESIZE", HTML.Attribute.BOOLEAN_TYPE),
-    NOSHADE_ATTRIBUTE        = addAttribute("NOSHADE", HTML.Attribute.BOOLEAN_TYPE),
-    NOWRAP_ATTRIBUTE         = addAttribute("NOWRAP", HTML.Attribute.BOOLEAN_TYPE),
-    OBJECT_ATTRIBUTE         = addAttribute("OBJECT"),
-    ONBLUR_ATTRIBUTE         = addAttribute("ONBLUR", HTML.Attribute.SCRIPT_TYPE),
-    ONCHANGE_ATTRIBUTE       = addAttribute("ONCHANGE", HTML.Attribute.SCRIPT_TYPE),
-    ONCLICK_ATTRIBUTE        = addAttribute("ONCLICK", HTML.Attribute.SCRIPT_TYPE),
-    ONDBLCLICK_ATTRIBUTE     = addAttribute("ONDBLCLICK", HTML.Attribute.SCRIPT_TYPE),
-    ONFOCUS_ATTRIBUTE        = addAttribute("ONFOCUS", HTML.Attribute.SCRIPT_TYPE),
-    ONKEYDOWN_ATTRIBUTE      = addAttribute("ONKEYDOWN", HTML.Attribute.SCRIPT_TYPE),
-    ONKEYPRESS_ATTRIBUTE     = addAttribute("ONKEYPRESS", HTML.Attribute.SCRIPT_TYPE),
-    ONKEYUP_ATTRIBUTE        = addAttribute("ONKEYUP", HTML.Attribute.SCRIPT_TYPE),
-    ONLOAD_ATTRIBUTE         = addAttribute("ONLOAD", HTML.Attribute.SCRIPT_TYPE),
-    ONMOUSEDOWN_ATTRIBUTE    = addAttribute("ONMOUSEDOWN", HTML.Attribute.SCRIPT_TYPE),
-    ONMOUSEMOVE_ATTRIBUTE    = addAttribute("ONMOUSEMOVE", HTML.Attribute.SCRIPT_TYPE),
-    ONMOUSEOUT_ATTRIBUTE     = addAttribute("ONMOUSEOUT", HTML.Attribute.SCRIPT_TYPE),
-    ONMOUSEOVER_ATTRIBUTE    = addAttribute("ONMOUSEOVER", HTML.Attribute.SCRIPT_TYPE),
-    ONMOUSEUP_ATTRIBUTE      = addAttribute("ONMOUSEUP", HTML.Attribute.SCRIPT_TYPE),
-    ONRESET_ATTRIBUTE        = addAttribute("ONRESET", HTML.Attribute.SCRIPT_TYPE),
-    ONSELECT_ATTRIBUTE       = addAttribute("ONSELECT", HTML.Attribute.SCRIPT_TYPE),
-    ONSUBMIT_ATTRIBUTE       = addAttribute("ONSUBMIT", HTML.Attribute.SCRIPT_TYPE),
-    ONUNLOAD_ATTRIBUTE       = addAttribute("ONUNLOAD", HTML.Attribute.SCRIPT_TYPE),
-    PROFILE_ATTRIBUTE        = addAttribute("PROFILE", HTML.Attribute.URI_TYPE),
-    PROMPT_ATTRIBUTE         = addAttribute("PROMPT"),
-    READONLY_ATTRIBUTE       = addAttribute("READONLY", HTML.Attribute.BOOLEAN_TYPE),
-    REL_ATTRIBUTE            = addAttribute("REL"),
-    REV_ATTRIBUTE            = addAttribute("REV"),
-    ROWS_ATTRIBUTE           = addAttribute("ROWS"),
-    ROWSPAN_ATTRIBUTE        = addAttribute("ROWSPAN"),
-    RULES_ATTRIBUTE          = addAttribute("RULES"),
-    SCHEME_ATTRIBUTE         = addAttribute("SCHEME"),
-    SCOPE_ATTRIBUTE          = addAttribute("SCOPE"),
-    SCROLLING_ATTRIBUTE      = addAttribute("SCROLLING",
-        HTML.Attribute.ENUM_TYPE,
-        new String[] {"yes", "no", "auto"}),
-    SELECTED_ATTRIBUTE       = addAttribute("SELECTED", HTML.Attribute.BOOLEAN_TYPE),
-    SHAPE_ATTRIBUTE          = addAttribute("SHAPE"),
-    SIZE_ATTRIBUTE           = addAttribute("SIZE"),
-    SPAN_ATTRIBUTE           = addAttribute("SPAN"),
-    SRC_ATTRIBUTE            = addAttribute("SRC", HTML.Attribute.URI_TYPE),
-    STANDBY_ATTRIBUTE        = addAttribute("STANDBY"),
-    START_ATTRIBUTE          = addAttribute("START"),
-    STYLE_ATTRIBUTE          = addAttribute("STYLE"),
-    SUMMARY_ATTRIBUTE        = addAttribute("SUMMARY"),
-    TABINDEX_ATTRIBUTE       = addAttribute("TABINDEX"),
-    TARGET_ATTRIBUTE         = addAttribute("TARGET"),
-    TEXT_ATTRIBUTE           = addAttribute("TEXT"),
-    TITLE_ATTRIBUTE          = addAttribute("TITLE"),
-    TYPE_ATTRIBUTE           = addAttribute("TYPE"),
-    USEMAP_ATTRIBUTE         = addAttribute("USEMAP", HTML.Attribute.URI_TYPE),
-    VALIGN_ATTRIBUTE         = addAttribute("VALIGN",
-        HTML.Attribute.ENUM_TYPE,
-        new String[] {"top", "middle", "bottom", "baseline"}),
-    VALUE_ATTRIBUTE          = addAttribute("VALUE"),
-    VALUETYPE_ATTRIBUTE      = addAttribute("VALUETYPE",
-        HTML.Attribute.ENUM_TYPE,
-        new String[] {"data", "ref", "object"}),
-    VERSION_ATTRIBUTE        = addAttribute("VERSION"),
-    VLINK_ATTRIBUTE          = addAttribute("VLINK"),
-    VSPACE_ATTRIBUTE         = addAttribute("VSPACE"),
-    WIDTH_ATTRIBUTE          = addAttribute("WIDTH");
-}
\ No newline at end of file
diff --git a/src/com/android/mail/lib/html/parser/HtmlDocument.java b/src/com/android/mail/lib/html/parser/HtmlDocument.java
deleted file mode 100644
index 09a6bbc..0000000
--- a/src/com/android/mail/lib/html/parser/HtmlDocument.java
+++ /dev/null
@@ -1,1272 +0,0 @@
-/**
- * Copyright (c) 2004, Google Inc.
- *
- * 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.android.mail.lib.html.parser;
-
-import com.android.mail.lib.base.CharEscapers;
-import com.android.mail.lib.base.CharMatcher;
-import com.android.mail.lib.base.StringUtil;
-import com.android.mail.lib.base.X;
-import com.google.common.collect.Lists;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-
-/**
- * HtmlDocument is a container for a list of html nodes, and represents the
- * entire html document. It contains toHTML() method which prints out the html
- * text, toXHTML for printing out XHTML text and toString() which prints out in
- * debug format.
- *
- * @author jlim@google.com (Jing Yee Lim)
- */
-public class HtmlDocument {
-  /** List of Node objects */
-  private final List<Node> nodes;
-
-  /**
-   * Creates a Html document.
-   * @param nodes list of html nodes
-   */
-  public HtmlDocument(List<Node> nodes) {
-    this.nodes = nodes;
-  }
-
-  /** Gets the list of nodes */
-  public List<Node> getNodes() {
-    return nodes;
-  }
-
-  /** Returns a HTML string for the current document */
-  public String toHTML() {
-    StringBuilder sb = new StringBuilder(nodes.size() * 10);
-    for (Node n : nodes) {
-      n.toHTML(sb);
-    }
-    return sb.toString();
-  }
-
-  /** Returns a XHTML string for the current document */
-  public String toXHTML() {
-    StringBuilder sb = new StringBuilder(nodes.size() * 10);
-    for (Node n : nodes) {
-      n.toXHTML(sb);
-    }
-    return sb.toString();
-  }
-
-  /**
-   * Returns, as much as possible, original content of preparsed nodes.  This
-   * is only different from toHTML() if the nodes were created with original
-   * content, e.g., by HtmlParser in preserve mode.
-   */
-  public String toOriginalHTML() {
-    StringBuilder sb = new StringBuilder(nodes.size() * 10);
-    for (Node n : nodes) {
-      n.toOriginalHTML(sb);
-    }
-    return sb.toString();
-  }
-
-  /** Returns the HTML document in debug format */
-  @Override
-  public String toString() {
-    StringWriter strWriter = new StringWriter();
-    accept(new DebugPrinter(new PrintWriter(strWriter)));
-    return strWriter.toString();
-  }
-
-  /**
-   * Creates start Tag Node.
-   * @see HtmlDocument#createTag(HTML.Element, List, String, String)
-   */
-  public static Tag createTag(HTML.Element element, List<TagAttribute> attributes) {
-    return createTag(element, attributes, null, null);
-  }
-
-  /**
-   * Creates start Tag Node.
-   * @see HtmlDocument.Tag#Tag(HTML.Element, List, boolean, String, String)
-   */
-  public static Tag createTag(HTML.Element element,
-      List<TagAttribute> attributes, String originalHtmlBeforeAttributes,
-      String originalHtmlAfterAttributes) {
-    return new Tag(element, attributes, false, originalHtmlBeforeAttributes,
-        originalHtmlAfterAttributes);
-  }
-
-  /**
-   * Creates self-terminating Tag Node.
-   * @see HtmlDocument#createSelfTerminatingTag(HTML.Element, List, String, String)
-   */
-  public static Tag createSelfTerminatingTag(HTML.Element element,
-      List<TagAttribute> attributes) {
-    return createSelfTerminatingTag(element, attributes, null, null);
-  }
-
-  /**
-   * Creates self-terminating Tag Node.
-   * @see HtmlDocument#createTag(HTML.Element, List, String, String)
-   */
-  public static Tag createSelfTerminatingTag(HTML.Element element,
-      List<TagAttribute> attributes, String originalHtmlBeforeAttributes,
-      String originalHtmlAfterAttributes) {
-    return new Tag(element, attributes, true, originalHtmlBeforeAttributes,
-        originalHtmlAfterAttributes);
-  }
-
-  /**
-   * @see HtmlDocument#createEndTag(HTML.Element, String)
-   */
-  public static EndTag createEndTag(HTML.Element element) {
-    return createEndTag(element, null);
-  }
-
-  /**
-   * @see HtmlDocument.EndTag#EndTag(HTML.Element, String)
-   */
-  public static EndTag createEndTag(HTML.Element element, String originalHtml) {
-    return new EndTag(element, originalHtml);
-  }
-
-  /**
-   * @see HtmlDocument#createTagAttribute(HTML.Attribute, String, String)
-   */
-  public static TagAttribute createTagAttribute(HTML.Attribute attr, String value) {
-    return createTagAttribute(attr, value, null);
-  }
-
-  /**
-   * @see HtmlDocument.TagAttribute#TagAttribute(HTML.Attribute, String, String)
-   */
-  public static TagAttribute createTagAttribute(HTML.Attribute attr,
-      String value, String originalHtml) {
-    X.assertTrue(attr != null);
-    return new TagAttribute(attr, value, originalHtml);
-  }
-
-  /**
-   * @see HtmlDocument#createText(String, String)
-   */
-  public static Text createText(String text) {
-    return createText(text, null);
-  }
-
-  /**
-   * Creates a Text node.
-   * @see UnescapedText#UnescapedText(String, String)
-   */
-  public static Text createText(String text, String original) {
-    return new UnescapedText(text, original);
-  }
-
-  /**
-   * Creates a Text node where the content hasn't been unescaped yet (this will
-   * be done lazily).
-   */
-  public static Text createEscapedText(String htmlText, String original) {
-    return new EscapedText(htmlText, original);
-  }
-
-  /**
-   * Creates an Comment node.
-   * @see Comment#Comment(String)
-   */
-  public static Comment createHtmlComment(String content) {
-    return new Comment(content);
-  }
-
-  /**
-   * Creates a CDATA node.
-   * @see CDATA#CDATA(String)
-   */
-  public static CDATA createCDATA(String text) {
-    return new CDATA(text);
-  }
-
-  /** Accepts a Visitor */
-  public void accept(Visitor v) {
-    v.start();
-    for (Node node : nodes) {
-      node.accept(v);
-    }
-    v.finish();
-  }
-
-  /**
-   * @param filter results of this filter replace the existing nodes
-   * @return new document with filtered nodes
-   */
-  public HtmlDocument filter(MultiplexFilter filter) {
-    filter.start();
-    List<Node> newNodes = new ArrayList<Node>();
-    for (Node node : nodes) {
-      filter.filter(node, newNodes);
-    }
-    filter.finish(newNodes);
-    return new HtmlDocument(newNodes);
-  }
-
-  /**
-   * Html node
-   */
-  public static abstract class Node {
-
-    /** Accepts a visitor */
-    public abstract void accept(Visitor visitor);
-
-    /** Converts to HTML */
-    public String toHTML() {
-      StringBuilder sb = new StringBuilder();
-      toHTML(sb);
-      return sb.toString();
-    }
-
-    /** Converts to HTML */
-    public abstract void toHTML(StringBuilder sb);
-
-    /** Converts to XHTML */
-    public String toXHTML() {
-      StringBuilder sb = new StringBuilder();
-      toXHTML(sb);
-      return sb.toString();
-    }
-
-    /** Converts to XHTML */
-    public abstract void toXHTML(StringBuilder sb);
-
-    /**
-     * @return Original if it's available; otherwise, returns
-     * <code>toHTML()</code>
-     */
-    public String toOriginalHTML() {
-      StringBuilder sb = new StringBuilder();
-      toOriginalHTML(sb);
-      return sb.toString();
-    }
-
-    /**
-     * @param sb Destination of HTML to be appended.  Appends original if it's
-     * available; otherwise, appends <code>toHTML()</code>
-     */
-    public abstract void toOriginalHTML(StringBuilder sb);
-  }
-
-  /**
-   * HTML comment node.
-   */
-  public static class Comment extends Node {
-
-    private final String content;
-
-    /**
-     * @param content Raw comment, including "&lt;!--" and "--&gt;".
-     */
-    public Comment(String content) {
-      this.content = content;
-    }
-
-    @Override
-    public void accept(Visitor visitor) {
-      visitor.visitComment(this);
-    }
-
-    /**
-     * Emit original unchanged.
-     * @param sb Destination of result.
-     */
-    @Override
-    public void toHTML(StringBuilder sb) {
-      sb.append(content);
-    }
-
-    /**
-     * Emit original unchanged.
-     * @param sb Destination of result.
-     */
-    @Override
-    public void toXHTML(StringBuilder sb) {
-      sb.append(content);
-    }
-
-    /**
-     * Emit original unchanged.
-     * @param sb Destination of result.
-     */
-    @Override
-    public void toOriginalHTML(StringBuilder sb) {
-      sb.append(content);
-    }
-
-    /**
-     * @return Original unchanged.
-     */
-    public String getContent() {
-      return content;
-    }
-  }
-
-  /**
-   * Text node
-   */
-  public static abstract class Text extends Node {
-
-    /**
-     * unaltered original content of this node
-     */
-    private final String originalHtml;
-
-    /**
-     * content of this node in HTML format
-     */
-    private String html;
-
-    /**
-     * @param originalHtml Unaltered original HTML. If not null,
-     *        toOriginalHTML() will return this.
-     */
-    protected Text(String originalHtml) {
-      this.originalHtml = originalHtml;
-    }
-
-    /**
-     * Gets the plain, unescaped text.
-     */
-    abstract public String getText();
-
-    // Returns true if it contains only white space
-    public boolean isWhitespace() {
-      String text = getText();
-      int len = text.length();
-      for (int i = 0; i < len; i++) {
-        if (!Character.isWhitespace(text.charAt(i))) {
-          return false;
-        }
-      }
-      return true;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (o == this) {
-        return true;
-      }
-      if (o instanceof Text) {
-        Text that = (Text) o;
-
-        return this.originalHtml == null ? that.originalHtml == null
-            : this.originalHtml.equals(that.originalHtml);
-      }
-      return false;
-    }
-
-    @Override
-    public int hashCode() {
-      return originalHtml == null ? 0 : originalHtml.hashCode();
-    }
-
-    @Override
-    public String toString() {
-      return getText();
-    }
-
-    /** Extends Node.accept */
-    @Override
-    public void accept(Visitor visitor) {
-      visitor.visitText(this);
-    }
-
-    /**
-     * Gets the HTML, with HTML entities escaped.
-     */
-    @Override
-    public void toHTML(StringBuilder sb) {
-      if (html == null) {
-        html = CharEscapers.asciiHtmlEscaper().escape(getText());
-      }
-      sb.append(html);
-    }
-
-    /**
-     * @see HtmlDocument.Text#toHTML(StringBuilder)
-     */
-    @Override
-    public void toXHTML(StringBuilder sb) {
-      toHTML(sb);
-    }
-
-    /**
-     * @param sb Appends original HTML to this if available.  Otherwise,
-     * same as toHTML().
-     */
-    @Override
-    public void toOriginalHTML(StringBuilder sb) {
-      if (originalHtml != null) {
-        sb.append(originalHtml);
-      } else {
-        toHTML(sb);
-      }
-    }
-
-    /**
-     * @return the original HTML (possibly with entities unescaped if the
-     * document was malformed). May be null if original HTML was not preserved
-     * (see constructor argument of {@link HtmlParser})
-     */
-    public String getOriginalHTML() {
-      return originalHtml;
-    }
-  }
-
-  /**
-   * {@link Text} implementation where the given text is assumed to have been
-   * already HTML unescaped.
-   */
-  private static class UnescapedText extends Text {
-    /**
-     * content of this node as plain, unescaped text
-     */
-    protected final String text;
-
-    private UnescapedText(String plainText, String originalHtml) {
-      super(originalHtml);
-      X.assertTrue(plainText != null);
-      this.text = plainText;
-    }
-
-    @Override public String getText() {
-      return text;
-    }
-  }
-
-  /**
-   * {@link Text} implementation where the given text is not unescaped yet, and
-   * unescaping will only be done lazily.
-   */
-  private static class EscapedText extends Text {
-    private final String htmlText;
-    private String text;
-
-    private EscapedText(String htmlText, String originalHtml) {
-      super(originalHtml);
-      this.htmlText = htmlText;
-    }
-
-    @Override public String getText() {
-      if (text == null) {
-        text = StringUtil.unescapeHTML(htmlText);
-      }
-      return text;
-    }
-  }
-
-  /**
-   * CDATA node is a subclass of Text node.
-   */
-  public static class CDATA extends UnescapedText {
-    private CDATA(String text) {
-      super(text, text);
-    }
-
-    @Override public void toHTML(StringBuilder sb) {
-      // Do not htmlescape CDATA text
-      sb.append(text);
-    }
-
-    @Override public void toXHTML(StringBuilder sb) {
-      sb.append("<![CDATA[")
-        .append(text)
-        .append("]]>");
-    }
-  }
-
-  /**
-   * Tag is a HTML open tag.
-   */
-  public static class Tag extends Node {
-    // The element
-    private final HTML.Element element;
-
-    // List of TagAttribute objects. This may be null.
-    private List<TagAttribute> attributes;
-
-    private final boolean isSelfTerminating;
-
-    private final String originalHtmlBeforeAttributes;
-
-    private final String originalHtmlAfterAttributes;
-
-    /**
-     * @param element the HTML4 element
-     * @param attributes list of TagAttribute objects, may be null
-     * @param isSelfTerminating
-     * @param originalHtmlBeforeAttributes Original tag's full content before
-     *        first attribute, including beginning '&lt;'. This should not
-     *        include preceeding whitespace for the first attribute, as that
-     *        should be included in the attribute node. If not null, tag will
-     *        preserve this original content. e.g., if original tag were
-     *        "&lt;foO bar='zbc'&gt;", case of foO would be preserved. This
-     *        method does not validate that
-     *        <code>originalHtmlBeforeAttributes</code> is a valid tag String.
-     * @param originalHtmlAfterAttributes Full content of original tag after
-     *        last attribute, including ending '>'. If not null, tag will
-     *        preserve this original content. e.g., if original tag were
-     *        "&lt;foo bar='zbc'  &gt;", the spaces before '&gt;' be preserved.
-     *        This method does not validate that
-     *        <code>originalHtmlAfterAttributes</code> is a valid tag String.
-     */
-    private Tag(HTML.Element element, List<TagAttribute> attributes,
-        boolean isSelfTerminating, String originalHtmlBeforeAttributes,
-        String originalHtmlAfterAttributes) {
-      X.assertTrue(element != null);
-      this.element = element;
-      this.attributes = attributes;
-      this.isSelfTerminating = isSelfTerminating;
-      this.originalHtmlBeforeAttributes = originalHtmlBeforeAttributes;
-      this.originalHtmlAfterAttributes = originalHtmlAfterAttributes;
-    }
-
-    /** Gets the name */
-    public String getName() {
-      return element.getName();
-    }
-
-    /** Gets the element */
-    public HTML.Element getElement() {
-      return element;
-    }
-
-    /** Adds an attribute */
-    public void addAttribute(HTML.Attribute attr, String value) {
-      X.assertTrue(attr != null);
-      addAttribute(new TagAttribute(attr, value, null));
-    }
-
-    /** Adds an attribute */
-    public void addAttribute(TagAttribute attr) {
-      X.assertTrue(attr != null);
-      if (attributes == null) {
-        attributes = new ArrayList<TagAttribute>();
-      }
-      attributes.add(attr);
-    }
-
-    /** Gets the list of attributes, note that this maybe null. */
-    public List<TagAttribute> getAttributes() {
-      return attributes;
-    }
-
-    /** Finds and returns a TagAttribute, or null if not found */
-    public TagAttribute getAttribute(HTML.Attribute attr) {
-      if (attributes != null) {
-        for (TagAttribute attribute : attributes) {
-          if (attribute.getAttribute().equals(attr)) {
-            return attribute;
-          }
-        }
-      }
-      return null;
-    }
-
-    /**
-     * Finds and returns list of TagAttribute of given attribute
-     * type, or empty list if not found,
-     */
-    public List<TagAttribute> getAttributes(HTML.Attribute attr) {
-      List<TagAttribute> result = Lists.newArrayList();
-      if (attributes != null) {
-        for (TagAttribute attribute : attributes) {
-          if (attribute.getAttribute().equals(attr)) {
-            result.add(attribute);
-          }
-        }
-      }
-      return result;
-    }
-
-    /** Returns debug string */
-    @Override
-    public String toString() {
-      StringBuilder sb = new StringBuilder();
-      sb.append("Start Tag: ");
-      sb.append(element.getName());
-      if (attributes != null) {
-        for (TagAttribute attr : attributes) {
-          sb.append(' ');
-          sb.append(attr.toString());
-        }
-      }
-      return sb.toString();
-    }
-
-    /** Implements Node.accept */
-    @Override
-    public void accept(Visitor visitor) {
-      visitor.visitTag(this);
-    }
-
-    /** Implements Node.toHTML */
-    @Override
-    public void toHTML(StringBuilder sb) {
-      serialize(sb, SerializeType.HTML);
-    }
-
-    @Override
-    public void toXHTML(StringBuilder sb) {
-      serialize(sb, SerializeType.XHTML);
-    }
-
-    @Override
-    public void toOriginalHTML(StringBuilder sb) {
-      serialize(sb, SerializeType.ORIGINAL_HTML);
-    }
-
-    /**
-     * Specifies format of serialized output.
-     */
-    private enum SerializeType {
-      ORIGINAL_HTML, HTML, XHTML
-    }
-
-    private void serialize(StringBuilder sb, SerializeType type) {
-      // before attributes
-      if (type == SerializeType.ORIGINAL_HTML && originalHtmlBeforeAttributes != null) {
-        sb.append(originalHtmlBeforeAttributes);
-      } else {
-        sb.append('<');
-        sb.append(element.getName());
-      }
-
-      // attributes
-      if (attributes != null) {
-        for (TagAttribute attr : attributes) {
-          // attribute includes leading whitespace, so we needn't add it here
-          if (type == SerializeType.ORIGINAL_HTML) {
-            attr.toOriginalHTML(sb);
-          } else if (type == SerializeType.HTML) {
-            attr.toHTML(sb);
-          } else {
-            attr.toXHTML(sb);
-          }
-        }
-      }
-
-      // after attributes
-      if (type == SerializeType.ORIGINAL_HTML && originalHtmlAfterAttributes != null) {
-        sb.append(originalHtmlAfterAttributes);
-      } else if (type == SerializeType.XHTML && (isSelfTerminating || getElement().isEmpty())) {
-        sb.append(" />");
-      } else {
-        sb.append('>');
-      }
-    }
-
-    public boolean isSelfTerminating() {
-      return isSelfTerminating;
-    }
-
-    public String getOriginalHtmlBeforeAttributes() {
-      return originalHtmlBeforeAttributes;
-    }
-
-    public String getOriginalHtmlAfterAttributes() {
-      return originalHtmlAfterAttributes;
-    }
-  }
-
-  /**
-   * EndTag is a closing HTML tag.
-   */
-  public static class EndTag extends Node {
-    // The element
-    private final HTML.Element element;
-
-    private final String originalHtml;
-
-    /**
-     * @param element The HTML.Element element.  Can not be null.
-     * @param originalHtml Full content of original tag, including beginning
-     * and ending '<' and '>'.  If not null, tag will preserve this original
-     * content. e.g., if original tag were "&lt;/foo &gt;", the space after foo
-     * would be preserved.  This method does not validate that originalHtml is a
-     * valid tag String.
-     */
-    private EndTag(HTML.Element element, String originalHtml) {
-      X.assertTrue(element != null);
-      this.element = element;
-      this.originalHtml = originalHtml;
-    }
-
-    /** Gets the name */
-    public String getName() {
-      return element.getName();
-    }
-
-    /** Gets the element */
-    public HTML.Element getElement() {
-      return element;
-    }
-
-    /** Returns debug string */
-    @Override
-    public String toString() {
-      return "End Tag: " + element.getName();
-    }
-
-    /** Implements Node.accept */
-    @Override
-    public void accept(Visitor visitor) {
-      visitor.visitEndTag(this);
-    }
-
-    /** Implements Node.toHTML */
-    @Override
-    public void toHTML(StringBuilder sb) {
-      sb.append("</");
-      sb.append(element.getName());
-      sb.append('>');
-    }
-
-    @Override
-    public void toXHTML(StringBuilder sb) {
-      toHTML(sb);
-    }
-
-    @Override
-    public void toOriginalHTML(StringBuilder sb) {
-      if (originalHtml != null) {
-        sb.append(originalHtml);
-      } else {
-        toHTML(sb);
-      }
-    }
-  }
-
-  /**
-   * TagAttribute represents an attribute in a HTML tag.
-   */
-  public static class TagAttribute {
-    private final HTML.Attribute attribute;
-    private String value;
-    private String originalHtml;
-
-    /**
-     * @param attribute the HTML.Attribute. Can't be null.
-     * @param value The value in plain-text format. This can be null if the
-     *        attribute has no value.
-     * @param originalHtml If not null, toOriginalHTML() will preserve original
-     *        content. This should contain any leading whitespace from the
-     *        original.
-     */
-    private TagAttribute(HTML.Attribute attribute, String value, String originalHtml) {
-      X.assertTrue(attribute != null);
-      this.attribute = attribute;
-      this.value = value;
-      this.originalHtml = originalHtml;
-    }
-
-    /** Gets the name */
-    public String getName() {
-      return attribute.getName();
-    }
-
-    /** Gets the HTML.Attribute information */
-    public HTML.Attribute getAttribute() {
-      return attribute;
-    }
-
-    /**
-     * Sets the attribute value.
-     * This value must be in plain-text, not html-escaped.
-     * This can be null, if the attribute has no values.
-     * This clears <code>originalHtml_</code> if it were set, so
-     * <code>toOriginalHTML()</code> might not preserve original any more.
-     */
-    public void setValue(String value) {
-      this.value = value;
-      originalHtml = null;
-    }
-
-    /** Returns the attribute value in plain-text, never null */
-    public String getValue() {
-      return value != null ? value : "";
-    }
-
-    /** Returns true if the attribute value is not empty */
-    public boolean hasValue() {
-      return value != null;
-    }
-
-    /**
-     * Writes out the attribute in HTML format with all necessary preceding
-     * whitespace. Emits originalHtml_ if it were specified to the constructor.
-     * Otherwise, emits a new name="value" string with a single preceding space.
-     */
-    public void toHTML(StringBuilder sb) {
-      sb.append(' ');
-      sb.append(attribute.getName());
-      if (value != null && attribute.getType() != HTML.Attribute.BOOLEAN_TYPE) {
-        sb.append("=\"");
-        sb.append(CharEscapers.asciiHtmlEscaper().escape(value));
-        sb.append("\"");
-      }
-    }
-
-    /** Returns the attribute html string */
-    public String toHTML() {
-      StringBuilder sb = new StringBuilder();
-      toHTML(sb);
-      return sb.toString();
-    }
-
-    /**
-     * Writes out the attribute in XHTML format (value is always appended,
-     * even if it is empty) with all necessary preceeding whitespace.
-     */
-    public void toXHTML(StringBuilder sb) {
-      sb.append(' ');
-      sb.append(attribute.getName()).append("=\"");
-
-      // Assume that value-less attribute are boolean attributes like "disabled"
-      if (hasValue()) {
-        sb.append(CharEscapers.asciiHtmlEscaper().escape(value));
-      } else {
-        sb.append(attribute.getName());
-      }
-
-      sb.append("\"");
-    }
-
-    /** Returns the attribute XHTML string */
-    public String toXHTML() {
-      StringBuilder sb = new StringBuilder();
-      toXHTML(sb);
-      return sb.toString();
-    }
-
-    /**
-     * @param sb Destination to which attribute is written, in its original
-     * preparsed form if possible.
-     */
-    public void toOriginalHTML(StringBuilder sb) {
-      if (originalHtml != null) {
-        sb.append(originalHtml);
-      } else {
-        toHTML(sb);
-      }
-    }
-
-    /**
-     * Writes out the attribute in its original form as it was parsed..
-     */
-    public String toOriginalHTML() {
-      StringBuilder sb = new StringBuilder();
-      toOriginalHTML(sb);
-      return sb.toString();
-    }
-
-    @Override
-    public String toString() {
-      return "{" + attribute.getName() + "=" + value + "}";
-    }
-  }
-
-  /**
-   * Filter is like Visitor, except it implies that the nodes may be changed,
-   * whereas HtmlDocument.Visitor just implies that the nodes are iterated
-   * over. A Filter can behave just like a Visitor if it merely returns the
-   * same node that it visited. Also, methods may be called on a node to change
-   * the values it contains. Alternatively, a new node entirely can be created
-   * and returned, which will essentially replace the previous node with the
-   * new node in the document tree. A node may be removed by returning null
-   * instead of a node.
-   */
-  public static interface Filter {
-    /** This is called first */
-    void start();
-
-    /** A text node */
-    Text visitText(Text n);
-
-    /** An open tag */
-    Tag visitTag(Tag n);
-
-    /** End tag */
-    EndTag visitEndTag(EndTag n);
-
-    /** HTML comment */
-    Comment visitComment(Comment n);
-
-    /* Called at the end. */
-    void finish();
-  }
-
-  /**
-   * Like Filter, except each node may be replaced by multiple nodes.  Also,
-   * does not do double dispatch accept/visit.
-   */
-  public static interface MultiplexFilter {
-    /**
-     * Called first.
-     */
-    void start();
-
-    /**
-     * @param originalNode node to filter
-     * @param out Destination to which this object appends nodes to replace
-     * originalNode.  Can not be null.
-     */
-    void filter(Node originalNode, List<Node> out);
-
-    /**
-     * Called at the end.
-     * @param out Destination to which this object appends nodes at the end of
-     * the document.  Can not be null.
-     */
-    void finish(List<Node> out);
-  }
-
-  /**
-   * Converts a normal {@link Filter} into a {@link MultiplexFilter}.
-   */
-  public static class MultiplexFilterAdapter implements MultiplexFilter {
-
-    private final Filter filter;
-
-    public MultiplexFilterAdapter(Filter filter) {
-      this.filter = filter;
-    }
-
-    public void start() {
-      filter.start();
-    }
-
-    public void filter(Node originalNode, List<Node> out) {
-      if (originalNode == null) {
-        return;
-      }
-
-      Node resultNode;
-      if (originalNode instanceof Tag) {
-        resultNode = filter.visitTag((Tag) originalNode);
-      } else if (originalNode instanceof Text) {
-        resultNode = filter.visitText((Text) originalNode);
-      } else if (originalNode instanceof EndTag) {
-        resultNode = filter.visitEndTag((EndTag) originalNode);
-      } else if (originalNode instanceof Comment) {
-        resultNode = filter.visitComment((Comment) originalNode);
-      } else {
-        throw new IllegalArgumentException("unknown node type: " + originalNode.getClass());
-      }
-
-      if (resultNode != null) {
-        out.add(resultNode);
-      }
-    }
-
-    public void finish(List<Node> out) {
-      filter.finish();
-    }
-  }
-
-  /**
-   * Like Filter, except each node may be replaced by multiple nodes.  Also,
-   * does not do double dispatch accept/visit.  Dispatches filterNode() to
-   * node-specific methods.
-   */
-  public static abstract class SimpleMultiplexFilter implements MultiplexFilter {
-
-    /**
-     * @see HtmlDocument.MultiplexFilter#filter(HtmlDocument.Node, List)
-     */
-    public void filter(Node originalNode, List<Node> out) {
-      if (originalNode == null) {
-        return;
-      }
-
-      if (originalNode instanceof Tag) {
-        filterTag((Tag) originalNode, out);
-      } else if (originalNode instanceof Text) {
-        filterText((Text) originalNode, out);
-      } else if (originalNode instanceof EndTag) {
-        filterEndTag((EndTag) originalNode, out);
-      } else if (originalNode instanceof Comment) {
-        filterComment((Comment) originalNode, out);
-      } else {
-        throw new IllegalArgumentException("unknown node type: "
-            + originalNode.getClass());
-      }
-    }
-
-    public abstract void filterTag(Tag originalTag, List<Node> out);
-
-    public abstract void filterText(Text originalText, List<Node> out);
-
-    public abstract void filterEndTag(EndTag originalEndTag, List<Node> out);
-
-    public void filterComment(Comment originalComment, List<Node> out) {
-    }
-  }
-
-  /**
-   * Contains a list of filters which are applied, in order, to each Node.  The
-   * output of each becomes the input to the next.  As soon as one returns an
-   * empty list it breaks the chain.
-   */
-  public static class MultiplexFilterChain implements MultiplexFilter {
-
-    private final List<MultiplexFilter> filters = new ArrayList<MultiplexFilter>();
-
-    /**
-     * @param sourceFilters these filters are applied in List order
-     */
-    public MultiplexFilterChain(List<MultiplexFilter> sourceFilters) {
-      filters.addAll(sourceFilters);
-    }
-
-    /**
-     * @see HtmlDocument.MultiplexFilter#start()
-     */
-    public void start() {
-      for (MultiplexFilter filter : filters) {
-        filter.start();
-      }
-    }
-
-    /**
-     * @see HtmlDocument.MultiplexFilter#filter(HtmlDocument.Node, List)
-     */
-    public void filter(Node originalNode, List<Node> out) {
-      List<Node> result = new ArrayList<Node>();
-      result.add(originalNode);
-
-      // loop through filters until one returns nothing, or until we're out of
-      // filters
-      for (MultiplexFilter filter : filters) {
-        if (result.isEmpty()) {
-          return;
-        }
-
-        // apply filter to each node and collect results
-        List<Node> newResult = new ArrayList<Node>();
-        for (Node node : result) {
-          filter.filter(node, newResult);
-        }
-        result = newResult;
-      }
-
-      out.addAll(result);
-    }
-
-    /**
-     * @see HtmlDocument.MultiplexFilter#finish(List)
-     */
-    public void finish(List<Node> out) {
-      List<Node> result = new ArrayList<Node>();
-
-      // loop through filters until one returns nothing, or until we're out of
-      // filters
-      for (MultiplexFilter filter : filters) {
-        // apply filter to each node and collect results
-        List<Node> newResult = new ArrayList<Node>();
-        for (Node node : result) {
-          filter.filter(node, newResult);
-        }
-        filter.finish(newResult);
-        result = newResult;
-      }
-
-      out.addAll(result);
-    }
-  }
-
-  /**
-   * Html visitor allows external code to iterate through the nodes in the
-   * document. See HtmlDocument.accept.
-   */
-  public static interface Visitor {
-    /** This is called first */
-    void start();
-
-    /** A text node */
-    void visitText(Text n);
-
-    /** An open tag */
-    void visitTag(Tag n);
-
-    /** End tag */
-    void visitEndTag(EndTag n);
-
-    /** comment */
-    void visitComment(Comment n);
-
-    /* Called at the end. */
-    void finish();
-  }
-
-  /**
-   * An implementation of the Visitor interface which simply delegates its
-   * methods to a wrapped instance of another Visitor.
-   *
-   * <p>This is useful for chaining Visitors together.
-   */
-  public static class VisitorWrapper implements Visitor {
-    private final Visitor wrapped;
-
-    protected VisitorWrapper(Visitor wrap) {
-      wrapped = wrap;
-    }
-
-    public void start() {
-      wrapped.start();
-    }
-
-    public void visitText(Text n) {
-      wrapped.visitText(n);
-    }
-
-    public void visitTag(Tag n) {
-      wrapped.visitTag(n);
-    }
-
-    public void visitEndTag(EndTag n) {
-      wrapped.visitEndTag(n);
-    }
-
-    public void visitComment(Comment n) {
-      wrapped.visitComment(n);
-    }
-
-    public void finish() {
-      wrapped.finish();
-    }
-  }
-
-  /**
-   * A special helper Visitor that builds a HtmlDocument.
-   */
-  public static class Builder implements Visitor {
-    private final boolean preserveComments;
-    private final List<Node> nodes = new ArrayList<Node>();
-    private HtmlDocument doc;
-
-    /**
-     * @see Builder#Builder(boolean)
-     */
-    public Builder() {
-      this(false);
-    }
-
-    /**
-     * @param preserveComments If false, ignores Comment nodes
-     */
-    public Builder(boolean preserveComments) {
-      this.preserveComments = preserveComments;
-    }
-
-    public void addNode(Node node) {
-      nodes.add(node);
-    }
-    public void start() {
-    }
-    public void visitText(Text t) {
-      addNode(t);
-    }
-    public void visitTag(Tag t) {
-      addNode(t);
-    }
-    public void visitComment(Comment n) {
-      if (preserveComments) {
-        addNode(n);
-      }
-    }
-    public void visitEndTag(EndTag t) {
-      addNode(t);
-    }
-    public void finish() {
-      doc = new HtmlDocument(nodes);
-    }
-
-    /** Gets the html document that has been constructed */
-    public HtmlDocument getDocument() {
-      return doc;
-    }
-  }
-
-  /**
-   * A Visitor that prints out the html document in debug format.
-   */
-  public static class DebugPrinter implements Visitor {
-
-    private final PrintWriter writer;
-
-    public DebugPrinter(PrintWriter writer) {
-      this.writer = writer;
-    }
-
-    public void start() {
-    }
-
-    public void visitText(Text t) {
-      writeCollapsed("TEXT", t.getText());
-    }
-
-    public void visitComment(Comment n) {
-      writeCollapsed("COMMENT", n.getContent());
-    }
-
-    private void writeCollapsed(String type, String s) {
-      writer.print(type);
-      writer.print(": ");
-      String noNewlines = s.replace("\n", " ");
-      // Use CharMatcher#WHITESPACE?
-      String collapsed = CharMatcher.LEGACY_WHITESPACE.trimAndCollapseFrom(noNewlines, ' ');
-      writer.print(collapsed);
-    }
-
-    public void visitTag(Tag tag) {
-      writer.print("==<" + tag.getName() + ">");
-      List<TagAttribute> attributes = tag.getAttributes();
-      if (attributes != null) {
-
-        // Attribute values
-        List<String> attrs = new ArrayList<String>();
-        for (TagAttribute a : attributes) {
-          attrs.add("[" + a.getName() + " : " + a.getValue() + "]");
-        }
-        String[] array = attrs.toArray(new String[attrs.size()]);
-
-        // Sort the attributes so that it's easier to read and compare
-        Arrays.sort(array);
-        for (int i = 0; i < array.length; i++) {
-          writer.print(" " + array[i]);
-        }
-      }
-      writer.println();
-    }
-
-    public void visitEndTag(EndTag endtag) {
-      writer.println("==</" + endtag.getName() + ">");
-    }
-
-    public void finish() {
-    }
-  }
-
-}
\ No newline at end of file
diff --git a/src/com/android/mail/lib/html/parser/HtmlParser.java b/src/com/android/mail/lib/html/parser/HtmlParser.java
deleted file mode 100644
index a501c85..0000000
--- a/src/com/android/mail/lib/html/parser/HtmlParser.java
+++ /dev/null
@@ -1,1131 +0,0 @@
-/**
- * Copyright (c) 2004, Google Inc.
- *
- * 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.android.mail.lib.html.parser;
-
-import com.android.mail.lib.base.CharEscapers;
-import com.android.mail.lib.base.CharMatcher;
-import com.android.mail.lib.base.Preconditions;
-import com.android.mail.lib.base.StringUtil;
-import com.android.mail.lib.base.X;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.io.ByteStreams;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * HtmlParser is a simple but efficient html parser.
- * - It's simple because it does not do incremental parsing like some other
- * parser. It assumes that the entire html text is available.
- * - It offers 3 levels of aggressiveness in correcting errors in HTML (see
- * HtmlParser.ParseStyle).
- * - HTML comments are ignored unless initialized with ParseStyle.PRESERVE_ALL.
- */
-public class HtmlParser {
-
-  // States
-  private enum State {
-    IN_TEXT, IN_TAG, IN_COMMENT, IN_CDATA
-  }
-
-  // The current state
-  private State state;
-
-  private int clipLength = Integer.MAX_VALUE;
-  private boolean clipped;
-
-  // The html text
-  private String html;
-
-  // The entire array of nodes
-  private List<HtmlDocument.Node> nodes;
-
-  // Turn on for debug information.
-  private static boolean DEBUG = false;
-
-  // Default whitelist
-  public static final HtmlWhitelist DEFAULT_WHITELIST = HTML4.getWhitelist();
-
-  // Whitelists for looking up accepted HTML tags and attributes
-  private List<HtmlWhitelist> whitelists = Lists.newArrayList(DEFAULT_WHITELIST);
-
-  /**
-   * This setting controls how much of the original HTML is preserved.  In
-   * ascending order of aggressiveness:
-   * - PRESERVE_ALL: Preserves all of original content.
-   * *** Warning - PRESERVE_ALL mode preserves invalid and unsafe HTML. ***
-   * - PRESERVE_VALID: Preserves only valid visible HTML handled by
-   * most browsers.  Discards comments, unknown tags and attributes, and
-   * nameless end tags.  Encodes all '<' characters that aren't part of a tag.
-   * - NORMALIZE: In addition to the changes made by PRESERVE_VALID, also
-   *   - unescapes then reescapes text to normalize entities
-   *   - normalizes whitespace and quotes around tag attributes
-   */
-  public enum ParseStyle { NORMALIZE, PRESERVE_VALID, PRESERVE_ALL }
-
-  /**
-   * True only in PRESERVE_ALL mode.
-   * @see HtmlParser.ParseStyle
-   */
-  private final boolean preserveAll;
-
-  /**
-   * True in either PRESERVE_ALL or PRESERVE_VALID mode.
-   * @see HtmlParser.ParseStyle
-   */
-  private final boolean preserveValidHtml;
-
-  /**
-   * @see HtmlParser#HtmlParser(HtmlParser.ParseStyle)
-   */
-  public HtmlParser() {
-    this(ParseStyle.NORMALIZE);
-  }
-
-  /**
-   * @param parseStyle Level of aggressiveness for how different
-   * toHTML()/toXHTML() are from original.
-   * @see HtmlParser.ParseStyle
-   */
-  public HtmlParser(ParseStyle parseStyle) {
-    preserveAll = (parseStyle == ParseStyle.PRESERVE_ALL);
-    preserveValidHtml = preserveAll || (parseStyle == ParseStyle.PRESERVE_VALID);
-  }
-
-  /**
-   * Sets the maximum length, in characters, of an HTML message.
-   *
-   * @param clipLength must be greater than zero.
-   * (It starts as Integer.MAX_VALUE)
-   */
-  public void setClipLength(int clipLength) {
-    if (clipLength <= 0) {
-      throw new IllegalArgumentException(
-        "clipLength '" + clipLength + "' <= 0");
-    }
-    this.clipLength = clipLength;
-  }
-
-  public boolean isClipped() {
-    return clipped;
-  }
-
-  /**
-   * Sets the HTML whitelist. Calling this overrides any whitelist(s) that
-   * the parser is configured to use. By default, the parser uses the standard
-   * HTML4 whitelist.
-   *
-   * This has no effect in <code>ParseStyle.PRESERVE_ALL</code> mode.
-   *
-   * @param whitelist The whitelist to use. Must not be null.
-   */
-  public void setWhitelist(HtmlWhitelist whitelist) {
-    Preconditions.checkNotNull(whitelist);
-    whitelists = Lists.newArrayList(whitelist);
-  }
-
-  /**
-   * Adds an HTML whitelist to the list of whitelists consulted when
-   * processing an element or attribute. By default, the parser only uses
-   * the standard HTML4 whitelist.
-   *
-   * Whitelists are consulted in reverse chronological order (starting from
-   * the most recently added whitelist). The last whitelist consulted will
-   * always be the standard HTML4 whitelist, unless this was overridden by
-   * a call to {@link #setWhitelist}.
-   *
-   * This has no effect in <code>ParseStyle.PRESERVE_ALL</code> mode.
-   *
-   * @param whitelist The whitelist to use.
-   */
-  public void addWhitelist(HtmlWhitelist whitelist) {
-    whitelists.add(whitelist);
-  }
-
-  /**
-   * These are characters that we don't want to allow unquoted in an attribute
-   * value because they might be interpreted by the browser as HTML control
-   * characters. They are the 5 characters that are escaped by
-   * com.google.common.base.CharEscapers.HTML_ESCAPE, plus '=' and whitespace.
-   * Note that it shouldn't be possible for '>' or whitespace to be parsed as
-   * part of an unquoted attribute value, but we leave them here for
-   * completeness.
-   * Package visibility for unit tests.
-   */
-  static Pattern NEEDS_QUOTING_ATTRIBUTE_VALUE_REGEX = Pattern.compile("[\"\'&<>=\\s]");
-
-  //------------------------------------------------------------------------
-  // Parsing
-  //------------------------------------------------------------------------
-
-  /**
-   * Parses a String as HTML.
-   *
-   * @param html String to parse
-   * @return an Html document
-   */
-  public HtmlDocument parse(String html) {
-    this.html = html;
-    // Use a LinkedList because we don't know the number of nodes ahead of
-    // time. This will be compacted into an ArrayList in coalesceTextNodes().
-    nodes = Lists.newLinkedList();
-    state = State.IN_TEXT;
-
-    clipped = false;
-    int end = html.length();
-    int clipEnd = Math.min(clipLength, end);
-
-    for (int i = 0; i < end && !clipped;) {
-
-      // At any one time, the parser is in one of these states:
-      int pos;
-      switch (state) {
-        case IN_TEXT:
-          // text will not attempt to parse beyond the clipping length
-          pos = scanText(i, clipEnd);
-          X.assertTrue(pos > i || state != State.IN_TEXT); // Must make progress.
-          break;
-
-        case IN_TAG:
-          pos = scanTag(i, end);
-          X.assertTrue(pos > i);        // Must make progress
-          break;
-
-        case IN_COMMENT:
-          pos = scanComment(i, end);
-          state = State.IN_TEXT;
-          X.assertTrue(pos > i);        // Must make progress
-          break;
-
-        case IN_CDATA:
-          pos = scanCDATA(i, end);
-          X.assertTrue(pos > i || state != State.IN_CDATA); // Must make progress
-          break;
-
-        default:
-          throw new Error("Unknown state!");
-      }
-
-      i = pos;
-
-      // If we've reached or gone beyond the clipping length, stop.
-      clipped = pos >= clipLength;
-    }
-
-    nodes = coalesceTextNodes(nodes);
-
-    HtmlDocument doc = new HtmlDocument(nodes);
-    nodes = null;
-    html = null;
-    return doc;
-  }
-
-  /**
-   * During the course of parsing, we may have multiple adjacent Text nodes,
-   * due to the sanitizer stripping out nodes between Text nodes. It is
-   * important to coalesce them so that later steps in the pipeline can
-   * treat the text as a single block (e.g. the step that inserts <wbr> tags).
-   * @param nodes Original nodes.
-   * @return Nodes with text nodes changed.
-   */
-  static List<HtmlDocument.Node> coalesceTextNodes(
-      List<HtmlDocument.Node> nodes) {
-    List<HtmlDocument.Node> out =
-        new ArrayList<HtmlDocument.Node>(nodes.size());
-    LinkedList<HtmlDocument.Text> textNodes = Lists.newLinkedList();
-
-    for (HtmlDocument.Node node : nodes) {
-      if (node instanceof HtmlDocument.Text) {
-        textNodes.add((HtmlDocument.Text) node);
-      } else {
-        mergeTextNodes(textNodes, out);
-        out.add(node);
-      }
-    }
-    mergeTextNodes(textNodes, out);
-    return out;
-  }
-
-  /**
-   * Flushes any Text nodes in {@code textNodes} into a single Text node
-   * in {@code output}. {@code textNodes} is guaranteed to be empty when
-   * the function returns.
-   * @param textNodes Text nodes.
-   * @param output Destination to which results are added.
-   */
-  private static void mergeTextNodes(LinkedList<HtmlDocument.Text> textNodes,
-                                     List<HtmlDocument.Node> output) {
-    if (!textNodes.isEmpty()) {
-      if (textNodes.size() == 1) {
-        output.add(textNodes.removeFirst());
-      } else {
-        int combinedTextLen = 0;
-        int combinedInputLen = 0;
-        for (HtmlDocument.Text text : textNodes) {
-          combinedTextLen += text.getText().length();
-          if (text.getOriginalHTML() != null) {
-            combinedInputLen += text.getOriginalHTML().length();
-          }
-        }
-        StringBuilder combinedText = new StringBuilder(combinedTextLen);
-        StringBuilder combinedInput = new StringBuilder(combinedInputLen);
-        while (!textNodes.isEmpty()) {
-          HtmlDocument.Text text = textNodes.removeFirst();
-          combinedText.append(text.getText());
-          if (text.getOriginalHTML() != null) {
-            combinedInput.append(text.getOriginalHTML());
-          }
-        }
-        String originalInput = combinedInputLen > 0 ? combinedInput.toString() : null;
-        output.add(HtmlDocument.createText(combinedText.toString(), originalInput));
-      }
-    }
-  }
-
-  //------------------------------------------------------------------------
-  // Text scanning
-  //------------------------------------------------------------------------
-  /**
-   * A truncated entity is something like <pre>&nbs or &#1a3</pre>.
-   * We only want to find these at the end of a clipped text.
-   */
-  private static final Pattern TRUNCATED_ENTITY =
-    Pattern.compile("\\& \\#? [0-9a-zA-Z]{0,8} $", Pattern.COMMENTS);
-
-  /**
-   * In a text mode, scan for a tag
-   * @param start Position in original html.
-   * @param end Position in original html.
-   * @return End position of scanned content.
-   */
-  int scanText(final int start, final int end) {
-    int pos;
-    for (pos = start; pos < end; pos++) {
-      char ch = html.charAt(pos);
-      if (ch == '<' && pos + 1 < end) {
-        // Check the next char
-        ch = html.charAt(pos + 1);
-        if (ch == '/' || Character.isLetter(ch) || ch == '!' || ch == '?') {
-
-          // Check if it's an html comment or tag
-          if (html.regionMatches(pos + 1, "!--", 0, 3)) {
-            state = State.IN_COMMENT;
-          } else {
-            state = State.IN_TAG;
-          }
-          break;
-        }
-      }
-    }
-
-    if (pos > start) {
-      int finalPos = pos;
-      String htmlTail = this.html.substring(start, finalPos);
-
-      if ((pos == clipLength) && (clipLength < html.length())) {
-        // We're clipping this HTML, not running off the end.
-        // If we're ending with what looks like a truncated entity,
-        // then clip that part off, too.
-        // If it really was a truncated entity, great.
-        // If it was a false positive, the user won't notice that we clipped
-        // an additional handful of characters.
-        Matcher matcher = TRUNCATED_ENTITY.matcher(htmlTail);
-        if (matcher.find()) {
-          int matchStart = matcher.start();
-          // The matcher matched in htmlTail, not html.
-          // htmlTail starts at html[start]
-          finalPos = start + matchStart;
-          htmlTail = htmlTail.substring(0, matchStart);
-        }
-      }
-
-      if (finalPos > start) {
-        String originalHtml = null;
-        if (preserveAll) {
-          originalHtml = htmlTail;
-        } else if (preserveValidHtml) {
-          // the only way htmlTail can start with '<' is if it's the last character
-          // in html; otherwise, we would have entered State.IN_TAG or
-          // State.IN_COMMENT above
-
-          // officially a '<' can be valid in a text node, but to be safe we
-          // always escape them
-          originalHtml = CharMatcher.is('<').replaceFrom(htmlTail, "&lt;");
-        }
-
-        HtmlDocument.Text textnode = HtmlDocument.createEscapedText(htmlTail, originalHtml);
-        nodes.add(textnode);
-      }
-    }
-    return pos;
-  }
-
-  //------------------------------------------------------------------------
-  // Tag name scanning utility class
-  //------------------------------------------------------------------------
-  private static class TagNameScanner {
-    private final String html;
-    private String tagName;
-    private int startNamePos = -1;
-    private int endNamePos = -1;
-
-    public TagNameScanner(String html) {
-      this.html = html;
-    }
-
-    /**
-     * Scans for a tag name. Sets #startNamePos and #endNamePos.
-     * @param start Position in original html.
-     * @param end Position in original html.
-     * @return End position of scanned content.
-     */
-    public int scanName(final int start, final int end) {
-      int pos;
-      for (pos = start; pos < end; pos++) {
-        char ch = html.charAt(pos);
-
-        // End of tag or end of name.
-        if ((ch == '>') || (ch == '/') || Character.isWhitespace(ch)) {
-          break;
-        }
-      }
-      if (pos > start) {
-        startNamePos = start;
-        endNamePos = pos;
-      }
-      return pos;
-    }
-
-    /**
-     * @return Tag name.
-     */
-    public String getTagName() {
-      if (tagName == null && startNamePos != -1 && endNamePos != -1) {
-        tagName = html.substring(startNamePos, endNamePos);
-      }
-      return tagName;
-    }
-  }
-
-  //------------------------------------------------------------------------
-  // Attribute scanning utility class
-  //------------------------------------------------------------------------
-  private static class AttributeScanner {
-    private final String html;
-    private String name;
-    private String value;
-
-    // The following have package visibility because they are accessed from
-    // HtmlParser.addAttribute() to handle preservation of original content
-    // around the attribute value, but quoting and escaping of the value itself.
-    int startNamePos = -1;
-    int endNamePos = -1;
-    int startValuePos = -1;
-    int endValuePos = -1;
-    boolean attrValueIsQuoted = false;
-
-    public AttributeScanner(String html) {
-      this.html = html;
-    }
-
-    /**
-     * Reset to scan another attribute.
-     */
-    public void reset() {
-      startNamePos = -1;
-      endNamePos = -1;
-      startValuePos = -1;
-      endValuePos = -1;
-      attrValueIsQuoted = false;
-      name = null;
-      value = null;
-    }
-
-    /**
-     * Scans for a tag attribute name. Sets startNamePos and endNamePos. Sets
-     * 'attrName'.
-     *
-     * @param start Position in original html
-     * @param end Position in original html
-     * @return End position of scanned content
-     */
-    int scanName(final int start, final int end) {
-      X.assertTrue(html.charAt(start) != '>');
-      if (start == end) {
-        // No attribute name
-        return start;
-      }
-
-      int pos;
-      for (pos = start + 1; pos < end; pos++) {
-        char ch = html.charAt(pos);
-
-        // End of tag or end of name.
-        if ((ch == '>') || (ch == '=') || (ch == '/') || Character.isWhitespace(ch)) {
-          break;
-        }
-      }
-      startNamePos = start;
-      endNamePos = pos;
-      return pos;
-    }
-
-    /**
-     * Scans for a tag attribute value. Sets startValuePos_ and endValuePos_.
-     *
-     * @param start Position in original html
-     * @param end Position in original html
-     * @return End position of scanned content
-     */
-    int scanValue(final int start, final int end) {
-      // Skip whitespace before '='.
-      int pos = skipSpaces(start, end);
-
-      // Handle cases with no attribute value.
-      if ((pos == end) || (html.charAt(pos) != '=')) {
-        // Return start so spaces will be parsed as part of next attribute,
-        // or end of tag.
-        return start;
-      }
-
-      // Skip '=' and whitespace after it.
-      pos++;
-      pos = skipSpaces(pos, end);
-
-      // Handle cases with no attribute value.
-      if (pos == end) {
-        return pos;
-      }
-
-      // Check for quote character ' or "
-      char ch = html.charAt(pos);
-      if (ch == '\'' || ch == '\"') {
-        attrValueIsQuoted = true;
-        pos++;
-        int valueStart = pos;
-        while (pos < end && html.charAt(pos) != ch) {
-          pos++;
-        }
-        startValuePos = valueStart;
-        endValuePos = pos;
-        if (pos < end) {
-          pos++;                        // Skip the ending quote char
-        }
-      } else {
-        int valueStart = pos;
-        for (; pos < end; pos++) {
-          ch = html.charAt(pos);
-
-          // End of tag or end of value. Not that '/' is included in the value
-          // even if it is the '/>' at the end of the tag.
-          if ((ch == '>') || Character.isWhitespace(ch)) {
-            break;
-          }
-        }
-        startValuePos = valueStart;
-        endValuePos = pos;
-      }
-
-      X.assertTrue(startValuePos > -1);
-      X.assertTrue(endValuePos > -1);
-      X.assertTrue(startValuePos <= endValuePos);
-      X.assertTrue(pos <= end);
-
-      return pos;
-    }
-
-    /**
-     * Skips white spaces.
-     *
-     * @param start Position in original html
-     * @param end Position in original html
-     * @return End position of scanned content
-     */
-    private int skipSpaces(final int start, final int end) {
-      int pos;
-      for (pos = start; pos < end; pos++) {
-        if (!Character.isWhitespace(html.charAt(pos))) {
-          break;
-        }
-      }
-      return pos;
-    }
-
-    public String getName() {
-      if (name == null && startNamePos != -1 && endNamePos != -1) {
-        name = html.substring(startNamePos, endNamePos);
-      }
-      return name;
-    }
-
-    public String getValue() {
-      if (value == null && startValuePos != -1 && endValuePos != -1) {
-        value = html.substring(startValuePos, endValuePos);
-      }
-      return value;
-    }
-  }
-
-  /**
-   * Holds any unrecognized elements we encounter.  Only applicable in
-   * PRESERVE_ALL mode.
-   */
-  private final HashMap<String,HTML.Element> unknownElements = Maps.newHashMap();
-
-  /**
-   * Holds any unrecognized attributes we encounter.  Only applicable in
-   * PRESERVE_ALL mode.
-   */
-  private final HashMap<String,HTML.Attribute> unknownAttributes = Maps.newHashMap();
-
-  /**
-   * @param name Element name.
-   * @return "Dummy" element.  Not useful for any real HTML processing, but
-   * gives us a placeholder for tracking original HTML contents.
-   */
-  private HTML.Element lookupUnknownElement(String name) {
-    name = name.toLowerCase();
-    HTML.Element result = unknownElements.get(name);
-    if (result == null) {
-      result = new HTML.Element(name,
-          HTML.Element.NO_TYPE,
-          /* empty */ false,
-          /* optional end tag */ true,
-          /* breaks flow*/ false,
-          HTML.Element.Flow.NONE);
-      unknownElements.put(name, result);
-    }
-    return result;
-  }
-
-  /**
-   * @param name Attribute name.
-   * @return "Dummy" attribute. Not useful for any real HTML processing, but
-   *         gives us a placeholder for tracking original HTML contents.
-   */
-  private HTML.Attribute lookupUnknownAttribute(String name) {
-    name = name.toLowerCase();
-    HTML.Attribute result = unknownAttributes.get(name);
-    if (result == null) {
-      result = new HTML.Attribute(name, HTML.Attribute.NO_TYPE);
-      unknownAttributes.put(name, result);
-    }
-    return result;
-  }
-
-  /**
-   * Scans for an HTML tag.
-   *
-   * @param start Position in original html.
-   * @param end Position in original html.
-   * @return End position of scanned content.
-   */
-  int scanTag(final int start, final int end) {
-    X.assertTrue(html.charAt(start) == '<');
-
-    // nameStart is where we begin scanning for the tag name and attributes,
-    // so we skip '<'.
-    int nameStart = start + 1;
-
-    // Next state is Text, except the case when we see a STYLE/SCRIPT tag. See
-    // code below.
-    state = State.IN_TEXT;
-
-    // End tag?
-    boolean isEndTag = false;
-    if (html.charAt(nameStart) == '/') {
-      isEndTag = true;
-      ++nameStart;
-    }
-
-    // Tag name and element
-    TagNameScanner tagNameScanner = new TagNameScanner(html);
-    int pos = tagNameScanner.scanName(nameStart, end);
-    String tagName = tagNameScanner.getTagName();
-    HTML.Element element = null;
-    if (tagName == null) {
-      // For some reason, browsers treat start and end tags differently
-      // when they don't have a valid tag name - end tags are swallowed
-      // (e.g., "</ >"), start tags treated as text (e.g., "< >")
-      if (!isEndTag) {
-        // This is not really a tag, treat the '<' as text.
-        HtmlDocument.Text text = HtmlDocument.createText("<", preserveAll ? "<" : null);
-        nodes.add(text);
-        state = State.IN_TEXT;
-        return nameStart;
-      }
-
-      if (preserveAll) {
-        element = lookupUnknownElement("");
-      }
-    } else {
-      element = lookupElement(tagName);
-      if (element == null) {
-        if (DEBUG) {
-          // Unknown element
-          debug("Unknown element: " + tagName);
-        }
-        if (preserveAll) {
-          element = lookupUnknownElement(tagName);
-        }
-      }
-    }
-
-    // Attributes
-    boolean isSingleTag = false;
-    ArrayList<HtmlDocument.TagAttribute> attributes = null;
-    int allAttributesStartPos = pos;
-    int nextAttributeStartPos = pos;
-    AttributeScanner attributeScanner = new AttributeScanner(html);
-    while (pos < end) {
-      int startPos = pos;
-      char ch = html.charAt(pos);
-
-      // Are we at the end of the tag?
-      if ((pos + 1 < end) && (ch == '/') && (html.charAt(pos + 1) == '>')) {
-        isSingleTag = true;
-        ++pos;
-        break;                          // Done
-      }
-      if (ch == '>') {
-        break;                          // Done
-      }
-
-      // See bug 870742 (Buganizer).
-      if (isEndTag && ('<' == ch)) {
-        // '<' not allowed in end tag, so we finish processing this tag and
-        // return to State.IN_TEXT. We mimic Safari & Firefox, which both
-        // terminate the tag when it contains a '<'.
-        if (element != null) {
-          addEndTag(element, start, allAttributesStartPos, pos);
-        }
-        state = State.IN_TEXT;
-        return pos;
-      }
-
-      if (Character.isWhitespace(ch)) {
-        // White space, skip it.
-        ++pos;
-      } else {
-        // Scan for attribute
-        attributeScanner.reset();
-        pos = attributeScanner.scanName(pos, end);
-        X.assertTrue(pos > startPos);
-
-        // If it's a valid attribute, scan attribute values
-        if (attributeScanner.getName() != null) {
-          pos = attributeScanner.scanValue(pos, end);
-
-          // Add the attribute to the list
-          if (element != null) {
-            if (attributes == null) {
-              attributes = new ArrayList<HtmlDocument.TagAttribute>();
-            }
-            addAttribute(attributes, attributeScanner, nextAttributeStartPos, pos);
-          }
-          nextAttributeStartPos = pos;
-        }
-      }
-
-      // Make sure that we make progress!
-      X.assertTrue(pos > startPos);
-    }
-
-    // Cannot find the close tag, so we treat this as text
-    if (pos == end) {
-      X.assertTrue(start < end);
-      String textNodeContent = html.substring(start, end);
-      String originalContent = null;
-      if (preserveAll) {
-        originalContent = textNodeContent;
-      } else if (preserveValidHtml) {
-        // Officially a '<' can be valid in a text node, but to be safe we
-        // always escape them.
-        originalContent =
-            CharMatcher.is('<').replaceFrom(html.substring(start, end), "&lt;");
-      }
-      nodes.add(HtmlDocument.createEscapedText(textNodeContent, originalContent));
-      return end;
-    }
-
-    // Skip '>'
-    X.assertTrue(html.charAt(pos) == '>');
-    pos++;
-
-    // Check if it's an element we're keeping (either an HTML4 element, or an
-    // unknown element we're preserving). If not, ignore the tag.
-    if (element != null) {
-      if (isEndTag) {
-        addEndTag(element, start, allAttributesStartPos, pos);
-      } else {
-        // Special case: if it's a STYLE/SCRIPT element, we go to into
-        // CDATA state.
-        if (HTML4.SCRIPT_ELEMENT.equals(element) || HTML4.STYLE_ELEMENT.equals(element)) {
-          state = State.IN_CDATA;
-        }
-
-        addStartTag(element, start, allAttributesStartPos,
-            nextAttributeStartPos,
-            pos, isSingleTag, attributes);
-      }
-    }
-
-    return pos;
-  }
-
-  /**
-   * Lookups the element in our whitelist(s). Whitelists are consulted in
-   * reverse chronological order (starting from the most recently added
-   * whitelist), allowing clients to override the default behavior.
-   *
-   * @param name Element name.
-   * @return Element.
-   */
-  HTML.Element lookupElement(String name) {
-    ListIterator<HtmlWhitelist> iter = whitelists.listIterator(whitelists.size());
-    while (iter.hasPrevious()) {
-      HTML.Element elem = iter.previous().lookupElement(name);
-      if (elem != null) {
-        return elem;
-      }
-    }
-    return null;
-  }
-
-  /**
-   * Lookups the attribute in our whitelist(s). Whitelists are consulted in
-   * reverse chronological order (starting from the most recently added
-   * whitelist), allowing clients to override the default behavior.
-   *
-   * @param name Attribute name.
-   * @return Attribute.
-   */
-  HTML.Attribute lookupAttribute(String name) {
-    ListIterator<HtmlWhitelist> iter = whitelists.listIterator(whitelists.size());
-    while (iter.hasPrevious()) {
-      HTML.Attribute attr = iter.previous().lookupAttribute(name);
-      if (attr != null) {
-        return attr;
-      }
-    }
-    return null;
-  }
-
-  /**
-   * @param element Tag element
-   * @param startPos Start of tag, including '<'
-   * @param startAttributesPos Start of attributes. This is the first
-   * character after the tag name. If there are no attributes, this is the end
-   * of the tag.
-   * @param endAttributesPos First position after last attribute
-   * @param endPos End of tag, including '>' character
-   * @param isSingleTag True iff this is a self-terminating tag
-   * @param attributes Tag attributes
-   */
-  private void addStartTag(HTML.Element element, final int startPos,
-      final int startAttributesPos, final int endAttributesPos,
-      final int endPos, final boolean isSingleTag,
-      ArrayList<HtmlDocument.TagAttribute> attributes) {
-    X.assertTrue(startPos < startAttributesPos);
-    X.assertTrue(startAttributesPos <= endAttributesPos);
-    X.assertTrue(endAttributesPos <= endPos);
-
-    if (preserveAll) {
-      String beforeAttrs = html.substring(startPos, startAttributesPos);
-      String afterAttrs = html.substring(endAttributesPos, endPos);
-      HtmlDocument.Tag tag = (isSingleTag)
-          ? HtmlDocument.createSelfTerminatingTag(element, attributes,
-              beforeAttrs, afterAttrs)
-          : HtmlDocument.createTag(element, attributes,
-              beforeAttrs, afterAttrs);
-      nodes.add(tag);
-    } else if (preserveValidHtml) {
-      // This is the beginning of the tag up through the tag name. It should not
-      // be possible for this to contain characters needing escaping, but we add
-      // this redundant check to avoid an XSS attack that might get past our
-      // parser but trick a browser into executing a script.
-      X.assertTrue(html.charAt(startPos) == '<');
-      StringBuilder beforeAttrs = new StringBuilder("<");
-      String tagName = html.substring(startPos + 1, startAttributesPos);
-      beforeAttrs.append(CharEscapers.asciiHtmlEscaper().escape(tagName));
-
-      // Verify end-of-tag characters
-      int endContentPos = endPos - 1;
-      X.assertTrue(html.charAt(endContentPos) == '>');
-      if (isSingleTag) {
-        --endContentPos;
-        X.assertTrue(html.charAt(endContentPos) == '/');
-      }
-      X.assertTrue(endAttributesPos <= endContentPos);
-
-      // This is any extra characters between the last attribute and the end of
-      // the tag.
-      X.assertTrue(endAttributesPos < endPos);
-      String afterAttrs = html.substring(endAttributesPos, endPos);
-
-      // Strip all but preceding whitespace.
-      HtmlDocument.Tag tag = (isSingleTag)
-          ? HtmlDocument.createSelfTerminatingTag(element, attributes,
-              beforeAttrs.toString(), afterAttrs)
-          : HtmlDocument.createTag(element, attributes,
-              beforeAttrs.toString(), afterAttrs);
-      nodes.add(tag);
-    } else {
-      // Normalize.
-      HtmlDocument.Tag tag = (isSingleTag)
-          ? HtmlDocument.createSelfTerminatingTag(element, attributes)
-          : HtmlDocument.createTag(element, attributes);
-      nodes.add(tag);
-    }
-  }
-
- /**
-   * @param element End tag element.
-   * @param startPos Start of tag, including '<'.
-   * @param startAttributesPos Start of attributes. This is the first
-   * character after the tag name. If there are no attributes, this is the end
-   * of the tag.
-   * @param endPos End of tag. This usually contains the '>' character, but in
-   * the case where browsers force a termination of a malformed tag, it doesn't.
-   */
-  private void addEndTag(HTML.Element element, final int startPos,
-      final int startAttributesPos, final int endPos) {
-    X.assertTrue(element != null);
-    X.assertTrue(html.charAt(startPos) == '<');
-    X.assertTrue(html.charAt(startPos + 1) == '/');
-
-    if (preserveAll) {
-      // Preserve all: keep actual content even if it's malformed.
-      X.assertTrue(startPos < endPos);
-      String content = html.substring(startPos, endPos);
-      nodes.add(HtmlDocument.createEndTag(element, content));
-    } else if (preserveValidHtml) {
-      // Preserve valid: terminate the tag.
-
-      StringBuilder validContent = new StringBuilder("</");
-
-      // This is the beginning of the tag up through the tag name. It should not
-      // be possible for this to contain characters needing escaping, but we add
-      // this redundant check to avoid an XSS attack that might get past our
-      // parser but trick a browser into executing a script.
-      X.assertTrue(startPos < startAttributesPos);
-      String tagName = html.substring(startPos + 2, startAttributesPos);
-      validContent.append(CharEscapers.asciiHtmlEscaper().escape(tagName));
-
-      // This is the rest of the tag, including any attributes.
-      // See bug 874396 (Buganizer). We don't allow attributes in an end tag.
-      X.assertTrue(startAttributesPos <= endPos);
-      String endOfTag = html.substring(startAttributesPos, endPos);
-      if (endOfTag.charAt(endOfTag.length() - 1) != '>') {
-        endOfTag += '>';
-      }
-
-      // Strip everything but leading whitespace.
-      validContent.append(endOfTag.replaceAll("\\S+.*>", ">"));
-
-      nodes.add(HtmlDocument.createEndTag(element, validContent.toString()));
-    } else {
-      // Normalize: ignore the original content.
-      nodes.add(HtmlDocument.createEndTag(element));
-    }
-  }
-
-  /**
-   * Creates and adds an attribute to the list.
-   *
-   * @param attributes Destination of new attribute.
-   * @param scanner Scanned attribute.
-   * @param startPos start position (inclusive) in original HTML of this
-   *        attribute, including preceeding separator characters (generally this
-   *        is whitespace, but it might contain other characters). This is the
-   *        end position of the tag name or previous attribute +1.
-   * @param endPos end position (exclusive) in original HTML of this attribute.
-   */
-  private void addAttribute(ArrayList<HtmlDocument.TagAttribute> attributes,
-      AttributeScanner scanner, final int startPos, final int endPos) {
-    X.assertTrue(startPos < endPos);
-
-    String name = scanner.getName();
-    X.assertTrue(name != null);
-    HTML.Attribute htmlAttribute = lookupAttribute(name);
-
-    // This can be null when there's no value, e.g., input.checked attribute.
-    String value = scanner.getValue();
-
-    if (htmlAttribute == null) {
-      // Unknown attribute.
-      if (DEBUG) {
-        debug("Unknown attribute: " + name);
-      }
-      if (preserveAll) {
-        String original = html.substring(startPos, endPos);
-        attributes.add(HtmlDocument.createTagAttribute(
-            lookupUnknownAttribute(name), value, original));
-      }
-    } else {
-      String unescapedValue = (value == null) ? null : StringUtil.unescapeHTML(value);
-      if (preserveAll) {
-        attributes.add(HtmlDocument.createTagAttribute(htmlAttribute,
-            unescapedValue, html.substring(startPos, endPos)));
-      } else if (preserveValidHtml) {
-        StringBuilder original = new StringBuilder();
-
-        // This includes any separator characters between the tag name or
-        // preceding attribute and this one.
-        // This addresses bugs 870757 and 875303 (Buganizer).
-        // Don't allow non-whitespace separators between attributes.
-        X.assertTrue(startPos <= scanner.startNamePos);
-        String originalPrefix = html.substring(
-            startPos, scanner.startNamePos).replaceAll("\\S+", "");
-        if (originalPrefix.length() == 0) {
-          originalPrefix = " ";
-        }
-        original.append(originalPrefix);
-
-        if (value == null) {
-          // This includes the name and any following whitespace. Escape in case
-          // the name has any quotes or '<' that could confuse a browser.
-          X.assertTrue(scanner.startNamePos < endPos);
-          String nameEtc = html.substring(scanner.startNamePos, endPos);
-          original.append(CharEscapers.asciiHtmlEscaper().escape(nameEtc));
-        } else {
-          // Escape name in case the name has any quotes or '<' that could
-          // confuse a browser.
-          original.append(CharEscapers.asciiHtmlEscaper().escape(name));
-
-          // This includes the equal sign, and any other whitespace
-          // between the name and value. It also contains the opening quote
-          // character if there is one.
-          X.assertTrue(scanner.endNamePos < scanner.startValuePos);
-          original.append(html.substring(scanner.endNamePos, scanner.startValuePos));
-
-          // This is the value, excluding any quotes.
-          if (scanner.attrValueIsQuoted) {
-            // Officially a '<' can be valid in an attribute value, but to be
-            // safe we always escape them.
-            original.append(value.replaceAll("<", "&lt;"));
-          } else {
-            // This addresses bug 881426 (Buganizer). Put quotes around any
-            // dangerous characters, which is what most of the browsers do.
-            if (NEEDS_QUOTING_ATTRIBUTE_VALUE_REGEX.matcher(value).find()) {
-              original.append('"');
-              original.append(value.replaceAll("\"", "&quot;"));
-              original.append('"');
-            } else {
-              original.append(value);
-            }
-          }
-
-          // This includes end quote, if applicable.
-          X.assertTrue(scanner.endValuePos <= endPos);
-          original.append(html.substring(scanner.endValuePos, endPos));
-        }
-
-        attributes.add(HtmlDocument.createTagAttribute(
-            htmlAttribute, unescapedValue, original.toString()));
-      } else {
-        attributes.add(HtmlDocument.createTagAttribute(
-            htmlAttribute, unescapedValue));
-      }
-    }
-  }
-
-  //------------------------------------------------------------------------
-  // Comment scanning
-  //------------------------------------------------------------------------
-  private static final String START_COMMENT = "<!--";
-  private static final String END_COMMENT = "-->";
-
-  private int scanComment(final int start, final int end) {
-
-    X.assertTrue(html.regionMatches(start, START_COMMENT, 0, START_COMMENT.length()));
-
-    // Scan for end of comment
-    int pos = html.indexOf(END_COMMENT, start + START_COMMENT.length());
-    if (pos != -1) {
-      pos += END_COMMENT.length();
-    } else {
-      // Look for '>'. If we can't find that, the rest of the text is comments.
-      pos = html.indexOf('>', start + 4);
-      if (pos != -1) {
-        ++pos;
-      } else {
-        pos = end;
-      }
-    }
-
-    if (preserveAll) {
-      nodes.add(HtmlDocument.createHtmlComment(html.substring(start, pos)));
-    }
-
-    return pos;
-  }
-
-  //------------------------------------------------------------------------
-  // CDATA scanning
-  //------------------------------------------------------------------------
-  int scanCDATA(final int start, final int end) {
-
-    // Get the tag: must be either STYLE or SCRIPT
-    HtmlDocument.Tag tag = (HtmlDocument.Tag) nodes.get(nodes.size() - 1);
-    HTML.Element element = tag.getElement();
-    X.assertTrue(HTML4.SCRIPT_ELEMENT.equals(element) || HTML4.STYLE_ELEMENT.equals(element));
-
-    int pos;
-    for (pos = start; pos < end; pos++) {
-      if (pos + 2 < end &&
-          html.charAt(pos) == '<' &&
-          html.charAt(pos + 1) == '/' &&
-          html.regionMatches(true, pos + 2, element.getName(), 0,
-                              element.getName().length())) {
-        break;
-      }
-    }
-
-    // Add a CDATA node
-    if (pos > start) {
-      HtmlDocument.CDATA cdata =
-        HtmlDocument.createCDATA(html.substring(start, pos));
-      nodes.add(cdata);
-    }
-
-    state = State.IN_TAG;
-    return pos;
-  }
-
-  //------------------------------------------------------------------------
-  public static void main(String[] args) throws IOException {
-
-    DEBUG = true;
-
-    String html = new String(ByteStreams.toByteArray(System.in), "ISO-8859-1");
-
-    HtmlParser parser = new HtmlParser();
-    HtmlDocument doc = parser.parse(html);
-    System.out.println(doc.toString());
-  }
-
-  private static void debug(String str) {
-    System.err.println(str);
-  }
-}
\ No newline at end of file
diff --git a/src/com/android/mail/lib/html/parser/HtmlTree.java b/src/com/android/mail/lib/html/parser/HtmlTree.java
deleted file mode 100644
index e64a8d5..0000000
--- a/src/com/android/mail/lib/html/parser/HtmlTree.java
+++ /dev/null
@@ -1,965 +0,0 @@
-/**
- * Copyright (c) 2004, Google Inc.
- *
- * 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.android.mail.lib.html.parser;
-
-import com.android.mail.lib.base.CharMatcher;
-import com.android.mail.lib.base.Preconditions;
-import com.android.mail.lib.base.X;
-import com.google.common.collect.ImmutableSet;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.Stack;
-import java.util.logging.Logger;
-
-/**
- * HtmlTree represents a parsed and well-formed html text, it provides
- * methods to convert to plain text. It also provides methods to find
- * well-formed blocks of text, for quote detection.
- *
- * We don't really build a html tree data structure. Instead, for
- * efficiency, and for the ability to do a simple in-order-traversal
- * of the tree, we simply keeps a linear list of nodes (in-order).
- * The begin_ and end_ arrays keeps track of the starting end ending
- * nodes:
- *
- * For a string node, begin_[node] = end_[node] = node
- * For an open tag, begin_[node] = node, end_[node] = the matching end tag
- * For a close tag, end_[node] = the matching open tag, end_[node] = node
- *
- * @author jlim@google.com (Jing Yee Lim)
- */
-public class HtmlTree {
-
-  /**
-   * An interface that allows clients to provide their own implementation
-   * of a {@link PlainTextConverter}.
-   */
-  public static interface PlainTextConverterFactory {
-    /**
-     * Creates a new instance of a {@link PlainTextConverter} to convert
-     * the contents of an {@link HtmlTree} to plain text.
-     */
-    PlainTextConverter createInstance();
-  }
-
-  /**
-   * An interface for an object which converts a single HtmlTree into
-   * plaintext.
-   */
-  public static interface PlainTextConverter {
-    /**
-     * Adds the given node {@code n} to plain text.
-     *
-     * @param n The node to convert to text.
-     * @param nodeNum The number of the node among the list of all notes.
-     * @param endNum The number of the ending node if this is a start node,
-     *    otherwise the same as {@code nodeNum}.
-     */
-    void addNode(HtmlDocument.Node n, int nodeNum, int endNum);
-
-    /**
-     * Returns the current length of the plain text.
-     */
-    int getPlainTextLength();
-
-    /**
-     * Returns the current plain text.
-     */
-    String getPlainText();
-  }
-
-  /** A factory that produces converters of the default implementation. */
-  private static final PlainTextConverterFactory DEFAULT_CONVERTER_FACTORY =
-      new PlainTextConverterFactory() {
-        public PlainTextConverter createInstance() {
-          return new DefaultPlainTextConverter();
-        }
-      };
-
-  /** Contains html nodes */
-  private final List<HtmlDocument.Node> nodes = new ArrayList<HtmlDocument.Node>();
-
-  /** Keeps track of beginning and end of each node */
-  private final Stack<Integer> begins = new Stack<Integer>();
-  private final Stack<Integer> ends = new Stack<Integer>();
-
-  /** Plain text (lazy creation) */
-  private String plainText;
-
-  /** The html string (lazy creation) */
-  private String html;
-
-  /** textPositions[node pos] = the text position */
-  private int[] textPositions;
-
-  private PlainTextConverterFactory converterFactory = DEFAULT_CONVERTER_FACTORY;
-
-  // For debugging only
-  private static final boolean DEBUG = false;
-
-  private static final Logger logger = Logger.getLogger(HtmlTree.class.getName());
-
-  //------------------------------------------------------------------------
-
-  /** HtmlTree can only be constructed from this package */
-  HtmlTree() {
-  }
-
-  /**
-   * Sets a new {@link PlainTextConverterFactory} to be used to convert
-   * the contents of this tree to plaintext.
-   */
-  public void setPlainTextConverterFactory(PlainTextConverterFactory factory) {
-    if (factory == null) {
-      throw new NullPointerException("factory must not be null");
-    }
-    converterFactory = factory;
-  }
-
-  /**
-   * Gets the list of node objects. A node can be either a
-   * Tag, EngTag or a String object.
-   * @return the nodes of the tree
-   */
-  public List<HtmlDocument.Node> getNodesList() {
-    return Collections.unmodifiableList(nodes);
-  }
-
-  /**
-   * @return number of nodes
-   */
-  public int getNumNodes() {
-    return nodes.size();
-  }
-
-  /**
-   * Gets the entire html.
-   */
-  public String getHtml() {
-    return getHtml(-1);
-  }
-
-  /**
-   * Gets the entire html, if wrapSize is > 0, it tries to do wrapping at the
-   * specified size.
-   */
-  public String getHtml(int wrapSize) {
-    if (html == null) {
-      html = getHtml(0, nodes.size(), wrapSize);
-    }
-    return html;
-  }
-
-  /** Gets parts of the html */
-  public String getHtml(int fromNode, int toNode) {
-    return getHtml(fromNode, toNode, -1);
-  }
-
-  /**
-   * Gets parts of the html, if wrapSize is > 0, it tries
-   * to do wrapping at the specified size.
-   */
-  public String getHtml(int fromNode, int toNode, int wrapSize) {
-    X.assertTrue(fromNode >= 0 && toNode <= nodes.size());
-
-    int estSize = (toNode - fromNode) * 10;
-    StringBuilder sb = new StringBuilder(estSize);
-    int lastWrapIndex = 0;      // used for wrapping
-    for (int n = fromNode; n < toNode; n++) {
-      HtmlDocument.Node node = nodes.get(n);
-      node.toHTML(sb);
-      // TODO: maybe we can be smarter about this and not add newlines
-      // within <pre> tags, unless the whole long line is encompassed
-      // by the <pre> tag.
-      if (wrapSize > 0) {
-        // We can only wrap if the last outputted node is an element that
-        // breaks the flow. Otherwise, we risk the possibility of inserting
-        // spaces where they shouldn't be.
-        if ((node instanceof HtmlDocument.Tag &&
-              ((HtmlDocument.Tag) node).getElement().breaksFlow()) ||
-            (node instanceof HtmlDocument.EndTag &&
-              ((HtmlDocument.EndTag) node).getElement().breaksFlow())) {
-          // Check to see if there is a newline in the most recent node's html.
-          int recentNewLine = sb.substring(lastWrapIndex + 1).lastIndexOf('\n');
-          if (recentNewLine != -1) {
-            lastWrapIndex += recentNewLine;
-          }
-          // If the last index - last index of a newline is greater than
-          // wrapSize, add a newline.
-          if (((sb.length() - 1) - lastWrapIndex) > wrapSize) {
-            sb.append('\n');
-            lastWrapIndex = sb.length() - 1;
-          }
-        }
-      }
-    }
-
-    return sb.toString();
-  }
-
-  /**
-   * Convert a html region into chunks of html code, each containing
-   * roughly chunkSize characters.
-   */
-  public ArrayList<String> getHtmlChunks(int fromNode, int toNode, int chunkSize) {
-    X.assertTrue(fromNode >= 0 && toNode <= nodes.size());
-
-    ArrayList<String> chunks = new ArrayList<String>();
-
-    // Do a best effort attempt to not split apart certain elements (as of now,
-    // just the <textarea>). We cannot guarantee that they will not be split
-    // because the client may specify endpoint nodes that land in the middle
-    // of an element (although this shouldn't happen if the endpoints returned
-    // by createBlocks() are properly used).
-    int stack = 0;
-    boolean balanced = true;
-
-    StringBuilder sb = new StringBuilder(chunkSize + 256);
-    for (int n = fromNode; n < toNode; n++) {
-      HtmlDocument.Node node = nodes.get(n);
-      node.toHTML(sb);
-
-      if (node instanceof HtmlDocument.Tag) {
-        if (HTML4.TEXTAREA_ELEMENT.equals(
-            ((HtmlDocument.Tag)node).getElement())) {
-          stack++;
-        }
-      }
-      if (node instanceof HtmlDocument.EndTag) {
-        if (HTML4.TEXTAREA_ELEMENT.equals(
-            ((HtmlDocument.EndTag)node).getElement())) {
-          if (stack == 0) {
-            balanced = false;
-          } else {
-            stack--;
-          }
-        }
-      }
-
-      if (stack == 0 && sb.length() >= chunkSize) {
-        chunks.add(sb.toString());
-        sb.setLength(0);
-      }
-    }
-
-    // Don't forget the last chunk!
-    if (sb.length() > 0) {
-      chunks.add(sb.toString());
-    }
-
-    // If the tree is not balanced (cut off in the middle of a node), log
-    // debug data. Clients should fix their code so that the endpoints from
-    // createBlocks() are properly used.
-    if (!balanced || stack != 0) {
-      StringBuilder debug = new StringBuilder("Returning unbalanced HTML:\n");
-      debug.append(getHtml());
-      debug.append("\nfromNode: ").append(fromNode);
-      debug.append("\ntoNode: ").append(toNode);
-      debug.append("\nNum nodes_: ").append(getNumNodes());
-      for (String chunk : chunks) {
-        debug.append("\nChunk:\n").append(chunk);
-      }
-      logger.severe(debug.toString());
-    }
-
-    return chunks;
-  }
-
-  /**
-   * Returns height (maximum length from root to a leaf) of the HTML tree.
-   * @return height of the HTML tree.
-   */
-  public int getTreeHeight() {
-    int currentHeight = 0;
-    int maxHeight = 0;
-
-    for (int i = 0; i < nodes.size(); i++) {
-      HtmlDocument.Node node = nodes.get(i);
-      if (node instanceof HtmlDocument.Tag) {
-        currentHeight++;
-        if (currentHeight > maxHeight) {
-          maxHeight = currentHeight;
-        }
-        if (((HtmlDocument.Tag) node).getElement().isEmpty()) {
-          // Empty tags have no closing pair, so decrease counter here.
-          currentHeight--;
-        }
-      } else if (node instanceof HtmlDocument.EndTag) {
-        currentHeight--;
-      }
-    }
-
-    // TODO(anatol): make this value cachable?
-    return maxHeight;
-  }
-
-  //------------------------------------------------------------------------
-  // Creating well-formed blocks within the html tree.
-  //------------------------------------------------------------------------
-  /**
-   * A Block represents a region of a html tree that
-   * 1) is well-formed, i.e. for each node in the block, all its descendants
-   * are also contained in the block. So it's safe to wrap the region
-   * within a <table> or <div>, etc.
-   * 2) starts at the beginning of a "line", e.g. a <div>, a <br>.
-   */
-  public static class Block {
-    /* The starting node */
-    public int start_node;
-
-    /* The ending node (non-inclusive to the block) */
-    public int end_node;
-  }
-
-  /**
-   * Creates a list of Blocks, given a text-range.
-   * We may create multiple blocks if one single well-formed Block cannot be
-   * created.
-   *
-   * @param textStart beginning plain-text offset
-   * @param textEnd beginning plain-text offset
-   * @param minNode the smallest node number
-   * @param maxNode the largest node number
-   * @return a list of 0 or more Block objects, never null
-   */
-  public ArrayList<Block> createBlocks(int textStart, int textEnd, int minNode, int maxNode) {
-
-    ArrayList<Block> blocks = new ArrayList<Block>();
-    int startNode = Math.max(getBlockStart(textStart), minNode);
-    int endNode = Math.min(getBlockEnd(textEnd), maxNode);
-
-    if (DEBUG) {
-      debug("Creating block: " +
-            "text pos: " + textStart + "-" + textEnd + "\n" +
-            "node pos: " + startNode + "-" + endNode + "\n" +
-            plainText.substring(textStart, textEnd));
-    }
-
-    // Split up the block [start, end) into one or more blocks that
-    // are well-formed, and begins at a "line" boundary.
-    int blockStart = -1;
-    for (int n = startNode; n < endNode;) {
-
-      // The node n spans [nBegin, nEnd]
-      int nBegin = begins.get(n);
-      int nEnd = ends.get(n);
-
-      if (blockStart == -1) {
-        // Check if this is a valid start node
-        if (nBegin >= n && nEnd <= endNode &&
-            canBeginBlockAt(n)) {
-          blockStart = n;
-          n = nEnd + 1;
-        } else {
-          n++;
-        }
-        continue;
-      }
-
-      // If the node [nBegin, nEnd) lies completely within
-      // the region then proceed to the (nEnd + 1).
-      if (nBegin >= blockStart && nEnd < endNode) {
-        n = nEnd + 1;
-        continue;
-      }
-
-      // If we got here, we have to break up the region into one
-      // or more blocks because the current node cannot be included
-      // in the region.
-      if (DEBUG) {
-        debug("Forcing new block: " + n + " ("  + nBegin + " " + nEnd +
-              ") exceeds (" + blockStart + " " + endNode + ")");
-      }
-      Block b = new Block();
-      b.start_node = blockStart;
-      b.end_node = n;
-      blocks.add(b);
-
-      blockStart = -1;
-      n++;
-    }
-
-    // Last block
-    if (blockStart != -1) {
-      Block b = new Block();
-      b.start_node = blockStart;
-      b.end_node = endNode;
-      blocks.add(b);
-    }
-
-    if (DEBUG) {
-      for (int i = 0; i < blocks.size(); i++) {
-        Block b = blocks.get(i);
-        debug("Block " + i + "/" + blocks.size() + ": " +
-              b.start_node + "-" + b.end_node + " " +
-              getPlainText(b.start_node, b.end_node));
-      }
-    }
-
-    return blocks;
-  }
-
-  /**
-   * Checks if a block can begin starting from a node position
-   */
-  private boolean canBeginBlockAt(int nodePos) {
-    int textPos = textPositions[nodePos];
-
-    // Make sure that we don't exceed the text position, this happens
-    // for the last tag nodes.
-    if (textPos == plainText.length()) {
-      textPos--;
-    }
-
-    // Scan backwards to check if a nodePos is at the beginning
-    // of a line.
-    for (int i = textPos; i > 0; i--) {
-      char ch = plainText.charAt(i);
-      if (ch == '\n') {
-        return true;
-      }
-      if (i < textPos && !Character.isWhitespace(ch)) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  /**
-   * Returns the start of a block given a text-pos
-   */
-  private int getBlockStart(int textPos) {
-    int nodenum = Arrays.binarySearch(textPositions, textPos);
-    if (nodenum >= 0) {
-      // Got an exact node alignment. Get the outer most pos that
-      // matches the text position
-      while ((nodenum - 1) >= 0 && textPositions[nodenum - 1] == textPos) {
-        nodenum--;
-      }
-    } else {
-      // textPos matches the middle of a node.
-      nodenum = -nodenum - 1;
-    }
-
-    X.assertTrue(nodenum >= 0 && nodenum <= nodes.size());
-    return nodenum;
-  }
-
-  /**
-   * Returns the end of a block given a text-pos
-   */
-  private int getBlockEnd(int textPos) {
-    int nodenum = Arrays.binarySearch(textPositions, textPos);
-    if (nodenum >= 0) {
-      // Got an exact node alignment.
-      while ((nodenum + 1) < textPositions.length && textPositions[nodenum + 1] == textPos) {
-        nodenum++;
-      }
-    } else {
-      // textPos matches the middle of a node.
-      nodenum = -nodenum - 2;
-    }
-    X.assertTrue(nodenum >= 0 && nodenum <= nodes.size());
-    return nodenum;
-  }
-
-  //------------------------------------------------------------------------
-  // Plain text view of the html tree
-  //------------------------------------------------------------------------
-  /**
-   * @return the plain-text position corresponding to the node
-   */
-  public int getTextPosition(int node) {
-    return textPositions[node];
-  }
-
-  /**
-   * @return a plain-text String of the html tree
-   */
-  public String getPlainText() {
-    if (plainText == null) {
-      convertToPlainText();
-    }
-    return plainText;
-  }
-
-  /**
-   * @return a plain-text String of a part of the html tree
-   */
-  public String getPlainText(int fromNode, int toNode) {
-    if (plainText == null) {
-      convertToPlainText();
-    }
-    int textstart = textPositions[fromNode];
-    int textend = textPositions[toNode];
-    return plainText.substring(textstart, textend);
-  }
-
-  /**
-   * Converts the html tree to plain text.
-   * We simply iterate through the nodes in the tree.
-   * As we output the plain-text, we keep track of the text position
-   * of each node.
-   * For String nodes, we replace '\n' with ' ' unless we're in a
-   * <pre> block.
-   */
-  private void convertToPlainText() {
-    X.assertTrue(plainText == null && textPositions == null);
-
-    int numNodes = nodes.size();
-
-    // Keeps track of start text position of each node, including a last
-    // entry for the size of the text.
-    textPositions = new int[numNodes + 1];
-
-    PlainTextConverter converter = converterFactory.createInstance();
-
-    for (int i = 0; i < numNodes; i++) {
-      textPositions[i] = converter.getPlainTextLength();
-      converter.addNode(nodes.get(i), i, ends.get(i));
-    }
-
-    // Add a last entry, so that textPositions_[nodes_.size()] is valid.
-    textPositions[numNodes] = converter.getPlainTextLength();
-
-    plainText = converter.getPlainText();
-
-    if (DEBUG) {
-      debug("Plain text: " + plainText);
-
-      for (int i = 0; i < nodes.size(); i++) {
-        int textPos = textPositions[i];
-        String text = plainText.substring(textPos, textPositions[i + 1]);
-        debug("At " + i + ": pos=" + textPos + " " +  text);
-      }
-    }
-  }
-
-  /**
-   * Encapsulates the logic for outputting plain text with respect to text
-   * segments, white space separators, line breaks, and quote marks.
-   */
-  static final class PlainTextPrinter {
-    /**
-     * Separators are whitespace inserted between segments of text. The
-     * semantics are such that between any two segments of text, there is
-     * at most one separator. As such, separators are ordered in increasing
-     * priority, and setting a separator multiple times between text will
-     * result in the single separator with the highest priority being used.
-     * For example, a LineBreak (one newline) will override a Space, but will
-     * be overriden by a BlankLine (two newlines).
-     */
-    static enum Separator {
-      // The values here must be ordered by increasing priority, as the
-      // enum's ordinal() method is used when determining if a new separator
-      // should override an existing one.
-      None,
-      Space,      // single space
-      LineBreak,  // single new line
-      BlankLine   // two new lines
-    }
-
-    // White space characters that are collapsed as a single space.
-    // Note that characters such as the non-breaking whitespace
-    // and full-width spaces are not equivalent to the normal spaces.
-    private static final String HTML_SPACE_EQUIVALENTS = " \n\r\t\f";
-
-    /**
-     * Determines if the given character is considered an HTML space character.
-     * Consecutive HTML space characters are collapsed into a single space when
-     * not within a PRE element.
-     */
-    private static boolean isHtmlWhiteSpace(char ch) {
-      return HTML_SPACE_EQUIVALENTS.indexOf(ch) >= 0;
-    }
-
-    // The buffer in which we accumulate the converted plain text
-    private final StringBuilder sb = new StringBuilder();
-
-    // How many <blockquote> blocks we are in.
-    private int quoteDepth = 0;
-
-    // How many logical newlines are at the end of the buffer we've outputted.
-    // Note that we can't simply count the newlines at the end of the output
-    // buffer because a logical new line may be followed by quote marks.
-    //
-    // We initialize the value to 2 so that we consume any initial separators,
-    // since we don't need separators at the beginning of the output. This also
-    // results in correctly outputting any quote marks at the beginning of the
-    // output if the first piece of text is within a BLOCKQUOTE element.
-    private int endingNewLines = 2;
-
-    // The next separator to be inserted between two text nodes.
-    private Separator separator = Separator.None;
-
-    /** Returns the current length of the text. */
-    final int getTextLength() {
-      return sb.length();
-    }
-
-    /** Returns the current text. */
-    final String getText() {
-      return sb.toString();
-    }
-
-    /**
-     * Sets the next separator between two text nodes. A Space separator is
-     * used if there is any whitespace between the two text nodes when there is
-     * no intervening element that breaks flow. This is automatically handled
-     * by the {@link #appendNormalText} function so the client never needs to
-     * specify this separator.
-     * <p>
-     * A LineBreak separator (single new line) is used if text segments are
-     * separated or enclosed by elements that break flow (e.g. DIV, TABLE, HR,
-     * etc.). The client should set this separator for opening and closing tags
-     * of any element that breaks flow.
-     * <p>
-     * A BlankLine separator (two new lines) should be set for opening and
-     * closing P tags.
-     * <p>
-     * If this method is called multiple times between text nodes, a
-     * separator with a higher priority will override that of a lower priority.
-     */
-    final void setSeparator(Separator newSeparator) {
-      if (newSeparator.ordinal() > separator.ordinal()) {
-        separator = newSeparator;
-      }
-    }
-
-    /** Increments the current quote depth of the text. */
-    final void incQuoteDepth() {
-      quoteDepth++;
-    }
-
-    /** Decrements the current quote depth of the text. */
-    final void decQuoteDepth() {
-      quoteDepth = Math.max(0, quoteDepth - 1);
-    }
-
-    /**
-     * Normalizes the HTML whitespace in the given {@code text} and appends it
-     * as the next segment of text. This will flush any separator that should
-     * be appended before the text, as well as any quote marks that should
-     * follow the last newline if the quote depth is non-zero.
-     */
-    final void appendNormalText(String text) {
-      if (text.length() == 0) {
-        return;
-      }
-      boolean startsWithSpace = isHtmlWhiteSpace(text.charAt(0));
-      boolean endsWithSpace = isHtmlWhiteSpace(text.charAt(text.length() - 1));
-
-      // Strip beginning and ending whitespace.
-      text = CharMatcher.anyOf(HTML_SPACE_EQUIVALENTS).trimFrom(text);
-
-      // Collapse whitespace within the text.
-      text = CharMatcher.anyOf(HTML_SPACE_EQUIVALENTS).collapseFrom(text, ' ');
-
-      if (startsWithSpace) {
-        setSeparator(Separator.Space);
-      }
-
-      appendTextDirect(text);
-
-      if (endsWithSpace) {
-        setSeparator(Separator.Space);
-      }
-    }
-
-    /**
-     * Appends the given text, preserving all whitespace. This is used for
-     * appending text in a PRE element.
-     */
-    final void appendPreText(String text) {
-      // We're in a <pre> block. Split the text into lines, and append
-      // each line with appendTextDirect() to preserve white space.
-      String[] lines = text.split("[\\r\\n]", -1);
-
-      // split() will always return an array with at least one element.
-      appendTextDirect(lines[0]);
-
-      // For all of the remaining lines, we append a newline first, which
-      // takes care of any quote marks that we need to output if the quote
-      // depth is non-zero.
-      for (int i = 1; i < lines.length; i++) {
-        appendNewLine();
-        appendTextDirect(lines[i]);
-      }
-    }
-
-    /**
-     * Appends the {@code text} directly to the output, taking into account
-     * any separator that should be appended before it, and any quote marks
-     * that should follow the last newline if the quote depth is non-zero.
-     * <p>
-     * {@code text} must not contain any new lines--in order to handle
-     * quoting correctly, it is up to the caller to either normalize away the
-     * newlines, or split the text up into separate lines and handle new lines
-     * with the {@link #appendNewLine} method.
-     * <p>
-     * The original {@code text} is not modified in any way. Use this method
-     * when you need to preserve the original white space.
-     * <p>
-     * If the given {@code text} is non empty, this method will result in
-     * {@code endingNewLines} being reset to 0.
-     */
-    private void appendTextDirect(String text) {
-      if (text.length() == 0) {
-        return;
-      }
-      Preconditions.checkArgument(text.indexOf('\n') < 0,
-                                  "text must not contain newlines.");
-      flushSeparator();
-      maybeAddQuoteMarks(true);
-      sb.append(text);
-      endingNewLines = 0;
-    }
-
-    /**
-     * Appends a forced line break, which is the equivalent of a BR element.
-     */
-    final void appendForcedLineBreak() {
-      flushSeparator();
-      appendNewLine();
-    }
-
-    /**
-     * Appends any pending separator to the output buffer. This should be
-     * called before appending text to the buffer.
-     */
-    private void flushSeparator() {
-      switch (separator) {
-        case Space:
-          if (endingNewLines == 0) {
-            // Only append a space separator if we are not following a new
-            // line character. For example, we don't append a separator
-            // space after a <br> tag, since the <br>'s newline fulfills the
-            // space separation requirement.
-            sb.append(" ");
-          }
-          break;
-        case LineBreak:
-          while (endingNewLines < 1) {
-            appendNewLine();
-          }
-          break;
-        case BlankLine:
-          while (endingNewLines < 2) {
-            appendNewLine();
-          }
-          break;
-      }
-      separator = Separator.None;
-    }
-
-    /**
-     * Adds a newline to the output. This handles any quote marks that should
-     * follow any previous new lines, and increments {@code endingNewLines}.
-     */
-    private void appendNewLine() {
-      maybeAddQuoteMarks(false);
-      sb.append('\n');
-      endingNewLines++;
-    }
-
-    /**
-     * Adds quote marks to the output if we are at the beginning of a line.
-     * One '>' character is used for every level of quoting we are in.
-     *
-     * @param includeEndingSpace Includes a single space after the quote marks.
-     */
-    private void maybeAddQuoteMarks(boolean includeEndingSpace) {
-      // We only need to add quote marks if we are at the beginning of line.
-      if (endingNewLines > 0 && quoteDepth > 0) {
-        for (int i = 0; i < quoteDepth; i++) {
-          sb.append('>');
-        }
-        if (includeEndingSpace) {
-          sb.append(' ');
-        }
-      }
-    }
-  }
-
-  /**
-   * Contains the logic for converting the contents of one HtmlTree into
-   * plaintext.
-   */
-  public static class DefaultPlainTextConverter implements PlainTextConverter {
-
-    private static final Set<HTML.Element> BLANK_LINE_ELEMENTS =
-        ImmutableSet.of(
-            HTML4.P_ELEMENT,
-            HTML4.BLOCKQUOTE_ELEMENT,
-            HTML4.PRE_ELEMENT);
-
-    private final PlainTextPrinter printer = new PlainTextPrinter();
-
-    private int preDepth = 0;
-
-    public void addNode(HtmlDocument.Node n, int nodeNum, int endNum) {
-      if (n instanceof HtmlDocument.Text) {        // A string node
-
-        HtmlDocument.Text textNode = (HtmlDocument.Text) n;
-        String str = textNode.getText();
-
-        if (preDepth > 0) {
-          printer.appendPreText(str);
-
-        } else {
-          printer.appendNormalText(str);
-        }
-
-      } else if (n instanceof HtmlDocument.Tag) {
-
-        // Check for linebreaking tags.
-        HtmlDocument.Tag tag = (HtmlDocument.Tag) n;
-        HTML.Element element = tag.getElement();
-
-        if (BLANK_LINE_ELEMENTS.contains(element)) {
-          printer.setSeparator(PlainTextPrinter.Separator.BlankLine);
-
-        } else if (HTML4.BR_ELEMENT.equals(element)) {
-          // The <BR> element is special in that it always adds a newline.
-          printer.appendForcedLineBreak();
-
-        } else if (element.breaksFlow()) {
-          // All other elements that break the flow add a LineBreak separator.
-          printer.setSeparator(PlainTextPrinter.Separator.LineBreak);
-
-          if (HTML4.HR_ELEMENT.equals(element)) {
-            printer.appendNormalText("________________________________");
-            printer.setSeparator(PlainTextPrinter.Separator.LineBreak);
-          }
-        }
-
-        if (HTML4.BLOCKQUOTE_ELEMENT.equals(element)) {
-          printer.incQuoteDepth();
-
-        } else if (HTML4.PRE_ELEMENT.equals(element)) {
-          preDepth++;
-        }
-
-      } else if (n instanceof HtmlDocument.EndTag) {
-
-        // Check for linebreaking tags.
-        HtmlDocument.EndTag endTag = (HtmlDocument.EndTag) n;
-        HTML.Element element = endTag.getElement();
-
-        if (BLANK_LINE_ELEMENTS.contains(element)) {
-          printer.setSeparator(PlainTextPrinter.Separator.BlankLine);
-
-        } else if (element.breaksFlow()) {
-          // All other elements that break the flow add a LineBreak separator.
-          printer.setSeparator(PlainTextPrinter.Separator.LineBreak);
-        }
-
-        if (HTML4.BLOCKQUOTE_ELEMENT.equals(element)) {
-          printer.decQuoteDepth();
-
-        } else if (HTML4.PRE_ELEMENT.equals(element)) {
-          preDepth--;
-        }
-      }
-    }
-
-    public final int getPlainTextLength() {
-      return printer.getTextLength();
-    }
-
-    public final String getPlainText() {
-      return printer.getText();
-    }
-  }
-
-  //------------------------------------------------------------------------
-  // The following methods are used to build the html tree.
-  //------------------------------------------------------------------------
-  /** For building the html tree */
-  private Stack<Integer> stack;
-  private int parent;
-
-  /** Starts the build process */
-  void start() {
-    stack = new Stack<Integer>();
-    parent = -1;
-  }
-
-  /** Finishes the build process */
-  void finish() {
-    X.assertTrue(stack.size() == 0);
-    X.assertTrue(parent == -1);
-  }
-
-  /**
-   * to add the matching end tag
-   */
-  void addStartTag(HtmlDocument.Tag t) {
-    int nodenum = nodes.size();
-    addNode(t, nodenum, -1);
-
-    stack.add(parent);
-    parent = nodenum;
-  }
-
-  /**
-   * Adds a html end tag, this must be preceded by a previous matching open tag
-   */
-  void addEndTag(HtmlDocument.EndTag t) {
-    int nodenum = nodes.size();
-    addNode(t, parent, nodenum);
-
-    if (parent != -1) {
-      ends.set(parent, nodenum);
-    }
-
-    //is this the right pop?
-    parent = stack.pop();
-  }
-
-  /** Adds a singular tag that does not have a corresponding end tag */
-  void addSingularTag(HtmlDocument.Tag t) {
-    int nodenum = nodes.size();
-    addNode(t, nodenum, nodenum);
-  }
-
-  /**
-   * Adds a text
-   * @param t a plain-text string
-   */
-  void addText(HtmlDocument.Text t) {
-    int nodenum = nodes.size();
-    addNode(t, nodenum, nodenum);
-  }
-
-  /** Adds a node */
-  private void addNode(HtmlDocument.Node n, int begin, int end) {
-
-    nodes.add(n);
-    begins.add(begin);
-    ends.add(end);
-  }
-
-  /** For debugging */
-  private static final void debug(String str) {
-    logger.finest(str);
-  }
-
-}
\ No newline at end of file
diff --git a/src/com/android/mail/lib/html/parser/HtmlTreeBuilder.java b/src/com/android/mail/lib/html/parser/HtmlTreeBuilder.java
deleted file mode 100644
index e5d975d..0000000
--- a/src/com/android/mail/lib/html/parser/HtmlTreeBuilder.java
+++ /dev/null
@@ -1,308 +0,0 @@
-/**
- * Copyright (c) 2004, Google Inc.
- *
- * 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.android.mail.lib.html.parser;
-
-import com.android.mail.lib.base.X;
-import com.android.mail.lib.html.parser.HtmlDocument.EndTag;
-import com.google.common.io.ByteStreams;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * HtmlTreeBuilder builds a well-formed HtmlTree.
- *
- * @see HtmlTree
- * @author jlim@google.com (Jing Yee Lim)
- */
-public class HtmlTreeBuilder implements HtmlDocument.Visitor {
-
-  private static final Logger logger = Logger.getLogger(HtmlTreeBuilder.class.getName());
-
-  /** Stack contains HTML4.Element objects to keep track of unclosed tags */
-  private final List<HTML.Element> stack = new ArrayList<HTML.Element>();
-  private final TableFixer tableFixer = new TableFixer();
-  private HtmlTree tree;
-  private boolean built = false;
-
-  /** Gets the built html tree */
-  public HtmlTree getTree() {
-    X.assertTrue(built);
-    return tree;
-  }
-
-  /** Implements HtmlDocument.Visitor.start */
-  public void start() {
-    tree = new HtmlTree();
-    tree.start();
-  }
-
-  /** Implements HtmlDocument.Visitor.finish */
-  public void finish() {
-    // Close all tags
-    while (stack.size() > 0) {
-      addMissingEndTag();
-    }
-    tableFixer.finish();
-    tree.finish();
-
-    built = true;
-  }
-
-  /** Implements HtmlDocument.Visitor.visitTag */
-  public void visitTag(HtmlDocument.Tag t) {
-    tableFixer.seeTag(t);
-
-    HTML.Element element = t.getElement();
-    if (element.isEmpty()) {
-      tree.addSingularTag(t);
-    } else if (t.isSelfTerminating()) {
-      // Explicitly create a non-selfterminating open tag and add it to the tree
-      // and also immediately add the corresponding close tag. This is done
-      // so that the toHTML, toXHTML and toOriginalHTML of the tree's node list
-      // will be balanced consistently.
-      // Otherwise there is a possibility of "<span /></span>" for example, if
-      // the created tree is converted to string through toXHTML.
-      tree.addStartTag(HtmlDocument.createTag(element,
-          t.getAttributes(), t.getOriginalHtmlBeforeAttributes(),
-          t.getOriginalHtmlAfterAttributes()));
-      EndTag end = HtmlDocument.createEndTag(element);
-      tableFixer.seeEndTag(end);
-      tree.addEndTag(end);
-    } else {
-      tree.addStartTag(t);
-      push(element);                       // Track the open tags
-    }
-  }
-
-  /** Implements HtmlVisitor.visit */
-  public void visitEndTag(HtmlDocument.EndTag t) {
-
-    // Here we pop back to the start tag
-    HTML.Element element = t.getElement();
-    int pos = findStartTag(element);
-    if (pos >= 0) {
-
-      // Add missing end-tags if any
-      while (pos < stack.size() - 1) {
-        addMissingEndTag();
-      }
-
-      pop();
-      tableFixer.seeEndTag(t);
-      tree.addEndTag(t);
-
-    } else {
-      // Not found, ignore this end tag
-      logger.finest("Ignoring end tag: " + element.getName());
-    }
-  }
-
-  /** Implements HtmlDocument.Visitor.visitText */
-  public void visitText(HtmlDocument.Text t) {
-    tableFixer.seeText(t);
-    tree.addText(t);
-  }
-
-  /** Implements HtmlDocument.Visitor.visitComment */
-  public void visitComment(HtmlDocument.Comment n) {
-    // ignore
-  }
-
-  /** Finds the start tag from the stack, returns -1 if not found */
-  private int findStartTag(HTML.Element element) {
-    for (int i = stack.size() - 1; i >= 0; i--) {
-      HTML.Element e = stack.get(i);
-      if (e == element) {
-        return i;
-      }
-    }
-    return -1;
-  }
-
-  /**
-   * Adds a close tag corresponding to a tag on the stack, if
-   * the tag needs a close tag.
-   */
-  private void addMissingEndTag() {
-    HTML.Element element = pop();
-
-    HtmlDocument.EndTag endTag = HtmlDocument.createEndTag(element);
-    tableFixer.seeEndTag(endTag);
-    tree.addEndTag(endTag);
-  }
-
-  /** Pushes a tag onto the stack */
-  private void push(HTML.Element element) {
-    stack.add(element);
-  }
-
-  /** Pops an elemnt from the stack */
-  private HTML.Element pop() {
-    return stack.remove(stack.size() - 1);
-  }
-
-  /**
-   * The TableFixer makes sure that a <table> structure is more or less well
-   * formed. Note that it only ensures that data within the <table> tag doesn't
-   * "leak out" of the table.
-   *
-   * For instance, all the tags here are balanced with end tags. But the
-   * 'outside' text ends up leaking out of the table.
-   * <table><tr><td bgcolor=yellow>
-   * <table><table>inside</table><td>outside</td></table>
-   * </td></tr></table>
-   *
-   * The TableFixer makes sure that
-   * 1) Within a table:, text and other elements are enclosed within a TD.
-   *    A TD tag is inserted where necessary.
-   * 2) All table structure tags are enclosed within a <table>. A TABLE tag
-   *    is inserted where necessary.
-   *
-   * Note that the TableFixer only adds open tags, it doesn't add end tags.
-   * The HtmlTreeVerifier ensures that all open tags are properly matched
-   * up and closed.
-   *
-   * @author Jing Yee Lim (jlim@google.com)
-   */
-  class TableFixer {
-
-    private int tables = 0;             // table nesting level
-
-    // States within a <table>
-    static final int NULL = 0;
-    static final int IN_CELL = 1;       // in a <td> or <th> tag
-    static final int IN_CAPTION = 2;    // in a <caption> tag
-
-    private int state;
-
-    void seeTag(HtmlDocument.Tag tag) {
-      HTML.Element element = tag.getElement();
-      if (element.getType() == HTML.Element.TABLE_TYPE) {
-
-        if (HTML4.TABLE_ELEMENT.equals(element)) {
-          if (tables > 0) {
-            ensureCellState();
-          }
-          tables++;
-          state = NULL;
-
-        } else {
-          // Make sure that we're in a table
-          ensureTableState();
-
-          // In cell/caption?
-          if (HTML4.TD_ELEMENT.equals(element) ||
-              HTML4.TH_ELEMENT.equals(element)) {
-            state = IN_CELL;
-
-          } else if (HTML4.CAPTION_ELEMENT.equals(element)) {
-            state = IN_CAPTION;
-          }
-        }
-      } else {
-        if (tables > 0) {
-
-          // Ok to have a form element outside a table cell.
-          // e.g. <TR><FORM><TD>...
-          if (!HTML4.FORM_ELEMENT.equals(element)) {
-            ensureCellState();
-          }
-        }
-      }
-    }
-
-    void seeEndTag(HtmlDocument.EndTag endTag) {
-      HTML.Element element= endTag.getElement();
-
-      if (tables > 0 && element.getType() == HTML.Element.TABLE_TYPE) {
-
-        if (HTML4.TD_ELEMENT.equals(element) ||
-            HTML4.TR_ELEMENT.equals(element) ||
-            HTML4.TH_ELEMENT.equals(element)) {
-          // End of a cell
-          state = NULL;
-
-        } else if (HTML4.CAPTION_ELEMENT.equals(element)) { // End caption
-          state = NULL;
-
-        } else if (HTML4.TABLE_ELEMENT.equals(element)) { // End table
-          X.assertTrue(tables > 0);
-          tables--;
-          state = (tables > 0) ? IN_CELL : NULL;
-        }
-      }
-    }
-
-    void seeText(HtmlDocument.Text textNode) {
-      // If we're in a table, but not in a cell or caption, and the
-      // text is not whitespace, add a <TD>
-      if (tables > 0 &&
-          state == NULL &&
-          !textNode.isWhitespace()) {
-        ensureCellState();
-      }
-    }
-
-    void finish() {
-      X.assertTrue(tables == 0);
-      X.assertTrue(state == NULL);
-    }
-
-    // Ensure that we're within a TABLE
-    private void ensureTableState() {
-      if (tables == 0) {
-        push(HTML4.TABLE_ELEMENT);
-
-        HtmlDocument.Tag tableTag =
-          HtmlDocument.createTag(HTML4.TABLE_ELEMENT, null);
-        tree.addStartTag(tableTag);
-
-        tables++;
-      }
-    }
-
-    // Ensure that we're within a TD or TH cell
-    private void ensureCellState() {
-      if (state != IN_CELL) {
-        push(HTML4.TD_ELEMENT);
-
-        HtmlDocument.Tag tdTag = HtmlDocument.createTag(HTML4.TD_ELEMENT, null);
-        tree.addStartTag(tdTag);
-
-        state = IN_CELL;
-      }
-    }
-  }
-
-  /** For testing */
-  public static void main(String[] args) throws IOException {
-    logger.setLevel(Level.FINEST);
-
-    String html = new String(ByteStreams.toByteArray(System.in));
-    HtmlParser parser = new HtmlParser();
-    HtmlDocument doc = parser.parse(html);
-
-    HtmlTreeBuilder builder = new HtmlTreeBuilder();
-    doc.accept(builder);
-    String outputHtml = builder.getTree().getHtml();
-
-    System.out.println(outputHtml);
-  }
-}
\ No newline at end of file
diff --git a/src/com/android/mail/lib/html/parser/HtmlWhitelist.java b/src/com/android/mail/lib/html/parser/HtmlWhitelist.java
deleted file mode 100644
index 836633b..0000000
--- a/src/com/android/mail/lib/html/parser/HtmlWhitelist.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * Copyright (c) 2004, Google Inc.
- *
- * 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.android.mail.lib.html.parser;
-
-/**
- * HtmlWhitelist is an interface that defines methods required by HtmlParser for
- * looking up accepted HTML elements and attributes.
- *
- * @author sammy@google.com (Sammy Leong)
- */
-public interface HtmlWhitelist {
-  /**
-   * Looks up the HTML.Element object associated with the given element tag
-   * name.
-   *
-   * @param name The tag name of the element to lookup
-   * @return The HTML.Element object associated with the given element tag name,
-   * or null if the given name is not in the whitelist.
-   */
-  HTML.Element lookupElement(String name);
-
-  /**
-   * Looks up the HTML.Attribute object associated with the given attribute
-   * name.
-   *
-   * @param name The name of the attribute to lookup
-   * @return The HTML.Attribute object associated with the given attribute name,
-   * or null if the given name is not in the whitelist.
-   */
-  HTML.Attribute lookupAttribute(String name);
-}
\ No newline at end of file
diff --git a/src/com/android/mail/providers/Account.java b/src/com/android/mail/providers/Account.java
index 0fe63f1..9a389f9 100644
--- a/src/com/android/mail/providers/Account.java
+++ b/src/com/android/mail/providers/Account.java
@@ -18,7 +18,6 @@
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
-import android.content.Context;
 import android.database.Cursor;
 import android.database.MatrixCursor;
 import android.net.Uri;
@@ -26,17 +25,16 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 
-import com.android.mail.R;
 import com.android.mail.content.CursorCreator;
 import com.android.mail.content.ObjectCursor;
-import com.android.mail.lib.base.Preconditions;
-import com.android.mail.lib.base.Strings;
 import com.android.mail.providers.UIProvider.AccountCapabilities;
 import com.android.mail.providers.UIProvider.AccountColumns;
 import com.android.mail.providers.UIProvider.SyncStatus;
 import com.android.mail.utils.LogTag;
 import com.android.mail.utils.LogUtils;
 import com.android.mail.utils.Utils;
+import com.google.android.mail.common.base.Preconditions;
+import com.google.android.mail.common.base.Strings;
 import com.google.common.base.Objects;
 import com.google.common.collect.Lists;
 
diff --git a/src/com/android/mail/providers/Settings.java b/src/com/android/mail/providers/Settings.java
index 683ee29..b179239 100644
--- a/src/com/android/mail/providers/Settings.java
+++ b/src/com/android/mail/providers/Settings.java
@@ -22,7 +22,6 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 
-import com.android.mail.lib.base.Strings;
 import com.android.mail.providers.UIProvider.AccountColumns.SettingsColumns;
 import com.android.mail.providers.UIProvider.AutoAdvance;
 import com.android.mail.providers.UIProvider.ConversationListIcon;
@@ -32,6 +31,7 @@
 import com.android.mail.utils.LogTag;
 import com.android.mail.utils.LogUtils;
 import com.android.mail.utils.Utils;
+import com.google.android.mail.common.base.Strings;
 import com.google.common.base.Objects;
 
 import org.json.JSONException;