mmRequestCallbacks[1]({"Scripts":[],"Campaigns":[{"Name":"Recirculation-widget-parsely-A-B-test-PROD","Type":"ABnMVT","CSName":"","HighLevelApiVersion":"1.12","PagePrefix":"","Scripts":[{"Name":"Rendering","Type":"script","Attrs":{"type":"text/javascript"},"Data":"var config = {\n    \"selectorsToHide\": null,\n    \"useSecondRequest\": false,\n    \"elements\": null\n};\n\nif (config.useSecondRequest) {\n    activateCampaign();\n} else {\n    render();\n}\n\ncampaign.events.on(\"urlChange\", activateCampaign);\n\nfunction activateCampaign() {\n    if (isRenderRequired()) {\n        var selectorsToHide = getSelectorsToHide();\n        hide(selectorsToHide);\n        when(isVisitorQualified())\n            .done(function () {\n                renderer.getContent().always(function () {\n                    render();\n                    show(selectorsToHide);\n                });\n            })\n            .fail(function () {\n                show(selectorsToHide);\n            });\n    }\n}\n\nfunction isRenderRequired() {\n    if (config.elements === null) { return true; }\n\n    var url = window.deproxy ? window.deproxy(window.location).href : window.location.href;\n    for (var i = 0; i < config.elements.length; i++) {\n        if (isUrlMatched(url, config.elements[i].includedUrls, config.elements[i].excludedUrls)) {\n            return true;\n        }\n    }\n    return false;\n}\n\nfunction hide(selectorsToHide) {\n    if (selectorsToHide) {\n        renderer.hide(selectorsToHide, \"ucb\");\n    }\n}\n\nfunction show(selectorsToHide) {\n    if (selectorsToHide) {\n        renderer.show(\"ucb\");\n    }\n}\n\nfunction getSelectorsToHide() {\n    if (config.elements === null) { return config.selectorsToHide; }\n\n    var url = window.deproxy ? window.deproxy(window.location).href : window.location.href;\n    var selectors = \"\";\n    for (var i = 0; i < config.elements.length; i++) {\n        if (isUrlMatched(url, config.elements[i].includedUrls, config.elements[i].excludedUrls)) {\n            selectors += \" \" + config.elements[i].selectors;\n        }\n    }\n    return selectors;\n}\n\nfunction render() {\n    renderCss();\n    renderJs();\n    campaign.events.trigger(\"lastRequest\");\n\n    var campaignName = campaign.getName();\n    window.MMExperience = window.MMExperience || {};\n    if(!window.MMExperience[campaignName]){\n        window.MMExperience[campaignName] = campaign.getExperience();\n    }\n}\n\nfunction renderJs() {\n    var elementsToRender = campaign.getElements();\n    for (var i in elementsToRender) {\n        if (elementsToRender.hasOwnProperty(i)) {\n            var element = elementsToRender[i];\n            renderer.runVariantJs(element);\n        }\n    }\n}\n\nfunction renderCss() {\n    var styles = campaign.getStyles();\n    if (styles.length) {\n        dom.addCss(styles);\n    }\n}\n\nfunction isVisitorQualified() {\n    if (window.isCampaignDesignMode) {\n        return true;\n    }\n    var rules = campaign.scope.qualificationRules || [];\n    var results = [];\n    for (var i = 0; i < rules.length; i++) {\n        var result = rules[i]();\n        if (typeof result.then !== \"function\") {\n            result = Deferred()[result ? \"resolve\" : \"reject\"]().promise();\n        }\n        results.push(result);\n    }\n    return when.apply(this, results);\n}\n\nfunction isUrlMatched(url, includedUrls, excludedUrls) {\n    var isIncluded = isMasksMatch(url, includedUrls);\n    var isExcluded = isMasksMatch(url, excludedUrls);\n    return isIncluded && !isExcluded;\n}\n\nfunction isMasksMatch(url, masks) {\n    if (!url) {\n        return false;\n    }\n    url = url.toLowerCase();\n    var matchedMasks = 0;\n\n    for (var i = 0; i < masks.length; i++) {\n        var mask = masks[i].toLowerCase();\n        if (isMaskMatch(url, window.deproxy({\n                href: mask\n            }).href)) {\n            matchedMasks = matchedMasks + 1;\n        }\n    };\n    return matchedMasks > 0;\n}\n\nfunction isMaskMatch(url, originalMask) {\n    var mask = \"^\";\n    var pos = 0;\n    while (originalMask.length > pos) {\n        var char = originalMask[pos];\n        if (char == \"*\") {\n            mask = mask + \".*\";\n            pos = pos + 1;\n        } else if (char == \"(\") {\n            var posClosing = originalMask.indexOf(\")\", pos + 1);\n            var posNextOpening = originalMask.indexOf(\"(\", pos + 1);\n            if (posClosing > pos && (posNextOpening < 0 || posClosing < posNextOpening)) {\n                mask = mask + \".*\";\n                pos = posClosing + 1;\n            } else {\n                return false;\n            }\n        } else {\n            mask = mask + char;\n            pos = pos + 1;\n        }\n    }\n    mask = mask + \"$\";\n    mask = mask.replace(\"?\", \"\\?\");\n    var r = new RegExp(mask);\n    return r.test(url);\n}","Order":5999,"HighLevelApiVersion":"1.12"},{"Name":"Adobe Analytics","Type":"script","Attrs":{"type":"text/javascript"},"Data":"var config = {\n    \"eVar\": \"51\",\n    \"sVar\": \"\",\n    \"sProp\": \"\",\n    \"append\": \"\"\n}\n// append could be either 'page', 'session' or empty\n\ntry { if (window.self !== window.top) { return; } }\ncatch (e) { return; }\n\ncampaign.events.on('lastRequest', function () {\n    if (!isGenerated()) { return }\n    waitForAdobe(function () {\n        sendPageview();\n    });\n});\n\nfunction isGenerated() {\n    var e = campaign.getExperience();\n    for (var k in e) {\n        if(e.hasOwnProperty(k)) return true;\n    }\n    return false;\n}\n\nfunction waitForAdobe(callback) {\n    var timeout = false;\n    when(function () {\n        return typeof window[config.sVar || 's'] === 'object';\n    }, function () {\n        return timeout;\n    }).done(function () {\n        callback();\n    });\n    setTimeout(function () {\n        timeout = true;\n    }, 10e3);\n}\n\nfunction sendPageview() {\n    var params = [];\n    if(config.eVar){\n        params.push('eVar' + config.eVar);\n    }\n\n    if('prop' + config.sProp){\n        params.push('prop' + config.sProp);\n    }\n\n    for(var i = 0; i < params.length; i++){\n        window[config.sVar || 's'][params[i]] = getExperienceData(params[i]);\n    }\n\n    window[config.sVar || 's'].linkTrackVars = params.join(',');\n    window[config.sVar || 's'].tl(true, 'o', 'Maxymiser' + (isProduction() ? '' : ' QA'));\n}\n\nfunction getExperienceData(param) {\n    var store = getDataStore(param);\n\n    var experience = campaign.getName() + '=' + function(){\n        var e = campaign.getExperience();\n        var variants = [];\n        for (var el in e) {\n            variants.push(el + ':' + e[el]);\n        }\n        return variants.join('|');\n    }();\n\n    var dataArray = store.get();\n\n    var index = -1;\n    for (var i = dataArray.length; i--;) {\n        if (new RegExp('(' + campaign.getName() + ')' + '\\=').test(dataArray[i])) {\n            index = i;\n            break;\n        }\n    }\n    if (index === -1) {\n        dataArray.push(experience);\n    } else {\n        dataArray[index] = experience;\n    }\n\n    while (dataArray.join(',').length > 150 && dataArray.length > 0) {\n        dataArray.shift();\n    }\n\n    store.set(dataArray);\n\n    return dataArray.join(',')\n\n}\n\nfunction getDataStore(key) {\n    switch (config.append) {\n        case 'page':\n            return {\n                get: function () {\n                    return window['mm-aa-' + key] || [];\n                },\n                set: function (value) {\n                    window['mm-aa-' + key] = value;\n                }\n            };\n        case 'session':\n            return {\n                get: function () {\n                    return visitor.getData('mm-aa-' + key) || [];\n                },\n                set: function (value) {\n                    visitor.setData('mm-aa-' + key, value);\n                }\n            };\n        default:\n            return {\n                get: function () {\n                    return []\n                },\n                set: function (value) {\n                }\n            };\n    }\n}\n\nfunction isProduction() {\n    if (location.search.toLowerCase().indexOf('mmcore.') > -1) {\n        return false;\n    }\n\n    function removeExpiration(v) {\n        return v ? v.replace(/^\\d\\|/, '') : '';\n    }\n\n    var storage = mmsystem.getConfig().storageType;\n    if (storage === 'cookie-key-value' || storage === 'cookie-key-value-secure') {\n        if (/mmapi.p.cfgid/i.test(document.cookie) || /mmapi.p.un/i.test(document.cookie)) {\n            return false;\n        } else {\n            return true;\n        }\n    }\n    var mmcoreP = readCookieStorage('mmcore.store.p.') || {};\n    var mmcoreS = readCookieStorage('mmcore.store.s.') || {};\n    var mmapiP = readCookieStorage('mmapi.store.p.') || {};\n    var mmapiS = readCookieStorage('mmapi.store.s.') || {};\n    var storageTypes = [mmcoreP, mmcoreS, mmapiP, mmapiS];\n    var storageKeys = {\n        'mmparams.p': 1,\n        'mmparams.d': 1\n    };\n    var utils = {\n        'un': 1,\n        'cfgID': 1,\n        'pruh': 1\n    };\n    for (var l = storageTypes.length; l--;) {\n        var storageType = storageTypes[l];\n        for (var storageKey in (storageKeys || {})) {\n            for (var util in (utils || {})) {\n                if ((storageType[storageKey] || {})[util]) {\n                    return false;\n                }\n            }\n        }\n    }\n\n    function readCookieStorage(name) {\n        var res = {},\n            whole = '',\n            i = 0,\n            chunk;\n        while ((chunk = getCookie(name + i++))) {\n            whole += chunk;\n        }\n        whole = decodeURIComponent(whole);\n        try {\n            res = JSON.parse(whole);\n        } catch (e) {\n        }\n        return res;\n    }\n\n    function getCookie(name) {\n        var r = new RegExp('(?:^|; )' + encodeURIComponent(name).replace(/([.$?*|{}()\\[\\]\\\\\\/+^])/g, '\\\\$1') + '=([^;]+)');\n        var value = (document.cookie.match(r) || ['', ''])[1];\n        return value;\n    }\n\n    return true;\n}\n","Order":5000,"HighLevelApiVersion":"1.12"},{"Name":"V2127531412","Type":"script","Attrs":{"type":"text/javascript"},"Data":"/*configuration block begin*/\nvar config = {\n\t\"actionName\": \"Parsely widget\",\n\t\"value\": 1,\n\t\"attr\": \"parsely widget\",\n\t\"multiplier\": 100,\n\t\"trackValueSelector\": \"\",\n\t\"urls\": null\n};\n/*configuration block end*/\n\nvar domReadyDeferred = Deferred();\nevents.domReady(function(){\n    domReadyDeferred.resolve();\n});\n\nvar toUngroupedNumber = function(input, decimalDelimiter) {\n    var groupSymbolsMatches = input.match(/[\\.,' ]/g);\n    //if the numbers are grouped\n    if (groupSymbolsMatches) {\n        //delimiter for decimal cannot be used as groups delimiter\n        var allowedSymbols = \".,' \".replace(decimalDelimiter, '');\n        var groupsDelim = groupSymbolsMatches[0];\n        //groups delimiter is allowed\n        if (allowedSymbols.indexOf(groupsDelim) == -1) {\n            return null;\n        }\n        //only one symbol used for grouping\n        for (var i = 0; i < groupSymbolsMatches.length; i++) {\n            if (groupSymbolsMatches[i] != groupsDelim) {\n                return null;\n            }\n        }\n    }\n    return input.replace(/[\\.,' ]/g, '');\n};\n\nvar getDecimalDelimiter = function(input) {\n    var decimalPartWithDelim = /[\\.,]\\d{1,2}$/.exec(input);\n    if (decimalPartWithDelim) {\n        return decimalPartWithDelim[0][0];\n    } else {\n        return \"\";\n    }\n};\n\nvar getDecimalPart = function(input) {\n    var decimalPartWithDelim = /[\\.,]\\d{1,2}$/.exec(input);\n    if (decimalPartWithDelim) {\n        return decimalPartWithDelim[0].substr(1);\n    } else {\n        return \"0\";\n    }\n};\n\nvar getIntegerPart = function(input) {\n    return input.replace(/[\\.,]\\d{1,2}$/, '');\n};\n\nvar parseValue = function(value) {\n    //get numbers part\n    var numberString = (/.?\\d+([\\S\\s]*\\d)?/).exec(value);\n    if (numberString == null) {\n        return null;\n    }\n    numberString = numberString[0];\n    //is negative value\n    if (numberString[0] === \"-\") {\n        return null;\n    }\n    //remove first character if it is not number\n    if (/^\\D/.test(numberString)) {\n        numberString = numberString.substr(1);\n    }\n    //number with wrong format\n    if (!(/^((\\d{1,3}([\\.,' ]\\d{3})*)|(\\d+))([\\.,]\\d{1,2})?$/.test(numberString))) {\n        return null;\n    }\n\n    var delimSymbol = getDecimalDelimiter(numberString);\n    var decimalPart = getDecimalPart(numberString);\n    var integerPart = getIntegerPart(numberString);\n    integerPart = toUngroupedNumber(integerPart, delimSymbol);\n    if (integerPart == null) {\n        return null;\n    }\n\n    return Math.floor((integerPart + \".\" + decimalPart) * config.multiplier);\n};\n\nvar isUrlMatched = function(url, includedUrls, excludedUrls) {\n    var isIncluded = isMasksMatch(url, includedUrls);\n    var isExcluded = isMasksMatch(url, excludedUrls);\n    return isIncluded && !isExcluded;\n};\n\nvar isMasksMatch = function(url, masks) {\n    if (!url) {\n        return false;\n    }\n    url = url.toLowerCase();\n\n    for (var i = 0; i < masks.length; i++) {\n        var mask = masks[i].toLowerCase();\n        if (isMaskMatch(url, window.deproxy ? window.deproxy({\n                href: mask\n            }).href : mask)) {\n            return true;\n        }\n    }\n    return false;\n};\n\nvar isMaskMatch = function(url, originalMask) {\n    var mask = '^';\n    var pos = 0;\n    while (originalMask.length > pos) {\n        var char = originalMask[pos];\n        if (char == '*') {\n            mask = mask + '.*';\n            pos = pos + 1;\n        } else if (char == '(') {\n            var posClosing = originalMask.indexOf(')', pos + 1);\n            var posNextOpening = originalMask.indexOf('(', pos + 1);\n            if (posClosing > pos && (posNextOpening < 0 || posClosing < posNextOpening)) {\n                mask = mask + '.*';\n                pos = posClosing + 1;\n            } else {\n                return false;\n            }\n        } else {\n            mask = mask + char;\n            pos = pos + 1;\n        }\n    }\n    mask = mask + '$';\n    mask = mask.replace('?', \"\\\\?\");\n    var r = new RegExp(mask);\n    return r.test(url);\n};\n\nvar waitForElement = function(elementSelector, timeoutValue){\n    var elementDeferred = Deferred();\n    var timeout = false;\n    \n    domReadyDeferred.promise().then(function(){\n        setTimeout(function () {\n            timeout = true;\n        }, timeoutValue);    \n    });\n\n    renderer.when(function(){\n        return timeout || dom.find(elementSelector).length;\n    })\n    .done(function(){ elementDeferred.resolve(); })\n    .fail(function(){ elementDeferred.reject(); });\n\n    return elementDeferred.promise();\n};\n\nvar getActionValue = function() {\n    var deferred = Deferred();\n\n    if (config.trackValueSelector) {\n        waitForElement(config.trackValueSelector, 2000)\n            .done(function(){\n                var elements = dom.find(config.trackValueSelector);\n                if (elements.length) {\n                    deferred.resolveWith(this, [parseValue(elements[0].textContent)]);\n                } else {\n                    deferred.reject();\n                }\n            })\n            .fail(function(){\n                deferred.reject();\n            });\n    } else {\n        deferred.resolveWith(this, [config.value]);\n    }\n\n    return deferred.promise();\n};\n\nvar getCurrentUrl = function() {\n    return window.deproxy\n        ? window.deproxy(window.location).href\n        : window.location.href;\n};\n\nvar isActionRequired = function() {\n    return !config.urls\n        ? true\n        : !!isUrlMatched(\n            getCurrentUrl(),\n            config.urls.includedUrls,\n            config.urls.excludedUrls);\n};\n\nvar trackViewAction = function() {\n    if (isActionRequired()) {\n        getActionValue().done(function (trackValue) {\n            if (trackValue) {\n                actions.send(config.actionName, trackValue, config.attr);\n            }\n        });\n    }\n};\n\ntrackViewAction();\n\ncampaign.events.on('urlChange', trackViewAction);","Order":4000,"HighLevelApiVersion":"1.12"}],"Elements":[{"Name":"element1","VariantName":"Default","Order":0}],"Recommendations":[]}],"MRRules":[],"PersistData":[{"Name":"srv","IsGlobal":false,"Value":"prodiadcgeu02","Expiration":365},{"Name":"bid","IsGlobal":false,"Value":"prodiadcgeu02","Expiration":0.00694},{"Name":"pd","IsGlobal":false,"Value":"478619439|AQAAAApVAwCqZl8aixOgiwABEgABQgCNUMeSAQCKKAAzOlfYSIooADM6V9hIAAAAAP//////////AAZEaXJlY3QBixMBAAAAAAAAAAAA////////////////AQAbQwEAfKFa+tqLEwD/////AYsTixP//wEAAAEAAAAAAZ40AwBHGAQAAAAAAAAAAUU=","Expiration":365}],"SiteInfo":[{"Url":"economist.com","ID":550}],"SystemData":[{"Version":"1.0","RequestId":1,"ResponseId":1}],"GenInfo":{"Recirculation-widget-parsely-A-B-test-PROD":{"element1":"Default"}},"ServerAttributes":{},"Iteration":"4iTqj5sWIYtpvTzuvy8CQonkX78","Packages":["mmpackage-1.12.js"]});