// qa-v1 s-na
//
(function() {
    // Johnny five out of here if FPS exists
    if (window && window.FPS) {
        return;
    }
    function checkT1(value){
        if( checkT2(value) ){
            return false;
        }

        return /^https?:\/\/(([a-zA-Z0-9-]){0,62}\.)*((ford|lincoln|lincolncanada)\.com|ford\.ca|fps-qa.azurewebsites\.net|ford\.mx)/.test(value);
    }
    function getT2InT1(){
        try{
            let currentURL = new URL(Encode(window.location));

            return /^https?:\/\/(([a-zA-Z0-9-]){0,62}\.)*ford\.com\/local/.test(currentURL);

        } catch(err) {
            console.log("checkT2",err);
        }

        return false;
    }
    function checkT2(value){
        if (/^https?:\/\/(([a-zA-Z0-9-]){0,62}\.)*(buyfordnow\.com)/.test(value)){
            return true;
        }

        if( getT2InT1() ){
            return true;
        }

        return /^https?:\/\/(([a-zA-Z0-9-]){0,62}\.)*(local\.ford\.com)/.test(value);
    }
    function getTier(value){
        if (checkT1(value)) {
            return "t1";
        }

        if (checkT2(value)) {
            return "t2";
        }

        return "tn";
    }
    var cookieOnLoad = {
        get: function(name) {
            var nameEQ = name + "=";
            var ca = document.cookie.split(';');
            for (var i = 0; i < ca.length; i++) {
                var c = ca[i];
                while (c.charAt(0) == ' ') c = c.substring(1, c.length);
                if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
            }
            return null;
        }
    };
    function encodeURL(urlString){
        try{
            let url = new URL(urlString);

            url.pathname = url.pathname.split("/").map((path)=>{
                if(/[^-a-z0-9@:%_+.~#?&/=]/ig.test(path)){
                    return encodeURIComponent(path);
                }
                return path;
            })
                .join('/');


            for( let [key,value] of url.searchParams ){
                url.searchParams.set(key,encodeURI(value));
            }

            return url.href;
        }catch(err){
            return urlString;
        }
    }
    var blockNetworkRequests = false;
    var disableInsights = true;
    var gt_slt = cookieOnLoad.get("gt_slt");
    var privacysettings = localStorage.getItem("privacysettings");
    var baseUrl = window.location.protocol + "//" + window.location.hostname;
    var tier = getTier(baseUrl);
    var blockNetworkRequestsDomain = tier === "tn";
    var xdcGTUID = '';
    var xdcRegSrvc = 'https://api.mss.ford.com/api/fps/personalization/v1/checkXDC';
    var xdcDomain = 'ford.com';
    var xdcPath = 'https://api.mss.ford.com/api/fps';
    var xdcPathSet= 'https://api.mss.ford.com/api/fps';
    var xdcPathGet= 'https://api.mss.ford.com/api/fps';
    var xdcPathSetExternalRef = 'https://api.mss.ford.com/api/fps';
    var tagBrand = 'Ford';
    var tagCountry = 'USA';
    var cookieDaysToLive = 365;
    var personalizationActive = true;
    var setExRefHasUpdatedCookie = false;
    var resolvedTier = "";
    var ccpaDomains = [];
    var apiPaths = {
        set:"/personalization/v1/set"
        , get: "/personalization/v1/get?uid="
        , setExternalRef: "/externalref/v1/set"
    };
    var vdmActiveNameplates = {"Mustang":{"2025":["ecoboostfastback","ecoboostconvertible","ecoboostpremiumfastback","ecoboostpremiumconvertible","gtfastback","gtpremiumfastback","gtpremiumconvertible","darkhorse","darkhorsepremium"],"2026":["ecoboostfastback","ecoboostconvertible","ecoboostpremiumfastback","ecoboostpremiumconvertible","gtfastback","gtpremiumfastback","gtpremiumconvertible","darkhorse","darkhorsepremium","darkhorsesc"],"Powers_2025":["eco,gas","eco,gas","eco,gas","eco,gas","gas","gas","gas","gas","gas"],"Powers_2026":["eco,gas","eco,gas","eco,gas","eco,gas","gas","gas","gas","gas","gas","gas"]},"Explorer":{"2026":["active","st-line","tremor","st","platinum","base"],"Powers_2026":["eco,gas","eco,gas","eco,gas","eco,gas","eco,gas","eco,gas"]},"Expedition":{"2025":["active","activemax","tremor","kingranch","kingranchmax","platinum","platinummax"],"2026":["active","activemax","tremor","platinum","platinummax","kingranch","kingranchmax"],"Powers_2025":["eco,gas","eco,gas","eco,gas","eco,gas","eco,gas","eco,gas","eco,gas"],"Powers_2026":["eco,gas","eco,gas","eco,gas","eco,gas","eco,gas","eco,gas","eco,gas"]},"Transit Chassis":{"2025":["cutaway","chassiscab"],"2026":["cutaway","chassiscab"],"Powers_2025":["eco,gas","eco,gas"],"Powers_2026":["eco,gas","eco,gas"]},"Econoline Cutaway":{"2026":["e-350srwcutaway","e-350drwcutaway","e-450drwcutaway"],"2027":["e-350srwcutaway","e-350drwcutaway","e-450drwcutaway"],"Powers_2026":["gas","gas","gas"],"Powers_2027":[null,null,null]},"F-650-750":{"2026":["f-650sdgasstraightframe","f-650sddieselstraightframe","f-750sdgasstraightframe","f-750sddieselstraightframe"],"2027":["f-650sdgasstraightframe","f-650sddieselstraightframe","f-750sdgasstraightframe","f-750sddieselstraightframe"],"Powers_2026":["gas","gas","gas","gas"],"Powers_2027":["gas","gas","gas","gas"]},"SuperDuty":{"2024":["f-250xl","f-350xl","f-450xl","f-250xlt","f-350xlt","f-450xlt","f-250lariat","f-350lariat","f-450lariat","f-250kingranch","f-350kingranch","f-250platinum","f-350platinum","f-250limited","f-350limited","f-450kingranch","f-450platinum","f-450limited"],"2025":["f-250xl","f-250xlt","f-250lariat","f-250kingranch","f-250platinum","f-350xl","f-350xlt","f-350lariat","f-350kingranch","f-350platinum","f-450xl","f-450xlt","f-450lariat","f-450kingranch","f-450platinum"],"2026":["f-250xl","f-350xl","f-450xl","f-250xlt","f-350xlt","f-450xlt","f-250lariat","f-350lariat","f-450lariat","f-250kingranch","f-350kingranch","f-450kingranch","f-250platinum","f-350platinum","f-450platinum"],"Powers_2024":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"Powers_2025":["gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas"],"Powers_2026":["gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas"]},"Chassis Cab":{"2024":["f-350xl","f-350xlt","f-350lariat","f-450xl","f-450xlt","f-450lariat","f-550xl","f-550xlt","f-550lariat","f-600xl","f-600xlt"],"2025":["f-350xl","f-350xlt","f-350lariat","f-450xl","f-450xlt","f-450lariat","f-550xl","f-550xlt","f-550lariat","f-600xl","f-600xlt"],"2026":["f-350xl","f-450xl","f-550xl","f-600xl","f-350xlt","f-450xlt","f-550xlt","f-600xlt","f-350lariat","f-450lariat","f-550lariat"],"Powers_2024":[null,null,null,null,null,null,null,null,null,null,null],"Powers_2025":["gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas"],"Powers_2026":["gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas"]},"SuperDuty Commercial":{"2024":["f-250xl","f-350xl","f-450xl","f-250xlt","f-350xlt","f-450xlt","f-250lariat","f-350lariat","f-450lariat","f-250kingranch","f-350kingranch","f-250platinum","f-350platinum","f-250limited","f-350limited","f-450kingranch","f-450platinum","f-450limited"],"2025":["f-250xl","f-250xlt","f-250lariat","f-250kingranch","f-250platinum","f-350xl","f-350xlt","f-350lariat","f-350kingranch","f-350platinum","f-450xl","f-450xlt","f-450lariat","f-450kingranch","f-450platinum"],"2026":["f-250xl","f-350xl","f-450xl","f-250xlt","f-350xlt","f-450xlt","f-250lariat","f-350lariat","f-450lariat","f-250kingranch","f-350kingranch","f-450kingranch","f-250platinum","f-350platinum","f-450platinum"],"Powers_2024":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"Powers_2025":["gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas"],"Powers_2026":["gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas","gas"]},"Econoline Chassis":{"2022":["E-350 SRW","E-350 DRW","E-450 DRW"],"Powers_2022":[null,null,null]},"Escape":{"2026":["active","st-line","st-lineplus","st-linepremium","platinum","phev"],"Powers_2026":["gas","gas","plugin,gas","plugin,gas","plugin,gas","plugin,gas"]},"Transit VanWagon":{"2025":["passengervanxl","passengervanxlt"],"2026":["passengervanxl","passengervanxlt"],"Powers_2025":["eco,gas","eco,gas"],"Powers_2026":["eco,gas","eco,gas"]},"Transit Commercial":{"2025":["cargovan","passengervanxl","passengervanxlt"],"2026":["cargovan","passengervanxl","passengervanxlt"],"Powers_2025":["eco,gas","eco,gas","eco,gas"],"Powers_2026":["eco,gas","eco,gas","eco,gas"]},"Ranger":{"2025":["xl","xlt","lariat","raptor"],"2026":["xl","xlt","lariat","raptor"],"Powers_2025":["eco,gas","eco,gas","eco,gas","eco,gas"],"Powers_2026":["eco,gas","eco,gas","eco,gas","eco,gas"]},"Mache":{"2023":["select","californiaroute1","premium","gt"],"2025":["select","premium","gt","rally"],"2026":["select","premium","gt","rally"],"Powers_2023":[null,null,null,null],"Powers_2025":["electric","electric","electric","electric"],"Powers_2026":["electric","electric","electric","electric"]},"Bronco":{"2025":["base","bigbend","outerbanks","badlands","oates","everglades","raptor","heritageedition"],"2026":["base","bigbend","outerbanks","badlands","oates","raptor","heritageedition"],"Powers_2025":["eco,gas","eco,gas","eco,gas","eco,gas","eco,gas",null,"eco,gas","eco,gas"],"Powers_2026":["eco,gas","eco,gas","eco,gas","eco,gas","eco,gas","eco,gas","eco,gas"]},"Bronco Sport":{"2025":["bigbend","heritage","freewheeling","outerbanks","badlands"],"2026":["bigbend","outerbanks","heritage","badlands"],"Powers_2025":["eco,gas","eco,gas",null,"eco,gas","eco,gas"],"Powers_2026":["eco,gas","eco,gas","eco,gas","eco,gas"]},"Escape Hybrid":{"2026":["st-lineplus","st-linepremium","platinum"],"Powers_2026":["hybrid","hybrid","hybrid"]},"Escape Plugin Hybrid":{"2026":["phev"],"Powers_2026":["plugin"]},"Explorer Hybrid":{"2023":["limited","platinum"],"Powers_2023":[null,null]},"F-Stripped Chassis":{"2025":["f-59commercial"],"2026":["f-59commercial"],"Powers_2025":["gas"],"Powers_2026":["gas"]},"E-Stripped Chassis":{"2026":["e-350drw","e-450drw"],"2027":["e-350drw","e-450drw"],"Powers_2026":["gas","gas"],"Powers_2027":["gas","gas"]},"Maverick":{"2025":["xl","xlt","lobo","lariat","tremor"],"2026":["xl","xlt","lobo","lariat","tremor"],"Powers_2025":["eco,hybrid,gas","eco,hybrid,gas","eco,hybrid,gas","eco,hybrid,gas","eco,hybrid,gas"],"Powers_2026":["eco,hybrid,gas","eco,hybrid,gas","eco,hybrid,gas","eco,hybrid,gas","eco,hybrid,gas"]},"F-150 Lightning":{"2025":["pro","xlt","flash","lariat","platinum"],"Powers_2025":["electric","electric","electric","electric","electric"]},"E-Transit":{"2025":["cargovan","cutaway","chassiscab"],"2026":["cargovan","cutaway","chassiscab"],"Powers_2025":["electric","electric","electric"],"Powers_2026":["electric","electric","electric"]},"F-150 F-150":{"2025":["xl","stx","xlt","tremor","lariat","kingranch","platinum","raptor"],"2026":["xl","stx","xlt","lariat","kingranch","platinum","tremor","raptor"],"Powers_2025":["eco,hybrid,gas","eco,hybrid,gas","eco,hybrid,gas","hybrid,gas","hybrid,gas","hybrid,gas","hybrid,gas","hybrid,gas"],"Powers_2026":["eco,hybrid,gas","eco,hybrid,gas","eco,hybrid,gas","hybrid,gas","hybrid,gas","hybrid,gas","hybrid,gas","hybrid,gas"]}};

    var vdmActiveNameplatesMap = Object.keys(vdmActiveNameplates||{}).reduce(function(accum,current){
        accum[current.trim().toLowerCase()] = current.trim();
        return accum;
    },{});

    var vdmTrims = (function(vdmActiveNameplates){
        var trims = {};
        try{
            for( var nameplate in vdmActiveNameplates ){
                for( var year in vdmActiveNameplates[nameplate] ){

                    if(!year || /^powers_/gmi.test(year)){
                        continue;
                    }

                    trims = vdmActiveNameplates[nameplate][year].reduce(function(accum,trim){
                        if(!accum[trim]){
                            accum[trim] = "";
                        }
                        accum[trim] = trim;
                        return accum;
                    },trims);
                }
            }
        }catch(err){

        }
        return trims;
    }(vdmActiveNameplates || {}));

    var vdmTrimsMap = Object.keys(vdmTrims||{})
      .reduce(function(accum,current){
          accum[current.trim().toLowerCase()] = current.trim();
          return accum;
      },{});


    try {
        var optOutState = cookieOnLoad.get('OptanonConsent');
        optOutState = optOutState ? decodeURIComponent(optOutState) : null;

        if (blockNetworkRequestsDomain) {
            blockNetworkRequests = ((document.cookie || "")
              .split(/gt_dns=/)[1] || '')
              .split(";")[0] === "true";
        } else {
            if( typeof optOutState === "string" ) {
                optOutState = optOutState.split('&').reduce(function(accum,current){

                    if( current.indexOf("groups=") === 0 ) {
                        return current;
                    }

                    return accum;
                },"");
                if(optOutState.indexOf("6:0") > -1 || optOutState.indexOf("4:0") > -1) {
                    blockNetworkRequests = true;
                }
                if(optOutState.indexOf("groups=") <= -1) {
                    if(tagCountry === "CAN") {
                        blockNetworkRequests = true;
                    }
                }
            } else if( optOutState == null ) {
                if(tagCountry === "CAN") {
                    console.log("CANADA SITE, NULL OR OBJECT");
                    blockNetworkRequests = true;
                }
            }
        }
        if (gt_slt === "true") {
            blockNetworkRequests = true;
        }
        if (tier.toUpperCase() === "TN") {
            if (privacysettings !== null && typeof privacysettings !== "undefined") {
                var flags = privacysettings.split(";");
                deleteFlag = flags[0];
                optOutFlag = flags[1];
                requestComp = flags[2];
                if (optOutFlag === "true") {
                    blockNetworkRequests = true;
                }
            }
        }
    } catch (err) {
        console.log("error loading optanoncookuie@#$%#$%!!!");
        console.log(err);
    }
    if( blockNetworkRequests === true ){
        console.log("FPS is in silent mode no data is being tracked")
    }

    let internals = {
        getFMAAuthenticationStatus() {
            return new Promise((resolve) => {
                let listeners = [];

                let checkForAuthentication = () => {
                    // this.handleExternalRef();
                    return window?.fma?.isAuthenticated;
                }

                function listenOnce(event, handler, target) {
                    listeners.push([event, handler, target]);
                    target.addEventListener(event, function h(e) {

                        handler(e);

                        listeners.forEach(([event, handler, target]) => {
                            target.removeEventListener(event, handler);
                        });
                        listeners = [];
                    })
                }

                let handlers = {
                    "fma_authenticated": (e) => {
                        resolve(checkForAuthentication());
                    },
                    "fma_unauthenticated": (e) => {
                        resolve(checkForAuthentication());
                    },
                    "fma_error": (e) => {
                        resolve(checkForAuthentication());
                    }
                }

                let fmaAuthenticationStates = {
                    "true": () => {
                        resolve(checkForAuthentication());
                    },
                    "false": () => {
                        resolve(checkForAuthentication());
                    },
                    "undefined": () => {
                        listenOnce("fma_authenticated", handlers.fma_authenticated, window.document.body);
                        listenOnce("fma_unauthenticated", handlers.fma_unauthenticated, window.document.body);
                        listenOnce("fma_error", handlers.fma_error, window.document.body);
                    },
                };

                fmaAuthenticationStates[checkForAuthentication()]();
            })
        },
        handleExternalRef() {
            // if(window?.fma?.isAuthenticated && fma?.CATBundle?.userId && this.externalRefCallbacks.length === 0){
            if (window?.fma?.isAuthenticated && fma?.CATBundle?.userId && !this.externalRefTriggered) {

                this.externalRefTriggered = true;

                ExternalRefBus.trigger({
                    id: UUIDV4()
                    , type: "FPS_API:setExternalRef"
                    , request: {
                        type: "CSDN"
                        , id: fma?.CATBundle?.userId
                        , callbacks: {
                            success: (e) => {
                                this.externalRefCallbacks.forEach((request) => {
                                    request.callbacks.success(e);
                                });
                                this.externalRefCallbacks = [];
                                this.externalRefTriggered = false;

                            },
                            error: (e) => {

                                this.externalRefCallbacks.forEach((request) => {
                                    request.callbacks.error(e);
                                });

                                this.externalRefCallbacks = [];
                                this.externalRefTriggered = false;
                            }
                        }
                        , unhashed: undefined
                    }
                });
            }
        },
        externalRefResp: new Map(),
        externalRefTriggered: false,
        externalRefCallbacks: [],
        addExternalRefCallback(type, id, callbacks, unhashed) {

            this.externalRefCallbacks = [...this.externalRefCallbacks, {type, id, callbacks, unhashed}];

            if (this.externalRefTriggered === false) {
                this.handleExternalRef();
            }
        }
    };

    function filterFPSGetVdmNameplateTrim(getResponse){
        if(!Array.isArray(getResponse)) return getResponse;
        return getResponse.map(function(el){
            el.Value = el.Value.map(function(vehicle){
                return Object.keys(vehicle).reduce(function(accum,current){
                    if((current === "_nameplate" || current.toLowerCase() === "nameplate") && vehicle && typeof vehicle[current] === "string" ){
                        var nameplate = vehicle[current];
                        accum[current] = vdmActiveNameplatesMap[nameplate.trim().toLowerCase()] || nameplate;
                    } else if( (current === "_trim" || current.toLowerCase() === "trim") && vehicle && typeof vehicle[current] === "string" ){
                        var trim = vehicle[current];
                        accum[current] = vdmTrimsMap[trim.trim().toLowerCase()] || trim;
                    }else{
                        accum[current] = vehicle[current];
                    }

                    return accum;
                },{})
            })
            return el;
        })
    }
    function buildStorageKey(name,data){

        var result = "FPS_Cache__"+name;

        try{
            Object.keys(data).forEach(function(key){
                if( key[0] === '_' ){
                    result = result +"__"+ data[key];
                }
            });
        }catch(err){

        }

        return result;
    }
    function setItem(name,data,timeToLive){

        if(!localStorage) return false;

        var ttl = timeToLive || Date.now();

        if(name && data && data[name]){
            //FPS-606 - SCA-C excluded from ttl
            if(data[name]._type !== "" && data[name]._type !== "SCA-C" ){
                var key = buildStorageKey(name,data[name]);
                localStorage.setItem(key,JSON.stringify({
                    ttl: ttl + FPS.Cache.set[name],
                    data: data
                }));
            } // END FPS-606
        }
    }
    function addGetter(target, prop, fn) {
        Object.defineProperty(target, prop, {
            enumberable: true,
            get: fn
        });
    }
    function addGetterToObject(property,actionMethod){
        return function addGetterToObject(obj){
            Object.defineProperty(obj, property, {
                enumberable: true,
                get: actionMethod
            });
            return obj;
        }
    }
    function addMethodToObject(methodName,actionMethod){
        return function addMethodToObject(obj){
            obj[methodName] = actionMethod;
            return obj;
        }
    }
    function addToArrayEnd(key) {
        return function addToArrayEnd(value) {
            this[key] = this[key].concat(value);
        };
    }
    function buildObject(pipe,data){
        return function buildObject(){
            return pipe(data);
        }
    }
    function clearArray(key){
        return function clearArray(){
            this[key] = [];
        }
    }
    function invokeOnElements(key) {
        return function invokeOnElements() {
            var _arguments = arguments;
            this[key].forEach(function (item) {
                if (typeof item !== "function") return;
                item.apply(null, _arguments);
            });
        };
    }
    function lengthFromArray(key) {
        return function lengthFromArray() {
            return (this[key] ? this[key] : []).length;
        };
    }
    function removeFromArray(key) {
        return function removeFromArray(value) {
            this[key] = this[key].filter(function (item) {
                return item !== value;
            });
        };
    }
    var buildList = [
        addMethodToObject("add",addToArrayEnd("list"))
        , addMethodToObject("remove",removeFromArray("list"))
        , addMethodToObject("clear",clearArray("list"))
        , addGetterToObject("length",lengthFromArray("list"))
    ];
    var buildEmitter = buildList.concat(
      addMethodToObject("trigger",invokeOnElements("list"))
    );
    function List(){
        return buildObject(pipe(buildList),{length:0,list:[]})();
    }
    function Emitter(){
        return buildObject(pipe(buildEmitter),{length:0,list:[]})();
    }
    var VOICacheObject = {
        cache:{}
        , update: function(messageType, RowKey, Value){
            try {
                switch (messageType) {
                    case "FPS_SET":
                        if (!this.cache[RowKey]) {
                            this.cache[RowKey] = ShallowMerge({},Value);
                        } else {
                            this.cache[RowKey].score += Value.score;
                            this.cache[RowKey].count += 1;
                        }
                        break;

                    case "FPS_GET":
                        if (!this.cache[RowKey]) {
                            this.cache[RowKey] = ShallowMerge({},Value);
                        } else {
                            var _cachedItem = JSON.stringify(this.cache[RowKey]);
                            var _value = JSON.stringify(Value);
                            if (_cachedItem !== _value) {
                                this.cache[RowKey] = ShallowMerge({},Value);
                            }
                        }
                        break;
                }
            }catch(err){
                console.log(err);
            }
        }
    };
    function JSONtoRowKey(data){
        return Object.keys(data)
          .filter(function(el){
              return el.indexOf("_") === 0;
          })
          .sort(function(a,b){

              var _a = a.replace(/_/,"").toLowerCase();
              var _b = b.replace(/_/,"").toLowerCase();

              if(_a < _b) return -1;
              if(_a === _b) return 0;
              return 1;

          })
          .reduce(function(accum,key){
              accum += ( "_" + data[key] );
              return accum;
          },"");
    }
    function sortByScore(voiCacheObject){
        return function sortByScore(a,b){
            var _scoreA = voiCacheObject[a].score;
            var _scoreB = voiCacheObject[b].score;
            if(_scoreA > _scoreB) return -1;
            if( _scoreA === _scoreB) return 0;
            return 1;
        }
    }
    function updateVOI(actionKey,updateTarget){
        return function updateVOI(voiCacheObject){
            var sortedAndMappedKeys = Object.keys(voiCacheObject)
              .filter(function(key){
                  return key.indexOf(actionKey) === 0;
              })
              .sort(sortByScore(voiCacheObject))
              .map(function(key){
                  return {Key:key,Value:voiCacheObject[key]};
              });
            var top = sortedAndMappedKeys[0];
            if(top && top.Value){
                updateTarget(top.Value);
            }
        }
    }
    function updateVOIModelCookie(value){
        if (value) {
            cookie.set('FPS_Target_VOI_Model', JSON.stringify({
                model: value._nameplate,
                year:  value._year !== undefined ? value._year.toString() : new Date().getFullYear().toString(),
                make: value._brand,
                score: value.score
            }), FPS.targetCookies.ttl(), '/', cookie.domain);
        }
    }
    function updateVOITrimCookie(value) {
        if (value) {
            cookie.set('FPS_Target_VOI_Trim', JSON.stringify({
                model: value._nameplate,
                year: value._year.toString(),
                make: value._brand,
                trim: value._trim,
                score: value.score
            }), FPS.targetCookies.ttl(), '/', cookie.domain);
        }
    }
    function VOISetCacheHandler(msg){
        var data = msg && msg.data;
        var entry = data && data.entry || {key:"",metadata:undefined,suffix:undefined,value:""};
        if(entry.key.indexOf("OITrim") === 0 || entry.key.indexOf("OINameplate") === 0){
            if(typeof entry.metadata === "string"){
                try{
                    var locale = getLocale({FPS: window.FPS, skipLocaleFilter: true});
                    entry.key = entry.key.replace(locale,"");
                    entry.value = JSON.parse(entry.value);
                    entry.metadata = JSON.parse(entry.metadata);
                    entry.value.score = Number(entry.metadata.score);
                    entry.value.count = 1;
                    entry.value.on = (new Date()).toISOString();
                    VOICacheObject.update(msg.type, entry.key + JSONtoRowKey(entry.value),entry.value);
                    if(entry.key.indexOf("OINameplate") === 0) updateVOI("OINameplate",updateVOIModelCookie)(VOICacheObject.cache);
                    if(entry.key.indexOf("OITrim") === 0) updateVOI("OITrim",updateVOITrimCookie)(VOICacheObject.cache);
                }catch(err){
                    console.log(err);
                }
            }

        }
    }
    function VOIGetCacheHandler(msg){
        var data = msg.data;
        var entry = data.entry || {Key:"",ReservedKey:undefined,Value:[]};
        if(entry.Key.indexOf("OITrim") === 0 || entry.Key.indexOf("OINameplate") === 0){
            entry.Value.forEach(function(el){
                VOICacheObject.update(msg.type, entry.Key + JSONtoRowKey(el),el);
            })
        }
    }
    var VOICache = function(options){
        try {
            var SetBus = options.SetBus;
            var GetBus = options.GetBus;
            SetBus.add(VOISetCacheHandler);
            GetBus.add(VOIGetCacheHandler);
        }catch(err){
            console.log(err);
        }

    }
    var ConvertReservedKeysToActionSuffixObject = function(reservedKeysArray){
        return reservedKeysArray.reduce(function(accum,current){
            var trueKey = current.trueKey;
            var params = current.params;
            var suffixFilter = params.suffixFilter;
            if(!accum[trueKey]) accum[trueKey] = {};
            suffixFilter.forEach(function(suffix){
                accum[trueKey][suffix] = suffix;
            })

            return accum;
        },{});
    }
    var RVVSetHandler = function(msg){
        if(msg && msg.type === "FPS_SET"){
            var rvvSetFilter = ConvertReservedKeysToActionSuffixObject([FPS.reserved.RVVVehicleTrim
                , FPS.reserved.RVVVehicleNameplate
                , FPS.reserved.RVVIONameplate
                , FPS.reserved.RVVSINGNameplate
                , FPS.reserved.RVVSINGSpecificVehicle
                , FPS.reserved.RVVBPNameplate
                , FPS.reserved.RVVBPSpecificVehicle
                , FPS.reserved.RVVVEHNameplate
            ]);

            try{
                var locale = getLocale({FPS: window.FPS, skipLocaleFilter: true});
                var key = msg.data.entry.key.replace(locale,"");
                var suffix = msg.data.entry.suffix;
                if(key && suffix && rvvSetFilter && rvvSetFilter[key] && rvvSetFilter[key][suffix]){
                    cookie.set('FPS_DTM_RVV-IMPRESS', "T", new Date(now.getTime() + (cookieDaysToLive * 86400000)), '/', cookie.domain);
                    SetBus.remove(RVVSetHandler);
                }
            }catch(err){
                console.log(err);
            }

        }
    }
    var RVVImpressionHandler = function(FPS,SetBus){
        if(!Encode(cookie.get("FPS_DTM_RVV-IMPRESS")) && !blockNetworkRequests){
            SetBus.add(RVVSetHandler);
        }
    }
    var ExternalRefStateMachineDefinition = function(){
        return {
            initial: ".waiting"
            , context: {}
            , states:{
                waiting:{
                    on:{
                        REQUEST: [
                            {
                                cond:"eventBusIsNotWellFormatted"
                                , meta: { error: "Invalid message format"}
                                , target: ".silentlyLogError"

                            }
                            , {
                                cond: "setExternalRefDataIsNotWellFormatted"
                                , meta: { error: "Invalid setExternalRef request"}
                                , target: ".silentlyLogError"
                            }
                            , {
                                cond: "isCSDNG"
                                , target: ".returnCachedResponse"
                            }
                            , {
                                cond: "isNotUsingKnownGuid"
                                , meta: { error: "Not a known guid"}
                                , target: ".convertToSet"
                            }
                            , { target:".addCallbacksToContext" }
                        ]
                    }
                }
                , addCallbacksToContext: {
                    invoke: function(ctx,event,methods){
                        methods.Update("callbacks",event.msg.request.callbacks);
                        methods.Send({
                            type: "NEXT"
                            ,msg: event.msg
                        })
                    },
                    on: {
                        NEXT:".mergeFPSConfigToCoreConfig"
                    }
                }
                , mergeFPSConfigToCoreConfig: {
                    invoke: function(ctx,event,methods){
                        ShallowMerge(core.config, FPS.config);
                        methods.Send({
                            type: "NEXT"
                            ,msg: event.msg
                        })
                    },
                    on: {
                        NEXT:".requesting"
                    }
                }
                , requesting: {
                    invoke: function(ctx,event,methods){
                        var type = event.msg.request.type;
                        var id = event.msg.request.id;
                        var callbacks = ctx.callbacks;
                        var hashed = event.msg.request.hashed;
                        var unhashed = typeof unhashed !== 'undefined' ? unhashed : true;
                        // var gt_exref = cookie.get('gt_exref');
                        var response = [{uid_submitted : uid, uid_reconciled : uid}];

                        // if(gt_exref && gt_exref === uid)
                        // {
                        //     methods.Send({
                        //         type: "SUCCESS"
                        //         , response: response
                        //     })
                        // }
                        // else
                        // {
                            core.setExternalRef([{
                                key: 'ExternalRef', value: JSON.stringify(core.lib['ExternalRef' + (unhashed === true ? 'Unhashed' : '')](type, id)['ExternalRef'])
                            }], callbacks.timeout)
                              .then(function (resp) {
                                  methods.Send({
                                      type: "SUCCESS"
                                      , response: resp
                                  })
                              }).catch(function (jqXHR, statusText, error) {
                                console.log(arguments);
                                methods.Send({
                                    type: "ERROR"
                                    , response: [jqXHR, statusText, error]
                                })
                            });
                        // }
                    }
                    , on:{
                        SUCCESS: ".processing"
                        , ERROR: ".error"
                    }
                }
                , processing:{
                    invoke: function(ctx,event,methods){
                        var data = event.response[0];
                        var statusText = event.response[1];
                        var jqXHR = event.response[2];
                        if (data && data.uid_submitted && data.uid_reconciled) {

                            var gt_dns = Encode(cookie.get("gt_dns"));
                            var dnsModeIsActive = gt_dns != null;
                            var xdcModeIsActive = xdcDomain.length > 0;
                            var tier3DNSModeIsActive = xdcModeIsActive && dnsModeIsActive;

                            setExRefHasUpdatedCookie = true;

                            if (dnsModeIsActive && (gt_dns === data.uid_reconciled || gt_dns === data.uid_submitted)) {
                                cookie.set('gt_dns', xdcModeIsActive ? true : UUIDV4(), new Date(now.getTime() + (cookieDaysToLive * 86400000)), '/', cookie.domain);
                                if(blockNetworkRequestsDomain) blockNetworkRequests = true;
                            }

                            if (data.uid_submitted !== data.uid_reconciled) {

                                uid = tier3DNSModeIsActive ? data.uid_submitted : data.uid_reconciled;

                                cookie.set('gt_uid', uid, new Date(now.getTime() + (cookieDaysToLive * 86400000)), '/', cookie.domain);
                                ajaxData.uid = uid;

                                if (localStorage) {
                                    for (sessionKey in localStorage) {
                                        if (sessionKey.slice(0, storageKeyPrefix.length) === storageKeyPrefix) {
                                            localStorage.removeItem(sessionKey);
                                        }
                                    }
                                }
                            } else if (data.uid_submitted === data.uid_reconciled && tier3DNSModeIsActive) {

                                uid = UUIDV4();

                                cookie.set('gt_uid', uid, new Date(now.getTime() + (cookieDaysToLive * 86400000)), '/', cookie.domain);
                                ajaxData.uid = uid;

                                if (localStorage) {
                                    for (sessionKey in localStorage) {
                                        if (sessionKey.slice(0, storageKeyPrefix.length) === storageKeyPrefix) {
                                            localStorage.removeItem(sessionKey);
                                        }
                                    }
                                }
                            }

                            if (FPS.hasOwnProperty('setTargetCookie')) {
                                FPS.setTargetCookie({ success: function () { }, error: function () { } });
                            }
                        }
                        methods.Send({
                            type:"DONE"
                            ,result: [data, statusText, jqXHR]
                        })
                    },
                    on: {
                        DONE: ".success"
                    }
                }
                , success: {
                    type: "final"
                    , invoke: function(ctx,event,methods){
                        ctx.callbacks.success.apply(null,event.result);
                    }
                }
                , error: {
                    type: "final"
                    , invoke: function(ctx,event,methods){
                        ctx.callbacks.error.apply(null,event.response);
                    }
                }
                , silentlyLogError: {
                    type: "final"
                    , invoke: function(ctx,event,methods){
                        console.error(event);
                    }
                }
                , returnCachedResponse: {
                    type: "final"
                    , invoke: function(ctx,event,methods){
                        var id = event.msg.request.id;
                        var callbacks = event.msg.request.callbacks;
                        if(callbacks && typeof callbacks.success === "function"){
                            callbacks.success({
                                uid_submitted: uid || "",
                                uid_reconciled: uid || "",
                                status: "2222-0000"
                            });
                        }
                    }
                }
                , convertToSet: {
                    type: "final"
                    , invoke: function(ctx,event,methods){
                        var type = event.msg.request.type;
                        var id = event.msg.request.id;
                        var callbacks = event.msg.request.callbacks;
                        FPS.set([{ 'AnonymousRef': { _type: type, id: id, _url:window.location.hostname } }],callbacks);
                    }
                }
            },
            guards: {
                eventBusIsNotWellFormatted: function(ctx,event,condMeta){
                    var msg = event && event.msg || {};
                    var id = msg.id;
                    var type = msg.type;
                    var request = msg.request;
                    return !id || !type || !request;
                }
                , setExternalRefDataIsNotWellFormatted: function(ctx,event,condMeta){
                    var msg = event && event.msg || {};
                    var request = msg.request || {};
                    var id = request.id;
                    var type = request.type;
                    var callbacks = request.callbacks || {};
                    var success = callbacks.success;
                    var error = callbacks.error;
                    return ( !request || !type || !id || !callbacks || !success || !error);
                }
                , isCSDNG: function(ctx,event,condMeta){
                    var msg = event && event.msg || {};
                    var request = msg.request || {};
                    return request.type === "CSDN-G"
                }
                , isNotUsingKnownGuid: function(ctx,event,condMeta){
                    var msg = event && event.msg || {};
                    var request = msg.request || {};
                    return request.type !== "CSDN"
                }
            }
        };
    }
    var GetStateProcessMachineDefinition = function(){
        return {
            initial: ".waiting"
            , context: {}
            , states:{
                waiting:{
                    on: {
                        REQUEST: ".grabRequestData"
                    }
                }
                , grabRequestData: {
                    on: {
                        NEXT: [
                            {
                                cond: "hasEmptyEntities"
                                , target: ".emptyResponse"
                            },
                            {
                                cond: "inStorageOnly"
                                , target: ".storageResponse"
                            }
                            , { target:".request" }
                        ]
                    }
                    , invoke: function(ctx,event,methods){
                        var msg = event && event.msg || {};
                        methods.Update("callbacks", msg.callbacks);
                        methods.Update("entries", msg.entries || []);
                        methods.Update("inStorage", msg.inStorage || []);
                        methods.Update("indices",msg.indices || {});
                        methods.Update("locale",getLocale({FPS: window.FPS}));
                        methods.Update("asBrand",msg.asBrand);
                        methods.Update("asCountry",msg.asCountry);
                        methods.Update("getAs",(msg.asBrand !== undefined) && (msg.asCountry !== undefined))
                        methods.Send({
                            type: "NEXT"
                            , event: msg
                        })
                    }
                }
                , storageResponse: {
                    type: "final"
                    , invoke: function(ctx,msg,methods){
                        var data = ctx.inStorage;
                        var xhr = {
                            readyState: 4
                            , status: 200
                            , statusText: 'OK'
                            , responseJSON: data
                            , responseText: JSON.stringify(data)
                        };

                        if(ctx.callbacks && typeof ctx.callbacks.success === "function"){
                            var newData = [];
                            if (data && data.length > 0) {
                                newData = data.map( function (kvPair, index) {
                                    var formattedObject = {};
                                    return formattedObject[kvPair['Key']] = kvPair['Value'];
                                });
                            }

                            ctx.callbacks.success(data, 'success', xhr);

                        }
                    }
                }
                , emptyResponse: {
                    type: "final"
                    , invoke: function(ctx,msg,methods){
                        var data = [];
                        var xhr = {
                            readyState: 4
                            , status: 400
                            , statusText: 'Bad Request'
                            , responseJSON: data
                            , responseText: JSON.stringify(data)
                        };

                        if(ctx.callbacks && typeof ctx.callbacks.error === "function"){
                            ctx.callbacks.error(data, 'error', xhr);
                        }
                    }
                }
                , request: {
                    invoke: function(ctx,event,methods){
                        ShallowMerge(core.config, FPS.config);
                        core.get(ctx.entries, ctx.callbacks.timeout, ctx.asBrand, ctx.asCountry)
                          .then(function (resp) {
                              var data = resp[0] || [];
                              var statusText = resp[1];
                              var jqXHR = resp[2];
                              var combined = [];
                              var locale = getLocale({FPS: window.FPS});

                              data.forEach(function (kvPair, index) {

                                  try{
                                      kvPair.Value = kvPair.Value.map(function(el){
                                          try{
                                              return Object.keys(el).reduce(function(accum,current){

                                                  try {
                                                      if (current === "_UID" || current === "UID") {
                                                          accum[current] = decodeURIComponent(accum[current]);
                                                      }
                                                  }catch(err){
                                                      console.error(err);
                                                  }
                                                  return accum;
                                              },el);

                                          }catch(err){
                                              console.log(err);
                                          }
                                      });
                                  }catch(err){
                                      console.error(err);
                                  }

                                  if (!ctx.getAs) {
                                      if (localStorage && FPS.reserved.hasOwnProperty(kvPair.Key)) {
                                          localStorage.setItem(storageKey(kvPair.Key + locale), JSON.stringify(kvPair.Value));
                                          localStorage.setItem(storageKey(kvPair.Key + locale) + '_TS', Date.now());
                                      }
                                      if (FPS.hasOwnProperty('targetCookies') && FPS.targetCookies.hasOwnProperty(kvPair.Key)) {
                                          FPS.targetCookies[kvPair.Key](kvPair);
                                      }
                                  }
                                  try {
                                      var regex = new RegExp(locale+"$","i");
                                      var _Key = kvPair.Key.replace(regex,"");
                                      var _Value = kvPair.Value;

                                      if( locale !== "" ){
                                          if(FPS.reserved.hasOwnProperty(_Key)){
                                              combined[ctx.indices[kvPair.Key + locale]] = { Key: _Key, Value: _Value };
                                          }else{
                                              combined[ctx.indices[kvPair.Key]] = { Key: _Key, Value: _Value };
                                          }
                                      }else{
                                          combined[ctx.indices[kvPair.Key]] = { Key: _Key, Value: _Value };
                                      }

                                  } catch (err) {
                                      combined[ctx.indices[kvPair.Key]] = kvPair;
                                  }


                              });
                              ctx.inStorage.forEach(function (index, kvPair) {

                                  try {
                                      var _Key = kvPair.Key;
                                      var _Value = kvPair.Value;
                                      combined.push({ Key: _Key, Value: _Value });

                                  } catch (err) {
                                      combined.push(kvPair);
                                  }

                              });

                              if(GetBus && UUIDV4){
                                  combined.forEach(function(el){
                                      el = DeepMerge({},el);
                                      var reservedKey = FPS.reserved[el.Key];
                                      if(reservedKey){
                                          el.ReservedKey = reservedKey.reservedKey;
                                          el.Key = reservedKey.trueKey;
                                      }else{
                                          el.ReservedKey = undefined;
                                      }

                                      try {
                                          el.Value = el.Value.map(function (entry) {
                                              if (typeof entry.returnURL === "string") {
                                                  entry.returnURL = decodeURIComponent(entry.returnURL);
                                              }
                                              return entry;
                                          });
                                      } catch(err) {

                                      }

                                      GetBus.trigger({
                                          id: UUIDV4()
                                          , type: "FPS_GET"
                                          , data:{
                                              entry: el
                                          }
                                      })
                                  });
                              }

                              if (combined && combined.length > 0) {
                                  combined = combined.map( function (kvPair, index) {
                                      var formattedObject = {};
                                      formattedObject[kvPair['Key']] = kvPair['Value'];
                                      return formattedObject;
                                  });
                              }

                              methods.Update("combined",combined);
                              methods.Update("statusText",statusText);
                              methods.Update("jqXHR",jqXHR);
                              methods.Send({
                                  type: "SUCCESS"
                                  , msg: event.msg
                              });
                          })
                          .catch(function (jqXHR, statusText, error) {
                              methods.Update("jqXHR",jqXHR);
                              methods.Update("statusText",statusText);
                              methods.Update("error",error);
                              methods.Send({
                                  type: "ERROR"
                                  , msg: event.msg
                              });
                          });

                    }
                    , on: {
                        SUCCESS: ".success"
                        , ERROR: ".error"
                    }
                }
                , success: {
                    type:"final"
                    , invoke: function( ctx, event, methods){
                        ctx.callbacks.success( ctx.combined, ctx.statusText, ctx.jqXHR );
                    }
                }
                , error: {
                    type: "final"
                    , invoke: function(ctx, event, methods){
                        ctx.callbacks.error( ctx.jqXHR, ctx.statusText, ctx.error );
                    }
                }
            }
            , guards: {
                inStorageOnly: function(ctx,event,condMeta){
                    var entries = ctx.entries || [];
                    var inStorage = ctx.inStorage || [];
                    return entries.length === 0 && inStorage.length > 0;
                },
                hasEmptyEntities: function(ctx,event,condMeta){
                    var entries = ctx.entries || [];
                    var inStorage = ctx.inStorage || [];

                    var hasEmpties = (entries.filter(el => !el) || []).length;
                    var noEntries = entries.length === 0 && inStorage.length === 0;

                    return hasEmpties > 0 || noEntries;
                },
            }
        }
    }
    var GetStatePreProcessMachineDefinition = function(){
        return {
            initial: ".waiting"
            , context: {}
            , states:{
                waiting:{
                    on: {
                        REQUEST: [
                            {
                                cond: "eventBusIsNotWellFormatted"
                                , target: ".silentlyLogError"
                            }
                            ,{target:".process"}
                        ]
                    }
                }
                , process: {
                    states:{
                        extract:{
                            states:{
                                match: {
                                    invoke: function(ctx,event,methods){
                                        var entry = ctx.entry;
                                        var fpsKey = getFPSKey(entry['match']);
                                        methods.Update("fpsKey",fpsKey);
                                        methods.Update("newEntry",{
                                            key: 'match',
                                            value: entry['match'],
                                            suffix: entry['match']['suffix'],
                                            query: entry.hasOwnProperty('query') ? entry['query'] : ''
                                        });

                                        methods.Send({
                                            type:"NEXT"
                                            , msg: event.msg
                                        });
                                    }
                                    , on: {
                                        NEXT: [
                                            {
                                                cond: "entityIsInStorage"
                                                , target: ".addToStorage"
                                            }
                                            , {target:".done"}
                                        ]
                                    }
                                }
                                , reservedKey: {
                                    invoke: function(ctx,event,methods){
                                        var entry = ctx.entry;
                                        var fpsKey = entry['reservedKey'];
                                        var locale = ctx.locale;
                                        if(checkIfKeyIsBlackListed({key:fpsKey,blacklist:getFPSBlacklistKeys(window.FPS)})){
                                            locale = "";
                                            methods.Update("locale","");
                                        }
                                        methods.Update("fpsKey",fpsKey);
                                        methods.Update("newEntry",{
                                            key: entry['trueKey'] + locale,
                                            value: entry['params'],
                                            reservedKey: fpsKey
                                        });

                                        methods.Send({
                                            type:"NEXT"
                                            , msg: event.msg
                                        });
                                    }
                                    , on: {
                                        NEXT: [
                                            {
                                                cond: "entityIsInStorage"
                                                , target: ".addToStorage"
                                            }
                                            , {target:".done"}
                                        ]
                                    }
                                }
                                , reservedObject: {
                                    invoke: function(ctx,event,methods){
                                        var entry = ctx.entry;
                                        var locale = ctx.locale;
                                        var fpsKey = getFPSKey(entry);
                                        var reservedObject = FPS.reserved[fpsKey];
                                        if(checkIfKeyIsBlackListed({key:fpsKey,blacklist:getFPSBlacklistKeys(window.FPS)})){
                                            locale = "";
                                            methods.Update("locale","");
                                        }
                                        methods.Update("fpsKey",fpsKey);
                                        methods.Update("newEntry",{
                                            key:  reservedObject['trueKey'] + locale,
                                            value: reservedObject['params'],
                                            reservedKey: fpsKey
                                        });

                                        methods.Send({
                                            type:"NEXT"
                                            , msg: event.msg
                                        });
                                    }
                                    , on: {
                                        NEXT: [
                                            {
                                                cond: "entityIsInStorage"
                                                , target: ".addToStorage"
                                            }
                                            , {target:".done"}
                                        ]
                                    }
                                }
                                , default: {
                                    invoke: function(ctx,event,methods){
                                        var entry = ctx.entry;
                                        var locale = ctx.locale;
                                        var fpsKey = getFPSKey(entry);
                                        if(checkIfKeyIsBlackListed({key:fpsKey,blacklist:getFPSBlacklistKeys(window.FPS)})){
                                            locale = "";
                                            methods.Update("locale","");
                                        }
                                        methods.Update("fpsKey",fpsKey);
                                        methods.Update("newEntry",{
                                            key: fpsKey + locale,
                                            value: entry[fpsKey],
                                            suffix: entry['suffix']
                                        });

                                        methods.Send({
                                            type:"NEXT"
                                            , msg: event.msg
                                        });
                                    }
                                    , on: {
                                        NEXT: [
                                            {
                                                cond: "entityIsInStorage"
                                                , target: ".addToStorage"
                                            }
                                            , {target:".done"}
                                        ]
                                    }
                                }
                            }
                        }
                    }
                    , on:{
                        NEXT:[
                            {
                                cond: "isMatchKey"
                                , target: ".process.extract.match"
                            }
                            , {
                                cond: "isReservedKey"
                                , target: ".process.extract.reservedKey"
                            }
                            , {
                                cond: "isReservedObject"
                                , target: ".process.extract.reservedObject"
                            }
                            , {target: ".process.extract.default"}
                        ]
                    }
                    , invoke: function(ctx,event,methods){
                        var msg = event && event.msg;
                        var request = msg && msg.request;
                        var callbacks = request && request.callbacks;
                        var entry = request && request.entry;
                        var locale = getLocale({FPS: window.FPS});
                        var asBrand = request && request.asBrand;
                        var asCountry = request && request.asCountry;
                        methods.Update("callbacks",callbacks);
                        methods.Update("entry",entry);
                        methods.Update("locale",locale);
                        methods.Update("getAs",(asBrand !== undefined) && (asCountry !== undefined));
                        methods.Send({
                            type: "NEXT"
                            , msg: event.msg
                        });
                        methods.Update("index", request.index >= 0 ? request.index : -1 );
                    }
                }
                , silentlyLogError: {
                    type: "final"
                    , invoke: function(ctx,event,methods){
                        console.error(event);
                    }
                }
                , addToStorage: {
                    final: "final"
                    , invoke: function(ctx,event,methods){
                        storageValue = localStorage.getItem(storageKey(ctx.newEntry['reservedKey']));
                        methods.Update("inStorage",{
                            Key: ctx.newEntry['reservedKey'],
                            Value: JSON.parse(storageValue)
                        });
                        methods.Send({
                            type: "NEXT"
                            , msg: event.msg
                        })
                    }
                    , on: {
                        NEXT: "done"
                    }
                }
                , done: {
                    type: "final"
                    , invoke: function(ctx,event,methods){
                        return ctx;
                    }
                }
            }
            , guards: {
                eventBusIsNotWellFormatted: function(ctx,event,condMeta){
                    var msg = event && event.msg || {};
                    var id = msg.id;
                    var type = msg.type;
                    var request = msg.request;
                    var entry = msg.request && msg.request.entry;
                    var callbacks = msg.request && msg.request.callbacks;
                    var success = callbacks && callbacks.success;
                    var error = callbacks && callbacks.error;
                    return !id || !type || !request || !entry || !success || !error;
                }
                , isMatchKey: function(ctx,event,condMeta){
                    var entry = ctx.entry || {};
                    return getFPSKey(entry['match']) !== null;
                }
                , isReservedKey: function(ctx,event,condMeta){
                    var entry = ctx.entry || {};
                    return getFPSKey(entry['reservedKey']) !== null;
                }
                , isReservedObject: function(ctx,event,condMeta){
                    var entry = ctx.entry || {};
                    return FPS.reserved[getFPSKey(entry)] !== undefined;
                }
                , entityIsInStorage: function(ctx,event,condMeta){
                    try{
                        var storageValue = localStorage.getItem(storageKey(ctx.newEntry['reservedKey']));
                        var storageValueTimestamp = parseInt(localStorage.getItem(storageKey(ctx.newEntry['reservedKey']) + '_TS') || 0);
                        return storageValue && (Date.now() - storageValueTimestamp) <= 0;
                    }catch(err){
                        return false;
                    }
                }
            }
        };
    }
    function mergeKeys(deepMerge){
        deepMerge = deepMerge || false;
        return function mergeKeys(target,obj){
            for( var key in obj){
                if(obj.hasOwnProperty(key)){
                    if(deepMerge){
                        if(target[key] && typeof target[key] === "object" && typeof obj[key] === "object" && !Array.isArray(obj[key])){
                            mergeKeys(target[key], obj[key]);
                        }else{
                            target[key] = obj[key];
                        }
                    }else{
                        target[key] = obj[key];
                    }
                }
            }
            return target;
        }
    }

    function Merge(deepMerge){
        deepMerge = deepMerge || false;
        return function Merge(target,obj){
            var target = arguments[0];
            var objs = [];
            for( var i=1; i < arguments.length; i++){
                objs.push(arguments[i]);
            }

            if(!target || objs.length === 0){
                return {};
            }

            var merge = mergeKeys(deepMerge);

            objs.forEach(function(obj){
                merge(target,obj);
            });

            return target;
        }
    }

    var ShallowMerge = Merge(false);
    var DeepMerge = Merge(true);
    if(window) window.DeepMerge = Merge(true);
    function pipe(fns) {
        fns = Array.isArray(fns) ? fns
          : typeof fns === "function" ? [fns]
            : [];
        return function (args) {
            return fns.reduce(function (accum, current) {
                return current(accum);
            }, args);
        }
    }
    var Promise = window && window.Promise || function (callback){
        var thenCallbacks = [];
        var catchCallbacks = [];
        var resolved = false;
        var resolvedWith;
        var rejected = false;
        var rejectedWith;

        function resolve(args){
            resolvedWith = args;
            pipe(thenCallbacks.slice())(args);
            resolved = true;
        }

        function reject(args){
            rejectedWith = args;
            pipe(catchCallbacks.slice())(args);
            rejected = true;
        }

        if(typeof callback === "function") {
            callback(resolve, reject);
        }

        return {
            then: function(callback){
                thenCallbacks = thenCallbacks.concat(callback);
                if (catchCallbacks.length >= 1) {
                    catchCallbacks = catchCallbacks.concat(callback);
                    if(rejected === true){
                        reject(rejectedWith);
                    }
                }
                if(resolved === true){
                    resolve(resolvedWith);
                }
                return this;
            },
            catch: function(callback){
                if(catchCallbacks.length === 0){
                    catchCallbacks = catchCallbacks.concat(callback);
                }
                if(rejected === true){
                    reject(rejectedWith);
                }
                return this;
            }
        };
    }
    function Request(args){
        return new Promise( function(resolve,reject) {

            if(blockNetworkRequests){
                try{
                    if(args.url.indexOf(xdcPathGet + apiPaths.get) > -1){
                        var response = JSON.parse(args.body).entries.map(function(entry){
                            var obj = {};
                            obj[entry.reservedKey || entry.key] = [];
                            return obj;
                        });
                        return reject([response, "error", xhr]);
                    } else if(args.url.indexOf(xdcPathSet + apiPaths.set) > -1){
                        return resolve([{
                            uid_submitted: uid,
                            uid_reconciled: uid,
                            status: "0000-0000"
                        },
                            "success"
                        ]);
                    } else if(args.url.indexOf(xdcPathSetExternalRef + apiPaths.setExternalRef) > -1){
                        return reject([{
                            uid_submitted: "",
                            uid_reconciled: "",
                            status: "0000-0000"
                        },
                            "error"
                        ]);
                    }
                }catch(err){
                    console.log(err);
                }
            }

            var body = args.body;
            var headers = args.headers || {};
            var method = args.method || "post";
            var timeout = args.timeout || 0;
            var url = args.url;
            var withCredentials = args.withCredentials || false;

            var xhr = new XMLHttpRequest();
            var responseHandler = ResponseHandler(xhr,resolve,reject);

            xhr.open(method, url);

            Object.keys(headers).forEach(function (headerKey) {
                xhr.setRequestHeader(headerKey, headers[headerKey]);
            });

            xhr.withCredentials = withCredentials;
            xhr.timeout = timeout;

            function addListeners(target, handler) {
                target.addEventListener("load", handler);
                target.addEventListener("abort", handler);
                target.addEventListener("error", handler);
                target.addEventListener("timeout", handler);
            }

            function removeListeners(target, handler) {
                target.removeEventListener("load", handler);
                target.removeEventListener("abort", handler);
                target.removeEventListener("error", handler);
                target.removeEventListener("timeout", handler);
            }

            addListeners(xhr, function handler(e) {
                removeListeners(xhr, handler);
                responseHandler(e);
            });

            if (body) {
                xhr.send(body);
            } else {
                xhr.send();
            }

        });
    }

    function ResponseHandler(xhr,resolve,reject) {
        return function(e){
            if (xhr.readyState === XMLHttpRequest.DONE) {
                var response = xhr.response;

                try {
                    response = JSON.parse(response);
                } catch (err) {
                }

                if (xhr.status >= 200 && xhr.status < 300) {
                    return resolve([response, "success", xhr]);
                } else if (e.type === "timeout") {
                    return reject([xhr, "timeout", {Message: "Request timed out in browser"}]);
                } else if (e.type === "abort") {
                    return reject([xhr, "abort", {Message: "Request aborted"}]);
                }
                return reject([xhr, "error", response]);
            }
        }
    }
    var SetStateMachineDefinition = function(initialContext){
        initialContext = initialContext || {};
        return {
            initial: ".waiting"
            , context: DeepMerge({},initialContext)
            , states:{
                waiting:{
                    on:{
                        REQUEST: [
                            {
                                cond:"eventBusIsNotWellFormatted"
                                , meta: { error: "Invalid message format"}
                                , target: ".silentlyLogError"

                            }
                            , {
                                cond: "isBroncoSportSet"
                                , target: ".normalizeNameplate"
                            }
                            , { target: ".cache" }
                        ]
                    }
                }
                , cache: {
                    invoke: function(ctx,event,methods){
                        // add entry to context
                        // add callbacks to context
                        // add key to context
                        // add value to context
                        // add CURRENT_TIME to context
                        var request = event && event.msg && event.msg.request || {};
                        var entry = request.entry || {};
                        var callbacks = request.callbacks || {success:function(){},error:function(){}};
                        var key = getFPSKey(entry);
                        var value = entry[key];
                        var metadata = entry.metadata;
                        var suffix = entry.suffix;
                        var CURRENT_TIME = Date.now();

                        var storageKey = buildStorageKey(key,value);
                        var result = JSON.parse(localStorage.getItem(storageKey) || "{}") || {};
                        var ttl = result.ttl;
                        var data = result.data;
                        var cacheTime = parseInt(FPS.Cache.set[key]) || 0;

                        methods.Update("entry",entry);
                        methods.Update("callbacks",callbacks);
                        methods.Update("key",key);
                        methods.Update("value",value);
                        methods.Update("metadata",metadata);
                        methods.Update("suffix",suffix);
                        methods.Update("CURRENT_TIME",CURRENT_TIME);

                        methods.Update("storageKey",storageKey);
                        methods.Update("storgeResult",result);
                        methods.Update("storageTTL",ttl);
                        methods.Update("storageData",data);
                        methods.Update("cacheTTL",cacheTime);

                        methods.Send({
                            type: "NEXT"
                            , msg: event.msg
                        });

                    }
                    , on: {
                        NEXT: [
                            {
                                cond:"isNotValidNameplate"
                                , meta: { error: "Invalid nameplate"}
                                , target: ".silentlyLogError"

                            }
                            , {
                                cond:"isNotValidTrim"
                                , meta: { error: "Invalid trim"}
                                , target: ".silentlyLogError"

                            }
                            ,  {
                                cond:"keyIsNotCachable"
                                , meta: { error: "Invalid message format"}
                                , target: ".set"

                            }
                            , {
                                cond: "checkIfStorageEntryIsNotFound"
                                , target: ".cache.cacheEntry"
                            }
                            , {
                                cond: "checkIfEntryDoesNotMatchStorage"
                                , target: ".cache.cacheEntry"
                            }
                            , {
                                cond: "checkIfTTLHasExpired"
                                , target: ".cache.cacheEntry"
                            }
                            , { target: ".returnCachedResponse" }
                        ]
                    }
                    , states: {
                        cacheEntry: {
                            invoke: function(ctx,event,methods){
                                setItem(ctx.key,ctx.entry,ctx.CURRENT_TIME);
                                methods.Send({
                                    type:"NEXT"
                                    ,msg: event.msg
                                })
                            }
                            , on: {
                                NEXT: ".set"
                            }
                        }
                    }
                }
                , set: {
                    invoke: function(ctx,event,methods){
                        var locale = getLocale({
                            FPS: window.FPS,
                            skipLocaleFilter: true
                        });

                        const localeWas = locale;

                        /*
                        Remove locale for Black Listed Keys
                     */
                        if(checkIfKeyIsBlackListed({key:ctx.key,blacklist:getFPSBlacklistKeys(window.FPS)})){
                            locale = "";
                        }

                        /*try{
              ctx.value = Object.keys(ctx.value).reduce(function(accum,current){
                try {
                  if (current === "_UID" || current === "UID") {
                    accum[current] = encodeURIComponent(accum[current]);
                  }
                }catch(err){
                  console.error(err);
                }
                return accum;
              },ctx.value);
            }catch(err){
              console.error(err);
            }*/

                        var finalEntry = stringifyEach([{
                            key: ctx.key + locale,
                            value: JSON.stringify(ctx.value),
                            metadata: JSON.stringify(ctx.metadata),
                            suffix: ctx.suffix
                        }]);

                        let wasEntry;

                        if(ctx?.metadata?.active === false && /^(NVCWishlist|SavedItems)/gi.test(ctx.key)){
                            wasEntry = stringifyEach([{
                                key: ctx.key + localeWas,
                                value: JSON.stringify(ctx.value),
                                metadata: JSON.stringify(ctx.metadata),
                                suffix: ctx.suffix
                            }]);
                        }

                        if(SetBus && UUIDV4){
                            SetBus.trigger({
                                id: UUIDV4()
                                , type: "FPS_SET"
                                , data:{
                                    entry: {
                                        key: ctx.key + locale,
                                        value: JSON.stringify(ctx.value),
                                        metadata: JSON.stringify(ctx.metadata),
                                        suffix: ctx.suffix
                                    }
                                }
                            })
                        }

                        if (localStorage) {
                            for (reservedKey in FPS.reserved) {
                                if (FPS.reserved[reservedKey]['trueKey'] === ctx.key) {
                                    localStorage.removeItem(storageKey(reservedKey));
                                }
                            }
                        }
                        ShallowMerge(core.config, FPS.config);
                        if (ctx.callbacks && ctx.callbacks.success && ctx.callbacks.error) {
                            core.set(finalEntry, ctx.callbacks.timeout)
                              .then(function (resp) {
                                  methods.Send({
                                      type: "SUCCESS"
                                      , result: resp
                                  })
                              }).catch(function (resp) {
                                methods.Send({
                                    type: "ERROR"
                                    , response: resp
                                })
                            });

                            if(wasEntry){
                                core.set(wasEntry, ctx.callbacks.timeout)
                                    .then(function (resp) {
                                        methods.Send({
                                            type: "SUCCESS"
                                            , result: resp
                                        })
                                    }).catch(function (resp) {
                                    methods.Send({
                                        type: "ERROR"
                                        , response: resp
                                    })
                                });
                            }
                        }
                        else {
                            core.set(finalEntry)
                              .then(function (resp) {})
                              .catch(function(resp){});

                            if(wasEntry){
                                core.set(wasEntry)
                                    .then(function (resp) {})
                                    .catch(function(resp){});
                            }
                        }
                    }
                    , on:{
                        SUCCESS: ".success"
                        , ERROR: ".error"
                    }
                }
                , success: {
                    type: "final"
                    , invoke: function(ctx,event,methods){
                        ctx.callbacks.success.apply(null,event.result);
                    }
                }
                , error: {
                    type: "final"
                    , invoke: function(ctx,event,methods){
                        ctx.callbacks.error.apply(null,event.response);
                    }
                }
                , silentlyLogError: {
                    type: "final"
                    , invoke: function(ctx,event,methods){
                        console.error(event);
                    }
                }
                , returnCachedResponse: {
                    type: "final"
                    , invoke: function(ctx,event,methods){
                        var id = event.msg.request.id;
                        var callbacks = event.msg.request.callbacks;
                        if(callbacks && typeof callbacks.success === "function"){
                            callbacks.success({
                                uid_submitted: uid || "",
                                uid_reconciled: uid || "",
                                status: "2222-0000"
                            });
                        }
                    }
                }
                , normalizeNameplate: {
                    invoke: function(ctx,event,methods){
                        try{
                            var entry = event && event.msg && event.msg.request && event.msg.request.entry || {};
                            var key = getFPSKey(entry);
                            event.msg.request.entry[key]._nameplate = "Bronco Sport";
                        }catch(err){

                        }
                        methods.Send({
                            type: "NEXT"
                            , msg: event.msg
                        });
                    }
                    , on: {
                        NEXT: ".cache"
                    }
                }
            },
            guards: {
                eventBusIsNotWellFormatted: function(ctx,event,condMeta){
                    var msg = event && event.msg || {};
                    var id = msg.id;
                    var type = msg.type;
                    var request = msg.request;
                    var entry = msg.request && msg.request.entry;
                    return !id || !type || !request || !entry;
                }
                , isNotValidNameplate: function(ctx,event,condMeta){
                    try{
                        if(ctx.value._brand !== tagBrand && !(ctx && ctx.key && (ctx.key === "ShowroomResultsEDI" || ctx.key === "RecentShowroomEDI"))){
                            return false;
                        }

                        var healNameplate = FPS.Validation.healNameplate(ctx.vdmActiveNameplates,ctx.vdmActiveNameplatesMap);
                        var _healedNameplate = "";
                        var failedNameplate = "";

                        if(ctx && ctx.value && ctx.value._nameplate){

                            _healedNameplate = healNameplate(ctx.value._nameplate, ctx.value);

                            if( _healedNameplate !== ctx.value._nameplate ) {
                                ctx.value.nameplateEcom = ctx.value._nameplate;
                                failedNameplate = ctx.value._nameplate;
                                ctx.value._nameplate = _healedNameplate;
                            }

                        }

                        if(ctx && ctx.value && ctx.value.nameplate){

                            _healedNameplate = healNameplate(ctx.value.nameplate, ctx.value);

                            if( _healedNameplate !== ctx.value.nameplate ) {
                                ctx.value.nameplateEcom = ctx.value.nameplate;
                                failedNameplate = ctx.value.nameplate;
                                ctx.value.nameplate = _healedNameplate;

                            }

                        }

                        if(ctx && ctx.value && ctx.value.model){

                            _healedNameplate = healNameplate(ctx.value.model, ctx.value);

                            if( _healedNameplate !== ctx.value.model ) {
                                ctx.value.nameplateEcom = ctx.value.model;
                                failedNameplate = ctx.value.model;
                                ctx.value.model = _healedNameplate;

                            }

                        }

                        if(ctx && ctx.value && ctx.value.firstVehicle && ctx.value.firstVehicle.Nameplate){

                            _healedNameplate = healNameplate(ctx.value.firstVehicle.Nameplate, ctx.value.firstVehicle);

                            if (_healedNameplate !== ctx.value.firstVehicle.Nameplate) {
                                ctx.value.nameplateEcom = ctx.value.firstVehicle.Nameplate;
                                failedNameplate = ctx.value.firstVehicle.Nameplate;
                                ctx.value.firstVehicle.Nameplate = _healedNameplate;

                            }
                        }

                        if(ctx && ctx.value && ctx.value.vehicle && ctx.value.vehicle.nameplate){

                            _healedNameplate = healNameplate(ctx.value.vehicle.nameplate, ctx.value.vehicle);

                            if (_healedNameplate !== ctx.value.vehicle.nameplate) {
                                ctx.value.nameplateEcom = ctx.value.vehicle.nameplate;
                                failedNameplate = ctx.value.vehicle.nameplate;
                                ctx.value.vehicle = DeepMerge({},ctx.value.vehicle);
                                ctx.value.vehicle.nameplate = _healedNameplate;
                            }
                        }

                        if( failedNameplate ) {

                            ctx.validationBus.trigger({
                                type: "VALIDATION_NAMEPLATE_FAILURE",
                                data: {
                                    value: failedNameplate,
                                    message: "Invalid nameplate being sent to FPS"
                                }
                            })
                        }

                    }catch(err){

                    }
                    return false;
                }
                ,  isNotValidTrim: function(ctx,event,condMeta){
                    try{
                        if(ctx.value._brand !== tagBrand) return false;

                        var trim = ctx.value._trim;

                        if( trim && !ctx.vdmTrims[trim] ){

                            ctx.value._trim = ctx.vdmTrimsMap[trim.trim().toLowerCase()] || trim;

                            ctx.validationBus.trigger({
                                type:"VALIDATION_TRIM_FAILURE",
                                data: {
                                    value: trim,
                                    message: "Invalid trim being sent to FPS"
                                }
                            })
                        }

                    }catch(err){

                    }
                    return false;
                }
                , keyIsNotCachable: function(ctx,event,condMeta){
                    return typeof FPS.Cache.set[ctx.key] === "undefined";
                }
                , checkIfStorageEntryIsNotFound: function(ctx,event,condMeta){
                    return typeof ctx.storageData === "undefined";
                }
                , checkIfEntryDoesNotMatchStorage: function(ctx,event,condMeta){
                    return JSON.stringify(ctx.storageData) !== JSON.stringify(ctx.entry);
                }
                , checkIfTTLHasExpired: function(ctx,event,condMeta){
                    return ctx.CURRENT_TIME - ctx.storageTTL > ctx.cacheTTL;
                }
                , isBroncoSportSet: function(ctx, event, condMeta){
                    try{
                        var entry = event && event.msg && event.msg.request && event.msg.request.entry || {};
                        var key = getFPSKey(entry);
                        var value = entry[key] || {_nameplate:""};
                        return value._nameplate === "broncosport";
                    }catch(err){
                        return false;
                    }
                }
            }
        };
    }
    function GetProps(prop,definition){
        var results = {};
        return function GetProps(path){
            var startPath = path;
            if(results[path]){
                return results[path];
            }
            var path = path.replace(/\./g,"."+prop+".").replace(/^\./,"").split('.');
            function loop(path,obj){
                var p = path[0] || prop;
                if(obj[p]){
                    if(path.length > 1){
                        return loop(path.slice(1),obj[p]);
                    }else{
                        results[startPath] = obj[p];
                        return obj[p];
                    }
                }
                return null;
            }
            return loop(path,definition);
        }
    }
    function StateMachine(definition){

        var currentState = definition.initial;
        var context = definition.context;
        var states = definition.states;
        var guards = definition.guards;
        var keywords = "initial,states,guards,on,cond,meta,target,invoke,context";

        var getState = GetProps("states",definition);

        var emitter = Emitter();


        ShallowMerge(emitter,{
            context: context
            , currentState: currentState
            , transition: function(fromState,event){
                // can I transition
                // run guards
                //==> fail: don't make transition
                // make transition
                // invoke transition
                var current = getState(fromState);
                var nextTarget = current.on[event.type];
                if(nextTarget){
                    var nextState;
                    if(Array.isArray(nextTarget)){
                        nextState = nextTarget.reduce(function(accum,guard){
                            if( accum === null && guards[guard.cond] ){
                                var result = guards[guard.cond](context,event);
                                if(result && guard.target){
                                    accum = guard;
                                }
                            }else if( accum === null && guard.target){
                                accum = guard;
                            }
                            return accum;
                        },null);
                    }else if(typeof nextTarget === "string"){
                        nextState = {target:nextTarget};
                    }
                    if(nextState && nextState.target){
                        emitter.trigger({
                            type:"transition"
                            , msg:{
                                from: this.currentState
                                , to: typeof nextState === "string" ? nextState : nextState.target || ""
                                , context: ShallowMerge({},this.context)
                            }
                        })
                        this.currentState = nextState.target;
                        var cond = nextState;
                        var nextState = getState(this.currentState);
                        var result;
                        if(typeof nextState.invoke === "function"){
                            result = nextState.invoke.call(null,context,event,{
                                Send: function(event){
                                    this.transition(this.currentState,event);
                                }.bind(this)
                                , Update: function(key,value){
                                    var newContext = this.context;
                                    newContext[key] = value;
                                    this.context = newContext;
                                }.bind(this)
                            });
                        }
                        if(nextState.type === "final"){
                            emitter.trigger({
                                type:"final"
                                , msg:{
                                    result:result
                                    , context: ShallowMerge({},this.context)
                                }
                            })
                        }
                    }else{
                        console.log("FPS -> StateMachine: could not find state",nextTarget,event.type);
                    }

                }else{
                    console.log("FPS -> StateMachine: Invalid transition",current,nextTarget,event.type);
                }
            }
        });

        return emitter;
    }
    function StateService(StateMachine){
        return function StateService(definition,initialContext){
            var stateMachine = StateMachine(definition(initialContext));
            var completed = false;
            var resultEvent;
            var resultState;
            return {
                send: function(transitionEvent){
                    stateMachine.transition(stateMachine.currentState,transitionEvent);
                    return this;
                }
                , update: function(key,value){
                    var newContext = stateMachine.context;
                    newContext[key] = value;
                    stateMachine.context = newContext;
                    return this;
                }
                , done: function(callback){
                    if(completed === false){
                        stateMachine.add(function(stateEvent){
                            if(stateEvent.type === "final"){
                                completed = true;
                                resultEvent = stateEvent;
                                resultState = stateMachine;
                                callback.call(null,resultEvent,resultState);
                            }
                        });
                    }else{
                        callback.call(null,resultEvent,resultState);
                    }
                    return this;
                }
            }
        }
    }

    function Encode(str) {
        var HTMLCharMap = {
            "&": "&amp;",
            "'": "&#39;",
            '"': "&quot;",
            "<": "&lt;",
            ">": "&gt;",
            "\\": "&#x5c;",
            "`": "&#x60;",
            ":": "&#58;"
        };

        function encodeHTMLmapper(ch) {
            return HTMLCharMap[ch];
        }

        if(typeof str === "string") {
            return str.replace(/[&"'<>\\`:]/g, encodeHTMLmapper);
        }

        return str;
    }

    function Random(){

        try {
            if (window.crypto) {

                const array = new Uint32Array(1);
                window.crypto.getRandomValues(array);

                return array[0] / (Math.pow(2, 32) - 1);
            }

            return Math.random();
        }catch(err){
            return Math.random();
        }
    }

    var CreateStateService = StateService(StateMachine);
    if(Emitter){
        var SetBus = Emitter();
        var GetBus = Emitter();
        var ExternalRefBus = Emitter();
        var SetValidationBus = Emitter();

        var validationFailedValues = {nameplate:[],trim:[]};
        var validationRequestTimeout;
        function validationReduceToUniqueList(list){
            if( !Array.isArray(list) || (Array.isArray(list) && list.length === 0) ) return [];
            return list.reduce(function(accum,current,index,original){
                var value = current && current.value;
                if(value){
                    accum[value] = value;
                }
                if(index === original.length -1){
                    return Object.keys(accum).reduce(function(accum,current){
                        if( current ){
                            accum.push({value:current});
                        }
                        return accum;
                    },[]);
                }

                return accum;
            },{});
        }

        function sendValidationFailureRequest(type,list){
            if(blockNetworkRequests === true) return;
            if(disableInsights === true) return;
            try{
                var xhr = new XMLHttpRequest();
                var pageName = (typeof window.digitaldata !== 'undefined' && typeof window.digitaldata.page !== 'undefined' && typeof
                  window.digitaldata.page.pageName !== 'undefined') ? window.digitaldata.page.pageName : null ;

                var _loc = FPS.Core.Insights.Utils.getTier("https://" + window.location.hostname);

                if(pageName !== null && _loc.toUpperCase() === "T1")
                {
                    _loc =_loc + "-" + pageName;
                }
                list = list.map(function(el)
                {
                    el.location = _loc;
                    return el;
                })
                xhr.open("post", xdcPathSet + "/api/insights/validation/type/"+type);
                xhr.setRequestHeader("Content-Type","application/json; charset=UTF-8");

                xhr.addEventListener("readystatechange",function(){});
                console.log("Send POST:",xdcPathSet + "/api/insights/validation/type/"+type,list);

                xhr.send(JSON.stringify(list));
            }catch(err){

            }
        }

        function sendValidationFailures(values){
            var nameplate = values && values.nameplate || [];
            var trim = values && values.trim || [];
            var filteredNameplate = validationReduceToUniqueList(nameplate);
            var filteredTrim = validationReduceToUniqueList(trim);

            if(filteredNameplate && filteredNameplate.length > 0) sendValidationFailureRequest('nameplate',filteredNameplate);
            if(filteredTrim && filteredTrim.length > 0) sendValidationFailureRequest('trim',filteredTrim);
        }

        SetValidationBus.add(function(msg){
            try{
                var type = msg.type === "VALIDATION_NAMEPLATE_FAILURE" ? "nameplate" : msg.type === "VALIDATION_TRIM_FAILURE" ? "trim" : "";
                var data = msg && msg.data || {};
                var value = data && typeof data.value === "string" ? data.value : "";
                var message = data && typeof data.message === "string" ? data.message : "";

                if((type === "nameplate" || type === "trim") && value){

                    validationFailedValues[type].push({value: value});
                    if(!validationRequestTimeout){
                        validationRequestTimeout = setTimeout(function(){
                            sendValidationFailures(validationFailedValues);
                            validationFailedValues = {nameplate:[],trim:[]};
                            clearTimeout(validationRequestTimeout);
                            validationRequestTimeout = null;
                        },500);
                    }
                }

            }catch(err){

            }

        });

        var SetStateMachineInitialContext = {
            vdmActiveNameplates: vdmActiveNameplates || {},
            vdmActiveNameplatesMap: vdmActiveNameplatesMap || {},
            vdmTrims: vdmTrims,
            vdmTrimsMap: vdmTrimsMap,
            validationBus: SetValidationBus
        };

        ExternalRefBus.add(function(msg){
            if(msg.type === "FPS_API:setExternalRef"){
                CreateStateService(ExternalRefStateMachineDefinition).send({
                    type: "REQUEST"
                    , msg: msg
                });
            }
        });

        SetBus.add(function(msg){
            if(msg.type === "FPS_API:set"){
                var entries = msg.request.entry;
                var callbacks = msg.request.callbacks;
                var success = callbacks && callbacks.success || function(){};
                var error = callbacks && callbacks.error || function(){};

                function CallbackHandler(length){
                    var count = 0;
                    return function(fn){
                        return function(result){
                            count++;
                            if(count === length && typeof fn === "function"){
                                fn.apply(null,arguments);
                            }
                        }
                    }
                }

                var callbackHandler = CallbackHandler(entries.length);

                entries.forEach(function(el,index){
                    CreateStateService(SetStateMachineDefinition,SetStateMachineInitialContext).send({
                        type:"REQUEST"
                        , msg: {
                            id: msg.id
                            , request: { entry: el, callbacks: {success: callbackHandler(success) , error: callbackHandler(error)}}
                            , type: "FPS_API:set"
                            , index: index
                        }
                    })
                })

            }
        });

        GetBus.add(function(msg){
            if(msg.type === "FPS_API:get" && msg.request && msg.request.entries){
                ShallowMerge(core.config, FPS.config);
                var callbacks = msg && msg.request && msg.request.callbacks || {success:function(e){},error:function(e){}};
                var asBrand = msg && msg.request && msg.request.asBrand;
                var asCountry = msg && msg.request && msg.request.asCountry;
                var timeout = callbacks && callbacks.timeout;
                var processed = [];
                msg.request.entries.forEach(function(el,index){
                    CreateStateService(GetStatePreProcessMachineDefinition)
                      .done(function(event,state){
                          processed.push(event.msg.result);
                      }).send({
                        type:"REQUEST"
                        , msg: {
                            id: msg.id
                            , type: msg.type
                            , request: {
                                callbacks: callbacks
                                , entry: el
                                , index: index
                            }
                        }
                    });
                });
                var result = processed.reduce(function(accum,current){
                    if(current && current.inStorage){
                        accum.inStorage.push(current.inStorage);
                    } else if( current && current.newEntry){
                        if(!accum.indices[current.fpsKey+current.locale]){
                            accum.indices[current.fpsKey+current.locale] = current.index;
                        }

                        try {
                            var hasValidKey = !/[^a-z0-9_]/gi.test(current.newEntry.key);
                            var hasValidReservedKey = !/[^a-z0-9_]/gi.test(current.newEntry.reservedKey);
                            var hasValidQuery = true;
                            var hasValidMax = true;
                            var hasValidSuffix = true;

                            if(current.newEntry && current.newEntry.value && current.newEntry.value.query){
                                hasValidQuery = ["Score","ScoreAggregate:p*","LatestFromGroups:p*"].includes(current.newEntry.value.query);
                            }

                            if(current.newEntry && current.newEntry.value && typeof current.newEntry.value.max === "number"){
                                hasValidMax = current.newEntry.value.max > 0 && current.newEntry.value.max <= 100;
                            }

                            if(current.newEntry && current.newEntry.value && Array.isArray(current.newEntry.value.suffixFilter) && current.newEntry.value.suffixFilter.length > 0){
                                var foundInvalidItems = current.newEntry.value.suffixFilter. filter(function(item){
                                    if(typeof item !== "string" || item === "") return true;
                                    return /[^a-z0-9_]/gi.test(item);
                                });

                                hasValidSuffix = foundInvalidItems.length === 0;
                            }

                            var isValidEntry = hasValidKey && hasValidReservedKey && hasValidQuery && hasValidMax && hasValidSuffix;

                            accum.entries.push(isValidEntry ? current.newEntry : null);

                        }catch(err){
                            accum.entries.push(current.newEntry);
                        }
                    }
                    return accum;
                },{entries:[],inStorage:[],indices:{}});
                CreateStateService(GetStateProcessMachineDefinition)
                  .send({
                      type:"REQUEST"
                      , msg: {
                          id: msg.id
                          , type: msg.type
                          , callbacks: callbacks
                          , entries: result.entries
                          , inStorage: result.inStorage
                          , indices: result.indices
                      }
                  });
            }
        });

    }

    var hasRDNS = ccpaDomains.filter(function (entry) {
        try {
            return entry._site === window.location.hostname;
        } catch (err) {
            return false;
        }
    }).length !== 0;

    var now = new Date();
    var cookie = {
        domain: (function () {
            var i = 0, domain = document.domain, p = domain.split('.'), s = '_gd' + now.getTime();
            while (i < (p.length - 1) && document.cookie.indexOf(s + '=' + s) == -1) {
                domain = p.slice(-1 - (++i)).join('.');
                document.cookie = s + "=" + s + ";domain=" + domain + ";";
            }
            document.cookie = s + "=;expires=Thu, 01 Jan 1970 00:00:01 GMT;domain=" + domain + ";";
            return domain;
        })(),
        set: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {
            if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; }
            var sExpires = "";
            var sSameSite = "None";
            if (vEnd) {
                switch (vEnd.constructor) {
                    case Number:
                        sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd;
                        break;
                    case String:
                        sExpires = "; expires=" + vEnd;
                        break;
                    case Date:
                        sExpires = "; expires=" + vEnd.toUTCString();
                        break;
                }
            }
            if (sSameSite === "None")
                bSecure = true;
            document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue.replace(/[^ -~]/gim,"")) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : "") + (sSameSite ? "; samesite=" + sSameSite : "None");
            return true;
        },
        get: function (name) {
            var nameEQ = name + "=";
            var dc = document.cookie;
            var ca = dc.split(';');
            for (var i = 0; i < ca.length; i++) {
                var c = ca[i];
                while (c.charAt(0) == ' ') c = c.substring(1, c.length);
                if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
            }
            return null;
        }
    };

    var UUIDV4 = function b(a) { return a ? (a ^ Random() * 16 >> a / 4).toString(16) : ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, b) };

    var gt_dns = Encode(cookie.get("gt_dns"));
    var currentGUID = Encode(cookie.get('gt_uid'));

    if (hasRDNS === true && gt_dns !== true) {

        cookie.set('gt_dns', true, new Date(now.getTime() + (cookieDaysToLive * 86400000)), '/', cookie.domain);

        gt_dns = "true";

        if (currentGUID === xdcGTUID) {
            var newId = UUIDV4();
            cookie.set('gt_uid', newId, new Date(now.getTime() + (cookieDaysToLive * 86400000)), '/', cookie.domain);
            if(blockNetworkRequestsDomain) blockNetworkRequests = true;
        }
    }

    // prevent cross domain request when local dns cookie is set
    //
    var skipXDCRequest = typeof gt_dns === "string" && gt_dns.toLocaleLowerCase() === "true";

    var registerXDC = function (xdcGuid, preventRequest) {

        if (preventRequest === true) return false;

        var url = xdcRegSrvc + "?regFPSID=" + xdcGuid;

        try {

            url = url += (xdcRegSrvc.indexOf("checkFPSXDC.json") > -1) ? "" : "&brand=" + tagBrand;

            window.fpsJSONPHandler = function(){
                console.log(arguments);
            }

            var script = document.createElement("script");
            script.id = "fpsJSONPLoader";
            script.src = url;
            document.body.appendChild(script);
            document.body.removeChild(script);

        } catch (err) { }

    };

    var uid = Encode(cookie.get('gt_uid'));
    if(!uid)
    {
        var tier  = "";
        if(checkT1(baseUrl)) {
            tier = "t1";
        }else if(checkT2(baseUrl)){
            tier = "t2";
        }
        else {
            tier = "tn";
        }
    }
    if (xdcDomain.length > 0 && skipXDCRequest === false) {
        if (!uid) {
            if (xdcGTUID.length > 0) {
                uid = xdcGTUID;
            } else {
                uid = UUIDV4();
                registerXDC(uid);
                if(typeof newFpsIdInsight === "function") newFpsIdInsight(tier);
            }
        } else {
            if (xdcGTUID.length > 0) {
                uid = xdcGTUID;
            } else {
                registerXDC(uid);
            }
        }
    }
    else if (!uid) {
        uid = UUIDV4();
        if(typeof newFpsIdInsight === "function") newFpsIdInsight(tier);
    }

    if (personalizationActive && uid) {
        cookie.set('gt_uid', uid, new Date(now.getTime() + (cookieDaysToLive * 86400000)), "/", cookie.domain);
    }

    var ajaxConfig = { type: 'POST', dataType: 'json', contentType: 'application/json; charset=UTF-8' };
    var ajaxData = { uid: uid, tagBrand: tagBrand, tagCountry: tagCountry, referrer: document.referrer };
    var djb2 = function (str) {
        var hash = 5381;
        for (i = 0; i < str.length; i++) {
            c = str.charCodeAt(i);
            hash = ((hash << 5) + hash) + c;
        }
        return hash;
    };
    var stringifyEach = function (keyValueObjects) {
        if (Array.isArray(keyValueObjects)) {
            keyValueObjects.forEach(function (keyValueObject) {
                for (var key in keyValueObject) {
                    if (typeof keyValueObject[key] !== "string")
                    {
                        keyValueObject[key] = JSON.stringify(keyValueObject[key]);
                    }
                }
            });
        }
        return keyValueObjects;
    };
    var core = {
        config: {
            locale: "",
            path: '',
            testMode: false
        },
        lib: {
            ExternalRef: function (type, id) {
                return { 'ExternalRef': { _type: type, id: djb2(id) } };
            },
            ExternalRefUnhashed: function (type, id) {
                return { 'ExternalRef': { _type: type, id: id, djb2: djb2(id) } };
            }
        },
        reservedProperties: ['metadata', 'reservedKey', 'trueKey', 'params', 'match', 'suffix', 'query', 'suffixFilter'],
        set: function (entries, _timeout) {
            var config = ShallowMerge(ajaxConfig, {
                url: xdcPathSet + apiPaths.set,
                timeout: typeof _timeout === "number" ? _timeout : 5000
            });
            config.data = JSON.stringify(ShallowMerge(ajaxData, {
                entries: entries,
                url: document.location.href,
                testMode: core.config.testMode
            }));
            return new Promise(function(resolve,reject){
                new Request({
                    method: "POST"
                    , url: config.url
                    , headers: {
                        "Content-Type": "application/json; charset=UTF-8"
                    }
                    , body: config.data
                    , timeout: config.timeout
                })
                  .then(function () {
                      resolve(arguments[0]);
                  })
                  .catch(function () {
                      reject(arguments[0]);
                  })
            });
        },
        get: function (keyValueObjects, _timeout, asBrand, asCountry) {
            var entries = stringifyEach(keyValueObjects);
            var config = ShallowMerge(ajaxConfig, {
                url: xdcPathGet + apiPaths.get + uid,
                timeout: (typeof _timeout === "number") ? _timeout : 3000
            });
            config.data = JSON.stringify(ShallowMerge(ajaxData, {
                entries: entries,
                tagBrand: asBrand || tagBrand,
                tagCountry: asCountry || tagCountry,
                testMode: core.config.testMode
            }));
            return new Promise(function(resolve,reject){
                new Request({
                    method: "POST"
                    , url: config.url
                    , headers: {
                        "Content-Type": "application/json; charset=UTF-8"
                    }
                    , body: config.data
                    , timeout: config.timeout
                })
                  .then(function () {
                      if(arguments && arguments[0] && arguments[0][0]){
                          arguments[0][0] = filterFPSGetVdmNameplateTrim(arguments[0][0]);
                      }
                      resolve(arguments[0]);
                  })
                  .catch(function () {
                      reject(arguments[0]);
                  })
            });
        },
        setExternalRef: function (entries, _timeout) {
            var config = ShallowMerge(ajaxConfig, {
                url: xdcPathSetExternalRef + apiPaths.setExternalRef,
                timeout: typeof _timeout === "number" ? _timeout : 5000,
                testMode: core.config.testMode
            });
            config.data = JSON.stringify(ShallowMerge(ajaxData, {
                entries: entries,
                url: document.location.href
            }));

            return new Promise(function(resolve,reject){
                new Request({
                    method: "POST"
                    , url: config.url
                    , headers: {
                        "Content-Type": "application/json; charset=UTF-8"
                    }
                    , body: config.data
                    , timeout: config.timeout
                })
                  .then(function () {
                      var resp = arguments[0][0];
                      // if(resp.uid_submitted === resp.uid_reconciled)
                      // {
                      //     cookie.set('gt_exref',resp.uid_reconciled);
                      // }
                      resolve(arguments[0]);
                  })
                  .catch(function () {
                      reject(arguments[0]);
                  })
            });
        }
    };
    var getFPSKey = function (fpsObject) {
        for (var key in fpsObject) {
            if(core.reservedProperties.indexOf(key) < 0) {
                return key;
            }
        }
        return null;
    };
    var storageKeyPrefix = 'FPS_Cache__';
    var storageKey = function (reservedKey) {
        return storageKeyPrefix + reservedKey;
    };
// NEW
    /**
     *
     * @function
     * @name getLocale
     * @description Gets the locale value from FPS.config.locale.
     * @description If skipLocalFilter is true no locale values will be filtered out.
     * @description If skipLocalFilter is false(default), then any locales on the black list will be filtered out"
     * @param {Object} options.FPS
     * @param {boolean} [options.skipLocalFilter=false]
     * @returns {string} FS.config.locale or ""
     */
    var getLocale = function (options) {

        try {

            var FPS = options.FPS;
            var skipLocaleFilter = options.skipLocaleFilter || false;

            if (!FPS || !FPS.config || !FPS.config.locale || typeof FPS.config.locale !== "string") return "";

            var _locale = FPS.config.locale.toLowerCase();
            var localeBlackList = "";

            if(skipLocaleFilter === false) {
                try{

                    localeBlackList = FPS && FPS.Blacklist && typeof FPS.Blacklist === "object" ? Object.keys(FPS.Blacklist.locale).join(',') : "";

                }catch(err){

                }
            }

            return localeBlackList.indexOf(_locale) === -1 ? "_" + _locale : "";

        } catch (err) {

        }

        return "";
    };
    /**
     *
     * Gets the locale value of FPS.Blacklist.keys
     * @function
     * @name getFPSBlacklistKeys
     * @param {Object} FPS
     * @returns {Object} FPS.Blacklist.keys or undefined
     */
    var getFPSBlacklistKeys = function(FPS){

        try{

            return FPS.Blacklist.keys;

        }catch(err){
            return {};
        }

    };
    /**
     *
     * Checks if a key is blacklisted
     * @function
     * @name checkIfKeyIsBlackListed
     * @param {string} options.key
     * @param {Object} options.blacklist
     * @returns {boolean}
     */
    var checkIfKeyIsBlackListed = function(options){

        try{

            var key = options && options.key;
            var blacklist = options && options.blacklist;

            return blacklist[key] ? true : false;

        }catch(err){
            return false;
        }

    };
// :NEW
    var globalHeaderLocale = "";
    try {
        globalHeaderLocale = window.FD && window.FD.Brand && window.FD.Brand.Context && typeof window.FD.Brand.Context.locale === "string" && window.FD.Brand.Context.locale.length > 0 ? window.FD.Brand.Context.locale.toLocaleLowerCase() : "";
    }catch(err){

    }
    window.FPS = {
        config: {
            path: xdcPath.length > 0 ? xdcPath : '/fps',
            locale: globalHeaderLocale
        },
        actions: {
            BPComplete: { name: 'BPComplete', score: '3' },
            BPStart: { name: 'BPStart', score: '2' },
            Referral: { name: 'Referral', score: '2' },
            RequestBrochure: { name: 'RequestBrochure', score: '3' },
            RequestPaymentEstimate: { name: 'RequestPaymentEstimate', score: '3' },
            RequestQuickQuote: { name: 'RequestQuickQuote', score: '5' },
            RequestQuote: { name: 'RequestQuote', score: '4' },
            RequestUpdates: { name: 'RequestUpdates', score: '5' },
            ScheduleTestDrive: { name: 'ScheduleTestDrive', score: '4' },
            SearchDealer: { name: 'SearchDealer', score: '2' },
            SearchInventory: { name: 'SearchInventory', score: '3' },
            SearchSite: { name: 'SearchSite', score: '2' },
            ViewPage: { name: 'ViewPage', score: '1' }
        },
        lib: {
            ActionNameplate: function (year, brand, nameplate, action, returnURL) {
                return { 'ActionNameplate': { _year: year, _brand: brand, _nameplate: nameplate, returnURL: returnURL }, suffix: action.name, metadata: { score: action.score } };
            },
            ActionTrim: function (year, brand, nameplate, trim, action, returnURL) {
                return { 'ActionTrim': { _year: year, _brand: brand, _nameplate: nameplate, _trim: trim, returnURL: returnURL }, suffix: action.name, metadata: { score: action.score } };
            },
            PageVisit: function (omniturePageName) {
                return { 'PageVisit': { _omniturePageName: omniturePageName } };
            },
            PreferredDealer: function (paCode, description) {
                return { 'PreferredDealer': { _paCode: paCode, description: description } };
            },
            UserDefinedLocation: function (name, description) {
                return { 'UserDefinedLocation': { _name: name, description: description } };
            },
            ViewedVehicle: function (year, brand, nameplate, trim) {
                return { 'ViewedVehicle': { _year: year, _brand: brand, _nameplate: nameplate, _trim: trim } };
            },
            Visited: function (url) {
                return { 'Visited': { _url: url } };
            }
        },
        reserved: {
            LastViewedVehicle: { reservedKey: 'LastViewedVehicle', trueKey: 'ViewedVehicle', params: { max: 1 } },
            RecentlyViewedVehicles: { reservedKey: 'RecentlyViewedVehicles', trueKey: 'ViewedVehicle', params: { max: 4 } },
            VOIAggregateNameplate: { reservedKey: 'VOIAggregateNameplate', trueKey: 'ActionNameplate', params: { query: 'ScoreAggregate:p*', max: 1 } },
            VOIAggregateTrim: { reservedKey: 'VOIAggregateTrim', trueKey: 'ActionTrim', params: { query: 'ScoreAggregate:p*', max: 1 } },
            VOISimpleNameplate: { reservedKey: 'VOISimpleNameplate', trueKey: 'ActionNameplate', params: { query: 'Score', max: 1 } },
            VOISimpleTrim: { reservedKey: 'VOISimpleTrim', trueKey: 'ActionTrim', params: { query: 'Score', max: 1 } }
        },
        get: function (keyValueObjects, callbacks, asBrand, asCountry) {
            if(callbacks && callbacks.success && callbacks.error){
                keyValueObjects = Array.isArray(keyValueObjects) ? keyValueObjects : [keyValueObjects];
                GetBus.trigger({
                    id: UUIDV4()
                    , type: "FPS_API:get"
                    , request:{
                        entries: keyValueObjects
                        , callbacks: callbacks
                        , asBrand: asBrand
                        , asCountry: asCountry
                    }
                });
            }
        },
        set: function (keyValueObjects, callbacks) {
            keyValueObjects = Array.isArray(keyValueObjects) ? keyValueObjects : [keyValueObjects];
            SetBus.trigger({
                id: UUIDV4()
                , type: "FPS_API:set"
                , request:{
                    entry: keyValueObjects
                    , callbacks: callbacks
                }
            })
        },
        getAll: function (callbacks) {
            FPS.get([
                { 'Visited': { max: 1 } },
                { 'UserDefinedLocation': { max: 1 } },
                FPS.reserved.RecentlyViewedVehicles,
                { 'PreferredDealer': { max: 10 } },
                FPS.reserved.LastViewedVehicle
            ], callbacks);
        },
        setExternalRef: function (type, id, callbacks, unhashed) {

            // if(type === "CSDN"){
            //     internals.addExternalRefCallback(type, id, callbacks, unhashed);
            //     return;
            // }

            ExternalRefBus.trigger({
                id: UUIDV4()
                , type: "FPS_API:setExternalRef"
                , request:{
                    type: type
                    , id: id
                    , callbacks: callbacks
                    , unhashed: unhashed
                }
            })
        }
    };
    DeepMerge( window.FPS, {getScore: function(action) {
            action = {
                scoreMobile: action && action.scoreMobile || 0
                ,score: action && action.score || 0
            };
            return (typeof s !== 'undefined' && typeof s.eVar54 !== 'undefined' && s.eVar54.indexOf('mobile') >= 0) ? action['scoreMobile'] : action['score'];
        }
        , getV1Score: function(action) {
            action = {
                "PBI Mobile": action && action["PBI Mobile"] || 0
                ,"PBI Desktop": action && action["PBI Desktop"] || 0
            };
            return (typeof s !== 'undefined' && typeof s.eVar54 !== 'undefined' && s.eVar54.indexOf('mobile') >= 0) ? action['PBI Mobile'] : action['PBI Desktop'];
        }
        , actions: {
            //  T1
            BaseAction1: { name: 'BaseAction1', score: '100', scoreMobile: '200' },
            BPComplete: { name: 'BPComplete', score: '2461', scoreMobile: '2274' },
            BPGetOffers: { name: 'BPGetOffers', score: '360', scoreMobile: '268' },
            BPModelSelect: { name: 'BPModelSelect', score: '393', scoreMobile: '391' },
            BPRequestQuote: { name: 'BPRequestQuote', score: '2718', scoreMobile: '2718' },
            BPResults: { name: 'BPResults', score: '0', scoreMobile: '0' },
            BPSave: { name: 'BPSave', score: '500', scoreMobile: '500' },
            BPSearchInv: { name: 'BPSearchInv', score: '400', scoreMobile: '400' },
            BPStart: { name: 'BPStart', score: '507', scoreMobile: '640' },
            FMCMNV: { name: "FMCMNV", score: "468", scoreMobile: "449" },
            GOLFOther: { name: 'GOLFOther', score: '300', scoreMobile: '300' },
            GOLFRequestQuickQuote: { name: 'GOLFRequestQuickQuote', score: '1319', scoreMobile: '1378' },
            GOLFRequestUpdates: { name: 'GOLFRequestUpdates', score: '460', scoreMobile: '393' },
            GOLFScheduleTestDrive: { name: 'GOLFScheduleTestDrive', score: '939', scoreMobile: '967' },
            IOAdditonalOffer: { name: 'IOAdditonalOffer', score: '1113', scoreMobile: '1103' },
            IOFeatured: { name: 'IOFeatured', score: '1113', scoreMobile: '1103' },
            IOModelOffers: { name: 'IOModelOffers', score: '476', scoreMobile: '455' },
            IOView: { name: 'IOView', score: '476', scoreMobile: '455' },
            Referral: { name: 'Referral', score: '0', scoreMobile: '0' },
            RequestBrochure: { name: 'RequestBrochure', score: '300', scoreMobile: '300' },
            RequestPaymentEstimate: { name: 'RequestPaymentEstimate', score: '507', scoreMobile: '640' },
            RequestQuickQuote: { name: 'RequestQuickQuote', score: '1319', scoreMobile: '1378' },
            RequestQuote: { name: 'RequestQuote', score: '2718', scoreMobile: '2718' },
            RequestUpdates: { name: 'RequestUpdates', score: '460', scoreMobile: '393' },
            ScheduleTestDrive: { name: 'ScheduleTestDrive', score: '939', scoreMobile: '967' },
            SearchDealer: { name: 'SearchDealer', score: '991', scoreMobile: '968' },
            SearchInventory: { name: 'SearchInventory', score: '300', scoreMobile: '300' },
            SearchSite: { name: 'SearchSite', score: '0', scoreMobile: '0' },
            SIResults: { name: 'SIResults', score: '300', scoreMobile: '300' },
            SVVBP: { name: 'SVVBP', score: '0', scoreMobile: '0' },
            SVVFMCMNV: { name: "SVVFMCMNV", score: "468", scoreMobile: "449" },
            SVVSI: { name: 'SVVSI', score: '1358', scoreMobile: '1289' },

            SVVSEVOSPEC: { name: 'SVVSEVOSPEC', score: '0', scoreMobile: '0' },
            SVVSEVOVIN: { name: 'SVVSEVOVIN', score: '1358', scoreMobile: '1289' },

            StartChat: { name: 'StartChat', score: '300', scoreMobile: '300' },
            ViewEventsPage: { name: 'ViewEventsPage', score: '100', scoreMobile: '100' },
            ViewFeatures: { name: 'ViewFeatures', score: '392', scoreMobile: '382' },
            ViewGallery: { name: 'ViewGallery', score: '905', scoreMobile: '886' },
            ViewModelDetail: { name: 'ViewModelDetail', score: '1006', scoreMobile: '986' },
            ViewModelDetailBlackLabel: { name: 'ViewModelDetailBlackLabel', score: '0', scoreMobile: '0' },
            ViewModels: { name: 'ViewModels', score: '1006', scoreMobile: '986' },
            ViewPage: { name: 'ViewPage', score: '300', scoreMobile: '300' },
            ViewPageBlackLabel: { name: 'ViewPageBlackLabel', score: '300', scoreMobile: '300' },
            ViewPageReveal: { name: 'ViewPageReveal', score: '300', scoreMobile: '300' },
            ViewWindowSticker: { name: 'ViewWindowSticker', score: '1597', scoreMobile: '1131' },
            // T2
            CompareT2: { name: 'CompareT2', score: '300', scoreMobile: '300' },
            CurrentOffersT2: { name: 'CurrentOffersT2', score: '360', scoreMobile: '268' },
            IOT2: { name: 'IOT2', score: '300', scoreMobile: '300' },
            LADT2: { name: 'LADT2', score: '0', scoreMobile: '0' },
            RequestQuoteT2: { name: 'RequestQuoteT2', score: '2718', scoreMobile: '2718' },
            HeadToHeadT2: { name: 'HeadToHeadT2', score: '1113', scoreMobile: '1103' },
            // T3
            BrowseGalleryT3: { name: 'BrowseGalleryT3', score: '905', scoreMobile: '886' },
            CPODetailViewT3: { name: 'CPODetailViewT3', score: '468', scoreMobile: '449' },
            GetAlertsT3: { name: 'GetAlertsT3', score: '400', scoreMobile: '400' },
            RequestQuoteT3: { name: 'RequestQuoteT3', score: '2718', scoreMobile: '2718' },
            SaveSIT3: { name: 'SaveSIT3', score: '300', scoreMobile: '0' },
            ScheduleTestDriveT3: { name: 'ScheduleTestDriveT3', score: '939', scoreMobile: '967' },
            SIResultsT3: { name: 'SIResultsT3', score: '0', scoreMobile: '0' },
            SVVSIT3: { name: 'SVVSIT3', score: '1358', scoreMobile: '1289' },
            ViewModelDetailT3: { name: 'ViewModelDetailT3', score: '1006', scoreMobile: '986' },
            ViewSpecsT3: { name: 'ViewSpecsT3', score: '737', scoreMobile: '775' },
            // Mach-e
            ViewPageEcom: { name: "ViewPageEcom", score: "300", scoreMobile: "300" },
            VewPageEcom: { name: "ViewPageEcom", score: "300", scoreMobile: "300" },
            StartConfigEcom: { name: "StartConfigEcom", score: "507", scoreMobile: "640", },
            SVVConfigInProgressEcom: { name: "SVVConfigInProgressEcom", score: "50", scoreMobile: "50" },
            SVVConfigCompleteEcom: { name: "SVVConfigCompleteEcom", score: "2461", scoreMobile: "2274", },
            SVVStartResvEcom: { name: "SVVStartResvEcom", score: "500", scoreMobile: "500" },
            // FBC (FPS-919
            ViewPageFBC: { name: "ViewPageFBC", score: "300", scoreMobile: "300" },
            StartConfigFBC: { name: "StartConfigFBC", score: "507", scoreMobile: "640" },
            SVVConfigInProgressFBC: { name: "SVVConfigInProgressFBC", score: "50", scoreMobile: "50" },
            SVVConfigCompleteFBC: { name: "SVVConfigCompleteFBC", score: "2461", scoreMobile: "2274" },
            SVVStartResvFBC: { name: "SVVStartResvFBC", score: "500", scoreMobile: "500" },
            PaymentCalculatorFBC: { name: "PaymentCalculatorFBC", score: "989", scoreMobile: "998" },
            PaymentCalculatorEcom: { name: "PaymentCalculatorEcom", score: "989", scoreMobile: "998" },
            // Fleet (FPS-1149)
            ViewPage_Fleet: { name: "ViewPage_Fleet", score: "300", scoreMobile: "300" },
            ViewPageReveal_Fleet: { name: "ViewPageReveal_Fleet", score: "300", scoreMobile: "300" },
            ViewPageEcom_Fleet: { name: "ViewPageEcom_Fleet", score: "300", scoreMobile: "300" },
            ViewModels_Fleet: { name: "ViewModels_Fleet", score: "1006", scoreMobile: "986" },
            ViewModelDetail_Fleet: { name: "ViewModelDetail_Fleet", score: "1006", scoreMobile: "986" },
            ViewGallery_Fleet: { name: "ViewGallery_Fleet", score: "905", scoreMobile: "886" },
            ViewFeatures_Fleet: { name: "ViewFeatures_Fleet", score: "392", scoreMobile: "382" },
            // showroom
            QuickView: { name: "QuickView", score: "300", scoreMobile: "300" },
            ViewPrice: { name: "ViewPrice", score: "376", scoreMobile: "376" },
            LoadMore: { name: "LoadMore", score: "300", scoreMobile: "300" },
            //VDP
            SVVEDI: { name: "SVVEDI", score: "459", scoreMobile: "459" },
            ViewGalleryEDI: { name: "ViewGalleryEDI ", score: "418", scoreMobile: "418" },
            SpecificationsEDI: { name: "SpecificationsEDI ", score: "410", scoreMobile: "410" },
            SaveEDI: { name: "SaveEDI ", score: "300", scoreMobile: "300" },
            ShareEDI: { name: "ShareEDI ", score: "300", scoreMobile: "300" },
            SPCLoad: { name: 'SPCLoad', score: '354', scoreMobile: '389' },
            // VFT
            ModelSelectVFT: { name: "ModelSelectVFT", score: "300", scoreMobile: "300" },
            FeatureSelectVFT: { name: "FeatureSelectVFT", score: "300", scoreMobile: "300" },
            SearchResultsVFT: { name: "SearchResultsVFT", score: "300", scoreMobile: "300" },
        }
    });DeepMerge( window.FPS, {lib: {
            // T1
            ActionNameplate: function (year, brand, nameplate, action, returnURL, options) {
                FPS.OI.Vehicle.set(year, brand, nameplate, '', FPS.getScore(action) );
                FPS.pageLoadTracker.trackPage();
                var displayName = options && typeof options.displayName === "string" ? options.displayName : "";

                return {
                    'ActionNameplate': {
                        _year: year,
                        _brand: brand,
                        _nameplate: nameplate,
                        returnURL: returnURL,
                        displayName: displayName
                    },
                    suffix: action.name,
                    metadata: { score: FPS.getScore(action) }
                };
            },
            ActionNameplateNoYR: function (brand, nameplate, action) {
                //FPS.OI.Vehicle.set('', brand, nameplate, '', FPS.getScore(action));
                FPS.pageLoadTracker.trackPage();
                return {
                    'ActionNameplateNoYR': {
                        _brand: brand,
                        _nameplate: nameplate
                    },
                    suffix: action.name,
                    metadata: { score: FPS.getScore(action) }
                };
            },
            ActionTrim: function (year, brand, nameplate, trim, action, returnURL, options) {
                FPS.OI.Vehicle.set(year, brand, nameplate, trim, FPS.getScore(action) );
                if(action.name==="BPComplete"){FPS.pageLoadTracker.trackPage();};


                var displayName = options && typeof options.displayName === "string" ? options.displayName : "";

                return {
                    'ActionTrim': {
                        _year: year,
                        _brand: brand,
                        _nameplate: nameplate,
                        _trim: trim,
                        returnURL: returnURL,
                        displayName: displayName
                    },
                    suffix: action.name,
                    metadata: { score: FPS.getScore(action) }
                };
            },
            CurrentDealerEDI: function (paCode,dealerId) {
                return {
                    CurrentDealerEDI:{
                        paCode: paCode,
                        dealerId: dealerId
                    }
                }
            },
            FPICookie: function (make, zip, year, model) {
                return {
                    'FPICookie': {
                        make: make,
                        zip: zip,
                        year: year,
                        model: model
                    }
                };
            },
            FPSTierDrop: function (tier, active) {
                return {
                    'FPSTierDrop': {
                        tier : tier
                    },
                    suffix: tier,
                    metadata : {active : active}
                };
            },
            RecentShowroomEDI : function(paCode,searchFilters,returnURL,pageName,pageNameNoVehicle,vehicle){
                return {
                    'RecentShowroomEDI': {
                        _paCode : paCode,
                        _searchFilters  : searchFilters,
                        returnURL : returnURL,
                        pageName : pageName,
                        pageNameNoVehicle : pageNameNoVehicle,
                        vehicle : vehicle
                    }
                };
            },
            ShowroomResultsEDI : function(returnURL, searchCriteria, firstVehicle, currentDealerEDI) {
                if(firstVehicle.APP_ID !== undefined){
                    firstVehicle.appID = firstVehicle.APP_ID;
                    delete firstVehicle.APP_ID;
                }
                return {
                    'ShowroomResultsEDI': {
                        returnURL: returnURL,
                        searchCriteria: searchCriteria,
                        firstVehicle: firstVehicle,
                        currentDealerEDI: currentDealerEDI
                    }
                };
            },
            SpecificVehicleView: function (UID, appID, PAcode, ZIP, year, brand, nameplate, trim, action, returnURL, options) {
                FPS.OI.Vehicle.set(year, brand, nameplate, trim, FPS.getScore(action) );
                FPS.pageLoadTracker.trackPage();
                // setTimeout(FPS.NME.Check, 500);

                var displayName = options && typeof options.displayName === "string" ? options.displayName : "";

                return {
                    'SpecificVehicleView': {
                        _UID: UID,
                        _appID: appID,
                        _PAcode: PAcode,
                        _ZIP: ZIP,
                        _year: year,
                        _brand: brand,
                        _nameplate: nameplate,
                        _trim: trim,
                        returnURL: returnURL,
                        displayName: displayName
                    },
                    suffix: action.name,
                    metadata: { score: FPS.getScore(action) }
                }
            },
            // T2
            ActionNameplateT2: function (year, brand, nameplate, returnURL, action) {
                FPS.OI.Vehicle.set(year, brand, nameplate, '', FPS.getScore(action) );
                return {
                    'ActionNameplateT2': {
                        _year: year,
                        _brand: brand,
                        _nameplate: nameplate,
                        returnURL: returnURL
                    },
                    suffix: action.name,
                    metadata: { score: FPS.getScore(action) }
                };
            },
            // T3
            ActionNameplateT3: function (year, brand, nameplate, PAcode, action) {
                nameplate = FPS.nValue('nameplateT3', nameplate);
                FPS.OI.Vehicle.set(year, brand, nameplate, '', FPS.getScore(action) );
                return {
                    'ActionNameplateT3': {
                        _year: year,
                        _brand: brand,
                        _nameplate: nameplate,
                        _paCode: PAcode
                    },
                    suffix: action.name,
                    metadata: { score: FPS.getScore(action) }
                };
            },
            ActionTrimT3: function (year, brand, nameplate, trim, returnURL, PAcode, action) {
                nameplate = FPS.nValue('nameplateT3', nameplate);
                FPS.OI.Vehicle.set(year, brand, nameplate, trim, FPS.getScore(action) );
                return {
                    'ActionTrimT3': {
                        _year: year,
                        _brand: brand,
                        _nameplate: nameplate,
                        _trim: trim,
                        _paCode: PAcode,
                        returnURL: returnURL
                    },
                    suffix: action.name,
                    metadata: { score: FPS.getScore(action) }
                };
            },
            SpecificVehicleViewT3: function (UID, appID, PAcode, ZIP, year, brand, nameplate, trim, returnURL, action) {
                nameplate = FPS.nValue('nameplateT3', nameplate);
                FPS.OI.Vehicle.set(year, brand, nameplate, trim, FPS.getScore(action) );
                return {
                    'SpecificVehicleViewT3': {
                        _UID: UID,
                        _appID: appID,
                        _PAcode: PAcode,
                        _ZIP: ZIP,
                        _year: year,
                        _brand: brand,
                        _nameplate: nameplate,
                        _trim: trim,
                        returnURL: returnURL
                    },
                    suffix: action.name,
                    metadata: { score: FPS.getScore(action) }
                };
            },
            OINameplate: function( year, brand, nameplate, score) {
                return {
                    'OINameplate': {
                        _year: year,
                        _brand: brand,
                        _nameplate: nameplate,
                        returnURL: '',
                    },
                    metadata: { score: score }
                };
            },
            T1OINameplate: function( year, brand, nameplate, score) {
                return {
                    'T1OINameplate': {
                        _year: year,
                        _brand: brand,
                        _nameplate: nameplate,
                        returnURL: '',
                    },
                    metadata: { score: score }
                };
            },
            T2OINameplate: function( year, brand, nameplate, score) {
                return {
                    'T2OINameplate': {
                        _year: year,
                        _brand: brand,
                        _nameplate: nameplate,
                        returnURL: '',
                    },
                    metadata: { score: score }
                };
            },
            TNOINameplate: function( year, brand, nameplate, score) {
                return {
                    'TNOINameplate': {
                        _year: year,
                        _brand: brand,
                        _nameplate: nameplate,
                        returnURL: '',
                    },
                    metadata: { score: score }
                };
            },
            OITrim: function (year, brand, nameplate, trim, score) {
                return {
                    'OITrim': {
                        _year: year,
                        _brand: brand,
                        _nameplate: nameplate,
                        _trim: trim,
                        returnURL: '',
                    },
                    metadata: { score: score }
                };
            },
            T1OITrim: function (year, brand, nameplate, trim, score) {
                return {
                    'T1OITrim': {
                        _year: year,
                        _brand: brand,
                        _nameplate: nameplate,
                        _trim: trim,
                        returnURL: '',
                    },
                    metadata: { score: score }
                };
            },
            T2OITrim: function (year, brand, nameplate, trim, score) {
                return {
                    'T2OITrim': {
                        _year: year,
                        _brand: brand,
                        _nameplate: nameplate,
                        _trim: trim,
                        returnURL: '',
                    },
                    metadata: { score: score }
                };
            },
            TNOITrim: function (year, brand, nameplate, trim, score) {
                return {
                    'TNOITrim': {
                        _year: year,
                        _brand: brand,
                        _nameplate: nameplate,
                        _trim: trim,
                        returnURL: '',
                    },
                    metadata: { score: score }
                };
            }
            , v1OINameplate: function( year, brand, nameplate, score) {
                return {
                    'v1OINameplate': {
                        _year: year,
                        _brand: brand,
                        _nameplate: nameplate,
                        returnURL: '',
                    },
                    metadata: { score: score || 0 }
                };
            }
            , v1OITrim: function (year, brand, nameplate, trim, score) {
                return {
                    'v1OITrim': {
                        _year: year,
                        _brand: brand,
                        _nameplate: nameplate,
                        _trim: trim,
                        returnURL: '',
                    },
                    metadata: { score: score || 0 }
                };
            }
        }});DeepMerge( window.FPS, {reserved: {
            VOIAggregateNameplate: { reservedKey: 'VOIAggregateNameplate', trueKey: 'OINameplate', params: { query: 'Score', max: 5 } },
            T1VOIAggregateNameplate: { reservedKey: 'T1VOIAggregateNameplate', trueKey: 'T1OINameplate', params: { query: 'Score', max: 5 } },
            T2VOIAggregateNameplate: { reservedKey: 'T2VOIAggregateNameplate', trueKey: 'T2OINameplate', params: { query: 'Score', max: 5 } },
            TNVOIAggregateNameplate: { reservedKey: 'TNVOIAggregateNameplate', trueKey: 'TNOINameplate', params: { query: 'Score', max: 5 } },
            VOIAggregateTrim: { reservedKey: 'VOIAggregateTrim', trueKey: 'OITrim', params: { query: 'Score', max: 5 } },
            T1VOIAggregateTrim: { reservedKey: 'T1VOIAggregateTrim', trueKey: 'T1OITrim', params: { query: 'Score', max: 5 } },
            T2VOIAggregateTrim: { reservedKey: 'T2VOIAggregateTrim', trueKey: 'T2OITrim', params: { query: 'Score', max: 5 } },
            TNVOIAggregateTrim: { reservedKey: 'TNVOIAggregateTrim', trueKey: 'TNOITrim', params: { query: 'Score', max: 5 } }
        }});
    DeepMerge( window.FPS, {Blacklist: {
            keys: {
                CCPA:true,
                AnonymousRef:true,
                SavedItems_Vehicle:true,
                SavedItems_Video:true,
                OINameplate:true,
                T1OINameplate:true,
                T2OINameplate:true,
                TNOINameplate:true,
                OITrim:true,
                T1OITrim:true,
                T2OITrim:true,
                TNOITrim:true,
                NotifyMeActivity: true,
                PreferredDealer: true,
                FPSTierDrop: true,
                TierDropTN: true,
                Status: true,
                PowertrainOfInterest: true,
                Propensity: true,
                NVCWishlist: true,
                NVCPreference: true,
            }
            , locale: {
                en_us:true
                , en_ca:true
                , es_us: true
                , sp_us: true
            }
        }});DeepMerge( window.FPS, {CCPA: {
            Utils:{
                extractDomainName: function(hostname){
                    if(typeof hostname !== "string") return "";
                    return hostname.split(".").slice(-2).join('.');
                }
            }
            , DNS: function DNS(options) {
                if (personalizationActive && uid) {

                    var doNotSet = options && options.doNotSet || false;

                    if (typeof setExRefHasUpdatedCookie !== "undefined" && setExRefHasUpdatedCookie === false) {

                        var newFPSId = UUIDV4();
                        var oldFPSId = uid;

                        uid = newFPSId;

                        try {
                            ajaxData.uid = uid;
                        } catch (err) {
                            console.log(err);
                        }

                        cookie.set('gt_uid', uid, new Date(now.getTime() + (cookieDaysToLive * 86400000)), "/", cookie.domain);

                        if (xdcDomain.length === 0) {
                            cookie.set('gt_dns', oldFPSId, new Date(now.getTime() + (cookieDaysToLive * 86400000)), "/", cookie.domain);
                        } else {
                            cookie.set('gt_dns', true, new Date(now.getTime() + (cookieDaysToLive * 86400000)), "/", cookie.domain);
                            if(blockNetworkRequestsDomain) blockNetworkRequests = true;
                        }

                    } else if (xdcDomain.length === 0) {
                        cookie.set('gt_dns', UUIDV4(), new Date(now.getTime() + (cookieDaysToLive * 86400000)), "/", cookie.domain);
                    } else {
                        cookie.set('gt_dns', true, new Date(now.getTime() + (cookieDaysToLive * 86400000)), "/", cookie.domain);
                        if(blockNetworkRequestsDomain) blockNetworkRequests = true;
                    }

                    if (doNotSet === false) {
                        FPS.set({
                            CCPA: {_site: this.Utils.extractDomainName(window.location.hostname)},
                            suffix: "DNS"
                        }, {
                            success: function () {
                            }, error: function () {
                            }
                        });
                    }

                    return true;
                }

                return false;
            }
            , RDNS: function RDNS(hostname) {
                if (personalizationActive && uid && typeof hostname === "string" && hostname.length > 0) {

                    if (typeof this.DNS === "function") {

                        this.DNS();

                        FPS.set({
                            CCPA: {_site: this.Utils.extractDomainName(hostname)},
                            suffix: "DNS"
                        }, {
                            success: function (e) {
                                console.log(e)
                            }, error: function (e) {
                                console.log(e)
                            }
                        });

                    }

                }
            }
        }});DeepMerge( window.FPS, {Cache: {
            set:{
                FPICookie: (1000 * 60 * 60),
                AnonymousRef: (1000 * 60 * 60),
                pageLoadTracking: (1000 * 60 * 2)
            }
        }});DeepMerge( window.FPS, {lib:{
            CurrentDealer: function (args) {
                return {
                    'CurrentDealer': {
                        DealerID: args.DealerID,
                        PACode: args.PACode,
                        CommonID: args.CommonID,
                    }
                };
            }
        }});DeepMerge( window.FPS, {Core: {
            Insights: {
                Config: {
                    Const: {
                        TRACK_DOMAIN_SINGLE_DOMAIN: false
                    },
                    trackDomain: function () {
                        return true;
                    },
                    triggerOnLoad: function () {
                        return ['t1','t2','tn'];
                    }
                },
                Utils: {
                    send: function (entries, options) {
                        options = options || {};
                        var action = options.action || "OnLoad";
                        var type = options.type || "Domain";
                        var baseUrl = window.location.protocol + "//" + window.location.hostname;

                        new Request({
                            method: "POST"
                            , url: xdcPathSet + apiPaths.set
                            , headers: {
                                "Content-Type": "application/json; charset=UTF-8"
                            }
                            , body: JSON.stringify({
                                uid: "8804e3c7-2605-4ca1-bfb5-99c949d18fb6",
                                tagBrand: tagBrand + "-Insights-" + action + "-" + type + "-" + this.getTier(baseUrl),
                                tagCountry: tagCountry,
                                referrer: "",
                                entries: entries,
                                url: document.location.href,
                                testMode: false
                            })
                            , timeout: 5000
                        })
                          .then(function(){
                              if (typeof options.success === "function") {
                                  options.success.apply(null, arguments);
                              }
                          })
                          .catch(function(){
                              if (typeof options.error === "function") {
                                  options.error.apply(null, arguments);
                              }
                          })
                    }
                    , rowKeyTimestamp: function (date) {
                        if(!date) return "--";
                        var year = date.getFullYear();
                        var month = date.getMonth() + 1;
                        var day = date.getDate();
                        var insightsMonth = month > 9 ? month : "0" + month;
                        var instghtsDay = day > 9 ? day : "0" + day;
                        return year + "-" + insightsMonth + "-" + instghtsDay;

                    }
                    , getTier: function (baseUrl) {
                        if (checkT1(baseUrl)) {
                            return "t1";
                        }

                        if (checkT2(baseUrl)) {
                            return "t2";
                        }

                        return "tn";
                    }
                }
                , trackDomain: function (options) {
                    options = options || {};
                    var yearMonthDay = options.timestamp || this.Utils.rowKeyTimestamp(new Date());
                    var hostname = options.hostname;
                    var keyDomain = "domain_" + yearMonthDay;

                    if (this.Config.trackDomain() === this.Config.Const.TRACK_DOMAIN_SINGLE_DOMAIN) {
                        var td = Encode(cookie.get("gt_td"));
                        if (td) return [];
                        var expires = new Date(now.getTime() + (cookieDaysToLive * 86400000));
                        document.cookie = "gt_td=true; Expires=" + expires + "; Domain=" + hostname + "; Path=/; Secure; SameSite=Strict";
                    }

                    return [{
                        key: keyDomain,
                        value: JSON.stringify({"_domain": hostname})
                    }];
                }
                , trackSNS: function (options) {
                    options = options || {};
                    var yearMonthDay = options.timestamp || this.Utils.rowKeyTimestamp(new Date());
                    var hostname = options.hostname;
                    var keyDomain = "sns";

                    return [{
                        key: keyDomain,
                        value: JSON.stringify({"_domain": hostname})
                    }];
                }
                , trackVOIModel: function (options) {
                    options = options || {};
                    var voiModelCookieValue = cookie.get("gt_voim");
                    var voiModel = cookie.get("FPS_Target_VOI_Model");
                    var voiModelReplaced = "";
                    var yearMonthDay = options.timestamp || this.Utils.rowKeyTimestamp(new Date());
                    var trackVOIModel = false;

                    voiModel = voiModel ? decodeURIComponent(voiModel) : null;
                    voiModelCookieValue = voiModelCookieValue ? decodeURIComponent(voiModelCookieValue) : null;

                    voiModelReplaced = typeof voiModel === "string" ? voiModel.replace(/,?"score":[0-9]{1,},?/gi, "") : "";

                    trackVOIModel = voiModel && (voiModelCookieValue !== voiModelReplaced);

                    if (trackVOIModel) {
                        try {
                            voiModelCookieValue = voiModelReplaced;
                            cookie.set('gt_voim', voiModelCookieValue, new Date(now.getTime() + (cookieDaysToLive * 86400000)), '/', cookie.domain);
                            try {
                                voiModelCookieValue = JSON.parse(decodeURIComponent(voiModelCookieValue));
                            }catch(err){
                                return [];
                            }

                            return [{
                                key: "voi-model_" + yearMonthDay
                                , value: JSON.stringify({
                                    _make: voiModelCookieValue.make
                                    , _model: voiModelCookieValue.model
                                    , score: voiModelCookieValue.score
                                    , _year: voiModelCookieValue.year
                                })
                            }];

                        } catch (err) {
                        }
                    }

                    return [];

                }
                , trackVOITrim: function (options) {
                    options = options || {};
                    var voiTrimCookieValue = cookie.get("gt_voit");
                    var voiTrim = cookie.get("FPS_Target_VOI_Trim");
                    var voiTrimReplaced = "";
                    var yearMonthDay = options.timestamp || this.Utils.rowKeyTimestamp(new Date());
                    var trackVOITrim = false;

                    voiTrimCookieValue = voiTrimCookieValue ? decodeURIComponent(voiTrimCookieValue) : null;
                    voiTrim = voiTrim ? decodeURIComponent(voiTrim) : null;

                    voiTrimReplaced = typeof voiTrim === "string" ? voiTrim.replace(/,?"score":[0-9]{1,},?/gi, "") : "";

                    trackVOITrim = voiTrim && (voiTrimCookieValue !== voiTrimReplaced);

                    if (trackVOITrim) {
                        try {
                            voiTrimCookieValue = voiTrimReplaced;
                            cookie.set('gt_voit', voiTrimCookieValue, new Date(now.getTime() + (cookieDaysToLive * 86400000)), '/', cookie.domain);
                            try {
                                voiTrimCookieValue = JSON.parse(decodeURIComponent(voiTrimCookieValue));
                            }catch(err){
                                return [];
                            }
                            return [{
                                key: "voi-trim_" + yearMonthDay
                                , value: JSON.stringify({
                                    _make: voiTrimCookieValue.make
                                    , _model: voiTrimCookieValue.model
                                    , score: voiTrimCookieValue.score
                                    , _trim: voiTrimCookieValue.trim
                                    , _year: voiTrimCookieValue.year
                                })
                            }];

                        } catch (err) {
                            console.log(err)
                        }

                    }

                    return [];

                }
                , onPageLoad: function (options) {
                    options = options || {};
                    var baseUrl = options.baseUrl || "";
                    var allowedTier = this.Config.triggerOnLoad().indexOf(this.Utils.getTier(baseUrl)) !== -1;

                    if (!allowedTier) {
                        return false;
                    }

                    var domainEntries = [].concat(this.trackDomain({
                        hostname: window.location.hostname
                    }));
                    var voiModelEntries = [].concat(this.trackVOIModel());
                    var voiTrimEntries = [];//.concat(this.trackVOITrim());

                    if (domainEntries.length > 0) {
                        this.Utils.send(domainEntries, {
                            action: "OnLoad"
                            , type: "Domain"
                        });
                    }

                    if (voiModelEntries.length > 0) {
                        this.Utils.send(voiModelEntries, {
                            action: "OnLoad"
                            , type: "Voi-Model"
                        });
                    }

                    if (voiTrimEntries.length > 0) {
                        this.Utils.send(voiTrimEntries, {
                            action: "OnLoad"
                            , type: "Voi-Trim"
                        });
                    }

                    if(window.FPS.steps){
                        var snsEntries = [].concat(this.trackSNS({
                            hostname: window.location.hostname+window.location.pathname
                        }));

                        this.Utils.send(snsEntries,{
                            action:"OnLoad"
                            , type: "SNS-Loaded"
                        })
                    }

                    return true;

                }
                , onVOIModelUpdate: function (options) {
                    options = options || {};

                    this.Utils.send(this.trackVOIModel(), options);
                }
                , onVOITrimUpdate: function (options) {
                    options = options || {};

                    this.Utils.send(this.trackVOITrim(), options);
                }
            }
        }});DeepMerge( window.FPS, {ManualXDC: function () {
            var manualXDC = FPS.Utils.getQueryStringParam("gtuid")
            if (manualXDC && xdcGTUID === '') {
                cookie.set("gt_uid", manualXDC, new Date(now.getTime() + (cookieDaysToLive * 86400000)), '/', cookie.domain);
                uid = manualXDC;
                ajaxData.uid = manualXDC;

            }
        }});DeepMerge( window.FPS, {CurrentDealerEDI: function() {
            try {
                var dealer = JSON.parse(localStorage.getItem("dealer"));
                if (dealer && dealer["code"]) {
                    return dealer["code"].split("|")[1] ? dealer["code"].split("|")[1] : null;
                } else {
                    return null;
                }
            } catch (err) {
                return null;
            }
        },
        RecentNameplateShowroomEDI: function(nameplate, callbacks) {
            FPS.get([{
                RecentShowroomEDI: {}
            }], {
                success: function(data, statusText, jqXHR) {
                    if (data && data.length > 0 && data[0]['RecentShowroomEDI'] && Array.isArray(data[0]['RecentShowroomEDI'])) {
                        data[0]['RecentShowroomEDI'] = data[0]['RecentShowroomEDI'].filter(x => x.vehicle.nameplate === nameplate);
                        callbacks.success(data, statusText, jqXHR);
                    }
                },
                error: function(jqXHR, statusText, error) {
                    callbacks.success(jqXHR, statusText, error);
                }
            });
        }});DeepMerge( window.FPS, {lib: {
            SavedVideoNameplate: function (options) {
                var options = options || {};
                var SetObj = {
                    'SavedVideoNameplate': {
                        _videoID: options.videoID
                        , _context: options.context
                        , tag: options.tag
                        , year: options.year
                        , brand: options.brand
                        , nameplate: options.nameplate
                        , trim: options.trim
                        , returnURL: options.returnURL
                    }
                    , suffix: "nvo"
                };

                if (options.active === false) {
                    SetObj.metadata = {active: false};
                }
                return SetObj;
            },
            ViewedVideoNameplate: function (options) {
                var options = options || {};
                var SetObj = {
                    'ViewedVideoNameplate': {
                        _videoID: options.videoID
                        , _context: options.context
                        , tag: options.tag
                        , viewstatus: options.viewstatus
                        , year: options.year
                        , brand: options.brand
                        , nameplate: options.nameplate
                        , trim: options.trim
                        , returnURL: options.returnURL
                    }
                    , suffix: "nvo"
                };
                if (options.active === false) {
                    SetObj.metadata = {active: false};
                }
                return SetObj;
            }
        }});DeepMerge( window.FPS, {nValue: function (type, nameplate) {
            if (type === "nameplateT3") {
                return nameplate.replace(new RegExp("^" + tagBrand + " +", "i"), "");
            }

            return nameplate;

        }});DeepMerge( window.FPS, {Notifications: {
            getAll: function(callbacks){
                callbacks = {
                    success: callbacks && callbacks.success || function(){}
                    , error: callbacks && callbacks.error || function(){}
                };

                var returnedData = {
                    SavedVehicleCount: {
                        total: 0
                        , SavedBPConfig: 0
                        , SavedInventoryVehicle: 0
                    }
                };

                FPS.get([{SavedBPConfig:{}},{SavedInventoryVehicle:{}}]
                  ,{
                      success: function(data){
                          data = data || returnedData;
                          if(Array.isArray(data)){
                              data = data.reduce(function(accum,current){ // || current["SavedInventoryVehicle"] || undefined
                                  var key = current["SavedBPConfig"] ? "SavedBPConfig"
                                    : current["SavedInventoryVehicle"] ? "SavedInventoryVehicle"
                                      : undefined;
                                  if(key){
                                      accum["SavedVehicleCount"][key] = current[key].length || 0;
                                      accum["SavedVehicleCount"].total += accum["SavedVehicleCount"][key];
                                  }
                                  return accum;
                              },returnedData);
                          }
                          callbacks.success(data);
                      }
                      , error: function(){
                          callbacks.error(returnedData);
                      }
                  }
                );
            }
        }});DeepMerge( window.FPS, {lib: {
            NotifyMeActivity: function(nameplate, update) {
                return {
                    'NotifyMeActivity': {
                        "_nameplate": nameplate,
                        "status": update,
                        "lastupdate": Date()
                    },
                };
            }
        },
        NME: {
            ClearNMEA: function() {},
            Check: function() {}
        }});DeepMerge( window.FPS, {OI: {
            Vehicle: {
                set: function (year, brand, nameplate, trim, score, options) {
                    options = options || {};
                    var v1Score = options.v1Score || 0;
                    var tier;
                    try{
                        tier = FPS.Core.Insights.Utils.getTier("https://" + window.location.hostname);
                        tier = tier.toUpperCase();
                    }catch(err){

                    }
                    if (score > 0) {
                        if (trim === '' || typeof trim === 'undefined' || !trim) {
                            FPS.set([
                                FPS.lib.OINameplate(year, brand, nameplate, score)
                            ]);
                            if(tier){
                                FPS.set([
                                    FPS.lib[tier + "OINameplate"](year, brand, nameplate, score)
                                ]);
                            }
                        } else {

                            let powerTrains = [];
                            try{
                                powerTrains = FPS.OI.Powertrain.getSegments(year, nameplate, trim);
                            }catch(err){

                            }

                            FPS.set([
                                FPS.lib.OITrim(year, brand, nameplate, trim, score)
                                , FPS.lib.OINameplate(year, brand, nameplate, score),
                                ...powerTrains
                            ]);
                            if(tier){
                                FPS.set([
                                    FPS.lib[tier + "OINameplate"](year, brand, nameplate, score)
                                    , FPS.lib[tier + "OITrim"](year, brand, nameplate, trim, score),
                                    ...powerTrains
                                ]);
                            }
                        }
                    }
                },
                get: function (callbacks) {
                    callbacks = {
                        success: callbacks && callbacks.success || function(){}
                        , error: callbacks && callbacks.error || function(){}
                    }
                    FPS.get([{ OINameplate: { query: 'Score', max: 1 } }, { OITrim: { query: 'Score', max: 1 } }], { success: callbacks.success, error: callbacks.error });
                }
            },
            Powertrain:{
                getSegments: function(year = "", nameplate = "", trim = ""){
                    const matches = [];

                    try {
                        const healNameplate = FPS.Validation.healNameplate(vdmActiveNameplates, vdmActiveNameplatesMap);
                        nameplate = healNameplate(nameplate,{year});

                        const trimIndex = vdmActiveNameplates?.[nameplate]?.[year].findIndex((t)=>{
                            if(t === trim){
                                return true;
                            }

                            if( t === trim.replace(/[^a-z0-9]/gmi, "").toLowerCase() ){
                                return true;
                            }

                            if( t === trim.replace(/[^a-z0-9_]/gmi, "").toLowerCase() ){
                                return true;
                            }

                            if( t === trim.replace(/[^a-z0-9 ]/gmi, "").toLowerCase() ){
                                return true;
                            }

                            if( t === trim.replace(/[^a-z0-9-]/gmi, "").toLowerCase() ){
                                return true;
                            }

                            if( t === trim.replace(/[^a-z0-9_ -]/gmi, "").toLowerCase() ){
                                return true;
                            }
                        });

                        let powerTrainValue = (typeof trimIndex === "number" && trimIndex > -1) ? vdmActiveNameplates?.[nameplate]?.[`Powers_${year}`]?.[trimIndex] : null;

                        const _nameplate = nameplate.replace(/[^a-z0-9]/gmi, "").toLowerCase();
                        if(_nameplate === "mache" || _nameplate === "etransit" || _nameplate === "f150lightning") {
                            powerTrainValue = "electric";
                        }

                        if (typeof powerTrainValue === "string") {

                            if (powerTrainValue.includes("electric")) {
                                matches.push({
                                    "PowertrainOfInterest": {
                                        _powertrain: "electric"
                                    }
                                });
                            }

                            if (powerTrainValue.includes("phev") || powerTrainValue.includes("hybrid") || powerTrainValue.includes("plugin")) {
                                matches.push({
                                    "PowertrainOfInterest": {
                                        _powertrain: "hybrid"
                                    }
                                });
                            }

                            if (powerTrainValue === "" || powerTrainValue.includes("gas") || powerTrainValue.includes("eco")) {
                                matches.push({
                                    "PowertrainOfInterest": {
                                        _powertrain: "ice"
                                    }
                                });
                            }
                        }

                    }catch(err){

                    }

                    return matches;
                }
            }
        }
    });DeepMerge( window.FPS, {    Queue: {
            CheckForDuplicateEntries: function (currentKeys, keyValueObjects) {
                var foundDuplicate = false;

                for (var i = 0; i < keyValueObjects.length; i++) {
                    var el = keyValueObjects[i];
                    var reservedKey = el['reservedKey'];
                    var key = el['key'];

                    if (!currentKeys[(reservedKey || key)]) {
                        currentKeys[(reservedKey || key)] = true;
                    } else if (currentKeys[key]) {
                        foundDuplicate = true;
                        break;
                    }
                }

                return foundDuplicate;
            }
            , ConvertGetRequestsGetEntriesAndResolvers: function(requests){
                return requests.list.reduce(function (accum, current) {
                    accum.entries = accum.entries.concat(current.entries);
                    current.entries.forEach(function (entry) {
                        if (!accum.uniqueKeys[entry["reservedKey"] || entry["key"]]) {
                            accum.uniqueEntries.push(entry);
                        }
                        accum.uniqueKeys[entry["reservedKey"] || entry["key"]] = entry;
                    });
                    accum.resolvers = accum.resolvers.concat(function (err, success) {
                        if (err) {
                            current.resolver(err);
                            return;
                        }

                        var resp = success[0];
                        var result = current.entries.reduce(function (accum, current) {
                            var Key = current["reservedKey"] || current["key"];
                            var match = resp.reduce(function (accum, current) {
                                return Key === current.Key ? current : accum;
                            }, {
                                Key: Key,
                                Value: []
                            });
                            accum = accum.concat(match);
                            return accum;
                        }, []);

                        result = filterFPSGetVdmNameplateTrim(result);

                        current.resolver(null, [result, success[1], success[2]]);
                    });
                    return accum;
                }, {
                    entries: [],
                    resolvers: [],
                    uniqueKeys: {},
                    uniqueEntries: []
                });
            }
            , GetQueue: function () {
                var getRequests = this.Utils.RequestList();
                getRequests.on(this.GetQueueHandler.bind(this));
                core.get = this.CoreGetOverride();
            }
            , GetQueueHandler: function (requests) {
                if (!(requests && requests.list && Array.isArray(requests.list) && requests.list.length > 0)) {
                    return false;
                }
                var _timeout = requests.list[0]._timeout || 3000;
                var asBrand = requests.list[0].asBrand || tagBrand;
                var asCountry = requests.list[0].asCountry || tagCountry;
                var result = this.ConvertGetRequestsGetEntriesAndResolvers(requests);
                var entries = stringifyEach(result.uniqueEntries);
                this.GetQueueResponse(entries, result.resolvers, asBrand, asCountry, _timeout)
            }
            , GetQueueResponse: function (entries, resolvers, asBrand, asCountry, _timeout) {
                var config = ShallowMerge(ajaxConfig, {
                    url: xdcPathGet + apiPaths.get + uid,
                    timeout: typeof _timeout === "number" ? _timeout : 3000
                });
                config.data = JSON.stringify(ShallowMerge(ajaxData, {
                    entries: entries,
                    tagBrand: asBrand || tagBrand,
                    tagCountry: asCountry || tagCountry,
                    testMode: core.config.testMode
                }));
                new Request({
                    method: "POST"
                    , url: config.url
                    , headers: {
                        "Content-Type": "application/json; charset=UTF-8"
                    }
                    , body: config.data
                    , timeout: config.timeout
                })
                  .then(function () {
                      var args = arguments[0];
                      resolvers.forEach(function (resolver) {
                          resolver(null,args);
                      });
                  })
                  .catch(function () {
                      var args = arguments[0];
                      resolvers.forEach(function (resolver) {
                          resolver(args);
                      });
                  })
            }
            , CoreGetOverride: function(){
                var getRequests = this.Utils.RequestList();
                getRequests.on(this.GetQueueHandler.bind(this));

                var getTimeoutId;
                var originalGet = core.get;
                var currentKeys = {};
                var Queue = this;

                return function CoreGetOverride(keyValueObjects, _timeout, asBrand, asCountry){
                    var foundDuplicate = Queue.CheckForDuplicateEntries(currentKeys, keyValueObjects);

                    if (foundDuplicate && !blockNetworkRequests) {
                        currentKeys = {};
                        foundDuplicate = false;
                        return originalGet.apply(null, arguments);
                    }

                    return new Promise(function (resolve, reject) {
                        getRequests.add({
                            resolver: function (err, success) {
                                if (err) {
                                    reject(err);
                                    return;
                                }
                                resolve(success);
                            },
                            entries: keyValueObjects,
                            _timeout: _timeout,
                            asBrand: asBrand,
                            asCountry: asCountry
                        });

                        if (!getTimeoutId) {
                            getTimeoutId = setTimeout(function (getRequests) {
                                getTimeoutId = null;
                                getRequests.process();
                            }, 500, getRequests);
                        }
                    });
                }
            }
        }});DeepMerge( window.FPS, {Queue: {
            ConvertRequestsToEntriesAndResolvers: function(requests){
                return requests.list.reduce(function (accum, current) {
                    accum.entries = accum.entries.concat(current.entries);
                    accum.resolvers = accum.resolvers.concat(current.resolver);
                    return accum;
                }, {entries: [], resolvers: []});
            }
            , SetQueue: function () {
                var setRequests = this.Utils.RequestList();
                setRequests.on(this.SetQueueHandler.bind(this));

                var setTimeoutId;

                core.set = function (entries, _timeout) {
                    return new Promise(function (resolve, reject) {
                        setRequests.add({
                            resolver: {resolve: resolve, reject: reject},
                            entries: entries,
                            _timeout: _timeout
                        });
                        if (!setTimeoutId) {
                            setTimeoutId = setTimeout(function (setRequests) {
                                setTimeoutId = null;
                                setRequests.process();
                                clearTimeout(setTimeoutId);
                            }, 500, setRequests);
                        }
                    });
                }
            }
            , SetQueueHandler: function (requests, msg) {
                if (requests && requests.list && Array.isArray(requests.list)) {
                    var getUniqueEntries = this.Utils.getUniqueEntries;
                    var result = this.ConvertRequestsToEntriesAndResolvers(requests);
                    var entries = getUniqueEntries(result.entries);
                    var resolvers = result.resolvers;

                    this.SetQueueResponse(entries, resolvers);
                }

            }
            , SetQueueResponse: function (entries, resolvers) {
                var config = ShallowMerge(ajaxConfig, {
                    url: xdcPathSet + apiPaths.set,
                    timeout: 5000
                });
                config.data = JSON.stringify(ShallowMerge(ajaxData, {
                    entries: entries,
                    url: encodeURL(document.location.href),
                    testMode: core.config.testMode
                }));
                new Request({
                    method: "POST"
                    , url: config.url
                    , headers: {
                        "Content-Type": "application/json; charset=UTF-8"
                    }
                    , body: config.data
                    , timeout: config.timeout
                }).then(function () {
                    var args = arguments;
                    resolvers.forEach(function (el) {
                        el.resolve.apply(null, args);
                    });
                })
                  .catch(function () {
                      var args = arguments;
                      resolvers.forEach(function (el) {
                          el.reject.apply(null, args);
                      });
                  })
            }
        }});DeepMerge( window.FPS, {Queue: {
            Utils: {
                RequestList: function () {
                    function RequestList(_ref) {
                        var List = _ref.List,
                          Emitter = _ref.Emitter;
                        var emitter = Emitter();
                        var requests = List();
                        var RequestList = {
                            add: function add(request) {
                                requests.add(request);
                            },
                            off: function off(handler) {
                                emitter.remove(handler);
                            },
                            on: function on(handler) {
                                emitter.add(handler);
                            },
                            reset: function reset() {
                                emitter.clear();
                                requests.clear();
                            },
                            process: function process() {
                                emitter.trigger(requests);
                                requests.clear();
                            }
                        };
                        addGetter(RequestList, "requests", function () {
                            return requests;
                        });
                        addGetter(RequestList, "handlers", function () {
                            return emitter;
                        });
                        return RequestList;
                    }

                    return RequestList({List: List, Emitter: Emitter});
                },
                getUniqueEntries: function (entries) {

                    entries = Array.isArray(entries) ? entries : [];

                    if (entries.length <= 1) {
                        return entries;
                    }
                    return entries.reduce(function (accum, current, index, list) {

                        try {

                            var _current = JSON.stringify(current);
                            if (accum.test.indexOf(_current) === -1) {
                                accum.test.push(_current);
                                accum.entries.push(current);
                            }

                        } catch (err) {
                            accum.entries.push(current);
                        }

                        return accum;
                    }, {entries: [], test: []}).entries;
                }
            }
        }});DeepMerge( window.FPS, {reserved: {
            RVVNameplate: {
                reservedKey: 'RVVNameplate',
                trueKey: 'ActionNameplate',
                params: {
                    query: 'LatestFromGroups:p*',
                    max: 3,
                    suffixFilter: ['ViewPage', 'BPModelSelect', 'RequestQuickQuote']
                }
            },
            RVVTrim: {
                reservedKey: 'RVVTrim',
                trueKey: 'ActionTrim',
                params: {
                    query: 'LatestFromGroups:p*',
                    max: 3,
                    suffixFilter: ['ViewModelDetail', 'ViewPage', 'SearchInventory']
                }
            },
            RVVVehicleTrim: {
                reservedKey: 'RVVVehicleTrim',
                trueKey: 'ActionTrim',
                params: {
                    query: 'LatestFromGroups:p*',
                    max: 3,
                    suffixFilter: ['ViewModelDetail', 'ViewModelDetailBlackLabel']
                }
            },
            RVVVehicleNameplate: {
                reservedKey: 'RVVVehicleNameplate',
                trueKey: 'ActionNameplate',
                params: {
                    query: 'LatestFromGroups:p*',
                    max: 3,
                    suffixFilter: ['ViewPage', 'ViewPageBlackLabel']
                }
            },
            RVVIONameplate: {
                reservedKey: 'RVVIONameplate',
                trueKey: 'ActionNameplate',
                params: {
                    query: 'LatestFromGroups:p*',
                    max: 3,
                    suffixFilter: ['IOFeatured', 'IOModelOffers', 'IOAdditonalOffer']
                }
            },
            RVVSINGNameplate: {
                reservedKey: 'RVVSINGNameplate',
                trueKey: 'ActionNameplate',
                params: {
                    query: 'LatestFromGroups:p*',
                    max: 3,
                    suffixFilter: ['SIResults']
                }
            },
            RVVSINGSpecificVehicle: {
                reservedKey: 'RVVSINGSpecificVehicle',
                trueKey: 'SpecificVehicleView',
                params: {
                    query: 'LatestFromGroups:p*',
                    max: 3,
                    suffixFilter: ['SVVSI','SVVSEVOVIN']
                }
            },
            RVVBPNameplate: {
                reservedKey: 'RVVBPNameplate',
                trueKey: 'ActionNameplate',
                params: {
                    query: 'LatestFromGroups:p*',
                    max: 3,
                    suffixFilter: ['BPModelSelect','ViewPageEcom']
                }
            },
            RVVBPSpecificVehicle: {
                reservedKey: 'RVVBPSpecificVehicle',
                trueKey: 'SpecificVehicleView',
                params: {
                    query: 'LatestFromGroups:p*',
                    max: 3,
                    suffixFilter: ['SVVBP','SVVConfigInProgressFBC','SVVConfigCompleteFBC'] // ,'SVVStartResvEcom','SVVConfigInProgressEcom','SVVConfigCompleteEcom'
                }
            },
            RVVVEHNameplate: {
                reservedKey: 'RVVVEHNameplate',
                trueKey: 'ActionNameplate',
                params: {
                    query: 'LatestFromGroups:p*',
                    max: 3,
                    suffixFilter: ['ViewGallery', 'ViewFeatures', 'ViewPageReveal']
                }
            },
            RVVEDISpecificVehicle: {
                reservedKey: 'RVVEDISpecificVehicle',
                trueKey: 'SpecificVehicleView',
                params: {
                    query: 'LatestFromGroups:p*',
                    max: 3,
                    suffixFilter: ["SVVEDI"]
                }
            },
            RVVEDIShowroom: {
                reservedKey: 'RVVEDIShowroom',
                trueKey: 'ShowroomResultsEDI',
                params: {
                    query: 'LatestFromGroups:p*',
                    max: 3,
                }
            },
        },
        RVV: {
            Utils: {
                concatDataFromResponse: function (data) {
                    return data.reduce(function (accum, currentData) {
                        return accum.concat(
                          Object.keys(currentData)
                            .reduce(function (accum, currentAction) {
                                try {
                                    accum = accum.concat(currentData[currentAction]);
                                } catch (err) {
                                    console.log(err);
                                }
                                return accum;
                            }, [])
                        );
                    }, []);
                }
                , getAllMerge: function (data) {
                    if (!data || !Array.isArray(data)) return [];
                    return this.concatDataFromResponse(data)
                      .sort(this.sortByDateOnDescending);
                }
                , filters: {
                    paramFilter: ["fmccmp", "bannerid", "intcmp", "gnav", "scmp", "type", "gmbxtid", "hptid", "vhptid", "rsttid", "rstid", "recipe"]
                    , filterRepeatNameplatesInGroupWithReturnURL: function (data) {
                        return data.reduce(function(accum,current){

                            var nameplate = current._nameplate || "";
                            var year = current._year || "";
                            var returnURL = current.returnURL || "";

                            if(nameplate && year && returnURL && !accum.obj[nameplate+"__"+year]){
                                accum.obj[nameplate+"__"+year] = true;
                                accum.list.push(current);
                            }
                            return accum;
                        }, {obj:{},list:[]}).list;
                    }
                    , filterRepeatNameplatesInGroup: function (data) {
                        return data.reduce(function(accum,current){

                            var nameplate = current._nameplate || "";
                            var year = current._year || "";

                            if(nameplate && year && !accum.obj[nameplate+"__"+year]){
                                accum.obj[nameplate+"__"+year] = true;
                                accum.list.push(current);
                            }
                            return accum;
                        }, {obj:{},list:[]}).list;
                    }
                    , filterMergeUniqueNPFromSVV: function (np, svv) {
                        var uniqueSVV = this.filterRepeatNameplatesInGroup(svv);
                        var filteredNP = [];
                        np.forEach( function (el, index) {
                            var matched = false;
                            var mi = -1;
                            var mv = null;
                            uniqueSVV.forEach( function (uEl, uIndex) {
                                if (el._nameplate === uEl._nameplate && el._year === uEl._year) {
                                    matched = true;
                                    mi = uIndex;
                                    mv = uEl;
                                }
                            });
                            if (matched === true) {
                                //compare datetime stamp; newest wins
                                if (el.on > mv.on) {
                                    //remove svv
                                    uniqueSVV.splice(mi, 1);
                                    //add np
                                    if (el.hasOwnProperty('returnURL') && el.returnURL.length > 0) {
                                        //v.returnURL = returnURLFilter(v.returnURL);
                                        filteredNP.push(el);
                                    }
                                } else {
                                    //don't add np, keep svv (do nothing)
                                }
                            } else {
                                if (el.hasOwnProperty('returnURL') && el.returnURL.length > 0) {
                                    //v.returnURL = returnURLFilter(v.returnURL);
                                    filteredNP.push(el);
                                }
                            }
                        });
                        return filteredNP.concat(uniqueSVV);
                    }
                    , removeSearchParameters: function(search,parameterNames){
                        if(!parameterNames || !Array.isArray(parameterNames)){
                            return search;
                        }
                        return search.split("&").reduce(function(accum,current){
                            var split = current.split("=");
                            var key = split[0];
                            var value = split[1];
                            var lowerCaseKey = typeof key === "string" ? key.toLocaleLowerCase() : "";

                            if(lowerCaseKey && parameterNames.indexOf(lowerCaseKey) === -1){
                                accum.push(key+(value ? "="+value : ""));
                            }

                            return accum;
                        }.bind(this),[]).join('&');

                    },
                    returnURL: function(url){

                        if( typeof url !== "string" || url === ""){
                            return "";
                        }

                        var splitUrlAtHash = url.split('#');
                        var beforeHash = splitUrlAtHash[0];
                        var hash = splitUrlAtHash[1] || "";
                        var pathAndSearch = beforeHash.split('?');

                        var path = pathAndSearch[0];
                        var search = pathAndSearch[1] || "";

                        search = this.removeSearchParameters(search,this.paramFilter);

                        return path+(search ? "?"+search : "")+(hash ? "#"+hash : "");
                    }
                }
                , sortByDateOnDescending: function (a, b) {
                    try {
                        a = new Date(a.on);
                        b = new Date(b.on);
                        return a > b ? -1 : a < b ? 1 : 0;
                    } catch (err) {
                        return 0;
                    }
                }
                , isValidActiveNameplate: function (vdmFilterObject){
                    var excludedVehicles = {
                        // Ex: "F-150 F-150_2024":true,
                    };

                    return function(entry){
                        var _nameplate = entry._nameplate;
                        var _year = entry._year;
                        try{

                            let excludedMatch = excludedVehicles[_nameplate+"_"+_year] || excludedVehicles[_nameplate+"_"+_year+"_"+tagCountry];

                            if(excludedMatch){
                                console.log("Excluded: ", _nameplate, _year);
                                return false;
                            }
                            return vdmFilterObject[_nameplate][_year];
                        }catch(err){
                            return false;
                        }
                    }
                }
                , ensureActiveNameplates: function (data,vdmFilterObject){
                    if(
                      !Array.isArray(data) || typeof vdmFilterObject !== "object"
                      || typeof vdmFilterObject == "object"
                      && Object.keys(vdmFilterObject).length === 0){
                        return data;
                    }
                    return data.map(function(el){
                        return Object.keys(el).reduce(function(accum,current){
                            try{
                                if(current === "RVVEDIShowroom"){
                                    accum[current] = el[current];
                                    return accum;
                                }
                                accum[current] = el[current].filter(this.isValidActiveNameplate(vdmFilterObject));
                            }catch(err){
                                console.log(err);
                            }
                            return accum;
                        }.bind(this),{});
                    }.bind(this))
                }
                , fleetFilter: function(data){

                    try{
                        return data.map(function(el){
                            return Object.keys(el).reduce(function(accum,current){
                                try{
                                    accum[current] = el[current].filter(function(_el) {
                                        var returnURL = _el && typeof _el.returnURL === "string" ? _el.returnURL : "";
                                        var suffix = _el && typeof _el.suffix === "string" ? _el.suffix : "";
                                        if (returnURL.indexOf("fleet.ford.com") > -1 && suffix.indexOf("_Fleet") === -1){
                                            return false;
                                        }
                                        return true;
                                    })
                                }catch(err){
                                    console.log(err);
                                }
                                return accum;
                            }.bind(this),{});
                        }.bind(this))
                    }catch(err){
                        console.log(err);
                    }
                    return data;

                }
                , convertSuffixes: function(data){
                    try{
                        return data.map(function(el){
                            if(el['RVVBPSpecificVehicle']){
                                el['RVVBPSpecificVehicle'] = el['RVVBPSpecificVehicle'].map(function(vehicle){
                                    if(['SVVConfigInProgressFBC','SVVConfigCompleteFBC'].indexOf(vehicle.suffix) > -1 && vehicle._nameplate && vehicle._nameplate === "Maverick" ){
                                        vehicle.suffix = "SVVConfigRevealFBC";
                                    }
                                    return vehicle;
                                });
                            }
                            return el;
                        });
                    }catch(err){
                        return data;
                    }
                }
                , encodeConfigToken: function(url, uid){
                    if (typeof url !== 'string' || url === '') return url;
                    if (url.indexOf('Config%255B') > -1) return url;

                    var isConfigUID = typeof uid === 'string' &&
                        uid.indexOf('Config[') === 0 && uid.lastIndexOf(']') === uid.length - 1;

                    if (isConfigUID) {
                        var encodedUID = encodeURIComponent(encodeURIComponent(uid));

                        if (url.indexOf('Config%5B') > -1) {
                            return url.replace(/Config%5B(.*?)%5D/i, encodedUID);
                        }

                        if (url.indexOf('Config[') > -1) {
                            return url.replace(/Config\[([^\]]*)\]/, encodedUID);
                        }

                        return url;
                    }

                    if (url.indexOf('Config%5B') > -1) {
                        return url.replace(
                            /Config%5B(.*?)%5D/i,
                            function(match) { return encodeURIComponent(match); }
                        );
                    }

                    if (url.indexOf('Config[') > -1) {
                        return url.replace(
                            /Config\[([^\]]*)\]/,
                            function(match) { return encodeURIComponent(encodeURIComponent(match)); }
                        );
                    }

                    return url;
                }
            },
            getAll: function (callbacks) {
                FPS.get([FPS.reserved.RVVNameplate, FPS.reserved.RVVTrim], {
                    success: function (data, statusText, jqXHR) {
                        callbacks.success([
                            {
                                RVVAll: this.Utils.getAllMerge(data)
                            }], statusText, jqXHR);
                    }.bind(this),
                    error: callbacks.error
                });

            },

            getAllByGroups: function (callbacks) {
                var mergeOnSuccess = function (data) {
                    data = [
                        {RVVVehicleTrim: data && data[0] && data[0].RVVVehicleTrim ? data[0].RVVVehicleTrim : []}
                        , {RVVVehicleNameplate: data && data[1] && data[1].RVVVehicleNameplate  ? data[1].RVVVehicleNameplate : []}
                        , {RVVIONameplate: data && data[2] && data[2].RVVIONameplate ? data[2].RVVIONameplate : []}
                        , {RVVSINGNameplate: data && data[3] && data[3].RVVSINGNameplate ? data[3].RVVSINGNameplate : []}
                        , {RVVSINGSpecificVehicle: data && data[4] && data[4].RVVSINGSpecificVehicle ? data[4].RVVSINGSpecificVehicle : []}
                        , {RVVBPNameplate: data && data[5] && data[5].RVVBPNameplate ? data[5].RVVBPNameplate : []}
                        , {RVVBPSpecificVehicle: data && data[6] && data[6].RVVBPSpecificVehicle ? data[6].RVVBPSpecificVehicle : []}
                        , {RVVVEHNameplate: data && data[7] && data[7].RVVVEHNameplate ? data[7].RVVVEHNameplate : []}
                        , {RVVEDISpecificVehicle: data && data[8] && data[8].RVVEDISpecificVehicle ? data[8].RVVEDISpecificVehicle :[]}
                        , {RVVEDIShowroom: data && data[9] && data[9].RVVEDIShowroom ? data[9].RVVEDIShowroom :[]}
                    ];

                    var vehGroupMerge = data[0]['RVVVehicleTrim']
                      .concat(data[1]['RVVVehicleNameplate'])
                      .sort(this.Utils.sortByDateOnDescending);

                    var vehGroupMergeFiltered = this.Utils.filters
                      .filterRepeatNameplatesInGroupWithReturnURL(vehGroupMerge);

                    var singFilteredUniqueNPSVV = this.Utils.filters
                      .filterMergeUniqueNPFromSVV(
                        data[3]['RVVSINGNameplate']
                        , data[4]['RVVSINGSpecificVehicle']
                      )
                      .sort(this.Utils.sortByDateOnDescending);

                    var bpFilteredUniqueNPSVV = this.Utils.filters
                      .filterMergeUniqueNPFromSVV(
                        data[5]['RVVBPNameplate']
                        , data[6]['RVVBPSpecificVehicle']
                      )
                      .sort(this.Utils.sortByDateOnDescending);

                    var ediFilterUniqueNPSVV = data[8]['RVVEDISpecificVehicle'];
                    var ediFilterShowroom = data[9]['RVVEDIShowroom'];

                    var ioGroupMergeFiltered = this.Utils.filters
                      .filterRepeatNameplatesInGroupWithReturnURL(
                        data[2]['RVVIONameplate'].sort(this.Utils.sortByDateOnDescending)
                      );

                    var rvvVehGroupMergeFiltered = this.Utils.filters
                      .filterRepeatNameplatesInGroupWithReturnURL(
                        data[7]['RVVVEHNameplate'].sort(this.Utils.sortByDateOnDescending)
                      );

                    var filteredMerge = []
                      .concat(
                        vehGroupMergeFiltered
                        , ediFilterUniqueNPSVV
                        , singFilteredUniqueNPSVV
                        , bpFilteredUniqueNPSVV
                        , ioGroupMergeFiltered
                        , rvvVehGroupMergeFiltered
                        , ediFilterShowroom
                      )
                      .sort(this.Utils.sortByDateOnDescending);

                    var result = filteredMerge.slice(0, 3).map(function (entry) {
                        if (entry.returnURL) {
                            entry.returnURL = this.Utils.filters.returnURL(entry.returnURL);
                        }
                        return entry;
                    }.bind(this));
                    return result;
                }.bind(this);

                FPS.get([
                    FPS.reserved.RVVVehicleTrim
                    , FPS.reserved.RVVVehicleNameplate
                    , FPS.reserved.RVVIONameplate
                    , FPS.reserved.RVVSINGNameplate
                    , FPS.reserved.RVVSINGSpecificVehicle
                    , FPS.reserved.RVVBPNameplate
                    , FPS.reserved.RVVBPSpecificVehicle
                    , FPS.reserved.RVVVEHNameplate
                    , FPS.reserved.RVVEDISpecificVehicle
                    , FPS.reserved.RVVEDIShowroom
                ], {
                    success: function (data, statusText, jqXHR) {
                        data = this.Utils.fleetFilter(data) || data;
                        data = this.Utils.convertSuffixes(data) || data;
                        if( tagBrand === "Ford" || tagBrand === "Lincoln"){
                            data = this.Utils.ensureActiveNameplates(data,vdmActiveNameplates) || data;
                        }
                        var returnObj = {RVVAllGrouped: mergeOnSuccess(data)};
                        var cookieValue = "";
                        var pageName = typeof digitaldata !== "undefined" && digitaldata.page && digitaldata.page.pageName ? digitaldata.page.pageName : 'pageName not found';
                        returnObj.RVVAllGrouped.forEach(function (val, key) {
                            cookieValue = cookieValue + "|rvv" + (key + 1) + ":" + val._year + ":" + val._nameplate + ":" + val.suffix;
                        });
                        cookie.set('FPS_DTM_RVV', (pageName + cookieValue.toLowerCase()), (new Date(new Date().getTime() + 1.8e+6).toGMTString()), '/', cookie.domain);

                        let rvvTrimFilterMap = [{"trimName":"Active","ngpTrimName":"active"},{"trimName":"Active 100A","ngpTrimName":"base"},{"trimName":"Active MAX","ngpTrimName":"activemax"},{"trimName":"Badlands","ngpTrimName":"badlands"},{"trimName":"Base","ngpTrimName":"base"},{"trimName":"Big Bend","ngpTrimName":"bigbend"},{"trimName":"Bronco Sport Free Wheeling","ngpTrimName":"freewheeling"},{"trimName":"California Route 1","ngpTrimName":"californiaroute1"},{"trimName":"Cargo Van","ngpTrimName":"cargovan"},{"trimName":"Chassis Cab","ngpTrimName":"chassiscab"},{"trimName":"Cutaway","ngpTrimName":"cutaway"},{"trimName":"Dark Horse","ngpTrimName":"darkhorse"},{"trimName":"Dark Horse Premium","ngpTrimName":"darkhorsepremium"},{"trimName":"Dark Horse Super Charge","ngpTrimName":"darkhorsesc"},{"trimName":"E-350 DRW","ngpTrimName":"e-350drwcutaway"},{"trimName":"E-350 DRW","ngpTrimName":"E-350 DRW"},{"trimName":"E-350 DRW","ngpTrimName":"e-350drw"},{"trimName":"E-350 SRW","ngpTrimName":"e-350srwcutaway"},{"trimName":"E-350 SRW","ngpTrimName":"E-350 SRW"},{"trimName":"E-450 DRW","ngpTrimName":"e-450drwcutaway"},{"trimName":"E-450 DRW","ngpTrimName":"E-450 DRW"},{"trimName":"E-450 DRW","ngpTrimName":"e-450drw"},{"trimName":"EcoBoost Convertible","ngpTrimName":"ecoboostconvertible"},{"trimName":"EcoBoost Fastback","ngpTrimName":"ecoboostfastback"},{"trimName":"EcoBoost Premium Convertible","ngpTrimName":"ecoboostpremiumconvertible"},{"trimName":"EcoBoost Premium Fastback","ngpTrimName":"ecoboostpremiumfastback"},{"trimName":"Everglades","ngpTrimName":"everglades"},{"trimName":"F-250 King Ranch","ngpTrimName":"f-250kingranch"},{"trimName":"F-250 Lariat","ngpTrimName":"f-250lariat"},{"trimName":"F-250 LARIAT","ngpTrimName":"f-250lariat"},{"trimName":"F-250 Limited","ngpTrimName":"f-250limited"},{"trimName":"F-250 Platinum","ngpTrimName":"f-250platinum"},{"trimName":"F-250 XL","ngpTrimName":"f-250xl"},{"trimName":"F-250 XLT","ngpTrimName":"f-250xlt"},{"trimName":"F-350 King Ranch","ngpTrimName":"f-350kingranch"},{"trimName":"F-350 Lariat","ngpTrimName":"f-350lariat"},{"trimName":"F-350 LARIAT","ngpTrimName":"f-350lariat"},{"trimName":"F-350 Limited","ngpTrimName":"f-350limited"},{"trimName":"F-350 Platinum","ngpTrimName":"f-350platinum"},{"trimName":"F-350 XL","ngpTrimName":"f-350xl"},{"trimName":"F-350 XLT","ngpTrimName":"f-350xlt"},{"trimName":"F-450 King Ranch","ngpTrimName":"f-450kingranch"},{"trimName":"F-450 Lariat","ngpTrimName":"f-450lariat"},{"trimName":"F-450 LARIAT","ngpTrimName":"f-450lariat"},{"trimName":"F-450 Limited","ngpTrimName":"f-450limited"},{"trimName":"F-450 Platinum","ngpTrimName":"f-450platinum"},{"trimName":"F-450 XL","ngpTrimName":"f-450xl"},{"trimName":"F-450 XLT","ngpTrimName":"f-450xlt"},{"trimName":"F-550 LARIAT","ngpTrimName":"f-550lariat"},{"trimName":"F-550 XL","ngpTrimName":"f-550xl"},{"trimName":"F-550 XLT","ngpTrimName":"f-550xlt"},{"trimName":"F-59 Commercial","ngpTrimName":"f-59commercial"},{"trimName":"F-600 XL","ngpTrimName":"f-600xl"},{"trimName":"F-600 XLT","ngpTrimName":"f-600xlt"},{"trimName":"F-650 Diesel Straight Frame","ngpTrimName":"f-650sddieselstraightframe"},{"trimName":"F-650 Gas Straight Frame","ngpTrimName":"f-650sdgasstraightframe"},{"trimName":"F-650 SD Diesel Straight Frame","ngpTrimName":"f-650sddieselstraightframe"},{"trimName":"F-650 SD Gas Straight Frame","ngpTrimName":"f-650sdgasstraightframe"},{"trimName":"F-750 Diesel Straight Frame","ngpTrimName":"f-750sddieselstraightframe"},{"trimName":"F-750 Gas Straight Frame","ngpTrimName":"f-750sdgasstraightframe"},{"trimName":"F-750 SD Diesel Straight Frame","ngpTrimName":"f-750sddieselstraightframe"},{"trimName":"F-750 SD Gas Straight Frame","ngpTrimName":"f-750sdgasstraightframe"},{"trimName":"Flash","ngpTrimName":"flash"},{"trimName":"GT","ngpTrimName":"gt"},{"trimName":"GT Fastback","ngpTrimName":"gtfastback"},{"trimName":"GT Premium Convertible","ngpTrimName":"gtpremiumconvertible"},{"trimName":"GT Premium Fastback","ngpTrimName":"gtpremiumfastback"},{"trimName":"Heritage","ngpTrimName":"heritage"},{"trimName":"Heritage Edition","ngpTrimName":"heritageedition"},{"trimName":"King Ranch","ngpTrimName":"kingranch"},{"trimName":"King Ranch MAX","ngpTrimName":"kingranchmax"},{"trimName":"LARIAT","ngpTrimName":"lariat"},{"trimName":"Lariat","ngpTrimName":"lariat"},{"trimName":"Limited","ngpTrimName":"limited"},{"trimName":"Lobo","ngpTrimName":"lobo"},{"trimName":"Maverick Lobo","ngpTrimName":"lobo"},{"trimName":"MAX Active","ngpTrimName":"activemax"},{"trimName":"MAX King Ranch","ngpTrimName":"kingranchmax"},{"trimName":"MAX Platinum","ngpTrimName":"platinummax"},{"trimName":"Mustang Mach-E Rally","ngpTrimName":"rally"},{"trimName":"Outer Banks","ngpTrimName":"outerbanks"},{"trimName":"Passenger Van XL","ngpTrimName":"passengervanxl"},{"trimName":"Passenger Van XLT","ngpTrimName":"passengervanxlt"},{"trimName":"Platinum","ngpTrimName":"platinum"},{"trimName":"Platinum MAX","ngpTrimName":"platinummax"},{"trimName":"Plug-in Hybrid","ngpTrimName":"phev"},{"trimName":"Premium","ngpTrimName":"premium"},{"trimName":"PRO","ngpTrimName":"pro"},{"trimName":"Rally","ngpTrimName":"rally"},{"trimName":"Raptor","ngpTrimName":"raptor"},{"trimName":"Select","ngpTrimName":"select"},{"trimName":"ST","ngpTrimName":"st"},{"trimName":"ST-Line","ngpTrimName":"st-line"},{"trimName":"ST-Line Elite","ngpTrimName":"st-linepremium"},{"trimName":"ST-Line Select","ngpTrimName":"st-lineplus"},{"trimName":"Stroppe Edition","ngpTrimName":"oates"},{"trimName":"STX","ngpTrimName":"stx"},{"trimName":"Tremor","ngpTrimName":"tremor"},{"trimName":"TREMOR","ngpTrimName":"tremor"},{"trimName":"XL","ngpTrimName":"xl"},{"trimName":"XLT","ngpTrimName":"xlt"}];

                        if(rvvTrimFilterMap){
                            returnObj.RVVAllGrouped.map(el => {

                                if(el._trim){
                                    try{
                                        const _trim = el._trim.replace(/[^a-zA-Z0-9 -]/g, '');
                                        const foundTrim = rvvTrimFilterMap.find( i => i.trimName === _trim || i.ngpTrimName === _trim).ngpTrimName;

                                        if(!foundTrim){
                                            throw Error(`Trim already defined ${e._trim}`)
                                        }
                                        el._trim = foundTrim;
                                    }catch(err){

                                    }
                                }

                                // Double-encode the Config token in returnURL
                                if (el.returnURL && typeof el.returnURL === 'string') {
                                    el.returnURL = this.Utils.encodeConfigToken(el.returnURL, el._UID);
                                }

                                return el;
                            });
                        }

                        callbacks.success([returnObj], statusText, jqXHR);
                    }.bind(this),
                    error: callbacks.error
                });
            }
        }});DeepMerge( window.FPS, {actions: {
            SIDetailView: {name: 'SIDetailView', score: '1358', scoreMobile: '1289' },
            SIRequestQuote: {name: 'SIRequestQuote', score: '2718', scoreMobile: '2718' },
            SIRequestTestDrive: {name: 'SIRequestTestDrive', score: '939', scoreMobile: '967' },
            SIResults: {name: 'SIResults', score: '300', scoreMobile: '300'},
            SISave: {name: 'SISave', score: '300', scoreMobile: '300'},
            SIShare: {name: 'SIShare', score: '300', scoreMobile: '300'}
        },
        lib: {
            SavedInventoryVehicle: function (vin, nameplate, year, nickname, notes, paCode, zip, programs) {
                return {
                    'SavedInventoryVehicle': {
                        _vin: vin,
                        nameplate: nameplate,
                        year: year,
                        nickname: nickname,
                        notes: notes,
                        paCode: paCode,
                        zip: zip,
                        programs: programs
                    }
                };
            },
            SINGSearchFilter: function (year, brand, nameplate, trim, bodyStyle, zip, engine, transmission, exteriorColor, interiorColor, exteriorFeatures, netPriceRange, cabStyle, boxSize, fuelEconomy, windowHref) {

                var returnURL = "";

                try {
                    if (typeof windowHref === "string" && new URL(windowHref)) {
                        returnURL = windowHref;
                    } else {
                        returnURL = window.location.href;
                    }
                } catch (err) {
                    returnURL = window.location.href;
                }

                return {
                    'SINGSearchFilter': {
                        _key: Math.round((new Date()).getTime() / 1000),
                        year: year,
                        brand: brand,
                        nameplate: nameplate,
                        trim: trim,
                        bodyStyle: bodyStyle,
                        zip: zip,
                        engine: engine,
                        transmission: transmission,
                        exteriorColor: exteriorColor,
                        interiorColor: interiorColor,
                        exteriorFeatures: exteriorFeatures,
                        netPriceRange: netPriceRange,
                        cabStyle: cabStyle,
                        boxSize: boxSize,
                        fuelEconomy: fuelEconomy,
                        returnURL: returnURL
                    }
                };
            },
            SpecificVehicleView: function (UID, appID, PAcode, ZIP, year, brand, nameplate, trim, action, returnURL, options) {
                FPS.OI.Vehicle.set(year, brand, nameplate, trim, FPS.getScore(action) );
                FPS.pageLoadTracker.trackPage();
                // setTimeout(FPS.NME.Check, 500);

                var displayName = options && typeof options.displayName === "string" ? options.displayName : "";

                return {
                    'SpecificVehicleView': {
                        _UID: UID,
                        _appID: appID,
                        _PAcode: PAcode,
                        _ZIP: ZIP,
                        _year: year,
                        _brand: brand,
                        _nameplate: nameplate,
                        _trim: trim,
                        returnURL: window.location.href,
                        displayName: displayName
                    },
                    suffix: action.name,
                    metadata: {score: FPS.getScore(action)}
                }
            }

        }});DeepMerge( window.FPS, {SavedItems: {
            Utils:{
                Validators: {
                    Vehicle:{
                        Set: {
                            UID: {required: true, rowKey:true}
                            , AppId: {required: true, suffix:true}
                            , Nickname: ""
                            , Notes: ""
                            , Brand: {required:true}
                            , Nameplate: {required:true}
                            , Trim: ""
                            , ReturnURL: ""
                            , Zip: ""
                            , PACode: ""
                            , Year: ""
                            , Status: ""
                            , StatusDate: ""
                            , Locale: ""
                            , ConfigId: ""
                        }
                        , Forget: {
                            AppId:{required: true, suffix:true}
                            , UID: {required: true, rowKey:true}
                        }
                        , Check: {
                            AppId:{suffix:true}
                            , UID: {required:true, rowKey:true}
                        }
                        , Get: {
                            AppId:{suffix:true}
                            , UID: {required:true, rowKey:true}
                        }

                    }
                    , Video:{
                        Set: {
                            UID: {required: true, rowKey:true}
                            , AppId: {required: true, suffix:true}
                            , title: ""
                        }
                        , Forget: {
                            AppId:{required: true, suffix:true}
                            , UID: {required: true, rowKey:true}
                        }
                        , Check: {
                            AppId:{suffix:true}
                            , UID: {required:true, rowKey:true}
                        }
                        , Get: {
                            AppId:{suffix:true}
                            , UID: {required:true, rowKey:true}
                        }
                    }
                    , CartProgress: {
                        Set: {
                            UID: { required: true, rowKey:true }
                            , Url: { required: true }
                            , VIN: { required: true }
                            , CurrentStep: { required: true }
                            , TotalSteps: { required: true }
                            , Progress: {required: true }
                            , StepName: { required: true }
                            , Nameplate: ""
                            , Trim: ""
                            , Year: ""
                        },
                        Forget: {
                            UID: { required: true, rowKey: true }
                        },
                        Check: {
                            UID: { required: true, rowKey: true }
                        },
                        Get: {
                            UID: { required: true, rowKey: true }
                        }

                    }
                }
                , ItemTypes:{
                    Vehicle: "Vehicle"
                    , Video: "Video"
                    , CartProgress: "CartProgress"
                }
                , propRequired: function (validator,target){
                    return Object.keys(validator)
                      .reduce(function(accum,key){
                          if( accum.required === true && validator[key] && validator[key].required === true && typeof target[key] === "undefined"){
                              accum.required = false;
                              accum.error = {message: "Failed Validation: [" + key + "] is undefined"}
                          }
                          return accum;
                      },{required:true,error:null});
                }
                , getProps: function (validator,target){
                    return Object.keys(validator)
                      .reduce(function(accum,key){
                          if(typeof target[key] !== "undefined"){
                              if(typeof validator[key] === "object" && validator[key].rowKey){
                                  accum["_"+key] = target[key];
                              }else if(typeof validator[key] === "object" && validator[key].suffix){
                                  accum["suffix"] = target[key];
                              }else{
                                  accum[key] = target[key];
                              }
                          }
                          return accum;
                      },{});
                }
                , process: function (data,Validators,method){
                    return Object.keys(data)
                      .reduce(function(accum,key){
                          return accum.concat(data[key].map(function(el){
                              return {key:key,value:el};
                          }));
                      },[])
                      .reduce(function(accum,current){
                          var hasRequiredProps = this.propRequired(Validators[current.key][method],current.value);
                          if(hasRequiredProps.required === false){
                              return accum.concat({
                                  key: current.key
                                  , props: current.value
                                  , isValid: false
                                  , error:hasRequiredProps.error
                              });
                          }
                          var props = this.getProps(Validators[current.key][method],current.value,current.key);
                          return accum.concat({
                              key: current.key
                              , value: current.value
                              , props: props
                              , isValid: true
                              , validator: Validators[current.key][method]
                          });
                      }.bind(this),[])
                }
                , consolidateErrors: function (props){
                    return props.map(function(el,index){
                        if(el.error){
                            el.errorAtIndex = index;
                        }
                        return el;
                    }).filter(function(el){
                        return el.error;
                    }).map(function(el){
                        var error = {};
                        error[el.key] = el.props;
                        error.error = el.error.message;
                        if(typeof el.errorAtIndex === "number"){
                            error.errorAtIndex = el.errorAtIndex;
                        }
                        return error;
                    });
                }
                , consolidateSetObjects: function (args){
                    args = args || {};
                    var props = Array.isArray(args.props) ? args.props : [args.props];
                    var prefix = args.prefix || "";
                    var metadata = args.metadata;
                    return props.reduce(function(accum,current){
                        var setObject = {};
                        var suffix = current.props.suffix || undefined;
                        if(suffix) {
                            delete current.props.suffix;
                            setObject.suffix = suffix;
                        }
                        if(metadata){
                            setObject.metadata = metadata;
                        }
                        setObject[prefix+current.key] = current.props;
                        accum.push(setObject);
                        return accum;
                    },[]);
                }
                , consolidateGetObjects: function (args){
                    args = args || {};
                    var props = Array.isArray(args.props) ? args.props : [args.props];
                    var prefix = args.prefix || "";
                    var usedKeys = {};
                    return props.reduce(function(accum,current){
                        var getKey = prefix + current.key;
                        current.get = {};
                        current.get[getKey] = {};
                        if(!usedKeys[getKey]){
                            usedKeys[getKey] = true;
                            return accum.concat(current.get);
                        }
                        return accum;
                    },[]);
                }
                , checkForMatch: function (data,validator,target){

                    var _key = null;
                    var result = Object.keys(data).reduce(function(accum,key){
                        var prop = key;
                        if(validator[key].rowKey === true){
                            prop = "_"+prop;
                        }else if(validator[key].suffix === true){
                            prop = "suffix";
                        }

                        if(validator[key].required === true){
                            _key = key;
                        }

                        return accum.concat({
                            prop: prop
                            , key: key
                            , matched: target.value[prop] === data[key]
                            , required: validator[key].required === true
                        });
                    },[]).filter(function(el){
                        return el.matched === true;
                    })
                    var matched = result.length === Object.keys(data).length;
                    return {
                        result: result
                        , matched: matched
                    }
                }
                , processCheckData: function(props,data){
                    var dataKeys = data.reduce(function(accum,current){
                        return accum.concat(Object.keys(current).reduce(function(accum,key){
                            return accum.concat(current[key].map(function(el){
                                var obj = {};
                                obj.key = key;
                                obj.value = el;
                                return obj;
                            }));
                        },[]));
                    },[]);

                    var result = props.reduce(function(accum,prop){
                        for( var index in dataKeys ){
                            var checkMatched = this.checkForMatch(prop.value,prop.validator,dataKeys[index]);
                            prop.matched = checkMatched.matched
                            if(checkMatched.matched === true){
                                return accum.concat(prop);
                            }
                        }
                        return accum.concat(prop);
                    }.bind(this),[]);

                    return result;
                }
                , processGetData: function (props,data){
                    var dataKeys = data.reduce(function(accum,current){
                        return accum.concat(Object.keys(current).reduce(function(accum,key){
                            return accum.concat(current[key].map(function(el){
                                var obj = {};
                                obj.key = key;
                                obj.value = el;
                                return obj;
                            }));
                        },[]));
                    },[]);

                    var result = props.reduce(function(accum,prop){
                        for( var index in dataKeys ){
                            var checkMatched = this.checkForMatch(prop.value,prop.validator,dataKeys[index]);
                            if(checkMatched.matched === true){
                                accum.push(dataKeys[index]);
                            }
                        }
                        return accum;
                    }.bind(this),[]);

                    return result;
                }
                , setBeaconCookie: function (props) {
                    try{

                        const containsFPSBeaconData = {};
                        const beaconData = cookie.get("FPS_Beacon");

                        if(typeof beaconData === "string" && beaconData.includes("build")){
                            containsFPSBeaconData.build = "build";
                        }

                        if(typeof beaconData === "string" && beaconData.includes("cart")){
                            containsFPSBeaconData.cart = "cart";
                        }

                        for( let prop of props){
                            if(prop?.key === this.ItemTypes.Vehicle && prop?.value?.AppId === "FBC"){
                                containsFPSBeaconData.build = "build";
                            } else if( prop?.key === this.ItemTypes.CartProgress){
                                containsFPSBeaconData.cart = "cart";
                            }
                        }

                        const fpsCookieBeaconValue = Object.keys(containsFPSBeaconData)
                            .sort((a,b)=>{
                                if(a < b) return 1;
                                if(b < a)return -1;
                                return 0;
                            })
                            .join("|");

                        const DaysFromNow = new Date(Date.now() + (45 * 86400000));

                        if( fpsCookieBeaconValue ) {
                            cookie.set("FPS_Beacon", fpsCookieBeaconValue, DaysFromNow, "/", cookie.domain);
                        }

                    }catch(err){
                        console.log(err);
                    }
                }
            }
            , Set: function(props, callbacks) {
                var props = this.Utils.process(props,this.Utils.Validators,"Set");
                var errors = this.Utils.consolidateErrors(props);

                if(errors.length > 0 && callbacks && typeof callbacks.error === "function"){
                    callbacks.error(errors);
                    return;
                }

                var sets = this.Utils.consolidateSetObjects({props:props,prefix:"SavedItems_"});
                var _year;
                var _locale = "";
                try{
                    _year = FD.Brand.Context.nameplate.ngpYear;
                }catch(err){

                }

                try{
                    _locale = FPS.config.locale;
                }catch(err){

                }

                sets = sets.map(function(el){
                    var saveSet = el && el.SavedItems_Vehicle;
                    var suffix = el && el.suffix;
                    if(saveSet){
                        if( suffix === "SING" && !saveSet.Year && typeof _year === "string" ){
                            saveSet.Year = _year;
                        } else if( suffix === "SING" && saveSet.Year && typeof _year === "undefined" ){
                            _year = saveSet.Year;
                        }

                        if(!saveSet.Locale && typeof _locale === "string" && _locale !== ""){
                            saveSet.Locale = _locale;
                        }

                    }
                    return el;
                });

                var vehicleSets = {SING:[],BNP:[]};
                try{
                    vehicleSets = sets.reduce(function(accum,el){
                        var _vehicle = el && el.SavedItems_Vehicle;
                        if(_vehicle.Nickname) _vehicle.Nickname = "";
                        if(_vehicle.Notes) _vehicle.Notes = "";
                        if(_vehicle){
                            if(el.suffix === "SING" && _vehicle.Year){
                                accum.SING.push({
                                    SavedInventoryVehicle:{
                                        _vin: _vehicle._UID,
                                        paCode: _vehicle.PACode,
                                        nameplate: _vehicle.Nameplate,
                                        zip: _vehicle.Zip,
                                        notes: _vehicle.Notes,
                                        nickname: _vehicle.Nickname,
                                        year: _vehicle.Year,
                                        programs: []
                                    }
                                });
                            } else if( el.suffix === "BNP" ){
                                accum.BNP.push({
                                    SavedBPConfig:{
                                        _config: _vehicle._UID,
                                        nickname: _vehicle.Nickname,
                                        notes: _vehicle.Notes,
                                        zip: _vehicle.Zip
                                    },
                                    suffix: _vehicle.Nickname
                                });
                            }
                        }
                        return accum;
                    },{SING:[],BNP:[]});

                }catch(err){

                }

                if (vehicleSets && Array.isArray(vehicleSets.SING) && vehicleSets.SING.length > 0) {
                    vehicleSets.SING.forEach( el => sets.push(el));
                } else if(vehicleSets && Array.isArray(vehicleSets.BNP) && vehicleSets.BNP.length > 0) {
                    vehicleSets.BNP.forEach( el => sets.push(el));
                }

                FPS.set(sets,callbacks);

                this.Utils.setBeaconCookie(props);

            }
            , Forget: function(props, callbacks) {

                var props = this.Utils.process(props,this.Utils.Validators,"Forget");
                var errors = this.Utils.consolidateErrors(props);

                if(errors.length > 0 && callbacks && typeof callbacks.error === "function"){
                    callbacks.error(errors);
                    return;
                }

                var sets = this.Utils.consolidateSetObjects({props:props,prefix:"SavedItems_",metadata:{active:false}});
                FPS.set(sets,callbacks);
            }
            , Check: function(props, callbacks) {
                var props = this.Utils.process(props,this.Utils.Validators,"Check");
                var errors = this.Utils.consolidateErrors(props);

                if(errors.length > 0 && callbacks && typeof callbacks.error === "function"){
                    callbacks.error(errors);
                    return;
                }

                var gets = this.Utils.consolidateGetObjects({props:props,prefix:"SavedItems_"});

                FPS.get(gets,{
                    error: callbacks && typeof callbacks.error === "function" && callbacks.error || function(){}
                    ,success: function(resp){
                        var result = this.Utils.processCheckData(props,resp).reduce(function(accum,current){
                            var getKey = Object.keys(current.validator).reduce(function(accum,key){
                                if(current.validator[key].required === true){
                                    return key;
                                }
                                return accum;
                            },null);
                            if(!accum[current.key]) accum[current.key] = {};
                            accum[current.key][current.value[getKey]] = current.matched || false;
                            return accum;
                        },{});

                        if(callbacks && typeof callbacks.success === "function"){
                            callbacks.success(result);
                        }
                    }.bind(this)
                })

            }
            , Get: function(props,callbacks){
                var outputStarter = Object.keys(props).reduce(function(accum,key){
                    if(!accum[key]) accum[key] = [];
                    return accum;
                },{});
                var props = this.Utils.process(props,this.Utils.Validators,"Get");
                var errors = this.Utils.consolidateErrors(props);

                if(errors.length > 0 && callbacks && typeof callbacks.error === "function"){
                    callbacks.error(errors);
                    return;
                }

                var gets = this.Utils.consolidateGetObjects({props:props,prefix:"SavedItems_"});

                FPS.get(gets,{
                    error: callbacks && typeof callbacks.error === "function" && callbacks.error || function(){}
                    ,success: function(resp){
                        var result = this.Utils.processGetData(props,resp).reduce(function(accum,current){
                            var key = current.key.replace(/SavedItems_?/,"");
                            if(!accum[key]) accum[key] = [];
                            accum[key].push(current.value);
                            return accum;
                        },outputStarter);

                        if(result.Vehicle) {
                            result.Vehicle = result.Vehicle.map((el) => {
                                if( el.Nickname) el.Nickname = "";
                                if( el.Notes) el.Notes = "";
                                return el;
                            })
                        }

                        if(callbacks && typeof callbacks.success === "function"){
                            callbacks.success(result);
                        }
                    }.bind(this)
                })
            }
            , GetAll: function(props,callbacks) {
                if(typeof callbacks === "undefined" && props && typeof props.error === "function" && typeof props.success === "function"){
                    callbacks = props;
                    props = Object.keys(this.Utils.ItemTypes);
                }

                var inValidProps = (
                  typeof props !== "string" && !Array.isArray(props)
                  || (typeof props === "string" && !this.Utils.ItemTypes[props])
                  || ( Array.isArray(props) && props.filter(function(el){
                      if(typeof el !== "string"){
                          return false;
                      }
                      return !!this.Utils.ItemTypes[el];
                  }.bind(this)).length < props.length)
                );

                if(inValidProps){
                    try{
                        throw Error("Invalid arguments");
                    }catch(err){
                        console.log("Expected 2 argumentes GetAll(\n\tprops:[<SavedItems.Utils.ItemTypes>]\n\t, callbacks:<{success:function,error:function}>\n)");
                        return;
                    }
                }
                var matchedKeys = {};
                var getObject = (Array.isArray(props) ? props : [props]).reduce(function(accum,key){
                    if(!matchedKeys[key]){
                        matchedKeys[key] = true;
                        var obj = {};
                        obj["SavedItems_"+key] = {};
                        accum.push(obj);
                    }
                    return accum;
                },[]);

                if(callbacks && typeof callbacks.success === "function"){
                    var original = callbacks.success;
                    callbacks.success = function(resp){
                        if( !resp
                          || !Array.isArray(resp)
                          || (Array.isArray(resp)
                            && resp.length === 0)
                        ){
                            return original.apply(null,arguments);
                        }
                        var data = (Array.isArray(resp) ? resp : [resp]).map(function(el){
                            for( var prop in el){
                                var newProp = prop.replace(/SavedItems_?/,"");
                                if(newProp !== prop){
                                    el[newProp] = el[prop];
                                    delete el[prop];
                                }
                            }
                            return el;
                        });

                        if(resp[0].Vehicle) {
                            resp[0].Vehicle = resp[0].Vehicle.map((el) => {
                                if( el.Nickname) el.Nickname = "";
                                if( el.Notes) el.Notes = "";
                                return el;
                            })
                        }

                        return original(resp);

                    }

                }
                FPS.get(getObject, callbacks);
            }
        }});DeepMerge( window.FPS, {targetCookies: {
            ttl: function() {
                return new Date(now.getTime() + (90 * 86400000));
            },
            voiChangeInsightsTrigger: function(voiCookieVal, voiLastCookieNameplate, voiCurrentCookieNameplate, tier) {

                var voiInsightsCookieName = tier !== '' ? 'VOI_Insights_' + tier : 'VOI_Insights';
                var voiInsightsCookieVal = cookie.get(voiInsightsCookieName);
                var hasInsightsCookie = typeof voiInsightsCookieVal === "string" && voiInsightsCookieVal !== null && voiInsightsCookieVal.length > 0;

                if (voiLastCookieNameplate !== voiCurrentCookieNameplate && !hasInsightsCookie) {
                    var date = new Date();
                    var midnight = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59);
                    cookie.set(voiInsightsCookieName, decodeURIComponent(voiCookieVal), midnight.toString(), '/', cookie.domain);
                    fpsVOIChangeInsight(tier !== '' ? 'voichange-update-' + tier : 'voichange-update');
                }
            },
            VOIAggregateNameplate: function(kvPair) {
                var key = kvPair.Key;
                var val = kvPair.Value;
                if (val.length > 0) {
                    var voiCookieVal = cookie.get('FPS_Target_VOI_Model');
                    var hasCookie = typeof voiCookieVal === "string" && voiCookieVal !== null && voiCookieVal.length > 0;
                    if (hasCookie) {
                        var voiLastCookieNameplate = JSON.parse(decodeURIComponent(voiCookieVal))['model'];
                    }

                    let nonEmptyVoiData = val.find( el => el?._nameplate && el?._brand );

                    if(nonEmptyVoiData && nonEmptyVoiData._nameplate && nonEmptyVoiData._brand) {
                        cookie.set('FPS_Target_VOI_Model', JSON.stringify({
                            model: nonEmptyVoiData._nameplate,
                            year: typeof nonEmptyVoiData._year === "string" && nonEmptyVoiData._year !== "" ? nonEmptyVoiData._year : new Date().getFullYear().toString(),
                            make: nonEmptyVoiData._brand,
                            score: nonEmptyVoiData.score
                        }), FPS.targetCookies.ttl(), '/', cookie.domain);
                    }

                    if (hasCookie) {
                        var voiCurrentCookieNameplate = JSON.parse(decodeURIComponent(cookie.get('FPS_Target_VOI_Model')))['model'];
                        var tier = '';
                        FPS.targetCookies.voiChangeInsightsTrigger(voiCookieVal, voiLastCookieNameplate, voiCurrentCookieNameplate, tier);
                    }
                }
            },
            T1VOIAggregateNameplate: function(kvPair) {
                var key = kvPair.Key;
                var val = kvPair.Value;
                if (val.length > 0) {
                    var voiCookieVal = cookie.get('FPS_Target_VOI_Model_T1');
                    var hasCookie = typeof voiCookieVal === "string" && voiCookieVal !== null &&  voiCookieVal.length > 0;
                    if (hasCookie) {
                        var voiLastCookieNameplate = JSON.parse(decodeURIComponent(voiCookieVal))['model'];
                    }

                    let nonEmptyVoiData = val.find( el => el?._nameplate && el?._brand );

                    if(nonEmptyVoiData && nonEmptyVoiData._nameplate && nonEmptyVoiData._brand) {
                        cookie.set('FPS_Target_VOI_Model_T1', JSON.stringify({
                            model: nonEmptyVoiData._nameplate,
                            year: typeof nonEmptyVoiData._year === "string" && nonEmptyVoiData._year !== "" ? nonEmptyVoiData._year : new Date().getFullYear().toString(),
                            make: nonEmptyVoiData._brand,
                            score: nonEmptyVoiData.score
                        }), FPS.targetCookies.ttl(), '/', cookie.domain);
                    }


                    if (hasCookie) {
                        var voiCurrentCookieNameplate = JSON.parse(decodeURIComponent(cookie.get('FPS_Target_VOI_Model_T1')))['model'];
                        var tier = 'T1';
                        FPS.targetCookies.voiChangeInsightsTrigger(voiCookieVal, voiLastCookieNameplate, voiCurrentCookieNameplate, tier);
                    }
                }
            },
            T2VOIAggregateNameplate: function(kvPair) {
                var key = kvPair.Key;
                var val = kvPair.Value;
                if (val.length > 0) {
                    var voiCookieVal = cookie.get('FPS_Target_VOI_Model_T2');
                    var hasCookie = typeof voiCookieVal === "string" && voiCookieVal !== null && voiCookieVal.length > 0;
                    if (hasCookie) {
                        var voiLastCookieNameplate = JSON.parse(decodeURIComponent(voiCookieVal))['model'];
                    }

                    let nonEmptyVoiData = val.find( el => el?._nameplate && el?._brand );

                    if(nonEmptyVoiData && nonEmptyVoiData._nameplate && nonEmptyVoiData._brand) {
                        cookie.set('FPS_Target_VOI_Model_T2', JSON.stringify({
                            model: nonEmptyVoiData._nameplate,
                            year: typeof nonEmptyVoiData._year === "string" && nonEmptyVoiData._year !== "" ? nonEmptyVoiData._year : new Date().getFullYear().toString(),
                            make: nonEmptyVoiData._brand,
                            score: nonEmptyVoiData.score
                        }), FPS.targetCookies.ttl(), '/', cookie.domain);
                    }

                    if (hasCookie) {
                        var voiCurrentCookieNameplate = JSON.parse(decodeURIComponent(cookie.get('FPS_Target_VOI_Model_T2')))['model'];
                        var tier = 'T2';
                        FPS.targetCookies.voiChangeInsightsTrigger(voiCookieVal, voiLastCookieNameplate, voiCurrentCookieNameplate, tier);
                    }
                }
            },
            TNVOIAggregateNameplate: function(kvPair) {
                var key = kvPair.Key;
                var val = kvPair.Value;
                if (val.length > 0) {
                    var voiCookieVal = cookie.get('FPS_Target_VOI_Model_TN');
                    var hasCookie = typeof voiCookieVal === "string" && voiCookieVal !== null && voiCookieVal.length > 0;
                    if (hasCookie) {
                        var voiLastCookieNameplate = JSON.parse(decodeURIComponent(voiCookieVal))['model'];
                    }

                    let nonEmptyVoiData = val.find( el => el?._nameplate && el?._brand );

                    if(nonEmptyVoiData && nonEmptyVoiData._nameplate && nonEmptyVoiData._brand) {
                        cookie.set('FPS_Target_VOI_Model_TN', JSON.stringify({
                            model: nonEmptyVoiData._nameplate,
                            year: typeof nonEmptyVoiData._year === "string" && nonEmptyVoiData._year !== "" ? nonEmptyVoiData._year : new Date().getFullYear().toString(),
                            make: nonEmptyVoiData._brand,
                            score: nonEmptyVoiData.score
                        }), FPS.targetCookies.ttl(), '/', cookie.domain);
                    }

                    if (hasCookie) {
                        var voiCurrentCookieNameplate = JSON.parse(decodeURIComponent(cookie.get('FPS_Target_VOI_Model_TN')))['model'];
                        var tier = 'TN';
                        FPS.targetCookies.voiChangeInsightsTrigger(voiCookieVal, voiLastCookieNameplate, voiCurrentCookieNameplate, tier);
                    }
                }
            },
            VOIAggregateTrim: function(kvPair) {
                var key = kvPair.Key;
                var val = kvPair.Value;
                if (val.length > 0) {
                    cookie.set('FPS_Target_VOI_Trim', JSON.stringify({
                        model: val[0]._nameplate,
                        year: val[0]._year.toString(),
                        make: val[0]._brand,
                        trim: val[0]._trim,
                        score: val[0].score
                    }), FPS.targetCookies.ttl(), '/', cookie.domain);
                }
            },
            T1VOIAggregateTrim: function(kvPair) {
                var key = kvPair.Key;
                var val = kvPair.Value;
                if (val.length > 0) {
                    cookie.set('FPS_Target_VOI_Trim_T1', JSON.stringify({
                        model: val[0]._nameplate,
                        year: val[0]._year.toString(),
                        make: val[0]._brand,
                        trim: val[0]._trim,
                        score: val[0].score
                    }), FPS.targetCookies.ttl(), '/', cookie.domain);
                }
            },
            T2VOIAggregateTrim: function(kvPair) {
                var key = kvPair.Key;
                var val = kvPair.Value;
                if (val.length > 0) {
                    cookie.set('FPS_Target_VOI_Trim_T2', JSON.stringify({
                        model: val[0]._nameplate,
                        year: val[0]._year.toString(),
                        make: val[0]._brand,
                        trim: val[0]._trim,
                        score: val[0].score
                    }), FPS.targetCookies.ttl(), '/', cookie.domain);
                }
            },
            TNVOIAggregateTrim: function(kvPair) {
                var key = kvPair.Key;
                var val = kvPair.Value;
                if (val.length > 0) {
                    cookie.set('FPS_Target_VOI_Trim_TN', JSON.stringify({
                        model: val[0]._nameplate,
                        year: val[0]._year.toString(),
                        make: val[0]._brand,
                        trim: val[0]._trim,
                        score: val[0].score
                    }), FPS.targetCookies.ttl(), '/', cookie.domain);
                }
            },
            RecentlyViewedVehicles: function(kvPair) {
                var key = kvPair.Key;
                var val = kvPair.Value;
                var arrVals = [];
                for (var i = 0; i < val.length; i++) {
                    arrVals.push({
                        model: val[i]._nameplate,
                        year: val[i]._year,
                        make: val[i]._brand,
                        date: val[i].on
                    })
                }
                if (arrVals.length > 0) {
                    cookie.set('FPS_Target_RVV', JSON.stringify(arrVals), FPS.targetCookies.ttl(), '/', cookie.domain);
                }
            },
            _RVVAggregate: function(kvPair) {
                var key = kvPair.Key;
                var val = kvPair.Value;
                if (val.length > 0) {
                    var writeCookie = true;
                    var cookieVal = cookie.get('FPS_Target_RVVAggregate');
                    if (cookieVal !== null) {
                        var cookieDate = new Date((JSON.parse(decodeURIComponent(cookieVal)))['on']);
                        var recordDate = new Date(val[0].on);
                        if (recordDate < cookieDate) {
                            writeCookie = false;
                        }
                    }
                    if (writeCookie) {
                        cookie.set('FPS_Target_RVVAggregate', JSON.stringify({
                            model: val[0]._nameplate,
                            year: val[0]._year,
                            make: val[0]._brand,
                            trim: val[0]._trim,
                            on: val[0].on,
                            score: val[0].score
                        }), FPS.targetCookies.ttl(), '/', cookie.domain);
                    }
                }
            },
            RVVNameplate: function(kvPair) {
                FPS.targetCookies._RVVAggregate(kvPair);
            },
            RVVTrim: function(kvPair) {
                FPS.targetCookies._RVVAggregate(kvPair);
            }
        }, setTargetCookie: function(callbacks) {
            var keys = [FPS.reserved.VOIAggregateNameplate, FPS.reserved.VOIAggregateTrim, FPS.reserved.RVVNameplate, FPS.reserved.RVVTrim];
            var tier;
            try {
                tier = FPS.Core.Insights.Utils.getTier("https://" + window.location.hostname);
                tier = tier.toUpperCase();
                keys.push(FPS.reserved[tier + "VOIAggregateNameplate"]);
                keys.push(FPS.reserved[tier + "VOIAggregateTrim"]);
            } catch (err) {

            }
            FPS.get(keys, callbacks);
        }});DeepMerge( window.FPS, {lib: {
            TargetPromoTracking: function (programName, dailyCount, lifetimeCount) {
                return {
                    'TargetPromoTracking': {
                        _programName: programName,
                        dailyCount: dailyCount,
                        lifetimeCount: lifetimeCount,
                        date: new Date()
                    }
                };
            }
        } });DeepMerge( window.FPS, {Utils: {
            getQueryStringParams: function getQueryStringParams() {

                var splitUrlAtHash = window.location.search.split('#');
                var beforeHash = splitUrlAtHash[0];
                var pathAndSearch = beforeHash.split('?');
                var search = pathAndSearch[1] || "";

                return search.split("&").reduce(function (accum, current) {
                    var keyValue = current.split('=');
                    var key = keyValue[0];
                    var value = keyValue[1];

                    accum[key] = value;

                    return accum;

                }, {});
            },
            getQueryStringParam: function getQueryStringParam(pram) {
                var params = this.getQueryStringParams();
                return params && params[pram];
            },
            activeVehicle: {
                list: vdmActiveNameplates,
                check: function(props){
                    props = props || {};
                    var nameplate = props.nameplate;
                    var year = props.year;
                    var trim = props.trim;
                    try{
                        if(!trim){
                            return !!vdmActiveNameplates[nameplate][year];
                        }
                        return !!vdmActiveNameplates[nameplate][year][trim];
                    }catch(err){
                        return false;
                    }
                }
            }
        }});DeepMerge( window.FPS, {  Validation: {
            healNameplate: function healNameplate(vdmFilterObject,vdmActiveNameplatesMap){
                return function healNameplate(input,options){
                    try {

                        options = options || {};

                        var year = options.year || options._year || options.Year || "0";

                        if (/mach-e/gmi.test(input)) {
                            return "Mache";
                        } else if (/F-250/gmi.test(input)) {
                            return "SuperDuty";
                        } else if (/Expedition/gmi.test(input)) {
                            return "Expedition";
                        } else if( /f150( |-)lightning/gmi.test(input)){
                            return "F-150 Lightning"
                        }

                        var lowerCaseInput = input.toLowerCase();

                        if( parseInt(year) >= 2022 && (lowerCaseInput === "f150" || lowerCaseInput === "f-150" || lowerCaseInput === "f-150 f-150") ){
                            return "F-150 F-150";
                        }

                        var nameplateMatch = vdmActiveNameplatesMap[input.trim().toLowerCase()]

                        if (nameplateMatch) {
                            return nameplateMatch;
                        }
                    }catch(err){

                    }

                    return input;
                }
            }
        }});DeepMerge( window.FPS, {YMAL: {
            Utils:{
                filters: {
                    paramFilter: ["fmccmp","bannerid","intcmp","gnav","scmp","type","gmbxtid","hptid","vhptid","rsttid","rstid","recipe"]
                    , SuffixKeyMap: {
                        SVVSI: "SISVV"
                        , "SVVEDI ": "EDIVDP"
                        , "SVVEDI": "EDIVDP"
                        , SVVBP: "BNP"
                        , SVVConfigInProgressFBC: "BNP"
                        , SVVConfigCompleteFBC: "BNP"
                        , SVVStartResvFBC: "BNP"
                        , IOFeatured: "OI"
                        , IOModelOffers: "OI"
                        , IOAdditonalOffer: "OI"
                        , BPModelSelect: "BPModelSelect"
                        , SIResults: "SIResults"
                        , "": "SINGSearch"
                    }
                    , removeSearchParameters: function(search,parameterNames){
                        if(!parameterNames || !Array.isArray(parameterNames)){
                            return search;
                        }
                        return search.split("&").reduce(function(accum,current){
                            var split = current.split("=");
                            var key = split[0];
                            var value = split[1];
                            var lowerCaseKey = typeof key === "string" ? key.toLocaleLowerCase() : "";

                            if(lowerCaseKey && parameterNames.indexOf(lowerCaseKey) === -1){
                                accum.push(key+(value ? "="+value : ""));
                            }

                            return accum;
                        }.bind(this),[]).join('&');

                    }
                    , returnURL: function(url){

                        if( typeof url !== "string" || url === ""){
                            return "";
                        }

                        var splitUrlAtHash = url.split('#');
                        var beforeHash = splitUrlAtHash[0];
                        var hash = splitUrlAtHash[1] || "";
                        var pathAndSearch = beforeHash.split('?');

                        var path = pathAndSearch[0];
                        var search = pathAndSearch[1] || "";

                        search = this.removeSearchParameters(search,this.paramFilter);

                        return path+(search ? "?"+search : "")+(hash ? "#"+hash : "");
                    }
                }
            }
            , extractEntries: function (keyValueArray, handler) {
                return Object.keys(keyValueArray).reduce(function (accum, key) {
                    return accum.concat(keyValueArray[key]);
                }, []);
            }
            , filterOutByNameplate: function (nameplate) {
                return function filterOutByNameplate(data) {
                    if (!nameplate) return null;
                    if ((data._nameplate || data.nameplate || "").toLowerCase() === nameplate.toLowerCase()) {
                        return data;
                    }
                    return {};
                }
            }
            ,filterOutByUndefinedTrim: function(trim) {
                return function filterOutByUndefinedTrim(data) {
                    if (!trim) return data;
                    data = data || {};
                    var currentTrim = data._trim || data.trim;
                    if(typeof currentTrim !== "string" && typeof currentTrim !== "object"){
                        return {};
                    }
                    return data;
                }
            }
            , filterOutByStringTrim: function(trim){
                return function filterOutByStringTrim(data){
                    if (!trim) return data;
                    data = data || {};
                    var currentTrim = data._trim || data.trim;
                    if (typeof currentTrim === "string") {
                        var handleSpecialCharactersString = currentTrim.match(/[ a-z|]+/gi);
                        if(handleSpecialCharactersString !== null){
                            currentTrim = handleSpecialCharactersString[0];
                        }
                        if(currentTrim.toLowerCase() === trim.toLowerCase()) {
                            return data;
                        }
                        return {};
                    }
                    return data;
                }
            }
            , filterOutByObjectTrim: function(trim){
                return function filterOutByObjectTrim(data){
                    if (!trim) return data;
                    data = data || {};
                    var currentTrim = data._trim || data.trim;
                    if(typeof currentTrim === "object"){
                        var handleSpecialCharactersObject = trim.match(/[a-z|]+/gi);
                        if(handleSpecialCharactersObject !== null){
                            trim = handleSpecialCharactersObject.join("");
                        }
                        var foundMatch = Object.keys(currentTrim).filter(function(el){
                            var trimFound = el.toLowerCase().indexOf(trim.toLowerCase()) > -1;
                            return trimFound && currentTrim[el] === 1;
                        });
                        if(foundMatch.length > 0){
                            return data;
                        }
                        return {};
                    }
                    return data;
                }
            }
            , filterOutByYear: function (year) {
                return function filterOutByYear(data) {
                    if (!year) return data;
                    var dataYear = data._year || data.year;

                    if (typeof dataYear === "string") {
                        if (dataYear === year) {
                            return data;
                        }
                    } else if (typeof dataYear === "object") {
                        if (dataYear[year] === 1) {
                            return data;
                        }
                    }
                    return {};
                }
            }
            , filterOutEmptyData: function(data){
                data = data || {}
                return Object.keys(data).length > 0;
            }
            , filterReturnUrl: function (data){
                if( data && typeof data.returnURL === "string" ){
                    data.returnURL = this.Utils.filters.returnURL(data.returnURL);
                }
                return data;
            }
            , mapSuffixToKey: function (accum, data) {
                var suffix = this.Utils.filters.SuffixKeyMap[data.suffix];

                if (suffix !== undefined) {
                    if (!accum[suffix]) {
                        accum[suffix] = data;
                    } else if (data.on > accum[suffix].on) {
                        accum[suffix] = data;
                    }
                }

                return accum;
            }
            , computeResult: function(args) {
                args = args || {};
                var nameplate = args.nameplate;
                var trim = args.trim;
                var year = args.year;
                var response = args.response || [];
                var filterOutByTrim = pipe([
                    this.filterOutByUndefinedTrim(trim)
                    , this.filterOutByStringTrim(trim)
                    , this.filterOutByObjectTrim(trim)
                ])
                var filterOutEntries = pipe([
                    this.filterOutByNameplate(nameplate)
                    , filterOutByTrim
                    , this.filterOutByYear(year)
                    , this.filterReturnUrl.bind(this)
                    , this.filterOutEmptyData
                ]);

                var result = response.reduce(function (accum, current) {
                    return this.extractEntries(current)
                      .filter(filterOutEntries)
                      .reduce(this.mapSuffixToKey.bind(this), accum);
                }.bind(this), {});

                var hasCurrentDealerEDI = null;
                var topEDISearchResults = [];
                try{
                    var foundCurrentDealerEDI = args.response.filter( el => el.CurrentDealerEDI )[0];
                    if(!!foundCurrentDealerEDI){
                        hasCurrentDealerEDI = foundCurrentDealerEDI.CurrentDealerEDI[0].paCode;
                    }
                }catch(err){

                }

                try{
                    topEDISearchResults = args.response.filter( function (el) {

                        if( el && el.ShowroomResultsEDI ) {
                            el.ShowroomResultsEDI = el.ShowroomResultsEDI.filter( function(el){
                                try{
                                    var result = el.searchCriteria.split(",").reduce(function(accum,current){
                                        var matcher = new RegExp(current,"gmi");
                                        if( /mach-e/gmi.test(current) && /mach-e|mache/gmi.test(nameplate) ){
                                            accum.count += 1;
                                            accum.searchCriteria = accum.searchCriteria.replace(matcher,"Mache");
                                        } else if( /escape/gmi.test(current) && /escape/gmi.test(nameplate) ){
                                            accum.count += 1;
                                            accum.searchCriteria = accum.searchCriteria.replace(matcher,"Escape");
                                        }
                                        return accum;
                                    },{count:0,searchCriteria:el.searchCriteria});

                                    if( result.count === 1){
                                        el.searchCriteria = result.searchCriteria;
                                        return el;
                                    }
                                    throw Error("Too many nameplates");

                                }catch(err){
                                    return false;
                                }
                            })
                        }
                        return el.ShowroomResultsEDI
                    })[0].ShowroomResultsEDI || [];
                }catch(err){

                }

                return [{
                    RVVYMAL:{
                        SISVV: result.SISVV || null,
                        SINGSearch: result.SINGSearch || result.SIResults || null,
                        OI: result.OI || null,
                        BNP: result.BNP || null,
                        BPModelSelect: result.BPModelSelect || null,
                        ShopEDI: hasCurrentDealerEDI,
                        EDIVDP: result.EDIVDP || null,
                        EDISearchResults: topEDISearchResults
                    }
                }]
            }
            , getByNamePlate:function (nameplate, trim, year, response) {

                if (typeof nameplate !== 'string') return;

                if (trim && typeof trim === 'object' && typeof trim.error === "function" && typeof trim.success === "function") {
                    response = {
                        error: trim.error,
                        success: trim.success
                    };
                    trim = null;
                }

                if (year && typeof year === 'object' && typeof year.error === "function" && typeof year.success === "function") {
                    response = {
                        error: year.error,
                        success: year.success
                    };
                    year = null;
                }

                if (!(typeof response === "object" && typeof response.success === "function" && typeof response.error === "function")) {
                    return;
                }

                FPS.get([
                    { SpecificVehicleView: { max: 10, suffixFilter: ['SVVSI'] } },
                    { SpecificVehicleView: { max: 10, suffixFilter: ['SVVBP'] } },
                    { SpecificVehicleView: { max: 10, suffixFilter: ['SVVEDI'] } },
                    { SpecificVehicleView: { max: 10, suffixFilter: ['SVVConfigInProgressFBC']}},
                    { SpecificVehicleView: { max: 10, suffixFilter: ['SVVConfigCompleteFBC']}},
                    { SpecificVehicleView: { max: 10, suffixFilter: ['SVVStartResvFBC']}},
                    { ActionNameplate: { max: 10, suffixFilter: ['IOFeatured'] } },
                    { ActionNameplate: { max: 10, suffixFilter: ['IOModelOffers'] } },
                    { ActionNameplate: { max: 10, suffixFilter: ['IOAdditonalOffer'] } },
                    { ActionNameplate: { max: 10, suffixFilter: ['BPModelSelect'] } },
                    { ActionNameplate: { max: 10, suffixFilter: ['SIResults'] } },
                    { SINGSearchFilter: { max: 10 } },
                    { CurrentDealerEDI: { max: 10 } },
                    { ShowroomResultsEDI: { max: 10 } }
                ],{
                    success: function(e){
                        var result = this.computeResult({
                            response:e
                            , nameplate:nameplate
                            , trim: trim
                            , year: year
                        });
                        response.success(result);
                    }.bind(this),
                    error: response.error
                });

            }
        }});DeepMerge( window.FPS, {pageLoadTracker: {
            trackPage: function () {
                try {
                    var bypassPageTrackingWhiteList = false;

                    function pageLoadTracker() {
                        var ddi = 0;
                        var _pageNameLoadKey = "";
                        var _vehicleNameCleanLoadKey = "";
                        var _vehicleYear = "";
                        var digitaldata = window.digitaldata;
                        function isdigitaldataready() {
                            try {

                                digitaldata = window.digitaldata;

                                if (digitaldata && digitaldata.page && digitaldata.page.pageNameNoVehicle) {
                                    setPageFPSPageLoad(digitaldata);
                                    clearInterval(lookfordigitaldata);
                                } else if (ddi > 39) {
                                    setPageLoadNoDigitalData();
                                    clearInterval(lookfordigitaldata);
                                } else {
                                    ddi++;
                                }
                            }catch (err){
                                setPageLoadNoDigitalData();
                                clearInterval(lookfordigitaldata);
                            }
                        }

                        function setPageLoadNoDigitalData(){
                            var tier = FPS.Core.Insights.Utils.getTier("https://" + window.location.hostname);
                            if(tier === "t1" || tier === "t2"){
                                const noDigDataOnLoadCookie = Encode(cookie.get("noDigDataOnLoad"));
                                if(!noDigDataOnLoadCookie){
                                    FPS.set([{
                                        pageLoadTracking: {
                                            _pageNameLoadKey: "onLoadNoDigData",
                                            _path: window.location.pathname
                                        }
                                    }],{
                                        success: function(resp){

                                            var expiresInAnHour = new Date(Date.now() + (1000 * 60 * 60));

                                            document.cookie = "noDigDataOnLoad=true;path="+Encode(window.location.pathname)+";expires="+expiresInAnHour.toUTCString();
                                        },
                                        error: function(){}
                                    });
                                }else{
                                    console.log("Skipped because the noDigDataOnLoad cookie exists");
                                }
                            }
                        }

                        function setPageFPSPageLoad(digitaldata) {

                            var pageLoadData = Object.keys(digitaldata).reduce(function (accum, current) {
                                try {

                                    if (current === "user") return accum;

                                    if (bypassPageTrackingWhiteList || !!FPS.pageLoadTracker.pagesTracking[digitaldata.page.pageNameNoVehicle]) {
                                        switch (current) {
                                            case "vehicle":
                                                if (typeof digitaldata[current].nameplate === "string") {
                                                    _vehicleNameCleanLoadKey = digitaldata[current].nameplate.replace("ford ", "").replace("lincoln ", "");
                                                    _vehicleYear = digitaldata[current].modelYear;

                                                }
                                                break;
                                            case "page":
                                                if (typeof digitaldata[current].pageNameNoVehicle === "string") {
                                                    _pageNameLoadKey = digitaldata[current].pageNameNoVehicle;

                                                }
                                                break;
                                            default:
                                                break;
                                        }


                                        accum[current] = JSON.stringify(digitaldata[current]);
                                    }
                                } catch (error) {

                                }
                                return accum;
                            }, {});



                            try {

                                if (Object.keys(pageLoadData).length > 0) {

                                    FPS.set([{
                                        pageLoadTracking: {
                                            _pageNameLoadKey: _pageNameLoadKey.trim(),
                                            _vehicleNameCleanLoadKey: _vehicleNameCleanLoadKey.trim(),
                                            _vehicleYear: _vehicleYear,
                                            pageLoadData: pageLoadData
                                        }
                                    }], {
                                        success: function () {

                                            FPS.pageLoadTracker.setCookie();
                                        },

                                        error: function () {}
                                    });

                                }

                            } catch (error) {
                            }

                        }

                        var lookfordigitaldata = setInterval(isdigitaldataready, 500);
                    }

                    function checkDomainForTracking(hostname,pathname) {
                        if ( hostname.indexOf("owner.ford.com") > -1 || hostname.indexOf("owner.lincoln.com") > -1 ) {
                            bypassPageTrackingWhiteList = true
                            return true
                        } else if (
                          (hostname.indexOf(".ford.com") > -1 || hostname.indexOf(".lincoln.com") > -1)
                          && /^\/support/.test(pathname) === true
                        ) {
                            bypassPageTrackingWhiteList = true
                            return true
                        } else if (hostname.indexOf(".ford.com") > -1 || hostname.indexOf(".lincoln.com") > -1) {
                            bypassPageTrackingWhiteList = false
                            return true
                        }
                        return false
                    }
                    if (checkDomainForTracking(document.location.hostname,document.location.pathname)) {
                        pageLoadTracker();

                    }else{

                    }
                } catch (error) {

                }
            },
            pagesTracking: {
                "fv:vehicle:home": "vhp",
                "fv:vehicle:models:select": "specs",
                "fv:vehicle:models:detail": "mdp",
                "dd:bp:0:fast or full": "bp",
                "dd:bp:2:model": "bp:2:model",
                "dd:bp:3:build" : "bp:3:build",
                "dd:bp:4:vehicle summary": "bp:4:vehiclesummary",
                "dd:bp:5:next steps" : "bp:5:nextsteps",
                "fv:si:vls-find it": "si:vls-findit",
                "fv:si:vls:results" : "si:vls:results",
                "fv:si:vls:vehicle details": "si:vls:vehicledetails",
                "fv:vehicles:incentives:featured offers": "pi",
                "fv:vehicles:incentives:offers by model": "pi",
                "fv:vehicles:incentives:additional offers": "pi",
                "fv:vehicle:get updates:2:thank you": "gup",
                "fv:vehicle:models:compare": "compare",
                "fv:reveal:home": "vhp",
                "fv:bp:model": "bp:model",
                "dd:bp:1:body" : "bp:1:body",
                "fv:reveal:home" : "vhp"
            },
            setCookie: function (callback) {
                FPS.get([{
                    pageLoadTracking: {max:15}
                }], {
                    success: function success(data) {

                        if (!data || !Array.isArray(data) || data.length === 0) {
                            if (callback && typeof callback === "function") {
                                callback();
                            }
                            return;
                        }

                        var pageTrackingList = FPS.pageLoadTracker.pagesTracking;
                        var pageTracking = data[0].pageLoadTracking;

                        var result = Object.keys(pageTracking).reduce(function (accum, current, index, list) {
                            if (pageTracking[current]._vehicleNameCleanLoadKey && pageTrackingList.hasOwnProperty(pageTracking[current]._pageNameLoadKey)) {
                                var delimiter = ":";

                                var modelYear = "";
                                if (pageTracking[current].pageLoadData &&
                                  pageTracking[current].pageLoadData.vehicle &&
                                  typeof pageTracking[current].pageLoadData.vehicle === "string") {
                                    try {
                                        modelYear = "-" + JSON.parse(pageTracking[current].pageLoadData.vehicle).modelYear;
                                    } catch (err) {

                                    }
                                }

                                if (!accum[pageTracking[current]._vehicleNameCleanLoadKey + modelYear]) {
                                    accum[pageTracking[current]._vehicleNameCleanLoadKey + modelYear] = pageTracking[current]._vehicleNameCleanLoadKey + modelYear + "|";
                                    delimiter = "";
                                }
                                //prevent duplicate keys
                                var currentKEY = pageTrackingList[pageTracking[current]._pageNameLoadKey];
                                if (JSON.stringify(accum[pageTracking[current]._vehicleNameCleanLoadKey + modelYear]).indexOf(currentKEY) < 0) {
                                    accum[pageTracking[current]._vehicleNameCleanLoadKey + modelYear] += delimiter + pageTrackingList[pageTracking[current]._pageNameLoadKey];
                                }
                                //original code
                                //accum[pageTracking[current]._vehicleNameCleanLoadKey + modelYear] += delimiter + pageTrackingList[pageTracking[current]._pageNameLoadKey];
                            }

                            return accum;
                        }, {});

                        var value = Object.keys(result).reduce(function (_accum, _current, index, list) {
                            var delimiter = "";

                            if (index > 0) {
                                delimiter = ",";
                            }

                            var appendingValue = delimiter + result[_current];
                            if( _accum.length <= 500 ){
                                _accum += appendingValue;
                            }
                            return _accum;
                        }, "");

                        if (tagBrand) {
                            value = tagBrand + "(" + value + ")";
                        }

                        setCookie("FPS_NJT", value, "60");

                        if (callback && typeof callback === "function") {
                            callback();
                        }

                    },
                    error: function error() {}
                });

                function setCookie(name, value, days) {
                    var date = new Date();
                    var expires = "";
                    vaue = typeof value !== "string" ? "" : value;
                    if (days) {
                        date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
                        expires = "; expires=" + date.toGMTString();
                    }

                    document.cookie = name + "=" + value.replace(/[^ -~]/gim,"") + expires + "; domain=.ford.com; path=/";
                }
            }
        }});
        DeepMerge( window.FPS, {
            lib:{
                VehiclePreference: function (nameplate,year,payload) {

                    var keys = {
                        _nameplate: nameplate,
                        payload: payload || year
                    }

                    if(year && payload){
                        keys._year = year;
                    }

                    return {
                        'VehiclePreference': keys
                    };
                }
            },
            VehiclePreference:{
                get(nameplate,year,callbacks){

                    var locale = "";
                    var hasYear = year && callbacks;
                    try{
                        locale = FPS.config.locale.toLowerCase();
                        locale = locale ? "_"+locale : locale;
                    }catch(err){

                    }

                    var actionKey = "VehiclePreference"+locale;

                    var keyValueObject = {};
                    keyValueObject[actionKey] = {
                        _nameplate: nameplate,
                    }

                    if(hasYear){
                        keyValueObject[actionKey]._year = year;
                    }else{
                        callbacks = year;
                    }

                    if(callbacks && callbacks.success && callbacks.error){
                        var originalSuccess = callbacks.success;

                        callbacks.success = function(resp){
                            try{
                                if(Array.isArray(resp)){

                                    resp.forEach(function(keyValueObject){
                                        if(locale) {
                                            // remove locale from the response object when locale is defined
                                            if (keyValueObject["VehiclePreference" + locale]) {
                                                keyValueObject["VehiclePreference"] = keyValueObject["VehiclePreference" + locale];
                                                delete keyValueObject["VehiclePreference" + locale];
                                            }
                                        }

                                        // remove elements that don't have a matching year when hasYear is true
                                        if (hasYear && Array.isArray(keyValueObject["VehiclePreference"])) {
                                            keyValueObject["VehiclePreference"] = keyValueObject["VehiclePreference"].filter(function (el) {
                                                return el._year === year;
                                            })
                                        }


                                    })

                                }
                                originalSuccess(resp);
                            }catch(err){
                                originalSuccess([{
                                    VehiclePreference:[]
                                }])
                            }
                        };
                        FPS.get([keyValueObject],callbacks);
                    }

                },
            }
        });
        DeepMerge( window.FPS, {
            lib: {
                AudienceTracking: function (audienceId) {

                    if(typeof audienceId !== "string") return false;
                    if(audienceId.length > 20) return false;

                    return {
                        AudienceTracking: {
                            _audienceId: audienceId
                        }
                    };
                }
            }
        });
        DeepMerge( window.FPS, {
            QuizResult: {
                get: function (quizId,callbacks) {

                    quizId = quizId || "";

                    FPS.get([{QuizResult:{}}],{
                        success(resp){
                            if(callbacks && callbacks.success){
                                if(Array.isArray(resp)) {
                                    for (let i = 0; i < resp.length; i++) {
                                        let current = resp[i];
                                        if(current && Array.isArray(current.QuizResult)){
                                            for(let k=0; k < current.QuizResult.length; k++) {
                                                let result = current.QuizResult[k];
                                                if (result && result._id === quizId) {
                                                    try {
                                                        callbacks.success(JSON.parse(result.result) || null);
                                                    }catch(err){
                                                        callbacks.success(result && result.result || null);
                                                    }
                                                    return;
                                                }
                                            }
                                        }
                                    }
                                }
                                callbacks.success(null);
                            }
                        },
                        error(err){
                            if(callbacks && callbacks.error){
                                callbacks.error(err);
                            }
                        }
                    });

                },
                set: function(quizId,quizResult,callbacks){

                    quizId = quizId || "";
                    quizResult = quizResult || {};

                    if(typeof quizResult !== "string"){
                        try{
                            quizResult = JSON.stringify(quizResult);
                        }catch(err){

                        }
                    }

                    FPS.set([{QuizResult:{_id:quizId,result:quizResult}}],{
                        success(resp){
                            if(callbacks && callbacks.success){
                                callbacks.success(resp);
                            }
                        },
                        error(err){
                            if(callbacks && callbacks.error){
                                callbacks.error(err);
                            }
                        }
                    });
                }
            }
        });
        DeepMerge( window.FPS, {
            OfInterest: {
                set: function (ofInterestType, ofInterestValue, callbacks) {
                    ofInterestValue = ofInterestValue || {};
                    if (typeof ofInterestType !== "string") {
                        if (callbacks && typeof callbacks.error === "function") {
                            callbacks.error();
                        }
                        return;
                    }
                    const actionkey = `OfInterest_${ofInterestType}`
                    if (ofInterestType === "ExteriorColor") {
                        let _normalized = ofInterestValue.normalized;
                        let _specificName = ofInterestValue.specificName;
                        let _value = ofInterestValue.value;
                        let score = ofInterestValue.score;
                        if (_normalized && _specificName && _value) {
                            let requestValue = {
                                [actionkey]: {
                                    _normalized: _normalized,
                                    _specificName: _specificName,
                                    _value: _value
                                }
                            }

                            if (typeof score === "number") {
                                requestValue.metadata = {
                                    score: score
                                };
                            }
                            FPS.set([requestValue], callbacks);
                            return;
                        }
                    }
                    if (callbacks && typeof callbacks.error === "function") {
                        callbacks.error();
                    }
                },
                get: function (type, callbacks) {
                    if (!callbacks || (callbacks && typeof callbacks.success !== "function") || (callbacks && typeof callbacks.error !== "function")) return;
                    if (type === "ExteriorColor") {
                        FPS.get([{OfInterest_ExteriorColor: {}}], {
                            success(resp) {
                                let first = resp[0]['OfInterest_ExteriorColor'];
                                first.sort(function (a, b) {
                                    let scoreComparisonResult = b.score - a.score;
                                    if (scoreComparisonResult !== 0) {
                                        return scoreComparisonResult;
                                    }

                                    if (a.on < b.on) return 1;
                                    if (a.on > b.on) return -1;

                                    return 0;
                                });

                                if(first.length === 0){
                                    callbacks.success(null);
                                    return;
                                }

                                let result = {
                                    type: type,
                                    normalized: first[0]._normalized,
                                    specificName: first[0]._specificName,
                                    value: first[0]._value
                                }
                                callbacks.success(result);
                            },
                            error(err) {
                                callbacks.error();
                            }
                        });
                        return;
                    }
                    callbacks.error();
                }
            }
        });

        try {
            window.FPS = {
                ...window.FPS,
                RVA: {
                    Set(type, props) {
                        return new Promise((resolve, reject) => {
                            const key = "RecentlyViewed" + type;

                            switch (type) {
                                case "Article":
                                    const {articleTitle, articleLink} = props || {};
                                    if (!articleTitle || !articleLink) {
                                        reject({"message": "articleTitle and articleLink must be defined"});
                                        return;
                                    }
                                    FPS.set(
                                        [{[key]: {_articleTitle: articleTitle, articleLink}}],
                                        {success: resolve, error: reject}
                                    )
                                    break;
                                default:
                                    console.log({type});
                                    reject({message: `RVA.Set type: [${type}] not found. Invalid RVA.Set type`});
                                    break;
                            }
                        });
                    },
                    Get(type, props) {
                        return new Promise((resolve, reject) => {
                            const key = "RecentlyViewed" + type;

                            switch (type) {
                                case "Article":
                                    FPS.get(
                                        [{[key]: {}}],
                                        {
                                            success(resp) {
                                                for (let obj of resp) {
                                                    if (Array.isArray(obj[key])) {
                                                        const sorted = obj[key].sort((a, b) => {
                                                            if (a.on < b.on) return 1;
                                                            if (a.on > b.on) return -1;
                                                            return 0;
                                                        });

                                                        const result = sorted.map(({
                                                                                       _articleTitle = "",
                                                                                       articleLink = ""
                                                                                   }) => {
                                                            return {articleLink, articleTitle: _articleTitle}
                                                        });
                                                        resolve(result);
                                                        return;
                                                    }
                                                }
                                                resolve([]);
                                            },
                                            error: reject
                                        }
                                    )
                                    break;
                                default:
                                    reject({message: `RVA.Get type: [${type}] not found. Invalid RVA.Get type`});
                                    break;
                            }
                        });
                    },
                    Forget(type, props) {
                        return new Promise((resolve, reject) => {
                            const key = "RecentlyViewed" + type;

                            switch (type) {
                                case "Article":
                                    const {articleTitle, articleLink} = props || {};
                                    if (!articleTitle) {
                                        reject({"message": "articleTitle must be defined"});
                                        return;
                                    }

                                    let requestProps = {_articleTitle: articleTitle};

                                    if (articleLink) {
                                        requestProps = {
                                            ...requestProps,
                                            articleLink
                                        }
                                    }

                                    FPS.set(
                                        [{[key]: requestProps, metadata: {active: false}}],
                                        {success: resolve, error: reject}
                                    )
                                    break;
                                default:
                                    reject({message: `RVA.Forget type: [${type}] not found. Invalid RVA.Forget type`});
                                    break;
                            }
                        });
                    },
                    Type: {
                        Article: "Article"
                    }
                },
            };


            window.FPS = {
                ...window.FPS,
                Status: {
                    Set(status){
                        return new Promise((resolve,reject)=>{

                            if(!status){
                                return reject(false);
                            }

                            FPS.set([{Status:{_status:status}}],{
                                success: () => resolve(true),
                                error: () => reject(false)
                            })
                        })
                    },
                    Get(status){
                        return new Promise((resolve,reject)=>{

                            FPS.get([{Status: {}}], {
                                success: (e) => {

                                    if(!status){
                                        return resolve(e);
                                    }

                                    for (let obj of e) {
                                        if (obj?.Status) {
                                            for(let item of obj?.Status){
                                                if(item?._status === status){
                                                    return resolve(true);
                                                }
                                            }
                                        }
                                    }
                                    reject(false);
                                },
                                error: (e) => reject(false),
                            });
                        })
                    },
                    Forget(status){
                        return new Promise((resolve,reject)=>{

                            if(!status){
                                return reject(false);
                            }

                            FPS.set([{Status:{_status:status},metadata: {active: false}}],{
                                success: () => resolve(true),
                                error: () => reject(false)
                            })
                        })
                    },
                    Type:{
                        Owner: "Owner"
                    }
                }
            }

            window.FPS = {
                ...window.FPS,
                NVC: {
                    Utils:{
                        normalizeReturnData(dataObject){

                            if(!dataObject){
                                return dataObject;
                            }

                            let response = {};
                            for( let [key,value] of Object.entries(dataObject) ){
                                if(!/^_/.test(key)){
                                    response[key] = value;
                                    continue;
                                }

                                response[key.slice(1)] = value;
                            }
                            return response;
                        }
                    },
                    Wishlist: {
                        Set(wishlistSetObject = {}, callbacks = {
                            success() {
                            }, error() {
                            }
                        }) {

                            let {
                                Category,
                                UID,
                                ProductImageUrl,
                                ProductName,
                                ProductPageUrl,
                                active,
                            } = wishlistSetObject;

                            const isValidInput = typeof Category === "string" &&
                                typeof UID === "string" &&
                                typeof ProductImageUrl === "string" &&
                                typeof ProductName === "string" &&
                                typeof ProductPageUrl === "string";

                            if (!isValidInput) {
                                callbacks?.error?.();
                                return false;
                            }

                            let setObject = {
                                "NVCWishlist": {
                                    _Category: Category,
                                    _UID: UID,
                                    ProductImageUrl,
                                    ProductName,
                                    ProductPageUrl,
                                }
                            }

                            if (active === "false" || active === false) {
                                setObject = {
                                    ...setObject,
                                    metadata: {
                                        active: false
                                    }
                                }
                            }

                            FPS.set([setObject], callbacks);

                        },
                        Get(wishlistGetObject,callbacks,{normalize} = {normalize:true}) {

                            if (!wishlistGetObject && !callbacks) {
                                return false;
                            }

                            let Category = "";
                            let UID = "";

                            if (!callbacks) {
                                callbacks = wishlistGetObject;
                            } else {
                                Category = wishlistGetObject?.Category || "";
                                UID = wishlistGetObject?.UID || "";
                            }

                            const isValidInput = typeof Category === "string" && typeof UID === "string";

                            if (!isValidInput) {
                                callbacks?.error?.();
                                return false;
                            }

                            let requestObject = {
                                "NVCWishlist": {}
                            }

                            if (Category && UID) {

                                FPS.get([requestObject], {
                                    success(e) {

                                        if (!Array.isArray(e)) callbacks?.error?.(e);

                                        let match = null;

                                        for( let entry of e ){
                                            if(!Array.isArray(entry.NVCWishlist) ){
                                                continue;
                                            }

                                            for( let item of entry.NVCWishlist ){
                                                if(item?._Category === Category && item?._UID === UID){
                                                    match = item;
                                                    break;
                                                }
                                            }

                                            if(match != null){
                                                break;
                                            }
                                        }

                                        if(match){
                                            match = normalize ? FPS.NVC.Utils.normalizeReturnData(match) : match
                                        }

                                        callbacks?.success?.( match );
                                    },
                                    error(e) {
                                        callbacks?.error?.(e);
                                    }
                                });

                                return;
                            } else if (Category) {

                                FPS.get([requestObject], {
                                    success(e) {

                                        let response = [];

                                        for (let entry of e) {
                                            if (entry.NVCWishlist) {
                                                response = entry.NVCWishlist.reduce((accum, current) => {
                                                    if (current?._Category === Category) {
                                                        accum.push(
                                                            normalize ? FPS.NVC.Utils.normalizeReturnData(current) : current
                                                        );
                                                    }
                                                    return accum;
                                                }, response);
                                            }
                                        }

                                        callbacks?.success?.( response || []);

                                    },
                                    error(e) {
                                        callbacks?.error?.(e);
                                    }
                                });

                                return;
                            }

                            FPS.get([requestObject], {
                                success(e) {
                                    if (!Array.isArray(e)) callbacks?.error?.(e);

                                    let response = {};

                                    for (let entry of e) {
                                        if (entry.NVCWishlist) {
                                            response = entry.NVCWishlist.reduce((accum, current) => {
                                                if (typeof current?._Category === "string") {
                                                    if (!accum[current._Category]) {
                                                        accum[current._Category] = [];
                                                    }

                                                    accum[current._Category].push(
                                                        normalize ? FPS.NVC.Utils.normalizeReturnData(current) : current
                                                    );
                                                }
                                                return accum;
                                            }, response);
                                        }
                                    }

                                    if(Object.keys(response).length > 0) {
                                        callbacks?.success?.(response);
                                        return;
                                    }

                                    callbacks?.success?.(null);
                                },
                                error(e) {
                                    callbacks?.error?.(e);
                                }
                            });

                        },
                        Forget(wishlistGetObject,callbacks) {

                            if(!wishlistGetObject && !callbacks){
                                return false;
                            }

                            let Category = "";
                            let UID = "";

                            if(!callbacks){
                                callbacks = wishlistGetObject;
                            }else{
                                Category = wishlistGetObject?.Category || "";
                                UID = wishlistGetObject?.UID || "";
                            }

                            const isValidInput = typeof Category === "string" && typeof UID === "string";

                            if(!isValidInput){
                                callbacks?.error?.();
                                return false;
                            }

                            FPS.NVC.Wishlist.Get({Category, UID}, {
                                success(item) {

                                    if(item == null){
                                        callbacks?.success?.(item);
                                        return;
                                    }

                                    try{
                                        FPS.NVC.Wishlist.Set({
                                            Category: item._Category,
                                            UID: item._UID,
                                            ProductImageUrl: item.ProductImageUrl,
                                            ProductName: item.ProductName,
                                            ProductPageUrl: item.ProductPageUrl,
                                            active: false
                                        }, callbacks);
                                    }catch(err){
                                        callbacks?.error?.(err);
                                    }
                                },
                                error(e) {
                                    callbacks?.error?.(e);
                                }
                            },{normalize: false});

                        }
                    },
                    Preference:{
                        Set(preferenceObject = {}, callbacks = {success(){},error(){}}){
                            try {
                                let {
                                    Category,
                                    Make,
                                    Model,
                                    Year,
                                    Trim,
                                    Engine,
                                    Transmission,
                                    VehicleImageUrl,
                                    active
                                } = preferenceObject;

                                const isValidInput = typeof Category === "string" &&
                                    typeof Make === "string" &&
                                    typeof Model === "string" &&
                                    typeof Year === "string";

                                if (!isValidInput) {
                                    callbacks?.error?.();
                                    return false;
                                }

                                let setObject = {
                                    "NVCPreference": {
                                        _Category: Category,
                                        _Make: Make,
                                        _Model: Model,
                                        _Year: Year,
                                    }
                                }

                                if (typeof Trim === "string") {
                                    setObject.NVCPreference._Trim = Trim;
                                }
                                if (typeof Engine === "string") {
                                    setObject.NVCPreference._Engine = Engine;
                                }
                                if (typeof Transmission === "string") {
                                    setObject.NVCPreference._Transmission = Transmission;
                                }
                                if (typeof VehicleImageUrl === "string") {
                                    setObject.NVCPreference.VehicleImageUrl = VehicleImageUrl;
                                }

                                if (active === "false" || active === false) {
                                    setObject = {
                                        ...setObject,
                                        metadata: {
                                            active: false
                                        }
                                    }
                                }

                                FPS.set([setObject], callbacks);
                            }catch(err){
                                console.log(err);
                            }
                        },
                        Get(preferenceGetObject,callbacks,{normalize} = {normalize:true}) {

                            if (!preferenceGetObject && !callbacks) {
                                return false;
                            }

                            let Category = "";
                            let UID = "";
                            let Make = "";
                            let Model = "";
                            let Year = "";
                            let Trim = "";
                            let Engine = "";
                            let Transmission = "";

                            if (!callbacks) {
                                callbacks = preferenceGetObject;
                            } else {
                                Category = preferenceGetObject?.Category || "";
                                Make = preferenceGetObject?.Make || "";
                                Model = preferenceGetObject?.Model || "";
                                Year = preferenceGetObject?.Year || "";
                                Trim = preferenceGetObject?.Trim || "";
                                Engine = preferenceGetObject?.Engine || "";
                                Transmission = preferenceGetObject?.Transmission || "";
                            }

                            const isValidInput = typeof Category === "string" &&
                                typeof Make === "string" &&
                                typeof Model === "string" &&
                                typeof Year === "string" &&
                                typeof Trim === "string" &&
                                typeof Engine === "string" &&
                                typeof Transmission === "string";

                            if (!isValidInput) {
                                callbacks?.error?.();
                                return false;
                            }

                            let requestObject = {
                                "NVCPreference": {}
                            }

                            let filterProps = [
                                {key: "_Category", value: Category},
                                {key: "_Make", value: Make},
                                {key: "_Model", value: Model},
                                {key: "_Year", value: Year},
                                {key: "_Trim", value: Trim},
                                {key: "_Engine", value: Engine},
                                {key: "_Transmission", value: Transmission}
                            ].filter( el => el.value);

                            if(Category && (Make || Model || Year || Trim || Engine || Transmission)) {

                                FPS.get([requestObject], {
                                    success(e) {
                                        if (!Array.isArray(e)) callbacks?.error?.(e);

                                        let response = null;

                                        for (let entry of e) {
                                            if (entry.NVCPreference) {
                                                response = entry.NVCPreference.reduce((accum, current) => {
                                                    if( accum == null) {
                                                        let result = filterProps.reduce((_accum,_current)=>{
                                                            if( _accum === true ){
                                                                if( current[_current?.key] !== _current?.value ){
                                                                    _accum = false;
                                                                }
                                                            }
                                                            return _accum;
                                                        },true);
                                                        //
                                                        if(result) {
                                                            accum = normalize ? FPS.NVC.Utils.normalizeReturnData(current) : current;
                                                        }
                                                    }

                                                    return accum;
                                                }, response);
                                            }
                                        }

                                        callbacks?.success?.(response);
                                    },
                                    error(e) {
                                        callbacks?.error?.(e);
                                    }
                                });

                                return;
                            } else if(Category){

                                FPS.get([requestObject], {
                                    success(e) {
                                        if (!Array.isArray(e)) callbacks?.error?.(e);

                                        let response = {};

                                        for (let entry of e) {
                                            if (entry.NVCPreference) {
                                                response = entry.NVCPreference.reduce((accum, current) => {
                                                    if (typeof current?._Category === "string") {
                                                        if (!accum[current._Category]) {
                                                            accum[current._Category] = [];
                                                        }

                                                        accum[current._Category].push(
                                                            normalize ? FPS.NVC.Utils.normalizeReturnData(current) : current
                                                        );
                                                    }
                                                    return accum;
                                                }, response);
                                            }
                                        }

                                        if(Object.keys(response).length > 0) {
                                            callbacks?.success?.( response?.[Category] || [] );
                                            return;
                                        }

                                        callbacks?.success?.([]);
                                    },
                                    error(e) {
                                        callbacks?.error?.(e);
                                    }
                                });

                                return;
                            }

                            FPS.get([requestObject], {
                                success(e) {
                                    if (!Array.isArray(e)) callbacks?.error?.(e);

                                    let response = {};

                                    for (let entry of e) {
                                        if (entry.NVCPreference) {
                                            response = entry.NVCPreference.reduce((accum, current) => {
                                                if (typeof current?._Category === "string") {
                                                    if (!accum[current._Category]) {
                                                        accum[current._Category] = [];
                                                    }

                                                    accum[current._Category].push(
                                                        normalize ? FPS.NVC.Utils.normalizeReturnData(current) : current
                                                    );
                                                }
                                                return accum;
                                            }, response);
                                        }
                                    }

                                    if(Object.keys(response).length > 0) {
                                        callbacks?.success?.(response);
                                        return;
                                    }

                                    callbacks?.success?.(null);
                                },
                                error(e) {
                                    callbacks?.error?.(e);
                                }
                            });

                        },
                        Forget(preferenceGetObject, callbacks){
                            if(!preferenceGetObject && !callbacks){
                                return false;
                            }

                            let Category = "";
                            let UID = "";
                            let Make = "";
                            let Model = "";
                            let Year = "";
                            let Trim = "";
                            let Engine = "";
                            let Transmission = "";

                            if(!callbacks){
                                callbacks = preferenceGetObject;
                            }else{
                                Category = preferenceGetObject?.Category || "";
                                Make = preferenceGetObject?.Make || "";
                                Model = preferenceGetObject?.Model || "";
                                Year = preferenceGetObject?.Year || "";
                                Trim = preferenceGetObject?.Trim || "";
                                Engine = preferenceGetObject?.Engine || "";
                                Transmission = preferenceGetObject?.Transmission || "";
                            }

                            const isValidInput = typeof Category === "string" &&
                                typeof Make === "string" &&
                                typeof Model === "string" &&
                                typeof Year === "string" &&
                                typeof Trim === "string" &&
                                typeof Engine === "string" &&
                                typeof Transmission === "string";

                            if(!isValidInput){
                                callbacks?.error?.();
                                return false;
                            }

                            let filterProps = [
                                {key: "Category", value: Category},
                                {key: "Make", value: Make},
                                {key: "Model", value: Model},
                                {key: "Year", value: Year},
                                {key: "Trim", value: Trim},
                                {key: "Engine", value: Engine},
                                {key: "Transmission", value: Transmission}
                            ].filter( el => el.value);

                            let getRequestObject = filterProps.reduce((accum,current)=>{

                                accum[current.key] = current.value;

                                return accum;
                            },{});

                            FPS.NVC.Preference.Get(getRequestObject, {
                                success(item) {

                                    if(item == null){
                                        callbacks?.success?.(null);
                                        return;
                                    }

                                    try{

                                        let setfilterProps = [
                                            {key: "Category", value: item?._Category},
                                            {key: "Make", value: item?._Make},
                                            {key: "Model", value: item?._Model},
                                            {key: "Year", value: item?._Year},
                                            {key: "Trim", value: item?._Trim},
                                            {key: "Engine", value: item?._Engine},
                                            {key: "Transmission", value: item?._Transmission},
                                            {key: "VehicleImageUrl", value: item?.VehicleImageUrl},
                                        ].filter( el => el.value)
                                            .reduce((accum,current)=>{
                                                accum[current.key] = current.value;
                                                return accum;
                                            },{});
                                        FPS.NVC.Preference.Set({
                                            ...setfilterProps,
                                            active: false
                                        }, callbacks);

                                    }catch(err){
                                        callbacks?.error?.(err);
                                    }
                                },
                                error(e) {
                                    callbacks?.error?.(e);
                                }
                            },{normalize: false});
                        }
                    },
                    PreferredDealer:{
                        Set(dealerId, callbacks = {success(){},error(){}}){
                            try{

                                if(!dealerId || typeof dealerId !== "string"){
                                    return;
                                }

                                let setObject = {
                                    NVCPreferredDealer: {
                                        dealerId: dealerId
                                    }
                                };

                                FPS.set([setObject],callbacks);
                            }catch(err){
                                console.log(err);
                            }
                        },
                        Get(callbacks){
                            if (!callbacks) {
                                return;
                            }

                            let getObject = {
                                NVCPreferredDealer: {}
                            };

                            FPS.get([getObject], {
                                success(e) {
                                    try {
                                        if (!Array.isArray(e)) {
                                            callbacks?.error?.(e);
                                            return;
                                        }

                                        if (e.length === 0) {
                                            callbacks?.success?.(null);
                                            return;
                                        }

                                        let preferredDealer = e[0]?.NVCPreferredDealer || null;

                                        if (!preferredDealer) {
                                            callbacks?.error?.(e);
                                            return;
                                        }

                                        let dealerId = preferredDealer[0]?.dealerId || null;

                                        callbacks?.success?.(dealerId);

                                    }catch(err){
                                        callbacks?.error?.(err);
                                    }
                                },
                                error(err) {
                                    callbacks?.error?.(err);
                                }
                            });
                        },
                        Forget(callbacks = {success(){},error(){}}){

                            let setObject = {
                                NVCPreferredDealer: {},
                                metadata: {
                                    active: false
                                }
                            };

                            FPS.set([setObject], callbacks);
                        }
                    }
                }
            }

        }catch(e){
            // silently handle error
        }

        try{

            window.FPS = {
                ...window.FPS,
                Cart: {
                    Set(Category, value) {

                        if (Category !== "NonVehicleCart" && Category !== "VehicleCart") {
                            return Promise.reject("Invalid Category");
                        }

                        if (typeof value !== "number" || value < 0) {
                            return Promise.reject("Invalid Value");
                        }

                        return new Promise(async (resolve, reject) => {

                            const authStatus = await internals.getFMAAuthenticationStatus();

                            let setData = {
                                CartItems: {
                                    _Category: Category,
                                    value
                                },
                                suffix: authStatus === true ? "1" : "0"
                            };

                            if (value === 0) {
                                setData = {
                                    ...setData,
                                    metadata: {active: false}
                                }
                            }

                            showCartIcon(value > 0);

                            FPS.set([setData], {
                                success(e) {
                                    resolve(e);
                                },
                                error(e) {
                                    reject(e);
                                }
                            });
                        });
                    },
                    Get() {

                        return new Promise(async (resolve, reject) => {
                            const authStatus = await internals.getFMAAuthenticationStatus();

                            let resolveDataByAuthState = {
                                "true": (resp) => {
                                    // return checkForCartItem(formatResponse(handleCartItemsResponse(resp)));
                                    return [
                                        handleCartItemsResponse,
                                        formatResponse,
                                        checkForCartItem
                                    ].reduce((accum, current) => current(accum),resp);
                                },
                                "false": (resp) => {
                                    // return checkForCartItem(formatResponse(filterOutExpiredData(handleCartItemsResponse(resp))));
                                    return [
                                        handleCartItemsResponse,
                                        filterOutExpiredData,
                                        formatResponse,
                                        checkForCartItem
                                    ].reduce((accum, current) => current(accum),resp);
                                },
                            }

                            FPS.get([{
                                CartItems: {
                                    suffixFilter: [authStatus === true ? "1" : "0"]
                                }
                            }], {
                                success(resp) {

                                    resolve(resolveDataByAuthState[authStatus === true](resp));

                                },
                                error(resp) {
                                    reject(resp);
                                }
                            });
                        });
                    }
                }
            }

            let cartExpirationTime = 90; // minutes, for unauthenticated data

            let filterCartItemsResponseBySuffix = function (suffix) {
                return (cartItems)=> {
                    return cartItems.filter(item => {
                        return item.suffix === suffix;
                    });
                }
            }

            let getTimeDiffInMinutes = function (timeInPast) {
                return Math.floor((Date.now() - new Date(timeInPast).getTime()) / 1000 / 60);
            }

            let filterOutExpiredData = function (cartItems) {

                if(cartExpirationTime === 0){
                    return cartItems;
                }

                return cartItems.filter(item => getTimeDiffInMinutes(item.on) < cartExpirationTime);
            }

            let getExpiredData = function (cartItems) {

                if(cartExpirationTime === 0){
                    return [];
                }

                return cartItems.filter(item => getTimeDiffInMinutes(item.on) >= cartExpirationTime);
            }

            let formatResponse = function (cartItems) {

                let response = {};

                if(!cartItems || !Array.isArray(cartItems)){
                    return {
                        NonVehicleCart: 0,
                        VehicleCart: 0
                    }
                }

                for (let entry of cartItems) {
                    if (typeof response[entry._Category] !== "number") {
                        response[entry._Category] = entry.value;
                    }
                }

                return {
                    NonVehicleCart: response.NonVehicleCart || 0,
                    VehicleCart: response.VehicleCart || 0
                };
            }

            let handleCartItemsResponse = function (resp){

                let cartItems = [];

                if(!Array.isArray(resp)){
                    return [];
                }

                for( let i =0; i < resp.length; i++ ){
                    for( let key of Object.keys(resp[i]) ){
                        if(key === "CartItems"){
                            cartItems = [...cartItems,...resp[i][key]];
                        }
                    }
                }

                return cartItems;
            }

            let getRawCartData = function (cartItems){
                return new Promise((resolve,reject)=>{
                    FPS.get([{CartItems:{}}],{
                        success(e){
                            resolve(e);
                        },
                        error(e){
                            reject(e);
                        }
                    })
                })
            }

            let checkForCartItem = function(result){
                let hasItemInCart = Object.values(result)
                    .reduce((accum, current) => {
                        if (current > 0) {
                            return true;
                        }
                        return accum;
                    }, false);

                showCartIcon(hasItemInCart);

                return result;
            };

            let checkForCartIcon = function(target){
                return new Promise((resolve)=>{

                    if(document.querySelector("#brand-nav-cart-full-lnk")){
                        resolve();
                        return;
                    }

                    let bodyObserver = new MutationObserver((mutationList, observer) => {
                        for (const mutation of mutationList) {
                            if( document.querySelector("#brand-nav-cart-full-lnk") ){
                                observer.disconnect();
                                resolve();
                                break;
                            }
                        }
                    });

                    bodyObserver.observe(document.body, {
                        attributes: true,
                        childList: true,
                        subtree: true
                    });

                });
            };

            let showCartIcon = function(show, {onload} = {onload:false}){

                if( !hasValidCartBrandCountry() ){
                    return;
                }

                checkForCartIcon()
                    .then(()=>{
                        let iconClassList = document.querySelector("#brand-nav-cart-full-lnk")?.classList;

                        let removeIconHiddenState = {
                            "true":()=>{

                                if( onload === true && canShowCartIcon() === false ){
                                    return;
                                }

                                setTimeout(()=>{
                                    iconClassList?.remove?.("hidden");

                                    let cartIconObserver = new MutationObserver((mutationList, observer) => {
                                        for (let mutation of mutationList) {
                                            mutation?.target?.classList?.remove?.("hidden");
                                            observer.disconnect();
                                            break;
                                        }
                                    });

                                    // Start observing the target node for configured mutations
                                    cartIconObserver.observe(document.querySelector("#brand-nav-cart-full-lnk"), {
                                        attributes: true,
                                        childList: false,
                                        subtree: false
                                    });
                                },100);
                            }
                        }

                        let addIconHiddenState = {
                            "false":()=>{
                                iconClassList?.add?.("hidden");

                                let cartIconObserver = new MutationObserver((mutationList, observer) => {
                                    for (let mutation of mutationList) {
                                        mutation?.target?.classList?.add?.("hidden");
                                        observer.disconnect();
                                        break;
                                    }
                                });

                                // Start observing the target node for configured mutations
                                cartIconObserver.observe(document.querySelector("#brand-nav-cart-full-lnk"), {
                                    attributes: true,
                                    childList: false,
                                    subtree: false
                                });
                            }
                        }

                        let iconShowStates = {
                            "true":()=>{
                                removeIconHiddenState[iconClassList?.contains("hidden")]?.();
                            },
                            "false":()=>{
                                addIconHiddenState[iconClassList?.contains("hidden")]?.();
                            }
                        }

                        iconShowStates[show === true]?.();
                    })
                    .catch(console.warn);

            }

            let hasValidCartBrandCountry = function(){
                return tagBrand === "Ford" && tagCountry === "USA";
            }

            let canShowCartIcon = function(){
                return /^https:\/\/(?:www(?:qa)?|(?:edu\.|qa\.)?accessories)\.ford\.com\/(?:accessories|vl\/ford|search|cl|product|cart)/gi.test(window.location.href);
            };

            window.document.addEventListener("FPS:Loaded",function handler() {
                window.document.removeEventListener("FPS:Loaded", handler);

                if( !hasValidCartBrandCountry() ){
                    return;
                }

                let authCheck = internals.getFMAAuthenticationStatus();
                let getCart = getRawCartData();

                Promise.allSettled([authCheck, getCart]).then((values) => {
                    let [auth, cart] = values;

                    cart.value = cart.value || [];

                    let authCart = [
                        handleCartItemsResponse,
                        filterCartItemsResponseBySuffix("1"),
                        formatResponse
                    ]
                        .reduce((accum, current) => current(accum),cart.value);

                    let unAuthCart = [
                        handleCartItemsResponse,
                        filterCartItemsResponseBySuffix("0"),
                        filterOutExpiredData,
                        formatResponse
                    ]
                        .reduce((accum, current) => current(accum),cart.value);

                    let expiredCarts = [
                        handleCartItemsResponse,
                        filterCartItemsResponseBySuffix("0"),
                        getExpiredData,
                    ]
                        .reduce((accum, current) => current(accum),cart.value);


                    let userIsAuthenticated = auth.value === true;

                    let hasUnAuthCart = Object.values(unAuthCart)
                        .reduce((accum, current) => {
                            if (current > 0) {
                                return true;
                            }
                            return accum;
                        }, false);

                    let hasAuthCart = Object.values(authCart)
                        .reduce((accum, current) => {
                            if (current > 0) {
                                return true;
                            }
                            return accum;
                        }, false);

                    if(userIsAuthenticated && hasUnAuthCart){
                        FPS.set([{
                            CartItems: {
                                _Category: "NonVehicleCart",
                                value: 1
                            },
                            suffix:"1"
                        },{
                            CartItems: {
                                _Category: "NonVehicleCart",
                                value: 0
                            },
                            suffix:"0",
                            metadata: { active: false }
                        }]);
                    }

                    if(userIsAuthenticated && hasAuthCart) {
                        showCartIcon(true, {onload: true});
                    }

                    if( hasUnAuthCart ) {
                        showCartIcon(true, {onload: true});
                    }

                    if(Array.isArray(expiredCarts) && expiredCarts.length > 0) {
                        let expiredSetData = expiredCarts.filter(item => item?._Category).map((item) => {
                            return {
                                CartItems: {
                                    _Category: item._Category,
                                        value: 0
                                },
                                suffix: "0",
                                    metadata: {active: false}
                            };
                        });

                        FPS.set(expiredSetData);
                    }

                });

            });

        }catch(e){

        }


// EXTENSIONS
    if (!personalizationActive) {
        // INACTIVE
        DeepMerge(window.FPS, {
            get: function (keyValueObjects, callbacks) {
                if (callbacks && callbacks.success) {
                    callbacks.success([], "success", null);
                }
            },
            set: function (keyValueObjects, callbacks) {
                if (callbacks && callbacks.success) {
                    callbacks.success([], "success", null);
                }
            },
            getAll: function (callbacks) {
                if (callbacks && callbacks.success) {
                    callbacks.success([], "success", null);
                }
            },
            setExternalRef: function (type, id, callbacks) {
                if (callbacks && callbacks.success) {
                    callbacks.success([], "success", null);
                }
            },
            setTargetCookie: function (callbacks) {
                if (callbacks && callbacks.success) {
                    callbacks.success([], "success", null);
                }
            }
        });

    }
    FPS.ManualXDC();
    if (FPS && FPS.Queue && FPS.Queue.SetQueue && typeof FPS.Queue.SetQueue === "function") {
        FPS.Queue.SetQueue();
    }
    if (FPS && FPS.Queue && FPS.Queue.GetQueue && typeof FPS.Queue.GetQueue === "function") {
        FPS.Queue.GetQueue();
    }
    if (RVVImpressionHandler && SetBus) {
        RVVImpressionHandler(window.FPS, SetBus);
    }

    function waitFor(maxWaitForCount){
        var waitForCount = 0;
        return function waitFor(target,fn,timeout){
            waitForCount += 1;
            if(waitForCount > maxWaitForCount){
                if(typeof timeout === "function") timeout();
                return;
            }
            if(target()){
                waitForCount = maxWaitForCount + 1;
                fn(target());
            }else{
                setTimeout(waitFor,100,target,fn,timeout);
            }
        }
    }

    (function() {

        var FPS = window.FPS || null;

        function scriptLoadInsight(name, url) {
            if(blockNetworkRequests === true) return false;
            if(disableInsights === true) return;
            try {
                var xhr = new XMLHttpRequest();
                var obj = {
                    url: url
                };
                xhr.open("post", xdcPathSet + "/api/insights/count/byurl/" + name.toLowerCase() + "/day");
                xhr.setRequestHeader("Content-Type", "application/json; charset=UTF-8");

                xhr.addEventListener("readystatechange", function() {});

                xhr.send(JSON.stringify(obj));
            } catch (err) {}
        }

        try {
            if (!FPS || !FPS.Cache || (FPS.Cache && !FPS.Cache.set) || Object.keys(FPS.Cache.set).length === 0) return false;
        } catch (err) {
            return false;
        }

        var waitForDigitalData = waitFor(100);

        waitForDigitalData(function(){
            return window.digitaldata && window.digitaldata.page && window.digitaldata.page.pageName ? window.digitaldata : undefined;
        },function runEdiOnLoad(_digitaldata){

            var dealer = JSON.parse(localStorage.getItem("dealer"));
            var url = window.location.href;

            try {
                var tier = FPS.Core.Insights.Utils.getTier("https://" + window.location.hostname);
                if (tier.toLowerCase() !== "tn") {
                    var urlPath = window.location.hostname + window.location.pathname;
                    if (urlPath.indexOf("wwwqa") > -1) {
                        if (xdcPath.indexOf("na.fps1") > -1)
                            scriptLoadInsight("prodscriptinqa", urlPath);

                    } else {
                        if (xdcPath.indexOf("na.fpsqa1") > -1)
                            scriptLoadInsight("qascriptinprod", urlPath);
                    }
                }

            } catch (err) {
                console.log(err);
            }

            try {
                if (tier.toLowerCase() === "tn") {
                    if (_digitaldata && _digitaldata.page && _digitaldata.page.pageName && _digitaldata.page.site && _digitaldata.page.site.indexOf("dealerinspire") > -1 && _digitaldata.page.pageName.indexOf("vehicle details") > -1) {
                        var UID = window.DITagLocalization.vehicleInfo.vin;
                        var paCode = window.DITagLocalization.oemDealerID;
                        var zip = window.DITagLocalization.dealer.postal_code;
                        var year = window.DITagLocalization.vehicleInfo.year;
                        var brand = window.DITagLocalization.vehicleInfo.make;
                        var nameplate = window.DITagLocalization.vehicleInfo.model;
                        var trim = window.DITagLocalization.vehicleInfo.trim;

                        FPS.set(FPS.lib.SpecificVehicleViewT3(UID, "DI", paCode, zip, year, brand, nameplate, trim, url, FPS.actions.SVVSIT3), {
                            success: function(data) {},
                            error: function() {}
                        });
                    }
                } else if( tier.toLowerCase() === "t2" ){
                    if( /^fdaf:t2:compare:3:details:/.test(digitaldata.page.pageName) ){
                        var healNameplate = FPS.Validation.healNameplate(vdmActiveNameplates,vdmActiveNameplatesMap);
                        var brandNameplate = digitaldata.page.pageName.split(":").slice(-1).join().split(" ");
                        var brand = brandNameplate[0].toLowerCase() === "ford" ? "Ford" : "Lincoln";
                        var nameplate = brandNameplate.slice(1).join(" ");
                        FPS.set(
                          [FPS.lib.ActionNameplateT2(
                            digitaldata.vehicle.modelYear,
                            "Ford",
                            healNameplate(nameplate),
                            window.location.href,
                            FPS.actions.HeadToHeadT2
                          )],{
                              success: function(e){
                                  console.log(e)
                              },
                              error:function(e){
                                  console.log(e)
                              }
                          }
                        );
                    }
                }
            } catch (err) {
                console.log(err)
            }
            if (dealer && dealer["code"]) {
                var dealerCode = dealer["code"].split("|")[1] ? dealer["code"].split("|")[1] : null;
                var searchFilters = window.location.hash.split('#config=')[1] || '';

                if (_digitaldata && _digitaldata.page && _digitaldata.page.pageName && _digitaldata.vehicle && _digitaldata.page.pageName.indexOf("edi:results") > -1) {
                    var pageName = _digitaldata.page.pageName;
                    var pageNameNoVehicle = _digitaldata.page.pageNameNoVehicle
                    var vehicle = _digitaldata.vehicle;
                    FPS.set(FPS.lib.RecentShowroomEDI(dealerCode, searchFilters, url, pageName, pageNameNoVehicle, vehicle), {
                        success: function(data) {},
                        error: function() {}
                    });
                }
                /*if (_digitaldata && _digitaldata.page && _digitaldata.page.pageName && _digitaldata.page.pageName.indexOf("edi:vehicle details") > -1) {

                var splitPathname = window.location.pathname.split('/').slice(2);
                var isInventory = splitPathname[0] === "inventory";

                if (isInventory === true) {
                    var ediVdpYear = splitPathname[1];
                    var ediVdpNameplate = splitPathname[2];
                    var ediVdpTrim = splitPathname[3];
                    var ediVin = splitPathname[4];
                    FPS.set(FPS.lib.SpecificVehicleView(ediVin, "EDI", dealerCode, dealerCode, ediVdpYear, tagBrand, ediVdpNameplate, ediVdpTrim, url, FPS.actions.SVVEDI), {
                        success: function(data) {},
                        error: function() {}
                    });
                }
            }*/
            }
        });

        let intentPageNames = [
            "flmo:owner:service-maintenance",
            "flmo:owner:coupons:all savings",
            "flmo:owner:coupons:oil change and maintenance",
            "flmo:owner:coupons:SR010:detail",
            "flmo:owner:coupons:tires",
            "flmo:owner:service-maintenance:coupons-offers-rebates/low-price-tire-guarantee",
            "flmo:service:tire finder:landing"
        ];

        let waitForVisitIntentDigitalData = waitFor(100);

        waitForVisitIntentDigitalData(function(){
            return window && window.digitaldata && window.digitaldata.page && window.digitaldata.page.pageNameNoVehicle;
        },function(value){
            if(typeof value === "string" && intentPageNames.includes(value)){
                FPS.set([{
                    "VisitIntent": {
                        "_intent": "Service",
                        "_timestamp": Date.now()
                    }
                }]);
            }
        });

        if((tier === "tn" || tier === "TN") && !window.sessionStorage.getItem("fps_lvd")) {

            let waitFordLastVisitedDealer = waitFor(30);

            waitFordLastVisitedDealer(function () {
                return window && window.digitaldata && window.digitaldata.user && window.digitaldata.user.paCode;
            }, function (paCode) {
                if (typeof paCode === "string") {
                    FPS.set([{
                        LastVisitedDealer: {
                            _paCode: paCode,
                            _time: new Date().toISOString()
                        }
                    }], {
                        success(e) {
                            console.log(e);
                            window.sessionStorage.setItem("fps_lvd","1");
                        },
                        error(e) {
                            console.log(e);
                        }
                    });
                }
            },function(){
                console.log("could not find paCode");
            })

        }

        function overrideFunction(target, methodName, newFunction) {

            var original = target && typeof target[methodName] === 'function' ? target[methodName] : null;

            if (typeof original === 'function') {

                target[methodName] = newFunction(original, target);

            }

            return original;

        }

        function removeValueFromStart(original, remove) {

            try {

                var removeFrom = original.indexOf(remove);

                if (removeFrom === -1) {
                    return original;
                }

                return original.slice(removeFrom + remove.length);

            } catch (err) {
                return original;
            }
        }

        function verifyT1UrlOrigin(urlString) {
            return checkT1(urlString);
        }
        //FPS-606 - SCA-C
        function getAllUrlParams(url) {

            // get query string from url (optional) or window
            var queryString = url ? url.split('?')[1] : window.location.search.slice(1);

            // we'll store the parameters here
            var obj = {};

            // if query string exists
            if (queryString) {

                // stuff after # is not part of query string, so get rid of it
                queryString = queryString.split('#')[0];

                // split our query string into its component parts
                var arr = decodeURIComponent(queryString).split("&");
                for (var i = 0; i < arr.length; i++) {
                    // separate the keys and the values
                    var a = arr[i].split('=');

                    // set parameter name and value (use 'true' if empty)
                    var paramName = a[0];
                    var paramValue = typeof(a[1]) === 'undefined' ? true : a[1];

                    // (optional) keep case consistent
                    paramName = paramName.toLowerCase();
                    if (typeof paramValue === 'string') paramValue = paramValue.toLowerCase();

                    if (!obj[paramName]) {
                        obj[paramName] = paramValue;
                    } else if (obj[paramName] && typeof obj[paramName] === 'string') {
                        // if property does exist and it's a string, convert it to an array
                        obj[paramName] = [obj[paramName]];
                        obj[paramName].push(paramValue);
                    } else {
                        // otherwise add the property
                        obj[paramName].push(paramValue);
                    }
                }
            }
            return obj;
        }

        var fpiCookie = cookie.get('FPI');
        var fmake = "";
        var fzip = "";
        var fmodel = "";
        var fyear = "";
        var cookieVars = "";
        var par = "";

        if (fpiCookie && fpiCookie.length > 0 && typeof FPS.lib.FPICookie !== 'undefined') {
            cookieVars = decodeURIComponent(fpiCookie).split("&");
            for (let i = 0; i < cookieVars.length; i++) {
                par = cookieVars[i].split("=");
                if (par[0] == "make") {
                    fmake = par[1];
                } else if (par[0] == "zip") {
                    fzip = par[1];
                } else if (par[0] == "model") {
                    fmodel = par[1];
                } else if (par[0] == "year") {
                    fyear = par[1];
                }
            }
            setTimeout(function() {
                FPS.set([FPS.lib.FPICookie(
                    Encode(fmake),
                    Encode(fzip),
                    Encode(fyear),
                    Encode(fmodel)
                )]);
            }, 500);
        }


        // FPS Set ExternalRef Override
        //
        var origin = window.location.protocol + "//" + window.location.hostname;
        var originVerified = verifyT1UrlOrigin(origin);

        var anonSetEntries = [];
        var s_ecid = Encode(cookie.get('s_ecid') || "");
        s_ecid = removeValueFromStart(s_ecid, "MCMID%7C");
        if (typeof s_ecid === 'string' && s_ecid.trim() !== "") {
            anonSetEntries.push({
                AnonymousRef: {
                    _type: 'ECID',
                    id: s_ecid,
                    _url: window.location.hostname
                }
            })
        }
        if (FPS && originVerified === true) {
            var scac_id = getAllUrlParams(window.location.href).cks;
            if (typeof scac_id === 'string' && scac_id.trim() !== "") {
                anonSetEntries.push({
                    AnonymousRef: {
                        _type: 'SCA-C',
                        id: scac_id,
                        _url: window.location.hostname
                    }
                })
            }
        }

        if (anonSetEntries.length > 0) {
            FPS.set(anonSetEntries, {
                success: function() {},
                error: function() {}
            });
        }
        // Set Document.Referrer
        //
        try {

            if (!document.querySelector('meta[name=referrer]') && checkT1(window.location.href)) {

                var meta = document.createElement('meta');

                meta.setAttribute('name', 'referrer');
                meta.setAttribute('content', 'origin');

                document.head.prepend(meta);

            }

        } catch (err) {

        }
        if (window && window.FPS && !window.fpsSettingOnload) {
            window.fpsSettingOnload = true;
            if (FPS && FPS.Core && FPS.Core.Insights && typeof FPS.Core.Insights.onPageLoad === "function") {
                // FPS.Core.Insights.onPageLoad();
            }
            //Handle any BackOffice Requests DNS
            if (FPS && gt_dns === null) {
                FPS.get([{
                    CCPA: {
                        suffixFilter: ['DNS']
                    }
                }], {
                    success: function(data) {
                        for (var i = 0; i < data[0].CCPA.length; i++) {
                            //fetch the only dns entry from the personalization data to compare with the requesting domain for dns
                            if (data[0].CCPA[i]['_site'] === window.location.hostname.split(".").slice(-2).join('.')) {
                                FPS.CCPA.DNS({
                                    doNotSet: true
                                });
                            }
                        }
                    },
                    error: function() {}
                }, tagBrand, tagCountry);
            }
        }

        FPS.get([{PowertrainOfInterest:{max:3}}],{
            success(e){

                try {
                    const PowertrainOfInterest = e?.[0]?.PowertrainOfInterest || [];
                    const oi = {
                        ice: 0,
                        hybrid: 0,
                        electric: 0,
                    };

                    let total = 0;
                    let largestPoiValue = 0;
                    let largestPoi = "";

                    for (let {_powertrain, count} of PowertrainOfInterest) {
                        if (oi.hasOwnProperty(_powertrain)) {
                            total += count;
                            oi[_powertrain] = count;
                        }
                    }

                    if (total > 0) {
                        for (let {_powertrain} of PowertrainOfInterest) {
                            if (oi.hasOwnProperty(_powertrain)) {
                                const value = ((oi[_powertrain] / total) * 100).toPrecision(3);
                                if (oi[_powertrain] > largestPoiValue) {
                                    largestPoiValue = oi[_powertrain];
                                    largestPoi = _powertrain;
                                }
                                cookie.set(`FPS_POI_${_powertrain}`, value, FPS.targetCookies.ttl(), '/', cookie.domain);
                            }
                        }

                        if (largestPoiValue > 0) {
                            cookie.set(`FPS_POI`, largestPoi, FPS.targetCookies.ttl(), '/', cookie.domain);
                        }
                    }

                }catch(err){

                }
            },
            error(e){
                // console.log(e);
            }
        });

        FPS.get([{Propensity:{}}],{
            success(resp) {
                try {
                    const decile = (resp?.[0]?.Propensity?.find?.( el => el?._data_type === "sales"))?.decile;

                    if (typeof decile === "number" || typeof decile === "string") {
                        cookie.set("fps_prop_buy", decile, FPS.targetCookies.ttl(), '/', cookie.domain);
                    }
                }catch(err){

                }
            },
            error(err){
                // console.log(err);
            }
        });

    }());
// qa-v1 Ford USA
function voinofipInsight(){
    if(blockNetworkRequests === true) return;
    if(disableInsights === true) return;
    try{
        var xhr = new XMLHttpRequest();

        xhr.open("post", xdcPathSet + "/api/insights/count/bytime/voinofpi/hour");

        xhr.addEventListener("readystatechange",function(){});

        xhr.send();
    }catch(err){

    }
}
function newFpsIdInsight(tier){
    if(blockNetworkRequests === true) return;
    if(disableInsights === true) return;
    try{
        var name = (tier +"newFpsId" ).toLowerCase();
        var xhr = new XMLHttpRequest();

        xhr.open("post", xdcPathSet + "/api/insights/count/bytime/"+name.toLowerCase()+"/day");

        xhr.addEventListener("readystatechange",function(){});

        xhr.send();
    }catch(err){

    }
}
function fpsTnTierDrop(){
    if(blockNetworkRequests === true) return;
    if(disableInsights === true) return;
    try{
        var xhr = new XMLHttpRequest();

        xhr.open("post", xdcPathSet + "/api/insights/count/bytime/tierDropTn/day");

        xhr.addEventListener("readystatechange",function(){});

        xhr.send();
    }catch(err){

    }
}

function fpsTierDropInsight(tier){
    if(blockNetworkRequests === true) return;
    if(disableInsights === true) return;
    try{
        var name = ("tierDrop|" + tier).toLowerCase();
        var xhr = new XMLHttpRequest();

        xhr.open("post", xdcPathSet + "/api/insights/count/bytime/"+name.toLowerCase()+"/day");
        xhr.addEventListener("readystatechange",function(){});
        xhr.send();

    }catch(err){
    }
}
function fpsVOIChangeInsight(voiUpdateTier) {
    if(blockNetworkRequests === true) return;
    if(disableInsights === true) return;
    try {

        var xhr = new XMLHttpRequest();
        xhr.open("post", xdcPathSet + "/api/insights/count/bytime/" + voiUpdateTier.toLowerCase() + "/day");
        xhr.addEventListener("readystatechange", function() {});

        xhr.send();
    } catch (err) {}
}
if( window && window.FPS && !window.fpsSiteOnload ){
    window.fpsSiteOnload=true;

    var tier;
    var initialGetKeys = [
        {VOIAggregateNameplate: {}}
        , {VOIAggregateTrim:{}}
        , {FPSTierDrop:{}}
    ];
    var tierNameplateObj = {};
    var tierTrimObj = {};
    try{
        tier = FPS.Core.Insights.Utils.getTier(window.location.protocol + "//" + window.location.hostname);
        tier = tier.toUpperCase();
        tierNameplateObj[tier + "VOIAggregateNameplate"] = {};
        tierTrimObj[tier + "VOIAggregateTrim"] = {};
        initialGetKeys.push(tierNameplateObj);
        initialGetKeys.push(tierTrimObj);
        if (tier === "TN")
            initialGetKeys.push({TierDropTN:{}});
    }catch(err){

    }

    FPS.get(initialGetKeys, {
        success: function(resp) {
            try{
                if( /^https:\/\/www(qa)?.ford.com\/?$/.test(window.location.protocol + "//" + window.location.hostname) && window.location.pathname === "/" ){

                    var fpiCookie = cookie.get("FPI");
                    var model = null;
                    var hasData = !!(Array.isArray(resp) && resp[0]["VOIAggregateNameplate"].length > 0 || resp[1]["VOIAggregateTrim"].length > 0);
                    var hasCookie = typeof fpiCookie === "string" && fpiCookie.length > 0;

                    if(hasData){
                        if(hasCookie){
                            model = fpiCookie.split("&").filter( el => el.indexOf("model=") > -1 ).map( el => el.split(/=/)[1])[0];
                            if(hasData && !model){
                                voinofipInsight();
                            }
                        }else{
                            voinofipInsight();
                        }
                    }
                }


                var hasFpsTierDrop = !!(Array.isArray(resp) && resp[2]["FPSTierDrop"].length > 0);
                const oneDay = 24 * 60 * 60 * 1000; // hours*minutes*seconds*milliseconds
                const firstDate = new Date();
                var currentTier = tier;

                if(hasFpsTierDrop){
                    var FPSTierDropList = resp[2]["FPSTierDrop"];
                    const oneDay = 24 * 60 * 60 * 1000; // hours*minutes*seconds*milliseconds
                    var today = new Date();
                    var tierComboEntity = [];
                    var lastTierSetOn = [];
                    var isTripleComboSet = false;
                    var isTierExists = false;
                    var isComboSetRequired = false;
                    var isTripleComboAlreadySet = false;

                    //last set
                    var	previousTier = FPSTierDropList[0].tier.split('_')[0];
                    var twinComboSet = currentTier + '_' + previousTier;

                    for(var fpsTierDropItem in FPSTierDropList)
                    {
                        isTripleComboSet = false;
                        isComboSetRequired = false;

                        tierComboEntity = FPSTierDropList[fpsTierDropItem].tier;

                        if(currentTier === FPSTierDropList[fpsTierDropItem].tier){
                            //indicator to idetify if already set
                            isTierExists = true;
                        }
                        else{
                            var tierSplitItems = tierComboEntity.split('_');
                            if(tierSplitItems.length > 1){
                                for(var i = 0; i < tierSplitItems.length; i++){
                                    if(tierSplitItems[i] === currentTier)
                                        isTripleComboSet = true;
                                }
                                if(!isTripleComboSet && !isTripleComboAlreadySet && previousTier === tierSplitItems[0] ){
                                    isTripleComboAlreadySet = true;
                                    isComboSetRequired = true;
                                    tierComboEntity = currentTier + '_' + tierComboEntity;
                                }
                            }
                        }

                        lastTierSetOn = new Date(FPSTierDropList[fpsTierDropItem].on);

                        //To calculate the time difference of two dates
                        var Difference_In_Time = today.getTime() - lastTierSetOn.getTime();
                        // To calculate the no. of days between two dates
                        var Difference_In_Days = Difference_In_Time / oneDay;

                        //Not required to set if user visits within 7 days
                        if(Difference_In_Days > 7){
                            if(currentTier === FPSTierDropList[fpsTierDropItem].tier){
                                //if re-visited tier invoke Set
                                FPS.set(FPS.lib.FPSTierDrop(currentTier, true),{ success: function(data) {}, error: function(){} });
                                fpsTierDropInsight(currentTier);
                            }
                            else{
                                //if unvisited tier as inactive
                                FPS.set(FPS.lib.FPSTierDrop(FPSTierDropList[fpsTierDropItem].tier, false),{ success: function(data) {}, error: function(){} });
                            }
                        }
                        else if(isComboSetRequired){
                            FPS.set(FPS.lib.FPSTierDrop(tierComboEntity, true),{ success: function(data) {}, error: function(){} });
                            fpsTierDropInsight(tierComboEntity);
                        }
                    }
                    if(previousTier!==currentTier){
                        FPS.set(FPS.lib.FPSTierDrop(twinComboSet, true),{ success: function(data) {}, error: function(){} });
                        fpsTierDropInsight(twinComboSet);
                    }
                    if(isTierExists === false){
                        FPS.set(FPS.lib.FPSTierDrop(currentTier, true),{ success: function(data) {}, error: function(){} });
                        fpsTierDropInsight(currentTier);
                    }
                }
                else{
                    //first time
                    FPS.set(FPS.lib.FPSTierDrop(currentTier, true),{ success: function(data) {}, error: function(){} });
                    fpsTierDropInsight(currentTier);
                }

                if(currentTier === "TN"){
                    var hasTnTierDrop = !!(Array.isArray(resp) && resp[5]["TierDropTN"].length > 0);
                    var isTnTierDropRequired = true;
                    if(typeof(digitaldata)!=="undefined" && digitaldata.user && digitaldata.user.paCode){
                        var _paCode = digitaldata.user.paCode;
                        if(hasTnTierDrop){
                            var tierDropList = resp[5]["TierDropTN"];
                            for(var tierItem in tierDropList)
                            {
                                if(tierDropList[tierItem]._paCode === _paCode)
                                    isTnTierDropRequired = false;
                            }
                            if(isTnTierDropRequired){
                                FPS.set([{TierDropTN:{_paCode:_paCode}}]);
                                fpsTnTierDrop();
                            }
                        }
                        else if(_paCode){
                            FPS.set([{TierDropTN:{_paCode: _paCode}}]);
                        }
                    }
                }

            }catch(err){
                console.log(err);
            }
        },
        error: function() {}
    });
    /* FPS-756*/

}

FPS.pageLoadTracker.trackPage();

try {

    let regexForColor = /\B-|-\B|[^a-z\u00C0-\u017F-\s]/gi;

    function getNameplateFromDigitalData(){
        let nameplate = digitaldata?.vehicle?.nameplate?.replace?.(/ford|lincoln/i,"")?.trim?.()?.toLocaleLowerCase?.();

        switch(nameplate){
            case "mach-e":
                nameplate = "mache";
                break;
            case "f-150":
            case "f150":
                nameplate = "f-150 f-150";
                break;
            case "f150 lightning":
                nameplate = "f-150 lightning";
                break;
            case "super duty":
            case "super-duty":
                nameplate = "superduty";
                break;
            case "transit":
            case "transitvanwagon":
            case "transit van wagon":
                nameplate = "transit vanwagon";
                break;
            case "":
                return "";
        }

        return vdmActiveNameplatesMap[nameplate] || "";
    }

    function setColorOfInterest(color, model, trim) {
        try {
            let cookieValue = encodeURIComponent(JSON.stringify({color, model, trim}));
            let date = new Date();
            date.setTime(date.getTime() + 7 * 24 * 60 * 60 * 1000);
            let expires = date.toGMTString();
            document.cookie = `FPS_OI_ext=${cookieValue}; Expires=${expires}; Domain=.ford.com; Path=/; Secure=true; SameSite=None;`;
        } catch (err) {
            console.log(err);
        }
    }

    document.body.querySelectorAll("div.color-selector-container")?.forEach((el)=> {

        el.addEventListener("click", function (e) {
            let color = "";
            let trim = "";
            let model = "";

            let initialContent = document.body.querySelector(".cmp-360-colorizer .dropdown-activeTrim")?.textContent;

            if (!initialContent) {
                return;
            }

            try {
                color = document.body.querySelector(".cmp-360-colorizer .model-container.show div.color-selector[role=radiogroup] > [aria-checked=true] > .sr-only").textContent.split(regexForColor)[0].trim();
                color = color.match(/extra[ -]cost/i) ? color.split(/extra[ -]cost/i)[0].trim() : color;
                color = color.match(/Color con Costo Adicional/i) ? color.split(/Color con Costo Adicional/i)[1].trim() : color;
                color = Encode(color);

            } catch (err) {
                console.log(err);
            }

            try {

                model = Encode(getNameplateFromDigitalData());
            } catch (err) {
                console.log(err);
            }

            try {
                trim = document.querySelector(".cmp-360-colorizer .dropdown.trimAware__dropdown.dropdown-trim")?.dataset?.trimid || "";
                trim = Encode(trim);
            } catch (err) {
                console.log(err);
            }

            setColorOfInterest(color, model, trim);

        });
    });

} catch(err) {
    console.log(err);
}

    try{
        document.dispatchEvent(new Event("FPS:Loaded"));
    }catch(err){}
}());
