function callstack() {
    function StackFrame(funcName, funcSource, flName, lnNumber) {
        this.functionName = funcName;
        this.functionSource = funcSource;
        this.fileName = flName;
        this.lineNumber = lnNumber;
    }
    StackFrame.prototype.toString = function() {
        return 'at ' + this.functionName + '(' + this.fileName + ':' +  this.lineNumber + ')' ;
    };
    StackFrame.prototype.toHtml = function() {
        return '<table border="0">' +
        '<tr valign="top"><td><b>Name:  </b></td><td>'           + this.functionName                + '</td></tr>' +
        '<tr valign="top"><td><b>File:  </b></td><td>'           + this.fileName                    + '</td></tr>' +
        '<tr valign="top"><td><b>Line:  </b></td><td>'           + this.lineNumber                  + '</td></tr>' +
        '<tr valign="top"><td><b>Source:</b></td><td>' +
        ( this.functionSource ?
          '<pre>' + this.functionSource.toString().replace(/\</g, '&lt;').replace(/\>/g, '&gt;') + '</pre>' :
          'unavailable')                                                                            + '</td></tr>' +
        '</table>'
        ;

    };
    var stackFrameStrings = new Error().stack.split('\n');
    // remove first two stack frames
    stackFrameStrings.splice(0,2);
    var stackFrames = [];
    for (var i in stackFrameStrings) {
        // a stack frame string split into parts
        var stackFrame = stackFrameStrings[i].split('@');
        if (stackFrame && stackFrame.length == 2) {
            stackFrames.push(
            // Stackframe object
            new StackFrame(stackFrame[0],
                           eval(stackFrame[0].replace(callstack.sansParenthesisRE,'')),
                           stackFrame[1].match(callstack.fileNameLineNumberRE)[1], // first group
                           stackFrame[1].match(callstack.fileNameLineNumberRE)[2]  // second group
            )
            );
        }
    }
    return stackFrames;
}
callstack.sansParenthesisRE = /[(][^)]*[)]/;
callstack.fileNameLineNumberRE = /(.*):(\d+)$/;
