function Identity() {
    //http://www.javascripter.net/faq/browsern.htm
    var nVer, nAgt, browserName, fullVersion, build, revision, minorVersion, majorVersion, getVersionInfoA, verOffset, browserToken;
    nVer = navigator.appVersion;
    nAgt = navigator.userAgent;
    browserName = '';
    fullVersion = 0;
    // added revision build and release, <major>.<minor>.<revision>.<build> <release> where release is alpha,beta,rc,rtm,debug
    build = null;
    revision = null;
    release = '';
    minorVersion = 0;
    majorVersion = 0;
    getVersionInfoA = function(token,forceName) {
        browserToken = arguments[0];
        var tokenLength, trueVerOffset, r;
        tokenLength = browserToken.length;
        verOffset = nAgt.indexOf(browserToken);
        trueVerOffset = verOffset + tokenLength + 1;
        if (verOffset != -1) {
            browserName = browserToken;
            // changed to use regular expressions to handle versions with revision/builds e.g. v3.0.1.0
            fullVersion = nAgt.substring(trueVerOffset).match(/[0-9.]+/) // nAgt.substring(trueVerOffset);
            if(fullVersion.length==1) {
                fullVersion=fullVersion[0];
                r = fullVersion.match(/[0-9]+/g).reverse();
                if (r.length>0) majorVersion = parseInt(r.pop());
                if (r.length>0) minorVersion = parseInt(r.pop());
                if (r.length>0) revision = parseInt(r.pop());
                if (r.length>0) build = parseInt(r.pop());
                //minorVersion = parseFloat(nAgt.substring(trueVerOffset)).toFixed(2);
                //majorVersion = parseInt('' + fullVersion);
                if(typeof forceName=='string')browserToken=forceName;
                return true;
            }
        }
        return false;
    };
    // In Internet Explorer, the true version is after "MSIE" in userAgent
    if (getVersionInfoA("MSIE")) {
        browserName = "Microsoft Internet Explorer";
    }
    // In Opera, the true version is after "Opera"
    else if (getVersionInfoA("Opera")) {
        // do nothing
    }
    //added: Netscape
    else if (getVersionInfoA("Navigator")) {
        browserName = "Netscape Navigator";
    }
    // In Firefox, the true version is after "Firefox"
    else if (getVersionInfoA("Firefox")) {
        // do nothing
    }
    /* added Minefield (Mozilla-x64) detection - Matthew Guscott */
    else if (getVersionInfoA("Minefield","Firefox")) {
    }
    /* added SeaMonkey detection - Matthew Guscott */
    // same as Firefox
    else if (getVersionInfoA("SeaMonkey")) {
        // do nothing
    }
    /* added Chrome detection - Matthew Guscott */
    // same as Firefox
    else if (getVersionInfoA("Chrome")) {
        browserName = "Google Chrome";
    }
    // In most other browsers, "name/version" is at the end of userAgent 
    else if ((nameOffset = nAgt.lastIndexOf(' ') + 1) < (verOffset = nAgt.lastIndexOf('/'))) {
        browserName = nAgt.substring(nameOffset, verOffset);
        fullVersion = nAgt.substring(verOffset + 1);
        minorVersion = parseFloat(nAgt.substring(verOffset + 1));
        if (!isNaN(minorVersion)) majorVersion = parseInt('' + fullVersion); else { fullVersion = 0; minorVersion = 0; majorVersion = 0; }
    } else {
        alert('you are using an un-recognised browser, or a beta/pre-release version,\nwhich may cause some incompatabilities with this site.');
    }
    // Finally, if no name and/or no version detected from userAgent...
    if (browserName.toLowerCase() == browserName.toUpperCase() || fullVersion == 0 || majorVersion == 0) {
        browserName = navigator.appName;
        fullVersion = nVer;
        minorVersion = parseFloat(nVer);
        majorVersion = parseInt(nVer);
    }
    var platform;
    switch (navigator.platform) {
        case "Win32": platform = "Windows"; break;
        case "Mac": default: platform = navigator.platform; break;
        case "Linux": platform = "Posix"; break;
    }
    this.BrowserToken = function() {return browserToken; };
    this.BrowserName = function() { return browserName; };
    this.FullVersion = function() { return fullVersion; };
    this.MajorVersion = function() { return majorVersion; };
    this.MinorVersion = function() { return minorVersion; };
    this.Revision = function() {return typeof revision=='number'?revision:null;}; // added
    this.Build = function() {return typeof build=='number'?build:null;}; // added
    this.AppName = function() { return navigator.appName; };
    this.UserAgent = function() { return navigator.userAgent; };
    this.Platform = function() { return platform; };
    
    // [added]
    // Browser Features
    this.Features = {push:function(K,V){this[K]=V;return this[K];}};
    with (this.Features) {
        try { push('XMLHttpRequest', (typeof window.XMLHttpRequest == 'function' || (window.XMLHttpRequest && typeof window.XMLHttpRequest == 'object'))); } catch (e) { push('XMLHttpRequest', false); }
        try{push('ActiveX',(typeof window.ActiveXObject == 'function'));}catch(e){push('ActiveX',false);}
        try{push('XPath',(typeof document.evaluate == 'function'));}catch(e){push('XPath',false);}
        with(push('DOM',{push:function(K,V){this[K]=V;return this[K];}})) {
            try{push('prototypes',(typeof window.DOMPrototype == 'object' && window.DOMPrototype instanceof DOMPrototype));}catch(e){push('prototypes',false);}
        }
        with(push('magic',{push:function(K,V){this[K]=V;return this[K];}})) {
            try{push('defineGetter',(typeof Object.prototype.__defineGetter__ == 'function'));}catch(e){push('defineGetter',false);}
            try{push('defineSetter',(typeof Object.prototype.__defineSetter__ == 'function'));}catch(e){push('defineSetter',false);}
            try{push('undefineGetter',(typeof Object.prototype.__undefineGetter__ == 'function'));}catch(e){push('undefineGetter',false);}
            try{push('undefineSetter',(typeof Object.prototype.__undefineSetter__ == 'function'));}catch(e){push('undefineSetter',false);}
            try{push('lookupGetter',(typeof Object.prototype.__lookupGetter__ == 'function'));}catch(e){push('lookupGetter',false);}
            try{push('lookupSetter',(typeof Object.prototype.__lookupSetter__ == 'function'));}catch(e){push('lookupSetter',false);}
        }
    }
    // from xpath lib
    var uai = new function() {

        var ua = navigator.userAgent;

        if (RegExp == undefined) {
            if (ua.indexOf("Opera") >= 0) {
                this.opera = true;
            } else if (ua.indexOf("Netscape") >= 0) {
                this.netscape = true;
            } else if (ua.indexOf("Mozilla/") == 0) {
                this.mozilla = true;
            } else {
                this.unknown = true;
            }

            if (ua.indexOf("Gecko/") >= 0) {
                this.gecko = true;
            }

            if (ua.indexOf("Win") >= 0) {
                this.windows = true;
            } else if (ua.indexOf("Mac") >= 0) {
                this.mac = true;
            } else if (ua.indexOf("Linux") >= 0) {
                this.linux = true;
            } else if (ua.indexOf("BSD") >= 0) {
                this.bsd = true;
            } else if (ua.indexOf("SunOS") >= 0) {
                this.sunos = true;
            }
        }
        else {

            /* for Trident/Tasman */
            /*@cc_on
            @if (@_jscript)
                function jscriptVersion() {
                    switch (@_jscript_version) {
                        case 3.0:  return "4.0";
                        case 5.0:  return "5.0";
                        case 5.1:  return "5.01";
                        case 5.5:  return "5.5";
                        case 5.6:
                            if ("XMLHttpRequest" in window) return "7.0";
                            return "6.0";
                        case 5.7:
                            return "7.0";
                        default:   return true;
                    }
                }
                if (@_win16 || @_win32 || @_win64) {
                    this.windows = true;
                    this.trident = jscriptVersion();
                } else if (@_mac || navigator.platform.indexOf("Mac") >= 0) {
                    // '@_mac' may be 'NaN' even if the platform is Mac,
                    // so we check 'navigator.platform', too.
                    this.mac = true;
                    this.tasman = jscriptVersion();
                }
                if (/MSIE (\d+\.\d+)b?;/.test(ua)) {
                    this.ie = RegExp.$1;
                    this['ie' + RegExp.$1.charAt(0)] = true;
                }
            @else @*/

            /* for AppleWebKit */
            if (/AppleWebKit\/(\d+(?:\.\d+)*)/.test(ua)) {
                this.applewebkit = RegExp.$1;
                if (RegExp.$1.charAt(0) == 4) {
                    this.applewebkit2 = true;
                }
                else {
                    this.applewebkit3 = true;
                }
            }

            /* for Gecko */
            else if (typeof Components == "object" &&
                     (/Gecko\/(\d{8})/.test(ua) ||
                      navigator.product == "Gecko" && /^(\d{8})$/.test(navigator.productSub))) {
                this.gecko = RegExp.$1;
            }

            /*@end @*/

            if (typeof(opera) == "object" && typeof(opera.version) == "function") {
                this.opera = opera.version();
                this['opera' + this.opera[0] + this.opera[2]] = true;
            } else if (typeof opera == "object"
                    && (/Opera[\/ ](\d+\.\d+)/.test(ua))) {
                this.opera = RegExp.$1;
            } else if (this.ie) {
            } else if (/Safari\/(\d+(?:\.\d+)*)/.test(ua)) {
                this.safari = RegExp.$1;
            } else if (/NetFront\/(\d+(?:\.\d+)*)/.test(ua)) {
                this.netfront = RegExp.$1;
            } else if (/Konqueror\/(\d+(?:\.\d+)*)/.test(ua)) {
                this.konqueror = RegExp.$1;
            } else if (ua.indexOf("(compatible;") < 0
                    && (/^Mozilla\/(\d+\.\d+)/.test(ua))) {
                this.mozilla = RegExp.$1;
                if (/\([^(]*rv:(\d+(?:\.\d+)*).*?\)/.test(ua))
                    this.mozillarv = RegExp.$1;
                if (/Firefox\/(\d+(?:\.\d+)*)/.test(ua)) {
                    this.firefox = RegExp.$1;
                } else if (/Netscape\d?\/(\d+(?:\.\d+)*)/.test(ua)) {
                    this.netscape = RegExp.$1;
                }
            } else {
                this.unknown = true;
            }

            if (ua.indexOf("Win 9x 4.90") >= 0) {
                this.windows = "ME";
            } else if (/Win(?:dows)? ?(NT ?(\d+\.\d+)?|\d+|ME|Vista|XP)/.test(ua)) {
                this.windows = RegExp.$1;
                if (RegExp.$2) {
                    this.winnt = RegExp.$2;
                } else switch (RegExp.$1) {
                    case "2000":   this.winnt = "5.0";  break;
                    case "XP":     this.winnt = "5.1";  break;
                    case "Vista":  this.winnt = "6.0";  break;
                }
            } else if (ua.indexOf("Mac") >= 0) {
                this.mac = true;
            } else if (ua.indexOf("Linux") >= 0) {
                this.linux = true;
            } else if (/(\w*BSD)/.test(ua)) {
                this.bsd = RegExp.$1;
            } else if (ua.indexOf("SunOS") >= 0) {
                this.sunos = true;
            }
        }
    };
    this.uai=uai;
    // end [added]

    // cross browser compliant
    this.DesktopWidth = function() { return screen.availWidth; };
    this.DesktopHeight = function() { return screen.availHeight; };
    this.DisplayWidth = function() { return screen.width; };
    this.DisplayHeight = function() { return screen.height; };
    this.DisplayDepth = function() { return screen.colorDepth; };
    this.isIE = this.BrowserName() == "Microsoft Internet Explorer";
    this.isFF = this.BrowserName() == "Firefox";
    this.isNN = this.BrowserName() == "Netscape Navigator";
    this.isOpera = this.BrowserName() == "Opera";
    this.isSafari = this.BrowserName() == "Safari";
    this.isSeaMonkey = this.BrowserName() == "SeaMonkey";
    this.isChrome = this.BrowserName() == "Google Chrome";

    if (this.isIE) this.BrowserID = "IE";
    else {
        if (this.isFF) this.BrowserID = "FF";
        else if (this.isNN) this.BrowserID = "NN";
        else if (this.isOpera) this.BrowserID = "O";
        else if (this.isSafari) this.BrowserID = "S";
        else if (this.isSeaMonkey) this.BrowserID = "SM";
        else if (this.isChrome) this.BrowserID = "C";
        else this.BrowserID = "?";
        if (this.BrowserID != "?") this.isFF = true; //need to check any compatability issues with assuming known non-IE browsers are compliant with FF
    }
    this.BrowserVID = (this.BrowserID + majorVersion);
    eval('this.is' + this.BrowserVID + '=true;');
    this.setInstance = function(_browserName, _majorVer, _minorVer, _fullVer) {
        browserName = _browserName;
        fullVersion = _fullVer;
        majorVersion = _majorVer;
        minorVersion = _minorVer;
        revision = null;
        build = null;

        this.isIE = this.BrowserName() == "Microsoft Internet Explorer";
        this.isFF = this.BrowserName() == "Firefox";
        this.isNN = this.BrowserName() == "Netscape Navigator";
        this.isOpera = this.BrowserName() == "Opera";
        this.isSafari = this.BrowserName() == "Safari";
        this.isSeaMonkey = this.BrowserName() == "SeaMonkey";
        this.isChrome = this.BrowserName() == "Google Chrome";
        if (this.isIE) this.BrowserID = "IE";
        else {
            if (this.isFF) this.BrowserID = "FF";
            else if (this.isNN) this.BrowserID = "NN";
            else if (this.isOpera) this.BrowserID = "O";
            else if (this.isSafari) this.BrowserID = "S";
            else if (this.isSeaMonkey) this.BrowserID = "SM";
            else if (this.isChrome) this.BrowserID = "C";
            else this.BrowserID = "?";
            if (this.BrowserID != "?") this.isFF = true; //need to check any compatability issues with assuming known non-IE browsers are compliant with FF
        }
        this.BrowserVID = (this.BrowserID + majorVersion);
        eval('this.is' + this.BrowserVID + '=true;');
    };
};
Identity.instance=null;
Identity.getInstance = function() {
    if (Identity.instance == null) {
        Identity.instance = new Identity();
    }
    return Identity.instance;
};
Identity.prototype.toString = function() {
    var format = "Browser: %s[Name:%s, Version: %s(%f), Platform: %s\nUserAgent: %s]\n\nDisplay: [resolution:%dx%d@%dbpp, desktop:%dx%d]";
    return sprintf(format, this.BrowserVID, this.BrowserName(), this.FullVersion(), this.MinorVersion(), this.Platform(), this.UserAgent(), this.DisplayWidth(), this.DisplayHeight(), this.DisplayDepth(), this.DesktopWidth(), this.DesktopHeight());
};
var CLIENTID = Identity.getInstance();
