﻿//Toolbar API
//FF - this class is overridden by toolbar.
//IE - this class catches all the calls IE didn't catch.

var __TPI =
{
    Result: "",

    ResetResult: function() {
        this.Result = "";
    },

    SetResult: function(strResult) {
        this.Result += strResult;
    },

    GetResult: function(bIsMultipleResponse) {
        return _TPIHelper.GetResult(this.Result, bIsMultipleResponse);
    },

    ExecuteApiFunction: function(strFuncName, strParam) {
        //do nothing
    }
};

//for Safari MAC
var _TPI = (typeof TPIObject != "undefined") ? TPIObject : __TPI;

//Wrapped JS function for IE to return Result
function _TPISetResult(strXmlResult) {
    _TPI.SetResult(strXmlResult);
};

//called from toolbar to set async result
function _TPISetAsyncResult() {
    var callbackID = arguments[0];
    var objData = _TPIHelper.callbacksHash[callbackID];
    var asyncCallback = objData.callback;
    asyncCallback(arguments, objData.state);

    //clear error timeout
    if (objData.timeout)
        clearTimeout(objData.timeout);
};

//Helper object with service functions for interaction with the toolbar.
var _TPIHelper =
{
    callbacksHash: Object(), //for IE, hash to handle sync API callbacks

    _handleAsync: function(asyncCallback, state, timeoutCallback, iTimeout) {
        //set default timeout
        if (!iTimeout) iTimeout = 15000;

        var callbackID = Math.random();
        var objData = new Object();
        objData.callback = asyncCallback;
        objData.state = state;
        if (timeoutCallback) {
            var fTimeout = function() {
                timeoutCallback(state);
            };

            objData.timeout = setTimeout(fTimeout, iTimeout);
        }
        this.callbacksHash[callbackID] = objData;

        return callbackID;
    },

    //This function interacts directly with toolbar, by calling JS functions,
    //which IE interprets as navigation, and FF gets the function itself.
    //args :        [0] -       function name
    //              [2]..[n]    function arguments
    ExecuteFunction: function(bIsMultipleResponse, args, asyncCallback, state, timeoutCallback, iTimeout) {
        _TPI.ResetResult();

        if (asyncCallback) {
            var callbackId = this._handleAsync(asyncCallback, state, timeoutCallback, iTimeout);
            args.splice(args.length - 1, 0, callbackId);
        }

        var strHref = "_TPI.ExecuteApiFunction('" + args.join("','") + "')";

        if (this.GetBrowser() == "IE") {
            var frameSrc = "about:blank#javascript:" + strHref;
            this.NavigateInIFrame(frameSrc);
        }
        else
            eval(strHref);

        if (asyncCallback)
            return true;
        else
            return _TPI.GetResult(bIsMultipleResponse);
    },

    GetBrowser: function() {
        var bVersion = "";

        if (!window.ActiveXObject)
            bVersion = "FF";
        else
            bVersion = "IE";

        return bVersion;
    },

    NavigateInIFrame: function(frameSrc) {
        var arrBody = document.getElementsByTagName('body');
        iFrame = document.createElement('iframe');
        iFrame.setAttribute("width", "0");
        iFrame.setAttribute("height", "0");
        arrBody[0].appendChild(iFrame);
        iFrame.src = frameSrc;
        arrBody[0].removeChild(iFrame);
    },

    //Parse Result XML
    //If bIsMultipleResponse = true, return array of objects, each contains response from specific toolbar.
    GetResult: function(strResult, bIsMultipleResponse) {
        var oResult = new Object();
        var arrResult = null;

        if (strResult != "") {
            strResult = "<ROOT>" + strResult + "</ROOT>";
            var oRootXML = null;
            var bIsMulty = false;

            if (window.ActiveXObject) {
                oRootXML = new ActiveXObject("Microsoft.XMLDOM");
                oRootXML.async = "false";
                oRootXML.loadXML(strResult);
                oRootXML = oRootXML.documentElement;
            }
            else {
                var parser = new DOMParser();
                oRootXML = parser.parseFromString(strResult, "text/xml");
                oRootXML = oRootXML.documentElement;
            }

            if (oRootXML.childNodes.length > 1 || bIsMultipleResponse) {
                bIsMulty = true;
                arrResult = new Array();
            }

            for (var z = 0; z < oRootXML.childNodes.length; z++) {
                oXML = oRootXML.childNodes[z];
                //Convert Result XML to an Object
                for (var i = 0; i < oXML.childNodes.length; i++) {
                    switch (oXML.childNodes[i].tagName) {
                        case "RETURN_VALUE": oResult.returnValue = this.GetBooleanValue(this.GetXMLNodeValue(oXML.childNodes[i])); break;
                        case "ERROR_CODE": oResult.errorCode = this.GetXMLNodeValue(oXML.childNodes[i]); break;
                        case "DATA": var oXmlNode = oXML.childNodes[i];
                            this.DataFactory(oResult, oXmlNode);
                            break;
                        default: break;
                    }
                }

                if (bIsMulty) {
                    arrResult.push(oResult);
                    oResult = new Object();
                }
            }
            if (bIsMulty) {
                oResult = arrResult;
            }
        }
        else {
            oResult.returnValue = false;
            oResult.errorCode = 0;
        }
        return oResult;
    },

    //Function which transfers string TRUE or FALSE into boolean.
    GetBooleanValue: function(strBool) {
        var bBool = (strBool.toLowerCase() == "true") ? true : false;
        return bBool;
    },

    //Factory for parsing data node from toolbar's response.
    DataFactory: function(oData, oXmlNode) {
        var xmlNode = null;

        for (var j = 0; j < oXmlNode.childNodes.length; j++) {
            xmlNode = oXmlNode.childNodes[j];
            switch (xmlNode.tagName) {
                //Toolbar info                 
                case "TOOLBAR_INFO":
                    for (var i = 0; i < xmlNode.childNodes.length; i++) {
                        switch (xmlNode.childNodes[i].tagName) {
                            case "VERSION": oData.version = this.GetXMLNodeValue(xmlNode.childNodes[i]); break;
                            case "NAME": oData.name = this.GetXMLNodeValue(xmlNode.childNodes[i]); break;
                            case "CURRENT_CTID": oData.CTID = this.GetXMLNodeValue(xmlNode.childNodes[i]);
                            case "ORIGINAL_CTID": oData.originalCTID = this.GetXMLNodeValue(xmlNode.childNodes[i]); break;
                            case "IS_MULTICOMMUNITY": oData.isMulticommunity = this.GetBooleanValue(this.GetXMLNodeValue(xmlNode.childNodes[i])); break;
                            case "IS_GROUPING": oData.isGrouping = this.GetBooleanValue(this.GetXMLNodeValue(xmlNode.childNodes[i])); break;
                            //new myStuff feature, status
                            // 0: disabled,
                            // 1: enabled
                            //-1: unsupported
                            case "MY_STUFF_STATUS": oData.myStuffStatus =  parseInt(this.GetXMLNodeValue(xmlNode.childNodes[i])); break;
                            default: break;
                        }
                    }

                    if (typeof oData.myStuffStatus == "undefined")
                        oData.myStuffStatus = -1;

                    break;
                //Single value                 
                case "SINGLE_VALUE":
                    oData.data = this.GetXMLNodeValue(xmlNode);
                    break;
                //Menus info                 
                case "MENUS_INFO":
                    oData.menusInfo = new Array();
                    for (var i = 0; i < xmlNode.childNodes.length; i++) {
                        var xmlNodeMenu = xmlNode.childNodes[i];
                        if (xmlNodeMenu.tagName == "MENU_INFO") {
                            var oDataMenu = new Object();
                            for (var k = 0; k < xmlNodeMenu.childNodes.length; k++) {
                                switch (xmlNodeMenu.childNodes[k].tagName) {
                                    case "COMP_ID": oDataMenu.componentID = this.GetXMLNodeValue(xmlNodeMenu.childNodes[k]); break;
                                    case "CAPTION": oDataMenu.caption = this.GetXMLNodeValue(xmlNodeMenu.childNodes[k]); break;
                                    case "ICON_URL": oDataMenu.iconUrl = this.GetXMLNodeValue(xmlNodeMenu.childNodes[k]); break;
                                    default: break;
                                }
                            }
                            oData.menusInfo.push(oDataMenu);
                        }
                    }
            }
        }
    },

    GetOldApiResult: function(bResult) {
        var oResult = new Object();
        oResult.returnValue = bResult;
        oResult.errorCode = 0;
        return oResult;
    },

    //Cross browser.
    GetXMLNodeValue: function(xmlNode) {
        if (xmlNode.text) {
            return xmlNode.text;
        }
        else if (xmlNode.childNodes.length != 0) {

            return xmlNode.childNodes[0].nodeValue;
        }
        else {
            return "";
        }
    },

    ToLegalXML: function(strXML) {
        strXML = strXML.replace(/&/g, '&amp;');
        strXML = strXML.replace(/</g, '&lt;');
        strXML = strXML.replace(/>/g, '&gt;');
        strXML = strXML.replace(/\'/g, '&apos;');
        strXML = strXML.replace(/\"/g, '&quot;');

        return strXML;
    },

    //Returns correct XML defining toolbar button
    BuildButtonXml: function(buttonLabel, buttonIcon, buttonTooltip, xmlData,
					   optionsDisplayText, optionsDisplayIcon, uniqueComponentID) {
        var strXML = '<BUTTON>';
        strXML += '<PERMISSIONS><EDIT>True</EDIT><MOVE>True</MOVE><DELETE>True</DELETE></PERMISSIONS>';
        strXML += '<USER_ATTRIBUTES><PERMISSION>FULL</PERMISSION><SHOW_IN_CHEVRON>True</SHOW_IN_CHEVRON></USER_ATTRIBUTES>';
        strXML += '<UNIQUE_COMP_ID>' + this.ToLegalXML(uniqueComponentID) + '</UNIQUE_COMP_ID>';
        strXML += '<DEFAULT_BUTTON_TEXT>' + this.ToLegalXML(buttonLabel) + '</DEFAULT_BUTTON_TEXT>';
        strXML += '<BUTTON_ICON_URL>' + this.ToLegalXML(buttonIcon) + '</BUTTON_ICON_URL>';
        strXML += '<BUTTON_TOOLTIP>' + this.ToLegalXML(buttonTooltip) + '</BUTTON_TOOLTIP>';
        //options display text/icon
        strXML += '<DISPLAY_TEXT>' + this.ToLegalXML(optionsDisplayText) + '</DISPLAY_TEXT>';
        strXML += '<DISPLAY_ICON>' + this.ToLegalXML(optionsDisplayIcon) + '</DISPLAY_ICON>';
        //data node
        strXML += xmlData;
        strXML += '</BUTTON>';

        return strXML;
    },

    //Returns correct XML defining toolbar RSS component
    BuildRssXml: function(buttonLabel, buttonIcon, rssFeedUrl, buttonNewMessagesIcon, optionsDisplayText,
									optionsDisplayIcon, refreshIntervalInMinutes, uniqueComponentID) {

        var strXML = '<RSS_FEED_ITEM>';
        strXML += '<PERMISSIONS><EDIT>True</EDIT><MOVE>True</MOVE><DELETE>True</DELETE></PERMISSIONS>';
        strXML += '<USER_ATTRIBUTES><PERMISSION>FULL</PERMISSION><SHOW_IN_CHEVRON>True</SHOW_IN_CHEVRON></USER_ATTRIBUTES>';
        strXML += '<UNIQUE_COMP_ID>' + this.ToLegalXML(uniqueComponentID) + '</UNIQUE_COMP_ID>';
        strXML += '<DISPLAY_TEXT>' + this.ToLegalXML(optionsDisplayText) + '</DISPLAY_TEXT>';
        strXML += '<DISPLAY_ICON>' + this.ToLegalXML(optionsDisplayIcon) + '</DISPLAY_ICON>';
        strXML += '<TITLE>' + this.ToLegalXML(buttonLabel) + '</TITLE>';
        strXML += '<LINK>' + this.ToLegalXML(rssFeedUrl) + '</LINK>';
        strXML += '<ICON_NORMAL_URL>' + this.ToLegalXML(buttonIcon) + '</ICON_NORMAL_URL>';
        strXML += '<ICON_STARED_URL>' + this.ToLegalXML(buttonNewMessagesIcon) + '</ICON_STARED_URL>';
        strXML += '<LIVE_MODE>False</LIVE_MODE>';
        strXML += '<INTERVAL>' + this.ToLegalXML(refreshIntervalInMinutes) + '</INTERVAL>';
        strXML += '<COMMENTS_LINK/>';
        strXML += '<RSS_VIEW>ADJUSTIVE</RSS_VIEW>';
        strXML += '</RSS_FEED_ITEM>';

        return strXML;
    },

    //Returns correct XML defining toolbar RadioSation
    BuildRadioStationXml: function(name, url, contantType, mediaType, uniqueComponentID) {
        var strXML = '<RADIO_STATION>';
        strXML += '<STATION_ID>' + this.ToLegalXML(uniqueComponentID) + '</STATION_ID>';
        strXML += '<STATION_NAME>' + this.ToLegalXML(name) + '</STATION_NAME>';
        strXML += '<STATION_URL>' + this.ToLegalXML(url) + '</STATION_URL>';
        strXML += '<TYPE>' + mediaType + '</TYPE>';
        strXML += '<CONTENT_TYPE>' + contantType + '</CONTENT_TYPE>';
        strXML += '</RADIO_STATION>';

        return strXML;
    },

    BuildMenuItemLinkType: function(menuItemCaption, menuItemIconUrl, linkUrl, linkTarget) {
        var strXML = '<MENU_ITEM>';
        strXML += '<CAPTION>' + this.ToLegalXML(menuItemCaption) + '</CAPTION>';
        strXML += '<ICON_URL>' + this.ToLegalXML(menuItemIconUrl) + '</ICON_URL>';
        strXML += '<DATA><TYPE>LINK</TYPE><LINK>';
        strXML += '<URL>' + this.ToLegalXML(linkUrl) + '</URL>';
        strXML += '<TARGET>' + this.ToLegalXML(linkTarget) + '</TARGET>';
        strXML += '</LINK></DATA></MENU_ITEM>';

        return strXML;
    },

    //Menu items functions ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    BuildMenuItemXML: function(menuItemCaption, menuItemIconUrl, xmlData) {
        var strXML = '<MENU_ITEM>';
        strXML += '<CAPTION>' + this.ToLegalXML(menuItemCaption) + '</CAPTION>';
        strXML += '<ICON_URL>' + this.ToLegalXML(menuItemIconUrl) + '</ICON_URL>';
        strXML += xmlData;
        strXML += '<HASH_CODE>' + MD5Hash.MD5(xmlData + menuItemCaption + menuItemIconUrl) + '</HASH_CODE>';
        strXML += '</MENU_ITEM>';
        return strXML;
    },

    BuildGadgetDataXML: function(linkUrl, width, height, defaultTarget) {
        var xmlData = '<DATA><TYPE>POP_HTML</TYPE><POP_HTML>';
        xmlData += '<URL>' + this.ToLegalXML(linkUrl) + '</URL>';
        xmlData += '<DEFAULT_TARGET>' + this.ToLegalXML(defaultTarget) + '</DEFAULT_TARGET>';
        xmlData += '<WIDTH>' + width + '</WIDTH>';
        xmlData += '<HEIGHT>' + height + '</HEIGHT>';
        xmlData += '</POP_HTML></DATA>';
        return xmlData;
    },

    BuildLinkDataXML: function(linkUrl, linkTarget) {
        var xmlData = '<DATA><TYPE>LINK</TYPE><LINK>';
        xmlData += '<URL>' + this.ToLegalXML(linkUrl) + '</URL>';
        xmlData += '<TARGET>' + this.ToLegalXML(linkTarget) + '</TARGET>';
        xmlData += '</LINK></DATA>';
        return xmlData;
    },

    BuildCommandDataXML: function(commandType) {
        var xmlData = '<DATA><TYPE>COMMAND</TYPE><COMMAND>';
        xmlData += '<TYPE>' + this.ToLegalXML(commandType) + '</TYPE>';
        xmlData += '</COMMAND></DATA>';
        return xmlData;
    },

    BuildApplicationDataXML: function(exeAlias, params, appNotFoundUrl) {
        var xmlData = '<DATA><TYPE>APPLICATION</TYPE><APPLICATION>';
        xmlData += '<EXE_ALIAS>' + this.ToLegalXML(exeAlias) + '</EXE_ALIAS>';
        xmlData += '<PARAMS>' + this.ToLegalXML(params) + '</PARAMS>';
        xmlData += '<APP_NOT_FOUND_URL>' + this.ToLegalXML(appNotFoundUrl) + '</APP_NOT_FOUND_URL>';
        xmlData += '</APPLICATION></DATA>';
        return xmlData;
    },
    //Menu items functions end ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    GetToolbarFunctionString: function(strFunctionName) {
        strFunctionName = strFunctionName.replace(/\(/, '');
        strFunctionName = strFunctionName.replace(/\)/, '');

        switch (strFunctionName) {
            case "Refresh": return "RefreshToolbarByCTID"; break;
            case "IsVisible": return "IsToolbarVisible"; break;
            case "GetInfo ": return "GetToolbarInfo"; break;
            case "AddGadget": return "AddComponentByXML"; break;
            case "AddRSS": return "AddComponentByXML"; break;
            case "AddLinkButton": return "AddComponentByXML"; break;
            default: return strFunctionName; break;
        }
    },

    parseBool: function(strValue) {
        if (!strValue) return false;

        return (strValue.toLowerCase() == "true");
    }
};

var _ManagerHelper =
{
    CreateReturnObject: function(iErrorCode, bReturnValue, data) {
        var objReturn = new Object();
        objReturn.errorCode = iErrorCode;
        objReturn.returnValue = bReturnValue;
        objReturn.data = data;

        return objReturn;
    },

    GetManagerReturnObject: function(objManagerReturn, IsData) {
        //not an array - returned error for all responses (probably not toolbars)
        if (!objManagerReturn.length)
            return objManagerReturn;

        var objReturn = new Object();
        var iCountUnsupported = 0;

        for (var i = 0; i < objManagerReturn.length; i++) {
            if (objManagerReturn[i].returnValue) {
                if (!IsData || objManagerReturn[i].data)
                    return objManagerReturn[i];
            }

            else if (objManagerReturn[i].errorCode == 2)
                iCountUnsupported++;

            //if at least one toolbar return untrusted domain, exit with untrusted domain error code
            else if (objManagerReturn[i].errorCode == 10)
                return this.CreateReturnObject(10, false, null);

            //if at least one toolbar returned mystuff not visible, exit
            else if (objManagerReturn[i].errorCode == 11)
                return this.CreateReturnObject(11, false, null);
        }

        //all toolbars are not support this command
        if (iCountUnsupported == objManagerReturn.length)
            return this.CreateReturnObject(2, false, null);

        //at least one toolbar responded, but the value is empty
        if (IsData)
            return this.CreateReturnObject(1, true, null);
        //unknown error - just to make sure that always returns some object
        else
            return this.CreateReturnObject(0, false, null);
    }
}

var ForceRefreshFlags =
{
    ALL: 0,
    SETTINGS: 1,
    CHAT: 2
    //RADIO: 4,
    //GROUPING: 8,
    //COMMUNITIES: 16,
    //MY_STUFF: 32
}

//User object to interact with toolbar / toolbars
var TPI =
{
    Toolbar: function(strCTID) {

        this.CTID = strCTID;
        if (this.CTID) {
            this.IsLatestApi = _TPIHelper.ExecuteFunction(false, ["IsLatestApi", strCTID], null).returnValue;
            this.IsToolbarInstalled = -1;
        }

        this.Refresh = function() {
            if (!this.CTID) return this.NoCTID();

            if (this.IsLatestApi)
                return _TPIHelper.ExecuteFunction(false, ["RefreshToolbarByCTID", this.CTID], null);
            else {
                var bResult = _RefreshToolbarByCTID(this.CTID);
                return _TPIHelper.GetOldApiResult(bResult);
            }
        };

        this.ForceRefresh = function() {
            if (!this.CTID) return this.NoCTID();

            if (this.IsLatestApi)
                return _TPIHelper.ExecuteFunction(false, ["ForceRefreshToolbar", this.CTID], null);
            else {
                var bResult = _RefreshToolbarByCTID(this.CTID);
                return _TPIHelper.GetOldApiResult(bResult);
            }
        };

        this.ForceRefreshServices = function(flags) {
            if (!this.CTID) return this.NoCTID();
            if (typeof (flags) == "undefined") return this.ParametersError();

            if (this.IsLatestApi) {
                if (this.IsSupportedFunction("ForceRefreshServices").returnValue)
                    return _TPIHelper.ExecuteFunction(false, ["ForceRefreshServices", flags, this.CTID], null);
                else
                    return this.ForceRefresh();
            }
            else {
                var bResult = _RefreshToolbarByCTID(this.CTID);
                return _TPIHelper.GetOldApiResult(bResult);
            }
        };

        this.IsVisible = function() {
            if (!this.CTID) return this.NoCTID();

            if (this.IsLatestApi)
                return _TPIHelper.ExecuteFunction(false, ["IsToolbarVisible", this.CTID], null);
            else {
                var bResult = _IsToolbarInstalled(this.CTID)
                return _TPIHelper.GetOldApiResult(bResult);
            }
        };

        this.AddComponentByXML = function(strXML) {
            if (!this.CTID) return this.NoCTID();

            if (this.IsLatestApi)
                return _TPIHelper.ExecuteFunction(false, ["AddComponentByXML", strXML, this.CTID], null);
            else {
                var bResult = _AddComponentByXML(strXML, this.CTID)
                return _TPIHelper.GetOldApiResult(bResult);
            }
        };

        this.GetInfo = function() {
            if (!this.CTID) return this.NoCTID();

            if (this.IsLatestApi)
                return _TPIHelper.ExecuteFunction(false, ["GetToolbarInfo", this.CTID], null);
            else {
                if (!this.GetIsToolbarInstalled())
                    return this.NoToolbarInstalled();
                else
                    return this.UnsupportedCommand()
            }
        };

        this.AddGadget = function(buttonLabel, buttonIcon, buttonTooltip, linkTargetUrl,
					   width, height, defaultTarget, optionsDisplayText, optionsDisplayIcon, uniqueComponentID) {
            if (!this.CTID) return this.NoCTID();

            //parameters checks
            if (buttonLabel == "" && buttonIcon == "" && optionsDisplayIcon == "" && optionsDisplayText == "") {
                return this.ParametersError();
            }

            if (typeof linkTargetUrl == "undefined" || linkTargetUrl == "") {
                return this.ParametersError();
            }

            if (typeof width == "undefined" || width == "" || height == "undefined" || height == "") {
                return this.ParametersError();
            }

            if (typeof optionsDisplayText == "undefined" || optionsDisplayText == "") {
                optionsDisplayText = buttonLabel;
            }

            if (typeof optionsDisplayIcon == "undefined" || optionsDisplayIcon == "") {
                optionsDisplayIcon = buttonIcon;
            }

            if (typeof uniqueComponentID == "undefined" || uniqueComponentID == "") {
                uniqueComponentID = "gadget" + linkTargetUrl + width + height;
            }

            if (typeof defaultTarget == "undefined" || defaultTarget == "") {
                defaultTarget = "_SELF";
            }

            var xmlData = "<DATA><TYPE>POP_HTML</TYPE><POP_HTML><URL>" + _TPIHelper.ToLegalXML(linkTargetUrl) + "</URL>";
            xmlData += "<DEFAULT_TARGET>" + _TPIHelper.ToLegalXML(defaultTarget) + "</DEFAULT_TARGET><WIDTH>" + width + "</WIDTH><HEIGHT>" + height + "</HEIGHT></POP_HTML></DATA>";

            var strXML = _TPIHelper.BuildButtonXml(buttonLabel, buttonIcon, buttonTooltip, xmlData,
				       optionsDisplayText, optionsDisplayIcon, uniqueComponentID);


            return this.AddComponentByXML(strXML);
        };

        this.AddRSS = function(buttonLabel, buttonIcon, rssFeedUrl, buttonNewMessagesIcon, optionsDisplayText,
									optionsDisplayIcon, refreshIntervalInMinutes, uniqueComponentID) {
            if (!this.CTID) return this.NoCTID();

            //parameters checks
            if (buttonLabel == "" && buttonIcon == "" && optionsDisplayIcon == "" && optionsDisplayText == "") {
                return this.ParametersError();
            }

            if (typeof rssFeedUrl == "undefined" || rssFeedUrl == "") {
                return this.ParametersError();
            }

            if (typeof optionsDisplayText == "undefined" || optionsDisplayText == "") {
                optionsDisplayText = buttonLabel;
            }

            if (typeof optionsDisplayIcon == "undefined" || optionsDisplayIcon == "") {
                optionsDisplayIcon = buttonIcon;
            }

            if (typeof buttonNewMessagesIcon == "undefined" || buttonNewMessagesIcon == "") {
                buttonNewMessagesIcon = buttonIcon;
            }

            if (typeof uniqueComponentID == "undefined" || uniqueComponentID == "") {
                uniqueComponentID = "rss" + rssFeedUrl;
            }

            if (typeof refreshIntervalInMinutes == "undefined" || refreshIntervalInMinutes == "") {
                refreshIntervalInMinutes = "120";
            }

            var strXML = _TPIHelper.BuildRssXml(buttonLabel, buttonIcon, rssFeedUrl, buttonNewMessagesIcon, optionsDisplayText,
								    optionsDisplayIcon, refreshIntervalInMinutes, uniqueComponentID);

            return this.AddComponentByXML(strXML);
        };

        this.AddLinkButton = function(buttonLabel, buttonIcon, buttonTooltip, linkTargetUrl,
					   linkTarget, optionsDisplayText, optionsDisplayIcon, uniqueComponentID) {
            if (!this.CTID) return this.NoCTID();

            //parameters checks
            if (buttonLabel == "" && buttonIcon == "" && optionsDisplayIcon == "" && optionsDisplayText == "") {
                return this.ParametersError();
            }

            if (typeof linkTargetUrl == "undefined" || linkTargetUrl == "") {
                return this.ParametersError();
            }

            if (typeof optionsDisplayText == "undefined" || optionsDisplayText == "") {
                optionsDisplayText = buttonLabel;
            }

            if (typeof optionsDisplayIcon == "undefined" || optionsDisplayIcon == "") {
                optionsDisplayIcon = buttonIcon;
            }

            if (typeof uniqueComponentID == "undefined" || uniqueComponentID == "") {
                uniqueComponentID = "button" + linkTargetUrl;
            }

            if (typeof linkTarget == "undefined" || linkTarget == "") {
                linkTarget = "SELF";
            }

            var xmlData = "<DATA><TYPE>LINK</TYPE><LINK><URL>" + _TPIHelper.ToLegalXML(linkTargetUrl) + "</URL><TARGET>" + _TPIHelper.ToLegalXML(linkTarget) + "</TARGET></LINK></DATA>";

            var strXML = _TPIHelper.BuildButtonXml(buttonLabel, buttonIcon, buttonTooltip, xmlData,
				       optionsDisplayText, optionsDisplayIcon, uniqueComponentID);

            return this.AddComponentByXML(strXML);
        };

        this.AddRadioStation = function(name, url, contantType, mediaType, uniqueComponentID) {
            if (!name || !url)
                return this.ParametersError();

            if (!contantType)
                contantType = "MP";

            if (!mediaType)
                mediaType = "STREAM";

            if (!uniqueComponentID)
                uniqueComponentID = url;

            var strXML = _TPIHelper.BuildRadioStationXml(name, url, contantType, mediaType, uniqueComponentID);

            if (!this.CTID) return this.NoCTID();

            if (this.IsLatestApi)
                return _TPIHelper.ExecuteFunction(false, ["AddRadioStation", strXML, this.CTID], null);
            else {
                if (!this.GetIsToolbarInstalled())
                    return this.NoToolbarInstalled();
                else
                    return this.UnsupportedCommand();
            }
        };

        this.SwitchToCommunity = function(strCTID) {
            if (!this.CTID) return this.NoCTID();

            if (this.IsLatestApi)
                return _TPIHelper.ExecuteFunction(false, ["SwitchToCommunity", strCTID, this.CTID], null);
            else {
                if (!this.GetIsToolbarInstalled())
                    return this.NoToolbarInstalled();
                else
                    return this.UnsupportedCommand();
            }
        };

        this.GetSupportedUserAddMenu = function() {
            if (!this.CTID) return this.NoCTID();

            if (this.IsLatestApi)
                return _TPIHelper.ExecuteFunction(false, ["GetSupportedUserAddMenu", this.CTID], null);
            else {
                if (!this.GetIsToolbarInstalled())
                    return this.NoToolbarInstalled();
                else
                    return this.UnsupportedCommand();
            }
        };

        this.AddLinkMenuItem = function(uniqueComponentID, menuItemCaption, menuItemIconUrl, linkUrl, linkTarget) {
            if (!this.CTID) return this.NoCTID();

            if (!uniqueComponentID || !linkUrl || (!menuItemCaption && !menuItemIconUrl))
                return this.ParametersError();

            var strXMLData = _TPIHelper.BuildLinkDataXML(linkUrl, linkTarget);
            var strXML = _TPIHelper.BuildMenuItemXML(menuItemCaption, menuItemIconUrl, strXMLData);

            if (this.IsLatestApi)
                return _TPIHelper.ExecuteFunction(false, ["AddUserLinkMenuItem", strXML, uniqueComponentID, this.CTID], null);
            else {
                if (!this.GetIsToolbarInstalled())
                    return this.NoToolbarInstalled();
                else
                    return this.UnsupportedCommand();
            }
        };

        this.AddGadgetMenuItem = function(uniqueComponentID, menuItemCaption, menuItemIconUrl, linkUrl, width, height, defaultTarget) {
            if (!this.CTID) return this.NoCTID();

            if (!uniqueComponentID || !linkUrl || (!menuItemCaption && !menuItemIconUrl) || !width || !height)
                return this.ParametersError();

            var strXMLData = _TPIHelper.BuildGadgetDataXML(linkUrl, width, height, defaultTarget);
            var strXML = _TPIHelper.BuildMenuItemXML(menuItemCaption, menuItemIconUrl, strXMLData);

            if (this.IsLatestApi)
                return _TPIHelper.ExecuteFunction(false, ["AddUserLinkMenuItem", strXML, uniqueComponentID, this.CTID], null);
            else {
                if (!this.GetIsToolbarInstalled())
                    return this.NoToolbarInstalled();
                else
                    return this.UnsupportedCommand();
            }
        };

        this.AddCommandMenuItem = function(uniqueComponentID, menuItemCaption, menuItemIconUrl, commandType) {
            if (!this.CTID) return this.NoCTID();

            if (!uniqueComponentID || (!menuItemCaption && !menuItemIconUrl) || !commandType)
                return this.ParametersError();

            var strXMLData = _TPIHelper.BuildCommandDataXML(commandType);
            var strXML = _TPIHelper.BuildMenuItemXML(menuItemCaption, menuItemIconUrl, strXMLData);

            if (this.IsLatestApi)
                return _TPIHelper.ExecuteFunction(false, ["AddUserLinkMenuItem", strXML, uniqueComponentID, this.CTID], null);
            else {
                if (!this.GetIsToolbarInstalled())
                    return this.NoToolbarInstalled();
                else
                    return this.UnsupportedCommand();
            }
        };

        this.AddApplicationMenuItem = function(uniqueComponentID, menuItemCaption, menuItemIconUrl, exeAlias, params, appNotFoundUrl) {
            if (!this.CTID) return this.NoCTID();

            if (!uniqueComponentID || (!menuItemCaption && !menuItemIconUrl) || !exeAlias)
                return this.ParametersError();

            var strXMLData = _TPIHelper.BuildApplicationDataXML(exeAlias, params, appNotFoundUrl)
            var strXML = _TPIHelper.BuildMenuItemXML(menuItemCaption, menuItemIconUrl, strXMLData);

            if (this.IsLatestApi)
                return _TPIHelper.ExecuteFunction(false, ["AddUserLinkMenuItem", strXML, uniqueComponentID, this.CTID], null);
            else {
                if (!this.GetIsToolbarInstalled())
                    return this.NoToolbarInstalled();
                else
                    return this.UnsupportedCommand();
            }
        };

        //************************ MyStuff functions ************************
        //asyncCallback will be called with following parameters(compGuid, isSucceeded, flags, state);
        //onErrorCallback will be called with (state) param
        this.AddMyStuffComponent = function(componentGuid, componentInstanceGuid, compName, asyncCallback, state, timeoutCallback, iTimeout) {
            if (!this.CTID) return this.NoCTID();
            if (!componentGuid || !componentInstanceGuid) return this.ParametersError();
            if (typeof compName == "undefined") compName = "";

            if (this.IsLatestApi) {
                if (asyncCallback) {
                    var callbackWrapper = function(arrArguments, state) {
                        var compGuid = arrArguments[1];
                        var isSuccess = arrArguments[2];
                        var flag = arrArguments[3];
                        asyncCallback(state, compGuid, isSuccess, flag);
                    };

                    return _TPIHelper.ExecuteFunction(false, ["AddMyStuffComponentAsync", componentGuid, componentInstanceGuid, compName, this.CTID], callbackWrapper, state, timeoutCallback, iTimeout);
                }
                else
                    return _TPIHelper.ExecuteFunction(false, ["AddMyStuffComponent", componentGuid, componentInstanceGuid, compName, this.CTID], null);
            }
            else {
                if (!this.GetIsToolbarInstalled())
                    return this.NoToolbarInstalled();
                else
                    return this.UnsupportedCommand();
            }
        };
        //************************ MyStuff functions end ************************

        this.IsSupportedFunction = function(strFunctionName) {
            if (!this.CTID) return this.NoCTID();
            if (this.IsLatestApi) {
                var strToolbarFunctionName = _TPIHelper.GetToolbarFunctionString(strFunctionName);
                return _TPIHelper.ExecuteFunction(false, ["IsSupportedFunction", strToolbarFunctionName, this.CTID], null);
            }
            else {
                if (!this.GetIsToolbarInstalled())
                    return this.NoToolbarInstalled();
                else
                    return this.UnsupportedCommand();
            }
        };

        //builds xml for response parser, for unsupported command
        this.UnsupportedCommand = function() {
            var strXmlResult = "<RETURN_OBJECT><RETURN_VALUE>false</RETURN_VALUE><ERROR_CODE>2</ERROR_CODE></RETURN_OBJECT>";
            return _TPIHelper.GetResult(strXmlResult);
        };

        //builds xml for response parser, for input parameters error
        this.ParametersError = function() {
            var strXmlResult = "<RETURN_OBJECT><RETURN_VALUE>false</RETURN_VALUE><ERROR_CODE>3</ERROR_CODE></RETURN_OBJECT>";
            return _TPIHelper.GetResult(strXmlResult);
        };

        this.NoToolbarInstalled = function() {
            var strXmlResult = "<RETURN_OBJECT><RETURN_VALUE>false</RETURN_VALUE><ERROR_CODE>0</ERROR_CODE></RETURN_OBJECT>";
            return _TPIHelper.GetResult(strXmlResult);
        };

        this.NoCTID = function() {
            var strXmlResult = "<RETURN_OBJECT><RETURN_VALUE>false</RETURN_VALUE><ERROR_CODE>6</ERROR_CODE></RETURN_OBJECT>";
            return _TPIHelper.GetResult(strXmlResult);
        };

        this.GetIsToolbarInstalled = function() {
            if (this.IsToolbarInstalled == -1) {
                this.IsToolbarInstalled = _IsToolbarInstalled(this.CTID);
            }

            return this.IsToolbarInstalled;
        }
    },

    //Helper manager to interract with multiple toolbars
    Manager: function() {
        this.GetAllToolbarsInfo = function() {
            return _TPIHelper.ExecuteFunction(true, ["GetAllToolbarsInfo"], null);
        };

        this.AddAlert = function(alertId) {
            return _TPIHelper.ExecuteFunction(true, ["AddAlert", alertId], null);
        };

        this.AddMyStuffAlert = function(alertId, alertProviderName) {
            return _TPIHelper.ExecuteFunction(true, ["AddMyStuffAlert", alertId, alertProviderName], null);
        };

        this.IsSubscribedToAlert = function(alertId) {
            var objMultipleReturn = _TPIHelper.ExecuteFunction(true, ["IsSubscribedToAlert", alertId], null);
            return _ManagerHelper.GetManagerReturnObject(objMultipleReturn, false);
        };

        this.OpenMiniIpage = function() {
            var objMultipleReturn = _TPIHelper.ExecuteFunction(true, ["OpenMiniIpage"], null);
            return _ManagerHelper.GetManagerReturnObject(objMultipleReturn, false);
        };

        this.IsSupportedFunction = function(strFunctionName) {
            var strToolbarFunctionName = _TPIHelper.GetToolbarFunctionString(strFunctionName);
            var objMultipleReturn = _TPIHelper.ExecuteFunction(true, ["IsSupportedFunction", strToolbarFunctionName], null);

            if (!objMultipleReturn.length)
                return objMultipleReturn;

            var bIsSucceeded = false;

            for (var i = 0; i < objMultipleReturn.length; i++) {
                //at least one toolbar support this function
                if (objMultipleReturn[i].returnValue)
                    return objMultipleReturn[i];

                //at least one toolbar supports the check-supported function, but not supports the requested function
                if (objMultipleReturn[i].errorCode == 1)
                    bIsSucceeded = true;
            }

            //at least one toolbar supports the check-supported function, but not supports the requested function
            if (bIsSucceeded)
                return _ManagerHelper.CreateReturnObject(1, false, null);
            //all toolbars doesn't recognize the heck-supported function
            else
                return _ManagerHelper.CreateReturnObject(2, false, null);
        };
    }
}

// ======================= Older API Functions ========================

//this is a blank object
//this object is used to catch all the calls 
//that the toolbars(IE & Firefox) didn't catch
var EBToolbarApi =
{
    Result: false,

    ResetResult: function() {
        this.SetResult(false);
    },

    SetResult: function(bValue) {
        this.Result = bValue;
    },

    GetResult: function() {
        return this.Result;
    },

    RefreshAllToolbars: function() {
        //do nothing...
    },

    RefreshToolbarByCTID: function(strCTID) {
        //do nothing...	
    },

    IsToolbarInstalled: function(strCTID) {
        //do nothing...
    },

    AddComponentByXML: function(strXML, strCTID) {
        //do nothing...
    }
}

//wrapped function to set result (for IE)
function EBSetResult(bValue) {
    EBToolbarApi.SetResult(bValue);
}

//-------------------------------------------------------------------

/***** Public API Functions *****/

/******************************** - IMPORTTANT - **********************************/
//                                                                                //
//	The functions should be called the earliset at the onload event of the page   //
//                                                                                //
/**********************************************************************************/

/************************************************/
/*			bool RefreshAllToolbars()			*/
/*	This function refreshes all toolbars.		*/
/************************************************/
function RefreshAllToolbars() {
    var bResult = _RefreshAllToolbars();

    var oManager = new TPI.Manager();
    var oResult = oManager.GetAllToolbarsInfo();
    var bResult = true;
    if (oResult.length) {
        for (var i = 0; i < oResult.length; i++) {
            var oToolbar = new TPI.Toolbar(oResult[i].CTID);
            var oRes = oToolbar.Refresh();
            bResult = oRes.returnValue || bResult;
        }
    }

    return bResult;
}

/************************************************/
/*		bool RefreshToolbarByCTID(strCTID)		*/
/*	This function refreshes the toolbar by CTID.*/
/************************************************/
function RefreshToolbarByCTID(strCTID) {
    var oToolbar = new TPI.Toolbar(strCTID);
    var oRes = oToolbar.Refresh();
    return oRes.returnValue;
}

/************************************************/
/*		bool IsToolbarInstalled(strCTID)	    */
/*	This function returns true if the toolbar   */
/*	with the given CTID is installed.			*/
/************************************************/
function IsToolbarInstalled(strCTID) {
    var oToolbar = new TPI.Toolbar(strCTID);
    var oRes = oToolbar.IsVisible();
    return oRes.returnValue;
}

/************************************************/
/*		bool AddComponentByXML(strXML,strCTID)  */
/*	This function returns true if the toolbar   */
/*	with the given CTID is installed.			*/
/************************************************/
function AddComponentByXML(strXML, strCTID) {
    var oToolbar = new TPI.Toolbar(strCTID);
    var oRes = oToolbar.AddComponentByXML(strXML);
    return oRes.returnValue;
}


//Inner functions for new API to talk to old toolbars
function _RefreshAllToolbars() {
    EBToolbarApi.ResetResult();

    if (_TPIHelper.GetBrowser() == "IE") {
        var frameSrc = 'about:blank#javascript:EBToolbarApi.RefreshAllToolbars();';
        _TPIHelper.NavigateInIFrame(frameSrc);
    }
    else {
        eval('EBToolbarApi.RefreshAllToolbars();');
    }

    return EBToolbarApi.GetResult();
}

function _RefreshToolbarByCTID(strCTID) {
    EBToolbarApi.ResetResult();

    if (_TPIHelper.GetBrowser() == "IE") {
        var frameSrc = 'about:blank#javascript:EBToolbarApi.RefreshToolbarByCTID(\'' + strCTID + '\');';
        _TPIHelper.NavigateInIFrame(frameSrc);
    }
    else {
        eval('EBToolbarApi.RefreshToolbarByCTID(\'' + strCTID + '\');');
    }

    return EBToolbarApi.GetResult();
}

function _IsToolbarInstalled(strCTID) {
    EBToolbarApi.ResetResult();

    if (_TPIHelper.GetBrowser() == "IE") {
        var frameSrc = 'about:blank#javascript:EBToolbarApi.IsToolbarInstalled(\'' + strCTID + '\');';
        _TPIHelper.NavigateInIFrame(frameSrc);
    }
    else {
        eval('EBToolbarApi.IsToolbarInstalled(\'' + strCTID + '\');');
    }

    return EBToolbarApi.GetResult();
}

function _AddComponentByXML(strXML, strCTID) {
    EBToolbarApi.ResetResult();
    if (_TPIHelper.GetBrowser() == "IE") {
        var frameSrc = "about:blank#javascript:EBToolbarApi.AddComponentByXML(\"" + strXML + "\",\"CTID=" + strCTID.toUpperCase() + "\");";
        _TPIHelper.NavigateInIFrame(frameSrc);
    }
    else {
        eval('EBToolbarApi.AddComponentByXML("' + strXML + '","CTID=' + strCTID.toUpperCase() + '");');
    }

    return EBToolbarApi.GetResult();
}


/*
* A JavaScript implementation of the RSA Data Security, Inc. this.MD5 Message
* Digest Algorithm, as defined in RFC 1321.
* Copyright (C) Paul Johnston 1999 - 2000.
* Updated by Greg Holt 2000 - 2001.
* See http://pajhome.org.uk/site/legal.html for details.
*/

/*
* Convert a 32-bit number to a hex string with ls-byte first
*/
var MD5Hash =
{
    hex_chr: "0123456789abcdef",

    rhex: function(num) {
        str = "";
        for (j = 0; j <= 3; j++)
            str += this.hex_chr.charAt((num >> (j * 8 + 4)) & 0x0F) +
               this.hex_chr.charAt((num >> (j * 8)) & 0x0F);
        return str;
    },

    /*
    * Convert a string to a sequence of 16-word blocks, stored as an array.
    * Append pthis.adding bits and the length, as described in the this.MD5 standard.
    */
    str2blks_MD5: function(str) {
        nblk = ((str.length + 8) >> 6) + 1;
        blks = new Array(nblk * 16);
        for (i = 0; i < nblk * 16; i++) blks[i] = 0;
        for (i = 0; i < str.length; i++)
            blks[i >> 2] |= str.charCodeAt(i) << ((i % 4) * 8);
        blks[i >> 2] |= 0x80 << ((i % 4) * 8);
        blks[nblk * 16 - 2] = str.length * 8;
        return blks;
    },

    /*
    * this.add integers, wrapping at 2^32. This uses 16-bit operations internally 
    * to work around bugs in some JS interpreters.
    */
    add: function(x, y) {
        var lsw = (x & 0xFFFF) + (y & 0xFFFF);
        var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
        return (msw << 16) | (lsw & 0xFFFF);
    },

    /*
    * Bitwise rotate a 32-bit number to the left
    */
    rol: function(num, cnt) {
        return (num << cnt) | (num >>> (32 - cnt));
    },

    /*
    * These functions implement the basic operation for each round of the
    * algorithm.
    */
    cmn: function(q, a, b, x, s, t) {
        return this.add(this.rol(this.add(this.add(a, q), this.add(x, t)), s), b);
    },

    ff: function(a, b, c, d, x, s, t) {
        return this.cmn((b & c) | ((~b) & d), a, b, x, s, t);
    },

    gg: function(a, b, c, d, x, s, t) {
        return this.cmn((b & d) | (c & (~d)), a, b, x, s, t);
    },

    hh: function(a, b, c, d, x, s, t) {
        return this.cmn(b ^ c ^ d, a, b, x, s, t);
    },

    ii: function(a, b, c, d, x, s, t) {
        return this.cmn(c ^ (b | (~d)), a, b, x, s, t);
    },

    /*
    * Take a string and return the hex representation of its this.MD5.
    */
    MD5: function(str) {
        x = this.str2blks_MD5(str);
        var a = 1732584193;
        var b = -271733879;
        var c = -1732584194;
        var d = 271733878;

        for (i = 0; i < x.length; i += 16) {
            var olda = a;
            var oldb = b;
            var oldc = c;
            var oldd = d;

            a = this.ff(a, b, c, d, x[i + 0], 7, -680876936);
            d = this.ff(d, a, b, c, x[i + 1], 12, -389564586);
            c = this.ff(c, d, a, b, x[i + 2], 17, 606105819);
            b = this.ff(b, c, d, a, x[i + 3], 22, -1044525330);
            a = this.ff(a, b, c, d, x[i + 4], 7, -176418897);
            d = this.ff(d, a, b, c, x[i + 5], 12, 1200080426);
            c = this.ff(c, d, a, b, x[i + 6], 17, -1473231341);
            b = this.ff(b, c, d, a, x[i + 7], 22, -45705983);
            a = this.ff(a, b, c, d, x[i + 8], 7, 1770035416);
            d = this.ff(d, a, b, c, x[i + 9], 12, -1958414417);
            c = this.ff(c, d, a, b, x[i + 10], 17, -42063);
            b = this.ff(b, c, d, a, x[i + 11], 22, -1990404162);
            a = this.ff(a, b, c, d, x[i + 12], 7, 1804603682);
            d = this.ff(d, a, b, c, x[i + 13], 12, -40341101);
            c = this.ff(c, d, a, b, x[i + 14], 17, -1502002290);
            b = this.ff(b, c, d, a, x[i + 15], 22, 1236535329);

            a = this.gg(a, b, c, d, x[i + 1], 5, -165796510);
            d = this.gg(d, a, b, c, x[i + 6], 9, -1069501632);
            c = this.gg(c, d, a, b, x[i + 11], 14, 643717713);
            b = this.gg(b, c, d, a, x[i + 0], 20, -373897302);
            a = this.gg(a, b, c, d, x[i + 5], 5, -701558691);
            d = this.gg(d, a, b, c, x[i + 10], 9, 38016083);
            c = this.gg(c, d, a, b, x[i + 15], 14, -660478335);
            b = this.gg(b, c, d, a, x[i + 4], 20, -405537848);
            a = this.gg(a, b, c, d, x[i + 9], 5, 568446438);
            d = this.gg(d, a, b, c, x[i + 14], 9, -1019803690);
            c = this.gg(c, d, a, b, x[i + 3], 14, -187363961);
            b = this.gg(b, c, d, a, x[i + 8], 20, 1163531501);
            a = this.gg(a, b, c, d, x[i + 13], 5, -1444681467);
            d = this.gg(d, a, b, c, x[i + 2], 9, -51403784);
            c = this.gg(c, d, a, b, x[i + 7], 14, 1735328473);
            b = this.gg(b, c, d, a, x[i + 12], 20, -1926607734);

            a = this.hh(a, b, c, d, x[i + 5], 4, -378558);
            d = this.hh(d, a, b, c, x[i + 8], 11, -2022574463);
            c = this.hh(c, d, a, b, x[i + 11], 16, 1839030562);
            b = this.hh(b, c, d, a, x[i + 14], 23, -35309556);
            a = this.hh(a, b, c, d, x[i + 1], 4, -1530992060);
            d = this.hh(d, a, b, c, x[i + 4], 11, 1272893353);
            c = this.hh(c, d, a, b, x[i + 7], 16, -155497632);
            b = this.hh(b, c, d, a, x[i + 10], 23, -1094730640);
            a = this.hh(a, b, c, d, x[i + 13], 4, 681279174);
            d = this.hh(d, a, b, c, x[i + 0], 11, -358537222);
            c = this.hh(c, d, a, b, x[i + 3], 16, -722521979);
            b = this.hh(b, c, d, a, x[i + 6], 23, 76029189);
            a = this.hh(a, b, c, d, x[i + 9], 4, -640364487);
            d = this.hh(d, a, b, c, x[i + 12], 11, -421815835);
            c = this.hh(c, d, a, b, x[i + 15], 16, 530742520);
            b = this.hh(b, c, d, a, x[i + 2], 23, -995338651);

            a = this.ii(a, b, c, d, x[i + 0], 6, -198630844);
            d = this.ii(d, a, b, c, x[i + 7], 10, 1126891415);
            c = this.ii(c, d, a, b, x[i + 14], 15, -1416354905);
            b = this.ii(b, c, d, a, x[i + 5], 21, -57434055);
            a = this.ii(a, b, c, d, x[i + 12], 6, 1700485571);
            d = this.ii(d, a, b, c, x[i + 3], 10, -1894986606);
            c = this.ii(c, d, a, b, x[i + 10], 15, -1051523);
            b = this.ii(b, c, d, a, x[i + 1], 21, -2054922799);
            a = this.ii(a, b, c, d, x[i + 8], 6, 1873313359);
            d = this.ii(d, a, b, c, x[i + 15], 10, -30611744);
            c = this.ii(c, d, a, b, x[i + 6], 15, -1560198380);
            b = this.ii(b, c, d, a, x[i + 13], 21, 1309151649);
            a = this.ii(a, b, c, d, x[i + 4], 6, -145523070);
            d = this.ii(d, a, b, c, x[i + 11], 10, -1120210379);
            c = this.ii(c, d, a, b, x[i + 2], 15, 718787259);
            b = this.ii(b, c, d, a, x[i + 9], 21, -343485551);

            a = this.add(a, olda);
            b = this.add(b, oldb);
            c = this.add(c, oldc);
            d = this.add(d, oldd);
        }
        return this.rhex(a) + this.rhex(b) + this.rhex(c) + this.rhex(d);
    }
}