/**
   * Encodes {@code value}.
   *
   * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer, Long, Double or
   *     null. May not be {@link Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}.
   * @return this stringer.
   */
  public JSONStringer value(Object value) throws JSONException {
    if (stack.isEmpty()) {
      throw new JSONException("Nesting problem");
    }

    if (value instanceof JSONArray) {
      ((JSONArray) value).writeTo(this);
      return this;

    } else if (value instanceof JSONObject) {
      ((JSONObject) value).writeTo(this);
      return this;
    }

    beforeValue();

    if (value == null || value instanceof Boolean || value == JSONObject.NULL) {
      out.append(value);

    } else if (value instanceof Number) {
      out.append(JSONObject.numberToString((Number) value));

    } else {
      string(value.toString());
    }

    return this;
  }
 /**
  * Encodes {@code value} to this stringer.
  *
  * @return this stringer.
  */
 public JSONStringer value(long value) throws JSONException {
   if (stack.isEmpty()) {
     throw new JSONException("Nesting problem");
   }
   beforeValue();
   out.append(value);
   return this;
 }
 /**
  * Encodes {@code value} to this stringer.
  *
  * @param value a finite value. May not be {@link Double#isNaN() NaNs} or {@link
  *     Double#isInfinite() infinities}.
  * @return this stringer.
  */
 public JSONStringer value(double value) throws JSONException {
   if (stack.isEmpty()) {
     throw new JSONException("Nesting problem");
   }
   beforeValue();
   out.append(JSONObject.numberToString(value));
   return this;
 }
 /** Enters a new scope by appending any necessary whitespace and the given bracket. */
 JSONStringer open(Scope empty, String openBracket) throws JSONException {
   if (stack.isEmpty() && out.length() > 0) {
     throw new JSONException("Nesting problem: multiple top-level roots");
   }
   beforeValue();
   stack.add(empty);
   out.append(openBracket);
   return this;
 }