    protected List<Rule> parsePattern() {
        DateFormatSymbols symbols = new DateFormatSymbols(mLocale);
        List<Rule> rules = new ArrayList<Rule>();
        String[] ERAs = symbols.getEras();
        String[] months = symbols.getMonths();
        String[] shortMonths = symbols.getShortMonths();
        String[] weekdays = symbols.getWeekdays();
        String[] shortWeekdays = symbols.getShortWeekdays();
        String[] AmPmStrings = symbols.getAmPmStrings();
        int length = mPattern.length();
        int[] indexRef = new int[1];
        for (int i = 0; i < length; i++) {
            indexRef[0] = i;
            String token = parseToken(mPattern, indexRef);
            i = indexRef[0];
            int tokenLen = token.length();
            if (tokenLen == 0) {
                break;
            }
            Rule rule;
            char c = token.charAt(0);
            switch (c) {
            case 'G':
                rule = new TextField(Calendar.ERA, ERAs);
                break;
            case 'y':
                if (tokenLen == 2) {
                    rule = TwoDigitYearField.INSTANCE;
                } else {
                    rule = selectNumberRule(Calendar.YEAR, tokenLen < 4 ? 4 : tokenLen);
                }
                break;
            case 'M':
                if (tokenLen >= 4) {
                    rule = new TextField(Calendar.MONTH, months);
                } else if (tokenLen == 3) {
                    rule = new TextField(Calendar.MONTH, shortMonths);
                } else if (tokenLen == 2) {
                    rule = TwoDigitMonthField.INSTANCE;
                } else {
                    rule = UnpaddedMonthField.INSTANCE;
                }
                break;
            case 'd':
                rule = selectNumberRule(Calendar.DAY_OF_MONTH, tokenLen);
                break;
            case 'h':
                rule = new TwelveHourField(selectNumberRule(Calendar.HOUR, tokenLen));
                break;
            case 'H':
                rule = selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen);
                break;
            case 'm':
                rule = selectNumberRule(Calendar.MINUTE, tokenLen);
                break;
            case 's':
                rule = selectNumberRule(Calendar.SECOND, tokenLen);
                break;
            case 'S':
                rule = selectNumberRule(Calendar.MILLISECOND, tokenLen);
                break;
            case 'E':
                rule = new TextField(Calendar.DAY_OF_WEEK, tokenLen < 4 ? shortWeekdays : weekdays);
                break;
            case 'D':
                rule = selectNumberRule(Calendar.DAY_OF_YEAR, tokenLen);
                break;
            case 'F':
                rule = selectNumberRule(Calendar.DAY_OF_WEEK_IN_MONTH, tokenLen);
                break;
            case 'w':
                rule = selectNumberRule(Calendar.WEEK_OF_YEAR, tokenLen);
                break;
            case 'W':
                rule = selectNumberRule(Calendar.WEEK_OF_MONTH, tokenLen);
                break;
            case 'a':
                rule = new TextField(Calendar.AM_PM, AmPmStrings);
                break;
            case 'k':
                rule = new TwentyFourHourField(selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen));
                break;
            case 'K':
                rule = selectNumberRule(Calendar.HOUR, tokenLen);
                break;
            case 'z':
                if (tokenLen >= 4) {
                    rule = new TimeZoneNameRule(mTimeZone, mLocale, TimeZone.LONG);
                } else {
                    rule = new TimeZoneNameRule(mTimeZone, mLocale, TimeZone.SHORT);
                }
                break;
            case 'Z':
                if (tokenLen == 1) {
                    rule = TimeZoneNumberRule.INSTANCE_NO_COLON;
                } else {
                    rule = TimeZoneNumberRule.INSTANCE_COLON;
                }
                break;
            case '\'':
                String sub = token.substring(1);
                if (sub.length() == 1) {
                    rule = new CharacterLiteral(sub.charAt(0));
                } else {
                    rule = new StringLiteral(sub);
                }
                break;
            default:
                throw new IllegalArgumentException("Illegal pattern component: " + token);
            }
            rules.add(rule);
        }
        return rules;
    }


    protected List<Rule> parsePattern() {
        DateFormatSymbols symbols = new DateFormatSymbols(mLocale);
        List<Rule> rules = new ArrayList<Rule>();
        String[] ERAs = symbols.getEras();
        String[] months = symbols.getMonths();
        String[] shortMonths = symbols.getShortMonths();
        String[] weekdays = symbols.getWeekdays();
        String[] shortWeekdays = symbols.getShortWeekdays();
        String[] AmPmStrings = symbols.getAmPmStrings();
        int length = mPattern.length();
        int[] indexRef = new int[1];
        for (int i = 0; i < length; i++) {
            indexRef[0] = i;
            String token = parseToken(mPattern, indexRef);
            i = indexRef[0];
            int tokenLen = token.length();
            if (tokenLen == 0) {
                break;
            }
            Rule rule;
            char c = token.charAt(0);
            switch (c) {
            case 'G':
                rule = new TextField(Calendar.ERA, ERAs);
                break;
            case 'y':
                if (tokenLen >= 4) {
                    rule = selectNumberRule(Calendar.YEAR, tokenLen);
                } else {
                    rule = TwoDigitYearField.INSTANCE;
                }
                break;
            case 'M':
                if (tokenLen >= 4) {
                    rule = new TextField(Calendar.MONTH, months);
                } else if (tokenLen == 3) {
                    rule = new TextField(Calendar.MONTH, shortMonths);
                } else if (tokenLen == 2) {
                    rule = TwoDigitMonthField.INSTANCE;
                } else {
                    rule = UnpaddedMonthField.INSTANCE;
                }
                break;
            case 'd':
                rule = selectNumberRule(Calendar.DAY_OF_MONTH, tokenLen);
                break;
            case 'h':
                rule = new TwelveHourField(selectNumberRule(Calendar.HOUR, tokenLen));
                break;
            case 'H':
                rule = selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen);
                break;
            case 'm':
                rule = selectNumberRule(Calendar.MINUTE, tokenLen);
                break;
            case 's':
                rule = selectNumberRule(Calendar.SECOND, tokenLen);
                break;
            case 'S':
                rule = selectNumberRule(Calendar.MILLISECOND, tokenLen);
                break;
            case 'E':
                rule = new TextField(Calendar.DAY_OF_WEEK, tokenLen < 4 ? shortWeekdays : weekdays);
                break;
            case 'D':
                rule = selectNumberRule(Calendar.DAY_OF_YEAR, tokenLen);
                break;
            case 'F':
                rule = selectNumberRule(Calendar.DAY_OF_WEEK_IN_MONTH, tokenLen);
                break;
            case 'w':
                rule = selectNumberRule(Calendar.WEEK_OF_YEAR, tokenLen);
                break;
            case 'W':
                rule = selectNumberRule(Calendar.WEEK_OF_MONTH, tokenLen);
                break;
            case 'a':
                rule = new TextField(Calendar.AM_PM, AmPmStrings);
                break;
            case 'k':
                rule = new TwentyFourHourField(selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen));
                break;
            case 'K':
                rule = selectNumberRule(Calendar.HOUR, tokenLen);
                break;
            case 'z':
                if (tokenLen >= 4) {
                    rule = new TimeZoneNameRule(mTimeZone, mLocale, TimeZone.LONG);
                } else {
                    rule = new TimeZoneNameRule(mTimeZone, mLocale, TimeZone.SHORT);
                }
                break;
            case 'Z':
                if (tokenLen == 1) {
                    rule = TimeZoneNumberRule.INSTANCE_NO_COLON;
                } else {
                    rule = TimeZoneNumberRule.INSTANCE_COLON;
                }
                break;
            case '\'':
                String sub = token.substring(1);
                if (sub.length() == 1) {
                    rule = new CharacterLiteral(sub.charAt(0));
                } else {
                    rule = new StringLiteral(sub);
                }
                break;
            default:
                throw new IllegalArgumentException("Illegal pattern component: " + token);
            }
            rules.add(rule);
        }
        return rules;
    }


    private void getNumUseInUseCfgNode(final Node cfgNode) {
      numUsesWithinCfgNode = 0;
      AbstractCfgNodeTraversalCallback gatherCb =
          new AbstractCfgNodeTraversalCallback() {
        @Override
        public void visit(NodeTraversal t, Node n, Node parent) {
          if (n.isName() && n.getString().equals(varName)) {
            if (parent.isAssign() && (parent.getFirstChild() == n)
                && isAssignChain(parent, cfgNode)) {
              return;
            } else {
              numUsesWithinCfgNode++;
            }
          }
        }
        private boolean isAssignChain(Node child, Node ancestor) {
          for (Node n = child; n != ancestor; n = n.getParent()) {
            if (!n.isAssign()) {
              return false;
            }
          }
          return true;
        }
      };
      NodeTraversal.traverse(compiler, cfgNode, gatherCb);
    }


    private void getNumUseInUseCfgNode(final Node cfgNode) {
      numUsesWithinCfgNode = 0;
      AbstractCfgNodeTraversalCallback gatherCb =
          new AbstractCfgNodeTraversalCallback() {
        @Override
        public void visit(NodeTraversal t, Node n, Node parent) {
          if (n.isName() && n.getString().equals(varName) &&
              !(parent.isAssign() &&
               (parent.getFirstChild() == n))) {
              numUsesWithinCfgNode++;
          }
        }
      };
      NodeTraversal.traverse(compiler, cfgNode, gatherCb);
    }


        void processResponseHeaders(Map<String, List<String>> resHeaders) {
            for (Map.Entry<String, List<String>> entry : resHeaders.entrySet()) {
                String name = entry.getKey();
                if (name == null)
                    continue;
                List<String> values = entry.getValue();
                if (name.equalsIgnoreCase("Set-Cookie")) {
                    for (String value : values) {
                        if (value == null)
                            continue;
                        TokenQueue cd = new TokenQueue(value);
                        String cookieName = cd.chompTo("=").trim();
                        String cookieVal = cd.consumeTo(";").trim();
                        if (cookieName.length() > 0)
                            cookie(cookieName, cookieVal);
                    }
                } else {
                    if (values.size() == 1)
                        header(name, values.get(0));
                    else if (values.size() > 1) {
                        StringBuilder accum = new StringBuilder();
                        for (int i = 0; i < values.size(); i++) {
                            final String val = values.get(i);
                            if (i != 0)
                                accum.append(", ");
                            accum.append(val);
                        }
                        header(name, accum.toString());
                    }
                }
            }
        }


        void processResponseHeaders(Map<String, List<String>> resHeaders) {
            for (Map.Entry<String, List<String>> entry : resHeaders.entrySet()) {
                String name = entry.getKey();
                if (name == null)
                    continue;
                List<String> values = entry.getValue();
                if (name.equalsIgnoreCase("Set-Cookie")) {
                    for (String value : values) {
                        if (value == null)
                            continue;
                        TokenQueue cd = new TokenQueue(value);
                        String cookieName = cd.chompTo("=").trim();
                        String cookieVal = cd.consumeTo(";").trim();
                        if (cookieName.length() > 0)
                            cookie(cookieName, cookieVal);
                    }
                } else {
                    if (!values.isEmpty())
                        header(name, values.get(0));
                }
            }
        }


  private Node parseContextTypeExpression(JsDocToken token) {
    if (token == JsDocToken.QMARK) {
      return newNode(Token.QMARK);
    } else {
      return parseBasicTypeExpression(token);
    }
  }


  private Node parseContextTypeExpression(JsDocToken token) {
          return parseTypeName(token);
  }


  public Date read(JsonReader in) throws IOException {
    if (in.peek() == JsonToken.NULL) {
      in.nextNull();
      return null;
    }
    Date date = deserializeToDate(in.nextString());
    if (dateType == Date.class) {
      return date;
    } else if (dateType == Timestamp.class) {
      return new Timestamp(date.getTime());
    } else if (dateType == java.sql.Date.class) {
      return new java.sql.Date(date.getTime());
    } else {
      throw new AssertionError();
    }
  }


  public Date read(JsonReader in) throws IOException {
    if (in.peek() != JsonToken.STRING) {
      throw new JsonParseException("The date should be a string value");
    }
    Date date = deserializeToDate(in.nextString());
    if (dateType == Date.class) {
      return date;
    } else if (dateType == Timestamp.class) {
      return new Timestamp(date.getTime());
    } else if (dateType == java.sql.Date.class) {
      return new java.sql.Date(date.getTime());
    } else {
      throw new AssertionError();
    }
  }


    private void annotateCalls(Node n) {
      Preconditions.checkState(n.isCall());
      Node first = n.getFirstChild();
      while (first.isCast()) {
        first = first.getFirstChild();
      }
      if (!NodeUtil.isGet(first)) {
        n.putBooleanProp(Node.FREE_CALL, true);
      }
      if (first.isName() &&
          "eval".equals(first.getString())) {
        first.putBooleanProp(Node.DIRECT_EVAL, true);
      }
    }


    private void annotateCalls(Node n) {
      Preconditions.checkState(n.isCall());
      Node first = n.getFirstChild();
      if (!NodeUtil.isGet(first)) {
        n.putBooleanProp(Node.FREE_CALL, true);
      }
      if (first.isName() &&
          "eval".equals(first.getString())) {
        first.putBooleanProp(Node.DIRECT_EVAL, true);
      }
    }


    protected final JsonDeserializer<Object> _findDeserializer(DeserializationContext ctxt,
            String typeId) throws IOException
    {
        JsonDeserializer<Object> deser = _deserializers.get(typeId);
        if (deser == null) {
            JavaType type = _idResolver.typeFromId(ctxt, typeId);
            if (type == null) {
                deser = _findDefaultImplDeserializer(ctxt);
                if (deser == null) {
                    JavaType actual = _handleUnknownTypeId(ctxt, typeId, _idResolver, _baseType);
                    if (actual == null) {
                        return null;
                    }
                    deser = ctxt.findContextualValueDeserializer(actual, _property);
                }
            } else {
                if ((_baseType != null)
                        && _baseType.getClass() == type.getClass()) {
                    if (!type.hasGenericTypes()) {
                        type = ctxt.getTypeFactory().constructSpecializedType(_baseType, type.getRawClass());
                    }
                }
                deser = ctxt.findContextualValueDeserializer(type, _property);
            }
            _deserializers.put(typeId, deser);
        }
        return deser;
    }


    protected final JsonDeserializer<Object> _findDeserializer(DeserializationContext ctxt,
            String typeId) throws IOException
    {
        JsonDeserializer<Object> deser = _deserializers.get(typeId);
        if (deser == null) {
            JavaType type = _idResolver.typeFromId(ctxt, typeId);
            if (type == null) {
                deser = _findDefaultImplDeserializer(ctxt);
                if (deser == null) {
                    JavaType actual = _handleUnknownTypeId(ctxt, typeId, _idResolver, _baseType);
                    if (actual == null) {
                        return null;
                    }
                    deser = ctxt.findContextualValueDeserializer(actual, _property);
                }
            } else {
                if ((_baseType != null)
                        && _baseType.getClass() == type.getClass()) {
                        type = ctxt.getTypeFactory().constructSpecializedType(_baseType, type.getRawClass());
                }
                deser = ctxt.findContextualValueDeserializer(type, _property);
            }
            _deserializers.put(typeId, deser);
        }
        return deser;
    }


    static void escape(StringBuilder accum, String string, Document.OutputSettings out,
                       boolean inAttribute, boolean normaliseWhite, boolean stripLeadingWhite) {
        boolean lastWasWhite = false;
        boolean reachedNonWhite = false;
        final EscapeMode escapeMode = out.escapeMode();
        final CharsetEncoder encoder = out.encoder();
        final CoreCharset coreCharset = CoreCharset.byName(encoder.charset().name());
        final Map<Character, String> map = escapeMode.getMap();
        final int length = string.length();
        int codePoint;
        for (int offset = 0; offset < length; offset += Character.charCount(codePoint)) {
            codePoint = string.codePointAt(offset);
            if (normaliseWhite) {
                if (StringUtil.isWhitespace(codePoint)) {
                    if ((stripLeadingWhite && !reachedNonWhite) || lastWasWhite)
                        continue;
                    accum.append(' ');
                    lastWasWhite = true;
                    continue;
                } else {
                    lastWasWhite = false;
                    reachedNonWhite = true;
                }
            }
            if (codePoint < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
                final char c = (char) codePoint;
                switch (c) {
                    case '&':
                        accum.append("&");
                        break;
                    case 0xA0:
                        if (escapeMode != EscapeMode.xhtml)
                            accum.append(" ");
                        else
                            accum.append(" ");
                        break;
                    case '<':
                        if (!inAttribute || escapeMode == EscapeMode.xhtml)
                            accum.append("<");
                        else
                            accum.append(c);
                        break;
                    case '>':
                        if (!inAttribute)
                            accum.append(">");
                        else
                            accum.append(c);
                        break;
                    case '"':
                        if (inAttribute)
                            accum.append(""");
                        else
                            accum.append(c);
                        break;
                    default:
                        if (canEncode(coreCharset, c, encoder))
                            accum.append(c);
                        else if (map.containsKey(c))
                            accum.append('&').append(map.get(c)).append(';');
                        else
                            accum.append("&#x").append(Integer.toHexString(codePoint)).append(';');
                }
            } else {
                final String c = new String(Character.toChars(codePoint));
                if (encoder.canEncode(c))
                    accum.append(c);
                else
                    accum.append("&#x").append(Integer.toHexString(codePoint)).append(';');
            }
        }
    }


    static void escape(StringBuilder accum, String string, Document.OutputSettings out,
                       boolean inAttribute, boolean normaliseWhite, boolean stripLeadingWhite) {
        boolean lastWasWhite = false;
        boolean reachedNonWhite = false;
        final EscapeMode escapeMode = out.escapeMode();
        final CharsetEncoder encoder = out.encoder();
        final CoreCharset coreCharset = CoreCharset.byName(encoder.charset().name());
        final Map<Character, String> map = escapeMode.getMap();
        final int length = string.length();
        int codePoint;
        for (int offset = 0; offset < length; offset += Character.charCount(codePoint)) {
            codePoint = string.codePointAt(offset);
            if (normaliseWhite) {
                if (StringUtil.isWhitespace(codePoint)) {
                    if ((stripLeadingWhite && !reachedNonWhite) || lastWasWhite)
                        continue;
                    accum.append(' ');
                    lastWasWhite = true;
                    continue;
                } else {
                    lastWasWhite = false;
                    reachedNonWhite = true;
                }
            }
            if (codePoint < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
                final char c = (char) codePoint;
                switch (c) {
                    case '&':
                        accum.append("&");
                        break;
                    case 0xA0:
                        if (escapeMode != EscapeMode.xhtml)
                            accum.append(" ");
                        else
                            accum.append(" ");
                        break;
                    case '<':
                        if (!inAttribute)
                            accum.append("<");
                        else
                            accum.append(c);
                        break;
                    case '>':
                        if (!inAttribute)
                            accum.append(">");
                        else
                            accum.append(c);
                        break;
                    case '"':
                        if (inAttribute)
                            accum.append(""");
                        else
                            accum.append(c);
                        break;
                    default:
                        if (canEncode(coreCharset, c, encoder))
                            accum.append(c);
                        else if (map.containsKey(c))
                            accum.append('&').append(map.get(c)).append(';');
                        else
                            accum.append("&#x").append(Integer.toHexString(codePoint)).append(';');
                }
            } else {
                final String c = new String(Character.toChars(codePoint));
                if (encoder.canEncode(c))
                    accum.append(c);
                else
                    accum.append("&#x").append(Integer.toHexString(codePoint)).append(';');
            }
        }
    }


    private Attribute parseAttribute() {
        tq.consumeWhitespace();
        String key = tq.consumeAttributeKey();
        String value = "";
        tq.consumeWhitespace();
        if (tq.matchChomp("=")) {
            tq.consumeWhitespace();
            if (tq.matchChomp(SQ)) {
                value = tq.chompTo(SQ);
            } else if (tq.matchChomp(DQ)) {
                value = tq.chompTo(DQ);
            } else {
                StringBuilder valueAccum = new StringBuilder();
                while (!tq.matchesAny("<", "/>", ">") && !tq.matchesWhitespace() && !tq.isEmpty()) {
                    valueAccum.append(tq.consume());
                }
                value = valueAccum.toString();
            }
            tq.consumeWhitespace();
        }
        if (key.length() != 0)
            return Attribute.createFromEncoded(key, value);
        else {
            if (value.length() == 0)
                tq.advance();
            return null;
        }
    }


    private Attribute parseAttribute() {
        tq.consumeWhitespace();
        String key = tq.consumeAttributeKey();
        String value = "";
        tq.consumeWhitespace();
        if (tq.matchChomp("=")) {
            tq.consumeWhitespace();
            if (tq.matchChomp(SQ)) {
                value = tq.chompTo(SQ);
            } else if (tq.matchChomp(DQ)) {
                value = tq.chompTo(DQ);
            } else {
                StringBuilder valueAccum = new StringBuilder();
                while (!tq.matchesAny("<", "/>", ">") && !tq.matchesWhitespace() && !tq.isEmpty()) {
                    valueAccum.append(tq.consume());
                }
                value = valueAccum.toString();
            }
            tq.consumeWhitespace();
        }
        if (key.length() != 0)
            return Attribute.createFromEncoded(key, value);
        else {
            tq.consume();
            return null;
        }
    }


    private void applyPaxHeadersToCurrentEntry(Map<String, String> headers) {
        for (Entry<String, String> ent : headers.entrySet()){
            String key = ent.getKey();
            String val = ent.getValue();
            if ("path".equals(key)){
                currEntry.setName(val);
            } else if ("linkpath".equals(key)){
                currEntry.setLinkName(val);
            } else if ("gid".equals(key)){
                currEntry.setGroupId(Long.parseLong(val));
            } else if ("gname".equals(key)){
                currEntry.setGroupName(val);
            } else if ("uid".equals(key)){
                currEntry.setUserId(Long.parseLong(val));
            } else if ("uname".equals(key)){
                currEntry.setUserName(val);
            } else if ("size".equals(key)){
                currEntry.setSize(Long.parseLong(val));
            } else if ("mtime".equals(key)){
                currEntry.setModTime((long) (Double.parseDouble(val) * 1000));
            } else if ("SCHILY.devminor".equals(key)){
                currEntry.setDevMinor(Integer.parseInt(val));
            } else if ("SCHILY.devmajor".equals(key)){
                currEntry.setDevMajor(Integer.parseInt(val));
            }
        }
    }


    private void applyPaxHeadersToCurrentEntry(Map<String, String> headers) {
        for (Entry<String, String> ent : headers.entrySet()){
            String key = ent.getKey();
            String val = ent.getValue();
            if ("path".equals(key)){
                currEntry.setName(val);
            } else if ("linkpath".equals(key)){
                currEntry.setLinkName(val);
            } else if ("gid".equals(key)){
                currEntry.setGroupId(Integer.parseInt(val));
            } else if ("gname".equals(key)){
                currEntry.setGroupName(val);
            } else if ("uid".equals(key)){
                currEntry.setUserId(Integer.parseInt(val));
            } else if ("uname".equals(key)){
                currEntry.setUserName(val);
            } else if ("size".equals(key)){
                currEntry.setSize(Long.parseLong(val));
            } else if ("mtime".equals(key)){
                currEntry.setModTime((long) (Double.parseDouble(val) * 1000));
            } else if ("SCHILY.devminor".equals(key)){
                currEntry.setDevMinor(Integer.parseInt(val));
            } else if ("SCHILY.devmajor".equals(key)){
                currEntry.setDevMajor(Integer.parseInt(val));
            }
        }
    }


    private void declareArguments(Node functionNode) {
      Node astParameters = functionNode.getFirstChild().getNext();
      Node body = astParameters.getNext();
      FunctionType functionType = (FunctionType) functionNode.getJSType();
      if (functionType != null) {
        Node jsDocParameters = functionType.getParametersNode();
        if (jsDocParameters != null) {
          Node jsDocParameter = jsDocParameters.getFirstChild();
          for (Node astParameter : astParameters.children()) {
            if (jsDocParameter != null) {
              defineSlot(astParameter, functionNode,
                  jsDocParameter.getJSType(), false);
              jsDocParameter = jsDocParameter.getNext();
            } else {
              defineSlot(astParameter, functionNode, null, true);
            }
          }
        }
      }
    }


    private void declareArguments(Node functionNode) {
      Node astParameters = functionNode.getFirstChild().getNext();
      Node body = astParameters.getNext();
      FunctionType functionType = (FunctionType) functionNode.getJSType();
      if (functionType != null) {
        Node jsDocParameters = functionType.getParametersNode();
        if (jsDocParameters != null) {
          Node jsDocParameter = jsDocParameters.getFirstChild();
          for (Node astParameter : astParameters.children()) {
            if (jsDocParameter != null) {
              defineSlot(astParameter, functionNode,
                  jsDocParameter.getJSType(), true);
              jsDocParameter = jsDocParameter.getNext();
            } else {
              defineSlot(astParameter, functionNode, null, true);
            }
          }
        }
      }
    }


  private boolean isSafeReplacement(Node node, Node replacement) {
    if (node.isName()) {
      return true;
    }
    Preconditions.checkArgument(node.isGetProp());
    while (node.isGetProp()) {
      node = node.getFirstChild();
    }
    if (node.isName()
        && isNameAssignedTo(node.getString(), replacement)) {
      return false;
    }
    return true;
  }


  private boolean isSafeReplacement(Node node, Node replacement) {
    if (node.isName()) {
      return true;
    }
    Preconditions.checkArgument(node.isGetProp());
      node = node.getFirstChild();
    if (node.isName()
        && isNameAssignedTo(node.getString(), replacement)) {
      return false;
    }
    return true;
  }


    private void updateBounds(TimePeriod period, int index) {
        long start = period.getStart().getTime();
        long end = period.getEnd().getTime();
        long middle = start + ((end - start) / 2);
        if (this.minStartIndex >= 0) {
            long minStart = getDataItem(this.minStartIndex).getPeriod()
                .getStart().getTime();
            if (start < minStart) {
                this.minStartIndex = index;
            }
        }
        else {
            this.minStartIndex = index;
        }
        if (this.maxStartIndex >= 0) {
            long maxStart = getDataItem(this.maxStartIndex).getPeriod()
                .getStart().getTime();
            if (start > maxStart) {
                this.maxStartIndex = index;
            }
        }
        else {
            this.maxStartIndex = index;
        }
        if (this.minMiddleIndex >= 0) {
            long s = getDataItem(this.minMiddleIndex).getPeriod().getStart()
                .getTime();
            long e = getDataItem(this.minMiddleIndex).getPeriod().getEnd()
                .getTime();
            long minMiddle = s + (e - s) / 2;
            if (middle < minMiddle) {
                this.minMiddleIndex = index;
            }
        }
        else {
            this.minMiddleIndex = index;
        }
        if (this.maxMiddleIndex >= 0) {
            long s = getDataItem(this.maxMiddleIndex).getPeriod().getStart()
                .getTime();
            long e = getDataItem(this.maxMiddleIndex).getPeriod().getEnd()
                .getTime();
            long maxMiddle = s + (e - s) / 2;
            if (middle > maxMiddle) {
                this.maxMiddleIndex = index;
            }
        }
        else {
            this.maxMiddleIndex = index;
        }
        if (this.minEndIndex >= 0) {
            long minEnd = getDataItem(this.minEndIndex).getPeriod().getEnd()
                .getTime();
            if (end < minEnd) {
                this.minEndIndex = index;
            }
        }
        else {
            this.minEndIndex = index;
        }
        if (this.maxEndIndex >= 0) {
            long maxEnd = getDataItem(this.maxEndIndex).getPeriod().getEnd()
                .getTime();
            if (end > maxEnd) {
                this.maxEndIndex = index;
            }
        }
        else {
            this.maxEndIndex = index;
        }
    }


    private void updateBounds(TimePeriod period, int index) {
        long start = period.getStart().getTime();
        long end = period.getEnd().getTime();
        long middle = start + ((end - start) / 2);
        if (this.minStartIndex >= 0) {
            long minStart = getDataItem(this.minStartIndex).getPeriod()
                .getStart().getTime();
            if (start < minStart) {
                this.minStartIndex = index;
            }
        }
        else {
            this.minStartIndex = index;
        }
        if (this.maxStartIndex >= 0) {
            long maxStart = getDataItem(this.maxStartIndex).getPeriod()
                .getStart().getTime();
            if (start > maxStart) {
                this.maxStartIndex = index;
            }
        }
        else {
            this.maxStartIndex = index;
        }
        if (this.minMiddleIndex >= 0) {
            long s = getDataItem(this.minMiddleIndex).getPeriod().getStart()
                .getTime();
            long e = getDataItem(this.minMiddleIndex).getPeriod().getEnd()
                .getTime();
            long minMiddle = s + (e - s) / 2;
            if (middle < minMiddle) {
                this.minMiddleIndex = index;
            }
        }
        else {
            this.minMiddleIndex = index;
        }
        if (this.maxMiddleIndex >= 0) {
            long s = getDataItem(this.minMiddleIndex).getPeriod().getStart()
                .getTime();
            long e = getDataItem(this.minMiddleIndex).getPeriod().getEnd()
                .getTime();
            long maxMiddle = s + (e - s) / 2;
            if (middle > maxMiddle) {
                this.maxMiddleIndex = index;
            }
        }
        else {
            this.maxMiddleIndex = index;
        }
        if (this.minEndIndex >= 0) {
            long minEnd = getDataItem(this.minEndIndex).getPeriod().getEnd()
                .getTime();
            if (end < minEnd) {
                this.minEndIndex = index;
            }
        }
        else {
            this.minEndIndex = index;
        }
        if (this.maxEndIndex >= 0) {
            long maxEnd = getDataItem(this.maxEndIndex).getPeriod().getEnd()
                .getTime();
            if (end > maxEnd) {
                this.maxEndIndex = index;
            }
        }
        else {
            this.maxEndIndex = index;
        }
    }


    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        if (!super.equals(o)) return false;
        Element element = (Element) o;
        return tag.equals(element.tag);
    }


    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        if (!super.equals(o)) return false;
        Element element = (Element) o;
        return this == o;
    }


    public TimeSeries createCopy(int start, int end)
            throws CloneNotSupportedException {
        if (start < 0) {
            throw new IllegalArgumentException("Requires start >= 0.");
        }
        if (end < start) {
            throw new IllegalArgumentException("Requires start <= end.");
        }
        TimeSeries copy = (TimeSeries) super.clone();
        copy.minY = Double.NaN;
        copy.maxY = Double.NaN;
        copy.data = new java.util.ArrayList();
        if (this.data.size() > 0) {
            for (int index = start; index <= end; index++) {
                TimeSeriesDataItem item
                        = (TimeSeriesDataItem) this.data.get(index);
                TimeSeriesDataItem clone = (TimeSeriesDataItem) item.clone();
                try {
                    copy.add(clone);
                }
                catch (SeriesException e) {
                    e.printStackTrace();
                }
            }
        }
        return copy;
    }


    public TimeSeries createCopy(int start, int end)
            throws CloneNotSupportedException {
        if (start < 0) {
            throw new IllegalArgumentException("Requires start >= 0.");
        }
        if (end < start) {
            throw new IllegalArgumentException("Requires start <= end.");
        }
        TimeSeries copy = (TimeSeries) super.clone();
        copy.data = new java.util.ArrayList();
        if (this.data.size() > 0) {
            for (int index = start; index <= end; index++) {
                TimeSeriesDataItem item
                        = (TimeSeriesDataItem) this.data.get(index);
                TimeSeriesDataItem clone = (TimeSeriesDataItem) item.clone();
                try {
                    copy.add(clone);
                }
                catch (SeriesException e) {
                    e.printStackTrace();
                }
            }
        }
        return copy;
    }


    protected void burstToken(String token, boolean stopAtNonOption)
    {
        for (int i = 1; i < token.length(); i++)
        {
            String ch = String.valueOf(token.charAt(i));
            if (options.hasOption(ch))
            {
                tokens.add("-" + ch);
                currentOption = options.getOption(ch);
                if (currentOption.hasArg() && (token.length() != (i + 1)))
                {
                    tokens.add(token.substring(i + 1));
                    break;
                }
            }
            else if (stopAtNonOption)
            {
                process(token.substring(i));
                break;
            }
            else
            {
                tokens.add(token);
                break;
            }
        }
    }


    protected void burstToken(String token, boolean stopAtNonOption)
    {
        for (int i = 1; i < token.length(); i++)
        {
            String ch = String.valueOf(token.charAt(i));
            if (options.hasOption(ch))
            {
                tokens.add("-" + ch);
                currentOption = options.getOption(ch);
                if (currentOption.hasArg() && (token.length() != (i + 1)))
                {
                    tokens.add(token.substring(i + 1));
                    break;
                }
            }
            else if (stopAtNonOption)
            {
                process(token.substring(i));
            }
            else
            {
                tokens.add(token);
                break;
            }
        }
    }


    public static StdKeyDeserializer forType(Class<?> raw)
    {
        int kind;
        if (raw == String.class || raw == Object.class || raw == CharSequence.class) {
            return StringKD.forType(raw);
        } else if (raw == UUID.class) {
            kind = TYPE_UUID;
        } else if (raw == Integer.class) {
            kind = TYPE_INT;
        } else if (raw == Long.class) {
            kind = TYPE_LONG;
        } else if (raw == Date.class) {
            kind = TYPE_DATE;
        } else if (raw == Calendar.class) {
            kind = TYPE_CALENDAR;
        } else if (raw == Boolean.class) {
            kind = TYPE_BOOLEAN;
        } else if (raw == Byte.class) {
            kind = TYPE_BYTE;
        } else if (raw == Character.class) {
            kind = TYPE_CHAR;
        } else if (raw == Short.class) {
            kind = TYPE_SHORT;
        } else if (raw == Float.class) {
            kind = TYPE_FLOAT;
        } else if (raw == Double.class) {
            kind = TYPE_DOUBLE;
        } else if (raw == URI.class) {
            kind = TYPE_URI;
        } else if (raw == URL.class) {
            kind = TYPE_URL;
        } else if (raw == Class.class) {
            kind = TYPE_CLASS;
        } else if (raw == Locale.class) {
            FromStringDeserializer<?> deser = FromStringDeserializer.findDeserializer(Locale.class);
            return new StdKeyDeserializer(TYPE_LOCALE, raw, deser);
        } else if (raw == Currency.class) {
            FromStringDeserializer<?> deser = FromStringDeserializer.findDeserializer(Currency.class);
            return new StdKeyDeserializer(TYPE_CURRENCY, raw, deser);
        } else {
            return null;
        }
        return new StdKeyDeserializer(kind, raw);
    }


    public static StdKeyDeserializer forType(Class<?> raw)
    {
        int kind;
        if (raw == String.class || raw == Object.class) {
            return StringKD.forType(raw);
        } else if (raw == UUID.class) {
            kind = TYPE_UUID;
        } else if (raw == Integer.class) {
            kind = TYPE_INT;
        } else if (raw == Long.class) {
            kind = TYPE_LONG;
        } else if (raw == Date.class) {
            kind = TYPE_DATE;
        } else if (raw == Calendar.class) {
            kind = TYPE_CALENDAR;
        } else if (raw == Boolean.class) {
            kind = TYPE_BOOLEAN;
        } else if (raw == Byte.class) {
            kind = TYPE_BYTE;
        } else if (raw == Character.class) {
            kind = TYPE_CHAR;
        } else if (raw == Short.class) {
            kind = TYPE_SHORT;
        } else if (raw == Float.class) {
            kind = TYPE_FLOAT;
        } else if (raw == Double.class) {
            kind = TYPE_DOUBLE;
        } else if (raw == URI.class) {
            kind = TYPE_URI;
        } else if (raw == URL.class) {
            kind = TYPE_URL;
        } else if (raw == Class.class) {
            kind = TYPE_CLASS;
        } else if (raw == Locale.class) {
            FromStringDeserializer<?> deser = FromStringDeserializer.findDeserializer(Locale.class);
            return new StdKeyDeserializer(TYPE_LOCALE, raw, deser);
        } else if (raw == Currency.class) {
            FromStringDeserializer<?> deser = FromStringDeserializer.findDeserializer(Currency.class);
            return new StdKeyDeserializer(TYPE_CURRENCY, raw, deser);
        } else {
            return null;
        }
        return new StdKeyDeserializer(kind, raw);
    }


    public CholeskyDecompositionImpl(final RealMatrix matrix,
                                     final double relativeSymmetryThreshold,
                                     final double absolutePositivityThreshold)
        throws NonSquareMatrixException,
               NotSymmetricMatrixException, NotPositiveDefiniteMatrixException {
        if (!matrix.isSquare()) {
            throw new NonSquareMatrixException(matrix.getRowDimension(),
                                               matrix.getColumnDimension());
        }
        final int order = matrix.getRowDimension();
        lTData   = matrix.getData();
        cachedL  = null;
        cachedLT = null;
        for (int i = 0; i < order; ++i) {
            final double[] lI = lTData[i];
            for (int j = i + 1; j < order; ++j) {
                final double[] lJ = lTData[j];
                final double lIJ = lI[j];
                final double lJI = lJ[i];
                final double maxDelta =
                    relativeSymmetryThreshold * Math.max(Math.abs(lIJ), Math.abs(lJI));
                if (Math.abs(lIJ - lJI) > maxDelta) {
                    throw new NotSymmetricMatrixException();
                }
                lJ[i] = 0;
           }
        }
        for (int i = 0; i < order; ++i) {
            final double[] ltI = lTData[i];
            if (ltI[i] < absolutePositivityThreshold) {
                throw new NotPositiveDefiniteMatrixException();
            }
            ltI[i] = Math.sqrt(ltI[i]);
            final double inverse = 1.0 / ltI[i];
            for (int q = order - 1; q > i; --q) {
                ltI[q] *= inverse;
                final double[] ltQ = lTData[q];
                for (int p = q; p < order; ++p) {
                    ltQ[p] -= ltI[q] * ltI[p];
                }
            }
        }
    }


    public CholeskyDecompositionImpl(final RealMatrix matrix,
                                     final double relativeSymmetryThreshold,
                                     final double absolutePositivityThreshold)
        throws NonSquareMatrixException,
               NotSymmetricMatrixException, NotPositiveDefiniteMatrixException {
        if (!matrix.isSquare()) {
            throw new NonSquareMatrixException(matrix.getRowDimension(),
                                               matrix.getColumnDimension());
        }
        final int order = matrix.getRowDimension();
        lTData   = matrix.getData();
        cachedL  = null;
        cachedLT = null;
        for (int i = 0; i < order; ++i) {
            final double[] lI = lTData[i];
            if (lTData[i][i] < absolutePositivityThreshold) {
                throw new NotPositiveDefiniteMatrixException();
            }
            for (int j = i + 1; j < order; ++j) {
                final double[] lJ = lTData[j];
                final double lIJ = lI[j];
                final double lJI = lJ[i];
                final double maxDelta =
                    relativeSymmetryThreshold * Math.max(Math.abs(lIJ), Math.abs(lJI));
                if (Math.abs(lIJ - lJI) > maxDelta) {
                    throw new NotSymmetricMatrixException();
                }
                lJ[i] = 0;
           }
        }
        for (int i = 0; i < order; ++i) {
            final double[] ltI = lTData[i];
            ltI[i] = Math.sqrt(ltI[i]);
            final double inverse = 1.0 / ltI[i];
            for (int q = order - 1; q > i; --q) {
                ltI[q] *= inverse;
                final double[] ltQ = lTData[q];
                for (int p = q; p < order; ++p) {
                    ltQ[p] -= ltI[q] * ltI[p];
                }
            }
        }
    }


      public int parseArguments(Parameters params) throws CmdLineException {
        String param = null;
        try {
          param = params.getParameter(0);
        } catch (CmdLineException e) {}
        if (param == null) {
          setter.addValue(true);
          return 0;
        } else {
          String lowerParam = param.toLowerCase();
          if (TRUES.contains(lowerParam)) {
            setter.addValue(true);
          } else if (FALSES.contains(lowerParam)) {
            setter.addValue(false);
          } else {
            setter.addValue(true);
            return 0;
          }
          return 1;
        }
      }


      public int parseArguments(Parameters params) throws CmdLineException {
        String param = params.getParameter(0);
        if (param == null) {
          setter.addValue(true);
          return 0;
        } else {
          String lowerParam = param.toLowerCase();
          if (TRUES.contains(lowerParam)) {
            setter.addValue(true);
          } else if (FALSES.contains(lowerParam)) {
            setter.addValue(false);
          } else {
            setter.addValue(true);
            return 0;
          }
          return 1;
        }
      }


    public char[] getTextBuffer()
    {
        if (_inputStart >= 0) return _inputBuffer;
        if (_resultArray != null)  return _resultArray;
        if (_resultString != null) {
            return (_resultArray = _resultString.toCharArray());
        }
        if (!_hasSegments && _currentSegment != null)  return _currentSegment;
        return contentsAsArray();
    }


    public char[] getTextBuffer()
    {
        if (_inputStart >= 0) return _inputBuffer;
        if (_resultArray != null)  return _resultArray;
        if (_resultString != null) {
            return (_resultArray = _resultString.toCharArray());
        }
        if (!_hasSegments)  return _currentSegment;
        return contentsAsArray();
    }


    protected void registerTypeVariablesOn(Type classType) {
        if (!(classType instanceof ParameterizedType)) {
            return;
        }
        ParameterizedType parameterizedType = (ParameterizedType) classType;
        TypeVariable[] typeParameters = ((Class<?>) parameterizedType.getRawType()).getTypeParameters();
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        for (int i = 0; i < actualTypeArguments.length; i++) {
            TypeVariable typeParameter = typeParameters[i];
            Type actualTypeArgument = actualTypeArguments[i];
            if (actualTypeArgument instanceof WildcardType) {
                contextualActualTypeParameters.put(typeParameter, boundsOf((WildcardType) actualTypeArgument));
            } else if (typeParameter != actualTypeArgument) {
                contextualActualTypeParameters.put(typeParameter, actualTypeArgument);
            }
        }
    }


    protected void registerTypeVariablesOn(Type classType) {
        if (!(classType instanceof ParameterizedType)) {
            return;
        }
        ParameterizedType parameterizedType = (ParameterizedType) classType;
        TypeVariable[] typeParameters = ((Class<?>) parameterizedType.getRawType()).getTypeParameters();
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        for (int i = 0; i < actualTypeArguments.length; i++) {
            TypeVariable typeParameter = typeParameters[i];
            Type actualTypeArgument = actualTypeArguments[i];
            if (actualTypeArgument instanceof WildcardType) {
                contextualActualTypeParameters.put(typeParameter, boundsOf((WildcardType) actualTypeArgument));
            } else {
                contextualActualTypeParameters.put(typeParameter, actualTypeArgument);
            }
        }
    }


    public boolean hasClass(String className) {
        final String classAttr = attributes.getIgnoreCase("class");
        final int len = classAttr.length();
        final int wantLen = className.length();
        if (len == 0 || len < wantLen) {
            return false;
        }
        if (len == wantLen) {
            return className.equalsIgnoreCase(classAttr);
        }
        boolean inClass = false;
        int start = 0;
        for (int i = 0; i < len; i++) {
            if (Character.isWhitespace(classAttr.charAt(i))) {
                if (inClass) {
                    if (i - start == wantLen && classAttr.regionMatches(true, start, className, 0, wantLen)) {
                        return true;
                    }
                    inClass = false;
                }
            } else {
                if (!inClass) {
                    inClass = true;
                    start = i;
                }
            }
        }
        if (inClass && len - start == wantLen) {
            return classAttr.regionMatches(true, start, className, 0, wantLen);
        }
        return false;
    }


    public boolean hasClass(String className) {
        final String classAttr = attributes.get("class");
        final int len = classAttr.length();
        final int wantLen = className.length();
        if (len == 0 || len < wantLen) {
            return false;
        }
        if (len == wantLen) {
            return className.equalsIgnoreCase(classAttr);
        }
        boolean inClass = false;
        int start = 0;
        for (int i = 0; i < len; i++) {
            if (Character.isWhitespace(classAttr.charAt(i))) {
                if (inClass) {
                    if (i - start == wantLen && classAttr.regionMatches(true, start, className, 0, wantLen)) {
                        return true;
                    }
                    inClass = false;
                }
            } else {
                if (!inClass) {
                    inClass = true;
                    start = i;
                }
            }
        }
        if (inClass && len - start == wantLen) {
            return classAttr.regionMatches(true, start, className, 0, wantLen);
        }
        return false;
    }


  private ExtractionInfo extractMultilineTextualBlock(JsDocToken token,
                                                      WhitespaceOption option) {
    if (token == JsDocToken.EOC || token == JsDocToken.EOL ||
        token == JsDocToken.EOF) {
      return new ExtractionInfo("", token);
    }
    stream.update();
    int startLineno = stream.getLineno();
    int startCharno = stream.getCharno() + 1;
    String line = stream.getRemainingJSDocLine();
    if (option != WhitespaceOption.PRESERVE) {
      line = line.trim();
    }
    StringBuilder builder = new StringBuilder();
    builder.append(line);
    state = State.SEARCHING_ANNOTATION;
    token = next();
    boolean ignoreStar = false;
    int lineStartChar = -1;
    do {
      switch (token) {
        case STAR:
          if (ignoreStar) {
            lineStartChar = stream.getCharno() + 1;
          } else {
            if (builder.length() > 0) {
              builder.append(' ');
            }
            builder.append('*');
          }
          token = next();
          continue;
        case EOL:
          if (option != WhitespaceOption.SINGLE_LINE) {
            builder.append("\n");
          }
          ignoreStar = true;
          lineStartChar = 0;
          token = next();
          continue;
        default:
          ignoreStar = false;
          state = State.SEARCHING_ANNOTATION;
          boolean isEOC = token == JsDocToken.EOC;
          if (!isEOC) {
            if (lineStartChar != -1 && option == WhitespaceOption.PRESERVE) {
              int numSpaces = stream.getCharno() - lineStartChar;
              for (int i = 0; i < numSpaces; i++) {
                builder.append(' ');
              }
              lineStartChar = -1;
            } else if (builder.length() > 0) {
              builder.append(' ');
            }
          }
          if (token == JsDocToken.EOC ||
              token == JsDocToken.EOF ||
              (token == JsDocToken.ANNOTATION &&
               option != WhitespaceOption.PRESERVE)) {
            String multilineText = builder.toString();
            if (option != WhitespaceOption.PRESERVE) {
              multilineText = multilineText.trim();
            }
            int endLineno = stream.getLineno();
            int endCharno = stream.getCharno();
            if (multilineText.length() > 0) {
              jsdocBuilder.markText(multilineText, startLineno, startCharno,
                  endLineno, endCharno);
            }
            return new ExtractionInfo(multilineText, token);
          }
          builder.append(toString(token));
          line = stream.getRemainingJSDocLine();
          if (option != WhitespaceOption.PRESERVE) {
            line = trimEnd(line);
          }
          builder.append(line);
          token = next();
      }
    } while (true);
  }


  private ExtractionInfo extractMultilineTextualBlock(JsDocToken token,
                                                      WhitespaceOption option) {
    if (token == JsDocToken.EOC || token == JsDocToken.EOL ||
        token == JsDocToken.EOF) {
      return new ExtractionInfo("", token);
    }
    stream.update();
    int startLineno = stream.getLineno();
    int startCharno = stream.getCharno() + 1;
    String line = stream.getRemainingJSDocLine();
    if (option != WhitespaceOption.PRESERVE) {
      line = line.trim();
    }
    StringBuilder builder = new StringBuilder();
    builder.append(line);
    state = State.SEARCHING_ANNOTATION;
    token = next();
    boolean ignoreStar = false;
    do {
      switch (token) {
        case STAR:
          if (ignoreStar) {
          } else {
            if (builder.length() > 0) {
              builder.append(' ');
            }
            builder.append('*');
          }
          token = next();
          continue;
        case EOL:
          if (option != WhitespaceOption.SINGLE_LINE) {
            builder.append("\n");
          }
          ignoreStar = true;
          token = next();
          continue;
        default:
          ignoreStar = false;
          state = State.SEARCHING_ANNOTATION;
          if (token == JsDocToken.EOC ||
              token == JsDocToken.EOF ||
              (token == JsDocToken.ANNOTATION &&
               option != WhitespaceOption.PRESERVE)) {
            String multilineText = builder.toString();
            if (option != WhitespaceOption.PRESERVE) {
              multilineText = multilineText.trim();
            }
            int endLineno = stream.getLineno();
            int endCharno = stream.getCharno();
            if (multilineText.length() > 0) {
              jsdocBuilder.markText(multilineText, startLineno, startCharno,
                  endLineno, endCharno);
            }
            return new ExtractionInfo(multilineText, token);
          }
          if (builder.length() > 0) {
            builder.append(' ');
          }
          builder.append(toString(token));
          line = stream.getRemainingJSDocLine();
          if (option != WhitespaceOption.PRESERVE) {
            line = trimEnd(line);
          }
          builder.append(line);
          token = next();
      }
    } while (true);
  }


    public Complex add(Complex rhs)
        throws NullArgumentException {
        MathUtils.checkNotNull(rhs);
        if (isNaN || rhs.isNaN) {
            return NaN;
        }
        return createComplex(real + rhs.getReal(),
            imaginary + rhs.getImaginary());
    }


    public Complex add(Complex rhs)
        throws NullArgumentException {
        MathUtils.checkNotNull(rhs);
        return createComplex(real + rhs.getReal(),
            imaginary + rhs.getImaginary());
    }


    public static String parseName(byte[] buffer, final int offset, final int length) {
        StringBuffer result = new StringBuffer(length);
        int          end = offset + length;
        for (int i = offset; i < end; ++i) {
            byte b = buffer[i];
            if (b == 0) {
                break;
            }
            result.append((char) (b & 0xFF));
        }
        return result.toString();
    }


    public static String parseName(byte[] buffer, final int offset, final int length) {
        StringBuffer result = new StringBuffer(length);
        int          end = offset + length;
        for (int i = offset; i < end; ++i) {
            if (buffer[i] == 0) {
                break;
            }
            result.append((char) buffer[i]);
        }
        return result.toString();
    }


    private Integer getPivotRow(SimplexTableau tableau, final int col) {
        List<Integer> minRatioPositions = new ArrayList<Integer>();
        double minRatio = Double.MAX_VALUE;
        for (int i = tableau.getNumObjectiveFunctions(); i < tableau.getHeight(); i++) {
            final double rhs = tableau.getEntry(i, tableau.getWidth() - 1);
            final double entry = tableau.getEntry(i, col);
            if (Precision.compareTo(entry, 0d, maxUlps) > 0) {
                final double ratio = rhs / entry;
                final int cmp = Double.compare(ratio, minRatio);
                if (cmp == 0) {
                    minRatioPositions.add(i);
                } else if (cmp < 0) {
                    minRatio = ratio;
                    minRatioPositions = new ArrayList<Integer>();
                    minRatioPositions.add(i);
                }
            }
        }
        if (minRatioPositions.size() == 0) {
            return null;
        } else if (minRatioPositions.size() > 1) {
            if (tableau.getNumArtificialVariables() > 0) {
                for (Integer row : minRatioPositions) {
                    for (int i = 0; i < tableau.getNumArtificialVariables(); i++) {
                        int column = i + tableau.getArtificialVariableOffset();
                        final double entry = tableau.getEntry(row, column);
                        if (Precision.equals(entry, 1d, maxUlps) && row.equals(tableau.getBasicRow(column))) {
                            return row;
                        }
                    }
                }
            }
            if (getIterations() < getMaxIterations() / 2) {
                Integer minRow = null;
                int minIndex = tableau.getWidth();
                for (Integer row : minRatioPositions) {
                    int i = tableau.getNumObjectiveFunctions();
                    for (; i < tableau.getWidth() - 1 && minRow != row; i++) {
                        if (row == tableau.getBasicRow(i)) {
                            if (i < minIndex) {
                                minIndex = i;
                                minRow = row;
                            }
                        }
                    }
                }
                return minRow;
            }
        }
        return minRatioPositions.get(0);
    }


    private Integer getPivotRow(SimplexTableau tableau, final int col) {
        List<Integer> minRatioPositions = new ArrayList<Integer>();
        double minRatio = Double.MAX_VALUE;
        for (int i = tableau.getNumObjectiveFunctions(); i < tableau.getHeight(); i++) {
            final double rhs = tableau.getEntry(i, tableau.getWidth() - 1);
            final double entry = tableau.getEntry(i, col);
            if (Precision.compareTo(entry, 0d, maxUlps) > 0) {
                final double ratio = rhs / entry;
                final int cmp = Double.compare(ratio, minRatio);
                if (cmp == 0) {
                    minRatioPositions.add(i);
                } else if (cmp < 0) {
                    minRatio = ratio;
                    minRatioPositions = new ArrayList<Integer>();
                    minRatioPositions.add(i);
                }
            }
        }
        if (minRatioPositions.size() == 0) {
            return null;
        } else if (minRatioPositions.size() > 1) {
                for (Integer row : minRatioPositions) {
                    for (int i = 0; i < tableau.getNumArtificialVariables(); i++) {
                        int column = i + tableau.getArtificialVariableOffset();
                        final double entry = tableau.getEntry(row, column);
                        if (Precision.equals(entry, 1d, maxUlps) && row.equals(tableau.getBasicRow(column))) {
                            return row;
                        }
                    }
                }
                Integer minRow = null;
                int minIndex = tableau.getWidth();
                for (Integer row : minRatioPositions) {
                    int i = tableau.getNumObjectiveFunctions();
                    for (; i < tableau.getWidth() - 1 && minRow != row; i++) {
                        if (row == tableau.getBasicRow(i)) {
                            if (i < minIndex) {
                                minIndex = i;
                                minRow = row;
                            }
                        }
                    }
                }
                return minRow;
        }
        return minRatioPositions.get(0);
    }


  static boolean isSimpleNumber(String s) {
    int len = s.length();
    if (len == 0) {
      return false;
    }
    for (int index = 0; index < len; index++) {
      char c = s.charAt(index);
      if (c < '0' || c > '9') {
        return false;
      }
    }
    return len == 1 || s.charAt(0) != '0';
  }


  static boolean isSimpleNumber(String s) {
    int len = s.length();
    for (int index = 0; index < len; index++) {
      char c = s.charAt(index);
      if (c < '0' || c > '9') {
        return false;
      }
    }
    return len > 0 && s.charAt(0) != '0';
  }


    private void checkRequiredOptions()
        throws MissingOptionException
    {
        if (requiredOptions.size() > 0)
        {
            Iterator iter = requiredOptions.iterator();
            StringBuffer buff = new StringBuffer("Missing required option");
            buff.append(requiredOptions.size() == 1 ? "" : "s");
            buff.append(": ");
            while (iter.hasNext())
            {
                buff.append(iter.next());
            }
            throw new MissingOptionException(buff.toString());
        }
    }


    private void checkRequiredOptions()
        throws MissingOptionException
    {
        if (requiredOptions.size() > 0)
        {
            Iterator iter = requiredOptions.iterator();
            StringBuffer buff = new StringBuffer();
            while (iter.hasNext())
            {
                buff.append(iter.next());
            }
            throw new MissingOptionException(buff.toString());
        }
    }


    public List<Connection.KeyVal> formData() {
        ArrayList<Connection.KeyVal> data = new ArrayList<Connection.KeyVal>();
        for (Element el: elements) {
            if (!el.tag().isFormSubmittable()) continue;
            if (el.hasAttr("disabled")) continue;
            String name = el.attr("name");
            if (name.length() == 0) continue;
            String type = el.attr("type");
            if ("select".equals(el.tagName())) {
                Elements options = el.select("option[selected]");
                boolean set = false;
                for (Element option: options) {
                    data.add(HttpConnection.KeyVal.create(name, option.val()));
                    set = true;
                }
                if (!set) {
                    Element option = el.select("option").first();
                    if (option != null)
                        data.add(HttpConnection.KeyVal.create(name, option.val()));
                }
            } else if ("checkbox".equalsIgnoreCase(type) || "radio".equalsIgnoreCase(type)) {
                if (el.hasAttr("checked")) {
                    final String val = el.val().length() >  0 ? el.val() : "on";
                    data.add(HttpConnection.KeyVal.create(name, val));
                }
            } else {
                data.add(HttpConnection.KeyVal.create(name, el.val()));
            }
        }
        return data;
    }


    public List<Connection.KeyVal> formData() {
        ArrayList<Connection.KeyVal> data = new ArrayList<Connection.KeyVal>();
        for (Element el: elements) {
            if (!el.tag().isFormSubmittable()) continue;
            String name = el.attr("name");
            if (name.length() == 0) continue;
            String type = el.attr("type");
            if ("select".equals(el.tagName())) {
                Elements options = el.select("option[selected]");
                boolean set = false;
                for (Element option: options) {
                    data.add(HttpConnection.KeyVal.create(name, option.val()));
                    set = true;
                }
                if (!set) {
                    Element option = el.select("option").first();
                    if (option != null)
                        data.add(HttpConnection.KeyVal.create(name, option.val()));
                }
            } else if ("checkbox".equalsIgnoreCase(type) || "radio".equalsIgnoreCase(type)) {
                if (el.hasAttr("checked")) {
                    final String val = el.val();
                    data.add(HttpConnection.KeyVal.create(name, val));
                }
            } else {
                data.add(HttpConnection.KeyVal.create(name, el.val()));
            }
        }
        return data;
    }


  public void matchConstraint(JSType constraint) {
    if (hasReferenceName()) {
      return;
    }
    if (constraint.isRecordType()) {
      matchRecordTypeConstraint(constraint.toObjectType());
    } else if (constraint.isUnionType()) {
      for (JSType alt : constraint.toMaybeUnionType().getAlternates()) {
        if (alt.isRecordType()) {
          matchRecordTypeConstraint(alt.toObjectType());
        }
      }
    }
  }


  public void matchConstraint(JSType constraint) {
    if (hasReferenceName()) {
      return;
    }
    if (constraint.isRecordType()) {
      matchRecordTypeConstraint(constraint.toObjectType());
    }
  }


  private boolean isFoldableExpressBlock(Node n) {
    if (n.getType() == Token.BLOCK) {
      if (n.hasOneChild()) {
        Node maybeExpr = n.getFirstChild();
        if (maybeExpr.getType() == Token.EXPR_RESULT) {
          if (maybeExpr.getFirstChild().getType() == Token.CALL) {
            Node calledFn = maybeExpr.getFirstChild().getFirstChild();
            if (calledFn.getType() == Token.GETELEM) {
              return false;
            } else if (calledFn.getType() == Token.GETPROP &&
                       calledFn.getLastChild().getString().startsWith("on")) {
              return false;
            }
          }
          return true;
        }
        return false;
      }
    }
    return false;
  }


  private boolean isFoldableExpressBlock(Node n) {
    if (n.getType() == Token.BLOCK) {
      if (n.hasOneChild()) {
        Node maybeExpr = n.getFirstChild();
          return NodeUtil.isExpressionNode(maybeExpr);
      }
    }
    return false;
  }


    Map<String, String> parsePaxHeaders(final InputStream i)
        throws IOException {
        final Map<String, String> headers = new HashMap<String, String>(globalPaxHeaders);
        while(true){
            int ch;
            int len = 0;
            int read = 0;
            while((ch = i.read()) != -1) {
                read++;
                if (ch == '\n') {
                    break;
                } else if (ch == ' '){
                    final ByteArrayOutputStream coll = new ByteArrayOutputStream();
                    while((ch = i.read()) != -1) {
                        read++;
                        if (ch == '='){
                            final String keyword = coll.toString(CharsetNames.UTF_8);
                            final int restLen = len - read;
                            if (restLen == 1) {
                                headers.remove(keyword);
                            } else {
                                final byte[] rest = new byte[restLen];
                                final int got = IOUtils.readFully(i, rest);
                                if (got != restLen) {
                                    throw new IOException("Failed to read "
                                                          + "Paxheader. Expected "
                                                          + restLen
                                                          + " bytes, read "
                                                          + got);
                                }
                                final String value = new String(rest, 0,
                                                          restLen - 1, CharsetNames.UTF_8);
                                headers.put(keyword, value);
                            }
                            break;
                        }
                        coll.write((byte) ch);
                    }
                    break;
                }
                len *= 10;
                len += ch - '0';
            }
            if (ch == -1){
                break;
            }
        }
        return headers;
    }


    Map<String, String> parsePaxHeaders(final InputStream i)
        throws IOException {
        final Map<String, String> headers = new HashMap<String, String>(globalPaxHeaders);
        while(true){
            int ch;
            int len = 0;
            int read = 0;
            while((ch = i.read()) != -1) {
                read++;
                if (ch == ' '){
                    final ByteArrayOutputStream coll = new ByteArrayOutputStream();
                    while((ch = i.read()) != -1) {
                        read++;
                        if (ch == '='){
                            final String keyword = coll.toString(CharsetNames.UTF_8);
                            final int restLen = len - read;
                            if (restLen == 1) {
                                headers.remove(keyword);
                            } else {
                                final byte[] rest = new byte[restLen];
                                final int got = IOUtils.readFully(i, rest);
                                if (got != restLen) {
                                    throw new IOException("Failed to read "
                                                          + "Paxheader. Expected "
                                                          + restLen
                                                          + " bytes, read "
                                                          + got);
                                }
                                final String value = new String(rest, 0,
                                                          restLen - 1, CharsetNames.UTF_8);
                                headers.put(keyword, value);
                            }
                            break;
                        }
                        coll.write((byte) ch);
                    }
                    break;
                }
                len *= 10;
                len += ch - '0';
            }
            if (ch == -1){
                break;
            }
        }
        return headers;
    }


    protected JavaType _narrow(Class<?> subclass)
    {
        if (_class == subclass) {
            return this;
        }
        return new SimpleType(subclass, _bindings, this, _superInterfaces,
                _valueHandler, _typeHandler, _asStatic);
    }


    protected JavaType _narrow(Class<?> subclass)
    {
        if (_class == subclass) {
            return this;
        }
        return new SimpleType(subclass, _bindings, _superClass, _superInterfaces,
                _valueHandler, _typeHandler, _asStatic);
    }


        boolean anyOtherEndTag(Token t, HtmlTreeBuilder tb) {
            String name = t.asEndTag().name();
            ArrayList<Element> stack = tb.getStack();
            for (int pos = stack.size() -1; pos >= 0; pos--) {
                Element node = stack.get(pos);
                if (node.nodeName().equals(name)) {
                    tb.generateImpliedEndTags(name);
                    if (!name.equals(tb.currentElement().nodeName()))
                        tb.error(this);
                    tb.popStackToClose(name);
                    break;
                } else {
                    if (tb.isSpecial(node)) {
                        tb.error(this);
                        return false;
                    }
                }
            }
            return true;
        }


        boolean anyOtherEndTag(Token t, HtmlTreeBuilder tb) {
            String name = t.asEndTag().normalName();
            ArrayList<Element> stack = tb.getStack();
            for (int pos = stack.size() -1; pos >= 0; pos--) {
                Element node = stack.get(pos);
                if (node.nodeName().equals(name)) {
                    tb.generateImpliedEndTags(name);
                    if (!name.equals(tb.currentElement().nodeName()))
                        tb.error(this);
                    tb.popStackToClose(name);
                    break;
                } else {
                    if (tb.isSpecial(node)) {
                        tb.error(this);
                        return false;
                    }
                }
            }
            return true;
        }


    protected final JsonDeserializer<Object> _findDeserializer(DeserializationContext ctxt,
            String typeId) throws IOException
    {
        JsonDeserializer<Object> deser = _deserializers.get(typeId);
        if (deser == null) {
            JavaType type = _idResolver.typeFromId(ctxt, typeId);
            if (type == null) {
                deser = _findDefaultImplDeserializer(ctxt);
                if (deser == null) {
                    JavaType actual = _handleUnknownTypeId(ctxt, typeId);
                    if (actual == null) {
                        return NullifyingDeserializer.instance;
                    }
                    deser = ctxt.findContextualValueDeserializer(actual, _property);
                }
            } else {
                if ((_baseType != null)
                        && _baseType.getClass() == type.getClass()) {
                    if (!type.hasGenericTypes()) {
                        type = ctxt.getTypeFactory().constructSpecializedType(_baseType, type.getRawClass());
                    }
                }
                deser = ctxt.findContextualValueDeserializer(type, _property);
            }
            _deserializers.put(typeId, deser);
        }
        return deser;
    }


    protected final JsonDeserializer<Object> _findDeserializer(DeserializationContext ctxt,
            String typeId) throws IOException
    {
        JsonDeserializer<Object> deser = _deserializers.get(typeId);
        if (deser == null) {
            JavaType type = _idResolver.typeFromId(ctxt, typeId);
            if (type == null) {
                deser = _findDefaultImplDeserializer(ctxt);
                if (deser == null) {
                    JavaType actual = _handleUnknownTypeId(ctxt, typeId);
                    if (actual == null) {
                        return null;
                    }
                    deser = ctxt.findContextualValueDeserializer(actual, _property);
                }
            } else {
                if ((_baseType != null)
                        && _baseType.getClass() == type.getClass()) {
                    if (!type.hasGenericTypes()) {
                        type = ctxt.getTypeFactory().constructSpecializedType(_baseType, type.getRawClass());
                    }
                }
                deser = ctxt.findContextualValueDeserializer(type, _property);
            }
            _deserializers.put(typeId, deser);
        }
        return deser;
    }


    protected final double doSolve() {
        double x0 = getMin();
        double x1 = getMax();
        double f0 = computeObjectiveValue(x0);
        double f1 = computeObjectiveValue(x1);
        if (f0 == 0.0) {
            return x0;
        }
        if (f1 == 0.0) {
            return x1;
        }
        verifyBracketing(x0, x1);
        final double ftol = getFunctionValueAccuracy();
        final double atol = getAbsoluteAccuracy();
        final double rtol = getRelativeAccuracy();
        boolean inverted = false;
        while (true) {
            final double x = x1 - ((f1 * (x1 - x0)) / (f1 - f0));
            final double fx = computeObjectiveValue(x);
            if (fx == 0.0) {
                return x;
            }
            if (f1 * fx < 0) {
                x0 = x1;
                f0 = f1;
                inverted = !inverted;
            } else {
                switch (method) {
                case ILLINOIS:
                    f0 *= 0.5;
                    break;
                case PEGASUS:
                    f0 *= f1 / (f1 + fx);
                    break;
                case REGULA_FALSI:
                    if (x == x1) {
                        final double delta = FastMath.max(rtol * FastMath.abs(x1),
                                                          atol);
                        x0 = 0.5 * (x0 + x1 - delta);
                        f0 = computeObjectiveValue(x0);
                    }
                    break;
                default:
                    throw new MathInternalError();
                }
            }
            x1 = x;
            f1 = fx;
            if (FastMath.abs(f1) <= ftol) {
                switch (allowed) {
                case ANY_SIDE:
                    return x1;
                case LEFT_SIDE:
                    if (inverted) {
                        return x1;
                    }
                    break;
                case RIGHT_SIDE:
                    if (!inverted) {
                        return x1;
                    }
                    break;
                case BELOW_SIDE:
                    if (f1 <= 0) {
                        return x1;
                    }
                    break;
                case ABOVE_SIDE:
                    if (f1 >= 0) {
                        return x1;
                    }
                    break;
                default:
                    throw new MathInternalError();
                }
            }
            if (FastMath.abs(x1 - x0) < FastMath.max(rtol * FastMath.abs(x1),
                                                     atol)) {
                switch (allowed) {
                case ANY_SIDE:
                    return x1;
                case LEFT_SIDE:
                    return inverted ? x1 : x0;
                case RIGHT_SIDE:
                    return inverted ? x0 : x1;
                case BELOW_SIDE:
                    return (f1 <= 0) ? x1 : x0;
                case ABOVE_SIDE:
                    return (f1 >= 0) ? x1 : x0;
                default:
                    throw new MathInternalError();
                }
            }
        }
    }


    protected final double doSolve() {
        double x0 = getMin();
        double x1 = getMax();
        double f0 = computeObjectiveValue(x0);
        double f1 = computeObjectiveValue(x1);
        if (f0 == 0.0) {
            return x0;
        }
        if (f1 == 0.0) {
            return x1;
        }
        verifyBracketing(x0, x1);
        final double ftol = getFunctionValueAccuracy();
        final double atol = getAbsoluteAccuracy();
        final double rtol = getRelativeAccuracy();
        boolean inverted = false;
        while (true) {
            final double x = x1 - ((f1 * (x1 - x0)) / (f1 - f0));
            final double fx = computeObjectiveValue(x);
            if (fx == 0.0) {
                return x;
            }
            if (f1 * fx < 0) {
                x0 = x1;
                f0 = f1;
                inverted = !inverted;
            } else {
                switch (method) {
                case ILLINOIS:
                    f0 *= 0.5;
                    break;
                case PEGASUS:
                    f0 *= f1 / (f1 + fx);
                    break;
                default:
                }
            }
            x1 = x;
            f1 = fx;
            if (FastMath.abs(f1) <= ftol) {
                switch (allowed) {
                case ANY_SIDE:
                    return x1;
                case LEFT_SIDE:
                    if (inverted) {
                        return x1;
                    }
                    break;
                case RIGHT_SIDE:
                    if (!inverted) {
                        return x1;
                    }
                    break;
                case BELOW_SIDE:
                    if (f1 <= 0) {
                        return x1;
                    }
                    break;
                case ABOVE_SIDE:
                    if (f1 >= 0) {
                        return x1;
                    }
                    break;
                default:
                    throw new MathInternalError();
                }
            }
            if (FastMath.abs(x1 - x0) < FastMath.max(rtol * FastMath.abs(x1),
                                                     atol)) {
                switch (allowed) {
                case ANY_SIDE:
                    return x1;
                case LEFT_SIDE:
                    return inverted ? x1 : x0;
                case RIGHT_SIDE:
                    return inverted ? x0 : x1;
                case BELOW_SIDE:
                    return (f1 <= 0) ? x1 : x0;
                case ABOVE_SIDE:
                    return (f1 >= 0) ? x1 : x0;
                default:
                    throw new MathInternalError();
                }
            }
        }
    }


        public int parseInto(DateTimeParserBucket bucket, String text, int position) {
            String str = text.substring(position);
            String best = null;
            for (String id : ALL_IDS) {
                if (str.startsWith(id)) {
                	if (best == null || id.length() > best.length()) {
                		best = id;
                	}
                }
            }
            if (best != null) {
                bucket.setZone(DateTimeZone.forID(best));
                return position + best.length();
            }
            return ~position;
        }


        public int parseInto(DateTimeParserBucket bucket, String text, int position) {
            String str = text.substring(position);
            for (String id : ALL_IDS) {
                if (str.startsWith(id)) {
                    bucket.setZone(DateTimeZone.forID(id));
                    return position + id.length();
                }
            }
            return ~position;
        }


    public byte[] getBinaryValue(Base64Variant b64variant)
        throws IOException, JsonParseException
    {
        JsonNode n = currentNode();
        if (n != null) {
            if (n instanceof TextNode) {
                return ((TextNode) n).getBinaryValue(b64variant);
            }
            return n.binaryValue();
        }
        return null;
    }


    public byte[] getBinaryValue(Base64Variant b64variant)
        throws IOException, JsonParseException
    {
        JsonNode n = currentNode();
        if (n != null) {
            byte[] data = n.binaryValue();
            if (data != null) {
                return data;
            }
            if (n.isPojo()) {
                Object ob = ((POJONode) n).getPojo();
                if (ob instanceof byte[]) {
                    return (byte[]) ob;
                }
            }
        }
        return null;
    }


    private boolean inSpecificScope(String[] targetNames, String[] baseTypes, String[] extraTypes) {
        final int bottom = stack.size() -1;
        final int top = bottom > MaxScopeSearchDepth ? bottom - MaxScopeSearchDepth : 0;
        for (int pos = bottom; pos >= top; pos--) {
            final String elName = stack.get(pos).nodeName();
            if (inSorted(elName, targetNames))
                return true;
            if (inSorted(elName, baseTypes))
                return false;
            if (extraTypes != null && inSorted(elName, extraTypes))
                return false;
        }
        return false;
    }


    private boolean inSpecificScope(String[] targetNames, String[] baseTypes, String[] extraTypes) {
        int bottom = stack.size() -1;
        if (bottom > MaxScopeSearchDepth) {
            bottom = MaxScopeSearchDepth;
        }
        final int top = bottom > MaxScopeSearchDepth ? bottom - MaxScopeSearchDepth : 0;
        for (int pos = bottom; pos >= top; pos--) {
            final String elName = stack.get(pos).nodeName();
            if (inSorted(elName, targetNames))
                return true;
            if (inSorted(elName, baseTypes))
                return false;
            if (extraTypes != null && inSorted(elName, extraTypes))
                return false;
        }
        return false;
    }


  static Type getSupertype(Type context, Class<?> contextRawType, Class<?> supertype) {
    if (context instanceof WildcardType) {
      context = ((WildcardType)context).getUpperBounds()[0];
    }
    checkArgument(supertype.isAssignableFrom(contextRawType));
    return resolve(context, contextRawType,
        $Gson$Types.getGenericSupertype(context, contextRawType, supertype));
  }


  static Type getSupertype(Type context, Class<?> contextRawType, Class<?> supertype) {
    checkArgument(supertype.isAssignableFrom(contextRawType));
    return resolve(context, contextRawType,
        $Gson$Types.getGenericSupertype(context, contextRawType, supertype));
  }


  private VariableLiveness isVariableReadBeforeKill(
      Node n, String variable) {
    if (NodeUtil.isName(n) && variable.equals(n.getString())) {
      if (NodeUtil.isLhs(n, n.getParent())) {
        Preconditions.checkState(n.getParent().getType() == Token.ASSIGN);
        Node rhs = n.getNext();
        VariableLiveness state = isVariableReadBeforeKill(rhs, variable);
        if (state == VariableLiveness.READ) {
          return state;
        }
        return VariableLiveness.KILL;
      } else {
        return VariableLiveness.READ;
      }
    }
    for (Node child = n.getFirstChild();
        child != null; child = child.getNext()) {
      if (!ControlFlowGraph.isEnteringNewCfgNode(child)) {
        VariableLiveness state = isVariableReadBeforeKill(child, variable);
        if (state != VariableLiveness.MAYBE_LIVE) {
          return state;
        }
      }
    }
    return VariableLiveness.MAYBE_LIVE;
  }


  private VariableLiveness isVariableReadBeforeKill(
      Node n, String variable) {
    if (NodeUtil.isName(n) && variable.equals(n.getString())) {
      if (NodeUtil.isLhs(n, n.getParent())) {
        return VariableLiveness.KILL;
      } else {
        return VariableLiveness.READ;
      }
    }
    for (Node child = n.getFirstChild();
        child != null; child = child.getNext()) {
      if (!ControlFlowGraph.isEnteringNewCfgNode(child)) {
        VariableLiveness state = isVariableReadBeforeKill(child, variable);
        if (state != VariableLiveness.MAYBE_LIVE) {
          return state;
        }
      }
    }
    return VariableLiveness.MAYBE_LIVE;
  }


    boolean matchesLetter() {
        if (isEmpty())
            return false;
        char c = input[pos];
        return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || Character.isLetter(c);
    }


    boolean matchesLetter() {
        if (isEmpty())
            return false;
        char c = input[pos];
        return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
    }


    public void addValue(Object v) {
        if (v instanceof Comparable<?>){
            addValue((Comparable<?>) v);
        } else {
            throw new IllegalArgumentException("Object must implement Comparable");
        }
    }


    public void addValue(Object v) {
            addValue((Comparable<?>) v);
    }