class ContextTools {

  private int contextSize = 40;
  private boolean escapeHtml = true;
  private String errorMarkerStart = "<b><font bgcolor=\"#ff8b8b\">";
  private String errorMarkerEnd = "</font></b>";

  public ContextTools() {
  }

  public String getContext(int fromPos, int toPos, String contents) {<FILL_FUNCTION_BODY>}

  /**
   * Get a plain text context that uses {@code ^} characters in a new line as a marker of the
   * given string region. Ignores {@link #setEscapeHtml(boolean)}.
   * @since 2.3
   */
  public String getPlainTextContext(int fromPos, int toPos, String contents) {
    // calculate context region:
    int startContent = fromPos - contextSize;
    String prefix = "...";
    String postfix = "...";
    if (startContent < 0) {
      prefix = "";
      startContent = 0;
    }
    int endContent = toPos + contextSize;
    if (endContent > contents.length()) {
      postfix = "";
      endContent = contents.length();
    }
    return prefix +
           contents.substring(startContent, endContent).replace('\n', ' ').replace('\r', ' ').replace('\t', ' ') +
           postfix + '\n' +
           getMarker(fromPos, toPos, startContent, endContent, prefix);
  }

  /**
   * Set the string used to mark the beginning and end of an error, e.g. {@code <span class="error">} and {@code </span>}
   * @since 5.1
   */
  public void setErrorMarker(String start, String end) {
    errorMarkerStart = start;
    errorMarkerEnd = end;
  }

  /**
   * Set the string used to mark the beginning of an error, e.g. {@code <span class="error">}
   */
  public void setErrorMarkerStart(String errorMarkerStart) {
    this.errorMarkerStart = errorMarkerStart;
  }

  /**
   * Set the string used to mark the end of an error, e.g. {@code </span>}
   */
  public void setErrorMarkerEnd(String errorMarkerEnd) {
    this.errorMarkerEnd = errorMarkerEnd;
  }

  /**
   * The context size of the error. This many characters of the original text will be used
   * from the left and from the right context of the error.
   */
  public void setContextSize(int contextSize) {
    this.contextSize = contextSize;
  }

  /**
   * Whether HTML special characters should be escaped.
   */
  public void setEscapeHtml(boolean escapeHtml) {
    this.escapeHtml = escapeHtml;
  }

  private static String getMarker(int fromPos, int toPos, int startContent, int endContent, String prefix) {
    return StringUtils.repeat(' ', prefix.length() + fromPos - startContent) +
           StringUtils.repeat('^', toPos - fromPos) +
           StringUtils.repeat(' ', endContent - toPos);
  }
}

    // calculate context region:
    int startContent = fromPos - contextSize;
    String prefix = "...";
    String postfix = "...";
    if (startContent < 0) {
      prefix = "";
      startContent = 0;
    }
    int endContent = toPos + contextSize;
    int textLength = contents.length();
    if (endContent > textLength) {
      postfix = "";
      endContent = textLength;
    }
    // now build context string plus marker:
    StringBuilder sb = new StringBuilder();
    sb.append(prefix);
    sb.append(contents.substring(startContent, endContent).replace('\n', ' '));
    String markerStr = getMarker(fromPos, toPos, startContent, endContent, prefix);
    sb.append(postfix);
    int startMark = markerStr.indexOf('^');
    int endMark = markerStr.lastIndexOf('^');
    String result = sb.toString();
    if (escapeHtml) {
      String escapedErrorPart = StringTools.escapeHTML(result.substring(startMark, endMark + 1))
              .replace(" ", "&nbsp;");   // make sure whitespace errors are visible
      result = StringTools.escapeHTML(result.substring(0, startMark))
          + errorMarkerStart
          + escapedErrorPart
          + errorMarkerEnd + StringTools.escapeHTML(result.substring(endMark + 1));
    } else {
      result = result.substring(0, startMark) + errorMarkerStart
          + result.substring(startMark, endMark + 1) + errorMarkerEnd
          + result.substring(endMark + 1);
    }
    return result;
  
<no_super_class>