/*
Dieses Skript ist Eigentum der xplosion interactive GmbH.
Version: v3.0.8.0
Last change: 2012-01-06
*/

var XPTraceLog = '';
// Debugging & Logging
var XPDoLogging = false;
var XPFBConsoleOut = false;
// Enable/Disable Profiling globally
var XPProfActive = true;
// Enable/Disable Piggybacking globally
var XPPGBActive = true;
var XPRand;
var XPPGBRes = false;
var XPSysError = false;
var XPIsSSL = false;
var XPConfigPreset = false;
var XPCondRes;
var XPCondAnyRes = false;
var XPPrtc;
var XPCConf;
var XPParams;
var XPEvent;
var XPPGBTrcData;
// CDN location
var XPCDNLoc = 'cdn.xplosion.de';
var XPCDNSSLLoc = 'ssl.xplosion.de';
var XPExtCConf;

//var liveScore
var XPEventStore = {};
//Determine if webstorage should be used if available
var XPScoreResult = {};
//JSON Object storing the scoring result
var XPScriptVersion = 'v3.0.8.0';

XPLogTrace('Version info: ' + XPScriptVersion);

// generate timestamp to avoid caching
XPRand = Math.random();
XPRand = XPRand.toString().substring(3, XPRand.toString().length);

XPLogTrace('Timestamp generated: ' + XPRand);

// If customer does not provide a proper 'script id', a separate variable (xpl_easytag) must be set in order to start profiling
if ((typeof (xpl_easytag) !== 'undefined' && xpl_easytag === true)) {
    XPLogTrace('Automode enabled. Entrypoint via xpl_easytag variable.');

    // start profiling
    XPProfiling();
} else if (document.getElementById('xplscript')) {
    if (document.getElementById('xplscript').src.indexOf('?easyTag') !== -1) {

        XPLogTrace('Automode enabled');

        if (document.getElementById('xplscript').src.indexOf('logging=true') !== -1) {
            XPSetLog(true);
        }

        XPProfiling();
    }
}

function XPProfiling(params) {
    try {
        if (XPProfActive) {

            XPParams = {};
            if (params !== undefined) {
                XPParams = params;
                if (typeof XPParams.extCustomerId !== 'undefined') {
                    XPExtCustomerId = XPParams.extCustomerId;
                }
            }

            // protocol detection
            XPPrtc = document.location.protocol;
            if (XPPrtc === 'file:') {
                XPPrtc = 'http:';
            } else if (XPPrtc === 'http:') {
                XPIsSSL = false;
            } else if (XPPrtc === 'https:') {
                XPIsSSL = true;
            }

            XPLogTrace('Protocol detection: ' + XPPrtc + '//');

            if (!XPConfigPreset) {
                // Site/Network
                if (XPParams.site_id) {
                    XPParams.customer_id = XPParams.site_id;
                }

                delete XPParams.site_id;

                // customer detection by variable (customer ID)
                // used if config can NOT be determined automatically by the customers domain
                // customer needs to provide XPExtCustomerId with the correct ID
                if (typeof XPExtCustomerId !== 'undefined') {

                    var customerDomain;

                    // check the HEIAS customer ID and set the domain name
                    switch (XPExtCustomerId) {
                    // Testcustomer (used for webtrekk example)
                    case 123456:
                        customerDomain = 'testcustomer.de';
                        break;
                    // Bonprix CH
                    case 7137:
                        customerDomain = 'bonprix.ch';
                        break;
                    // Bonprix AT
                    case 7463:
                        customerDomain = 'bonprix.at';
                        break;
                    // flug.de
                    case 9434:
                        customerDomain = 'flug.de';
                        break;
                    // travelchannel.de
                    case 9435:
                        customerDomain = 'travelchannel.de';
                        break;
                    // Travel Overland
                    case 9436:
                        customerDomain = 'travel-overland.de';
                        break;
                    // Esprit
                    case 11121:
                        customerDomain = 'esprit.de';
                        break;
                    // HEINE CH
                    case 10869:
                        customerDomain = 'heine.ch';
                        break;
                    // HEINE FR
                    case 11248:
                        customerDomain = 'heine.fr';
                        break;
                    // Dansommer NL checkout
                    case 11209:
                        customerDomain = 'dansommer.nl';
                        break;
                    // Novasol DE checkout
                    case 6593:
                        customerDomain = 'novasol.de';
                        break;
                    default:
                        customerDomain = '';
                        break;
                    }

                    if (customerDomain === '') {
                        // customer domain could not be determined by customer ID
                        XPLogError('F016: Error mapping customer domain from external customer ID. Config could not be loaded!');
                    } else {
                        // load customer config from customerDomain variable
                        XPLoadCusC(customerDomain);
                    }
                } else if (!XPParams.customer_id) {
                    // use autodetection to load customer config
                    XPDetectCus();
                } else {
                    XPLoadCusC(XPParams.customer_id);
                }
            } else {
                XPLogTrace('Customer config preset mode');

                if (XPExtCConf !== undefined && XPExtCConf !== null) {
                    XPExecP(XPExtCConf);
                } else {
                    XPLogError('F001: External customer config is null');
                }
            }
        }
    } catch(error) {
        XPLogError('F000: ' + error);
        XPLogTrace('Tag call aborted.');
    }
}

function XPExecP(conf) {
    XPCConf = conf;

    // Piggy-backing
    var pbn = 0;

    try {
        if (XPProfActive) {
            if (XPCConf) {
                if (XPCConf.config.pactive) {

                    XPLogTrace('Customer determined and config loaded: ' + XPCConf.customerid + ' (' + XPCConf.networkid + ')');

                    var ev;

                    // read eventtype from parameters
                    ev = XPParam(XPParams.event_id);

                    if (ev !== '' && XPCConf.config.autoevents) {
                        XPLogWarn('Auto event mode enabled but event was given by XPProfiling call. Auto event mode ignored.');
                    }

                    if (ev === '' && XPCConf.config.autoevents) {
                        XPLogTrace('Auto event mode enabled.');

                        var eventFound = false;

                        for ( var event in XPCConf.eventconfig) {
                            for ( var eventCondition in XPCConf.eventconfig[event]) {
                                var obj = XPCConf.eventconfig[event];
                                var condition = obj[eventCondition];
                                var siteUrl = top.location.href;

                                XPLogTrace('Probe for the "' + event + '" event by following condition: ' + condition);

                                // evaluate the event condition from the customer config
                                if (eval(condition) === true) {
                                    XPLogTrace('Condition match. Event detected: ' + event);
                                    ev = event;
                                    eventFound = true;
                                    break;
                                }
                            }
                            if (eventFound) {
                                break;
                            }
                        }
                        if (!eventFound) {
                            XPLogWarn('No event detected');
                            ev = 'unknown';
                        }
                    }

                    // events by variable
                    if (typeof XPCConf.config.eventvariable === 'undefined') {
                        XPCConf.config.eventvariable = false;
                    }

                    if (XPCConf.config.eventbyvariable === true) {
                        // load event from eventvariable (customer config)
                        ev = eval(XPCConf.config.eventvariable);
                    }

                    if (ev !== undefined && ev !== null && ev !== '') {

                        XPLogTrace('Event type determined: ' + ev);
                        XPParams.event_id = ev;

                        //Load EventStore data
                        if (XPCConf.config.livescoring === true) {
                            XPLogTrace('Live scoring is active');
                            XPScoreResult = XPDetermineScore(ev);
                        } else {
                            XPLogTrace('Live scoring is inactive');
                        }

                        if (XPCConf.config.pgbmode == 1 || XPCConf.config.pgbmode == 2) {

                            //Determine parammode
                            if (XPCConf.config.autoparam !== undefined && XPCConf.config.autoparam) {
                                XPLogTrace('Autoparam mode enabled.');

                                if (XPCConf.pvars === undefined) {
                                    XPLogWarn('Autoparam mode enabled but no variables defined.');
                                }

                                ///Merge given params with autoparam list
                                for ( var param in XPCConf.pvars) {
                                    if (XPCConf.pvars[param] !== undefined) {
                                        XPLogTrace('"' + param + '" parameter is configured to be loaded from external variable: ' + XPCConf.pvars[param]);

                                        var isUndefined = eval('typeof ' + XPCConf.pvars[param] + ' == "undefined"');
                                        if (!isUndefined) {
                                            XPParams[param] = eval(XPCConf.pvars[param]);
                                        } else {
                                            XPLogWarn('F020: External variable ' + (XPCConf.pvars[param]) + ' for ' + param + ' parameter does not exist. Ignored.');
                                        }
                                    } else {
                                        XPLogError('F015: External variable for ' + param + ' parameter is not configured. Ignored.');
                                    }
                                }
                            }

                            // read PGB trace data
                            XPLoadPGBTrcData();
                            // set PGB trace data
                            XPSetPGBTrcData();

                            //Read and execute piggyback condition
                            if (XPPGBActive === true && XPCConf.config.pgbactive === true) {
                                try {
                                    XPLogTrace('PGBMode: ' + ((XPCConf.config.pgbmode == 1) ? 'old mode' : 'new mode'));

                                    if (document.cookie.indexOf(XPCConf.config.pgbccname + '=true') == -1) {
                                        with (XPParams) {
                                            var counter = 0;
                                            XPCondRes = {};
                                            for ( var cond in XPCConf.pgbcond) {
                                                if (XPCConf.pgbcond[cond] !== undefined && XPCConf.pgbcond[cond] !== null) {
                                                    XPCondRes[cond] = eval(XPCConf.pgbcond[cond]);
                                                    XPLogTrace('Piggyback condition ' + cond + ' executed: ' + XPCConf.pgbcond[cond] + '. Condition Result: ' + XPCondRes[cond]);

                                                    if (XPCondRes[cond]) {
                                                        XPCondAnyRes = true;
                                                    }
                                                } else {
                                                    XPLogWarn('Piggyback condition is not defined.');
                                                }
                                                counter++;
                                            }
                                            if (counter > 1 && XPCConf.config.pgbmode == 1) {
                                                XPLogWarn('Old piggyback mode enabled but multiple piggyback conditions defined.');
                                            }
                                        }
                                    } else {
                                        XPLogTrace('Piggyback cache detected');
                                    }
                                } catch(error) {
                                    XPLogError('F002: Piggyback condition error: ' + XPCConf.pgbcond + '. Error: ' + error);
                                }
                            } else {
                                XPLogWarn('Piggybacking disabled.');
                            }

                            //Determine if it is an order
                            var isOrder = false;
                            if (ev === 'order') {
                                isOrder = true;
                                XPLogTrace('Order detected');
                            }

                            //1 = old mode, 2 = new mode
                            if (XPCondAnyRes && XPCConf.config.pgbmode == 1) {
                                pbn = 1;
                            }
                            var s = '';
                            //Write profiling/checkout tag
                            if (!isOrder) {
                                var heias_ref = '-';
                                try {
                                    heias_ref = escape((document.location == top.document.location) ? document.location : top.document.location);
                                } catch(e) {
                                    heias_ref = '-';
                                }
                                if (parent == top) {
                                    heias_ref = escape(document.referrer);
                                }
                                heias_ref = heias_ref;
                                var heias_fl_ver = 0;

                                s = XPPrtc + "//ads.heias.com/x/heias.ret.px/?PX=HT|" + XPRand + "|fl_ver|" + heias_fl_ver + "|js_var|" + screen.width + "," + screen.height + "," + navigator.cookieEnabled + "|n|" + XPCConf.networkid + "|cus|" + XPCConf.customerid + "|pb|" + pbn + XPCreateParamList(XPParams, XPCConf) + "|scriptversion|" + XPScriptVersion;

                                XPLogTrace('Profiling system request prepared (js, ppx): ' + s);

                                var HeiasCallJs = document.createElement('script');
                                HeiasCallJs.language = 'JavaScript';
                                HeiasCallJs.type = 'text/javascript';
                                HeiasCallJs.src = s;
                                HeiasCallJs.onerror = "XPSysError = true; XPLogError (\'F011: Requesting profiling system failed. No piggybacks set.\');";
                                HeiasCallJs.onload = "XPLogTrace (\'Successfull tag call (js)\');";

                                // append to page body
                                document.getElementsByTagName('BODY')[0].appendChild(HeiasCallJs);

                            } else {
                                // HEIAS checkout call
                                s = XPPrtc + "//ads.heias.com/x/heias.cpa/count.px.js/?PX=HT|" + XPRand + "|cus|" + XPCConf.customerid + "|pb|" + pbn + XPCreateParamList(XPParams, XPCConf);

                                XPLogTrace('Checkout system request prepared: (js, chkout) ' + s);

                                var HeiasCheckoutCallJs = document.createElement('script');
                                HeiasCheckoutCallJs.language = 'JavaScript';
                                HeiasCheckoutCallJs.type = 'text/javascript';
                                HeiasCheckoutCallJs.src = s;
                                HeiasCheckoutCallJs.onerror = "XPSysError = true;  XPLogError (\'F011: Requesting profiling system failed. No piggybacks set.\');";
                                HeiasCheckoutCallJs.onload = "XPDoPGB(); XPLogTrace (\'Successfull checkout call (js)\');";

                                // append to page body
                                document.getElementsByTagName('BODY')[0].appendChild(HeiasCheckoutCallJs);
                            }
                            setTimeout('XPDoPGB();', 1000);
                        } else {
                            XPLogError('F014: Invalid pgb mode. Call aborted.');
                        }
                    } else {
                        XPLogError('F003: No event defined. Call aborted.');
                    }
                } else {
                    XPLogWarn('Profiling is deactivated');
                }
            } else {
                XPLogError('F004: Customer_id was not provided and unable to detect customer id by hostname. Call aborted.');
            }
        } else {
            XPLogWarn('Profiling was disabled.');
        }
    } catch(error) {
        XPLogError('F000: ' + error);
        XPLogTrace('Tag call aborted.');
    }
}

function XPCheckEventVisits(event, cond) {
    var result = false;

    if (XPCConf.config.pgbtracing) {
        if (event !== null && event !== '' && cond !== null && cond !== '') {
            var code = 'if (XPPGBTrcData.trc.c_' + XPCConf.customerid + ' !== undefined && XPPGBTrcData.trc.c_' + XPCConf.customerid + '.e_' + XPParams.event_id + ' !== undefined) { result = (XPPGBTrcData.trc.c_' + XPCConf.customerid + '.e_' + event + ' ' + cond + '); }';
            eval(code);
        }
    } else {
        XPLogWarn('PGB tracing condition used but pgb tracing is disabled.');
    }

    return result;
}

function XPDoPGB() {
    // write piggybacks (new mode)
    // 1 = Old mode, 2 = new mode
    if (XPPGBActive === true && XPCConf.config.pgbactive === true) {
        if (XPCondAnyRes && XPCConf.config.pgbmode == 2 && !XPSysError) {

            XPLogTrace('Writing Piggybacks (new mode)...');

            var pgbsDone = {};
            var pgbCounter = 0;
            for ( var cond in XPCondRes) {
                XPLogTrace('Processing condition result of ' + cond);
                if (XPCondRes[cond] === true) {
                    if (XPCConf.pgbconf[cond] !== undefined && XPCConf.pgbconf[cond] !== null) {

                        XPLogTrace('Following piggybacks are matching this condition: ' + XPCConf.pgbconf[cond]);

                        var arr = XPCConf.pgbconf[cond].split(',');
                        for ( var i = 0; i < arr.length; i++) {
                            var currPGBId = arr[i];

                            if (pgbsDone[currPGBId] === undefined || pgbsDone[currPGBId] === false) {

                                if (XPCConf.pgbs[currPGBId] !== undefined && XPCConf.pgbs[currPGBId].pgbType !== null && XPCConf.pgbs[currPGBId].pgbUrl !== null && XPCConf.pgbs[currPGBId].pgbHttpOnly !== null) {

                                    // http-only PGBs shall under no circumstances been fired on a 'https' page!
                                    // check the protocol of the page and see if the current PGB does work on both 'http' and 'https'
                                    if ((XPPrtc == "http:") || (XPPrtc === "https:" && XPCConf.pgbs[currPGBId].pgbHttpOnly === false)) {

                                        var pgbName = XPCConf.pgbs[currPGBId].pgbName;

                                        var pgbUrl = XPCConf.pgbs[currPGBId].pgbUrl;
                                        pgbUrl = pgbUrl.replace(/\[timestamp\]/, XPRand).replace(/\[TIMESTAMP]\]/, XPRand).replace(/\[protocol\]/, XPPrtc);

                                        var pgbType = XPCConf.pgbs[currPGBId].pgbType;

                                        // Image based PGB
                                        if (pgbType == 1) {

                                            XPLogTrace('Processing image-based (type: ' + pgbType + ') piggyback ' + pgbName + ' (' + currPGBId + ')');

                                            var currentPGBImg = document.createElement('img');
                                            currentPGBImg.width = 1;
                                            currentPGBImg.height = 1;
                                            currentPGBImg.border = 0;
                                            currentPGBImg.src = pgbUrl;
                                            currentPGBImg.onload = 'XPLogTrace (\'Piggyback \'+currPGBId+\' successfully loaded. \');';
                                            currentPGBImg.onerror = 'XPLogError (\'Loading piggyback \'+currPGBId+\' failed. \');';

                                            document.getElementsByTagName('BODY')[0].appendChild(currentPGBImg);

                                            XPLogTrace('Firing piggyback ' + currPGBId + ': ' + pgbUrl);

                                            // JavaScript based PGB
                                        } else if (pgbType == 2) {

                                            XPLogTrace('Processing script-based (type: ' + pgbType + ') piggyback ' + pgbName + ' (' + currPGBId + ')');

                                            var currentPGBScr = document.createElement('script');
                                            currentPGBScr.type = 'text/javascript';
                                            currentPGBScr.src = pgbUrl;
                                            currentPGBScr.onload = 'XPLogTrace (\'Piggyback \'+currPGBId+\' successfully loaded. \');';
                                            currentPGBScr.onerror = 'XPLogError (\'Loading piggyback \'+currPGBId+\' failed. \');';

                                            var headArr = document.getElementsByTagName('head');
                                            var headElement;
                                            if (headArr.length == 1) {
                                                headElement = headArr[0];
                                            } else {
                                                XPLogError('F019: No head element found. Cant add script element.');
                                            }

                                            headElement.appendChild(currentPGBScr);

                                            XPLogTrace('Firing piggyback ' + pgbName + ' (' + currPGBId + '): ' + pgbUrl);

                                            // iFrame based PGB
                                        } else if (pgbType == 3) {

                                            XPLogTrace('Processing iFrame-based (type: ' + pgbType + ') piggyback ' + pgbName + ' (' + currPGBId + ')');

                                            // set a blind div around the iFrame
                                            var iframeDiv = document.createElement('div');
                                            iframeDiv.id = 'pgb_div' + currPGBId + XPRand;
                                            iframeDiv.style.position = 'absolute';
                                            iframeDiv.style.left = '0';
                                            iframeDiv.style.top = '0';
                                            iframeDiv.style.position = 'absolute';
                                            iframeDiv.style.width = '0px';
                                            iframeDiv.style.height = '0px';

                                            // set iframe attributes
                                            var currentPGBIfr = document.createElement('iframe');
                                            currentPGBIfr.id = 'pgb_iframe' + currPGBId + XPRand;
                                            currentPGBIfr.name = 'pgb_iframe' + currPGBId + XPRand;
                                            currentPGBIfr.src = pgbUrl;
                                            currentPGBIfr.allowtransparency = 'true';
                                            currentPGBIfr.framespacing = '0';
                                            currentPGBIfr.frameBorder = 'no';
                                            currentPGBIfr.scrolling = 'no';
                                            currentPGBIfr.width = '1';
                                            currentPGBIfr.height = '1';

                                            // append the iframe to the div ...
                                            iframeDiv.appendChild(currentPGBIfr);
                                            // ... and then the div to the page body
                                            document.getElementsByTagName('BODY')[0].appendChild(iframeDiv);

                                            XPLogTrace('Firing piggyback ' + currPGBId + ': ' + pgbUrl);
                                        }
                                        // unknown PGB type
                                        else {
                                            XPLogError('F017: Invalid pgbType (' + pgbType + ') in for ' + pgbName + ' (' + currPGBId + ').');
                                        }
                                        pgbsDone[currPGBId] = true;
                                        pgbCounter++;
                                    } else if (XPPrtc === "https:" && XPCConf.pgbs[currPGBId].pgbHttpOnly === true) {
                                        // secure page / PGB works only on 'http' and has not been fired
                                        XPLogWarn('Piggyback ' + '*' + currPGBId + '*' + ' is http-only and was thus NOT fired on https!');
                                    }
                                } else {
                                    XPLogError('F018: Error in PGBConfig (' + pgbName + ', ' + currPGBId + ')). Undefined type or url.');
                                }
                            } else {
                                XPLogTrace('Piggyback ' + pgbName + ' (' + currPGBId + ') already fired. Ignored.');
                            }
                        }
                    } else {
                        XPLogWarn('No piggybacks for this condition found.');
                    }
                }
            }
            if (pgbCounter === 0) {
                XPLogWarn('New piggyback mode enabled but no piggybacks defined.');
            }
            if (XPCConf.config.pgbcaching) {
                XPPBCCookie();
            }
        }
    }
}

function XPLoadPGBTrcData() {
    try {
        if (XPCConf.config.pgbtracing) {
            XPLogTrace('Loading PGBTrace data');

            var cValueArr = document.cookie.split(';');
            var found = false;
            var content = '';

            for ( var i = 0; i < cValueArr.length; i++) {
                if (cValueArr[i].indexOf(XPCConf.config.pgbtrccname + '=') != -1) {
                    content = unescape(cValueArr[i].split('=')[1]);
                    found = true;
                    break;
                }
            }

            if (!found) {
                XPLogTrace('No PGBTrace data found.');
            } else {
                XPLogTrace('PGBTrace data found: ' + content);
            }

            eval('XPPGBTrcData = { trc: {' + content + '} };');
        } else {
            XPLogTrace('PGB tracing disabled');
        }

    } catch(error) {
        XPLogError('F000: ' + error);
    }
}

function XPSetPGBTrcData() {
    try {
        if (XPCConf.config.pgbtracing) {
            XPLogTrace('Writing PGB trace data');

            if (XPPGBTrcData !== undefined && XPPGBTrcData !== null) {
                var cmd = 'if (XPPGBTrcData.trc.c_' + XPCConf.customerid + ' === undefined) { XPPGBTrcData.trc.c_' + XPCConf.customerid + ' = new Object(); }';
                eval(cmd);

                cmd = 'if (XPPGBTrcData.trc.c_' + XPCConf.customerid + '.e_' + XPParams.event_id + ' === undefined) { XPPGBTrcData.trc.c_' + XPCConf.customerid + '.e_' + XPParams.event_id + ' = 0; }';
                eval(cmd);

                cmd = 'XPPGBTrcData.trc.c_' + XPCConf.customerid + '.e_' + XPParams.event_id + '++;';
                eval(cmd);

                var serializedpgbtrc = '';
                for ( var e1 in XPPGBTrcData.trc) {
                    serializedpgbtrc = serializedpgbtrc + e1 + ': {';
                    for ( var e2 in XPPGBTrcData.trc[e1]) {
                        serializedpgbtrc = serializedpgbtrc + e2 + ': ' + XPPGBTrcData.trc[e1][e2] + ',';
                    }
                    serializedpgbtrc = serializedpgbtrc.substr(0, (serializedpgbtrc.length - 1));
                    serializedpgbtrc = serializedpgbtrc + '},';
                }
                serializedpgbtrc = serializedpgbtrc.substr(0, (serializedpgbtrc.length - 1));

                var lifetime = 0;
                lifetime = (XPCConf.config.pgbtrclifetime !== undefined) ? XPCConf.config.pgbtrclifetime : 0;
                var expiryDateStr = '';
                if (lifetime > 0) {
                    var expiryDate = new Date();
                    expiryDate.setTime(expiryDate.getTime() + (lifetime * 60 * 60 * 1000));
                    expiryDateStr = expiryDate.toLocaleString();
                }

                var currCustDomain = top.location.host;
                currCustDomain = XPGetTopLevelDomainPart(currCustDomain);
                document.cookie = XPCConf.config.pgbtrccname + '=' + escape(serializedpgbtrc) + '; expires=' + expiryDateStr + '; domain='+currCustDomain+'; path=/;';

                if (typeof localStorage !== 'undefined') {
                    localStorage.setItem(XPCConf.config.pgbtrccname, escape(serializedpgbtrc));
                }
                XPLogTrace('Trace cookie set, expires in ' + lifetime + ' hours at ' + expiryDateStr);

            } else {
                XPLogError('F012: XPPGBTrcData null or undefined');
            }
        }

    } catch(error) {
        XPLogError('F000: ' + error);
    }
}

function XPGetTopLevelDomainPart(completeDomain) {
    var domainArray = completeDomain.split('.');
    var numDomainParts = domainArray.length;
    return "." + domainArray[numDomainParts - 2] + "." + domainArray[numDomainParts - 1];	
}

// Session ID
function XPGetSessionId() {
    try {
        if (sessionStorage.XPSessionId === null || sessionStorage.XPSessionId === "") {
            // create a new Session ID if it does not exist
            XPLogTrace('No SessionID found.');
            sessionStorage.XPSessionId = XPRand;
        } else if ((new Date().getTime() - sessionStorage.XPSessionUpdated) > 1800000) {
            // Session expired, create a new Session ID
            XPLogTrace('Session is expired.');
            sessionStorage.XPSessionId = XPRand;
        }

        XPLogTrace('Session timestamp updated.');
        XPLogTrace('SessionID is ' + sessionStorage.XPSessionId + '.');

        sessionStorage.XPSessionUpdated = new Date().getTime();

        return sessionStorage.XPSessionId;
    } catch(e) {
        XPLogWarn("sessionStorage won't work for local files. Please open file via http!");
        return null;
    }
}

function XPCreateParamList(p, config) {
    try {
        var varList = '';

        // add additional parameters
        // replace | with * in URL
        p.hostname = escape(parent.location).replace(/\|/g, '*');

        var sessionIdParam = XPGetSessionId();
        if (sessionIdParam === undefined) {
            sessionIdParam = '';
        }

        p.sessionid = sessionIdParam;
        p.cookieEnabled = navigator.cookieEnabled;
        p.userAgent = navigator.userAgent;
        p.userLang = navigator.language;
        p.userTimezone = (new Date().getTimezoneOffset() / 60) * -1;

        //check if score result has to be transfered via heias pixel
        if (XPCConf.config.livescoreresulttracking === true) {
            p.score1 = XPScoreResult.result.score1;
            p.score2 = XPScoreResult.result.score2;
            p.cluster1 = XPScoreResult.result.cluster1;
            p.cluster2 = XPScoreResult.result.cluster2;

            p.lastVisit = XPScoreResult.debug.lastVisit;
            p.pv7d = XPScoreResult.debug.pv7d;
            p.pv8to14d = XPScoreResult.debug.pv8to14d;
            p.distinctVisit = XPScoreResult.debug.distinctVisit;
        }

        for ( var param in XPParams) {
            if (param != 'customer_id') {
                XPLogTrace('Param processing: ' + param + '=' + XPParams[param]);

                // Rename/Map param names
                var paramName = (eval('config.pmap.' + param) === undefined) ? param : eval('config.pmap.' + param);

                if (paramName !== undefined && paramName !== null) {
                    if (XPParams[param] === null || (XPParams[param] + '') === '') {
                        XPLogWarn('F005: Error while creating paramlist. Empty, null or invalid value for ' + paramName + ' paramter found.');
                    } else {

                        var paramVal = p[param];

                        // load 'pvarmod' from customer config
                        var mod = XPCConf.pvarmod;

                        if (typeof mod === 'undefined') {
                            XPLogWarn('pvarmod is undefined in config');
                        } else {
                            // assign new (modified) vars if applicable
                            if (mod[param] !== undefined) {
                                var oldValue = paramVal;
                                XPLogTrace('-pvarmod- oldValue: ' + oldValue);
                                paramVal = eval(mod[param]);
                                XPLogTrace('-pvarmod- paramVal before escaping: ' + paramVal);
                            }
                            paramVal = escape(unescape(paramVal));

                            if (paramVal != p[param]) {
                                XPLogTrace('Parameter value was escaped: ' + paramVal);
                            }

                            varList += '|' + paramName + '|' + paramVal;
                            XPLogTrace('Param mapping (' + ((param == paramName) ? 'no' : 'yes') + '): ' + param + ' -> ' + paramName);
                        }
                    }
                } else {
                    XPLogError('F006: Error while creating paramlist. Invalid param name found, is null or undefined.');
                }
            }
        }

    } catch(error) {
        XPLogError('F000: ' + error);
        XPLogTrace('Tag call aborted.');
    }

    return varList;
}

function XPCheckout(p) {
    XPParams.event_id = "order";
    XPProfiling(XPParams);
}

function XPLoadCusC(s) {
    try {
        // protocol detection
        var XPPrtc = document.location.protocol;
        if (XPPrtc === 'file:') {
            XPPrtc = 'http:';
        }

        var CDNLocation = (XPIsSSL) ? XPCDNSSLLoc : XPCDNLoc;

        var cconfUrl = XPPrtc + '//' + CDNLocation + '/' + s + '.js';
        XPLogTrace('Loading customer config: ' + cconfUrl);

        var LoadCustomerJs = document.createElement('script');
        LoadCustomerJs.language = 'JavaScript';
        LoadCustomerJs.type = 'text/javascript';
        LoadCustomerJs.id = 'XPCConfig_' + XPRand;
        LoadCustomerJs.src = cconfUrl;
        LoadCustomerJs.onerror = "XPLogError(\'F010: Loading customer config failed\');";

        // append to page body
        document.getElementsByTagName('BODY')[0].appendChild(LoadCustomerJs);

    } catch(error) {
        XPLogError('F000: ' + error);
    }
}

function XPDetectCus() {
    try {
        var domain = top.location.host;
        var domainArray = domain.split('.');

        var numDomainParts = domainArray.length;
        var newDomain = domainArray[numDomainParts - 2] + "." + domainArray[numDomainParts - 1];

        XPLogTrace('Customer auto-detection by hostname: ' + domain);

        return XPLoadCusC(newDomain);
    } catch(error) {
        XPLogError('F000: ' + error);
        return '';
    }
}

function XPParam(a) {
    if (a) {
        return a;
    }
    return '';
}

function XPLogEntry(message, entryType) {
    try {
        if (XPDoLogging !== undefined) {
            if (XPDoLogging) {
                var currEntry;
                if (message && message !== '') {
                    currEntry = entryType + ' [' + new Date() + ']' + ((XPRand === undefined) ? '' : ('\t' + XPRand)) + '\t' + message + '\n';
                    XPTraceLog += currEntry;

                    if (XPFBConsoleOut && console !== undefined) {
                        if (entryType == 'INFO') {
                            console.log(currEntry);
                        } else if (entryType == 'ERR') {
                            console.error(currEntry);
                        } else if (entryType == 'WARN') {
                            console.warn(currEntry);
                        }
                    }
                }
            }
        }
    } catch(error) {
        XPTraceLog = 'FATAL ERROR';
    }
}

function XPLogError(message) {
    XPSysError = true;
    XPLogEntry(message, 'ERR');
}

function XPLogWarn(message) {
    XPSysError = false;
    XPLogEntry(message, 'WARN');
}

function XPLogTrace(message) {
    XPLogEntry(message, 'INFO');
}

function XPPBCCookie() {
    try {
        var currCustDomain = top.location.host;
        currCustDomain = XPGetTopLevelDomainPart(currCustDomain);
        if (XPCConf.config.pgbccname !== null && XPCConf.config.pgbccname !== "") {
            document.cookie = XPCConf.config.pgbccname + '=true; domain='+currCustDomain+'; expires=; path=/;';
            XPLogTrace('PGBCaching cookie set: ' + XPCConf.config.pgbccname + '=true. Will expire when session finished.');
        } else {
            XPLogError('F008: No pgbcache cookie name defined. ');
        }
    } catch(error) {
        XPLogError('F000: ' + error);
    }
}

function XPMakeAgeRange(dateStr) {
    try {
        var pattern = /^\d{2}\.\d{2}\.\d{4}$/;
        if (dateStr !== null && pattern.test(dateStr)) {
            var day = dateStr.split('.')[0];
            var month = dateStr.split('.')[1];
            var year = dateStr.split('.')[2];

            var ageInYears = 0;

            ageInYears = Math.floor((new Date().getTime() - new Date(year, month, day).getTime()) / (365 * 24 * 60 * 60 * 1000));

            if (ageInYears >= 14 && ageInYears <= 19) {
                return 1;
            } else if (ageInYears >= 20 && ageInYears <= 24) {
                return 2;
            } else if (ageInYears >= 25 && ageInYears <= 29) {
                return 3;
            } else if (ageInYears >= 30 && ageInYears <= 34) {
                return 4;
            } else if (ageInYears >= 35 && ageInYears <= 39) {
                return 5;
            } else if (ageInYears >= 40 && ageInYears <= 44) {
                return 6;
            } else if (ageInYears >= 45 && ageInYears <= 49) {
                return 7;
            } else if (ageInYears >= 50 && ageInYears <= 54) {
                return 8;
            } else if (ageInYears >= 55 && ageInYears <= 59) {
                return 9;
            } else if (ageInYears >= 60 && ageInYears <= 64) {
                return 10;
            } else if (ageInYears >= 65 && ageInYears <= 69) {
                return 11;
            } else if (ageInYears >= 70) {
                return 12;
            } else {
                return 0;
            }
        } else {
            XPLogError('FC01: Could not parse date string to determine agerange. Datestring has invalid value.');
            return 0;
        }

    } catch(error) {
        XPLogError('F000: ' + error);
        return 0;
    }
}

function XPSetLog(logging) {
    XPDoLogging = logging;
    XPFBConsoleOut = logging;
}

var XPL_LIVE_SCORE = function() {
    var that = {};

    var DAY = 86400000; // one day in ms
    var DAYS_TO_KEEP = 30;

    var BVAR_1 = -1.73725946085809;
    var BVAR_2 = 1.72674589879073;
    var BVAR_3 = 0.0242078467024682;
    var BVAR_4 = 0.312995067858576;

    var PRODUCT_VIEW_014_CL000_000 = -0.729417489733292;
    var PRODUCT_VIEW_014_CL001_001 = -0.584349727110545;
    var PRODUCT_VIEW_014_CL002_002 = -0.35375687318633;
    var PRODUCT_VIEW_014_CL003_003 = -0.290363726953847;
    var PRODUCT_VIEW_014_CL004_004 = -0.284374775479624;
    var PRODUCT_VIEW_014_CL005_005 = -0.251675916598251;
    var PRODUCT_VIEW_014_CL006_010 = -0.0236943713648684;

    var CLUSTER_CONFIG = new Array(0.26, 0.38, 0.5, 0.65, 1);

    var determineProductView14Cl = function(pview14) {
        if (pview14 === 0) {
            return "000-000";
        } else if (pview14 < 2) {
            return "001-001";
        } else if (pview14 < 3) {
            return "002-002";
        } else if (pview14 < 4) {
            return "003-003";
        } else if (pview14 < 5) {
            return "004-004";
        } else if (pview14 < 6) {
            return "005-005";
        } else if (pview14 < 11) {
            return "006-010";
        } else if (pview14 >= 0) {
            return "011-000";
        }
    };

    var calcRShopDD = function(daysSinceLastvisit) {
        if (typeof daysSinceLastvisit === 'undefined' || daysSinceLastvisit === null) {
            daysSinceLastvisit = 28;
        }
        var quote = (14.0 / (14.0 + (daysSinceLastvisit * 1)));
        return quote;
    };

    var calcScore = function(r_shop_dd, prod_views_ant, shopdd_dist, pview14Cl) {
        var score = 0;

        if (r_shop_dd > -1 && prod_views_ant > -1 && shopdd_dist > -1) {
            var pview14Val = 0;
            if (pview14Cl == "000-000") {
                pview14Val = PRODUCT_VIEW_014_CL000_000;
            } else if (pview14Cl == "001-001") {
                pview14Val = PRODUCT_VIEW_014_CL001_001;
            } else if (pview14Cl == "002-002") {
                pview14Val = PRODUCT_VIEW_014_CL002_002;
            } else if (pview14Cl == "003-003") {
                pview14Val = PRODUCT_VIEW_014_CL003_003;
            } else if (pview14Cl == "004-004") {
                pview14Val = PRODUCT_VIEW_014_CL004_004;
            } else if (pview14Cl == "005-005") {
                pview14Val = PRODUCT_VIEW_014_CL005_005;
            } else if (pview14Cl == "006-010") {
                pview14Val = PRODUCT_VIEW_014_CL006_010;
            }

            score = BVAR_1 + r_shop_dd * BVAR_2 + prod_views_ant * BVAR_3 + shopdd_dist * BVAR_4 + pview14Val;
        }
        return score;
    };

    var calcScoreWithExp = function(score) {
        var exp_score = Math.exp(score) / (Math.exp(score) + 1);
        return exp_score;
    };

    var calcScoreEnhanced = function(score, exp_score) {
        var enhanced_score = 0;
        if (score < 0) {
            if ((score + exp_score) >= 0) {
                enhanced_score = (score + exp_score);
            }
        } else {
            enhanced_score = exp_score;
        }
        return enhanced_score;
    };

    var determineCluster = function(score, clusterConfig) {
        var cluster = -1;
        try {
            for (i = 0; i < clusterConfig.length; i++) {
                var max = clusterConfig[i];
                if ((max < 1 && score < max) || (max === 1 && score <= max)) {
                    return i + 1;
                }
            }
        } catch(error) {
            XPLogWarn('failed to determine cluster: ' + error);
        }
        return cluster;
    };

    var calculateDiffInDays = function(timestamp1, timestamp2) {
        var diff = Math.floor((timestamp1 - timestamp2) / DAY);
        return diff;
    };

    var removeOldEntries = function(eventCounter) {
        for (dayEntry in eventCounter) {
            if (calculateDiffInDays((new Date()).getTime(), that.parseDate(dayEntry)) > DAYS_TO_KEEP) {
                delete eventCounter[dayEntry];
            }
        }
        return eventCounter;
    };


    // +++++++++++++++++++++++++++++ JSON from jquery-json-2.3 +++++++++++++++++++++++++++++++++ //
    /**
     * jQuery.toJSON
     * Converts the given argument into a JSON respresentation.
     *
     * @param o {Mixed} The json-serializble *thing* to be converted
     *
     * If an object has a toJSON prototype, that will be used to get the representation.
     * Non-integer/string keys are skipped in the object, as are keys that point to a
     * function.
     *
     */
    that.toJSON = function(o) {

        if (o === null) {
            return 'null';
        }

        var type = typeof o;

        if (type === 'undefined') {
            return undefined;
        }
        if (type === 'number' || type === 'boolean') {
            return '' + o;
        }
        if (type === 'string') {
            return that.quoteString(o);
        }
        if (type === 'object') {
            if (typeof o.toJSON === 'function') {
                return that.toJSON(o.toJSON());
            }
            if (o.constructor === Date) {
                var month = o.getUTCMonth() + 1,
                day = o.getUTCDate(),
                year = o.getUTCFullYear(),
                hours = o.getUTCHours(),
                minutes = o.getUTCMinutes(),
                seconds = o.getUTCSeconds(),
                milli = o.getUTCMilliseconds();

                if (month < 10) {
                    month = '0' + month;
                }
                if (day < 10) {
                    day = '0' + day;
                }
                if (hours < 10) {
                    hours = '0' + hours;
                }
                if (minutes < 10) {
                    minutes = '0' + minutes;
                }
                if (seconds < 10) {
                    seconds = '0' + seconds;
                }
                if (milli < 100) {
                    milli = '0' + milli;
                }
                if (milli < 10) {
                    milli = '0' + milli;
                }
                return '"' + year + '-' + month + '-' + day + 'T' +
                hours + ':' + minutes + ':' + seconds +
                '.' + milli + 'Z"';
            }
            if (o.constructor === Array) {
                var ret = [];
                for (var i = 0; i < o.length; i++) {
                    ret.push(that.toJSON(o[i]) || 'null');
                }
                return '[' + ret.join(',') + ']';
            }
            var name,
            val,
            pairs = [];
            for (var k in o) {
                type = typeof k;
                if (type === 'number') {
                    name = '"' + k + '"';
                } else if (type === 'string') {
                    name = that.quoteString(k);
                } else {
                    // Keys must be numerical or string. Skip others
                    continue;
                }
                type = typeof o[k];

                if (type === 'function' || type === 'undefined') {
                    // Invalid values like these return undefined
                    // from toJSON, however those object members
                    // shouldn't be included in the JSON string at all.
                    continue;
                }
                val = that.toJSON(o[k]);
                pairs.push(name + ':' + val);
            }
            return '{' + pairs.join(',') + '}';
        }
    };

    /**
     * jQuery.evalJSON
     * Evaluates a given piece of json source.
     *
     * @param src {String}
     */
    that.evalJSON = function(src) {
        return eval('(' + src + ')');
    };

    /**
     * jQuery.secureEvalJSON
     * Evals JSON in a way that is *more* secure.
     *
     * @param src {String}
     */
    that.secureEvalJSON = function(src) {
        var filtered = src.replace(/\\["\\\/bfnrtu]/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, '');

        if (/^[\],:{}\s]*$/.test(filtered)) {
            return eval('(' + src + ')');
        } else {
            throw new SyntaxError('Error parsing JSON, source is not valid.');
        }
    };

    /**
     * jQuery.quoteString
     * Returns a string-repr of a string, escaping quotes intelligently.
     * Mostly a support function for toJSON.
     * Examples:
     * >>> jQuery.quoteString('apple')
     * "apple"
     *
     * >>> jQuery.quoteString('"Where are we going?", she asked.')
     * "\"Where are we going?\", she asked."
     */
    that.quoteString = function(string) {
        var escapeable = /["\\\x00-\x1f\x7f-\x9f]/g,
        meta = {
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"': '\\"',
            '\\': '\\\\'
        };
        if (string.match(escapeable)) {
            return '"' + string.replace(escapeable,
            function(a) {
                var c = meta[a];
                if (typeof c === 'string') {
                    return c;
                }
                c = a.charCodeAt();
                return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
            }) + '"';
        }
        return '"' + string + '"';
    };


    // +++++++++++++++++++ JSON parser ++++++++++++++++++++++++++++++++++ //
    that.trim = String.prototype.trim ? function(text) {
        return text === null ? '' :  String.prototype.trim.call(text);
    } :
    // Otherwise use our own trimming functionality
    function(text) {
        return text === null ? '' : text.toString().replace(trimLeft, '').replace(trimRight, '');
    };

    that.parseJSON = function(data) {
        if (typeof data !== 'string' || !data) {
            return null;
        }

        // Make sure leading/trailing whitespace is removed (IE can't handle it)
        data = that.trim(data);

        // JSON RegExp
        var rvalidchars = /^[\],:{}\s]*$/;
        var rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
        var rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
        var rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g;
        
        // Make sure the incoming data is actual JSON
        // Logic borrowed from http://json.org/json2.js
        if (rvalidchars.test(data.replace(rvalidescape, '@').replace(rvalidtokens, ']').replace(rvalidbraces, ''))) {
            return (new Function('return ' + data))();
        }
        return null;
    };


    /** Parses a date String and returns ms */
    that.parseDate = function(dateString) {
        return Date.parse(dateString.replace(/-/g,'/'));
    };

    /** Parses a date String with a format like '2011-06-23' into a JavaScript date. */
    that.parseFormattedDate = function(dateString) {
        return new Date(that.parseDate(dateString));
    };

    /** Formats a given date as String with a pattern like '2011-06-23' */
    that.dateFormatter = function(d) {
        var dateString = d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate();

        if (dateString.match(/\d{2,4}\-\d{1,2}-\d{1,2}/)) { //fill date with leading zeros, if not present
            var firstIndex = dateString.indexOf('-');
            var lastIndex = dateString.lastIndexOf('-');
            var yearStr = ('20' + dateString.substr(0, firstIndex)).slice(-4) + '-';
            var monthStr = ('0' + dateString.substring(firstIndex + 1, lastIndex)).slice(-2) + '-';
            var dayStr = ('0' + dateString.substr(lastIndex + 1, dateString.length)).slice(-2);
            dateString = (yearStr + monthStr + dayStr);
        }

        return dateString;
    };

    /** Returns a formatted date String with today's date */
    that.todayString = function() {
        return that.dateFormatter(new Date());
    };

    that.setLastShopVisit = function() {
        localStorage.setItem('xpl_last_shop_visit', that.todayString());
    };

    that.getLastShopVisitInDaysAgo = function() {
        var storedDate = localStorage.getItem('xpl_last_shop_visit');
        if (storedDate !== null) {
            var parsedDate;
            try {
                parsedDate = that.parseDate(storedDate);
                var result = calculateDiffInDays((new Date()).getTime(), parsedDate);
                XPLogTrace('determined last shop visit: ' + result + ' days ago');
                return result;
            } catch(e) {}
        }
        return null;
    };

    that.getEventCounts = function() {
        var jsonString = localStorage.getItem('xpl_event_counter');
        if (jsonString === null) {
            return null;
        }
        return that.parseJSON(jsonString);
    };

    that.getNumberOfEvents = function(eventName, maxAgeInDays, minAgeInDays) {
        if (minAgeInDays === undefined) {
            minAgeInDays = 0;
        }
        if (maxAgeInDays < minAgeInDays) {
            return 0;
        }
        var result = 0;
        var minDate = new Date();
        if (minAgeInDays !== 0) {
            minDate = new Date((new Date() - (minAgeInDays * DAY)));
        }

        var eventCounter = that.getEventCounts();
        for (dayEntry in eventCounter) {
            var diff = calculateDiffInDays(minDate.getTime(), that.parseDate(dayEntry));
            if (diff <= maxAgeInDays && diff >= 0) {
                if (eventCounter[dayEntry][eventName] !== undefined) {
                    result += eventCounter[dayEntry][eventName];
                }
            }
        }

        XPLogTrace('Returning count for event "' + eventName + '": ' + result);
        return result;
    };

    that.determineDistinctShopVisits = function(maxAgeInDays) {
        if (maxAgeInDays === undefined) {
            maxAgeInDays = DAYS_TO_KEEP;
        }
        var result = 0;
        var eventCounter = that.getEventCounts();
        for (dayEntry in eventCounter) {
            var diff = calculateDiffInDays((new Date()).getTime(), that.parseDate(dayEntry));
            if (diff <= maxAgeInDays && diff >= 0) {
                result++;
            }
        }
        XPLogTrace('determined distinct shop visits for the last ' + maxAgeInDays + ' days: ' + result);
        return result;
    };

    that.addEvent = function(eventName) {
        if (eventName === undefined) {
            eventName = 'unknown';
        }

        var dailyEventCounter = that.getEventCounts();
        if (dailyEventCounter === null) {
            dailyEventCounter = {};
        }

        var today = that.todayString();

        if (dailyEventCounter[today] === undefined) {
            dailyEventCounter[today] = {};
            dailyEventCounter[today][eventName] = 1;
        } else if (dailyEventCounter[today][eventName] === undefined) {
            dailyEventCounter[today][eventName] = 1;
        } else {
            dailyEventCounter[today][eventName] += 1;
        }

        dailyEventCounter = removeOldEntries(dailyEventCounter);

        var jsonString = that.toJSON(dailyEventCounter);

        localStorage.setItem('xpl_event_counter', jsonString);
        XPLogTrace('stored event "' + eventName + '" in tracing cookie / localStorage');
    };

    that.calculateLiveScore = function() {
        XPLogTrace('start calculating LiveScore...');

        var lastShopVisitInDaysAgo = that.getLastShopVisitInDaysAgo();
        var rShopDD = calcRShopDD(lastShopVisitInDaysAgo);

        var productViewsLast7Days = that.getNumberOfEvents('product_view', 7);
        var productViews8To14Days = that.getNumberOfEvents('product_view', 14, 8);
        var productViewsAnt = ( (productViews8To14Days === 0) ? 0 : ( productViewsLast7Days / productViews8To14Days) );
        var distinctShopVisits = that.determineDistinctShopVisits(14);
        var productView14Cl = determineProductView14Cl(productViewsLast7Days + productViews8To14Days);

        var scoreVal1 = calcScore(rShopDD, productViewsAnt, distinctShopVisits, productView14Cl);
        var scoreValExp = calcScoreWithExp(scoreVal1);
        var scoreVal2 = calcScoreEnhanced(scoreVal1, scoreValExp);

        var clusterGroup1 = determineCluster(scoreValExp, CLUSTER_CONFIG);
        var clusterGroup2 = determineCluster(scoreVal2, CLUSTER_CONFIG);

        XPLogTrace('user score calculation done.');
        XPLogTrace('user score cluster1 is: ' + clusterGroup1 + ' (' + scoreValExp + ').');
        XPLogTrace('user score cluster2 is: ' + clusterGroup2 + ' (' + scoreVal2 + ').');

        var scoreResult = {};
        scoreResult.result = {};
        scoreResult.debug = {};

        scoreResult.debug.lastVisit = lastShopVisitInDaysAgo;
        scoreResult.debug.pv7d = productViewsLast7Days;
        scoreResult.debug.pv8to14d = productViews8To14Days;
        scoreResult.debug.distinctVisit = distinctShopVisits;

        if (productViewsLast7Days === 0 && productViews8To14Days === 0) {
            scoreResult.result.score1 = '';
            scoreResult.result.score2 = '';
            scoreResult.result.cluster1 = '';
            scoreResult.result.cluster2 = '';
        } else {
            scoreResult.result.score1 = scoreValExp;
            scoreResult.result.score2 = scoreVal2;
            scoreResult.result.cluster1 = clusterGroup1;
            scoreResult.result.cluster2 = clusterGroup2;
        }

        return scoreResult;
    };

    return that;
};

function XPTestLocalStorage() {
    try {
        return !!localStorage.getItem;
    } catch(e) {
        return false;
    }
}

function XPDetermineScore(ev) {
    var scoreResult = {};
    scoreResult.result = {};
    scoreResult.debug = {};
    scoreResult.result.score1 = '';
    scoreResult.result.score2 = '';
    scoreResult.result.cluster1 = '';
    scoreResult.result.cluster2 = '';
    scoreResult.debug.lastVisit = '';
    scoreResult.debug.pv7d = '';
    scoreResult.debug.pv8to14d = '';
    scoreResult.debug.distinctVisit = '';
    try {
        if (XPTestLocalStorage()) {
            var ls = XPL_LIVE_SCORE();
            ls.addEvent(ev);
            scoreResult = ls.calculateLiveScore();
            ls.setLastShopVisit();
        } else {
            XPLogWarn('Local Storage is not available. Aborted calculation of livescore!');
        }
    } catch(error) {
        XPLogError('F000: ' + error);
    }
    return scoreResult;
}

