(function ()
{
    //create hotlinks object
    if ((!window.hotlinks) || (typeof (window.hotlinks) !== "object"))
        window.hotlinks = {};

    //alias hotlinks objects
    var hl = window.hotlinks;

    //create global object
    hl.global =
    {
        head: document.getElementsByTagName('head')[0],
        container: null,
        interfaceHost: "js.hotkeys.com",
        interfaceUrl: "http://##HOST##/interface/6/?mode=hl&outputType=json&jsonWrapper=hotlinks.interfaceCallback",
        domain: window.location.host.replace('www\.', ''),
        queryParams: {},
        requestUrl: "",
        interfaceCallForModal: false,
        json: null
    };


    //***************************************************
    // False if object is null, undefined or empty string
    //***************************************************
    hl.exists = function (x)
    {
        if (typeof (x) == "undefined")
            return false;
        if (x == null)
            return false;
        if (x === "")
            return false;
        return true;
    };


    //**************************************
    // Seperate & decode querystring params
    //**************************************
    hl.getQueryParams = function ()
    {
        var params = {};

        //split params and add to array if not empty
        var split1 = location.href.split("?");
        if (split1.length > 1)
        {
            var raw = split1[1].split("&");
            for (var i = 0; i < raw.length; i++)
            {
                var parts = raw[i].split("=");
                if (parts.length > 1)
                {
                    var name = parts.shift();
                    var val = parts.join("=");
                    if ((name.length > 0) && (val.length > 0))
                        params[name] = decodeURIComponent(val);
                }
            }
        }

        return params;
    };


    //**************************************
    // Determine whether we're using modal
    //**************************************
    hl.useModal = function ()
    {
        try
        {
            //use modal? (don't allow on D2R domains)
            return ((hl.global.json.widgetConfig.general.resultDisplayModeID == "2") && (hl.global.json.widgetConfig.general.widgetModeID != "3"))
        }
        catch (e)
        {
            return false;
        }
    };


    //**************************************
    // Create interface request URL
    //**************************************
    hl.createInterfaceRequest = function (interfaceUrl, domain, queryParams)
    {
        var requestUrl = "";

        //append common params
        if (hl.exists(HL_WIDGET_OPTIONS.interfaceHost))
            requestUrl = interfaceUrl.replace("##HOST##", HL_WIDGET_OPTIONS.interfaceHost);
        else
            requestUrl = interfaceUrl.replace("##HOST##", hl.global.interfaceHost);
        requestUrl += "&custID=" + encodeURIComponent(HL_WIDGET_OPTIONS.customerID);
        requestUrl += "&widgetID=" + encodeURIComponent(HL_WIDGET_OPTIONS.widgetID);
        requestUrl += "&dn=" + encodeURIComponent(domain);
        requestUrl += "&pu=" + encodeURIComponent(location.pathname);
        requestUrl += "&ref=" + encodeURIComponent(document.referrer);
        requestUrl += "&ua=" + encodeURIComponent(navigator.userAgent);
        if ((hl.exists(HL_WIDGET_OPTIONS.keywords)) && (!hl.exists(queryParams["st"])) && (!hl.exists(queryParams["i_st"])))
            requestUrl += "&customLinks=1";
        if ((hl.exists(HL_WIDGET_OPTIONS.widgetConfig)) && (hl.exists(HL_WIDGET_OPTIONS.widgetConfig.general)) && (hl.exists(HL_WIDGET_OPTIONS.widgetConfig.general.widgetModeID)))
            requestUrl += "&widgetMode=" + encodeURIComponent(HL_WIDGET_OPTIONS.widgetConfig.general.widgetModeID);

        //append return values from querystring
        for (var i in queryParams)
        {
            if (i.indexOf("i_") === 0)
            {
                var name = i.substring(2);
                var value = queryParams[i];
                if ((name.length > 0) && (value.length > 0))
                    requestUrl += "&" + name + "=" + encodeURIComponent(value);
            }
        }

        return requestUrl;
    };


    //****************************************
    // Create interface request URL for modal
    //****************************************
    hl.createModalInterfaceRequest = function (interfaceUrl, domain, globalReturn, linkReturn, searchTerm, additionalParams)
    {
        var requestUrl = "";

        //append common params
        if (hl.exists(HL_WIDGET_OPTIONS.interfaceHost))
            requestUrl = interfaceUrl.replace("##HOST##", HL_WIDGET_OPTIONS.interfaceHost);
        else
            requestUrl = interfaceUrl.replace("##HOST##", hl.global.interfaceHost);
        requestUrl += "&custID=" + encodeURIComponent(HL_WIDGET_OPTIONS.customerID);
        requestUrl += "&widgetID=" + encodeURIComponent(HL_WIDGET_OPTIONS.widgetID);
        requestUrl += "&dn=" + encodeURIComponent(domain);
        requestUrl += "&pu=" + encodeURIComponent(location.pathname);
        requestUrl += "&ref=" + encodeURIComponent(document.referrer);
        requestUrl += "&ua=" + encodeURIComponent(navigator.userAgent);
        if ((hl.exists(HL_WIDGET_OPTIONS.widgetConfig)) && (hl.exists(HL_WIDGET_OPTIONS.widgetConfig.general)) && (hl.exists(HL_WIDGET_OPTIONS.widgetConfig.general.widgetModeID)))
            requestUrl += "&widgetMode=" + encodeURIComponent(HL_WIDGET_OPTIONS.widgetConfig.general.widgetModeID);

        //holder for return items
        var returnItems = {};

        //add global return items
        for (var gNname in globalReturn)
        {
            var gValue = globalReturn[gNname];
            if ((gNname.length != 0) && (gValue.length != 0))
            {
                if (!hl.exists(returnItems[gNname]))
                    returnItems[gNname] = gValue;
            }
        }

        //have link return items?
        if (hl.exists(linkReturn))
        {
            //add link return items (overwrite global items)
            for (var lName in linkReturn)
            {
                var lValue = linkReturn[lName];
                if ((lName.length != 0) && (lValue.length != 0))
                    returnItems[lName] = lValue;
            }
        }
        else
        {
            //append search term
            requestUrl += "&st=" + encodeURIComponent(searchTerm);
        }

        //append return items, properly encoded
        for (var rName in returnItems)
        {
            var rValue = returnItems[rName];
            requestUrl += "&" + rName + "=" + encodeURIComponent(rValue);
        }

        //append additional params?
        if (additionalParams)
            requestUrl += additionalParams;

        return requestUrl;
    }


    //**************************************
    // Make interface call
    //**************************************
    hl.makeInterfaceCall = function (requestUrl, head, useModal)
    {
        //set global flag indicating whether last interface call was for modal display window
        hl.global.interfaceCallForModal = useModal;

        //two methods of adding interface call script
        if (document.readyState === "loading")
        {
            document.write('<script type="text/javascript" src="' + requestUrl + '"></script>');
        }
        else
        {
            var script = document.createElement('script');
            script.type = 'text/javascript';
            script.src = requestUrl;
            script.async = 1;
            head.insertBefore(script, head.firstChild);
        }
    };


    //**************************************
    // Add style rule to CSS
    //**************************************
    hl.addStyle = function (css, selector, rule)
    {
        try
        {
            //add rule
            if (css.addRule)
                css.addRule(selector, rule);
            else
                css.insertRule(selector + "{" + rule + "}", css.cssRules.length);
        }
        catch (e)
        {
        }
    };


    //**************************************
    // Convert HEX color to HSL
    //**************************************
    hl.hexToHsl = function (hex)
    {
        //hex to rgb
        if (hex.indexOf("#") !== -1)
            hex.replace('#', '');
        r = parseInt(hex.substring(0, 2), 16);
        g = parseInt(hex.substring(2, 4), 16);
        b = parseInt(hex.substring(4, 6), 16);

        //rgb to hsl
        r /= 255;
        g /= 255;
        b /= 255;
        var max = Math.max(r, g, b), min = Math.min(r, g, b);
        var h, s, l = (max + min) / 2;
        if (max == min)
        {
            h = s = 0;
        }
        else
        {
            var d = max - min;
            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
            switch (max)
            {
                case r:
                    h = (g - b) / d + (g < b ? 6 : 0);
                    break;
                case g:
                    h = (b - r) / d + 2;
                    break;
                case b:
                    h = (r - g) / d + 4;
                    break;
            }
            h /= 6;
        }

        return [h, s, l];
    };


    //**************************************
    // Create & add page styles
    //**************************************
    hl.createPageStyles = function (config, head, haveResults, useModal, queryParams)
    {
        //get or create our inline css
        var css = null;
        if (document.styleSheets)
        {
            for (var i = 0; i < document.styleSheets.length; i++)
            {
                if (document.styleSheets[i].title == "hotlinks")
                {
                    css = document.styleSheets[i];
                    break;
                }
            }
        }
        if (!hl.exists(css))
        {
            var c = document.createElement('style');
            c.type = 'text/css';
            c.rel = 'stylesheet';
            c.media = 'screen';
            c.title = 'hotlinks';
            head.insertBefore(c, head.firstChild);
            css = document.styleSheets[0];
        }

        //inherit links font name?
        if ((config.links) && (!config.links.linksFontName))
            config.links.linksFontName = "inherit";

        //inherit results font name?
        if ((config.results) && (!config.results.resultsFontName))
            config.results.resultsFontName = "inherit";

        //have config for links?
        if (config.links)
        {
            hl.addStyle(css, '.relatedSearch', 'font-family: ' + config.links.linksFontName + '; border: 1px solid #' + config.links.linksBorderColor + '; padding: 10px; background: #' + config.links.linksBackgroundColor);
            hl.addStyle(css, '.relatedSearchTitle', 'color: #' + config.links.linksHeaderColor + '!important; border-bottom: 1px solid #' + config.links.linksBorderColor);
            if (typeof parseInt(config.links.linksHeaderFontSize, 10) == "number")
                hl.addStyle(css, '.relatedSearchTitle', 'font-size: ' + config.links.linksHeaderFontSize + 'px;');
            else
                hl.addStyle(css, '.relatedSearchTitle', 'font-size: ' + config.links.linksHeaderFontSize + ';');
            hl.addStyle(css, '.relatedAd', 'margin: 10px 0; padding: 0; font-size: ' + config.links.linkFontSize + 'px;');
            hl.addStyle(css, '.relatedAdWord', 'margin: 0 0 5px 0; list-style: none;');
            hl.addStyle(css, '.relatedAdWord a, .relatedAdWord a:link, .hotkey a:link', 'color: #' + config.links.linkColor);
            hl.addStyle(css, 'p.hotkey', 'text-align: right; font-size: 80% !important');
            hl.addStyle(css, '.hotkey a:link', 'text-decoration: none;');
        }

        //have config for searchbox?
        if (config.searchBox)
        {
            //ensure default 150px length
            if (config.searchBox.searchBoxLength == "0")
                config.searchBox.searchBoxLength = "150px";

            //add searchbox specific styles
            hl.addStyle(css, '.searchInput', 'border: 1px solid #' + config.searchBox.searchBoxBorderColor + ' !important; height: 20px; line-height: 20px; width: ' + config.searchBox.searchBoxLength + 'px; padding: 1px 5px; margin: 0 5px 5px 0 !important');
            hl.addStyle(css, '.searchButton', 'border: 0; background: #' + config.searchBox.searchBoxButtonColor + '; height: 26px; padding: 0 10px; font-size: 14px; vertical-align: bottom; margin: 0 0 5px !important;');

            //have specific button color?
            if (config.searchBox.searchBoxButtonColor)
            {
                //convert hex to hsl, to get lightness of color
                var searchHSL = hl.hexToHsl(config.searchBox.searchBoxButtonColor);

                //use dark or light border depending on lightness of background color
                if (searchHSL[2] > .5)
                    hl.addStyle(css, '.searchButton', 'color: #000 !important');
                else
                    hl.addStyle(css, '.searchButton', 'color: #fff !important');
            }
        }

        //have results on non-modal page?
        if ((haveResults) && (!useModal))
        {
            hl.addStyle(css, '.relatedSearchResults', 'width: 53%; float: left;');
            hl.addStyle(css, '.referredSearchResults', 'float: none !important;');
            hl.addStyle(css, '.relatedSearch', 'width: 162px; float: right;');
            hl.addStyle(css, '.relatedAdWord', 'display: block !important; border: 0 !important;');
        }

        //have config for results?
        if (config.results)
        {
            //add results specific styles
            hl.addStyle(css, '.relatedSearchResults', 'border: 1px solid #' + config.results.resultsBorderColor + '; padding: 10px; background: #' + config.results.resultsBackgroundColor + '; font-family: ' + config.results.resultsFontName);
            hl.addStyle(css, '.relatedSearchResults .resultsSearchTitle', 'color: #' + config.results.resultsHeaderColor + ' !important; margin-bottom: 10px; float: left; clear: none; font-size: ' + config.results.resultsHeaderFontSize + 'px;');
            hl.addStyle(css, '.relatedSearchResults .resultsSubTitle', 'color: #' + config.results.resultsSubHeaderColor + ' !important; margin-bottom: 10px; font-size: small; float: right; clear: none;');
            hl.addStyle(css, '.relatedSearchResults .resultLink', 'margin: 0 0 15px; clear: both;');
            hl.addStyle(css, '.relatedSearchResults .resultLinkTitle', 'color: #' + config.results.resultTitleColor + "; font-size: " + config.results.resultTitleFontSize + "px; font-weight: bold; text-decoration: underline");
            hl.addStyle(css, '.relatedSearchResults p.resultLinkAbstract', 'margin: 0 !important; font-size: 12px; color: #' + config.results.resultAbstractColor + ';');
            hl.addStyle(css, '.relatedSearchResults a.resultLinkUrl:link', 'text-decoration: none !important;');
            hl.addStyle(css, '.relatedSearchResults a.resultLinkUrl, .relatedSearchResults a.resultLinkUrl:link', 'color: #' + config.results.resultUrlColor + "; font-size: 12px");
        }

        //layout is horizontal? (1=vertical, 2=horizontal)
        if ((config.links) && (config.links.linkLayoutID == "2"))
        {
            //add horizontal-required styles
            hl.addStyle(css, '.relatedAdWord', 'display: inline; padding: 0 5px; border-right: 1px solid #' + config.links.linksBorderColor + ';');
            hl.addStyle(css, '.relatedAd .last', 'border-right: 0; padding-right: 0;');
        }
    };


    //**************************************
    // Build search link URL
    //**************************************
    hl.buildSearchLinkUrl = function (globalReturn, linkReturn, searchTerm, additionalParams)
    {
        var url = "";

        //use predefined results url?
        if ((hl.exists(HL_WIDGET_OPTIONS.linksResultsPageUrl)) && (HL_WIDGET_OPTIONS.linksResultsPageUrl.length > 0))
            url = HL_WIDGET_OPTIONS.linksResultsPageUrl;
        else
            url = location.href;

        //holder for return items
        var returnItems = {};

        //add global return items
        for (var gName in globalReturn)
        {
            var gValue = globalReturn[gName];
            if ((gName.length != 0) && (gValue.length != 0))
            {
                var newName1 = "i_" + gName;
                if (!hl.exists(returnItems[newName1]))
                    returnItems[newName1] = gValue;
            }
        }

        //have link return items?
        if (hl.exists(linkReturn))
        {
            //add link return items (overwrite global items)
            for (var lName in linkReturn)
            {
                var lValue = linkReturn[lName];
                if ((lName.length != 0) && (lValue.length != 0))
                {
                    var newName2 = "i_" + lName;
                    returnItems[newName2] = lValue;
                }
            }
        }
        else
        {
            //append search term
            returnItems["i_st"] = searchTerm;
        }

        //append return items, properly encoded
        for (var rName in returnItems)
        {
            var rValue = returnItems[rName];
            url += (url.indexOf("?") === -1) ? "?" : "&";
            url += rName + "=" + encodeURIComponent(rValue);
        }

        //append additional params?
        if (hl.exists(additionalParams))
            url += additionalParams;

        return url;
    }


    //**********************************************
    // Convert customer-specified keywords to links
    //**********************************************
    hl.keywordsToLinks = function (keywords)
    {
        var links = [];
        for (var i = 0; i < keywords.length; i++)
        {
            links[i] = {};
            links[i].searchTerm = keywords[i];
            links[i].linkReturn = {};
            links[i].linkReturn.st = keywords[i];
            links[i].linkReturn.slr = (i + 1).toString();
            links[i].linkReturn.slt = "17";
        }
        return links;
    };


    //**************************************
    // Create search links & searchbox
    //**************************************
    hl.createSearchLinks = function (j, keywords, container, useModal)
    {
        //determine if we're showing links
        //complicated due to conflicting/redundant settings..
        var showLinks = true;
        if (((!hl.exists(j.links)) || (j.links.length <= 0)) && (!hl.exists(HL_WIDGET_OPTIONS.keywords)))
            showLinks = false;
        if ((showLinks) && (!hl.exists(j.widgetConfig.links)))
            showLinks = false;
        if ((showLinks) && (hl.exists(j.widgetConfig.links.showLinks)) && (j.widgetConfig.links.showLinks == "0"))
            showLinks = false;
        if ((showLinks) && ((!hl.exists(j.widgetConfig.links.linkCount)) || (parseInt(j.widgetConfig.links.linkCount) <= 0)))
            showLinks = false;

        //create 'div' wrapper
        //used by both links & searchbox
        var linksWrapper = document.createElement('div');
        linksWrapper.className = "relatedSearch";

        //show links?
        if (showLinks)
        {
            //create 'h2' header
            var h2 = document.createElement('h2');
            h2.className = "relatedSearchTitle";
            if (hl.exists(HL_WIDGET_OPTIONS.header))
                h2.appendChild(document.createTextNode(HL_WIDGET_OPTIONS.header));
            else if (hl.exists(j.widgetConfig.links.linksHeaderText))
                h2.appendChild(document.createTextNode(j.widgetConfig.links.linksHeaderText));
            else
                h2.appendChild(document.createTextNode(''));

            //create 'ul' list container
            var ul = document.createElement('ul');
            ul.className = "relatedAd";

            //determine links list and render count
            var numToRender;
            if (hl.exists(keywords))
            {
                //convert customer-specified keywords to links
                links = hl.keywordsToLinks(keywords);

                //use user-defined links
                numToRender = links.length;
            }
            else
            {
                //use them, calculate how many to use
                var linksWanted = 0;
                if ((hl.exists(j.widgetConfig.links)) && (hl.exists(j.widgetConfig.links.linkCount)))
                    linksWanted = parseInt(j.widgetConfig.links.linkCount);
                numToRender = (linksWanted < j.links.length) ? linksWanted : j.links.length;
                links = j.links;
            }

            //loop through links to render
            for (var i = 0; i < numToRender; i++)
            {
                //create 'li'
                var li = document.createElement('li');
                li.className = "relatedAdWord";
                if (i == (numToRender - 1))
                    li.className += " last";

                //create 'a'
                var a = document.createElement('a');
                a.appendChild(document.createTextNode(links[i]["searchTerm"]));

                //non-modal?
                if (!useModal)
                {
                    //create link url
                    var url = hl.buildSearchLinkUrl(j.globalReturn, links[i].linkReturn, null, null);
                    a.setAttribute('href', url);
                }

                //modal
                else
                {
                    //assign empty href to 'a'
                    a.setAttribute('href', "#");

                    //assign identifier (keyword index) to 'a'
                    a.setAttribute('id', i);

                    try
                    {
                        //add click event
                        //method 1 (IE)
                        a.attachEvent('onclick', function (e)
                        {
                            //make interface call for modal
                            var requestUrl = hl.createModalInterfaceRequest(hl.global.interfaceUrl, hl.global.domain, j.globalReturn, links[e.srcElement.id].linkReturn, null, null);
                            hl.makeInterfaceCall(requestUrl, hl.global.head, true);
                            e.returnValue = false;
                        });
                    }
                    catch (e)
                    {
                        //add click event
                        //method 2 (others)
                        a.addEventListener('click', function (e)
                        {
                            //make interface call for modal
                            var requestUrl = hl.createModalInterfaceRequest(hl.global.interfaceUrl, hl.global.domain, j.globalReturn, links[this.id].linkReturn, null, null);
                            hl.makeInterfaceCall(requestUrl, hl.global.head, true);
                            e.preventDefault();
                        }, false);
                    }
                }

                //append 'a'
                li.appendChild(a);

                //append 'li'
                ul.appendChild(li);
            };

            //append 'h2'
            linksWrapper.appendChild(h2);

            //append 'ul'
            linksWrapper.appendChild(ul);
        }

        //show searchbox?
        var showSearchBox = false;
        if ((hl.exists(j.results)) && (hl.exists(j.widgetConfig.searchBox)) && (hl.exists(j.widgetConfig.searchBox.showSearchBoxWithResults)) && (j.widgetConfig.searchBox.showSearchBoxWithResults == "1"))
            showSearchBox = true;
        if ((!hl.exists(j.results)) && (hl.exists(j.widgetConfig.searchBox)) && (hl.exists(j.widgetConfig.searchBox.showSearchBoxWithoutResults)) && (j.widgetConfig.searchBox.showSearchBoxWithoutResults == "1"))
            showSearchBox = true;
        if (showSearchBox)
        {
            //create 'input' textbox
            var input = document.createElement('input');
            input.type = "text";
            input.className = "searchInput";
            input.id = "searchInput";

            //create 'input' button
            var button = document.createElement('input');
            button.type = "button";
            button.value = "Search";
            button.name = "search";
            button.className = "searchButton";

            //inline button click function
            button.onclick = function ()
            {
                //get search term from textbox
                var searchTerm = document.getElementById('searchInput').value;

                //non-modal
                if (!hl.useModal())
                {
                    //create search url, navigate
                    var url = hl.buildSearchLinkUrl(j.globalReturn, null, searchTerm, "&i_slr=0&i_slt=5");
                    location.href = url;
                }

                //modal
                else
                {
                    //make interface call for modal
                    var requestUrl = hl.createModalInterfaceRequest(hl.global.interfaceUrl, hl.global.domain, j.globalReturn, null, searchTerm, "&slr=0&slt=5");
                    hl.makeInterfaceCall(requestUrl, hl.global.head, true);
                }
            };

            //create 'div' wrapper
            var div = document.createElement('div');

            //inline keypress function
            div.onkeypress = function (e)
            {
                //get key code
                e = e || window.event;
                var code = e.keyCode || e.which;

                //enter pressed?
                if (code == 13)
                {
                    //get search term from textbox
                    var searchTerm = document.getElementById('searchInput').value;

                    //non-modal
                    if (!hl.useModal())
                    {
                        //create search url, navigate
                        var url = hl.buildSearchLinkUrl(j.globalReturn, null, searchTerm, "&i_slr=0&i_slt=5");
                        location.href = url;
                    }

                    //modal
                    else
                    {
                        //make interface call for modal
                        var requestUrl = hl.createModalInterfaceRequest(hl.global.interfaceUrl, hl.global.domain, j.globalReturn, null, searchTerm, "&slr=0&slt=5");
                        hl.makeInterfaceCall(requestUrl, hl.global.head, true);
                    }
                }
            };

            //append textbox & button to wrapper
            div.appendChild(input);
            div.appendChild(button);

            //append searchbox wrapper to outer wrapper
            linksWrapper.appendChild(div);
        }

        //append outer wrapper to container
        container.appendChild(linksWrapper);
    };


    //******************************************
    // Create result link (single sponsored ad)
    //******************************************
    hl.createResultLink = function (result, dw)
    {
        //create 'div' wrapper
        var div = document.createElement('div');
        div.className = "resultLink";

        //create 'a' title
        var a = document.createElement('a');
        a.className = "resultLinkTitle";
        if (dw)
            a.target = "_blank";
        a.href = result.clickUrl;
        a.innerHTML = result.title;

        //create 'p' abstract
        var p = document.createElement('p');
        p.className = "resultLinkAbstract";
        p.innerHTML = result.abs;

        //create 'a' url
        var url = document.createElement('a');
        url.className = "resultLinkUrl";
        url.href = result.clickUrl;
        if (dw)
            a.target = "_blank";
        url.innerHTML = result.displayUrl;

        //append child controls to wrapper
        div.appendChild(a);
        div.appendChild(p);
        div.appendChild(url);

        //return wrapper
        return div;
    };


    //**************************************
    // Create modal window
    //**************************************
    hl._createModal = function (head)
    {
        //get or create our inline css
        var css = null;
        if (document.styleSheets)
        {
            for (var i = 0; i < document.styleSheets.length; i++)
            {
                if (document.styleSheets[i].title == "hotlinks")
                {
                    css = document.styleSheets[i];
                    break;
                }
            }
        }
        if (!hl.exists(css))
        {
            var c = document.createElement('style');
            c.type = 'text/css';
            c.rel = 'stylesheet';
            c.media = 'screen';
            c.title = 'hotlinks';
            head.insertBefore(c, head.firstChild);
            css = document.styleSheets[0];
        }

        //create overlay 'div'
        var overlay = document.createElement('div');
        overlay.className = "hotlink_overlay";

        //create results 'div'
        var results = document.createElement('div');
        results.className = "hotlink_results";
        results.id = "results";
        results.appendChild(document.createTextNode(''));

        //cleate 'a' for closing modal
        var close = document.createElement('a');
        close.className = "close";
        close.href = "#";
        close.appendChild(document.createTextNode("Ã—"));

        try
        {
            //add click event to close
            //method 1 (IE)
            close.attachEvent('onclick', function (e)
            {
                overlay.style.display = "none";
                document.body.style.overflow = "auto";
                results.style.height = "auto";
                while (results.hasChildNodes())
                {
                    results.removeChild(results.lastChild);
                }
                e.returnValue = false;
            });
        }
        catch (e)
        {
            //add click event to close
            //method 2 (others)
            close.addEventListener('click', function (e)
            {
                overlay.style.display = "none";
                document.body.style.overflow = "auto";
                results.style.height = "auto";
                while (results.hasChildNodes())
                {
                    results.removeChild(results.lastChild);
                }
                e.preventDefault();
            }, false);
        }

        //append inner elements to overlay
        overlay.appendChild(close);
        overlay.appendChild(results);

        //append overlay to body
        document.body.appendChild(overlay);

        //add required styles & image links
        hl.addStyle(css, '.hotlink_overlay', 'background: url(http://i.nuseek.com/images/widget/hotlinks/overlay.png) transparent; position: fixed; top: 0; left: 0; right: 0; bottom: 0; display: none; z-index:99998;');
        hl.addStyle(css, '.hotlink_overlay .hotlink_results', 'background: #fff; position: absolute; top: 50%; left: 50%; width: 500px; margin-left: -270px; border-radius: 5px; padding: 20px;');
        hl.addStyle(css, '.hotlink_overlay .close', 'background: url(http://i.nuseek.com/images/widget/hotlinks/close.png); display: block; height: 40px; width: 40px; position: absolute; top: 1px; left: 50%; margin-left: 250px; z-index: 99999; text-indent: -99999px');
        hl.addStyle(css, '.hotlink_results .hotlinkWraper', 'height: 100%; width: 100%; overflow: auto;');
    };


    //**************************************
    // Recursively merge two objects 
    //**************************************
    hl._extend = function (obj1, obj2)
    {
        for (var p in obj2)
        {
            try
            {
                if (obj2[p].constructor == Object)
                {
                    obj1[p] = hl.extend(obj1[p], obj2[p]);
                }
                else
                {
                    obj1[p] = obj2[p];
                }

            }
            catch (e)
            {
                obj1[p] = obj2[p];
            }
        }

        return obj1;
    };


    //**************************************
    // Interface callback function
    //**************************************
    hl.interfaceCallback = function (data)
    {
        //alias json data
        var j = data.hotlinksInterface;
        hl.global.json = j;

        //write interface-returned errors as comments
        //some errors may be serious, others informational
        if (hl.exists(j.errors))
        {
            var errorMsg = "\r\n\r\n";
            for (var i = 0; i < j.errors.length; i++)
                errorMsg += '<!-- ' + j.errors[i] + ' -->\r\n';
            errorMsg += "\r\n";
            hl.global.container.innerHTML += errorMsg;
            if ((hl.exists(j.required.popErrors)) && (j.required.popErrors == "1"))
                alert("Hotlinks Message:" + errorMsg.replace("<!--", "").replace("-->", ""));
        }

        //have page-level widget config?
        if (hl.exists(HL_WIDGET_OPTIONS.widgetConfig))
        {
            //merge page-level and interface-returned widget config options
            var config = hl._extend(j.widgetConfig, HL_WIDGET_OPTIONS.widgetConfig);

            //store in json object
            j.widgetConfig = config;
        }

        //create page styles
        hl.createPageStyles(j.widgetConfig, hl.global.head, j.results, hl.useModal(), hl.global.queryParams);

        //have results?
        if (hl.exists(j.results))
        {
            //create outer 'div' wrapper
            var wrapper = document.createElement('div');

            //if search referred add special class
            if (j.info.referrer.search(/(google|yahoo|bing)\.com/gi) > -1) {
                wrapper.className = "relatedSearchResults referredSearchResults";
            } else {
                wrapper.className = "relatedSearchResults";
            }

            //create 'h2' header
            var h2 = document.createElement('h2');
            if (!hl.exists(j.widgetConfig.results.resultsHeaderText))
                j.widgetConfig.results.resultsHeaderText = "";
            var text = j.widgetConfig.results.resultsHeaderText;
            if (hl.exists(hl.global.queryParams["i_st"]))
                text += " " + hl.global.queryParams["i_st"];
            else if (hl.exists(hl.global.queryParams["st"]))
                text += " " + hl.global.queryParams["st"];
            else if ((hl.exists(j.required)) && (hl.exists(j.required.searchTerm)))
                text += " " + j.required.searchTerm;
            h2.appendChild(document.createTextNode(text));
            h2.className = "resultsSearchTitle";

            //create 'h3' subheader
            var h3 = document.createElement('h3');
            h3.appendChild(document.createTextNode('Sponsored Links'));
            h3.className = "resultsSubTitle";

            //append header & subheader to outer wrapper
            wrapper.appendChild(h2);
            wrapper.appendChild(h3);

            //create inner 'div' wrapper
            var div = document.createElement('div');
            div.style.clear = "both";
            div.style.overflow = "hidden";

            //loop through and build results, appending to inner wrapper
            var dw = true;
            if ((hl.exists(j.widgetConfig.results)) && (hl.exists(j.widgetConfig.results.resultsClickDaughterWindow)))
                dw = j.widgetConfig.results.resultsClickDaughterWindow == "1";
            for (var ii = 0; ii < j.results.length; ii++)
            {
                var result = hl.createResultLink(j.results[ii], dw);
                div.appendChild(result);
            }

            //append inner wrapper to outer wrapper
            wrapper.appendChild(div);

            //modal?
            if (hl.useModal())
            {
                //not sure why we're doing a referrer comparison here..??
                if ((document.referrer.split('?')[0].match(location.hostname)) || (document.referrer == ""))
                {
                    //create modal container and required styles
                    hl._createModal(hl.global.head);

                    //find results container
                    var results = document.getElementById('results');

                    //remove any existing child nodes
                    while (results.hasChildNodes())
                        results.removeChild(results.lastChild);

                    //identify 'a' used for closing modal
                    var close = results.previousSibling;

                    //append prebuilt results object
                    results.appendChild(wrapper);

                    //apply style to parent (overlay)
                    results.parentNode.style.display = "block";

                    //apply style to results container
                    if ((window.innerHeight - results.scrollHeight) / 2 < 50)
                    {
                        results.style.height = (window.innerHeight - 90) + "px";
                        results.style.top = "25px";
                        results.style.overflow = "auto";
                    }
                    else
                    {
                        try
                        {
                            results.style.top = ((window.innerHeight - results.scrollHeight) / 2) + "px";
                        }
                        catch (e)
                        {
                            results.style.top = Math.abs((document.documentElement.clientHeight - results.scrollHeight) / 2) + "px";
                        }
                    }

                    //apply style to closing 'a' link
                    close.style.top = (parseInt(results.style.top, 10) - 20) + "px";

                    //add required style
                    document.body.style.overflow = "hidden";
                }

                //referrer doesn't match (again, why?)
                else
                {
                    //append results to container (non-modal fashion)
                    hl.global.container.appendChild(wrapper);
                }
            }

            //non-modal
            else
            {
                //append results to container
                hl.global.container.appendChild(wrapper);
            }

            //create search links
            if ((hl.exists(j.links)) && (!hl.global.interfaceCallForModal) && (j.required.actionCodeID != "12"))
                hl.createSearchLinks(j, null, hl.global.container, hl.useModal());
        }

        //don't have results
        else
        {
            //create search links
            if ((hl.exists(HL_WIDGET_OPTIONS.keywords)) && (!hl.global.interfaceCallForModal))
                hl.createSearchLinks(j, HL_WIDGET_OPTIONS.keywords, hl.global.container, hl.useModal());
            else if ((hl.exists(j.links)) && (!hl.global.interfaceCallForModal))
                hl.createSearchLinks(j, null, hl.global.container, hl.useModal());
        }
    };


    //**************************************
    // Execute Hotlinks widget
    //**************************************
    hl.execute = function ()
    {
        //find output container
        if (hl.exists(HL_WIDGET_OPTIONS.widgetDivID))
            hl.global.container = document.getElementById(HL_WIDGET_OPTIONS.widgetDivID);
        else
            hl.global.container = document.getElementById('hotlinksScript').parentNode;

        //override domain w/ widget option?
        if (hl.exists(HL_WIDGET_OPTIONS.domain))
            hl.global.domain = HL_WIDGET_OPTIONS.domain;

        //seperate & decode querystring params
        hl.global.queryParams = hl.getQueryParams();

        //create interface request
        hl.global.requestUrl = hl.createInterfaceRequest(hl.global.interfaceUrl, hl.global.domain, hl.global.queryParams);

        //make interface call
        hl.makeInterfaceCall(hl.global.requestUrl, hl.global.head, false);
    };


    //execute immediately if widget is inline
    if (!hl.exists(HL_WIDGET_OPTIONS.widgetDivID))
        hl.execute();

})();
