<NME> Translate.java
<BEF> // http://sourceforge.org/projects/htmlparser
// Copyright (C) 2004 Derrick Oswald
//
// Revision Control Information
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//

package sage.media.rss;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.UnsupportedEncodingException;

/**
 * Structure to hold a character and it's equivalent entity reference kernel.
 * For the character reference &amp;copy; the character would be '&copy;' and
 * the kernel would be "copy", for example.<p>
 * Character references are described at <a href="Character references">http://www.w3.org/TR/REC-html40/charset.html#entities</a>
 * Supports the Ordered interface so it's easy to create a list sorted by
 * kernel, to perform binary searches on.<p>
 */
class CharacterReference
implements
Cloneable,
Comparable
{
  /**
   * The character value as an integer.
   */
  protected int mCharacter;

  /**
   * This entity reference kernel.
   * The text between the ampersand and the semicolon.
   */
  protected String mKernel;

  /**
   * Construct a <code>CharacterReference</code> with the character and kernel given.
   * @param kernel The kernel in the equivalent character entity reference.
   * @param character The character needing encoding.
   */
  public CharacterReference (String kernel, int character)
  {
    mKernel = kernel;
    mCharacter = character;
    if (null == mKernel)
      mKernel = "";
  }

  /**
   * Get this CharacterReference's kernel.
   * @return The kernel in the equivalent character entity reference.
   */
  public String getKernel ()
  {
    return (mKernel);
  }

  /**
   * Set this CharacterReference's kernel.
   * This is used to avoid creating a new object to perform a binary search.
   * @param kernel The kernel in the equivalent character entity reference.
   */
  void setKernel (String kernel)
  {
    mKernel = kernel;
  }

  /**
   * Get the character needing translation.
   * @return The character.
   */
  public int getCharacter ()
  {
    return (mCharacter);
  }

  /**
   * Set the character.
   * This is used to avoid creating a new object to perform a binary search.
   * @param character The character needing translation.
   */
  void setCharacter (int character)
  {
    mCharacter = character;
  }

  /**
   * Visualize this character reference as a string.
   * @return A string with the character and kernel.
   */
  public String toString ()
  {
    String hex;
    StringBuffer ret;

    ret = new StringBuffer (6 + 8 + 2); // max 8 in string
    hex = Integer.toHexString (getCharacter ());
    ret.append ("\\u");
    for (int i = hex.length (); i < 4; i++)
      ret.append ("0");
    ret.append (hex);
    ret.append ("[");
    ret.append (getKernel ());
    ret.append ("]");

    return (ret.toString ());
  }

  //
  // Ordered interface
  //

  /**
   * Compare one reference to another.
   * @see org.htmlparser.util.sort.Ordered
   */
  public int compareTo (Object that)
  {
    CharacterReference r;

    r = (CharacterReference)that;

    return (getKernel ().compareTo (r.getKernel ()));
  }
}



/**
 * Extended character entity reference.
 * Handles kernels within other strings, just for lookup purposes.
 */
class CharacterReferenceEx extends CharacterReference
{
  /**
   * The starting point in the string.
   */
  protected int mStart;

  /**
   * The ending point in the string.
   */
  protected int mEnd;

  /**
   * Zero args constructor.
   * This object is only ever used after setting the kernel, start and end.
   */
  public CharacterReferenceEx ()
  {
    super ("", 0);
  }

  /**
   * Set the starting point of the kernel.
   */
  public void setStart (int start)
  {
    mStart = start;
  }

  /**
   * Set the supposed ending point.
   * This only specifies an upper bound on the kernel length.
   */
  public void setEnd (int end)
  {
    mEnd = end;
  }

  /**
   * Get this CharacterReference's kernel.
   * @return The kernel in the equivalent character entity reference.
   */
  public String getKernel ()
  {
    return (mKernel.substring (mStart, mEnd));
  }

  //
  // Ordered interface
  //

  /**
   * Compare one reference to another.
   * @see org.htmlparser.util.sort.Ordered
   */
  public int compare (Object that)
  {
    CharacterReference r;
    String kernel;
    int length;
    int ret;

    ret = 0;
    r = (CharacterReference)that;
    kernel = r.getKernel ();
    length = kernel.length ();
    for (int i = mStart, j = 0; i < mEnd; i++, j++)
    {
      if (j >= length)
      {
        ret = 1;
        break;
      }
      ret = mKernel.charAt (i) - kernel.charAt (j);
      if (0 != ret)
        break;
    }

    return (ret);
  }
}

/**
 * Translate numeric character references and character entity references to unicode characters.
 * Based on tables found at <a href="http://www.w3.org/TR/REC-html40/sgml/entities.html">
 * http://www.w3.org/TR/REC-html40/sgml/entities.html</a>
 * <p>Typical usage:
 * <pre>
 *      String s = Translate.decode (getTextFromHtmlPage ());
 * </pre>
 * or
 * <pre>
 *      String s = "&lt;HTML&gt;" + Translate.encode (getArbitraryText ()) + "&lt;/HTML&gt;";
 * </pre>
 */
public class Translate
{
  /**
   * If this member is set <code>true</code>, decoding of streams is
   * done line by line in order to reduce the maximum memory required.
   */
  static public boolean DECODE_LINE_BY_LINE = false;

  /**
   * If this member is set <code>true</code>, encoding of numeric character
   * references uses hexadecimal digits, i.e. &amp;#x25CB;, instead of decimal
   * digits.
   */
  static public boolean ENCODE_HEXADECIMAL = false;

  /**
   * Table mapping entity reference kernel to character.
   * This is sorted by kernel when the class is loaded.
   */
  protected static final CharacterReference[] mCharacterReferences =
    {
    // Portions (c) International Organization for Standardization 1986
    // Permission to copy in any form is granted for use with
    // conforming SGML systems and applications as defined in
    // ISO 8879, provided this notice is included in all copies.
    // Character entity set. Typical invocation:
    // <!ENTITY % HTMLlat1 PUBLIC
    // "-//W3C//ENTITIES Latin 1//EN//HTML">
    // %HTMLlat1;
    new CharacterReference ("nbsp",     '\u00a0'), // no-break space = non-breaking space, U+00A0 ISOnum
    new CharacterReference ("iexcl",    '\u00a1'), // inverted exclamation mark, U+00A1 ISOnum
    new CharacterReference ("cent",     '\u00a2'), // cent sign, U+00A2 ISOnum
    new CharacterReference ("pound",    '\u00a3'), // pound sign, U+00A3 ISOnum
    new CharacterReference ("curren",   '\u00a4'), // currency sign, U+00A4 ISOnum
    new CharacterReference ("yen",      '\u00a5'), // yen sign = yuan sign, U+00A5 ISOnum
    new CharacterReference ("brvbar",   '\u00a6'), // broken bar = broken vertical bar, U+00A6 ISOnum
    new CharacterReference ("sect",     '\u00a7'), // section sign, U+00A7 ISOnum
    new CharacterReference ("uml",      '\u00a8'), // diaeresis = spacing diaeresis, U+00A8 ISOdia
    new CharacterReference ("copy",     '\u00a9'), // copyright sign, U+00A9 ISOnum
    new CharacterReference ("ordf",     '\u00aa'), // feminine ordinal indicator, U+00AA ISOnum
    new CharacterReference ("laquo",    '\u00ab'), // left-pointing double angle quotation mark = left pointing guillemet, U+00AB ISOnum
    new CharacterReference ("not",      '\u00ac'), // not sign, U+00AC ISOnum
    new CharacterReference ("shy",      '\u00ad'), // soft hyphen = discretionary hyphen, U+00AD ISOnum
    new CharacterReference ("reg",      '\u00ae'), // registered sign = registered trade mark sign, U+00AE ISOnum
    new CharacterReference ("macr",     '\u00af'), // macron = spacing macron = overline = APL overbar, U+00AF ISOdia
    new CharacterReference ("deg",      '\u00b0'), // degree sign, U+00B0 ISOnum
    new CharacterReference ("plusmn",   '\u00b1'), // plus-minus sign = plus-or-minus sign, U+00B1 ISOnum
    new CharacterReference ("sup2",     '\u00b2'), // superscript two = superscript digit two = squared, U+00B2 ISOnum
    new CharacterReference ("sup3",     '\u00b3'), // superscript three = superscript digit three = cubed, U+00B3 ISOnum
    new CharacterReference ("acute",    '\u00b4'), // acute accent = spacing acute, U+00B4 ISOdia
    new CharacterReference ("micro",    '\u00b5'), // micro sign, U+00B5 ISOnum
    new CharacterReference ("para",     '\u00b6'), // pilcrow sign = paragraph sign, U+00B6 ISOnum
    new CharacterReference ("middot",   '\u00b7'), // middle dot = Georgian comma = Greek middle dot, U+00B7 ISOnum
    new CharacterReference ("cedil",    '\u00b8'), // cedilla = spacing cedilla, U+00B8 ISOdia
    new CharacterReference ("sup1",     '\u00b9'), // superscript one = superscript digit one, U+00B9 ISOnum
    new CharacterReference ("ordm",     '\u00ba'), // masculine ordinal indicator, U+00BA ISOnum
    new CharacterReference ("raquo",    '\u00bb'), // right-pointing double angle quotation mark = right pointing guillemet, U+00BB ISOnum
    new CharacterReference ("frac14",   '\u00bc'), // vulgar fraction one quarter = fraction one quarter, U+00BC ISOnum
    new CharacterReference ("frac12",   '\u00bd'), // vulgar fraction one half = fraction one half, U+00BD ISOnum
    new CharacterReference ("frac34",   '\u00be'), // vulgar fraction three quarters = fraction three quarters, U+00BE ISOnum
    new CharacterReference ("iquest",   '\u00bf'), // inverted question mark = turned question mark, U+00BF ISOnum
    new CharacterReference ("Agrave",   '\u00c0'), // latin capital letter A with grave = latin capital letter A grave, U+00C0 ISOlat1
    new CharacterReference ("Aacute",   '\u00c1'), // latin capital letter A with acute, U+00C1 ISOlat1
    new CharacterReference ("Acirc",    '\u00c2'), // latin capital letter A with circumflex, U+00C2 ISOlat1
    new CharacterReference ("Atilde",   '\u00c3'), // latin capital letter A with tilde, U+00C3 ISOlat1
    new CharacterReference ("Auml",     '\u00c4'), // latin capital letter A with diaeresis, U+00C4 ISOlat1
    new CharacterReference ("Aring",    '\u00c5'), // latin capital letter A with ring above = latin capital letter A ring, U+00C5 ISOlat1
    new CharacterReference ("AElig",    '\u00c6'), // latin capital letter AE = latin capital ligature AE, U+00C6 ISOlat1
    new CharacterReference ("Ccedil",   '\u00c7'), // latin capital letter C with cedilla, U+00C7 ISOlat1
    new CharacterReference ("Egrave",   '\u00c8'), // latin capital letter E with grave, U+00C8 ISOlat1
    new CharacterReference ("Eacute",   '\u00c9'), // latin capital letter E with acute, U+00C9 ISOlat1
    new CharacterReference ("Ecirc",    '\u00ca'), // latin capital letter E with circumflex, U+00CA ISOlat1
    new CharacterReference ("Euml",     '\u00cb'), // latin capital letter E with diaeresis, U+00CB ISOlat1
    new CharacterReference ("Igrave",   '\u00cc'), // latin capital letter I with grave, U+00CC ISOlat1
    new CharacterReference ("Iacute",   '\u00cd'), // latin capital letter I with acute, U+00CD ISOlat1
    new CharacterReference ("Icirc",    '\u00ce'), // latin capital letter I with circumflex, U+00CE ISOlat1
    new CharacterReference ("Iuml",     '\u00cf'), // latin capital letter I with diaeresis, U+00CF ISOlat1
    new CharacterReference ("ETH",      '\u00d0'), // latin capital letter ETH, U+00D0 ISOlat1
    new CharacterReference ("Ntilde",   '\u00d1'), // latin capital letter N with tilde, U+00D1 ISOlat1
    new CharacterReference ("Ograve",   '\u00d2'), // latin capital letter O with grave, U+00D2 ISOlat1
    new CharacterReference ("Oacute",   '\u00d3'), // latin capital letter O with acute, U+00D3 ISOlat1
    new CharacterReference ("Ocirc",    '\u00d4'), // latin capital letter O with circumflex, U+00D4 ISOlat1
    new CharacterReference ("Otilde",   '\u00d5'), // latin capital letter O with tilde, U+00D5 ISOlat1
    new CharacterReference ("Ouml",     '\u00d6'), // latin capital letter O with diaeresis, U+00D6 ISOlat1
    new CharacterReference ("times",    '\u00d7'), // multiplication sign, U+00D7 ISOnum
    new CharacterReference ("Oslash",   '\u00d8'), // latin capital letter O with stroke = latin capital letter O slash, U+00D8 ISOlat1
    new CharacterReference ("Ugrave",   '\u00d9'), // latin capital letter U with grave, U+00D9 ISOlat1
    new CharacterReference ("Uacute",   '\u00da'), // latin capital letter U with acute, U+00DA ISOlat1
    new CharacterReference ("Ucirc",    '\u00db'), // latin capital letter U with circumflex, U+00DB ISOlat1
    new CharacterReference ("Uuml",     '\u00dc'), // latin capital letter U with diaeresis, U+00DC ISOlat1
    new CharacterReference ("Yacute",   '\u00dd'), // latin capital letter Y with acute, U+00DD ISOlat1
    new CharacterReference ("THORN",    '\u00de'), // latin capital letter THORN, U+00DE ISOlat1
    new CharacterReference ("szlig",    '\u00df'), // latin small letter sharp s = ess-zed, U+00DF ISOlat1
    new CharacterReference ("agrave",   '\u00e0'), // latin small letter a with grave = latin small letter a grave, U+00E0 ISOlat1
    new CharacterReference ("aacute",   '\u00e1'), // latin small letter a with acute, U+00E1 ISOlat1
    new CharacterReference ("acirc",    '\u00e2'), // latin small letter a with circumflex, U+00E2 ISOlat1
    new CharacterReference ("atilde",   '\u00e3'), // latin small letter a with tilde, U+00E3 ISOlat1
    new CharacterReference ("auml",     '\u00e4'), // latin small letter a with diaeresis, U+00E4 ISOlat1
    new CharacterReference ("aring",    '\u00e5'), // latin small letter a with ring above = latin small letter a ring, U+00E5 ISOlat1
    new CharacterReference ("aelig",    '\u00e6'), // latin small letter ae = latin small ligature ae, U+00E6 ISOlat1
    new CharacterReference ("ccedil",   '\u00e7'), // latin small letter c with cedilla, U+00E7 ISOlat1
    new CharacterReference ("egrave",   '\u00e8'), // latin small letter e with grave, U+00E8 ISOlat1
    new CharacterReference ("eacute",   '\u00e9'), // latin small letter e with acute, U+00E9 ISOlat1
    new CharacterReference ("ecirc",    '\u00ea'), // latin small letter e with circumflex, U+00EA ISOlat1
    new CharacterReference ("euml",     '\u00eb'), // latin small letter e with diaeresis, U+00EB ISOlat1
    new CharacterReference ("igrave",   '\u00ec'), // latin small letter i with grave, U+00EC ISOlat1
    new CharacterReference ("iacute",   '\u00ed'), // latin small letter i with acute, U+00ED ISOlat1
    new CharacterReference ("icirc",    '\u00ee'), // latin small letter i with circumflex, U+00EE ISOlat1
    new CharacterReference ("iuml",     '\u00ef'), // latin small letter i with diaeresis, U+00EF ISOlat1
    new CharacterReference ("eth",      '\u00f0'), // latin small letter eth, U+00F0 ISOlat1
    new CharacterReference ("ntilde",   '\u00f1'), // latin small letter n with tilde, U+00F1 ISOlat1
    new CharacterReference ("ograve",   '\u00f2'), // latin small letter o with grave, U+00F2 ISOlat1
    new CharacterReference ("oacute",   '\u00f3'), // latin small letter o with acute, U+00F3 ISOlat1
    new CharacterReference ("ocirc",    '\u00f4'), // latin small letter o with circumflex, U+00F4 ISOlat1
    new CharacterReference ("otilde",   '\u00f5'), // latin small letter o with tilde, U+00F5 ISOlat1
    new CharacterReference ("ouml",     '\u00f6'), // latin small letter o with diaeresis, U+00F6 ISOlat1
    new CharacterReference ("divide",   '\u00f7'), // division sign, U+00F7 ISOnum
    new CharacterReference ("oslash",   '\u00f8'), // latin small letter o with stroke, = latin small letter o slash, U+00F8 ISOlat1
    new CharacterReference ("ugrave",   '\u00f9'), // latin small letter u with grave, U+00F9 ISOlat1
    new CharacterReference ("uacute",   '\u00fa'), // latin small letter u with acute, U+00FA ISOlat1
    new CharacterReference ("ucirc",    '\u00fb'), // latin small letter u with circumflex, U+00FB ISOlat1
    new CharacterReference ("uuml",     '\u00fc'), // latin small letter u with diaeresis, U+00FC ISOlat1
    new CharacterReference ("yacute",   '\u00fd'), // latin small letter y with acute, U+00FD ISOlat1
    new CharacterReference ("thorn",    '\u00fe'), // latin small letter thorn, U+00FE ISOlat1
    new CharacterReference ("yuml",     '\u00ff'), // latin small letter y with diaeresis, U+00FF ISOlat1
    // Mathematical, Greek and Symbolic characters for HTML
    // Character entity set. Typical invocation:
    // <!ENTITY % HTMLsymbol PUBLIC
    // "-//W3C//ENTITIES Symbols//EN//HTML">
    // %HTMLsymbol;
    // Portions (c) International Organization for Standardization 1986:
    // Permission to copy in any form is granted for use with
    // conforming SGML systems and applications as defined in
    // ISO 8879, provided this notice is included in all copies.
    // Relevant ISO entity set is given unless names are newly introduced.
    // New names (i.e., not in ISO 8879 list) do not clash with any
    // existing ISO 8879 entity names. ISO 10646 character numbers
    // are given for each character, in hex. CDATA values are decimal
    // conversions of the ISO 10646 values and refer to the document
    // character set. Names are ISO 10646 names.
    // Latin Extended-B
    new CharacterReference ("fnof",     '\u0192'), // latin small f with hook = function = florin, U+0192 ISOtech
    // Greek
    new CharacterReference ("Alpha",    '\u0391'), // greek capital letter alpha, U+0391
    new CharacterReference ("Beta",     '\u0392'), // greek capital letter beta, U+0392
    new CharacterReference ("Gamma",    '\u0393'), // greek capital letter gamma, U+0393 ISOgrk3
    new CharacterReference ("Delta",    '\u0394'), // greek capital letter delta, U+0394 ISOgrk3
    new CharacterReference ("Epsilon",  '\u0395'), // greek capital letter epsilon, U+0395
    new CharacterReference ("Zeta",     '\u0396'), // greek capital letter zeta, U+0396
    new CharacterReference ("Eta",      '\u0397'), // greek capital letter eta, U+0397
    new CharacterReference ("Theta",    '\u0398'), // greek capital letter theta, U+0398 ISOgrk3
    new CharacterReference ("Iota",     '\u0399'), // greek capital letter iota, U+0399
    new CharacterReference ("Kappa",    '\u039a'), // greek capital letter kappa, U+039A
    new CharacterReference ("Lambda",   '\u039b'), // greek capital letter lambda, U+039B ISOgrk3
    new CharacterReference ("Mu",       '\u039c'), // greek capital letter mu, U+039C
    new CharacterReference ("Nu",       '\u039d'), // greek capital letter nu, U+039D
    new CharacterReference ("Xi",       '\u039e'), // greek capital letter xi, U+039E ISOgrk3
    new CharacterReference ("Omicron",  '\u039f'), // greek capital letter omicron, U+039F
    new CharacterReference ("Pi",       '\u03a0'), // greek capital letter pi, U+03A0 ISOgrk3
    new CharacterReference ("Rho",      '\u03a1'), // greek capital letter rho, U+03A1
    // there is no Sigmaf, and no U+03A2 character either
    new CharacterReference ("Sigma",    '\u03a3'), // greek capital letter sigma, U+03A3 ISOgrk3
    new CharacterReference ("Tau",      '\u03a4'), // greek capital letter tau, U+03A4
    new CharacterReference ("Upsilon",  '\u03a5'), // greek capital letter upsilon, U+03A5 ISOgrk3
    new CharacterReference ("Phi",      '\u03a6'), // greek capital letter phi, U+03A6 ISOgrk3
    new CharacterReference ("Chi",      '\u03a7'), // greek capital letter chi, U+03A7
    new CharacterReference ("Psi",      '\u03a8'), // greek capital letter psi, U+03A8 ISOgrk3
    new CharacterReference ("Omega",    '\u03a9'), // greek capital letter omega, U+03A9 ISOgrk3
    new CharacterReference ("alpha",    '\u03b1'), // greek small letter alpha, U+03B1 ISOgrk3
    new CharacterReference ("beta",     '\u03b2'), // greek small letter beta, U+03B2 ISOgrk3
    new CharacterReference ("gamma",    '\u03b3'), // greek small letter gamma, U+03B3 ISOgrk3
    new CharacterReference ("delta",    '\u03b4'), // greek small letter delta, U+03B4 ISOgrk3
    new CharacterReference ("epsilon",  '\u03b5'), // greek small letter epsilon, U+03B5 ISOgrk3
    new CharacterReference ("zeta",     '\u03b6'), // greek small letter zeta, U+03B6 ISOgrk3
    new CharacterReference ("eta",      '\u03b7'), // greek small letter eta, U+03B7 ISOgrk3
    new CharacterReference ("theta",    '\u03b8'), // greek small letter theta, U+03B8 ISOgrk3
    new CharacterReference ("iota",     '\u03b9'), // greek small letter iota, U+03B9 ISOgrk3
    new CharacterReference ("kappa",    '\u03ba'), // greek small letter kappa, U+03BA ISOgrk3
    new CharacterReference ("lambda",   '\u03bb'), // greek small letter lambda, U+03BB ISOgrk3
    new CharacterReference ("mu",       '\u03bc'), // greek small letter mu, U+03BC ISOgrk3
    new CharacterReference ("nu",       '\u03bd'), // greek small letter nu, U+03BD ISOgrk3
    new CharacterReference ("xi",       '\u03be'), // greek small letter xi, U+03BE ISOgrk3
    new CharacterReference ("omicron",  '\u03bf'), // greek small letter omicron, U+03BF NEW
    new CharacterReference ("pi",       '\u03c0'), // greek small letter pi, U+03C0 ISOgrk3
    new CharacterReference ("rho",      '\u03c1'), // greek small letter rho, U+03C1 ISOgrk3
    new CharacterReference ("sigmaf",   '\u03c2'), // greek small letter final sigma, U+03C2 ISOgrk3
    new CharacterReference ("sigma",    '\u03c3'), // greek small letter sigma, U+03C3 ISOgrk3
    new CharacterReference ("tau",      '\u03c4'), // greek small letter tau, U+03C4 ISOgrk3
    new CharacterReference ("upsilon",  '\u03c5'), // greek small letter upsilon, U+03C5 ISOgrk3
    new CharacterReference ("phi",      '\u03c6'), // greek small letter phi, U+03C6 ISOgrk3
    new CharacterReference ("chi",      '\u03c7'), // greek small letter chi, U+03C7 ISOgrk3
    new CharacterReference ("psi",      '\u03c8'), // greek small letter psi, U+03C8 ISOgrk3
    new CharacterReference ("omega",    '\u03c9'), // greek small letter omega, U+03C9 ISOgrk3
    new CharacterReference ("thetasym", '\u03d1'), // greek small letter theta symbol, U+03D1 NEW
    new CharacterReference ("upsih",    '\u03d2'), // greek upsilon with hook symbol, U+03D2 NEW
    new CharacterReference ("piv",      '\u03d6'), // greek pi symbol, U+03D6 ISOgrk3
    // General Punctuation
    new CharacterReference ("bull",     '\u2022'), // bullet = black small circle, U+2022 ISOpub
    // bullet is NOT the same as bullet operator, U+2219
    new CharacterReference ("hellip",   '\u2026'), // horizontal ellipsis = three dot leader, U+2026 ISOpub
    new CharacterReference ("prime",    '\u2032'), // prime = minutes = feet, U+2032 ISOtech
    new CharacterReference ("Prime",    '\u2033'), // double prime = seconds = inches, U+2033 ISOtech
    new CharacterReference ("oline",    '\u203e'), // overline = spacing overscore, U+203E NEW
    new CharacterReference ("frasl",    '\u2044'), // fraction slash, U+2044 NEW
    // Letterlike Symbols
    new CharacterReference ("weierp",   '\u2118'), // script capital P = power set = Weierstrass p, U+2118 ISOamso
    new CharacterReference ("image",    '\u2111'), // blackletter capital I = imaginary part, U+2111 ISOamso
    new CharacterReference ("real",     '\u211c'), // blackletter capital R = real part symbol, U+211C ISOamso
    new CharacterReference ("trade",    '\u2122'), // trade mark sign, U+2122 ISOnum
    new CharacterReference ("alefsym",  '\u2135'), // alef symbol = first transfinite cardinal, U+2135 NEW
    // alef symbol is NOT the same as hebrew letter alef,
    // U+05D0 although the same glyph could be used to depict both characters
    // Arrows
    new CharacterReference ("larr",     '\u2190'), // leftwards arrow, U+2190 ISOnum
    new CharacterReference ("uarr",     '\u2191'), // upwards arrow, U+2191 ISOnum
    new CharacterReference ("rarr",     '\u2192'), // rightwards arrow, U+2192 ISOnum
    new CharacterReference ("darr",     '\u2193'), // downwards arrow, U+2193 ISOnum
    new CharacterReference ("harr",     '\u2194'), // left right arrow, U+2194 ISOamsa
    new CharacterReference ("crarr",    '\u21b5'), // downwards arrow with corner leftwards = carriage return, U+21B5 NEW
    new CharacterReference ("lArr",     '\u21d0'), // leftwards double arrow, U+21D0 ISOtech
    // ISO 10646 does not say that lArr is the same as the 'is implied by' arrow
    // but also does not have any other character for that function. So ? lArr can
    // be used for 'is implied by' as ISOtech suggests
    new CharacterReference ("uArr",     '\u21d1'), // upwards double arrow, U+21D1 ISOamsa
    new CharacterReference ("rArr",     '\u21d2'), // rightwards double arrow, U+21D2 ISOtech
    // ISO 10646 does not say this is the 'implies' character but does not have
    // another character with this function so ?
    // rArr can be used for 'implies' as ISOtech suggests
    new CharacterReference ("dArr",     '\u21d3'), // downwards double arrow, U+21D3 ISOamsa
    new CharacterReference ("hArr",     '\u21d4'), // left right double arrow, U+21D4 ISOamsa
    // Mathematical Operators
    new CharacterReference ("forall",   '\u2200'), // for all, U+2200 ISOtech
    new CharacterReference ("part",     '\u2202'), // partial differential, U+2202 ISOtech
    new CharacterReference ("exist",    '\u2203'), // there exists, U+2203 ISOtech
    new CharacterReference ("empty",    '\u2205'), // empty set = null set = diameter, U+2205 ISOamso
    new CharacterReference ("nabla",    '\u2207'), // nabla = backward difference, U+2207 ISOtech
    new CharacterReference ("isin",     '\u2208'), // element of, U+2208 ISOtech
    new CharacterReference ("notin",    '\u2209'), // not an element of, U+2209 ISOtech
    new CharacterReference ("ni",       '\u220b'), // contains as member, U+220B ISOtech
    // should there be a more memorable name than 'ni'?
    new CharacterReference ("prod",     '\u220f'), // n-ary product = product sign, U+220F ISOamsb
    // prod is NOT the same character as U+03A0 'greek capital letter pi' though
    // the same glyph might be used for both
    new CharacterReference ("sum",      '\u2211'), // n-ary sumation, U+2211 ISOamsb
    // sum is NOT the same character as U+03A3 'greek capital letter sigma'
    // though the same glyph might be used for both
    new CharacterReference ("minus",    '\u2212'), // minus sign, U+2212 ISOtech
    new CharacterReference ("lowast",   '\u2217'), // asterisk operator, U+2217 ISOtech
    new CharacterReference ("radic",    '\u221a'), // square root = radical sign, U+221A ISOtech
    new CharacterReference ("prop",     '\u221d'), // proportional to, U+221D ISOtech
    new CharacterReference ("infin",    '\u221e'), // infinity, U+221E ISOtech
    new CharacterReference ("ang",      '\u2220'), // angle, U+2220 ISOamso
    new CharacterReference ("and",      '\u2227'), // logical and = wedge, U+2227 ISOtech
    new CharacterReference ("or",       '\u2228'), // logical or = vee, U+2228 ISOtech
    new CharacterReference ("cap",      '\u2229'), // intersection = cap, U+2229 ISOtech
    new CharacterReference ("cup",      '\u222a'), // union = cup, U+222A ISOtech
    new CharacterReference ("int",      '\u222b'), // integral, U+222B ISOtech
    new CharacterReference ("there4",   '\u2234'), // therefore, U+2234 ISOtech
    new CharacterReference ("sim",      '\u223c'), // tilde operator = varies with = similar to, U+223C ISOtech
    // tilde operator is NOT the same character as the tilde, U+007E,
    // although the same glyph might be used to represent both
    new CharacterReference ("cong",     '\u2245'), // approximately equal to, U+2245 ISOtech
    new CharacterReference ("asymp",    '\u2248'), // almost equal to = asymptotic to, U+2248 ISOamsr
    new CharacterReference ("ne",       '\u2260'), // not equal to, U+2260 ISOtech
    new CharacterReference ("equiv",    '\u2261'), // identical to, U+2261 ISOtech
    new CharacterReference ("le",       '\u2264'), // less-than or equal to, U+2264 ISOtech
    new CharacterReference ("ge",       '\u2265'), // greater-than or equal to, U+2265 ISOtech
    new CharacterReference ("sub",      '\u2282'), // subset of, U+2282 ISOtech
    new CharacterReference ("sup",      '\u2283'), // superset of, U+2283 ISOtech
    // note that nsup, 'not a superset of, U+2283' is not covered by the Symbol
    // font encoding and is not included. Should it be, for symmetry?
    // It is in ISOamsn
    new CharacterReference ("nsub",     '\u2284'), // not a subset of, U+2284 ISOamsn
    new CharacterReference ("sube",     '\u2286'), // subset of or equal to, U+2286 ISOtech
    new CharacterReference ("supe",     '\u2287'), // superset of or equal to, U+2287 ISOtech
    new CharacterReference ("oplus",    '\u2295'), // circled plus = direct sum, U+2295 ISOamsb
    new CharacterReference ("otimes",   '\u2297'), // circled times = vector product, U+2297 ISOamsb
    new CharacterReference ("perp",     '\u22a5'), // up tack = orthogonal to = perpendicular, U+22A5 ISOtech
    new CharacterReference ("sdot",     '\u22c5'), // dot operator, U+22C5 ISOamsb
    // dot operator is NOT the same character as U+00B7 middle dot
    // Miscellaneous Technical
    new CharacterReference ("lceil",    '\u2308'), // left ceiling = apl upstile, U+2308 ISOamsc
    new CharacterReference ("rceil",    '\u2309'), // right ceiling, U+2309 ISOamsc
    new CharacterReference ("lfloor",   '\u230a'), // left floor = apl downstile, U+230A ISOamsc
    new CharacterReference ("rfloor",   '\u230b'), // right floor, U+230B ISOamsc
    new CharacterReference ("lang",     '\u2329'), // left-pointing angle bracket = bra, U+2329 ISOtech
    // lang is NOT the same character as U+003C 'less than'
    // or U+2039 'single left-pointing angle quotation mark'
    new CharacterReference ("rang",     '\u232a'), // right-pointing angle bracket = ket, U+232A ISOtech
    // rang is NOT the same character as U+003E 'greater than'
    // or U+203A 'single right-pointing angle quotation mark'
    // Geometric Shapes
    new CharacterReference ("loz",      '\u25ca'), // lozenge, U+25CA ISOpub
    // Miscellaneous Symbols
    new CharacterReference ("spades",   '\u2660'), // black spade suit, U+2660 ISOpub
    // black here seems to mean filled as opposed to hollow
    new CharacterReference ("clubs",    '\u2663'), // black club suit = shamrock, U+2663 ISOpub
    new CharacterReference ("hearts",   '\u2665'), // black heart suit = valentine, U+2665 ISOpub
    new CharacterReference ("diams",    '\u2666'), // black diamond suit, U+2666 ISOpub
    // Special characters for HTML
    // Character entity set. Typical invocation:
    // <!ENTITY % HTMLspecial PUBLIC
    // "-//W3C//ENTITIES Special//EN//HTML">
    // %HTMLspecial;
    // Portions (c) International Organization for Standardization 1986:
    // Permission to copy in any form is granted for use with
    // conforming SGML systems and applications as defined in
    // ISO 8879, provided this notice is included in all copies.
    // Relevant ISO entity set is given unless names are newly introduced.
    // New names (i.e., not in ISO 8879 list) do not clash with any
    // existing ISO 8879 entity names. ISO 10646 character numbers
    // are given for each character, in hex. CDATA values are decimal
    // conversions of the ISO 10646 values and refer to the document
    // character set. Names are ISO 10646 names.
    // C0 Controls and Basic Latin
    new CharacterReference ("quot",     '\u0022'), // quotation mark = APL quote, U+0022 ISOnum
    new CharacterReference ("amp",      '\u0026'), // ampersand, U+0026 ISOnum
    new CharacterReference ("lt",       '\u003c'), // less-than sign, U+003C ISOnum
    new CharacterReference ("gt",       '\u003e'), // greater-than sign, U+003E ISOnum
    // Latin Extended-A
    new CharacterReference ("OElig",    '\u0152'), // latin capital ligature OE, U+0152 ISOlat2
    new CharacterReference ("oelig",    '\u0153'), // latin small ligature oe, U+0153 ISOlat2
    // ligature is a misnomer, this is a separate character in some languages
    new CharacterReference ("Scaron",   '\u0160'), // latin capital letter S with caron, U+0160 ISOlat2
    new CharacterReference ("scaron",   '\u0161'), // latin small letter s with caron, U+0161 ISOlat2
    new CharacterReference ("Yuml",     '\u0178'), // latin capital letter Y with diaeresis, U+0178 ISOlat2
    // Spacing Modifier Letters
    new CharacterReference ("circ",     '\u02c6'), // modifier letter circumflex accent, U+02C6 ISOpub
    new CharacterReference ("tilde",    '\u02dc'), // small tilde, U+02DC ISOdia
    // General Punctuation
    new CharacterReference ("ensp",     '\u2002'), // en space, U+2002 ISOpub
    new CharacterReference ("emsp",     '\u2003'), // em space, U+2003 ISOpub
    new CharacterReference ("thinsp",   '\u2009'), // thin space, U+2009 ISOpub
    new CharacterReference ("zwnj",     '\u200c'), // zero width non-joiner, U+200C NEW RFC 2070
    new CharacterReference ("zwj",      '\u200d'), // zero width joiner, U+200D NEW RFC 2070
    new CharacterReference ("lrm",      '\u200e'), // left-to-right mark, U+200E NEW RFC 2070
    new CharacterReference ("rlm",      '\u200f'), // right-to-left mark, U+200F NEW RFC 2070
    new CharacterReference ("ndash",    '\u2013'), // en dash, U+2013 ISOpub
    new CharacterReference ("mdash",    '\u2014'), // em dash, U+2014 ISOpub
    new CharacterReference ("lsquo",    '\u2018'), // left single quotation mark, U+2018 ISOnum
    new CharacterReference ("rsquo",    '\u2019'), // right single quotation mark, U+2019 ISOnum
    new CharacterReference ("sbquo",    '\u201a'), // single low-9 quotation mark, U+201A NEW
    new CharacterReference ("ldquo",    '\u201c'), // left double quotation mark, U+201C ISOnum
    new CharacterReference ("rdquo",    '\u201d'), // right double quotation mark, U+201D ISOnum
    new CharacterReference ("bdquo",    '\u201e'), // double low-9 quotation mark, U+201E NEW
    new CharacterReference ("dagger",   '\u2020'), // dagger, U+2020 ISOpub
    new CharacterReference ("Dagger",   '\u2021'), // double dagger, U+2021 ISOpub
    new CharacterReference ("permil",   '\u2030'), // per mille sign, U+2030 ISOtech
    new CharacterReference ("lsaquo",   '\u2039'), // single left-pointing angle quotation mark, U+2039 ISO proposed
    // lsaquo is proposed but not yet ISO standardized
    new CharacterReference ("rsaquo",   '\u203a'), // single right-pointing angle quotation mark, U+203A ISO proposed
    // rsaquo is proposed but not yet ISO standardized
    new CharacterReference ("euro",     '\u20ac'), // euro sign, U+20AC NEW
    };

  /**
   * The dividing point between a simple table lookup and a binary search.
   * Characters below the break point are stored in a sparse array allowing
   * direct index lookup.
   */
  protected static final int BREAKPOINT = 0x100;

  /**
   * List of references sorted by character.
   * The first part of this array, up to <code>BREAKPOINT</code> is stored
   * in a direct translational table, indexing into the table with a character
   * yields the reference. The second part is dense and sorted by character,
   * suitable for binary lookup.
   */
  protected static final CharacterReference[] mCharacterList;

  static
  {
    int index;
    CharacterReference item;
    int character;

    // count below the break point
    index = 0;
    for (int i = 0; i < mCharacterReferences.length; i++)
      if (mCharacterReferences[i].getCharacter () < BREAKPOINT)
        index++;
    // allocate enough for the linear table and remainder
    mCharacterList = new CharacterReference[BREAKPOINT + mCharacterReferences.length - index];
    index = BREAKPOINT;
    for (int i = 0; i < mCharacterReferences.length; i++)
    {
      item = mCharacterReferences[i];
      character = mCharacterReferences[i].getCharacter ();
      if (character < BREAKPOINT)
        mCharacterList[character] = item;
      else
      {
        // use a linear search and insertion sort, done only once
        int x = BREAKPOINT;
        while (x < index)
          if (mCharacterList[x].getCharacter () > character)
            break;
          else
            x++;
        int y = index - 1;
        while (y >= x)
        {
          mCharacterList[y + 1] = mCharacterList[y];
          y--;
        }
        mCharacterList[x] = item;
        index++;
      }
    }
    // reorder the original array into kernel order
    java.util.Arrays.sort(mCharacterReferences);
  }

  /**
   * Private constructor.
   * This class is fully static and thread safe.
   */
  private Translate ()
  {
  }

  /**
   * Binary search for a reference.
   * @param array The array of <code>CharacterReference</code> objects.
   * @param ref The character to search for.
   * @param lo The lower index within which to look.
   * @param hi The upper index within which to look.
   * @return The index at which reference was found or is to be inserted.
   */
  protected static int lookup (CharacterReference[] array, char ref, int lo, int hi) {
    int num;
    int mid;
    int half;
    int result;
    int ret;

    ret = -1;

    num = (hi - lo) + 1;
    while ((-1 == ret) && (lo <= hi))
    {
      half = num / 2;
      mid = lo + ((0 != (num & 1)) ? half : half - 1);
      result = ref - array[mid].getCharacter ();
      if (0 == result)
        ret = mid;
      else if (0 > result)
      {
        hi = mid - 1;
        num = ((0 != (num & 1)) ? half : half - 1);
      }
      else
      {
        lo = mid + 1;
        num = half;
      }
    }
    if (-1 == ret)
      ret = lo;

    return (ret);
  }

  /**
   * Look up a reference by character.
   * Use a combination of direct table lookup and binary search to find
   * the reference corresponding to the character.
   * @param character The character to be looked up.
   * @return The entity reference for that character or <code>null</code>.
   */
  public static CharacterReference lookup (char character)
  {
    int index;
    CharacterReference ret;

    if (character < BREAKPOINT)
      ret = mCharacterList[character];
    else
    {
      index = lookup (mCharacterList, character, BREAKPOINT, mCharacterList.length - 1);
      if (index < mCharacterList.length)
      {
        ret = mCharacterList[index];
        if (character != ret.getCharacter ())
          ret = null;
      }
      else
        ret = null;
    }

    return (ret);
  }

  /**
   * Look up a reference by kernel.
   * Use a binary search on the ordered list of known references.
   * Since the binary search returns the position at which a new item should
   * be inserted, we check the references earlier in the list if there is
   * a failure.
   * @param key A character reference with the kernel set to the string
   * to be found. It need not be truncated at the exact end of the reference.
   */
  protected static CharacterReference lookup (CharacterReference key)
  {
    String string;
    int index;
    String kernel;
    char character;
    CharacterReference test;
    CharacterReference ret;

    // Care should be taken here because some entity references are
    // prefixes of others, i.e.:
    // \u2209[notin] \u00ac[not]
    // \u00ba[ordm] \u2228[or]
    // \u03d6[piv] \u03c0[pi]
    // \u00b3[sup3] \u2283[sup]
    ret = null;
    index = java.util.Arrays.binarySearch(mCharacterReferences, key);
    string = key.getKernel ();
    if (index < mCharacterReferences.length && index >= 0)
    {
      ret = mCharacterReferences[index];
      kernel = ret.getKernel ();
      if (!string.regionMatches (
          0,
          kernel,
          0,
          kernel.length ()))
      {   // not exact, check references starting with same character
        // to see if a subset matches
        ret = null;
      }
    }
    if (null == ret)
    {
      character = string.charAt (0);
      while (--index >= 0)
      {
        test = mCharacterReferences[index];
        kernel = test.getKernel ();
        if (character == kernel.charAt (0))
        {
          if (string.regionMatches (
              0,
              kernel,
              0,
              kernel.length ()))
          {
            ret = test;
            break;
          }
        }
        else
          break;
      }
    }

    return (ret);
  }

  /**
   * Look up a reference by kernel.
   * Use a binary search on the ordered list of known references.
   * <em>This is not very efficient, use {@link org.htmlparser.util.Translate#lookup(org.htmlparser.util.CharacterReference) lookup(CharacterReference)}
   * instead.</em>
   * @param kernel The string to lookup, i.e. "amp".
   * @param start The starting point in the string of the kernel.
   * @param end The ending point in the string of the kernel.
   * This should be the index of the semicolon if it exists, or failing that,
   * at least an index past the last character of the kernel.
   * @return The reference that matches the given string, or <code>null</code>
   * if it wasn't found.
   */
  public static CharacterReference lookup (String kernel, int start, int end)
  {
    CharacterReferenceEx probe;

    probe = new CharacterReferenceEx ();
    probe.setKernel (kernel);
    probe.setStart (start);
    probe.setEnd (end);

    return (lookup (probe));
  }

  /**
   * Convert a reference to a unicode character.
   * Convert a single numeric character reference or character entity reference
   * to a unicode character.
   * @param string The string to convert. Of the form &xxxx; or &amp;#xxxx; with
   * or without the leading ampersand or trailing semi-colon.
   * @param start The starting pooint in the string to look for a character reference.
   * @param end The ending point in the string to stop looking for a character reference.
   * @return The converted character or '' (zero) if the string is an
   * invalid reference.
   * @deprecated Use {@link #decode(String) decode}.
   */
  public static char convertToChar (String string, int start, int end)
  {
    return (decode (string.substring (start, end)).charAt (0));
  }

  /**
   * Convert a reference to a unicode character.
   * Convert a single numeric character reference or character entity reference
   * to a unicode character.
   * @param string The string to convert. Of the form &xxxx; or &amp;#xxxx; with
   * or without the leading ampersand or trailing semi-colon.
   * @return The converted character or '' (zero) if the string is an
   * invalid reference.
   * @deprecated Use {@link #decode(String) decode}.
   */
  public static char convertToChar (String string)
  {
    return (decode (string).charAt (0));
  }

  /**
   * Decode a string containing references.
   * Change all numeric character reference and character entity references
   * to unicode characters.
   * @param string The string to translate.
   */
  public static String decode (String string)
  {
    CharacterReferenceEx key;
    int amp;
    int index;
    int length;
    StringBuffer buffer;
    char character;
    int number;
    int radix;
    int i;
    int semi;
    boolean done;
    CharacterReference item;
    String ret;

    if (-1 == (amp = string.indexOf ('&')))
      ret = string;
    else
    {
      key = null;
      index = 0;
      length = string.length ();
      buffer = new StringBuffer (length);
      do
      {
        // equivalent to buffer.append (string.substring (index, amp));
        // but without the allocation of a new String
        while (index < amp)
          buffer.append (string.charAt (index++));

        index++;
        if (index < length)
        {
          character = string.charAt (index);
          if ('#' == character)
          {
            // numeric character reference
            index++;
            number = 0;
            radix = 0;
            i = index;
            done = false;
            while ((i < length) && !done)
            {
              character = string.charAt (i);
              switch (character)
              {
                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9':
                  if (0 == radix)
                    radix = 10;
                  number = number * radix + (character - '0');
                  break;
                case 'A':
                case 'B':
                case 'C':
                case 'D':
                case 'E':
                case 'F':
                  if (16 == radix)
                    number = number * radix + (character - 'A' + 10);
                  else
                    done = true;
                  break;
                case 'a':
                case 'b':
                case 'c':
                case 'd':
                case 'e':
                case 'f':
                  if (16 == radix)
                    number = number * radix + (character - 'a' + 10);
                  else
                    done = true;
                  break;
                case 'x':
                case 'X':
                  if (0 == radix)
                    radix = 16;
                  else
                    done = true;
                  break;
                case ';':
                  done = true;
                  i++;
                  break;
                default:
                  done = true;
                  break;
              }
              if (!done)
                i++;
            }
            if (0 != number)
            {
              buffer.append ((char)number);
              index = i;
              amp = index;
            }

          }
          else if (Character.isLetter (character)) // really can't start with a digit eh...
          {
            // character entity reference
            i = index + 1;
            done = false;
            semi = length;
            while ((i < length) && !done)
            {
              character = string.charAt (i);
              if (';' == character)
              {
                done = true;
                semi = i;
                i++;
              }
              else if (Character.isLetterOrDigit (character))
                i++;
              else
              {
                done = true;
                semi = i;
              }
            }
            // new CharacterReference (string.substring (index, semi), 0);
            if (null == key)
              key = new CharacterReferenceEx ();
            key.setKernel (string);
            key.setStart (index);
            key.setEnd (semi);
            item = lookup (key);
            if (null != item)
            {
              buffer.append ((char)item.getCharacter ());
              index += item.getKernel ().length ();
              if ((index < length) && (';' == string.charAt (index)))
                index++;
              amp = index;
            }
          }
          else
          {
            // need do nothing here, the ampersand will be consumed below
          }
        }
        // gather up unconsumed characters
        while (amp < index)
          buffer.append (string.charAt (amp++));
      }
      while ((index < length) && (-1 != (amp = string.indexOf ('&', index))));
      // equivalent to buffer.append (string.substring (index));
      // but without the allocation of a new String
      while (index < length)
        buffer.append (string.charAt (index++));
      ret = buffer.toString ();
    }

    return (ret);
  }

  /**
   * Decode the characters in a string buffer containing references.
   * Change all numeric character reference and character entity references
   * to unicode characters.
   * @param buffer The StringBuffer containing references.
   * @return The decoded string.
   */
  public static String decode (StringBuffer buffer)
  {
    return decode (buffer.toString());
  }

  /**
   * Decode a stream containing references.
   * Change all numeric character reference and character entity references
   * to unicode characters. If <code>DECODE_LINE_BY_LINE</code> is true,
   * the input stream is broken up into lines, terminated by either
   * carriage return or newline, in order to reduce the latency and maximum
   * buffering memory size required.
   * @param in The stream to translate. It is assumed that the input
   * stream is encoded with ISO-8859-1 since the table of character
   * entity references in this class applies only to ISO-8859-1.
   * @param out The stream to write the decoded stream to.
   */
  public static void decode (InputStream in, PrintStream out)
  {
    Reader reader;
    StringBuffer buffer;
    int character;
    String string;
    boolean newlines;

    try
    {
      try
      {
        reader = new BufferedReader (new InputStreamReader (in, "ISO-8859-1"));
      }
      catch (UnsupportedEncodingException use)
      {
        // yeah, like this will happen; OK, assume the default is ISO-8859-1
        reader = new BufferedReader (new InputStreamReader (in));
      }
      buffer = new StringBuffer (1024);
      newlines = false;
      if (DECODE_LINE_BY_LINE)
        while (-1 != (character = reader.read ()))
        {
          if (('\r' == character) || ('\n' == character))
          {
            if (!newlines)
            {
              string = decode (buffer.toString ());
              out.print (string);
              buffer.setLength (0);
              newlines = true;
            }
            buffer.append ((char)character);
          }
          else
          {
            if (newlines)
            {
              out.print (buffer.toString ());
              buffer.setLength (0);
              newlines = false;
            }
            buffer.append ((char)character);
          }
        }
      else
        while (-1 != (character = reader.read ()))
          buffer.append ((char)character);
      if (0 != buffer.length ())
      {
        if (newlines)
          out.print (buffer.toString ());
        else
        {
          string = decode (buffer.toString ());
          out.print (string);
        }
      }
    }
    catch (IOException ioe)
    {
      out.println ();
      out.println (ioe.getMessage ());
    }
    finally
    {
      out.flush ();
    }
  }

  /**
   * Convert a character to a numeric character reference.
   * Convert a unicode character to a numeric character reference of
   * the form &amp;#xxxx;.
   * @param character The character to convert.
   * @return The converted character.
   * @deprecated Use {@link #encode(int) encode}.
   */
  public static String convertToString (int character)
  {
    return (encode (character));
  }

  /**
   * Convert a character to a numeric character reference.
   * Convert a unicode character to a numeric character reference of
   * the form &amp;#xxxx;.
   * @param character The character to convert.
   * @return The converted character.
   */
  public static String encode (int character)
  {
    StringBuffer ret;

    ret = new StringBuffer (13); /* &#2147483647; */
    ret.append ("&#");
    if (ENCODE_HEXADECIMAL)
    {
      ret.append ("x");
      ret.append (Integer.toHexString (character));
    }
    else
      ret.append (character);
    ret.append (';');

    return (ret.toString ());
  }

  /**
   * Encode a string to use references.
   * Change all characters that are not ISO-8859-1 to their numeric character
   * reference or character entity reference.
   * @param string The string to translate.
   * @return The encoded string.
   */
  public static String encode (String string)
  {
    int length;
    char c;
    CharacterReference candidate;
    StringBuffer ret;
    ret = new StringBuffer (string.length () * 6);
    length  = string.length ();
    for (int i = 0; i < length; i++)
    {
      c = string.charAt (i);
      candidate = lookup (c);
      if (null != candidate)
      {
        ret.append ('&');
        ret.append (candidate.getKernel ());
        ret.append (';');
      }
      else if (!(c < 0x007F))
      {
        ret.append ("&#");
        if (ENCODE_HEXADECIMAL)
        {
          ret.append ("x");
          ret.append (Integer.toHexString (c));
        }
        else
          ret.append ((int)c);
        ret.append (';');
      }
      else
        ret.append (c);
    }

    return (ret.toString ());
  }

  /**
   * Encode a stream to use references.
   * Change all characters that are not ISO-8859-1 to their numeric character
   * reference or character entity reference.
   * @param in The stream to translate. It is assumed that the input
   * stream is encoded with ISO-8859-1 since the table of character
   * entity references in this class applies only to ISO-8859-1.
   * @param out The stream to write the decoded stream to.
   */
  public static void encode (InputStream in, PrintStream out)
  {
    Reader reader;
    char c;
    int index;
    CharacterReference candidate;
    PrintWriter output;

    try
    {
      reader = new BufferedReader (new InputStreamReader (in, "ISO-8859-1"));
      output = new PrintWriter (new BufferedWriter (new OutputStreamWriter (out, "ISO-8859-1")));
    }
    catch (UnsupportedEncodingException use)
    {
      // yeah, like this will happen; OK, assume default is ISO-8859-1
      reader = new BufferedReader (new InputStreamReader (in));
      output = new PrintWriter (new BufferedWriter (new OutputStreamWriter (out)));
    }
    try
    {
      while (-1 != (index = reader.read ()))
      {
        c = (char)index;
        candidate = lookup (c);
        if (null != candidate)
        {
          output.print ('&');
          output.print (candidate.getKernel ());
          output.print (';');
        }
        else if (!(c < 0x007F))
        {
          output.print ("&#");
          if (ENCODE_HEXADECIMAL)
          {
            output.print ("x");
            output.print (Integer.toHexString (c));
          }
          else
            output.print ((int)c);
          output.print (';');
        }
        else
          output.print (c);
      }
    }
    catch (IOException ioe)
    {
      output.println ();
      output.println (ioe.getMessage ());
    }
    finally
    {
      output.flush ();
    }
  }

  /**
   * Numeric character reference and character entity reference to unicode codec.
   * Translate the <code>System.in</code> input into an encoded or decoded
   * stream and send the results to <code>System.out</code>.
   * @param args If arg[0] is <code>-encode</code> perform an encoding on
   * <code>System.in</code>, otherwise perform a decoding.
   */
  public static void main (String[] args)
  {
    boolean encode;

    if (0 < args.length && args[0].equalsIgnoreCase ("-encode"))
      encode = true;
    else
      encode = false;
    if (encode)
      encode (System.in, System.out);
    else
      decode (System.in, System.out);
  }
}

<MSG> Merge remote-tracking branch 'google/master'

<DFF> @@ -35,9 +35,9 @@ import java.io.UnsupportedEncodingException;
  * Structure to hold a character and it's equivalent entity reference kernel.
  * For the character reference &amp;copy; the character would be '&copy;' and
  * the kernel would be "copy", for example.<p>
- * Character references are described at <a href="Character references">http://www.w3.org/TR/REC-html40/charset.html#entities</a>
+ * Character references are described at <a href="http://www.w3.org/TR/REC-html40/charset.html#entities">Character references</a>
  * Supports the Ordered interface so it's easy to create a list sorted by
- * kernel, to perform binary searches on.<p>
+ * kernel, to perform binary searches on.
  */
 class CharacterReference
 implements
@@ -134,7 +134,6 @@ Comparable
 
   /**
    * Compare one reference to another.
-   * @see org.htmlparser.util.sort.Ordered
    */
   public int compareTo (Object that)
   {
@@ -205,7 +204,6 @@ class CharacterReferenceEx extends CharacterReference
 
   /**
    * Compare one reference to another.
-   * @see org.htmlparser.util.sort.Ordered
    */
   public int compare (Object that)
   {
@@ -812,7 +810,7 @@ public class Translate
   /**
    * Look up a reference by kernel.
    * Use a binary search on the ordered list of known references.
-   * <em>This is not very efficient, use {@link org.htmlparser.util.Translate#lookup(org.htmlparser.util.CharacterReference) lookup(CharacterReference)}
+   * <em>This is not very efficient, use org.htmlparser.util.Translate.lookup(org.htmlparser.util.CharacterReference)
    * instead.</em>
    * @param kernel The string to lookup, i.e. "amp".
    * @param start The starting point in the string of the kernel.
@@ -838,7 +836,7 @@ public class Translate
    * Convert a reference to a unicode character.
    * Convert a single numeric character reference or character entity reference
    * to a unicode character.
-   * @param string The string to convert. Of the form &xxxx; or &amp;#xxxx; with
+   * @param string The string to convert. Of the form &amp;xxxx; or &amp;#xxxx; with
    * or without the leading ampersand or trailing semi-colon.
    * @param start The starting pooint in the string to look for a character reference.
    * @param end The ending point in the string to stop looking for a character reference.
@@ -855,7 +853,7 @@ public class Translate
    * Convert a reference to a unicode character.
    * Convert a single numeric character reference or character entity reference
    * to a unicode character.
-   * @param string The string to convert. Of the form &xxxx; or &amp;#xxxx; with
+   * @param string The string to convert. Of the form &amp;xxxx; or &amp;#xxxx; with
    * or without the leading ampersand or trailing semi-colon.
    * @return The converted character or '' (zero) if the string is an
    * invalid reference.

{'commit': 'diff --git a/java/sage/CaptureDeviceInput.java b/java/sage/CaptureDeviceInput.java\nindex e8e3778a..54a6fa9c 100644\n--- a/java/sage/CaptureDeviceInput.java\n+++ b/java/sage/CaptureDeviceInput.java\n@@ -20,7 +20,6 @@ public class CaptureDeviceInput\n   private static final String CABLE_BASED_RF = "cable_based_rf";\n   private static final String ATSC_TUNING = "atsc_tuning";\n   private static final String TUNING_MODE = "tuning_mode";\n-  public static final String AVAILABLE_CHANNELS = "available_channels";\n   public static final String CABLE = "Cable";\n   public static final String AIR = "Air";\n   public static final String ATSC = "ATSC";\n@@ -95,7 +94,6 @@ public class CaptureDeviceInput\n     crossbarType = inCrossType;\n     crossbarIndex = inCrossIdx;\n     prefs = basePrefs + crossbarType + \'/\' + crossbarIndex + \'/\';\n-    availChanMap = new java.util.HashMap(); // String->String, keys are avail chans, values are alternate names\n   }\n   public String getCrossName()\n   {\n@@ -199,18 +197,6 @@ public class CaptureDeviceInput\n \n   public void loadPrefs()\n   {\n-    availChanMap.clear();\n-    java.util.StringTokenizer toker = new java.util.StringTokenizer(Sage.get(prefs + AVAILABLE_CHANNELS, ""), ";");\n-    while (toker.hasMoreTokens())\n-    {\n-      String currChan = toker.nextToken();\n-      int commaIdx = currChan.indexOf(\',\');\n-      if (commaIdx != -1)\n-        availChanMap.put(currChan.substring(0, commaIdx), currChan.substring(commaIdx+1));\n-      else\n-        availChanMap.put(currChan, currChan);\n-    }\n-\n     crossbarIndex = Sage.getInt(prefs + VIDEO_CROSSBAR_INDEX, 0);\n     crossbarType = Sage.getInt(prefs + VIDEO_CROSSBAR_TYPE, 1);\n     lastChannel = Sage.get(prefs + LAST_CHANNEL, "");\n@@ -256,17 +242,6 @@ public class CaptureDeviceInput\n   }\n   void writePrefs()\n   {\n-    StringBuffer availChanStr = new StringBuffer();\n-    java.util.Iterator walker = availChanMap.entrySet().iterator();\n-    while (walker.hasNext())\n-    {\n-      java.util.Map.Entry currEnt = (java.util.Map.Entry) walker.next();\n-      availChanStr.append(currEnt.getKey());\n-      availChanStr.append(\',\');\n-      availChanStr.append(currEnt.getValue());\n-      availChanStr.append(\';\');\n-    }\n-    Sage.put(prefs + AVAILABLE_CHANNELS, availChanStr.toString());\n     Sage.putInt(prefs + VIDEO_CROSSBAR_INDEX, crossbarIndex);\n     Sage.putInt(prefs + VIDEO_CROSSBAR_TYPE, crossbarType);\n     Sage.put(prefs + LAST_CHANNEL, lastChannel);\n@@ -283,61 +258,6 @@ public class CaptureDeviceInput\n     Sage.put(prefs + BROADCAST_STANDARD, broadcastStd);\n   }\n \n-  /*\n-   * SAGETV RECORDER API - BEGIN\n-   */\n-  // this is also add\n-  public void autoTunedChannelSet(java.util.Collection allChans)\n-  {\n-    availChanMap.keySet().retainAll(allChans);\n-    java.util.Iterator walker = allChans.iterator();\n-    while (walker.hasNext())\n-    {\n-      String c = (String) walker.next();\n-      if (availChanMap.get(c) == null)\n-        availChanMap.put(c, c);\n-    }\n-    writePrefs();\n-  }\n-  public void setChannelName(String chanNum, String chanName)\n-  {\n-    availChanMap.put(chanNum, chanName);\n-    writePrefs();\n-  }\n-  public void removeChannel(String chanNum)\n-  {\n-    availChanMap.remove(chanNum);\n-    writePrefs();\n-  }\n-  public boolean canViewChannelOnSource(String x)\n-  {\n-    return availChanMap.containsKey(x);\n-  }\n-  public java.util.Map getAvailChanMap()\n-  {\n-    return (java.util.Map)availChanMap.clone();\n-  }\n-  public String getChannelName(String chanNum) { return "".equals(chanNum) ? "" : (String) availChanMap.get(chanNum); }\n-  public String getChannelNumForName(String chanName)\n-  {\n-    java.util.Iterator walker = availChanMap.entrySet().iterator();\n-    while (walker.hasNext())\n-    {\n-      java.util.Map.Entry ent = (java.util.Map.Entry) walker.next();\n-      if (chanName.equals(ent.getValue()))\n-        return (String) ent.getKey();\n-    }\n-    return chanName;\n-  }\n-  public String[] getAvailChans()\n-  {\n-    String[] rv = (String[]) availChanMap.keySet().toArray(Pooler.EMPTY_STRING_ARRAY);\n-    java.util.Arrays.sort(rv, MMC.stringNumComparator);\n-    return rv;\n-  }\n-  /*\n-   * SAGETV RECORDER API - END\n-   */\n   public CaptureDeviceInput getWeirdRFCompanion(int chanNum)\n   {\n     capDev.ensureInputExists(1, chanNum);\n@@ -670,7 +590,6 @@ public class CaptureDeviceInput\n         (!Sage.getBoolean("mmc/disable_dvbs_epg_data_scanning", true) || !"DVB-S".equals(getBroadcastStandard()));\n   }\n \n-  private java.util.HashMap availChanMap;\n   private int crossbarIndex = -1; // this is the RF channel if its a tuner and this is > 1\n   private int crossbarType; // tuner1, comp2, s3\n   private String lastChannel = "";\ndiff --git a/java/sage/api/AiringAPI.java b/java/sage/api/AiringAPI.java\nindex 03c385fa..b1b5ab17 100644\n--- a/java/sage/api/AiringAPI.java\n+++ b/java/sage/api/AiringAPI.java\n@@ -29,7 +29,7 @@ import sage.*;\n  *<p>\n  * SageTV will automatically convert the following types to Airing if used for a parameter that requires the Airing type:<p>\n  * MediaFile - the Airing that represents the content is used<p>\n- * java.io.File - the corresponding MediaFile (if it exists) is resolved and then its Airing is used<p>\n+ * java.io.File - the corresponding MediaFile (if it exists) is resolved and then its Airing is used\n  */\n public class AiringAPI{\n   private AiringAPI() {}\n@@ -38,7 +38,7 @@ public class AiringAPI{\n     rft.put(new PredefinedJEPFunction("Airing", "SetRecordingName", new String[] { "Airing", "Name" })\n     {\n       /**\n-       * Sets the name for this recording. For Timed Recordings this will effect the title & associated attributes.\n+       * Sets the name for this recording. For Timed Recordings this will effect the title &amp; associated attributes.\n        * For ManualRecordings this will not have any side effects at all.\n        * @param Airing the ManualRecord to set the name for\n        * @param Name the name to set\n@@ -238,7 +238,7 @@ public class AiringAPI{\n     rft.put(new PredefinedJEPFunction("Airing", "PrintAiringLong", 1, new String[] { "Airing" })\n     {\n       /**\n-       * Returns a lengthy string which is suitable for displaying information about this Airing. This contains nearly all the details of the Airing & its Show\n+       * Returns a lengthy string which is suitable for displaying information about this Airing. This contains nearly all the details of the Airing &amp; its Show\n        * @param Airing the Airing object\n        * @return a lengthy string which is suitable for displaying information about this Airing\n        *\n@@ -250,7 +250,7 @@ public class AiringAPI{\n     rft.put(new PredefinedJEPFunction("Airing", "PrintAiringMedium", 1, new String[] { "Airing" })\n     {\n       /**\n-       * Returns a string which is suitable for displaying information about this Airing. This contains the Airing\'s channel & a short time string as well as the title & episode name or a short description\n+       * Returns a string which is suitable for displaying information about this Airing. This contains the Airing\'s channel &amp; a short time string as well as the title &amp; episode name or a short description\n        * @param Airing the Airing object\n        * @return a string which is suitable for displaying information about this Airing\n        *\n@@ -262,7 +262,7 @@ public class AiringAPI{\n     rft.put(new PredefinedJEPFunction("Airing", "PrintAiringShort", 1, new String[] { "Airing" })\n     {\n       /**\n-       * Returns a brief string which is suitable for displaying information about this Airing. This contains the Airing\'s channel & a short time string as well as the title\n+       * Returns a brief string which is suitable for displaying information about this Airing. This contains the Airing\'s channel &amp; a short time string as well as the title\n        * @param Airing the Airing object\n        * @return a brief string which is suitable for displaying information about this Airing\n        *\n@@ -464,6 +464,7 @@ public class AiringAPI{\n       /**\n        * Gets the time that viewing should resume from for this Airing if it is selected to view\n        * @param Airing the Airing object\n+       * @return the time that viewing should resume from for this Airing if it is selected to view\n        *\n        * @declaration public long GetLatestWatchedTime(Airing Airing);\n        */\n@@ -1164,6 +1165,7 @@ public class AiringAPI{\n        * Checks the airing for exceeding parental ratings and return a string array filled with each rating.\n        * If parental ratings is disabled, or the airing exceeds no parental settings, return empty array.\n        * @param Airing the Airing object to check against ratings\n+       * @return a String[] of the parental limits exceeded by this Airing\n        * @since 8.1\n        *\n        * @declaration public String[] GetParentalLimitsExceeded(Airing Airing);\ndiff --git a/java/sage/api/ChannelAPI.java b/java/sage/api/ChannelAPI.java\nindex 84ccd7b1..228bdc7b 100644\n--- a/java/sage/api/ChannelAPI.java\n+++ b/java/sage/api/ChannelAPI.java\n@@ -25,7 +25,7 @@ import sage.*;\n  * <p>\n  * SageTV will automatically convert the following types to Channel if used for a parameter that requires the Channel type:<p>\n  * Airing - every Airing has an associated Channel, that Channel is used<p>\n- * MediaFile - due to the 1:1 mapping between MediaFiles and Airings, the MediaFile is resolved to an Airing and then to a Channel<p>\n+ * MediaFile - due to the 1:1 mapping between MediaFiles and Airings, the MediaFile is resolved to an Airing and then to a Channel\n  */\n public class ChannelAPI{\n   private ChannelAPI() {}\ndiff --git a/java/sage/api/Configuration.java b/java/sage/api/Configuration.java\nindex 42a6f375..ee61eb6c 100644\n--- a/java/sage/api/Configuration.java\n+++ b/java/sage/api/Configuration.java\n@@ -476,7 +476,7 @@ public class Configuration{\n        * @param RemoteName the name of the \'Remote Control\'\n        * @param MsecDelay the minimum delay in milliseconds between finishing one channel change sequence and starting another when using the specified \'Remote Control\'\n        *\n-       * @declaration public int SetSequenceDelayForInfraredTuningPlugin(String PluginName, int PluginPortNumber, String RemoteName, int MsecDelay);\n+       * @declaration public void SetSequenceDelayForInfraredTuningPlugin(String PluginName, int PluginPortNumber, String RemoteName, int MsecDelay);\n        */\n       public Object runSafely(Catbert.FastStack stack) throws Exception{\n         int num = getInt(stack);\n@@ -1293,6 +1293,7 @@ public class Configuration{\n     {\n       /**\n        * Returns true if the specified rating is in the list that is under parental control\n+       * @param Rating the rating to check\n        * @return true if the specified rating is in the list that is under parental control, false otherwise\n        *\n        * @declaration public boolean IsRatingUnderParentalLock(String Rating);\n@@ -1565,7 +1566,7 @@ public class Configuration{\n     rft.put(new PredefinedJEPFunction("Configuration", "AddVideoDirectory", 3, new String[] {"Directory", "Rule", "Size"}, true)\n     {\n       /**\n-       * Adds a new directory to SageTV\'s list of directories that it can record video to. Also specifies what rule & size to use\n+       * Adds a new directory to SageTV\'s list of directories that it can record video to. Also specifies what rule &amp; size to use\n        * when managing the diskspace for this directory.\n        * @param Directory the directory to add as a video directory\n        * @param Rule the diskspace rule to use for this directory see {@link #GetVideoDiskspaceRules GetVideoDiskspaceRules()}\n@@ -1649,6 +1650,8 @@ public class Configuration{\n       /**\n        * Gets the name that is associated with an IR code. This has no functional purpose and is purely for display purposes.\n        * @param IRCode the IRCode to get the associated name for, see {@link #SetNameForIRCode SetNameForIRCode()}\n+       * @return the name for the specified IRCode\n+       *\n        * @declaration public String GetNameForIRCode(long IRCode);\n        */\n       public Object runSafely(Catbert.FastStack stack) throws Exception{\n@@ -1794,6 +1797,7 @@ public class Configuration{\n       /**\n        * Sets the name of the port that the infrared receiver is connected to.\n        * @param Port the name of the port that the infrared receiver is connected to; should be a value like: "COM1", "COM2" or "USB"\n+       * @return true on success, false otherwise\n        *\n        * @declaration public boolean SetInfraredReceiverPort(String Port);\n        */\n@@ -1894,6 +1898,8 @@ public class Configuration{\n        * Specifies whether or not 3D acceleration should be enabled for the rendering engine. This uses DirectX9 on Windows and OpenGL on Linux.\n        * This call takes effect immediately.\n        * @param Enabled true if 3D acceleration should be enabled, false otherwise.\n+       * @return true if the change succeeded, false otherwise\n+       *\n        * @declaration public boolean SetAcceleratedDrawingEnabled(boolean Enabled);\n        */\n       public Object runSafely(Catbert.FastStack stack) throws Exception{\n@@ -2712,7 +2718,7 @@ public class Configuration{\n     rft.put(new PredefinedJEPFunction("Configuration", "RunFilterAutoconfiguration")\n     {\n       /**\n-\t\t\t * Sets the DirectShow audio & video decoders on windows to acceptable values\n+\t\t\t * Sets the DirectShow audio &amp; video decoders on windows to acceptable values\n        * @deprecated\n        *\n        * @declaration public void RunFilterAutoconfiguration();\ndiff --git a/java/sage/api/Database.java b/java/sage/api/Database.java\nindex 856ccceb..fcc0148f 100644\n--- a/java/sage/api/Database.java\n+++ b/java/sage/api/Database.java\n@@ -58,10 +58,10 @@ public class Database {\n       /**\n        * Filters data by a boolean method. Each element in the \'Data\' has the \'Method\' executed on it.\n        * If the result is the same as the \'MatchValue\' parameter then that element will be in the\n-       * returned data. For Maps & Collections this is done in place. For Arrays a new Array is created.\n+       * returned data. For Maps &amp; Collections this is done in place. For Arrays a new Array is created.\n        * NOTE: If you pass more than 3 arguments to this function then the extra arguments will\n        * be passed along to the Method that should be executed.\n-       * @param Data the data that is to be filtered; this can be a java.util.Collection, java.util.Map or an Array. For Maps & Collections the filtering is done IN-PLACE.\n+       * @param Data the data that is to be filtered; this can be a java.util.Collection, java.util.Map or an Array. For Maps &amp; Collections the filtering is done IN-PLACE.\n        * @param Method This is what is evaluated with an element as the only argument. This can be a list of methods to test against separated by the \'|\' character.\n        * @param MatchValue the Method must return this value to be in the returned data\n        * @return The elements that passed the filter. The type is the same type as the passed in Data.\n@@ -345,11 +345,11 @@ public class Database {\n        * Filters data by a method. Each element in the \'Data\' has the \'Method\' executed on it.\n        * If the result is the same as the \'MatchValue\' parameter then that element will be in the\n        * returned data if MatchedPasses is true. If MatchedPasses is false then non-matching elements will be in the returned data.\n-       * For Maps & Collections this is done in place. For Arrays a new Array is created.\n+       * For Maps &amp; Collections this is done in place. For Arrays a new Array is created.\n        * NOTE: If you pass more than 4 arguments to this function then the extra arguments will\n        * be passed along to the Method that should be executed.\n-       * @param Data the data that is to be filtered; this can be a java.util.Collection, java.util.Map or an Array. For Maps & Collections the filtering is done IN-PLACE. For Maps the keys are used for the filtering.\n-       * @param Method This is what is evaluated with an element as the only argument. This can be a list of methods to test against separated by the \'|\' character. There is also a special \'UserCategories\' option which will check the ManualRecord, Favorite and MediaFile "UserCategory" property as well as the Show Category & SubCategory for any matches against a comma-delimited list in the MatchValue parameter.\n+       * @param Data the data that is to be filtered; this can be a java.util.Collection, java.util.Map or an Array. For Maps &amp; Collections the filtering is done IN-PLACE. For Maps the keys are used for the filtering.\n+       * @param Method This is what is evaluated with an element as the only argument. This can be a list of methods to test against separated by the \'|\' character. There is also a special \'UserCategories\' option which will check the ManualRecord, Favorite and MediaFile "UserCategory" property as well as the Show Category &amp; SubCategory for any matches against a comma-delimited list in the MatchValue parameter.\n        * @param MatchValue the value to test the return value of Method against\n        * @param MatchedPasses if true then matches are included in the return data, if false then everything that doesn\'t match is returned\n        * @return The elements that passed the filter. The type is the same type as the passed in Data.\n@@ -761,10 +761,10 @@ public class Database {\n        * The result is then converted to a String and RegexPattern is applied to it.\n        * If the regular expression matches the String value and MatchedPasses is true, then the element\n        * will be in the returned data. If MatchedPasses is false then non-matching elements will be in the returned data.\n-       * For Maps & Collections this is done in place. For Arrays a new Array is created.\n+       * For Maps &amp; Collections this is done in place. For Arrays a new Array is created.\n        * NOTE: If you pass more than 5 arguments to this function then the extra arguments will\n        * be passed along to the Method that should be executed.\n-       * @param Data the data that is to be filtered; this can be a java.util.Collection, java.util.Map or an Array. For Maps & Collections the filtering is done IN-PLACE.\n+       * @param Data the data that is to be filtered; this can be a java.util.Collection, java.util.Map or an Array. For Maps &amp; Collections the filtering is done IN-PLACE.\n        * @param Method This is what is evaluated with an element as the only argument (and additional arguments if passed in).\n        * @param RegexPattern The compiled regular expression used for matching (if it\'s not compiled, then it will be converted to a compiled regular expression)\n        * @param MatchedPasses if true then matches are included in the return data, if false then everything that doesn\'t match is returned\n@@ -865,8 +865,8 @@ public class Database {\n        * Filters data by a comparable range. Each element in the \'Data\' has the \'Method\' executed on it.\n        * If KeepWithinBounds is true, then results that are within the specified range are included in the returned data; otherwise\n        * if KeepWithinBounds is false then results that are outside of the specified range are included in the returned data.\n-       * For Maps & Collections this is done in place. For Arrays a new Array is created.\n-       * @param Data the data that is to be filtered; this can be a java.util.Collection, java.util.Map or an Array. For Maps & Collections the filtering is done IN-PLACE.\n+       * For Maps &amp; Collections this is done in place. For Arrays a new Array is created.\n+       * @param Data the data that is to be filtered; this can be a java.util.Collection, java.util.Map or an Array. For Maps &amp; Collections the filtering is done IN-PLACE.\n        * @param Method This is what is evaluated with an element as the only argument\n        * @param LowerBoundInclusive a java.lang.Comparable which specifies the INCLUSIVE lower bound for the range\n        * @param UpperBoundExclusive a java.lang.Comparable which specified the EXCLUSIVE upper bound for the range\n@@ -963,7 +963,7 @@ public class Database {\n     {\n \n       /**\n-       * Grouping method for data lists/maps. This will return a Map that uses a key->value mapping to group the data.\n+       * Grouping method for data lists/maps. This will return a Map that uses a key-&gt;value mapping to group the data.\n        * The order of the grouping is stable, which means the order of the elements within a subgroup will be the same\n        * order as in the pased in data. Use the GetSubgroup method to get the corresponding value for a key.\n        * The key for each data element is determined by calling the specified \'Method\' with that data element as the sole parameter.\n@@ -1185,7 +1185,7 @@ public class Database {\n     {\n \n       /**\n-       * Grouping method for data lists/maps. This will return a Map that uses a key->value mapping to group the data.\n+       * Grouping method for data lists/maps. This will return a Map that uses a key-&gt;value mapping to group the data.\n        * The order of the grouping is stable, which means the order of the elements within a subgroup will be the same\n        * order as in the pased in data. Use the GetSubgroup method to get the corresponding value for a key.\n        * The keys for each data element is determined by calling the specified \'Method\' with that data element as the sole parameter.\n@@ -2128,7 +2128,7 @@ public class Database {\n        * in the list of people involved (i.e. actors, directors, producers, etc.). The content must also match\n        * one of the media types specified in the MediaMask\n        * @param SearchString the name of the person to search for matching content on\n-       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV & Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n+       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV &amp; Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n        * @return an array of Airing objects that reference content that includes the specified person and matches the media mask\n        * @since 5.1\n        *\n@@ -2159,7 +2159,7 @@ public class Database {\n        * specified search string. This search is case insensitive. The content must also match\n        * one of the media types specified in the MediaMask\n        * @param SearchString the string to search for\n-       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV & Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n+       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV &amp; Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n        * @return an array of Airings who\'s content has the specified search string in its description or episode name and matches the media mask\n        * @since 5.1\n        *\n@@ -2189,7 +2189,7 @@ public class Database {\n        * Returns all Airings in the database that refer to content that has the specified title. The content must also match\n        * one of the media types specified in the MediaMask\n        * @param SearchString the title of the content must match this exactly\n-       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV & Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n+       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV &amp; Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n        * @return an array of Airing objects that reference content with the specified title and matches the media mask\n        * @since 5.1\n        *\n@@ -2219,7 +2219,7 @@ public class Database {\n        * Returns a list of all of the people in the database that include the search string in their name.\n        * This search is case insensitive. The content it references must also match one of the media types specified in the MediaMask.\n        * @param SearchString the string to search on\n-       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV & Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n+       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV &amp; Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n        * @return an array of Persons which represent all of the people in the database that matched the search that also have content that matches the MediaMask\n        * @since 5.1\n        *\n@@ -2249,7 +2249,7 @@ public class Database {\n        * Returns a list of all of the titles in the database that include the search string in them.\n        * This search is case insensitive. The content it references must also match one of the media types specified in the MediaMask.\n        * @param SearchString the string to search on\n-       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV & Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n+       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV &amp; Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n        * @return an array of Strings which represent all of the titles in the database that matched the search that also have content that matches the MediaMask\n        * @since 5.1\n        *\n@@ -2279,7 +2279,7 @@ public class Database {\n        * Returns a list of all of the people in the database that match the passed in regular expression.\n        * The content it references must also match one of the media types specified in the MediaMask.\n        * @param RegexPattern The compiled regular expression used for matching (if it\'s not compiled, then it will be converted to a compiled regular expression)\n-       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV & Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n+       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV &amp; Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n        * @return an array of Persons which represent all of the people in the database that matched the search that also have content that matches the MediaMask\n        * @since 5.1\n        *\n@@ -2299,9 +2299,9 @@ public class Database {\n       /**\n        * Returns a list of all of the people in the database that match the passed in text, where\n        * the Unicode characters u2460-u2468 and u24EA  (Unicode Circled Digits) in the text represent the\n-       * numeric Text Keys 1-9 and 0. This is similar to the predictive text entry input of mobile phones.<br/>\n+       * numeric Text Keys 1-9 and 0. This is similar to the predictive text entry input of mobile phones.<br>\n        * The characters represented by the keys are defined by the client properties\n-       * <tt>"ui/numeric_text_input_<ui/translation_language_code>_<key>_lower</tt>\n+       * <tt>"ui/numeric_text_input_&lt;ui/translation_language_code&gt;_&lt;key&gt;_lower</tt>\n        *\n        * @param NTEString A string containing a mix of normal and NumericTextKey characters (u2460-2468, u24ae)\n        * @return an array of Persons which represent all of the people in the database that matched the search\n@@ -2313,12 +2313,12 @@ public class Database {\n       /**\n        * Returns a list of all of the people in the database that match the passed in text, where\n        * the Unicode characters u2460-u2468 and u24EA  (Unicode Circled Digits) in the text represent the\n-       * numeric Text Keys 1-9 and 0. This is similar to the predictive text entry input of mobile phones.<br/>\n+       * numeric Text Keys 1-9 and 0. This is similar to the predictive text entry input of mobile phones.<br>\n        * The characters represented by the keys are defined by the client properties\n-       * <tt>"ui/numeric_text_input_<ui/translation_language_code>_<key>_lower</tt>\n+       * <tt>"ui/numeric_text_input_&lt;ui/translation_language_code&gt;_&lt;key&gt;_lower</tt>\n        * The content it references must also match one of the media types specified in the MediaMask.\n        * @param NTEString A string containing a mix of normal and NumericTextKey characters (u2460-2468, u24ae)\n-       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV & Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n+       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV &amp; Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n        * @return an array of Persons which represent all of the people in the database that matched the search that also have content that matches the MediaMask\n        * @since 8.0\n        *\n@@ -2348,7 +2348,7 @@ public class Database {\n        * Returns a list of all of the titles in the database that match the passed in regular expression.\n        * The content it references must also match one of the media types specified in the MediaMask.\n        * @param RegexPattern The compiled regular expression used for matching (if it\'s not compiled, then it will be converted to a compiled regular expression)\n-       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV & Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n+       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV &amp; Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n        * @return an array of Strings which represent all of the titles in the database that matched the search that also have content that matches the MediaMask\n        * @since 5.1\n        *\n@@ -2368,9 +2368,9 @@ public class Database {\n       /**\n        * Returns a list of all of the titles in the database that match the passed in text, where\n        * the Unicode characters u2460-u2468 and u24EA  (Unicode Circled Digits) in the text represent the\n-       * numeric Text Keys 1-9 and 0. This is similar to the predictive text entry input of mobile phones.<br/>\n+       * numeric Text Keys 1-9 and 0. This is similar to the predictive text entry input of mobile phones.<br>\n        * The characters represented by the keys are defined by the client properties\n-       * <tt>"ui/numeric_text_input_<ui/translation_language_code>_<key>_lower</tt>\n+       * <tt>"ui/numeric_text_input_&lt;ui/translation_language_code&gt;_&lt;key&gt;_lower</tt>\n        * The content it references must also match one of the media types specified in the MediaMask.\n        * @param NTEString A string containing a mix of normal and NumericTextKey characters (u2460-2468, u24ae)\n        * @return an array of Strings which represent all of the titles in the database that matched the search\n@@ -2382,12 +2382,12 @@ public class Database {\n       /**\n        * Returns a list of all of the titles in the database that match the passed in text, where\n        * the Unicode characters u2460-u2468 and u24EA  (Unicode Circled Digits) in the text represent the\n-       * numeric Text Keys 1-9 and 0. This is similar to the predictive text entry input of mobile phones.<br/>\n+       * numeric Text Keys 1-9 and 0. This is similar to the predictive text entry input of mobile phones.<br>\n        * The characters represented by the keys are defined by the client properties\n-       * <tt>"ui/numeric_text_input_<ui/translation_language_code>_<key>_lower</tt>\n+       * <tt>"ui/numeric_text_input_&lt;ui/translation_language_code&gt;_&lt;key&gt;_lower</tt>\n        * The content it references must also match one of the media types specified in the MediaMask.\n        * @param NTEString A string containing a mix of normal and NumericTextKey characters (u2460-2468, u24ae)\n-       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV & Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n+       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV &amp; Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n        * @return an array of Strings which represent all of the titles in the database that matched the search that also have content that matches the MediaMask\n        * @since 8.0\n        *\n@@ -2563,7 +2563,7 @@ public class Database {\n        * @param ExtendedRatings if true then the extended ratings fields will be searched, if false then they will not be\n        * @param Year if true then the year fields will be searched, if false then they will not be\n        * @param Misc if true then the miscellaneous fields will be searched, if false then they will not be\n-       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV & Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n+       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV &amp; Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n        * @return an array of Airings which matches the search criteria\n        * @since 5.1\n        *\n@@ -2631,7 +2631,7 @@ public class Database {\n        * @param ExtendedRatings if true then the extended ratings fields will be searched, if false then they will not be\n        * @param Year if true then the year fields will be searched, if false then they will not be\n        * @param Misc if true then the miscellaneous fields will be searched, if false then they will not be\n-       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV & Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n+       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV &amp; Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n        * @return an array of Airings which matches the search criteria\n        * @since 5.1\n        *\n@@ -2694,7 +2694,7 @@ public class Database {\n        * @param ExtendedRatings if true then the extended ratings fields will be searched, if false then they will not be\n        * @param Year if true then the year fields will be searched, if false then they will not be\n        * @param Misc if true then the miscellaneous fields will be searched, if false then they will not be\n-       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV & Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n+       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV &amp; Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n        * @return an array of Airings which matches the search criteria\n        * @since 5.1\n        *\n@@ -2725,9 +2725,9 @@ public class Database {\n       /**\n        * Searches the specified fields of all the Airings in the database and tries to match them against\n        * the passed in text, where the Unicode characters u2460-u2468 and u24EA  (Unicode Circled Digits) in the text represent the\n-       * numeric Text Keys 1-9 and 0. This is similar to the predictive text entry input of mobile phones.<br/>\n+       * numeric Text Keys 1-9 and 0. This is similar to the predictive text entry input of mobile phones.<br>\n        * The characters represented by the keys are defined by the client properties\n-       * <tt>"ui/numeric_text_input_<ui/translation_language_code>_<key>_lower</tt>.\n+       * <tt>"ui/numeric_text_input_&lt;ui/translation_language_code&gt;_&lt;key&gt;_lower</tt>.\n        * @param NTEString A string containing a mix of normal and NumericTextKey characters (u2460-2468, u24ae)\n        * @param Titles if true then the title fields will be searched, if false then they will not be\n        * @param Episode if true then the episode fields will be searched, if false then they will be not be\n@@ -2747,9 +2747,9 @@ public class Database {\n       /**\n        * Searches the specified fields of all the Airings in the database and tries to match them against\n        * the passed in text where the Unicode characters u2460-u2468 and u24EA  (Unicode Circled Digits) in the text represent the\n-       * numeric Text Keys 1-9 and 0. This is similar to the predictive text entry input of mobile phones.<br/>\n+       * numeric Text Keys 1-9 and 0. This is similar to the predictive text entry input of mobile phones.<br>\n        * The characters represented by the keys are defined by the client properties\n-       * <tt>"ui/numeric_text_input_<ui/translation_language_code>_<key>_lower</tt>.\n+       * <tt>"ui/numeric_text_input_&lt;ui/translation_language_code&gt;_&lt;key&gt;_lower</tt>.\n        * The content it references must also match one of the media types specified in the MediaMask.\n        * @param NTEString A string containing a mix of normal and NumericTextKey characters (u2460-2468, u24ae)\n        * @param Titles if true then the title fields will be searched, if false then they will not be\n@@ -2761,7 +2761,7 @@ public class Database {\n        * @param ExtendedRatings if true then the extended ratings fields will be searched, if false then they will not be\n        * @param Year if true then the year fields will be searched, if false then they will not be\n        * @param Misc if true then the miscellaneous fields will be searched, if false then they will not be\n-       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV & Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n+       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV &amp; Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n        * @return an array of Airings which matches the search criteria\n        * @since 8.0\n        *\n@@ -2817,7 +2817,7 @@ public class Database {\n       /**\n        * Gets all of the titles that are in the database.\n        * The content it references must also match one of the media types specified in the MediaMask.\n-       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV & Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n+       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV &amp; Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n        * @return a list of all of the titles that are in the database that also have content that matches the MediaMask\n        * @since 5.1\n        *\n@@ -2843,7 +2843,7 @@ public class Database {\n       /**\n        * Gets all of the people that are in the database.\n        * The content it references must also match one of the media types specified in the MediaMask.\n-       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV & Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n+       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV &amp; Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n        * @return a list of all of the names of people in the database that also have content that matches the MediaMask\n        * @since 5.1\n        *\n@@ -2869,7 +2869,7 @@ public class Database {\n       /**\n        * Gets all of the categories that are in the database.\n        * The content it references must also match one of the media types specified in the MediaMask.\n-       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV & Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n+       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV &amp; Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n        * @return all of the names of categories that are in the database that also have content that matches the MediaMask\n        * @since 5.1\n        *\n@@ -2900,7 +2900,7 @@ public class Database {\n        * This is different than GetAllCategories because this one will break apart\n        * any comma or semicolon delimited category lists into multiple different categories. i.e. if you have "Comedy; Horror" as a category\n        * this API call will break it up into Comedy and Horror as two separate categories. This call will also coalesce any case-sensitive differences in category names.\n-       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV & Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n+       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV &amp; Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n        * @return all of the names of categories that are in the database that also have content that matches the MediaMask with multi-categories broken apart\n        * @since 7.0\n        *\n@@ -2934,7 +2934,7 @@ public class Database {\n       /**\n        * Returns the last modification time for objects that match anything in the specified MediaMask. This is useful\n        * for knowing when to clear caches that are used to optimize UI rendering.\n-       * @param MediaMask string specifying what content types  (i.e. "TM" for TV & Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n+       * @param MediaMask string specifying what content types  (i.e. "TM" for TV &amp; Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n        * @return the last modification time of anything in the DB that matches anything in the specified MediaMask\n        * @since 5.1\n        *\n@@ -3241,7 +3241,7 @@ public class Database {\n        * @return an array of Channel objects that includes the SearchString\n        * @since 8.1\n        *\n-       * @declaration public Channel[] SearchForChannel(String SearchString, Boolean IncludeDisabled);\n+       * @declaration public Channel[] SearchForChannel(String SearchString, Boolean IncludeNonViewable);\n        */\n \n       public Object runSafely(Catbert.FastStack stack) throws Exception{\ndiff --git a/java/sage/api/Global.java b/java/sage/api/Global.java\nindex c44c2673..42523396 100644\n--- a/java/sage/api/Global.java\n+++ b/java/sage/api/Global.java\n@@ -30,6 +30,7 @@ import sage.LinuxUtils;\n import sage.MMC;\n import sage.ManualRecord;\n import sage.MediaFile;\n+import sage.MetaImage;\n import sage.MiniClientSageRenderer;\n import sage.NetworkClient;\n import sage.NewStorageDeviceDetector;\n@@ -153,6 +154,7 @@ public class Global {\n        *\n        * @param Name the name to use for this \'static context\' variable\n        * @param Value the value to set this \'static context\' variable to\n+       * @return the passed in Value\n        *\n        * @declaration public Object AddStaticContext(String Name, Object Value);\n        */\n@@ -172,6 +174,7 @@ public class Global {\n        * will exist for the lifetime of the SageTV application and is always in scope for all expression evaluation. This is a \'global variable\'.\n        * @param Name the name to use for this \'global context\' variable\n        * @param Value the value to set this \'global context\' variable to\n+       * @return the passed in Value\n        *\n        * @declaration public Object AddGlobalContext(String Name, Object Value);\n        */\n@@ -1185,6 +1188,7 @@ public class Global {\n        * of transitioning to. This will only be true during the processing of MenuUnloaded effects. If a null argument is given; then this is\n        * true in the case that any menu transition is about to occur. The name match is case-insensitive.\n        * @param MenuName the name of the menu to test to see if we\'re transitioning to; null if it matches any menu name\n+       * @return true if the specified menu name matches the name of the menu widget that the UI is in the process of transitioning to, false otherwise\n        * @since 7.0\n        *\n        * @declaration public boolean IsTransitioningToMenu(String MenuName);\n@@ -1205,6 +1209,7 @@ public class Global {\n        * Returns true if the specified menu name matches the name of the menu widget for the previously loaded menu. The name match is case-insensitive.\n        * Unlike <b>IsTransitioningToMenu</b>, this is true even after the transition is complete. A null argument always returns false.\n        * @param MenuName the name of the menu to test to see if it was the previously loaded menu\n+       * @return true if the specified menu name matches the name of the menu widget for the previously loaded menu, false otherwise\n        * @since 7.0\n        *\n        * @declaration public boolean IsTransitioningFromMenu(String MenuName);\n@@ -1228,6 +1233,7 @@ public class Global {\n        * of transitioning to. This will only be true during the processing of MenuUnloaded effects. If a null argument or empty list is given; then this is\n        * true in the case that any menu transition is about to occur. The name match is case-insensitive.\n        * @param MenuNames the names of the menu to test to see if we\'re transitioning to; null or empty list if it matches any menu name\n+       * @return true if one of the specified menu name matches the name of the menu widget that the UI is in the process of transitioning to, false otherwise\n        * @since 8.0\n        *\n        * @declaration public boolean IsTransitioningToMenus(String[] MenuNames);\n@@ -1254,6 +1260,7 @@ public class Global {\n        * Returns true if one of the specified menu names matches the name of the menu widget for the previously loaded menu. The name match is case-insensitive.\n        * Unlike <b>IsTransitioningToMenus</b>, this is true even after the transition is complete. A null argument or empty list always returns false.\n        * @param MenuNames the names of the menus to test to see if it was the previously loaded menu\n+       * @return true if one of the specified menu names matches the name of the menu widget for the previously loaded menu, false otherwise\n        * @since 8.0\n        *\n        * @declaration public boolean IsTransitioningFromMenus(String[] MenuNames);\n@@ -2278,7 +2285,7 @@ public class Global {\n     {\n       /**\n        * Returns whether or not the current file being downloaded can be played back while being downloaded. This is only valid\n-       * for when the file being downloaded is an FLV, MP3, MP4 or Quicktime file. It will always be true for MP3 & FLV files;\n+       * for when the file being downloaded is an FLV, MP3, MP4 or Quicktime file. It will always be true for MP3 &amp; FLV files;\n        * and for MP4/Quicktime files it\'ll be true if the sample section is before the movie data in the file. If this is true\n        * and the download stream time is greater than zero; then it\'s OK to start progressive playback of downloaded media.\n        * @return true if the current file being downloaded can potentially be played back while being downloaded, false if it definitely cannot be\n@@ -2312,7 +2319,7 @@ public class Global {\n     {\n       /**\n        * Returns whether or not the current file being downloaded can be played back while being downloaded. This is only valid\n-       * for when the file being downloaded is an FLV, MP3, MP4 or Quicktime file. It will always be true for MP3 & FLV files;\n+       * for when the file being downloaded is an FLV, MP3, MP4 or Quicktime file. It will always be true for MP3 &amp; FLV files;\n        * and for MP4/Quicktime files it\'ll be true if the sample section is before the movie data in the file. If this is true\n        * and the download stream time is greater than zero; then it\'s OK to start progressive playback of downloaded media.\n        * @param DestFile the destination file specified in the original download request\n@@ -2563,6 +2570,7 @@ public class Global {\n       /**\n        * Returns the detailed format description for the specific resolution returned from GetDisplayResolutionOptions()\n        * NOTE: This API call is only valid on embedded platforms.\n+       * @param Resolution the resolution to get the details for\n        * @return a the detailed format description for a specific Resolution\n        *\n        * @since 6.4\n@@ -2787,10 +2795,10 @@ public class Global {\n     rft.put(new PredefinedJEPFunction("Global", "GetHotplugStorageMap")\n     {\n       /**\n-       * Returns a map of name->file for any hotplug storage devies on the system. The\n+       * Returns a map of name-&gt;file for any hotplug storage devies on the system. The\n        * names are user-presentable and the path is the java.io.File root which corresponds to the root of that device.\n        * NOTE: This is only valid on embedded platforms.\n-       * @return a Map of name->file for hotplugged storage devices\n+       * @return a Map of name-&gt;file for hotplugged storage devices\n        *\n        * @since 6.4\n        *\n@@ -2865,7 +2873,7 @@ public class Global {\n     rft.put(new PredefinedJEPFunction("Global", "PrepareForFirmwareLoad", true)\n     {\n       /**\n-       * Prepares the device for a firmware download & flash. This internally will stop the library importing process,\n+       * Prepares the device for a firmware download &amp; flash. This internally will stop the library importing process,\n        * empty all of the database tables, clear the UI caches, and then force a complete garbage collection.\n        * NOTE: This is only valid on embedded platforms.\n        *\ndiff --git a/java/sage/api/MediaFileAPI.java b/java/sage/api/MediaFileAPI.java\nindex 2aa4e434..d8668927 100644\n--- a/java/sage/api/MediaFileAPI.java\n+++ b/java/sage/api/MediaFileAPI.java\n@@ -53,7 +53,7 @@ public class MediaFileAPI {\n        * Returns all of the MediaFile objects in the database\n        * The content it references must also match one of the media types specified in the MediaMask.\n        * There\'s also an additional supported type of \'L\' which indicates files that pass IsLibraryFile()\n-       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV & Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n+       * @param MediaMask string specifying what content types to search (i.e. "TM" for TV &amp; Music, \'T\'=TV, \'M\'=Music, \'V\'=Video, \'D\'=DVD, \'P\'=Pictures, \'B\'=BluRay)\n        * @return a list of all of the MediaFile objects in the database that match the mask\n        * @since 6.4\n        *\n@@ -393,10 +393,10 @@ public class MediaFileAPI {\n     rft.put(new PredefinedJEPFunction("MediaFile", "GenerateThumbnail", new String[] { "MediaFile", "Time", "Width", "Height", "File" })\n     {\n       /**\n-       * Generates a thumbnail for the specified MediaFile at the requested offset time in the file using the desired width & height.\n+       * Generates a thumbnail for the specified MediaFile at the requested offset time in the file using the desired width &amp; height.\n        * The resulting thumbnail will be saved to the specified file. This call DOES NOT need to be used for GetThumbnail to work properly; this\n        * API call is intended as an extra for developers who want additional thumbnails beyond the one that is normally auto-generated for MediaFiles.\n-       * This API call will not return until the generation of the thumbnail is complete. If both width & height are zero, then the size will be determined\n+       * This API call will not return until the generation of the thumbnail is complete. If both width &amp; height are zero, then the size will be determined\n        * automatically to match the aspect ratio of the video (the largest dimension will match what SageTV uses internally for thumbnail sizes). If only one\n        * of width or height is zero, then the other dimension will be determined automatically to match the aspect ratio of the video.\n        * @param MediaFile the MediaFile object, must be a Video file (no BluRays or DVDs)\ndiff --git a/java/sage/api/PlaylistAPI.java b/java/sage/api/PlaylistAPI.java\nindex 4b1caf6d..6d852e1a 100644\n--- a/java/sage/api/PlaylistAPI.java\n+++ b/java/sage/api/PlaylistAPI.java\n@@ -411,6 +411,8 @@ public class PlaylistAPI {\n       /**\n        * Creates a new Playlist object\n        * @param Name the name for the new Playlist\n+       * @return the newly created Playlist\n+       *\n        * @declaration public Playlist AddPlaylist(String Name);\n        */\n       public Object runSafely(Catbert.FastStack stack) throws Exception{\ndiff --git a/java/sage/api/SeriesInfoAPI.java b/java/sage/api/SeriesInfoAPI.java\nindex 03476566..b19bc080 100644\n--- a/java/sage/api/SeriesInfoAPI.java\n+++ b/java/sage/api/SeriesInfoAPI.java\n@@ -470,6 +470,7 @@ public class SeriesInfoAPI\n       /**\n        * Returns the name of the character that the corresponding actor plays in this series\n        * @param SeriesInfo the SeriesInfo object\n+       * @param Actor the actor\n        * @return the name of the character that the corresponding actor plays in this series, the empty string if there\'s no correlation\n        * @since 7.0\n        *\ndiff --git a/java/sage/api/ShowAPI.java b/java/sage/api/ShowAPI.java\nindex f72c977f..7b4c1e46 100644\n--- a/java/sage/api/ShowAPI.java\n+++ b/java/sage/api/ShowAPI.java\n@@ -23,7 +23,7 @@ import sage.*;\n  * <p>\n  * SageTV will automatically convert the following types to Show if used for a parameter that requires the Show type:<p>\n  * Airing - every Airing corresponds to a single Show which describes the Airing\'s content in more detail, so the Airing\'s Show is used<p>\n- * MediaFile - this is resolved to an Airing by the 1:1 relationship between MediaFiles and Airings, and then the Airing is resolved to a Show<p>\n+ * MediaFile - this is resolved to an Airing by the 1:1 relationship between MediaFiles and Airings, and then the Airing is resolved to a Show\n  */\n public class ShowAPI {\n   private ShowAPI() {}\ndiff --git a/java/sage/api/SystemMessageAPI.java b/java/sage/api/SystemMessageAPI.java\nindex 12df41cf..80d46584 100644\n--- a/java/sage/api/SystemMessageAPI.java\n+++ b/java/sage/api/SystemMessageAPI.java\n@@ -270,7 +270,7 @@ public class SystemMessageAPI\n        * @param MessageCode the integer code that specifies the type of message\n        * @param MessageLevel the integer code specifying the level of the message; 0=Status(does not raise global level),1=Info, 2=Warning, 3=Error\n        * @param MessageString a localized message string that explains what the message is in detail\n-       * @param MessageVariables a java.util.Properties object which has name->value pairs that represent variables corresponding to the details of this message\n+       * @param MessageVariables a java.util.Properties object which has name-&gt;value pairs that represent variables corresponding to the details of this message\n        * @since 6.6\n        *\n        * @declaration public void PostSystemMessage(int MessageCode, int MessageLevel, String MessageString, java.util.Properties MessageVariables);\ndiff --git a/java/sage/api/TranscodeAPI.java b/java/sage/api/TranscodeAPI.java\nindex 744fcb8c..0af8314a 100644\n--- a/java/sage/api/TranscodeAPI.java\n+++ b/java/sage/api/TranscodeAPI.java\n@@ -59,7 +59,7 @@ public class TranscodeAPI\n        * @param FormatDetails the detailed property string for the new format\n        * @since 5.1\n        *\n-       * @declaration public String AddTranscodeFormat(String FormatName, String FormatDetails);\n+       * @declaration public void AddTranscodeFormat(String FormatName, String FormatDetails);\n        */\n       public Object runSafely(Catbert.FastStack stack) throws Exception{\n         String details = getString(stack);\n@@ -75,7 +75,7 @@ public class TranscodeAPI\n        * @param FormatName the name of the transcode format to remove\n        * @since 5.1\n        *\n-       * @declaration public String RemoveTranscodeFormat(String FormatName);\n+       * @declaration public void RemoveTranscodeFormat(String FormatName);\n        */\n       public Object runSafely(Catbert.FastStack stack) throws Exception{\n         String name = getString(stack);\ndiff --git a/java/sage/api/UserRecordAPI.java b/java/sage/api/UserRecordAPI.java\nindex 30b774db..e4084094 100644\n--- a/java/sage/api/UserRecordAPI.java\n+++ b/java/sage/api/UserRecordAPI.java\n@@ -175,7 +175,7 @@ public class UserRecordAPI {\n     rft.put(new PredefinedJEPFunction("UserRecord", "GetUserRecordNames", new String[] { "UserRecord" })\n     {\n       /**\n-       * Gets a list of all the \'Name\' values used in name->value pairs in this UserRecord object\n+       * Gets a list of all the \'Name\' values used in name-&gt;value pairs in this UserRecord object\n        * @param UserRecord the UserRecord object to get the list of Names stored in\n        * @return an array of all the names used to store data within this UserRecord object\n        * @since 7.0\ndiff --git a/java/sage/api/Utility.java b/java/sage/api/Utility.java\nindex f477d4a5..5b4953bc 100644\n--- a/java/sage/api/Utility.java\n+++ b/java/sage/api/Utility.java\n@@ -993,7 +993,7 @@ public class Utility {\n     rft.put(new PredefinedJEPFunction("Utility", "GetWindowsRegistryNames", 2, new String[]{"Root", "Key"})\n     {\n       /**\n-       * Returns a list of the Windows registry names which exist under the specified root & key (Windows only)\n+       * Returns a list of the Windows registry names which exist under the specified root &amp; key (Windows only)\n        * Acceptable values for the Root are: "HKCR", "HKEY_CLASSES_ROOT", "HKCC", "HKEY_CURRENT_CONFIG", "HKCU",\n        * "HKEY_CURRENT_USER", "HKU", "HKEY_USERS", "HKLM" or "HKEY_LOCAL_MACHINE" (HKLM is the default if nothing matches)\n        * @param Root the registry hive to look in\n@@ -2637,12 +2637,12 @@ public class Utility {\n        * SlideRightIn - slides in from the right of its parent component</li><li>\n        * FadeOut - fades out</li><li>\n        * FadeIn - fades in</li><li>\n-       * Smooth - smoothly transitions from one position & size to another; the destination image is used for the animation</li><li>\n-       * Morph - smoothly transitions from one position & size to another; the image fades between the source and the destination</li><li>\n+       * Smooth - smoothly transitions from one position &amp; size to another; the destination image is used for the animation</li><li>\n+       * Morph - smoothly transitions from one position &amp; size to another; the image fades between the source and the destination</li><li>\n        * ZoomOut - shrinks the size down to nothing from its source size</li><li>\n-       * ZoomIn - grows the size from nothing to its destination size</li>\n+       * ZoomIn - grows the size from nothing to its destination size</li><li>\n        * HZoomOut - shrinks the size down to nothing horitonzatlly from its source size</li><li>\n-       * HZoomIn - grows the size from nothing horitonzatlly to its destination size</li>\n+       * HZoomIn - grows the size from nothing horitonzatlly to its destination size</li><li>\n        * VZoomOut - shrinks the size down to nothing vertically from its source size</li><li>\n        * VZoomIn - grows the size from nothing vertically to its destination size</li>\n        * </ul><p>\n@@ -2662,10 +2662,10 @@ public class Utility {\n        * North - for Zoom animations will center the zoom around the top of the component (i.e. ZoomInNorth) </li><li>\n        * West - for Zoom animations will center the zoom around the left of the component </li><li>\n        * South - for Zoom animations will center the zoom around the bottom of the component </li><li>\n-       * East - for Zoom animations will center the zoom around the right of the component </li></ul>\n-       * Behind - for Out animations will cause it to be rendered behind the other layers instead of on top as Out animations usually are </li></ul>\n-       * Unclipped - for Slide animations will cause the same motion to occur but without clipping the area when drawn </li></ul>\n-       * Unease - for In or Out animations it will reverse the \'easing\' direction so you can slide in & out the same panel w/ out overlap </li></ul>\n+       * East - for Zoom animations will center the zoom around the right of the component </li><li>\n+       * Behind - for Out animations will cause it to be rendered behind the other layers instead of on top as Out animations usually are </li><li>\n+       * Unclipped - for Slide animations will cause the same motion to occur but without clipping the area when drawn </li><li>\n+       * Unease - for In or Out animations it will reverse the \'easing\' direction so you can slide in &amp; out the same panel w/ out overlap </li></ul>\n        *<p>\n        * You may combine the directional suffixes to get an additional four directions (i.e. ZoomOutNorthEast). And this\n        * can also be combined with the timeline suffixes as well, or even Fade (i.e. ZoomInQuadraticSouthWestFade)\n@@ -2888,7 +2888,7 @@ public class Utility {\n        *\n        * @since 6.4\n        *\n-       * @declaration public boolean ReleaseUIRefreshLock();\n+       * @declaration public void ReleaseUIRefreshLock();\n        */\n       public Object runSafely(Catbert.FastStack stack) throws Exception{\n         UIManager uiMgr = stack.getUIMgr();\n@@ -3198,11 +3198,11 @@ public class Utility {\n       /**\n        * converts a string of NTE key characters (and normal characters) into their\n        * default character representation - given by the first character in the\n-       * NTE chatacter list<br/>\n+       * NTE chatacter list<br>\n        * The NTE key characters are the Unicode characters u2460-u2468 and u24EA  (Unicode Circled Digits),\n-       * representing the numeric Text Keys 1-9 and 0.<br/>\n+       * representing the numeric Text Keys 1-9 and 0.<br>\n        * The characters represented by the keys are defined by the client properties\n-       * <tt>"ui/numeric_text_input_<ui/translation_language_code>_<key>_lower</tt>.\n+       * <tt>"ui/numeric_text_input_&lt;ui/translation_language_code&gt;_&lt;key&gt;_lower</tt>.\n        *\n        * @param NteString the string to convert\n        * @return the converted string\n@@ -3222,11 +3222,11 @@ public class Utility {\n     rft.put(new PredefinedJEPFunction("Utility", "StringIndexOfNTE", 2, new String[]{"FullString","MatchStringNTE"})\n     {\n       /**\n-       * Returns the index of MatchStringNTE string within FullString, -1 if it is not found.<br/>\n-       * Search is case-insentive<br/>\n+       * Returns the index of MatchStringNTE string within FullString, -1 if it is not found.<br>\n+       * Search is case-insentive<br>\n        * The MatchStringNTE may contain the Unicode characters u2460-u2468 and u24EA  (Unicode Circled Digits) representing\n        * numeric Text Keys 1-9 and 0. The characters represented by the keys are defined by the client properties\n-       * <tt>"ui/numeric_text_input_<ui/translation_language_code>_<key>_lower</tt>.\n+       * <tt>"ui/numeric_text_input_&lt;ui/translation_language_code&gt;_&lt;key&gt;_lower</tt>.\n        * @param FullString the string to search in\n        * @param MatchStringNTE the string to search for\n        * @return the first 0-based index in FullString that MatchStringNTE occurs at or -1 if it is not found\n@@ -3244,11 +3244,11 @@ public class Utility {\n     rft.put(new PredefinedJEPFunction("Utility", "StringStartsWithNTE", 2, new String[]{"FullString","MatchStringNTE"})\n     {\n       /**\n-       * Returns true if the Full String starts with characters matching MatchStringNTE<br/>\n-       * Search is case-insentive<br/>\n+       * Returns true if the Full String starts with characters matching MatchStringNTE<br>\n+       * Search is case-insentive<br>\n        * The MatchStringNTE may contain the Unicode characters u2460-u2468 and u24EA  (Unicode Circled Digits) representing\n        * numeric Text Keys 1-9 and 0. The characters represented by the keys are defined by the client properties\n-       * <tt>"ui/numeric_text_input_<ui/translation_language_code>_<key>_lower</tt>.\n+       * <tt>"ui/numeric_text_input_&lt;ui/translation_language_code&gt;_&lt;key&gt;_lower</tt>.\n        * @param FullString the string to search in\n        * @param MatchStringNTE the string to search for\n        * @return true if FullString starts with characters matching MatchStringNTE\ndiff --git a/java/sage/api/WidgetAPI.java b/java/sage/api/WidgetAPI.java\nindex 892ca45b..04f7f811 100644\n--- a/java/sage/api/WidgetAPI.java\n+++ b/java/sage/api/WidgetAPI.java\n@@ -178,6 +178,7 @@ public class WidgetAPI {\n     {\n       /**\n        * Gets all of the Widgets that are in the currently loaded STV that are of the specified type\n+       * @param WidgetType the name of the widget type\n        * @return all of the Widgets that are in the currently loaded STV that are of the specified type\n        *\n        * @declaration public Widget[] GetWidgetsByType(String WidgetType);\n@@ -206,6 +207,7 @@ public class WidgetAPI {\n        * Creates a new Widget of the specified type and adds it to the STV. This also allows specifying the desired symbol to use for the Widget.\n        * If the symbol is already in use; then a new symbol will automatically be assigned to this Widget instead.\n        * @param WidgetType the type of the new Widget\n+       * @param Symbol the symbol name for the new widget (UID)\n        * @return the newly created Widget\n        * @since 7.0\n        *\ndiff --git a/native/so/DVBCapture2.0/Makefile b/native/so/DVBCapture2.0/Makefile\nindex bc12b27d..b3ea1bbe 100755\n--- a/native/so/DVBCapture2.0/Makefile\n+++ b/native/so/DVBCapture2.0/Makefile\n@@ -40,8 +40,8 @@ libDVBCapture.so: $(OBJFILES)\n libDVBCapture.so.debug: $(OBJFILES) \n \t$(CC) -g -O0 -Wl,-Map=libDVBCapture.map -shared -W1 -o libDVBCapture.so libNativeCored.so $(OBJFILES)  $(CHANNELD_LIB)\n \n-dvbtest: dep_make libDVBCapture.so dvbtest.o sage_DVBCaptureDevice.c\n-\t$(CC)   -Wall -o dvbtest dvbtest.o libNativeCore.so  $(CHANNEL_LIB)\n+dvbtest: dep_make libDVBCapture.so dvbtest.o\n+\t$(CC) -pthread -Wall -o dvbtest dvbtest.o libNativeCore.so circbuffer.o thread_util.o $(CHANNEL_LIB)\n \n dvbtest.o: sage_DVBCaptureDevice.c\n \t$(CC) $(CFLAGS) -c -o dvbtest.o -DSTANDALONE sage_DVBCaptureDevice.c\t\t\ndiff --git a/stvs/GenerateStudioAPIDocs.sh b/stvs/GenerateStudioAPIDocs.sh\nnew file mode 100755\nindex 00000000..89138210\n--- /dev/null\n+++ b/stvs/GenerateStudioAPIDocs.sh\n@@ -0,0 +1,16 @@\n+#!/bin/bash\n+javac ../java/tv/sage/util/StudioAPIProcessor.java\n+java -cp ../java/ tv.sage.util.StudioAPIProcessor ../java/sage/api/ ../java/tempdocs/sage/api\n+rm ../java/tv/sage/util/StudioAPIProcessor*.class\n+cd ../java/tempdocs\n+# For some reason the javadocs generated with jdk7/8 from Googles builds\n+# end up with no formatting at all...but the one from jdk6 works, so force\n+# that for Narflex since he\'ll usually be building this. :)\n+if [ -e /usr/local/buildtools/java/jdk6/bin/javadoc ] ; then\n+  JAVADOC="/usr/local/buildtools/java/jdk6/bin/javadoc"\n+else\n+  JAVADOC="javadoc"\n+fi\n+# We are two levels of the base now\n+$JAVADOC -classpath ../../third_party/Oracle/vecmath.jar:../../third_party/Lucene/lucene-core-3.6.0.jar:../../third_party/JCIFS/jcifs-1.1.6.jar -package -windowtitle "SageTV V9.0 API Specification" -doctitle \'SageTV<sup><font size="-2">TM</font></sup> V9.0 API Specification\' -header \'<b>SageTV Platform </b><br><font size="-1">V9.0</font>\' -bottom \'<font size="-1">SageTV is a trademark or registered trademark of Google, Inc. in the US and other countries.<br>Copyright 2000-2015 The SageTV Authors. All Rights Reserved.</font>\' -d ../../stvs/doc -sourcepath .:../../java:../../third_party/RSSLIB4J/java:../../third_party/Javolution/java:../../third_party/Ogle/java:../../third_party/jtux/java:../../third_party/MetadataExtractor/java:../../third_party/SingularSys/java:../../third_party/jcraft/java sage.api sage.media.rss\n+rm -rf ../../java/tempdocs\ndiff --git a/third_party/RSSLIB4J/java/sage/media/rss/RSSDoublinCoreModule.java b/third_party/RSSLIB4J/java/sage/media/rss/RSSDoublinCoreModule.java\nindex 477a5cf3..3e7f7e76 100644\n--- a/third_party/RSSLIB4J/java/sage/media/rss/RSSDoublinCoreModule.java\n+++ b/third_party/RSSLIB4J/java/sage/media/rss/RSSDoublinCoreModule.java\n@@ -35,11 +35,6 @@ import java.util.*;\n  * <li><b>&lt;dc:rights&gt;</b> ( #PCDATA )</li>\n  * </ul>\n  *\n- * </p>\n- *\n- * </blockquote>\n- *\n- *\n  *\n  * @since RSSLIB4J 0.1\n  * @author Francesco aka \'Stealthp\' stealthp[@]stealthp.org\ndiff --git a/third_party/RSSLIB4J/java/sage/media/rss/Translate.java b/third_party/RSSLIB4J/java/sage/media/rss/Translate.java\nindex 4bdfea11..d9ee8efd 100644\n--- a/third_party/RSSLIB4J/java/sage/media/rss/Translate.java\n+++ b/third_party/RSSLIB4J/java/sage/media/rss/Translate.java\n@@ -35,9 +35,9 @@ import java.io.UnsupportedEncodingException;\n  * Structure to hold a character and it\'s equivalent entity reference kernel.\n  * For the character reference &amp;copy; the character would be \'&copy;\' and\n  * the kernel would be "copy", for example.<p>\n- * Character references are described at <a href="Character references">http://www.w3.org/TR/REC-html40/charset.html#entities</a>\n+ * Character references are described at <a href="http://www.w3.org/TR/REC-html40/charset.html#entities">Character references</a>\n  * Supports the Ordered interface so it\'s easy to create a list sorted by\n- * kernel, to perform binary searches on.<p>\n+ * kernel, to perform binary searches on.\n  */\n class CharacterReference\n implements\n@@ -134,7 +134,6 @@ Comparable\n \n   /**\n    * Compare one reference to another.\n-   * @see org.htmlparser.util.sort.Ordered\n    */\n   public int compareTo (Object that)\n   {\n@@ -205,7 +204,6 @@ class CharacterReferenceEx extends CharacterReference\n \n   /**\n    * Compare one reference to another.\n-   * @see org.htmlparser.util.sort.Ordered\n    */\n   public int compare (Object that)\n   {\n@@ -812,7 +810,7 @@ public class Translate\n   /**\n    * Look up a reference by kernel.\n    * Use a binary search on the ordered list of known references.\n-   * <em>This is not very efficient, use {@link org.htmlparser.util.Translate#lookup(org.htmlparser.util.CharacterReference) lookup(CharacterReference)}\n+   * <em>This is not very efficient, use org.htmlparser.util.Translate.lookup(org.htmlparser.util.CharacterReference)\n    * instead.</em>\n    * @param kernel The string to lookup, i.e. "amp".\n    * @param start The starting point in the string of the kernel.\n@@ -838,7 +836,7 @@ public class Translate\n    * Convert a reference to a unicode character.\n    * Convert a single numeric character reference or character entity reference\n    * to a unicode character.\n-   * @param string The string to convert. Of the form &xxxx; or &amp;#xxxx; with\n+   * @param string The string to convert. Of the form &amp;xxxx; or &amp;#xxxx; with\n    * or without the leading ampersand or trailing semi-colon.\n    * @param start The starting pooint in the string to look for a character reference.\n    * @param end The ending point in the string to stop looking for a character reference.\n@@ -855,7 +853,7 @@ public class Translate\n    * Convert a reference to a unicode character.\n    * Convert a single numeric character reference or character entity reference\n    * to a unicode character.\n-   * @param string The string to convert. Of the form &xxxx; or &amp;#xxxx; with\n+   * @param string The string to convert. Of the form &amp;xxxx; or &amp;#xxxx; with\n    * or without the leading ampersand or trailing semi-colon.\n    * @return The converted character or \'\x00\' (zero) if the string is an\n    * invalid reference.\n', 'commit_subject': "Merge remote-tracking branch 'google/master'", 'repo_name': 'google/sagetv', 'committer': {'name': 'Keith Fischer', 'email': 'd012bab67fa823e9925cafd140eaae8a5cf8f40b@yahoo.com', 'time_sec': '1440555986', 'tz_offset': '-420', 'date': {'seconds': '1440555986'}}, 'commit_tree': '45c1dc26f0d59ebc84e87af63418e6d186c851f7', 'commit_message': "Merge remote-tracking branch 'google/master'\n", 'language_name': 'C++', 'license': 'apache-2.0', 'hunks': '@@ -35,9 +35,9 @@ import java.io.UnsupportedEncodingException;\n  * Structure to hold a character and it\'s equivalent entity reference kernel.\n  * For the character reference &amp;copy; the character would be \'&copy;\' and\n  * the kernel would be "copy", for example.<p>\n- * Character references are described at <a href="Character references">http://www.w3.org/TR/REC-html40/charset.html#entities</a>\n+ * Character references are described at <a href="http://www.w3.org/TR/REC-html40/charset.html#entities">Character references</a>\n  * Supports the Ordered interface so it\'s easy to create a list sorted by\n- * kernel, to perform binary searches on.<p>\n+ * kernel, to perform binary searches on.\n  */\n class CharacterReference\n implements\n@@ -134,7 +134,6 @@ Comparable\n \n   /**\n    * Compare one reference to another.\n-   * @see org.htmlparser.util.sort.Ordered\n    */\n   public int compareTo (Object that)\n   {\n@@ -205,7 +204,6 @@ class CharacterReferenceEx extends CharacterReference\n \n   /**\n    * Compare one reference to another.\n-   * @see org.htmlparser.util.sort.Ordered\n    */\n   public int compare (Object that)\n   {\n@@ -812,7 +810,7 @@ public class Translate\n   /**\n    * Look up a reference by kernel.\n    * Use a binary search on the ordered list of known references.\n-   * <em>This is not very efficient, use {@link org.htmlparser.util.Translate#lookup(org.htmlparser.util.CharacterReference) lookup(CharacterReference)}\n+   * <em>This is not very efficient, use org.htmlparser.util.Translate.lookup(org.htmlparser.util.CharacterReference)\n    * instead.</em>\n    * @param kernel The string to lookup, i.e. "amp".\n    * @param start The starting point in the string of the kernel.\n@@ -838,7 +836,7 @@ public class Translate\n    * Convert a reference to a unicode character.\n    * Convert a single numeric character reference or character entity reference\n    * to a unicode character.\n-   * @param string The string to convert. Of the form &xxxx; or &amp;#xxxx; with\n+   * @param string The string to convert. Of the form &amp;xxxx; or &amp;#xxxx; with\n    * or without the leading ampersand or trailing semi-colon.\n    * @param start The starting pooint in the string to look for a character reference.\n    * @param end The ending point in the string to stop looking for a character reference.\n@@ -855,7 +853,7 @@ public class Translate\n    * Convert a reference to a unicode character.\n    * Convert a single numeric character reference or character entity reference\n    * to a unicode character.\n-   * @param string The string to convert. Of the form &xxxx; or &amp;#xxxx; with\n+   * @param string The string to convert. Of the form &amp;xxxx; or &amp;#xxxx; with\n    * or without the leading ampersand or trailing semi-colon.\n    * @return The converted character or \'\x00\' (zero) if the string is an\n    * invalid reference.\n', 'addition_count': 5, 'deletion_count': 7, 'src_file': 'a/third_party/RSSLIB4J/java/sage/media/rss/Translate.java', 'tgt_file': 'b/third_party/RSSLIB4J/java/sage/media/rss/Translate.java', 'file_extension': '.java', 'before_file': '// http://sourceforge.org/projects/htmlparser\n// Copyright (C) 2004 Derrick Oswald\n//\n// Revision Control Information\n//\n// This library is free software; you can redistribute it and/or\n// modify it under the terms of the GNU Lesser General Public\n// License as published by the Free Software Foundation; either\n// version 2.1 of the License, or (at your option) any later version.\n//\n// This library is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n// Lesser General Public License for more details.\n//\n// You should have received a copy of the GNU Lesser General Public\n// License along with this library; if not, write to the Free Software\n// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n//\n\npackage sage.media.rss;\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStreamWriter;\nimport java.io.PrintStream;\nimport java.io.PrintWriter;\nimport java.io.Reader;\nimport java.io.UnsupportedEncodingException;\n\n/**\n * Structure to hold a character and it\'s equivalent entity reference kernel.\n * For the character reference &amp;copy; the character would be \'&copy;\' and\n * the kernel would be "copy", for example.<p>\n * Character references are described at <a href="Character references">http://www.w3.org/TR/REC-html40/charset.html#entities</a>\n * Supports the Ordered interface so it\'s easy to create a list sorted by\n * kernel, to perform binary searches on.<p>\n */\nclass CharacterReference\nimplements\nCloneable,\nComparable\n{\n  /**\n   * The character value as an integer.\n   */\n  protected int mCharacter;\n\n  /**\n   * This entity reference kernel.\n   * The text between the ampersand and the semicolon.\n   */\n  protected String mKernel;\n\n  /**\n   * Construct a <code>CharacterReference</code> with the character and kernel given.\n   * @param kernel The kernel in the equivalent character entity reference.\n   * @param character The character needing encoding.\n   */\n  public CharacterReference (String kernel, int character)\n  {\n    mKernel = kernel;\n    mCharacter = character;\n    if (null == mKernel)\n      mKernel = "";\n  }\n\n  /**\n   * Get this CharacterReference\'s kernel.\n   * @return The kernel in the equivalent character entity reference.\n   */\n  public String getKernel ()\n  {\n    return (mKernel);\n  }\n\n  /**\n   * Set this CharacterReference\'s kernel.\n   * This is used to avoid creating a new object to perform a binary search.\n   * @param kernel The kernel in the equivalent character entity reference.\n   */\n  void setKernel (String kernel)\n  {\n    mKernel = kernel;\n  }\n\n  /**\n   * Get the character needing translation.\n   * @return The character.\n   */\n  public int getCharacter ()\n  {\n    return (mCharacter);\n  }\n\n  /**\n   * Set the character.\n   * This is used to avoid creating a new object to perform a binary search.\n   * @param character The character needing translation.\n   */\n  void setCharacter (int character)\n  {\n    mCharacter = character;\n  }\n\n  /**\n   * Visualize this character reference as a string.\n   * @return A string with the character and kernel.\n   */\n  public String toString ()\n  {\n    String hex;\n    StringBuffer ret;\n\n    ret = new StringBuffer (6 + 8 + 2); // max 8 in string\n    hex = Integer.toHexString (getCharacter ());\n    ret.append ("\\\\u");\n    for (int i = hex.length (); i < 4; i++)\n      ret.append ("0");\n    ret.append (hex);\n    ret.append ("[");\n    ret.append (getKernel ());\n    ret.append ("]");\n\n    return (ret.toString ());\n  }\n\n  //\n  // Ordered interface\n  //\n\n  /**\n   * Compare one reference to another.\n   * @see org.htmlparser.util.sort.Ordered\n   */\n  public int compareTo (Object that)\n  {\n    CharacterReference r;\n\n    r = (CharacterReference)that;\n\n    return (getKernel ().compareTo (r.getKernel ()));\n  }\n}\n\n\n\n/**\n * Extended character entity reference.\n * Handles kernels within other strings, just for lookup purposes.\n */\nclass CharacterReferenceEx extends CharacterReference\n{\n  /**\n   * The starting point in the string.\n   */\n  protected int mStart;\n\n  /**\n   * The ending point in the string.\n   */\n  protected int mEnd;\n\n  /**\n   * Zero args constructor.\n   * This object is only ever used after setting the kernel, start and end.\n   */\n  public CharacterReferenceEx ()\n  {\n    super ("", 0);\n  }\n\n  /**\n   * Set the starting point of the kernel.\n   */\n  public void setStart (int start)\n  {\n    mStart = start;\n  }\n\n  /**\n   * Set the supposed ending point.\n   * This only specifies an upper bound on the kernel length.\n   */\n  public void setEnd (int end)\n  {\n    mEnd = end;\n  }\n\n  /**\n   * Get this CharacterReference\'s kernel.\n   * @return The kernel in the equivalent character entity reference.\n   */\n  public String getKernel ()\n  {\n    return (mKernel.substring (mStart, mEnd));\n  }\n\n  //\n  // Ordered interface\n  //\n\n  /**\n   * Compare one reference to another.\n   * @see org.htmlparser.util.sort.Ordered\n   */\n  public int compare (Object that)\n  {\n    CharacterReference r;\n    String kernel;\n    int length;\n    int ret;\n\n    ret = 0;\n    r = (CharacterReference)that;\n    kernel = r.getKernel ();\n    length = kernel.length ();\n    for (int i = mStart, j = 0; i < mEnd; i++, j++)\n    {\n      if (j >= length)\n      {\n        ret = 1;\n        break;\n      }\n      ret = mKernel.charAt (i) - kernel.charAt (j);\n      if (0 != ret)\n        break;\n    }\n\n    return (ret);\n  }\n}\n\n/**\n * Translate numeric character references and character entity references to unicode characters.\n * Based on tables found at <a href="http://www.w3.org/TR/REC-html40/sgml/entities.html">\n * http://www.w3.org/TR/REC-html40/sgml/entities.html</a>\n * <p>Typical usage:\n * <pre>\n *      String s = Translate.decode (getTextFromHtmlPage ());\n * </pre>\n * or\n * <pre>\n *      String s = "&lt;HTML&gt;" + Translate.encode (getArbitraryText ()) + "&lt;/HTML&gt;";\n * </pre>\n */\npublic class Translate\n{\n  /**\n   * If this member is set <code>true</code>, decoding of streams is\n   * done line by line in order to reduce the maximum memory required.\n   */\n  static public boolean DECODE_LINE_BY_LINE = false;\n\n  /**\n   * If this member is set <code>true</code>, encoding of numeric character\n   * references uses hexadecimal digits, i.e. &amp;#x25CB;, instead of decimal\n   * digits.\n   */\n  static public boolean ENCODE_HEXADECIMAL = false;\n\n  /**\n   * Table mapping entity reference kernel to character.\n   * This is sorted by kernel when the class is loaded.\n   */\n  protected static final CharacterReference[] mCharacterReferences =\n    {\n    // Portions (c) International Organization for Standardization 1986\n    // Permission to copy in any form is granted for use with\n    // conforming SGML systems and applications as defined in\n    // ISO 8879, provided this notice is included in all copies.\n    // Character entity set. Typical invocation:\n    // <!ENTITY % HTMLlat1 PUBLIC\n    // "-//W3C//ENTITIES Latin 1//EN//HTML">\n    // %HTMLlat1;\n    new CharacterReference ("nbsp",     \'\\u00a0\'), // no-break space = non-breaking space, U+00A0 ISOnum\n    new CharacterReference ("iexcl",    \'\\u00a1\'), // inverted exclamation mark, U+00A1 ISOnum\n    new CharacterReference ("cent",     \'\\u00a2\'), // cent sign, U+00A2 ISOnum\n    new CharacterReference ("pound",    \'\\u00a3\'), // pound sign, U+00A3 ISOnum\n    new CharacterReference ("curren",   \'\\u00a4\'), // currency sign, U+00A4 ISOnum\n    new CharacterReference ("yen",      \'\\u00a5\'), // yen sign = yuan sign, U+00A5 ISOnum\n    new CharacterReference ("brvbar",   \'\\u00a6\'), // broken bar = broken vertical bar, U+00A6 ISOnum\n    new CharacterReference ("sect",     \'\\u00a7\'), // section sign, U+00A7 ISOnum\n    new CharacterReference ("uml",      \'\\u00a8\'), // diaeresis = spacing diaeresis, U+00A8 ISOdia\n    new CharacterReference ("copy",     \'\\u00a9\'), // copyright sign, U+00A9 ISOnum\n    new CharacterReference ("ordf",     \'\\u00aa\'), // feminine ordinal indicator, U+00AA ISOnum\n    new CharacterReference ("laquo",    \'\\u00ab\'), // left-pointing double angle quotation mark = left pointing guillemet, U+00AB ISOnum\n    new CharacterReference ("not",      \'\\u00ac\'), // not sign, U+00AC ISOnum\n    new CharacterReference ("shy",      \'\\u00ad\'), // soft hyphen = discretionary hyphen, U+00AD ISOnum\n    new CharacterReference ("reg",      \'\\u00ae\'), // registered sign = registered trade mark sign, U+00AE ISOnum\n    new CharacterReference ("macr",     \'\\u00af\'), // macron = spacing macron = overline = APL overbar, U+00AF ISOdia\n    new CharacterReference ("deg",      \'\\u00b0\'), // degree sign, U+00B0 ISOnum\n    new CharacterReference ("plusmn",   \'\\u00b1\'), // plus-minus sign = plus-or-minus sign, U+00B1 ISOnum\n    new CharacterReference ("sup2",     \'\\u00b2\'), // superscript two = superscript digit two = squared, U+00B2 ISOnum\n    new CharacterReference ("sup3",     \'\\u00b3\'), // superscript three = superscript digit three = cubed, U+00B3 ISOnum\n    new CharacterReference ("acute",    \'\\u00b4\'), // acute accent = spacing acute, U+00B4 ISOdia\n    new CharacterReference ("micro",    \'\\u00b5\'), // micro sign, U+00B5 ISOnum\n    new CharacterReference ("para",     \'\\u00b6\'), // pilcrow sign = paragraph sign, U+00B6 ISOnum\n    new CharacterReference ("middot",   \'\\u00b7\'), // middle dot = Georgian comma = Greek middle dot, U+00B7 ISOnum\n    new CharacterReference ("cedil",    \'\\u00b8\'), // cedilla = spacing cedilla, U+00B8 ISOdia\n    new CharacterReference ("sup1",     \'\\u00b9\'), // superscript one = superscript digit one, U+00B9 ISOnum\n    new CharacterReference ("ordm",     \'\\u00ba\'), // masculine ordinal indicator, U+00BA ISOnum\n    new CharacterReference ("raquo",    \'\\u00bb\'), // right-pointing double angle quotation mark = right pointing guillemet, U+00BB ISOnum\n    new CharacterReference ("frac14",   \'\\u00bc\'), // vulgar fraction one quarter = fraction one quarter, U+00BC ISOnum\n    new CharacterReference ("frac12",   \'\\u00bd\'), // vulgar fraction one half = fraction one half, U+00BD ISOnum\n    new CharacterReference ("frac34",   \'\\u00be\'), // vulgar fraction three quarters = fraction three quarters, U+00BE ISOnum\n    new CharacterReference ("iquest",   \'\\u00bf\'), // inverted question mark = turned question mark, U+00BF ISOnum\n    new CharacterReference ("Agrave",   \'\\u00c0\'), // latin capital letter A with grave = latin capital letter A grave, U+00C0 ISOlat1\n    new CharacterReference ("Aacute",   \'\\u00c1\'), // latin capital letter A with acute, U+00C1 ISOlat1\n    new CharacterReference ("Acirc",    \'\\u00c2\'), // latin capital letter A with circumflex, U+00C2 ISOlat1\n    new CharacterReference ("Atilde",   \'\\u00c3\'), // latin capital letter A with tilde, U+00C3 ISOlat1\n    new CharacterReference ("Auml",     \'\\u00c4\'), // latin capital letter A with diaeresis, U+00C4 ISOlat1\n    new CharacterReference ("Aring",    \'\\u00c5\'), // latin capital letter A with ring above = latin capital letter A ring, U+00C5 ISOlat1\n    new CharacterReference ("AElig",    \'\\u00c6\'), // latin capital letter AE = latin capital ligature AE, U+00C6 ISOlat1\n    new CharacterReference ("Ccedil",   \'\\u00c7\'), // latin capital letter C with cedilla, U+00C7 ISOlat1\n    new CharacterReference ("Egrave",   \'\\u00c8\'), // latin capital letter E with grave, U+00C8 ISOlat1\n    new CharacterReference ("Eacute",   \'\\u00c9\'), // latin capital letter E with acute, U+00C9 ISOlat1\n    new CharacterReference ("Ecirc",    \'\\u00ca\'), // latin capital letter E with circumflex, U+00CA ISOlat1\n    new CharacterReference ("Euml",     \'\\u00cb\'), // latin capital letter E with diaeresis, U+00CB ISOlat1\n    new CharacterReference ("Igrave",   \'\\u00cc\'), // latin capital letter I with grave, U+00CC ISOlat1\n    new CharacterReference ("Iacute",   \'\\u00cd\'), // latin capital letter I with acute, U+00CD ISOlat1\n    new CharacterReference ("Icirc",    \'\\u00ce\'), // latin capital letter I with circumflex, U+00CE ISOlat1\n    new CharacterReference ("Iuml",     \'\\u00cf\'), // latin capital letter I with diaeresis, U+00CF ISOlat1\n    new CharacterReference ("ETH",      \'\\u00d0\'), // latin capital letter ETH, U+00D0 ISOlat1\n    new CharacterReference ("Ntilde",   \'\\u00d1\'), // latin capital letter N with tilde, U+00D1 ISOlat1\n    new CharacterReference ("Ograve",   \'\\u00d2\'), // latin capital letter O with grave, U+00D2 ISOlat1\n    new CharacterReference ("Oacute",   \'\\u00d3\'), // latin capital letter O with acute, U+00D3 ISOlat1\n    new CharacterReference ("Ocirc",    \'\\u00d4\'), // latin capital letter O with circumflex, U+00D4 ISOlat1\n    new CharacterReference ("Otilde",   \'\\u00d5\'), // latin capital letter O with tilde, U+00D5 ISOlat1\n    new CharacterReference ("Ouml",     \'\\u00d6\'), // latin capital letter O with diaeresis, U+00D6 ISOlat1\n    new CharacterReference ("times",    \'\\u00d7\'), // multiplication sign, U+00D7 ISOnum\n    new CharacterReference ("Oslash",   \'\\u00d8\'), // latin capital letter O with stroke = latin capital letter O slash, U+00D8 ISOlat1\n    new CharacterReference ("Ugrave",   \'\\u00d9\'), // latin capital letter U with grave, U+00D9 ISOlat1\n    new CharacterReference ("Uacute",   \'\\u00da\'), // latin capital letter U with acute, U+00DA ISOlat1\n    new CharacterReference ("Ucirc",    \'\\u00db\'), // latin capital letter U with circumflex, U+00DB ISOlat1\n    new CharacterReference ("Uuml",     \'\\u00dc\'), // latin capital letter U with diaeresis, U+00DC ISOlat1\n    new CharacterReference ("Yacute",   \'\\u00dd\'), // latin capital letter Y with acute, U+00DD ISOlat1\n    new CharacterReference ("THORN",    \'\\u00de\'), // latin capital letter THORN, U+00DE ISOlat1\n    new CharacterReference ("szlig",    \'\\u00df\'), // latin small letter sharp s = ess-zed, U+00DF ISOlat1\n    new CharacterReference ("agrave",   \'\\u00e0\'), // latin small letter a with grave = latin small letter a grave, U+00E0 ISOlat1\n    new CharacterReference ("aacute",   \'\\u00e1\'), // latin small letter a with acute, U+00E1 ISOlat1\n    new CharacterReference ("acirc",    \'\\u00e2\'), // latin small letter a with circumflex, U+00E2 ISOlat1\n    new CharacterReference ("atilde",   \'\\u00e3\'), // latin small letter a with tilde, U+00E3 ISOlat1\n    new CharacterReference ("auml",     \'\\u00e4\'), // latin small letter a with diaeresis, U+00E4 ISOlat1\n    new CharacterReference ("aring",    \'\\u00e5\'), // latin small letter a with ring above = latin small letter a ring, U+00E5 ISOlat1\n    new CharacterReference ("aelig",    \'\\u00e6\'), // latin small letter ae = latin small ligature ae, U+00E6 ISOlat1\n    new CharacterReference ("ccedil",   \'\\u00e7\'), // latin small letter c with cedilla, U+00E7 ISOlat1\n    new CharacterReference ("egrave",   \'\\u00e8\'), // latin small letter e with grave, U+00E8 ISOlat1\n    new CharacterReference ("eacute",   \'\\u00e9\'), // latin small letter e with acute, U+00E9 ISOlat1\n    new CharacterReference ("ecirc",    \'\\u00ea\'), // latin small letter e with circumflex, U+00EA ISOlat1\n    new CharacterReference ("euml",     \'\\u00eb\'), // latin small letter e with diaeresis, U+00EB ISOlat1\n    new CharacterReference ("igrave",   \'\\u00ec\'), // latin small letter i with grave, U+00EC ISOlat1\n    new CharacterReference ("iacute",   \'\\u00ed\'), // latin small letter i with acute, U+00ED ISOlat1\n    new CharacterReference ("icirc",    \'\\u00ee\'), // latin small letter i with circumflex, U+00EE ISOlat1\n    new CharacterReference ("iuml",     \'\\u00ef\'), // latin small letter i with diaeresis, U+00EF ISOlat1\n    new CharacterReference ("eth",      \'\\u00f0\'), // latin small letter eth, U+00F0 ISOlat1\n    new CharacterReference ("ntilde",   \'\\u00f1\'), // latin small letter n with tilde, U+00F1 ISOlat1\n    new CharacterReference ("ograve",   \'\\u00f2\'), // latin small letter o with grave, U+00F2 ISOlat1\n    new CharacterReference ("oacute",   \'\\u00f3\'), // latin small letter o with acute, U+00F3 ISOlat1\n    new CharacterReference ("ocirc",    \'\\u00f4\'), // latin small letter o with circumflex, U+00F4 ISOlat1\n    new CharacterReference ("otilde",   \'\\u00f5\'), // latin small letter o with tilde, U+00F5 ISOlat1\n    new CharacterReference ("ouml",     \'\\u00f6\'), // latin small letter o with diaeresis, U+00F6 ISOlat1\n    new CharacterReference ("divide",   \'\\u00f7\'), // division sign, U+00F7 ISOnum\n    new CharacterReference ("oslash",   \'\\u00f8\'), // latin small letter o with stroke, = latin small letter o slash, U+00F8 ISOlat1\n    new CharacterReference ("ugrave",   \'\\u00f9\'), // latin small letter u with grave, U+00F9 ISOlat1\n    new CharacterReference ("uacute",   \'\\u00fa\'), // latin small letter u with acute, U+00FA ISOlat1\n    new CharacterReference ("ucirc",    \'\\u00fb\'), // latin small letter u with circumflex, U+00FB ISOlat1\n    new CharacterReference ("uuml",     \'\\u00fc\'), // latin small letter u with diaeresis, U+00FC ISOlat1\n    new CharacterReference ("yacute",   \'\\u00fd\'), // latin small letter y with acute, U+00FD ISOlat1\n    new CharacterReference ("thorn",    \'\\u00fe\'), // latin small letter thorn, U+00FE ISOlat1\n    new CharacterReference ("yuml",     \'\\u00ff\'), // latin small letter y with diaeresis, U+00FF ISOlat1\n    // Mathematical, Greek and Symbolic characters for HTML\n    // Character entity set. Typical invocation:\n    // <!ENTITY % HTMLsymbol PUBLIC\n    // "-//W3C//ENTITIES Symbols//EN//HTML">\n    // %HTMLsymbol;\n    // Portions (c) International Organization for Standardization 1986:\n    // Permission to copy in any form is granted for use with\n    // conforming SGML systems and applications as defined in\n    // ISO 8879, provided this notice is included in all copies.\n    // Relevant ISO entity set is given unless names are newly introduced.\n    // New names (i.e., not in ISO 8879 list) do not clash with any\n    // existing ISO 8879 entity names. ISO 10646 character numbers\n    // are given for each character, in hex. CDATA values are decimal\n    // conversions of the ISO 10646 values and refer to the document\n    // character set. Names are ISO 10646 names.\n    // Latin Extended-B\n    new CharacterReference ("fnof",     \'\\u0192\'), // latin small f with hook = function = florin, U+0192 ISOtech\n    // Greek\n    new CharacterReference ("Alpha",    \'\\u0391\'), // greek capital letter alpha, U+0391\n    new CharacterReference ("Beta",     \'\\u0392\'), // greek capital letter beta, U+0392\n    new CharacterReference ("Gamma",    \'\\u0393\'), // greek capital letter gamma, U+0393 ISOgrk3\n    new CharacterReference ("Delta",    \'\\u0394\'), // greek capital letter delta, U+0394 ISOgrk3\n    new CharacterReference ("Epsilon",  \'\\u0395\'), // greek capital letter epsilon, U+0395\n    new CharacterReference ("Zeta",     \'\\u0396\'), // greek capital letter zeta, U+0396\n    new CharacterReference ("Eta",      \'\\u0397\'), // greek capital letter eta, U+0397\n    new CharacterReference ("Theta",    \'\\u0398\'), // greek capital letter theta, U+0398 ISOgrk3\n    new CharacterReference ("Iota",     \'\\u0399\'), // greek capital letter iota, U+0399\n    new CharacterReference ("Kappa",    \'\\u039a\'), // greek capital letter kappa, U+039A\n    new CharacterReference ("Lambda",   \'\\u039b\'), // greek capital letter lambda, U+039B ISOgrk3\n    new CharacterReference ("Mu",       \'\\u039c\'), // greek capital letter mu, U+039C\n    new CharacterReference ("Nu",       \'\\u039d\'), // greek capital letter nu, U+039D\n    new CharacterReference ("Xi",       \'\\u039e\'), // greek capital letter xi, U+039E ISOgrk3\n    new CharacterReference ("Omicron",  \'\\u039f\'), // greek capital letter omicron, U+039F\n    new CharacterReference ("Pi",       \'\\u03a0\'), // greek capital letter pi, U+03A0 ISOgrk3\n    new CharacterReference ("Rho",      \'\\u03a1\'), // greek capital letter rho, U+03A1\n    // there is no Sigmaf, and no U+03A2 character either\n    new CharacterReference ("Sigma",    \'\\u03a3\'), // greek capital letter sigma, U+03A3 ISOgrk3\n    new CharacterReference ("Tau",      \'\\u03a4\'), // greek capital letter tau, U+03A4\n    new CharacterReference ("Upsilon",  \'\\u03a5\'), // greek capital letter upsilon, U+03A5 ISOgrk3\n    new CharacterReference ("Phi",      \'\\u03a6\'), // greek capital letter phi, U+03A6 ISOgrk3\n    new CharacterReference ("Chi",      \'\\u03a7\'), // greek capital letter chi, U+03A7\n    new CharacterReference ("Psi",      \'\\u03a8\'), // greek capital letter psi, U+03A8 ISOgrk3\n    new CharacterReference ("Omega",    \'\\u03a9\'), // greek capital letter omega, U+03A9 ISOgrk3\n    new CharacterReference ("alpha",    \'\\u03b1\'), // greek small letter alpha, U+03B1 ISOgrk3\n    new CharacterReference ("beta",     \'\\u03b2\'), // greek small letter beta, U+03B2 ISOgrk3\n    new CharacterReference ("gamma",    \'\\u03b3\'), // greek small letter gamma, U+03B3 ISOgrk3\n    new CharacterReference ("delta",    \'\\u03b4\'), // greek small letter delta, U+03B4 ISOgrk3\n    new CharacterReference ("epsilon",  \'\\u03b5\'), // greek small letter epsilon, U+03B5 ISOgrk3\n    new CharacterReference ("zeta",     \'\\u03b6\'), // greek small letter zeta, U+03B6 ISOgrk3\n    new CharacterReference ("eta",      \'\\u03b7\'), // greek small letter eta, U+03B7 ISOgrk3\n    new CharacterReference ("theta",    \'\\u03b8\'), // greek small letter theta, U+03B8 ISOgrk3\n    new CharacterReference ("iota",     \'\\u03b9\'), // greek small letter iota, U+03B9 ISOgrk3\n    new CharacterReference ("kappa",    \'\\u03ba\'), // greek small letter kappa, U+03BA ISOgrk3\n    new CharacterReference ("lambda",   \'\\u03bb\'), // greek small letter lambda, U+03BB ISOgrk3\n    new CharacterReference ("mu",       \'\\u03bc\'), // greek small letter mu, U+03BC ISOgrk3\n    new CharacterReference ("nu",       \'\\u03bd\'), // greek small letter nu, U+03BD ISOgrk3\n    new CharacterReference ("xi",       \'\\u03be\'), // greek small letter xi, U+03BE ISOgrk3\n    new CharacterReference ("omicron",  \'\\u03bf\'), // greek small letter omicron, U+03BF NEW\n    new CharacterReference ("pi",       \'\\u03c0\'), // greek small letter pi, U+03C0 ISOgrk3\n    new CharacterReference ("rho",      \'\\u03c1\'), // greek small letter rho, U+03C1 ISOgrk3\n    new CharacterReference ("sigmaf",   \'\\u03c2\'), // greek small letter final sigma, U+03C2 ISOgrk3\n    new CharacterReference ("sigma",    \'\\u03c3\'), // greek small letter sigma, U+03C3 ISOgrk3\n    new CharacterReference ("tau",      \'\\u03c4\'), // greek small letter tau, U+03C4 ISOgrk3\n    new CharacterReference ("upsilon",  \'\\u03c5\'), // greek small letter upsilon, U+03C5 ISOgrk3\n    new CharacterReference ("phi",      \'\\u03c6\'), // greek small letter phi, U+03C6 ISOgrk3\n    new CharacterReference ("chi",      \'\\u03c7\'), // greek small letter chi, U+03C7 ISOgrk3\n    new CharacterReference ("psi",      \'\\u03c8\'), // greek small letter psi, U+03C8 ISOgrk3\n    new CharacterReference ("omega",    \'\\u03c9\'), // greek small letter omega, U+03C9 ISOgrk3\n    new CharacterReference ("thetasym", \'\\u03d1\'), // greek small letter theta symbol, U+03D1 NEW\n    new CharacterReference ("upsih",    \'\\u03d2\'), // greek upsilon with hook symbol, U+03D2 NEW\n    new CharacterReference ("piv",      \'\\u03d6\'), // greek pi symbol, U+03D6 ISOgrk3\n    // General Punctuation\n    new CharacterReference ("bull",     \'\\u2022\'), // bullet = black small circle, U+2022 ISOpub\n    // bullet is NOT the same as bullet operator, U+2219\n    new CharacterReference ("hellip",   \'\\u2026\'), // horizontal ellipsis = three dot leader, U+2026 ISOpub\n    new CharacterReference ("prime",    \'\\u2032\'), // prime = minutes = feet, U+2032 ISOtech\n    new CharacterReference ("Prime",    \'\\u2033\'), // double prime = seconds = inches, U+2033 ISOtech\n    new CharacterReference ("oline",    \'\\u203e\'), // overline = spacing overscore, U+203E NEW\n    new CharacterReference ("frasl",    \'\\u2044\'), // fraction slash, U+2044 NEW\n    // Letterlike Symbols\n    new CharacterReference ("weierp",   \'\\u2118\'), // script capital P = power set = Weierstrass p, U+2118 ISOamso\n    new CharacterReference ("image",    \'\\u2111\'), // blackletter capital I = imaginary part, U+2111 ISOamso\n    new CharacterReference ("real",     \'\\u211c\'), // blackletter capital R = real part symbol, U+211C ISOamso\n    new CharacterReference ("trade",    \'\\u2122\'), // trade mark sign, U+2122 ISOnum\n    new CharacterReference ("alefsym",  \'\\u2135\'), // alef symbol = first transfinite cardinal, U+2135 NEW\n    // alef symbol is NOT the same as hebrew letter alef,\n    // U+05D0 although the same glyph could be used to depict both characters\n    // Arrows\n    new CharacterReference ("larr",     \'\\u2190\'), // leftwards arrow, U+2190 ISOnum\n    new CharacterReference ("uarr",     \'\\u2191\'), // upwards arrow, U+2191 ISOnum\n    new CharacterReference ("rarr",     \'\\u2192\'), // rightwards arrow, U+2192 ISOnum\n    new CharacterReference ("darr",     \'\\u2193\'), // downwards arrow, U+2193 ISOnum\n    new CharacterReference ("harr",     \'\\u2194\'), // left right arrow, U+2194 ISOamsa\n    new CharacterReference ("crarr",    \'\\u21b5\'), // downwards arrow with corner leftwards = carriage return, U+21B5 NEW\n    new CharacterReference ("lArr",     \'\\u21d0\'), // leftwards double arrow, U+21D0 ISOtech\n    // ISO 10646 does not say that lArr is the same as the \'is implied by\' arrow\n    // but also does not have any other character for that function. So ? lArr can\n    // be used for \'is implied by\' as ISOtech suggests\n    new CharacterReference ("uArr",     \'\\u21d1\'), // upwards double arrow, U+21D1 ISOamsa\n    new CharacterReference ("rArr",     \'\\u21d2\'), // rightwards double arrow, U+21D2 ISOtech\n    // ISO 10646 does not say this is the \'implies\' character but does not have\n    // another character with this function so ?\n    // rArr can be used for \'implies\' as ISOtech suggests\n    new CharacterReference ("dArr",     \'\\u21d3\'), // downwards double arrow, U+21D3 ISOamsa\n    new CharacterReference ("hArr",     \'\\u21d4\'), // left right double arrow, U+21D4 ISOamsa\n    // Mathematical Operators\n    new CharacterReference ("forall",   \'\\u2200\'), // for all, U+2200 ISOtech\n    new CharacterReference ("part",     \'\\u2202\'), // partial differential, U+2202 ISOtech\n    new CharacterReference ("exist",    \'\\u2203\'), // there exists, U+2203 ISOtech\n    new CharacterReference ("empty",    \'\\u2205\'), // empty set = null set = diameter, U+2205 ISOamso\n    new CharacterReference ("nabla",    \'\\u2207\'), // nabla = backward difference, U+2207 ISOtech\n    new CharacterReference ("isin",     \'\\u2208\'), // element of, U+2208 ISOtech\n    new CharacterReference ("notin",    \'\\u2209\'), // not an element of, U+2209 ISOtech\n    new CharacterReference ("ni",       \'\\u220b\'), // contains as member, U+220B ISOtech\n    // should there be a more memorable name than \'ni\'?\n    new CharacterReference ("prod",     \'\\u220f\'), // n-ary product = product sign, U+220F ISOamsb\n    // prod is NOT the same character as U+03A0 \'greek capital letter pi\' though\n    // the same glyph might be used for both\n    new CharacterReference ("sum",      \'\\u2211\'), // n-ary sumation, U+2211 ISOamsb\n    // sum is NOT the same character as U+03A3 \'greek capital letter sigma\'\n    // though the same glyph might be used for both\n    new CharacterReference ("minus",    \'\\u2212\'), // minus sign, U+2212 ISOtech\n    new CharacterReference ("lowast",   \'\\u2217\'), // asterisk operator, U+2217 ISOtech\n    new CharacterReference ("radic",    \'\\u221a\'), // square root = radical sign, U+221A ISOtech\n    new CharacterReference ("prop",     \'\\u221d\'), // proportional to, U+221D ISOtech\n    new CharacterReference ("infin",    \'\\u221e\'), // infinity, U+221E ISOtech\n    new CharacterReference ("ang",      \'\\u2220\'), // angle, U+2220 ISOamso\n    new CharacterReference ("and",      \'\\u2227\'), // logical and = wedge, U+2227 ISOtech\n    new CharacterReference ("or",       \'\\u2228\'), // logical or = vee, U+2228 ISOtech\n    new CharacterReference ("cap",      \'\\u2229\'), // intersection = cap, U+2229 ISOtech\n    new CharacterReference ("cup",      \'\\u222a\'), // union = cup, U+222A ISOtech\n    new CharacterReference ("int",      \'\\u222b\'), // integral, U+222B ISOtech\n    new CharacterReference ("there4",   \'\\u2234\'), // therefore, U+2234 ISOtech\n    new CharacterReference ("sim",      \'\\u223c\'), // tilde operator = varies with = similar to, U+223C ISOtech\n    // tilde operator is NOT the same character as the tilde, U+007E,\n    // although the same glyph might be used to represent both\n    new CharacterReference ("cong",     \'\\u2245\'), // approximately equal to, U+2245 ISOtech\n    new CharacterReference ("asymp",    \'\\u2248\'), // almost equal to = asymptotic to, U+2248 ISOamsr\n    new CharacterReference ("ne",       \'\\u2260\'), // not equal to, U+2260 ISOtech\n    new CharacterReference ("equiv",    \'\\u2261\'), // identical to, U+2261 ISOtech\n    new CharacterReference ("le",       \'\\u2264\'), // less-than or equal to, U+2264 ISOtech\n    new CharacterReference ("ge",       \'\\u2265\'), // greater-than or equal to, U+2265 ISOtech\n    new CharacterReference ("sub",      \'\\u2282\'), // subset of, U+2282 ISOtech\n    new CharacterReference ("sup",      \'\\u2283\'), // superset of, U+2283 ISOtech\n    // note that nsup, \'not a superset of, U+2283\' is not covered by the Symbol\n    // font encoding and is not included. Should it be, for symmetry?\n    // It is in ISOamsn\n    new CharacterReference ("nsub",     \'\\u2284\'), // not a subset of, U+2284 ISOamsn\n    new CharacterReference ("sube",     \'\\u2286\'), // subset of or equal to, U+2286 ISOtech\n    new CharacterReference ("supe",     \'\\u2287\'), // superset of or equal to, U+2287 ISOtech\n    new CharacterReference ("oplus",    \'\\u2295\'), // circled plus = direct sum, U+2295 ISOamsb\n    new CharacterReference ("otimes",   \'\\u2297\'), // circled times = vector product, U+2297 ISOamsb\n    new CharacterReference ("perp",     \'\\u22a5\'), // up tack = orthogonal to = perpendicular, U+22A5 ISOtech\n    new CharacterReference ("sdot",     \'\\u22c5\'), // dot operator, U+22C5 ISOamsb\n    // dot operator is NOT the same character as U+00B7 middle dot\n    // Miscellaneous Technical\n    new CharacterReference ("lceil",    \'\\u2308\'), // left ceiling = apl upstile, U+2308 ISOamsc\n    new CharacterReference ("rceil",    \'\\u2309\'), // right ceiling, U+2309 ISOamsc\n    new CharacterReference ("lfloor",   \'\\u230a\'), // left floor = apl downstile, U+230A ISOamsc\n    new CharacterReference ("rfloor",   \'\\u230b\'), // right floor, U+230B ISOamsc\n    new CharacterReference ("lang",     \'\\u2329\'), // left-pointing angle bracket = bra, U+2329 ISOtech\n    // lang is NOT the same character as U+003C \'less than\'\n    // or U+2039 \'single left-pointing angle quotation mark\'\n    new CharacterReference ("rang",     \'\\u232a\'), // right-pointing angle bracket = ket, U+232A ISOtech\n    // rang is NOT the same character as U+003E \'greater than\'\n    // or U+203A \'single right-pointing angle quotation mark\'\n    // Geometric Shapes\n    new CharacterReference ("loz",      \'\\u25ca\'), // lozenge, U+25CA ISOpub\n    // Miscellaneous Symbols\n    new CharacterReference ("spades",   \'\\u2660\'), // black spade suit, U+2660 ISOpub\n    // black here seems to mean filled as opposed to hollow\n    new CharacterReference ("clubs",    \'\\u2663\'), // black club suit = shamrock, U+2663 ISOpub\n    new CharacterReference ("hearts",   \'\\u2665\'), // black heart suit = valentine, U+2665 ISOpub\n    new CharacterReference ("diams",    \'\\u2666\'), // black diamond suit, U+2666 ISOpub\n    // Special characters for HTML\n    // Character entity set. Typical invocation:\n    // <!ENTITY % HTMLspecial PUBLIC\n    // "-//W3C//ENTITIES Special//EN//HTML">\n    // %HTMLspecial;\n    // Portions (c) International Organization for Standardization 1986:\n    // Permission to copy in any form is granted for use with\n    // conforming SGML systems and applications as defined in\n    // ISO 8879, provided this notice is included in all copies.\n    // Relevant ISO entity set is given unless names are newly introduced.\n    // New names (i.e., not in ISO 8879 list) do not clash with any\n    // existing ISO 8879 entity names. ISO 10646 character numbers\n    // are given for each character, in hex. CDATA values are decimal\n    // conversions of the ISO 10646 values and refer to the document\n    // character set. Names are ISO 10646 names.\n    // C0 Controls and Basic Latin\n    new CharacterReference ("quot",     \'\\u0022\'), // quotation mark = APL quote, U+0022 ISOnum\n    new CharacterReference ("amp",      \'\\u0026\'), // ampersand, U+0026 ISOnum\n    new CharacterReference ("lt",       \'\\u003c\'), // less-than sign, U+003C ISOnum\n    new CharacterReference ("gt",       \'\\u003e\'), // greater-than sign, U+003E ISOnum\n    // Latin Extended-A\n    new CharacterReference ("OElig",    \'\\u0152\'), // latin capital ligature OE, U+0152 ISOlat2\n    new CharacterReference ("oelig",    \'\\u0153\'), // latin small ligature oe, U+0153 ISOlat2\n    // ligature is a misnomer, this is a separate character in some languages\n    new CharacterReference ("Scaron",   \'\\u0160\'), // latin capital letter S with caron, U+0160 ISOlat2\n    new CharacterReference ("scaron",   \'\\u0161\'), // latin small letter s with caron, U+0161 ISOlat2\n    new CharacterReference ("Yuml",     \'\\u0178\'), // latin capital letter Y with diaeresis, U+0178 ISOlat2\n    // Spacing Modifier Letters\n    new CharacterReference ("circ",     \'\\u02c6\'), // modifier letter circumflex accent, U+02C6 ISOpub\n    new CharacterReference ("tilde",    \'\\u02dc\'), // small tilde, U+02DC ISOdia\n    // General Punctuation\n    new CharacterReference ("ensp",     \'\\u2002\'), // en space, U+2002 ISOpub\n    new CharacterReference ("emsp",     \'\\u2003\'), // em space, U+2003 ISOpub\n    new CharacterReference ("thinsp",   \'\\u2009\'), // thin space, U+2009 ISOpub\n    new CharacterReference ("zwnj",     \'\\u200c\'), // zero width non-joiner, U+200C NEW RFC 2070\n    new CharacterReference ("zwj",      \'\\u200d\'), // zero width joiner, U+200D NEW RFC 2070\n    new CharacterReference ("lrm",      \'\\u200e\'), // left-to-right mark, U+200E NEW RFC 2070\n    new CharacterReference ("rlm",      \'\\u200f\'), // right-to-left mark, U+200F NEW RFC 2070\n    new CharacterReference ("ndash",    \'\\u2013\'), // en dash, U+2013 ISOpub\n    new CharacterReference ("mdash",    \'\\u2014\'), // em dash, U+2014 ISOpub\n    new CharacterReference ("lsquo",    \'\\u2018\'), // left single quotation mark, U+2018 ISOnum\n    new CharacterReference ("rsquo",    \'\\u2019\'), // right single quotation mark, U+2019 ISOnum\n    new CharacterReference ("sbquo",    \'\\u201a\'), // single low-9 quotation mark, U+201A NEW\n    new CharacterReference ("ldquo",    \'\\u201c\'), // left double quotation mark, U+201C ISOnum\n    new CharacterReference ("rdquo",    \'\\u201d\'), // right double quotation mark, U+201D ISOnum\n    new CharacterReference ("bdquo",    \'\\u201e\'), // double low-9 quotation mark, U+201E NEW\n    new CharacterReference ("dagger",   \'\\u2020\'), // dagger, U+2020 ISOpub\n    new CharacterReference ("Dagger",   \'\\u2021\'), // double dagger, U+2021 ISOpub\n    new CharacterReference ("permil",   \'\\u2030\'), // per mille sign, U+2030 ISOtech\n    new CharacterReference ("lsaquo",   \'\\u2039\'), // single left-pointing angle quotation mark, U+2039 ISO proposed\n    // lsaquo is proposed but not yet ISO standardized\n    new CharacterReference ("rsaquo",   \'\\u203a\'), // single right-pointing angle quotation mark, U+203A ISO proposed\n    // rsaquo is proposed but not yet ISO standardized\n    new CharacterReference ("euro",     \'\\u20ac\'), // euro sign, U+20AC NEW\n    };\n\n  /**\n   * The dividing point between a simple table lookup and a binary search.\n   * Characters below the break point are stored in a sparse array allowing\n   * direct index lookup.\n   */\n  protected static final int BREAKPOINT = 0x100;\n\n  /**\n   * List of references sorted by character.\n   * The first part of this array, up to <code>BREAKPOINT</code> is stored\n   * in a direct translational table, indexing into the table with a character\n   * yields the reference. The second part is dense and sorted by character,\n   * suitable for binary lookup.\n   */\n  protected static final CharacterReference[] mCharacterList;\n\n  static\n  {\n    int index;\n    CharacterReference item;\n    int character;\n\n    // count below the break point\n    index = 0;\n    for (int i = 0; i < mCharacterReferences.length; i++)\n      if (mCharacterReferences[i].getCharacter () < BREAKPOINT)\n        index++;\n    // allocate enough for the linear table and remainder\n    mCharacterList = new CharacterReference[BREAKPOINT + mCharacterReferences.length - index];\n    index = BREAKPOINT;\n    for (int i = 0; i < mCharacterReferences.length; i++)\n    {\n      item = mCharacterReferences[i];\n      character = mCharacterReferences[i].getCharacter ();\n      if (character < BREAKPOINT)\n        mCharacterList[character] = item;\n      else\n      {\n        // use a linear search and insertion sort, done only once\n        int x = BREAKPOINT;\n        while (x < index)\n          if (mCharacterList[x].getCharacter () > character)\n            break;\n          else\n            x++;\n        int y = index - 1;\n        while (y >= x)\n        {\n          mCharacterList[y + 1] = mCharacterList[y];\n          y--;\n        }\n        mCharacterList[x] = item;\n        index++;\n      }\n    }\n    // reorder the original array into kernel order\n    java.util.Arrays.sort(mCharacterReferences);\n  }\n\n  /**\n   * Private constructor.\n   * This class is fully static and thread safe.\n   */\n  private Translate ()\n  {\n  }\n\n  /**\n   * Binary search for a reference.\n   * @param array The array of <code>CharacterReference</code> objects.\n   * @param ref The character to search for.\n   * @param lo The lower index within which to look.\n   * @param hi The upper index within which to look.\n   * @return The index at which reference was found or is to be inserted.\n   */\n  protected static int lookup (CharacterReference[] array, char ref, int lo, int hi) {\n    int num;\n    int mid;\n    int half;\n    int result;\n    int ret;\n\n    ret = -1;\n\n    num = (hi - lo) + 1;\n    while ((-1 == ret) && (lo <= hi))\n    {\n      half = num / 2;\n      mid = lo + ((0 != (num & 1)) ? half : half - 1);\n      result = ref - array[mid].getCharacter ();\n      if (0 == result)\n        ret = mid;\n      else if (0 > result)\n      {\n        hi = mid - 1;\n        num = ((0 != (num & 1)) ? half : half - 1);\n      }\n      else\n      {\n        lo = mid + 1;\n        num = half;\n      }\n    }\n    if (-1 == ret)\n      ret = lo;\n\n    return (ret);\n  }\n\n  /**\n   * Look up a reference by character.\n   * Use a combination of direct table lookup and binary search to find\n   * the reference corresponding to the character.\n   * @param character The character to be looked up.\n   * @return The entity reference for that character or <code>null</code>.\n   */\n  public static CharacterReference lookup (char character)\n  {\n    int index;\n    CharacterReference ret;\n\n    if (character < BREAKPOINT)\n      ret = mCharacterList[character];\n    else\n    {\n      index = lookup (mCharacterList, character, BREAKPOINT, mCharacterList.length - 1);\n      if (index < mCharacterList.length)\n      {\n        ret = mCharacterList[index];\n        if (character != ret.getCharacter ())\n          ret = null;\n      }\n      else\n        ret = null;\n    }\n\n    return (ret);\n  }\n\n  /**\n   * Look up a reference by kernel.\n   * Use a binary search on the ordered list of known references.\n   * Since the binary search returns the position at which a new item should\n   * be inserted, we check the references earlier in the list if there is\n   * a failure.\n   * @param key A character reference with the kernel set to the string\n   * to be found. It need not be truncated at the exact end of the reference.\n   */\n  protected static CharacterReference lookup (CharacterReference key)\n  {\n    String string;\n    int index;\n    String kernel;\n    char character;\n    CharacterReference test;\n    CharacterReference ret;\n\n    // Care should be taken here because some entity references are\n    // prefixes of others, i.e.:\n    // \\u2209[notin] \\u00ac[not]\n    // \\u00ba[ordm] \\u2228[or]\n    // \\u03d6[piv] \\u03c0[pi]\n    // \\u00b3[sup3] \\u2283[sup]\n    ret = null;\n    index = java.util.Arrays.binarySearch(mCharacterReferences, key);\n    string = key.getKernel ();\n    if (index < mCharacterReferences.length && index >= 0)\n    {\n      ret = mCharacterReferences[index];\n      kernel = ret.getKernel ();\n      if (!string.regionMatches (\n          0,\n          kernel,\n          0,\n          kernel.length ()))\n      {   // not exact, check references starting with same character\n        // to see if a subset matches\n        ret = null;\n      }\n    }\n    if (null == ret)\n    {\n      character = string.charAt (0);\n      while (--index >= 0)\n      {\n        test = mCharacterReferences[index];\n        kernel = test.getKernel ();\n        if (character == kernel.charAt (0))\n        {\n          if (string.regionMatches (\n              0,\n              kernel,\n              0,\n              kernel.length ()))\n          {\n            ret = test;\n            break;\n          }\n        }\n        else\n          break;\n      }\n    }\n\n    return (ret);\n  }\n\n  /**\n   * Look up a reference by kernel.\n   * Use a binary search on the ordered list of known references.\n   * <em>This is not very efficient, use {@link org.htmlparser.util.Translate#lookup(org.htmlparser.util.CharacterReference) lookup(CharacterReference)}\n   * instead.</em>\n   * @param kernel The string to lookup, i.e. "amp".\n   * @param start The starting point in the string of the kernel.\n   * @param end The ending point in the string of the kernel.\n   * This should be the index of the semicolon if it exists, or failing that,\n   * at least an index past the last character of the kernel.\n   * @return The reference that matches the given string, or <code>null</code>\n   * if it wasn\'t found.\n   */\n  public static CharacterReference lookup (String kernel, int start, int end)\n  {\n    CharacterReferenceEx probe;\n\n    probe = new CharacterReferenceEx ();\n    probe.setKernel (kernel);\n    probe.setStart (start);\n    probe.setEnd (end);\n\n    return (lookup (probe));\n  }\n\n  /**\n   * Convert a reference to a unicode character.\n   * Convert a single numeric character reference or character entity reference\n   * to a unicode character.\n   * @param string The string to convert. Of the form &xxxx; or &amp;#xxxx; with\n   * or without the leading ampersand or trailing semi-colon.\n   * @param start The starting pooint in the string to look for a character reference.\n   * @param end The ending point in the string to stop looking for a character reference.\n   * @return The converted character or \'\x00\' (zero) if the string is an\n   * invalid reference.\n   * @deprecated Use {@link #decode(String) decode}.\n   */\n  public static char convertToChar (String string, int start, int end)\n  {\n    return (decode (string.substring (start, end)).charAt (0));\n  }\n\n  /**\n   * Convert a reference to a unicode character.\n   * Convert a single numeric character reference or character entity reference\n   * to a unicode character.\n   * @param string The string to convert. Of the form &xxxx; or &amp;#xxxx; with\n   * or without the leading ampersand or trailing semi-colon.\n   * @return The converted character or \'\x00\' (zero) if the string is an\n   * invalid reference.\n   * @deprecated Use {@link #decode(String) decode}.\n   */\n  public static char convertToChar (String string)\n  {\n    return (decode (string).charAt (0));\n  }\n\n  /**\n   * Decode a string containing references.\n   * Change all numeric character reference and character entity references\n   * to unicode characters.\n   * @param string The string to translate.\n   */\n  public static String decode (String string)\n  {\n    CharacterReferenceEx key;\n    int amp;\n    int index;\n    int length;\n    StringBuffer buffer;\n    char character;\n    int number;\n    int radix;\n    int i;\n    int semi;\n    boolean done;\n    CharacterReference item;\n    String ret;\n\n    if (-1 == (amp = string.indexOf (\'&\')))\n      ret = string;\n    else\n    {\n      key = null;\n      index = 0;\n      length = string.length ();\n      buffer = new StringBuffer (length);\n      do\n      {\n        // equivalent to buffer.append (string.substring (index, amp));\n        // but without the allocation of a new String\n        while (index < amp)\n          buffer.append (string.charAt (index++));\n\n        index++;\n        if (index < length)\n        {\n          character = string.charAt (index);\n          if (\'#\' == character)\n          {\n            // numeric character reference\n            index++;\n            number = 0;\n            radix = 0;\n            i = index;\n            done = false;\n            while ((i < length) && !done)\n            {\n              character = string.charAt (i);\n              switch (character)\n              {\n                case \'0\':\n                case \'1\':\n                case \'2\':\n                case \'3\':\n                case \'4\':\n                case \'5\':\n                case \'6\':\n                case \'7\':\n                case \'8\':\n                case \'9\':\n                  if (0 == radix)\n                    radix = 10;\n                  number = number * radix + (character - \'0\');\n                  break;\n                case \'A\':\n                case \'B\':\n                case \'C\':\n                case \'D\':\n                case \'E\':\n                case \'F\':\n                  if (16 == radix)\n                    number = number * radix + (character - \'A\' + 10);\n                  else\n                    done = true;\n                  break;\n                case \'a\':\n                case \'b\':\n                case \'c\':\n                case \'d\':\n                case \'e\':\n                case \'f\':\n                  if (16 == radix)\n                    number = number * radix + (character - \'a\' + 10);\n                  else\n                    done = true;\n                  break;\n                case \'x\':\n                case \'X\':\n                  if (0 == radix)\n                    radix = 16;\n                  else\n                    done = true;\n                  break;\n                case \';\':\n                  done = true;\n                  i++;\n                  break;\n                default:\n                  done = true;\n                  break;\n              }\n              if (!done)\n                i++;\n            }\n            if (0 != number)\n            {\n              buffer.append ((char)number);\n              index = i;\n              amp = index;\n            }\n\n          }\n          else if (Character.isLetter (character)) // really can\'t start with a digit eh...\n          {\n            // character entity reference\n            i = index + 1;\n            done = false;\n            semi = length;\n            while ((i < length) && !done)\n            {\n              character = string.charAt (i);\n              if (\';\' == character)\n              {\n                done = true;\n                semi = i;\n                i++;\n              }\n              else if (Character.isLetterOrDigit (character))\n                i++;\n              else\n              {\n                done = true;\n                semi = i;\n              }\n            }\n            // new CharacterReference (string.substring (index, semi), 0);\n            if (null == key)\n              key = new CharacterReferenceEx ();\n            key.setKernel (string);\n            key.setStart (index);\n            key.setEnd (semi);\n            item = lookup (key);\n            if (null != item)\n            {\n              buffer.append ((char)item.getCharacter ());\n              index += item.getKernel ().length ();\n              if ((index < length) && (\';\' == string.charAt (index)))\n                index++;\n              amp = index;\n            }\n          }\n          else\n          {\n            // need do nothing here, the ampersand will be consumed below\n          }\n        }\n        // gather up unconsumed characters\n        while (amp < index)\n          buffer.append (string.charAt (amp++));\n      }\n      while ((index < length) && (-1 != (amp = string.indexOf (\'&\', index))));\n      // equivalent to buffer.append (string.substring (index));\n      // but without the allocation of a new String\n      while (index < length)\n        buffer.append (string.charAt (index++));\n      ret = buffer.toString ();\n    }\n\n    return (ret);\n  }\n\n  /**\n   * Decode the characters in a string buffer containing references.\n   * Change all numeric character reference and character entity references\n   * to unicode characters.\n   * @param buffer The StringBuffer containing references.\n   * @return The decoded string.\n   */\n  public static String decode (StringBuffer buffer)\n  {\n    return decode (buffer.toString());\n  }\n\n  /**\n   * Decode a stream containing references.\n   * Change all numeric character reference and character entity references\n   * to unicode characters. If <code>DECODE_LINE_BY_LINE</code> is true,\n   * the input stream is broken up into lines, terminated by either\n   * carriage return or newline, in order to reduce the latency and maximum\n   * buffering memory size required.\n   * @param in The stream to translate. It is assumed that the input\n   * stream is encoded with ISO-8859-1 since the table of character\n   * entity references in this class applies only to ISO-8859-1.\n   * @param out The stream to write the decoded stream to.\n   */\n  public static void decode (InputStream in, PrintStream out)\n  {\n    Reader reader;\n    StringBuffer buffer;\n    int character;\n    String string;\n    boolean newlines;\n\n    try\n    {\n      try\n      {\n        reader = new BufferedReader (new InputStreamReader (in, "ISO-8859-1"));\n      }\n      catch (UnsupportedEncodingException use)\n      {\n        // yeah, like this will happen; OK, assume the default is ISO-8859-1\n        reader = new BufferedReader (new InputStreamReader (in));\n      }\n      buffer = new StringBuffer (1024);\n      newlines = false;\n      if (DECODE_LINE_BY_LINE)\n        while (-1 != (character = reader.read ()))\n        {\n          if ((\'\\r\' == character) || (\'\\n\' == character))\n          {\n            if (!newlines)\n            {\n              string = decode (buffer.toString ());\n              out.print (string);\n              buffer.setLength (0);\n              newlines = true;\n            }\n            buffer.append ((char)character);\n          }\n          else\n          {\n            if (newlines)\n            {\n              out.print (buffer.toString ());\n              buffer.setLength (0);\n              newlines = false;\n            }\n            buffer.append ((char)character);\n          }\n        }\n      else\n        while (-1 != (character = reader.read ()))\n          buffer.append ((char)character);\n      if (0 != buffer.length ())\n      {\n        if (newlines)\n          out.print (buffer.toString ());\n        else\n        {\n          string = decode (buffer.toString ());\n          out.print (string);\n        }\n      }\n    }\n    catch (IOException ioe)\n    {\n      out.println ();\n      out.println (ioe.getMessage ());\n    }\n    finally\n    {\n      out.flush ();\n    }\n  }\n\n  /**\n   * Convert a character to a numeric character reference.\n   * Convert a unicode character to a numeric character reference of\n   * the form &amp;#xxxx;.\n   * @param character The character to convert.\n   * @return The converted character.\n   * @deprecated Use {@link #encode(int) encode}.\n   */\n  public static String convertToString (int character)\n  {\n    return (encode (character));\n  }\n\n  /**\n   * Convert a character to a numeric character reference.\n   * Convert a unicode character to a numeric character reference of\n   * the form &amp;#xxxx;.\n   * @param character The character to convert.\n   * @return The converted character.\n   */\n  public static String encode (int character)\n  {\n    StringBuffer ret;\n\n    ret = new StringBuffer (13); /* &#2147483647; */\n    ret.append ("&#");\n    if (ENCODE_HEXADECIMAL)\n    {\n      ret.append ("x");\n      ret.append (Integer.toHexString (character));\n    }\n    else\n      ret.append (character);\n    ret.append (\';\');\n\n    return (ret.toString ());\n  }\n\n  /**\n   * Encode a string to use references.\n   * Change all characters that are not ISO-8859-1 to their numeric character\n   * reference or character entity reference.\n   * @param string The string to translate.\n   * @return The encoded string.\n   */\n  public static String encode (String string)\n  {\n    int length;\n    char c;\n    CharacterReference candidate;\n    StringBuffer ret;\n    ret = new StringBuffer (string.length () * 6);\n    length  = string.length ();\n    for (int i = 0; i < length; i++)\n    {\n      c = string.charAt (i);\n      candidate = lookup (c);\n      if (null != candidate)\n      {\n        ret.append (\'&\');\n        ret.append (candidate.getKernel ());\n        ret.append (\';\');\n      }\n      else if (!(c < 0x007F))\n      {\n        ret.append ("&#");\n        if (ENCODE_HEXADECIMAL)\n        {\n          ret.append ("x");\n          ret.append (Integer.toHexString (c));\n        }\n        else\n          ret.append ((int)c);\n        ret.append (\';\');\n      }\n      else\n        ret.append (c);\n    }\n\n    return (ret.toString ());\n  }\n\n  /**\n   * Encode a stream to use references.\n   * Change all characters that are not ISO-8859-1 to their numeric character\n   * reference or character entity reference.\n   * @param in The stream to translate. It is assumed that the input\n   * stream is encoded with ISO-8859-1 since the table of character\n   * entity references in this class applies only to ISO-8859-1.\n   * @param out The stream to write the decoded stream to.\n   */\n  public static void encode (InputStream in, PrintStream out)\n  {\n    Reader reader;\n    char c;\n    int index;\n    CharacterReference candidate;\n    PrintWriter output;\n\n    try\n    {\n      reader = new BufferedReader (new InputStreamReader (in, "ISO-8859-1"));\n      output = new PrintWriter (new BufferedWriter (new OutputStreamWriter (out, "ISO-8859-1")));\n    }\n    catch (UnsupportedEncodingException use)\n    {\n      // yeah, like this will happen; OK, assume default is ISO-8859-1\n      reader = new BufferedReader (new InputStreamReader (in));\n      output = new PrintWriter (new BufferedWriter (new OutputStreamWriter (out)));\n    }\n    try\n    {\n      while (-1 != (index = reader.read ()))\n      {\n        c = (char)index;\n        candidate = lookup (c);\n        if (null != candidate)\n        {\n          output.print (\'&\');\n          output.print (candidate.getKernel ());\n          output.print (\';\');\n        }\n        else if (!(c < 0x007F))\n        {\n          output.print ("&#");\n          if (ENCODE_HEXADECIMAL)\n          {\n            output.print ("x");\n            output.print (Integer.toHexString (c));\n          }\n          else\n            output.print ((int)c);\n          output.print (\';\');\n        }\n        else\n          output.print (c);\n      }\n    }\n    catch (IOException ioe)\n    {\n      output.println ();\n      output.println (ioe.getMessage ());\n    }\n    finally\n    {\n      output.flush ();\n    }\n  }\n\n  /**\n   * Numeric character reference and character entity reference to unicode codec.\n   * Translate the <code>System.in</code> input into an encoded or decoded\n   * stream and send the results to <code>System.out</code>.\n   * @param args If arg[0] is <code>-encode</code> perform an encoding on\n   * <code>System.in</code>, otherwise perform a decoding.\n   */\n  public static void main (String[] args)\n  {\n    boolean encode;\n\n    if (0 < args.length && args[0].equalsIgnoreCase ("-encode"))\n      encode = true;\n    else\n      encode = false;\n    if (encode)\n      encode (System.in, System.out);\n    else\n      decode (System.in, System.out);\n  }\n}\n', 'message': "Merge remote-tracking branch 'google/master'\n", 'author_name': 'Keith Fischer', 'lang': 'java'}