package java.lang;

import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.IOException;

public class Throwable {
  private String message;
  private Object trace;
  private Throwable cause;

  public Throwable(String message, Throwable cause) {
    this.message = message;
    this.trace = trace(1);
    this.cause = cause;
  }

  public Throwable(String message) {
    this(message, null);
  }

  public Throwable(Throwable cause) {
    this(null, cause);
  }

  public Throwable() {
    this(null, null);
  }

  public Throwable getCause() {
    return cause;
  }

  public void initCause(Throwable e) {
    if (cause == null) {
      cause = e;
    } else {
      throw new IllegalStateException();
    }
  }

  public String getMessage() {
    return message;
  }

  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append(getClass().getName());
    if (message != null) {
      sb.append(": ").append(message);
    }
    return sb.toString();
  }

  private static native Object trace(int skipCount);

  private static native StackTraceElement[] resolveTrace(Object trace);

  private StackTraceElement[] resolveTrace() {
    if (! (trace instanceof StackTraceElement[])) {
      trace = resolveTrace(trace);
    }
    return (StackTraceElement[]) trace;
  }

  public StackTraceElement[] getStackTrace() {
    return resolveTrace();
  }

  public void printStackTrace(PrintStream out) {
    StringBuilder sb = new StringBuilder();
    printStackTrace(sb, System.getProperty("line.separator"));
    out.print(sb.toString());
    out.flush();
  }

  public void printStackTrace(PrintWriter out) {
    StringBuilder sb = new StringBuilder();
    printStackTrace(sb, System.getProperty("line.separator"));
    out.print(sb.toString());
    out.flush();
  }

  public void printStackTrace() {
    printStackTrace(System.err);
  }

  private void printStackTrace(StringBuilder sb, String nl) {
    sb.append(toString()).append(nl);

    StackTraceElement[] trace = resolveTrace();
    for (int i = 0; i < trace.length; ++i) {
      sb.append("  at ")
        .append(trace[i].getClassName())
        .append(".")
        .append(trace[i].getMethodName());

      if (trace[i].isNativeMethod()) {
        sb.append(" (native)");
      } else {
        int line = trace[i].getLineNumber();
        if (line >= 0) {
          sb.append(" (line ").append(line).append(")");
        }
      }

      sb.append(nl);
    }

    if (cause != null) {
      sb.append("caused by: ");
      cause.printStackTrace(sb, nl);
    }
  }
}

@@ -586,20 +586,25 @@
  public 
-void
+Throwable
  initCau
@@ -663,16 +663,35 @@
 se = e;%0A
+      return this;%0A
     %7D el

Throwable.initCause should return 'this'