function Exception(number, source, descriptionFormat) {
    this.number = number;
    this.source = source;

    if (arguments.length > 2) {
        var args = arguments;
        descriptionFormat = descriptionFormat.replace(/{(\d)}/g, function(match, n) { return args[parseInt(n, 10) + 2]; });
    }
    this.description = descriptionFormat;

    var func, callStack = new Array();
    func = arguments.callee.caller;
    while (func) {
        callStack.push(func);
        func = func.caller;
    }
    if (callStack.length > 0)
        this.callStack = callStack;

    this.toString = function() {
        var str = "Description: " + this.description + "\nNumber: " + this.number;
        if (this.callStack) {
            var funcNames = new Array(), funcName;
            var regex = /.*function\s*([\w\d]+)/;
            for (var i = 0; i < this.callStack.length; i++) {
                funcName = regex.exec(this.callStack[i]);
                if (funcName)
                    funcNames[i] = funcName[1];
                else
                    funcNames[i] = "anonymous";
            }
            str += "\nCall stack: " + funcNames.join('->');
        }
        return str;
    };

}
String.prototype.format = function() {
    var args = arguments;
    return this.replace(/{(\d)}/g, function(match, n) { return args[parseInt(n, 10)]; });
};
String.prototype.trim = function() {
    return (/^\s*(.*?)\s*$/.exec(this)[1]);
};
Number.prototype.format = function(format) {
    var str;
    if (typeof (format) == "undefined")
        return this.toString();
    else
        str = Math.floor(this).toString();
    var specifier, n, ic, dc;
    if (typeof (format) == "object") {
        if (typeof (format.integerChars) != "undefined")
            ic = format.integerChars;
        if (typeof (format.decimalChars) != "undefined")
            dc = format.decimalChars;
        if (typeof (format.specifier) != "undefined")
            specifier = format.specifier;
    } else if (typeof (format) == "string") {
        specifier = format;
    }
    if (specifier == "c" && typeof (dc) == "undefined")
        dc = $eSRO.decimalPlaces;

    if (typeof (ic) != "undefined") {
        ic = ic - str.length;
        for (n = 0; n < ic; n++)
            str = '0' + str;
    }
    if (typeof (dc) != "undefined") {
        var d = Math.round(
            (this - Math.floor(this)) * Math.pow(10, dc)
        );
        if (d !== "")
            str += $eSRO.decimalSeparator + d;
    }
    if (typeof (specifier) != "undefined") {
        switch (specifier) {
            case "c":
                str = $eSRO.defaultCurrencySign + str;
                break;
            default:
                break;
        }
    }
    return str;
};
//Object.prototype.equals = function(other){return equals(this,other);};

function equal(a, b) {
    function contains(a, b) {
        for (member in a) {
            if (a[member].constructior != Function) {
                if (typeof (b[member]) == "undefined")
                    return false;
                else if (!equal(a[member], b[member])) {
                    return false;
                }
            }
        }
        return true;
    }
    
    if (a == b) {
        return true;
    } else if (a.constructor != b.constructor) {
        return false;
    } else if (a.constructor == String || a.constructor == Number) {
        return a == b;
    } else {
        return contains(a, b) && contains(b, a);
    }
}

function clone(o) {
    var r = new Object();
    for (member in o) {
        r[member] = o[member];
    }
    return r;
}
