docs: function computeStackTraceFromOperaMultiLineMessage(ex) {
          // Opera includes a stack trace into the exception message. An example is:
          //
          // Statement on line 3: Undefined variable: undefinedFunc
          // Backtrace:
          //   Line 3 of linked script file://localhost/Users/andreyvit/Projects/TraceKit/javascript-client/sample.js: In function zzz
          //         undefinedFunc(a);
          //   Line 7 of inline#1 script in file://localhost/Users/andreyvit/Projects/TraceKit/javascript-client/sample.html: In function yyy
          //           zzz(x, y, z);
          //   Line 3 of inline#1 script in file://localhost/Users/andreyvit/Projects/TraceKit/javascript-client/sample.html: In function xxx
          //           yyy(a, a, a);
          //   Line 1 of function script
          //     try { xxx('hi'); return false; } catch(ex) { TraceKit.report(ex); }
          //   ...
  
          var lines = ex.message.split('\n');
          if (lines.length < 4) {
              return null;
          }
  
          var lineRE1 = /^\s*Line (\d+) of linked script ((?:file|http|https)\S+)(?:: in function (\S+))?\s*$/i,
              lineRE2 = /^\s*Line (\d+) of inline#(\d+) script in ((?:file|http|https)\S+)(?:: in function (\S+))?\s*$/i,
              lineRE3 = /^\s*Line (\d+) of function script\s*$/i,
              stack = [],
              scripts = document.getElementsByTagName('script'),
              inlineScriptBlocks = [],
              parts,
              i,
              len,
              source;
  
          for (i in scripts) {
              if (scripts.hasOwnProperty(i) && !scripts[i].src) {
                  inlineScriptBlocks.push(scripts[i]);
              }
          }
  
          for (i = 2, len = lines.length; i < len; i += 2) {
              var item = null;
              if ((parts = lineRE1.exec(lines[i]))) {
                  item = {
                      'url': parts[2],
                      'func': parts[3],
                      'line': +parts[1]
                  };
              } else if ((parts = lineRE2.exec(lines[i]))) {
                  item = {
                      'url': parts[3],
                      'func': parts[4]
                  };
                  var relativeLine = (+parts[1]); // relative to the start of the <SCRIPT> block
                  var script = inlineScriptBlocks[parts[2] - 1];
                  if (script) {
                      source = getSource(item.url);
                      if (source) {
                          source = source.join('\n');
                          var pos = source.indexOf(script.innerText);
                          if (pos >= 0) {
                              item.line = relativeLine + source.substring(0, pos).split('\n').length;
                          }
                      }
                  }
              } else if ((parts = lineRE3.exec(lines[i]))) {
                  var url = window.location.href.replace(/#.*$/, ''),
                      line = parts[1];
                  var re = new RegExp(escapeCodeAsRegExpForMatchingInsideHTML(lines[i + 1]));
                  source = findSourceInUrls(re, [url]);
                  item = {
                      'url': url,
                      'line': source ? source.line : line,
                      'func': ''
                  };
              }
  
              if (item) {
                  if (!item.func) {
                      item.func = guessFunctionName(item.url, item.line);
                  }
                  var context = gatherContext(item.url, item.line);
                  var midline = (context ? context[Math.floor(context.length / 2)] : null);
                  if (context && midline.replace(/^\s*/, '') === lines[i + 1].replace(/^\s*/, '')) {
                      item.context = context;
                  } else {
                      // if (context) alert("Context mismatch. Correct midline:\n" + lines[i+1] + "\n\nMidline:\n" + midline + "\n\nContext:\n" + context.join("\n") + "\n\nURL:\n" + item.url);
                      item.context = [lines[i + 1]];
                  }
                  stack.push(item);
              }
          }
          if (!stack.length) {
              return null; // could not parse multiline exception message as Opera stack trace
          }
  
          return {
              'mode': 'multiline',
              'name': ex.name,
              'message': lines[0],
              'url': document.location.href,
              'stack': stack,
              'useragent': navigator.userAgent
          };
      }