CodeMirror.runMode = function(string, modespec, callback, options) {

function esc(str) {
  return str.replace(/[<&]/g, function(ch) { return ch == "<" ? "&lt;" : "&amp;"; });
}

var mode = CodeMirror.getMode(CodeMirror.defaults, modespec);
var isNode = callback.nodeType == 1;
var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;
if (isNode) {
  var node = callback, accum = [], col = 0;
  callback = function(text, style) {
    if (text == "\n") {
      accum.push("<br>");
      col = 0;
      return;
    }
    var escaped = "";
    // HTML-escape and replace tabs
    for (var pos = 0;;) {
      var idx = text.indexOf("\t", pos);
      if (idx == -1) {
        escaped += esc(text.slice(pos));
        col += text.length - pos;
        break;
      } else {
        col += idx - pos;
        escaped += esc(text.slice(pos, idx));
        var size = tabSize - col % tabSize;
        col += size;
        for (var i = 0; i < size; ++i) escaped += " ";
        pos = idx + 1;
      }
    }

    if (style) 
      accum.push("<span class=\"cm-" + esc(style) + "\">" + escaped + "</span>");
    else
      accum.push(escaped);
  };
}
var lines = CodeMirror.splitLines(string), state = CodeMirror.startState(mode);
for (var i = 0, e = lines.length; i < e; ++i) {
  if (i) callback("\n");
  var stream = new CodeMirror.StringStream(lines[i]);
  while (!stream.eol()) {
    var style = mode.token(stream, state);
    callback(stream.current(), style, i, stream.start);
    stream.start = stream.pos;
  }
}
if (isNode)
  node.innerHTML = accum.join("");

};