PageSourceSearch

https://mydearbeer.com/wp-content/plugins/metrion/js/bundles/core.js?ver=1791200608

js mydearbeer.com collected 2026-10-05 20:50:22 UTC 119,944 bytes, 2,857 lines download raw bytes

1window.metrion = {
2  // Configuration object
3  configuration: {
4    init_unix_timestamp: Date.now(),
5    //last_interaction_unix_timestamp_ms: Date.now(),
6    cookie_value_separator: "--",
7    user_cookie_name: metrion_api.user_cookie_name + "_js",
8    user_cookie_lifetime_milliseconds:
9      metrion_api.user_cookie_lifetime_milliseconds,
10    session_cookie_name: metrion_api.session_cookie_name,
11    session_cookie_lifetime_milliseconds: Number(
12      metrion_api.session_cookie_lifetime_milliseconds
13    ),
14    cookie_expiration_milliseconds: Number(
15      metrion_api.user_cookie_lifetime_milliseconds
16    ),
17    cookie_domain: window.location.hostname.split(/\./).slice(-2).join("."),
18    session_start_trigger: false,
19    session_start_reasons: [],
20    event_id_name: metrion_api.event_id_name,
21    browser_support_safe_uuid: true,
22    consent_cookie_name: metrion_api.consent_cookie_name,
23    cmp_selection: metrion_api.cmp_selection,
24    cmp_update_handled: false,
25    cmp_allow_marketing: false,
26    session_start_handled: false,
27    floodgate_name: metrion_api.floodgate_name,
28    onetrust_marketing_code: metrion_api.onetrust_marketing_code,
29    onetrust_analytics_code: metrion_api.onetrust_analytics_code,
30    floodgate_open: false,
31    floodgate_release_pending: false,
32    session_info_storage_name: metrion_api.session_info_storage_name,
33    event_broker_queue: [],
34    purchase_only_tracking: metrion_api.purchase_only_tracking,
35    allow_cookie_placement_before_explicit_consent:
36      metrion_api.allow_cookie_placement_before_explicit_consent,
37    click_ids_cookie_name: metrion_api.click_ids_cookie_name,
38    allow_pings: metrion_api.allow_pings,
39    blocking_detected: false,
40    prices_vat_included: metrion_api.metrion_vat_included,
41    prices_shipping_included: metrion_api.metrion_shipping_costs_included
42  },
43
44  // The user manager object
45  user_manager: {
46    //Function to create the user cookie if not called by the PHP itself
47    ensure_user_cookie_existance: function (callback) {
48      var cookie_url = metrion_api.api_url.replace(/\/?$/, "/") + "cookies";
49      var xhr = new XMLHttpRequest();
50      xhr.open("POST", cookie_url, true);
51      xhr.setRequestHeader("Content-Type", "application/json");
52
53      xhr.onreadystatechange = function () {
54        if (xhr.readyState === 4) {
55          
56          var domain = window.metrion.helpers.get_cookie_domain(window.location.hostname);
57          var base_cookie_name = window.metrion.configuration.user_cookie_name.replace("_js", "");
58          var header_was_stripped = (window.metrion.helpers.get_cookie_value(base_cookie_name) === null);
59          
60          // Use the dynamic separator from config instead of hardcoding "--"
61          var separator = window.metrion.configuration.cookie_value_separator;
62          
63          // A fresh user starts at session 0. The session_manager will immediately increment this to 1.
64          var initial_session_number = 0;
65
66          // IF SERVER/CDN RESPONDED NORMALLY (200 OK or 204 No Content)
67          if (xhr.status === 200 || xhr.status === 204) {
68            
69            var response_data = null;
70            try {
71              if (xhr.responseText) {
72                response_data = JSON.parse(xhr.responseText);
73              }
74            } catch(e) {
75              window.metrion.helpers.log_debug("Failed to parse JSON cookie response", "warn");
76            }
77
78            // SCENARIO A: Server returned JSON (CDN stripped header, but left body intact)
79            if (response_data && response_data.cookie_name && response_data.cookie_value) {
80              
81              if (header_was_stripped) {
82                window.metrion.helpers.log_debug("Applying JSON fallback to create user cookie.", "log");
83                var lifetime_ms = (response_data.expiration_days || 365) * 86400 * 1000;
84
85                window.metrion.helpers.set_cookie(response_data.cookie_name, response_data.cookie_value, lifetime_ms, "/", domain);
86
87                var parts = response_data.cookie_value.split(separator);
88                if (parts.length >= 3) {
89                  var js_cookie_value = parts[0] + separator + parts[2];
90                  window.metrion.helpers.set_cookie(response_data.cookie_name + "_js", js_cookie_value, lifetime_ms, "/", domain);
91                }
92
93                window.metrion.send_event("status_event", {
94                  "message": "Set-Cookie header stripped by CDN/cache, falling back to JSON response.", 
95                  "id": "fallback_cookie_creation_via_json"
96                });
97              }
98
99            } 
100            // SCENARIO B: CDN forced a 204 No Content AND destroyed the JSON body
101            else if (header_was_stripped) {
102                window.metrion.helpers.log_debug("CDN forced 204/stripped body. Generating user cookie locally.", "log");
103                
104                var local_uuid = window.metrion.helpers.generate_uuid();
105                var local_lifetime_ms = window.metrion.configuration.user_cookie_lifetime_milliseconds || (365 * 86400 * 1000);
106                var local_timestamp = new Date().getTime() + local_lifetime_ms;
107                
108                var local_cookie_value = local_uuid + separator + local_timestamp + separator + initial_session_number;
109                var local_js_value = local_uuid + separator + initial_session_number;
110                
111                window.metrion.helpers.set_cookie(base_cookie_name, local_cookie_value, local_lifetime_ms, "/", domain);
112                window.metrion.helpers.set_cookie(base_cookie_name + "_js", local_js_value, local_lifetime_ms, "/", domain);
113
114                window.metrion.send_event("status_event", {
115                  "message": "CDN forced empty 204 response. User cookie generated natively via JS fallback.", 
116                  "id": "fallback_cookie_creation_local_js"
117                });
118            }
119          } 
120          
121          // SCENARIO C: Request was blocked or failed (Status 0, 403, 500, etc.)
122          else {
123            if (header_was_stripped) {
124                window.metrion.helpers.log_debug("Request blocked/failed (Status: " + xhr.status + "). Generating user cookie locally.", "log");
125                
126                var error_uuid = window.metrion.helpers.generate_uuid();
127                var error_lifetime_ms = window.metrion.configuration.user_cookie_lifetime_milliseconds || (365 * 86400 * 1000);
128                var error_timestamp = new Date().getTime() + error_lifetime_ms;
129                
130                var error_cookie_value = error_uuid + separator + error_timestamp + separator + initial_session_number;
131                var error_js_value = error_uuid + separator + initial_session_number;
132
133                window.metrion.helpers.set_cookie(base_cookie_name, error_cookie_value, error_lifetime_ms, "/", domain);
134                window.metrion.helpers.set_cookie(base_cookie_name + "_js", error_js_value, error_lifetime_ms, "/", domain);
135
136                window.metrion.send_event("status_event", {
137                  "message": "Request blocked or failed (Status: " + xhr.status + "). User cookie generated natively via JS fallback.", 
138                  "id": "fallback_cookie_creation_network_error"
139                });
140            } else {
141                window.metrion.helpers.log_debug("Metrion Cookie Error: " + window.metrion.helpers.safe_to_string(xhr.statusText), "log");
142            }
143          }
144
145          // Continue with standard session creation
146          if (!window.metrion.session_manager.session_cookie_exists()) {
147            window.metrion.session_manager.create_session_cookie();
148          }
149          callback(); // Call the next function after success
150        }
151      };
152      xhr.send(); 
153    },
154    get_user_cookie_values: function () {
155      // Return in this order: session id, session expiration time, session start time, session number
156      var user_cookie_value = window.metrion.helpers.get_cookie_value(
157        window.metrion.configuration.user_cookie_name
158      );
159      if (user_cookie_value !== null) {
160        var user_cookie_value_parts = user_cookie_value.split("--");
161        return user_cookie_value_parts;
162      }
163      return [undefined, undefined];
164    },
165  },
166
167  // The session manager object
168  session_manager: {
169    session_cookie_exists: function () {
170      var configuration = window.metrion.configuration;
171
172      return (
173        window.metrion.helpers.get_cookie_value(
174          configuration.session_cookie_name
175        ) !== null
176      );
177    },
178
179    is_session_cookie_expired: function () {
180      var configuration = window.metrion.configuration;
181
182      if (!window.metrion.session_manager.session_cookie_exists()) {
183        return true;
184      }
185
186      var session_cookie_value = window.metrion.helpers.get_cookie_value(
187        configuration.session_cookie_name
188      );
189      var session_expiration = parseInt(session_cookie_value.split("--")[1]);
190      return new Date(session_expiration) < new Date();
191    },
192
193    get_session_cookie_values: function () {
194      // Return in this order: session id, session expiration time, session start time, session number
195      var session_cookie_value = window.metrion.helpers.get_cookie_value(
196        window.metrion.configuration.session_cookie_name
197      );
198      if (session_cookie_value !== null) {
199        var session_cookie_value_parts = session_cookie_value.split(
200          window.metrion.configuration.cookie_value_separator
201        );
202        return session_cookie_value_parts;
203      }
204      return [undefined, undefined, undefined, undefined];
205    },
206
207    create_session_cookie: function () {
208      window.metrion.helpers.log_debug(
209        "Session cookie creation started:",
210        "log"
211      );
212      var configuration = window.metrion.configuration;
213      var session_start_timestamp_seconds = Math.floor(Date.now() / 1000);
214      // Default value
215      var session_number = 1;
216      // If session number exists in the user cookie
217      var user_cookie_values =
218        window.metrion.user_manager.get_user_cookie_values();
219      // If only user exists, get it from the user and increment it with 1 (since this function is started to launch a new session)
220      if (user_cookie_values[1] !== undefined) {
221        session_number =
222          window.metrion.helpers.safe_parse_int(user_cookie_values[1]) + 1;
223      }
224      var session_id = window.metrion.helpers.generate_uuid();
225      var session_expiration =
226        new Date().getTime() +
227        configuration.session_cookie_lifetime_milliseconds;
228      var session_cookie_new_value =
229        session_id +
230        window.metrion.configuration.cookie_value_separator +
231        session_expiration +
232        window.metrion.configuration.cookie_value_separator +
233        session_start_timestamp_seconds;
234      // Set the session cookie with the session start time
235      //{session id}--{session expiration}--{session start time}
236      window.metrion.helpers.set_cookie(
237        configuration.session_cookie_name,
238        session_cookie_new_value,
239        configuration.session_cookie_lifetime_milliseconds,
240        "/",
241        window.metrion.helpers.get_cookie_domain(window.location.hostname)
242      );
243      // Update the user cookie with the session number variable
244      //{user id}--{session number}
245      var user_cookie_new_value = user_cookie_values[0] + "--" + session_number;
246      window.metrion.helpers.set_cookie(
247        configuration.user_cookie_name,
248        user_cookie_new_value,
249        configuration.user_cookie_lifetime_milliseconds,
250        "/",
251        window.metrion.helpers.get_cookie_domain(window.location.hostname)
252      );
253      return session_id;
254    },
255
256    extend_session_cookie_lifetime: function () {
257      var configuration = window.metrion.configuration;
258
259      if (!window.metrion.session_manager.session_cookie_exists()) {
260        return undefined;
261      }
262
263      if (window.metrion.session_manager.is_session_cookie_expired()) {
264        return window.metrion.session_manager.create_session_cookie();
265      }
266
267      var session_cookie_values =
268        window.metrion.session_manager.get_session_cookie_values();
269      var new_session_expiration =
270        new Date().getTime() +
271        configuration.session_cookie_lifetime_milliseconds;
272      var updated_session_cookie_value =
273        session_cookie_values[0] +
274        window.metrion.configuration.cookie_value_separator +
275        new_session_expiration +
276        window.metrion.configuration.cookie_value_separator +
277        session_cookie_values[2];
278      window.metrion.helpers.set_cookie(
279        configuration.session_cookie_name,
280        updated_session_cookie_value,
281        configuration.session_cookie_lifetime_milliseconds,
282        "/",
283        window.metrion.helpers.get_cookie_domain(window.location.hostname)
284      );
285
286      return session_cookie_values[0];
287    },
288  },
289
290  // Helper functions
291  helpers: {
292    generate_uuid_non_secure: function () {
293      window.metrion.configuration.browser_support_safe_uuid = false;
294      return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(
295        /[018]/g,
296        function (c) {
297          return (
298            c ^
299            (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))
300          ).toString(16);
301        }
302      );
303    },
304    generate_uuid_secure: function () {
305      window.metrion.configuration.browser_support_safe_uuid = true;
306      return crypto.randomUUID();
307    },
308    generate_uuid: function () {
309      try {
310        if (typeof crypto.randomUUID === "function") {
311          return window.metrion.helpers.generate_uuid_secure();
312        } else if (typeof crypto.getRandomValues === "function") {
313          return window.metrion.helpers.generate_uuid_non_secure();
314        }
315      } catch (e) {
316        window.metrion.configuration.browser_support_safe_uuid = false;
317        return (
318          Math.floor(100000000 + Math.random() * 900000000).toString() +
319          "." +
320          new Date().getTime().toString()
321        );
322      }
323
324      return (
325        Math.floor(100000000 + Math.random() * 900000000).toString() +
326        "." +
327        new Date().getTime().toString()
328      );
329    },
330    get_cookie_value: function (cookie_name) {
331      var value = "; " + document.cookie;
332      var parts = value.split("; " + cookie_name + "=");
333
334      if (parts.length == 2) {
335        return parts.pop().split(";").shift();
336      }
337
338      return null;
339    },
340    set_cookie: function (
341      cookie_name,
342      cookie_value,
343      cookie_lifetime_in_milliseconds,
344      cookie_path,
345      cookie_domain
346    ) {
347      var cookie_secure = ";secure";
348      var cookie_samesite = "lax";
349
350      var d = new Date();
351      d.setTime(d.getTime() + cookie_lifetime_in_milliseconds);
352
353      var domain_string = "";
354      if (cookie_domain && cookie_domain !== "") {
355          domain_string = ";domain=" + cookie_domain;
356      }
357
358      document.cookie =
359        cookie_name +
360        "=" +
361        cookie_value +
362        ";expires=" +
363        d.toUTCString() +
364        ";path=" +
365        cookie_path +
366        domain_string +
367        cookie_secure +
368        ";SameSite=" +
369        cookie_samesite;
370    },
371    set_consent_cookie: function (cookie_value) {
372      var hostname = window.location.hostname;
373      var cookie_domain = window.metrion.helpers.get_cookie_domain(hostname);
374      window.metrion.helpers.set_cookie(
375        window.metrion.configuration.consent_cookie_name,
376        cookie_value,
377        window.metrion.configuration.cookie_expiration_milliseconds,
378        "/",
379        cookie_domain
380      );
381    },
382    get_cookie_domain: function (hostname) {
383      if (hostname === 'localhost' || /^[0-9\.]+$/.test(hostname)) {
384          return ""; 
385      }
386      var parts = hostname.split('.');
387      if (parts.length <= 2) {
388          return "." + hostname;
389      }
390      var tld = parts[parts.length - 1]; 
391      var sld = parts[parts.length - 2];
392
393      if (tld.length === 2 && sld.length <= 3) {
394          return "." + parts.slice(-3).join('.'); 
395      }
396      return "." + parts.slice(-2).join('.'); 
397    },
398    get_url_parameter_value: function (url_parameter_name) {
399      var urlParams = new URLSearchParams(window.location.search);
400      return urlParams.get(url_parameter_name) || null;
401    },
402    log_debug: function (message, type) {
403      type = type || "log"; // Default parameter handling for ES5 compatibility
404
405      if (
406        typeof window.metrion_api !== "undefined" &&
407        window.metrion_api.debug_mode === "1"
408      ) {
409        switch (type) {
410          case "log":
411            console.log(message);
412            break;
413          case "warn":
414            console.warn(message);
415            break;
416          case "error":
417            console.error(message);
418            break;
419          default:
420            console.log(message);
421        }
422      }
423    },
424    sha256_hash: function(string_to_hash) {
425      // 1. Check availability and otherwise return undefined
426      // ECMA 2015 friendly
427      if (typeof window === 'undefined' || !window.crypto || !window.crypto.subtle) {
428        window.metrion.helpers.log_debug("Web Crypto API is not available.", "log");
429        return Promise.resolve(undefined); 
430      }
431
432      try {
433        var string_to_hash_uint8 = new TextEncoder().encode(string_to_hash);
434        
435        // 2. Return the Promise chain directly
436        return window.crypto.subtle.digest('SHA-256', string_to_hash_uint8)
437          .then(function(hashBuffer) {
438            var hashArray = Array.from(new Uint8Array(hashBuffer));
439            return hashArray.map(function(b) {
440              // Fallback for padStart if you need to support truly ancient browsers like IE11
441              var hex = b.toString(16);
442              return hex.length === 1 ? '0' + hex : hex; 
443            }).join('');
444          })
445          .catch(function(error) {
446            window.metrion.helpers.log_debug("SHA-256 hashing failed:", "log");
447            return undefined;
448          });
449          
450      } catch (error) {
451        window.metrion.helpers.log_debug("SHA-256 hashing setup failed:", "log");
452        return Promise.resolve(undefined);
453      }
454    },
455    wait_for_jquery: function (callback) {
456      if (typeof jQuery !== "undefined") {
457        callback(); // jQuery is available, proceed with logic
458      } else {
459        // Use DOMContentLoaded to ensure the document is loaded
460        document.addEventListener("DOMContentLoaded", function () {
461          if (typeof jQuery !== "undefined") {
462            callback(); // jQuery is available, proceed with logic
463          } else {
464            window.metrion.helpers.log_debug("jQuery is not loaded yet", "log");
465          }
466        });
467      }
468    },
469    safe_parse_float: function (value) {
470      try {
471        if (value === null || typeof value === "undefined") {
472          return 0;
473        }
474        var parsed = parseFloat(value);
475        if (isNaN(parsed)) {
476          return 0;
477        }
478        return parsed;
479      } catch (e) {
480        return 0;
481      }
482    },
483    safe_parse_int: function (value) {
484      try {
485        if (value === null || typeof value === "undefined") {
486          return 0;
487        }
488        var parsed = parseInt(value);
489        if (isNaN(parsed)) {
490          return 0;
491        }
492        return parsed;
493      } catch (e) {
494        return 0;
495      }
496    },
497    safe_to_string: function (value) {
498      if (value === null || typeof value === "undefined") {
499        return "";
500      }
501      return String(value);
502    },
503
504    clean_url: function (s) {
505      return s.replace(/\/$/, '').replace(/^https?:\/\/(www\.)?/, '');
506    },
507    post_json: function (url, payload) {
508      var body = JSON.stringify(payload);
509      try {
510        if (typeof fetch === "function") {
511          fetch(url, {
512            method: "POST",
513            headers: { "Content-Type": "application/json" },
514            body: body,
515            keepalive: true,
516            credentials: "include",
517            mode: "cors",
518          }).catch(function (e) {
519            window.metrion.helpers.log_debug("post_json fetch error: " + e, "log");
520          });
521          window.metrion.helpers.log_debug("Event sent using fetch", "log");
522          return;
523        }
524      } catch (e) {
525        window.metrion.helpers.log_debug("post_json fetch threw: " + e, "log");
526      }
527      try {
528        var xhr = new XMLHttpRequest();
529        xhr.open("POST", url, true);
530        xhr.setRequestHeader("Content-Type", "application/json");
531        xhr.send(body);
532        window.metrion.helpers.log_debug("Event sent using XMLHttpRequest", "log");
533      } catch (e2) {
534        window.metrion.helpers.log_debug("post_json xhr error: " + e2, "log");
535      }
536    },
537  },
538
539  // All consent management functionality
540  consent_manager: {
541    // Function to load js of destination channels dynamically through an internal API
542    load_destination_js_dynamically: function () {
543      var script_src =
544        metrion_api.api_url.replace(/\/?$/, "/") + "destinations";
545      var existing_script = document.querySelector(
546        'script[src="' + script_src + '"]'
547      );
548      if (!existing_script) {
549        var script = document.createElement("script");
550        script.src = script_src;
551        script.async = true;
552        document.body.appendChild(script);
553        window.metrion.helpers.log_debug(
554          "Loaded script: " + script_src.toString(),
555          "log"
556        );
557      } else {
558        window.metrion.helpers.log_debug(
559          "Script already exists, skipping: " + script_src.toString(),
560          "log"
561        );
562      }
563    },
564    timeout_consent_listener_updates: function () {
565      // Reset flag after 3 seconds
566      setTimeout(function () {
567        window.metrion.configuration.cmp_update_handled = false;
568      }, 1500);
569    },
570    // Initial consent check sequence
571    initial_consent_enforcement: function () {
572      // Start initial consent enforcement
573      window.metrion.helpers.log_debug(
574        "Initial consent enforcement triggered!",
575        "log"
576      );
577
578      // First check the initial Metrion consent cookie value (if available)
579      var metrion_consent_cookie = window.metrion.helpers.get_cookie_value(
580        window.metrion.configuration.consent_cookie_name
581      );
582
583      // Set initial check variables related to consent and system detection
584      var initial_metrion_allow_marketing = false; // Metrion itself assumes marketing is not allowed by default
585      window.metrion.configuration.blocking_detected = undefined; // No blocking detected by default
586      window.metrion.helpers.log_debug(
587        "Initial consent enforcement cookie value: " +
588        (metrion_consent_cookie || "null"),
589        "log"
590      );
591
592      // If the Metrion consent cookie is NOT emtpy
593      if (metrion_consent_cookie !== null) {
594        window.metrion.helpers.log_debug(
595          "Consent cookie !== to null, so open floodgate.",
596          "log"
597        );
598        window.metrion.configuration.floodgate_open = true;
599        try {
600          // If the value of the initial Metrion consent cookie is 1, then this indicates that here is no dynamic loading necessary
601          initial_metrion_allow_marketing =
602            JSON.parse(decodeURIComponent(metrion_consent_cookie))
603              .allow_marketing === "1";
604          // If the blocking parameter is detected with a high probability (1), change the check variable to 1 else to 0 (because detection is completed)
605          if (
606            JSON.parse(decodeURIComponent(metrion_consent_cookie)).b === "1"
607          ) {
608            window.metrion.configuration.blocking_detected = "1";
609          } else if (
610            JSON.parse(decodeURIComponent(metrion_consent_cookie)).b === "0"
611          ) {
612            window.metrion.configuration.blocking_detected = "0";
613          }
614        } catch (parse_error) {
615          window.metrion.helpers.log_debug(
616            "Metrion consent cookie parse error:",
617            "log"
618          );
619          window.metrion.helpers.log_debug(parse_error, "log");
620        }
621      }
622
623      // Log the selected CMP
624      window.metrion.helpers.log_debug(
625        "Initial consent enforcement for: " +
626        window.metrion.configuration.cmp_selection,
627        "log"
628      );
629
630      /// CMP logic here
631      if (typeof window.metrion.consent_manager.cmp_init === "function") {
632        window.metrion.consent_manager.cmp_init();
633      }
634
635      // Evaluate floodgate after to trigger the Metrion events
636      if (
637        window.metrion.configuration.floodgate_open === true &&
638        window.metrion.configuration.cmp_update_handled === true
639      ) {
640        window.metrion.consent_manager.evaluate_consent_floodgate();
641      }
642
643      // If only initial evaluation is required, also load destinations dynamically when the initial metrion consent cookie is not available
644      if (
645        window.metrion.configuration.floodgate_open === true &&
646        metrion_consent_cookie === null &&
647        window.metrion.configuration.cmp_allow_marketing === true
648      ) {
649        window.metrion.consent_manager.load_destination_js_dynamically();
650      } else if (
651        window.metrion.configuration.floodgate_open === true &&
652        metrion_consent_cookie !== null &&
653        initial_metrion_allow_marketing == false &&
654        window.metrion.configuration.cmp_allow_marketing === true
655      ) {
656        window.metrion.consent_manager.load_destination_js_dynamically();
657      }
658
659      return window.metrion.configuration.cmp_allow_marketing;
660    },
661    // Function to evaluate the floodgate status
662    evaluate_consent_floodgate: function () {
663      window.metrion.helpers.log_debug("Start Floodgate evaluation...", "log");
664      // First check if the floodgate is open
665      if (!window.metrion.configuration.floodgate_open) {
666        window.metrion.helpers.log_debug(
667          "Floodgate evaluation stopped. Floodgate closed",
668          "log"
669        );
670        return;
671      }
672
673      // Retrieve floodgate events
674      var floodgate_events = [];
675      if (
676        typeof localStorage !== "undefined" &&
677        typeof window.metrion.floodgate_events === "undefined"
678      ) {
679        floodgate_events =
680          JSON.parse(
681            localStorage.getItem(window.metrion.configuration.floodgate_name)
682          ) || [];
683      } else if (typeof window.metrion.floodgate_events !== "undefined") {
684        floodgate_events = window.metrion.floodgate_events;
685      }
686      window.metrion.helpers.log_debug(
687        "Collected floodgated events: " + floodgate_events.length.toString(),
688        "log"
689      );
690
691      // Store session info if available
692      if (
693        typeof window.metrion.session_info !== "undefined" &&
694        typeof sessionStorage !== "undefined"
695      ) {
696        sessionStorage.setItem(
697          window.metrion.configuration.session_info_storage_name,
698          window.metrion.session_info
699        );
700      }
701
702      // Store click-id info if available
703      if (typeof window.metrion.click_ids !== "undefined") {
704        window.metrion.helpers.set_cookie(
705          window.metrion.configuration.click_ids_cookie_name,
706          window.metrion.click_ids,
707          window.metrion.configuration.cookie_expiration_milliseconds,
708          "/",
709          window.metrion.helpers.get_cookie_domain(window.location.hostname)
710        );
711      }
712
713      // If no floodgate events exist, log and exit
714      if (floodgate_events.length === 0) {
715        window.metrion.helpers.log_debug("No Floodgate events sent", "log");
716        return;
717      }
718
719      // Function to send floodgated events
720      function send_floodgated_events() {
721        window.metrion.helpers.log_debug("Sending floodgated events", "log");
722
723        for (var i = 0; i < floodgate_events.length; i++) {
724          window.metrion.send_floodgated_event(floodgate_events[i]);
725        }
726
727        // Empty the floodgate to prevent double triggers
728        localStorage.removeItem(window.metrion.configuration.floodgate_name);
729        window.metrion.floodgate_events = [];
730      }
731
732      window.metrion.helpers.log_debug(
733        "Evaluation finished with floodgate status: " +
734        window.metrion.configuration.floodgate_open.toString(),
735        "log"
736      );
737      // Ensure user cookie existence before sending events
738      if (
739        window.metrion.user_manager.get_user_cookie_values()[0] === undefined
740      ) {
741        // A release is already waiting for the user cookie request to finish
742        // (e.g. UC_CONSENT and the dataLayer push both fire for one consent
743        // change). Starting a second one would send every floodgated event twice.
744        if (window.metrion.configuration.floodgate_release_pending === true) {
745          window.metrion.helpers.log_debug(
746            "Floodgate release already pending, skipping duplicate evaluation",
747            "log"
748          );
749          return;
750        }
751        window.metrion.configuration.floodgate_release_pending = true;
752        try {
753          window.metrion.user_manager.ensure_user_cookie_existance(function () {
754            window.metrion.configuration.floodgate_release_pending = false;
755            window.metrion.helpers.log_debug(
756              "Dynamic user cookie ensuration function called",
757              "log"
758            );
759            send_floodgated_events();
760            window.metrion.helpers.log_debug(
761              "Send floodgated events function called with status: " +
762              window.metrion.configuration.floodgate_open.toString(),
763              "log"
764            );
765            // Load destination js files dynamically
766            window.metrion.consent_manager.load_destination_js_dynamically();
767          });
768        } catch (cookie_request_error) {
769          // The request never started, so no callback will clear the flag
770          window.metrion.configuration.floodgate_release_pending = false;
771          throw cookie_request_error;
772        }
773      } else {
774        send_floodgated_events();
775      }
776    },
777    // Function to manually overwrite the consent settings when no CMP is selected
778    update_consent: function (consent_object) {
779      var metrion_consent_cookie = window.metrion.helpers.get_cookie_value(
780        window.metrion.configuration.consent_cookie_name
781      );
782      if (metrion_consent_cookie !== null) {
783        var current_consent_object = JSON.parse(
784          decodeURIComponent(metrion_consent_cookie)
785        );
786        window.metrion.configuration.blocking_detected = "0"; // No blocking detected by default
787        if (JSON.parse(decodeURIComponent(metrion_consent_cookie)).b === "1") {
788          window.metrion.configuration.blocking_detected = "1";
789        }
790        var updated_consent_object = consent_object;
791        // Add the blocking parameter
792        updated_consent_object.b =
793          window.metrion.configuration.blocking_detected;
794
795        // Merge new consent values into the current consent object (the current is the one that needs updating)
796        for (var key in updated_consent_object) {
797          if (
798            updated_consent_object.hasOwnProperty(key) &&
799            current_consent_object.hasOwnProperty(key)
800          ) {
801            current_consent_object[key] =
802              updated_consent_object[key].toString();
803          }
804        }
805        current_consent_object["unix"] = Date.now();
806
807        window.metrion.helpers.set_consent_cookie(encodeURIComponent(JSON.stringify(current_consent_object)));
808      }
809    },
810  },
811
812  // Send floodgated events
813  send_floodgated_event: function (stored_event) {
814    var current_stored_event = stored_event;
815    var consent_cookie_value = window.metrion.helpers.get_cookie_value(
816      window.metrion.configuration.consent_cookie_name
817    );
818    var metrion_consent_cookie_value = {};
819    if (consent_cookie_value) {
820      try {
821        metrion_consent_cookie_value = JSON.parse(
822          decodeURIComponent(consent_cookie_value)
823        );
824      } catch (e) {
825        // handle parse error
826      }
827    }
828    var allow_uid = metrion_consent_cookie_value.allow_uid === "1";
829    var allow_sid = metrion_consent_cookie_value.allow_sid === "1";
830
831    // Apply consent settings on floodgated events
832    if (allow_uid) {
833      current_stored_event[metrion_api.user_cookie_name] =
834        window.metrion.user_manager.get_user_cookie_values()[0];
835    } else {
836      delete current_stored_event[metrion_api.user_cookie_name];
837    }
838    if (allow_sid) {
839      current_stored_event[metrion_api.session_cookie_name] =
840        window.metrion.session_manager.get_session_cookie_values()[0];
841    } else {
842      delete current_stored_event[metrion_api.session_cookie_name];
843    }
844    // Overwrite the consent object with the recent change
845    current_stored_event.consent = metrion_consent_cookie_value;
846
847    // Add additional floodgate context which we don't want stored before consent.
848    current_stored_event["screen_height"] = screen.height || "";
849    current_stored_event["screen_width"] = screen.width || "";
850    current_stored_event["user_agent"] = navigator.userAgent || "";
851    current_stored_event["language"] = navigator.language || "";
852    current_stored_event["consent"] = metrion_consent_cookie_value;
853    current_stored_event["event_body"]["floodgated"] = true;
854    current_stored_event["event_body"]["floodgate_release_unix_timestamp"] =
855      Date.now();
856    current_stored_event["event_body"]["session_number"] =
857      window.metrion.user_manager.get_user_cookie_values()[1];
858    current_stored_event["event_body"]["session_start_time"] =
859      window.metrion.session_manager.get_session_cookie_values()[2];
860    //current_stored_event["event_body"]["engaged_time_ms"] =
861    //  current_stored_event["event_unix_timestamp"] -
862    //  window.metrion.configuration.last_interaction_unix_timestamp_ms;
863    //window.metrion.configuration.last_interaction_unix_timestamp_ms =
864    //  current_stored_event["event_unix_timestamp"];
865
866    // Prepare for data sending to API
867    window.metrion.helpers.log_debug("Sending event data to API...", "log");
868    window.metrion.helpers.post_json(metrion_api.api_url, stored_event);
869
870    // Push the event to the event broker
871    window.metrion.configuration.event_broker_queue.push({
872      event_name: current_stored_event.event_name,
873      event_data: current_stored_event,
874    });
875  },
876
877  // Send event function
878  send_event: function (event_name, event_body) {
879    // Construct the event context
880    var event_data = {};
881    event_data[metrion_api.event_id_name] =
882      window.metrion.helpers.generate_uuid();
883    event_data["event_name"] = event_name;
884    event_data["event_unix_timestamp"] = Date.now();
885    event_data["event_timestamp"] = new Date().toISOString();
886    event_data["location"] = {
887      protocol: window.location.protocol || "",
888      host: window.location.host || "",
889      path: window.location.pathname || "",
890      query: window.location.search || "",
891      hash: window.location.hash || "",
892      referrer: document.referrer || "",
893      title: document.title || "",
894    };
895    event_data["event_body"] = event_body || {};
896    event_data["event_body"]["browser_support_safe_uuid"] =
897      window.metrion.configuration.browser_support_safe_uuid;
898    event_data["event_body"]["init_unix_timestamp"] =
899      window.metrion.configuration.init_unix_timestamp;
900    event_data["event_body"]["session_number"] =
901      window.metrion.user_manager.get_user_cookie_values()[1];
902    event_data["event_body"]["session_start_time"] =
903      window.metrion.session_manager.get_session_cookie_values()[2];
904
905    // If consent cookie is available and floodgate open, handle based on the metrion consent cookie. Otherwise the event will be floodgated later
906    window.metrion.helpers.log_debug(
907      "Floodgate open:  " +
908      window.metrion.configuration.floodgate_open.toString(),
909      "log"
910    );
911    window.metrion.helpers.log_debug(
912      "Consent cookie value:  " +
913      window.metrion.helpers.get_cookie_value(
914        decodeURIComponent(window.metrion.configuration.consent_cookie_name)
915      ),
916      "log"
917    );
918    window.metrion.helpers.log_debug(
919      "User cookie value: " +
920      window.metrion.user_manager.get_user_cookie_values()[0],
921      "log"
922    );
923
924    // Only push events to the metrion API if the floodgates are open!
925    if (window.metrion.configuration.floodgate_open) {
926      // First check consent information
927      var consent_cookie_value = window.metrion.helpers.get_cookie_value(
928        window.metrion.configuration.consent_cookie_name
929      );
930      var metrion_consent_cookie_value = {};
931      if (consent_cookie_value) {
932        // A corrupted consent cookie must not stop the event from being sent.
933        // Same fallback as send_floodgated_event(): no consent information, so
934        // no identifiers are attached.
935        try {
936          metrion_consent_cookie_value = JSON.parse(
937            decodeURIComponent(consent_cookie_value)
938          );
939        } catch (e) {
940          window.metrion.helpers.log_debug(
941            "Metrion consent cookie parse error in send_event",
942            "log"
943          );
944          metrion_consent_cookie_value = {};
945        }
946      }
947      var allow_uid = metrion_consent_cookie_value.allow_uid === "1";
948      var allow_sid = metrion_consent_cookie_value.allow_sid === "1";
949      if (allow_uid) {
950        event_data[metrion_api.user_cookie_name] =
951          window.metrion.user_manager.get_user_cookie_values()[0];
952      }
953      if (allow_sid) {
954        event_data[metrion_api.session_cookie_name] =
955          window.metrion.session_manager.get_session_cookie_values()[0];
956      }
957
958      // Add other event-level context
959      event_data["screen_height"] = screen.height || "";
960      event_data["screen_width"] = screen.width || "";
961      event_data["user_agent"] = navigator.userAgent || "";
962      event_data["language"] = navigator.language || "";
963      event_data["consent"] = metrion_consent_cookie_value;
964
965      // Trigger the main Metrion event
966      window.metrion.helpers.log_debug("Sending event data to API...", "log");
967      window.metrion.helpers.post_json(metrion_api.api_url, event_data);
968
969      // Push the event to the event broker
970      window.metrion.configuration.event_broker_queue.push({
971        event_name: event_name,
972        event_data: event_data,
973      });
974    }
975    // Floodgate closed, store event behind floodgate and send ping
976    else {
977      if (window.metrion.configuration.allow_pings === "1") {
978        //Trigger the ping
979        this.send_ping(event_name, event_data);
980      }
981
982      if (
983        typeof localStorage !== "undefined" &&
984        window.metrion.configuration
985          .allow_cookie_placement_before_explicit_consent === "1"
986      ) {
987        //Append to floodgate array in localStorage which is persisstent across pages.
988        window.metrion.floodgate_events =
989          JSON.parse(
990            localStorage.getItem(window.metrion.configuration.floodgate_name)
991          ) || [];
992        window.metrion.floodgate_events.push(event_data);
993        window.metrion.helpers.log_debug(
994          "Event floodgated using localStorage",
995          "log"
996        );
997        localStorage.setItem(
998          window.metrion.configuration.floodgate_name,
999          JSON.stringify(window.metrion.floodgate_events)
1000        );
1001      } else {
1002        //Append to floodgate array in JS variable which is not persisstent across pages!
1003        window.metrion.floodgate_events = window.metrion.floodgate_events || [];
1004        window.metrion.floodgate_events.push(event_data);
1005        window.metrion.helpers.log_debug(
1006          "Event floodgated using JS variable",
1007          "log"
1008        );
1009      }
1010    }
1011  },
1012
1013  // Send anonymous ping function
1014  send_ping: function (event_name, event_body) {
1015    var ping_url = metrion_api.api_url.replace(/\/?$/, "/") + "ping/";
1016    var origin = window.location.href;
1017    var referrer = document.referrer;
1018
1019    window.metrion.helpers.post_json(ping_url, {
1020      origin: origin,
1021      referrer: referrer,
1022      event: event_name,
1023      id: event_body[metrion_api.event_id_name],
1024    });
1025  },
1026
1027  // Advertising click ID capture and storage.
1028  //
1029  // Cookie format: {"<param>": ["<click_id>", <unix_milliseconds>]}, e.g.
1030  // {"gclid":["123",1725095000000]}. Milliseconds to match event_unix_timestamp
1031  // and every other event-level timestamp (all Date.now()); one shared cookie
1032  // keeps the value small, and at most max_click_ids touchpoints are kept with
1033  // the oldest evicted first.
1034  click_id_manager: {
1035    // Maximum number of click IDs kept in the cookie
1036    max_click_ids: 6,
1037    // Secondary guard for the 4KB per-domain cookie budget. encodeURIComponent
1038    // output is ASCII, so string length equals the byte length of the value.
1039    max_cookie_value_bytes: 3072,
1040    // Used when no cookie lifetime is configured
1041    default_cookie_lifetime_milliseconds: 365 * 86400 * 1000,
1042    // The canonical list lives in config/advertising_params.json and arrives as
1043    // metrion_api.advertising_params. This copy is only the safety net for when
1044    // that file cannot be read, so keep the two in sync.
1045    fallback_advertising_params: [
1046      "__hsfp",
1047      "__hssc",
1048      "__hstc",
1049      "__s",
1050      "_hsenc",
1051      "_openstat",
1052      "dclid",
1053      "fbclid",
1054      "gclid",
1055      "gbraid",
1056      "wbraid",
1057      "hsCtaTracking",
1058      "mc_eid",
1059      "mkt_tok",
1060      "ml_subscriber",
1061      "ml_subscriber_hash",
1062      "msclkid",
1063      "oly_anon_id",
1064      "oly_enc_id",
1065      "rb_clickid",
1066      "s_cid",
1067      "vero_conv",
1068      "vero_id",
1069      "wickedid",
1070      "yclid",
1071      "scid",
1072      "ttclid",
1073      "li_fat_id",
1074      "cnvsn_id",
1075      "nclid",
1076      "clickid",
1077      "tid",
1078      "clickId",
1079      "channelId",
1080      "advertiserId",
1081      "_kx",
1082      "twclid",
1083      "epik",
1084      "rdt_cid",
1085      "sccid",
1086      "awc",
1087      "tblci",
1088      "ob_click_id",
1089      "dicid",
1090      "irclickid",
1091      "vmcid"
1092    ],
1093
1094    // Allowlist of URL parameters to capture
1095    get_advertising_params: function () {
1096      var manager = window.metrion.click_id_manager;
1097      var configured = null;
1098      if (typeof metrion_api !== "undefined" && metrion_api) {
1099        configured = metrion_api.advertising_params;
1100      }
1101
1102      var allowlist = [];
1103      if (Object.prototype.toString.apply(configured) === "[object Array]") {
1104        for (var i = 0; i < configured.length; i++) {
1105          if (typeof configured[i] === "string" && configured[i] !== "") {
1106            allowlist.push(configured[i]);
1107          }
1108        }
1109      }
1110
1111      if (allowlist.length > 0) {
1112        return allowlist;
1113      }
1114
1115      window.metrion.helpers.log_debug(
1116        "No central advertising parameter list available, using built-in fallback",
1117        "log"
1118      );
1119      return manager.fallback_advertising_params;
1120    },
1121
1122    // Allowlisted parameters present in the current URL, as [{name, value}].
1123    // Matching is on the exact parameter name: a substring test against the query
1124    // string also matched other parameters' names and values (the query
1125    // "?irclickid=x" contains "clickid"), which stored empty click IDs.
1126    detect_in_url: function () {
1127      var manager = window.metrion.click_id_manager;
1128      var allowlist = manager.get_advertising_params();
1129      var detected = [];
1130
1131      for (var i = 0; i < allowlist.length; i++) {
1132        var value = window.metrion.helpers.get_url_parameter_value(allowlist[i]);
1133        if (typeof value === "string" && value !== "") {
1134          detected.push({ name: allowlist[i], value: value });
1135        }
1136      }
1137      return detected;
1138    },
1139
1140    // Separates a seconds-scale timestamp from a milliseconds one: 1e11 as
1141    // milliseconds is 1973, and as seconds it is the year 5138, so nothing real
1142    // falls on the wrong side.
1143    milliseconds_scale_threshold: 100000000000,
1144
1145    // One stored entry as [click_id, unix_milliseconds], or null when unusable
1146    normalize_entry: function (value) {
1147      var manager = window.metrion.click_id_manager;
1148
1149      // Current format: [click_id, unix_milliseconds]
1150      if (Object.prototype.toString.apply(value) === "[object Array]") {
1151        var click_id = window.metrion.helpers.safe_to_string(value[0]);
1152        if (click_id === "") {
1153          return null;
1154        }
1155        var timestamp = window.metrion.helpers.safe_parse_int(value[1]);
1156        if (timestamp < 0) {
1157          timestamp = 0;
1158        }
1159        // A timestamp written in seconds (an earlier build, or a hand-edited
1160        // cookie) is scaled up, otherwise it would look ancient next to a
1161        // millisecond one and always be the first evicted.
1162        if (timestamp > 0 && timestamp < manager.milliseconds_scale_threshold) {
1163          timestamp = timestamp * 1000;
1164        }
1165        return [click_id, timestamp];
1166      }
1167
1168      // Legacy flat format {"gclid":"123"}: the click ID is still usable but its
1169      // age is unknown, so it is stamped 0 and is the first to be evicted.
1170      if (typeof value === "string" && value !== "") {
1171        return [value, 0];
1172      }
1173
1174      return null;
1175    },
1176
1177    // Stored click IDs as {param: [click_id, unix_milliseconds]}. A corrupted or
1178    // malformed cookie yields an empty object instead of throwing.
1179    read: function () {
1180      var manager = window.metrion.click_id_manager;
1181      var stored = {};
1182      var raw_cookie_value = window.metrion.helpers.get_cookie_value(
1183        window.metrion.configuration.click_ids_cookie_name
1184      );
1185
1186      if (raw_cookie_value === null) {
1187        return stored;
1188      }
1189
1190      var parsed;
1191      try {
1192        // decodeURIComponent also throws on a malformed percent sequence
1193        parsed = JSON.parse(decodeURIComponent(raw_cookie_value));
1194      } catch (e) {
1195        window.metrion.helpers.log_debug(
1196          "Click id cookie could not be parsed, starting with an empty object",
1197          "log"
1198        );
1199        return stored;
1200      }
1201
1202      if (
1203        !parsed ||
1204        typeof parsed !== "object" ||
1205        Object.prototype.toString.apply(parsed) === "[object Array]"
1206      ) {
1207        return stored;
1208      }
1209
1210      for (var key in parsed) {
1211        if (!parsed.hasOwnProperty(key)) {
1212          continue;
1213        }
1214        var entry = manager.normalize_entry(parsed[key]);
1215        if (entry !== null) {
1216          stored[key] = entry;
1217        }
1218      }
1219      return stored;
1220    },
1221
1222    // Overwrite only the parameters present in this URL, with the current
1223    // timestamp. Other touchpoints (a stored gbraid when a gclid comes in) are
1224    // left untouched.
1225    apply_detected: function (stored, detected) {
1226      // Same unit as event_unix_timestamp and the other event-level timestamps
1227      var now_milliseconds = Date.now();
1228      for (var i = 0; i < detected.length; i++) {
1229        stored[detected[i].name] = [detected[i].value, now_milliseconds];
1230      }
1231      return stored;
1232    },
1233
1234    encode: function (stored) {
1235      return encodeURIComponent(JSON.stringify(stored));
1236    },
1237
1238    // FIFO: while over the key cap or the size budget, drop the oldest timestamp.
1239    // The last remaining entry is never dropped on size alone.
1240    enforce_limits: function (stored) {
1241      var manager = window.metrion.click_id_manager;
1242      var keys = [];
1243      for (var key in stored) {
1244        if (stored.hasOwnProperty(key)) {
1245          keys.push(key);
1246        }
1247      }
1248
1249      while (keys.length > 0) {
1250        var over_count = keys.length > manager.max_click_ids;
1251        var over_size =
1252          keys.length > 1 &&
1253          manager.encode(stored).length > manager.max_cookie_value_bytes;
1254        if (!over_count && !over_size) {
1255          break;
1256        }
1257
1258        var oldest_key = keys[0];
1259        for (var i = 1; i < keys.length; i++) {
1260          if (stored[keys[i]][1] < stored[oldest_key][1]) {
1261            oldest_key = keys[i];
1262          }
1263        }
1264
1265        window.metrion.helpers.log_debug(
1266          "Click id limit reached, evicting oldest click id: " + oldest_key,
1267          "log"
1268        );
1269        delete stored[oldest_key];
1270        keys.splice(keys.indexOf(oldest_key), 1);
1271      }
1272      return stored;
1273    },
1274
1275    // Persist when cookie placement is allowed, otherwise keep the encoded value
1276    // on the window so evaluate_consent_floodgate() can write it once consent
1277    // arrives. Same contract as before: an already encoded string.
1278    persist: function (stored) {
1279      var manager = window.metrion.click_id_manager;
1280      var encoded_value = manager.encode(stored);
1281      var cookie_lifetime = window.metrion.helpers.safe_parse_int(
1282        window.metrion.configuration.cookie_expiration_milliseconds
1283      );
1284      if (cookie_lifetime <= 0) {
1285        cookie_lifetime = manager.default_cookie_lifetime_milliseconds;
1286      }
1287
1288      if (
1289        window.metrion.configuration.floodgate_open ||
1290        window.metrion.configuration
1291          .allow_cookie_placement_before_explicit_consent === "1"
1292      ) {
1293        window.metrion.helpers.log_debug("Updating the click-id cookie...", "log");
1294        window.metrion.helpers.set_cookie(
1295          window.metrion.configuration.click_ids_cookie_name,
1296          encoded_value,
1297          cookie_lifetime,
1298          "/",
1299          window.metrion.helpers.get_cookie_domain(window.location.hostname)
1300        );
1301      } else {
1302        window.metrion.helpers.log_debug(
1303          "No acces to storage/cookies so store click id in JS",
1304          "log"
1305        );
1306        // Store in a temporary JS variable (non-persistent)
1307        window.metrion.click_ids = encoded_value;
1308      }
1309      return encoded_value;
1310    },
1311
1312    // The click ID string for one parameter, or undefined when not stored.
1313    // Reads both the current [click_id, unix_milliseconds] format and the legacy flat
1314    // format, so destination scripts never have to know which one is in the
1315    // cookie. Never throws.
1316    get_click_id: function (param_name) {
1317      try {
1318        var entry = window.metrion.click_id_manager.read()[param_name];
1319        if (!entry) {
1320          return undefined;
1321        }
1322        return entry[0];
1323      } catch (e) {
1324        return undefined;
1325      }
1326    },
1327
1328    // Read, merge, cap and store. Never throws: a failure here must not stop the
1329    // session and page_view events.
1330    store: function (detected) {
1331      var manager = window.metrion.click_id_manager;
1332      try {
1333        if (!detected || detected.length === 0) {
1334          return null;
1335        }
1336        var stored = manager.apply_detected(manager.read(), detected);
1337        manager.enforce_limits(stored);
1338        return manager.persist(stored);
1339      } catch (e) {
1340        window.metrion.helpers.log_debug("Click id storage failed: " + e, "log");
1341        return null;
1342      }
1343    },
1344  },
1345
1346  // JS session definition logic
1347  session_event_logic: function () {
1348    window.metrion.helpers.log_debug("Start session logic function", "log");
1349
1350    // Reload session exclusion
1351    var nav = [];
1352    if (
1353      typeof performance !== "undefined" &&
1354      typeof performance.getEntriesByType === "function"
1355    ) {
1356      nav = performance.getEntriesByType("navigation");
1357    }
1358    if (nav.length > 0 && nav[0] && nav[0].type === "reload") {
1359      return;
1360    }
1361
1362    // Payment session exclusions
1363    var payment_referrer_exclusions = [
1364      "anbamro.nl",
1365      "asnbank.nl",
1366      "pay.mollie.nl",
1367      "mollie.com",
1368      "ecommerce-gateway.mollie.com",
1369      "paypal.com",
1370      "klarna.com",
1371      "girogate.be",
1372      "snsbank.nl",
1373      "rabobank.nl",
1374      "knab.nl",
1375      "bunq.com",
1376      ".ing.nl",
1377      "regiobank.nl",
1378      "triodos.nl",
1379      "vanlanschot.nl",
1380      "moneyou.nl",
1381      "multisafepay.com",
1382      "agone.com",
1383      "pay.nl",
1384      "sips-atos.com",
1385      "curopayments.net",
1386      "ideal.nl",
1387      "adyen.com",
1388      "afterpay.nl",
1389      "tikkie.me",
1390      "buckaroo.nl",
1391      "sisow.nl",
1392      "targetpay.com",
1393      "paypro.nl",
1394      "icepay.nl",
1395      "omnikassa.rabobank.nl",
1396      "postnl.nl",
1397      "billink.nl",
1398      "spraypay.nl",
1399      "capayable.nl",
1400      "in3.nl",
1401      "klarna.nl",
1402      "vividmoney.nl",
1403      "revolut.com",
1404      "n26.com",
1405      "wise.com",
1406      "bancontact.com",
1407      "belfius.be",
1408      "cbc.be",
1409      "kbc.be",
1410      ".ing.be",
1411      "bnpparibasfortis.be",
1412      "keytradebank.be",
1413      "argenta.be",
1414      "fintro.be",
1415      "hellobank.be",
1416      "crelan.be",
1417      "axabank.be",
1418      "recordbank.be",
1419      "sofort.com",
1420      "stripe.com",
1421      "worldline.com",
1422      "eps-payment.eu",
1423      "ogone.com",
1424      "viva.com",
1425      "twikey.com",
1426      "hipay.com",
1427      "payconiq.com",
1428      "postfinance.be",
1429      "six-payment-services.com",
1430    ];
1431    var regex_payment = new RegExp(
1432      payment_referrer_exclusions
1433        .map(function (domain) {
1434          return domain.replace(/\./g, "\\.");
1435        })
1436        .join("|"),
1437      "i"
1438    );
1439
1440    if (regex_payment.test(document.referrer)) {
1441      return;
1442    }
1443
1444    // Referrer session evaluation
1445    if (document.referrer !== "") {
1446      var referrerHost = new URL(document.referrer).hostname
1447        .split(".")
1448        .slice(-2)
1449        .join(".");
1450      var currentHost = location.hostname.split(".").slice(-2).join(".");
1451      if (referrerHost !== currentHost) {
1452        window.metrion.configuration.session_start_trigger = true;
1453        window.metrion.configuration.session_start_reasons.push("new referrer");
1454      }
1455    } else {
1456      window.metrion.configuration.session_start_trigger = true;
1457      window.metrion.configuration.session_start_reasons.push("no referrer");
1458    }
1459
1460    // UTM session evaluation
1461    if (window.location.search.indexOf("utm_") > -1) {
1462      window.metrion.configuration.session_start_trigger = true;
1463      window.metrion.configuration.session_start_reasons.push("utms detected");
1464    }
1465
1466    // Advertising click tracker evaluation. The canonical parameter list lives in
1467    // config/advertising_params.json and reaches the front end through
1468    // metrion_api.advertising_params.
1469    var detected_advertising_params =
1470      window.metrion.click_id_manager.detect_in_url();
1471    var detected_advertising_param_names = [];
1472    for (
1473      var advertising_param_i = 0;
1474      advertising_param_i < detected_advertising_params.length;
1475      advertising_param_i++
1476    ) {
1477      detected_advertising_param_names.push(
1478        detected_advertising_params[advertising_param_i].name
1479      );
1480    }
1481    var known_advertising_param_present =
1482      detected_advertising_params.length > 0;
1483    window.metrion.helpers.log_debug(
1484      "Detected params: " + detected_advertising_param_names.join(","),
1485      "log"
1486    );
1487
1488    // Add the context and click ids if they are available
1489    if (
1490      known_advertising_param_present &&
1491      window.location.search.indexOf("_gl") === -1
1492    ) {
1493      window.metrion.configuration.session_start_trigger = true;
1494      window.metrion.configuration.session_start_reasons.push(
1495        "advertising param detected"
1496      );
1497      window.metrion.helpers.log_debug(
1498        "Advertising parameters detected",
1499        "log"
1500      );
1501
1502      window.metrion.click_id_manager.store(detected_advertising_params);
1503    }
1504
1505    // Check if a duplicate session start is being triggered (when sessionStorage is available)
1506    var duplicate_session_start = false;
1507    if (
1508      window.metrion.configuration.session_start_trigger &&
1509      typeof sessionStorage !== "undefined" &&
1510      window.metrion.configuration.floodgate_open
1511    ) {
1512      var current_session_info = JSON.stringify({
1513        reasons: window.metrion.configuration.session_start_reasons,
1514        referrer: document.referrer,
1515        search: window.location.search,
1516      });
1517      var previous_session_info = sessionStorage.getItem(
1518        window.metrion.configuration.session_info_storage_name
1519      );
1520      // Duplicate session_start information detected.
1521      if (current_session_info === previous_session_info) {
1522        duplicate_session_start = true;
1523      } else {
1524        if (
1525          window.metrion.configuration
1526            .allow_cookie_placement_before_explicit_consent === "1"
1527        ) {
1528          sessionStorage.setItem(
1529            window.metrion.configuration.session_info_storage_name,
1530            current_session_info
1531          );
1532        } else {
1533          // Otherwise just add it to the window for later placement
1534          window.metrion.session_info = JSON.stringify({
1535            reasons: window.metrion.configuration.session_start_reasons,
1536            referrer: document.referrer,
1537            search: window.location.search,
1538          });
1539        }
1540      }
1541    }
1542    // Otherwise just add it to the window for later placement
1543    else {
1544      window.metrion.session_info = JSON.stringify({
1545        reasons: window.metrion.configuration.session_start_reasons,
1546        referrer: document.referrer,
1547        search: window.location.search,
1548      });
1549    }
1550
1551    // No session id exists
1552    if (
1553      window.metrion.helpers.get_cookie_value(
1554        window.metrion.configuration.session_cookie_name
1555      ) === null
1556    ) {
1557      window.metrion.configuration.session_start_trigger = true;
1558      window.metrion.configuration.session_start_reasons.push("no session id");
1559    }
1560
1561    // Metrion default session evaluation
1562    if (!duplicate_session_start) {
1563      if (
1564        window.metrion.configuration
1565          .allow_cookie_placement_before_explicit_consent === "1" &&
1566        !window.metrion.configuration.floodgate_open &&
1567        window.metrion.configuration.session_start_trigger
1568      ) {
1569        window.metrion.session_manager.create_session_cookie();
1570      } else if (
1571        window.metrion.configuration.floodgate_open &&
1572        window.metrion.configuration.session_start_trigger
1573      ) {
1574        window.metrion.session_manager.create_session_cookie();
1575      }
1576      window.metrion.helpers.log_debug(
1577        "Eligible session_start: " +
1578        window.metrion.configuration.session_start_trigger.toString(),
1579        "log"
1580      );
1581      window.metrion.helpers.log_debug(
1582        "Eligible session_start reasons: " +
1583        window.metrion.configuration.session_start_reasons.toString(),
1584        "log"
1585      );
1586
1587      if (window.metrion.configuration.session_start_trigger) {
1588        window.metrion.configuration.session_start_trigger = false;
1589        window.metrion.send_event(
1590          "session_start",
1591          {
1592            reason:
1593              window.metrion.configuration.session_start_reasons.toString(),
1594            trigger_type: "front-end",
1595          },
1596          {}
1597        );
1598      }
1599    }
1600    // Cover the cookie if the session cookie is gone in a duplicate session state
1601    else if (
1602      duplicate_session_start &&
1603      window.metrion.configuration.session_start_trigger &&
1604      window.metrion.helpers.get_cookie_value(
1605        window.metrion.configuration.session_cookie_name
1606      ) === null &&
1607      window.metrion.configuration.floodgate_open
1608    ) {
1609      window.metrion.session_manager.create_session_cookie();
1610    }
1611  },
1612
1613  // JS pageview event logic
1614  page_view_event_logic: function () {
1615    window.metrion.configuration.pageview_send =
1616      window.metrion.configuration.pageview_send || false;
1617    if (!window.metrion.configuration.pageview_send) {
1618      window.metrion.send_event("page_view", {
1619        trigger_type: "front-end",
1620      });
1621      window.metrion.configuration.pageview_send = true;
1622    }
1623  },
1624};
1625
1626window.metrion.configuration.cookie_domain = window.metrion.helpers.get_cookie_domain(window.location.hostname);
1627;
1628
1629// Cookiebot
1630// This file can be evaluated more than once on a single page (it is part of the
1631// core bundle and is also served standalone by the /cmp fallback endpoint), so
1632// state that has to survive a re-evaluation is only initialised when undefined.
1633if (typeof window.metrion.consent_manager.initialized === "undefined") {
1634    window.metrion.consent_manager.initialized = false;
1635}
1636if (typeof window.metrion.consent_manager.listeners_initialized === "undefined") {
1637    window.metrion.consent_manager.listeners_initialized = false;
1638}
1639// Registry of the window listeners this file attached. cmp_init() runs on every
1640// initial_consent_enforcement() call, so without it every consent update would
1641// attach yet another copy of the same listener.
1642if (typeof window.metrion.consent_manager.cookiebot_listeners_attached === "undefined") {
1643    window.metrion.consent_manager.cookiebot_listeners_attached = {};
1644}
1645// Raw CookieConsent value that was last mirrored into the Metrion consent cookie.
1646// Used to tell Cookiebot's on-load re-fire of CookiebotOnAccept/OnDecline apart
1647// from a real consent change on the same page.
1648if (typeof window.metrion.consent_manager.cookiebot_last_synced_consent === "undefined") {
1649    window.metrion.consent_manager.cookiebot_last_synced_consent = null;
1650}
1651window.metrion.consent_manager.cmp_version = "cookiebot-legacy";
1652window.metrion.consent_manager.cmp_js_in_bundle = "cookiebot";
1653
1654// Storage access can throw (Safari private mode, blocked storage, sandboxed iframes).
1655// Treat a throwing or missing storage the same as a missing key.
1656window.metrion.consent_manager.cookiebot_storage_get = function(storage_name, key) {
1657    try {
1658        var storage = window[storage_name];
1659        if (typeof storage === "undefined" || storage === null) {
1660            return null;
1661        }
1662        return storage.getItem(key);
1663    } catch (e) {
1664        return null;
1665    }
1666};
1667
1668// Attach a listener at most once per registry key, regardless of how often cmp_init() runs
1669window.metrion.consent_manager.cookiebot_add_listener_once = function(context, event_name, handler, registry_key) {
1670    var key = registry_key || event_name;
1671    var registry = window.metrion.consent_manager.cookiebot_listeners_attached;
1672    if (registry[key] === true) {
1673        return false;
1674    }
1675    registry[key] = true;
1676    window.metrion.helpers.log_debug(("Add listener for consent update: " + event_name), "log");
1677    context.addEventListener(event_name, handler);
1678    return true;
1679};
1680
1681// Usercentrics documents "EXPLICIT"/"IMPLICIT" for the dataLayer and uses lower case in
1682// several examples, so compare case-insensitively.
1683window.metrion.consent_manager.cookiebot_is_consent_type = function(type_value, expected) {
1684    return typeof type_value === "string" && type_value.toLowerCase() === expected;
1685};
1686
1687// Marketing consent ("1"/"0") from a Usercentrics consent payload, or null when the
1688// payload carries no category information. Handles the shapes Usercentrics emits:
1689// - v2 dataLayer / window event:  ucCategory.marketing = true|false|null
1690// - v3 UC_CONSENT:                categories.marketing.state = "ALL_ACCEPTED"|...,
1691//                                 categories.marketing = true|false, consent.status
1692window.metrion.consent_manager.cookiebot_uc_marketing_consent = function(payload) {
1693    if (!payload || typeof payload !== "object") {
1694        return null;
1695    }
1696    var marketing;
1697    if (payload.categories && typeof payload.categories === "object") {
1698        marketing = payload.categories.marketing;
1699        if (Array.isArray(payload.categories)) {
1700            marketing = undefined;
1701            for (var category_i = 0; category_i < payload.categories.length; category_i++) {
1702                var category = payload.categories[category_i];
1703                if (category && (category.slug === "marketing" || category.categorySlug === "marketing")) {
1704                    marketing = category;
1705                    break;
1706                }
1707            }
1708        }
1709        if (marketing && typeof marketing === "object") {
1710            if (typeof marketing.state === "string") {
1711                return marketing.state === "ALL_ACCEPTED" ? "1" : "0";
1712            }
1713            if (typeof marketing.consent === "boolean") {
1714                return marketing.consent ? "1" : "0";
1715            }
1716        }
1717        if (typeof marketing === "boolean") {
1718            return marketing ? "1" : "0";
1719        }
1720    }
1721    if (payload.ucCategory && typeof payload.ucCategory === "object" && typeof payload.ucCategory.marketing === "boolean") {
1722        return payload.ucCategory.marketing ? "1" : "0";
1723    }
1724    if (payload.consent && typeof payload.consent.status === "string") {
1725        if (payload.consent.status === "ALL_ACCEPTED") {
1726            return "1";
1727        }
1728        if (payload.consent.status === "ALL_DENIED") {
1729            return "0";
1730        }
1731    }
1732    return null;
1733};
1734
1735// Write the Metrion consent cookie. Marketing and PII share one flag, user id and session id share one flag.
1736window.metrion.consent_manager.cookiebot_write_consent_cookie = function(allow_marketing, allow_identifiers) {
1737    var encoded_cookie_value = encodeURIComponent(JSON.stringify({
1738        "allow_marketing": allow_marketing,
1739        "allow_pii": allow_marketing,
1740        "allow_uid": allow_identifiers,
1741        "allow_sid": allow_identifiers,
1742        "b": window.metrion.configuration.blocking_detected,
1743        "unix": Date.now()
1744    }));
1745    window.metrion.helpers.log_debug(encoded_cookie_value, "log");
1746    window.metrion.helpers.set_consent_cookie(encoded_cookie_value);
1747    window.metrion.helpers.log_debug("Metrion consent cookie set", "log");
1748    return encoded_cookie_value;
1749};
1750
1751// Explicit consent is known: open the floodgate and mark the CMP update as handled
1752window.metrion.consent_manager.cookiebot_open_floodgate = function(allow_marketing) {
1753    // Set the marketing metrion cookie value for dynamic loading of destinations
1754    window.metrion.configuration.cmp_allow_marketing = allow_marketing === "1";
1755    window.metrion.configuration.floodgate_open = true;
1756    window.metrion.helpers.log_debug("Metrion floodgate_open set to true.", "log");
1757    window.metrion.configuration.cmp_update_handled = true;
1758};
1759
1760// Whether the current Metrion consent cookie already allows marketing
1761window.metrion.consent_manager.cookiebot_current_allow_marketing = function() {
1762    var metrion_consent_cookie = window.metrion.helpers.get_cookie_value(window.metrion.configuration.consent_cookie_name);
1763    if (metrion_consent_cookie === null) {
1764        return false;
1765    }
1766    try {
1767        return JSON.parse(decodeURIComponent(metrion_consent_cookie)).allow_marketing === "1";
1768    } catch (e) {
1769        return false;
1770    }
1771};
1772
1773// Mirror a Usercentrics consent change (UC_CONSENT / uc-event payload) into Metrion.
1774// Shared by the UC v3 UC_CONSENT listener and the UC v2 window event listener.
1775window.metrion.consent_manager.cookiebot_apply_uc_consent = function(payload) {
1776    // CMP update is already handled, if so, extend the timeout
1777    if (window.metrion.configuration.cmp_update_handled) {
1778        window.metrion.consent_manager.timeout_consent_listener_updates();
1779    }
1780
1781    var uc_allow_marketing = window.metrion.consent_manager.cookiebot_uc_marketing_consent(payload) === "1" ? "1" : "0";
1782    window.metrion.helpers.log_debug((uc_allow_marketing + "-" + uc_allow_marketing), "log");
1783
1784    // Remember the state before overwriting the cookie so destinations can be loaded when marketing turns on
1785    var previous_allow_marketing = window.metrion.consent_manager.cookiebot_current_allow_marketing();
1786
1787    // Sync/mirror the Metrion cookie based on the UC consent change
1788    window.metrion.consent_manager.cookiebot_write_consent_cookie(uc_allow_marketing, "1");
1789
1790    // Update Metrion consent settings after setting the consent cookie
1791    window.metrion.consent_manager.cookiebot_open_floodgate(uc_allow_marketing);
1792
1793    // Trigger initial consent enforcement again (releases floodgated events)
1794    window.metrion.consent_manager.initial_consent_enforcement();
1795
1796    // initial_consent_enforcement() reads the consent cookie before cmp_init(
1796) and only loads
1797    // destinations when that cookie still said "0". The cookie was already updated above, so
1798    // handle the "marketing just got allowed" transition here.
1799    if (uc_allow_marketing === "1" && !previous_allow_marketing) {
1800        window.metrion.consent_manager.load_destination_js_dynamically();
1801    }
1802};
1803
1804window.metrion.consent_manager.cmp_init = function(){
1805    // Set basic detection variables
1806    var cookiebot_version = "cookiebot-legacy";
1807    var cookiebot_initial_allow_marketing = "0";
1808    var cookiebot_explicit_consent = false;
1809
1810    // Marketing consent from the Usercentrics legacy UC_UI API: "1" when any marketing service is consented
1811    function usercentrics_legacy_marketing_consent(){
1812        var allow_marketing = "0";
1813        if(typeof(window.UC_UI) === "undefined" || typeof(window.UC_UI.getServicesBaseInfo) !== "function"){
1814            return allow_marketing;
1815        }
1816        var accepted_services = window.UC_UI.getServicesBaseInfo();
1817        // Check if the marketing caterogy is accepted
1818        if(Array.isArray(accepted_services) && accepted_services.length > 0){
1819            for(var service_i = 0; service_i < accepted_services.length; service_i++){
1820                var service = accepted_services[service_i];
1821                if(service && service.categorySlug === "marketing" && service.consent && service.consent.status === true){
1822                    allow_marketing = "1";
1823                    break;
1824                }
1825            }
1826        }
1827        return allow_marketing;
1828    }
1829
1830    // 1. Usercentrics legacy edition
1831    function usercentrics_legacy_init(){
1832        if(window.metrion.consent_manager.cookiebot_storage_get("sessionStorage", "uc_user_country") !== null &&
1833            window.metrion.consent_manager.cookiebot_storage_get("localStorage", "uc_ui_version") !== null){
1834            cookiebot_version = "uc-version-legacy";
1835            window.metrion.consent_manager.cmp_version = cookiebot_version;
1836
1837            // Check Usercentrics legacy window object and if there has been an user interaction
1838            if(typeof(window.UC_UI) !== "undefined" && window.metrion.consent_manager.cookiebot_storage_get("localStorage", "uc_user_interaction") === "true"){
1839                var allow_marketing_initial = usercentrics_legacy_marketing_consent();
1840                // Set Metrion consent cookie based on Usercentrics legacy
1841                window.metrion.consent_manager.cookiebot_write_consent_cookie(allow_marketing_initial, "1");
1842                // Explicit consent exists: open the floodgate, same as the Cookiebot legacy branch does
1843                window.metrion.consent_manager.cookiebot_open_floodgate(allow_marketing_initial);
1844            }
1845        }
1846        // Set initial listeners
1847        window.metrion.consent_manager.cookiebot_add_listener_once(window, 'UC_UI_INITIALIZED', function(event) {
1848            window.metrion.helpers.log_debug("Cookiebot version listener: Usercentrics legacy edition");
1849            if(typeof(window.UC_UI) !== "undefined"){
1850                var allow_marketing_initial = usercentrics_legacy_marketing_consent();
1851                // Set Metrion consent cookie based on Usercentrics legacy
1852                window.metrion.consent_manager.cookiebot_write_consent_cookie(allow_marketing_initial, "1");
1853            }
1854        }, "UC_UI_INITIALIZED:legacy");
1855        return "uc-legacy";
1856    }
1857
1858    // 2. Usercentrics modern edition
1859    function usercentrics_modern_init(){
1860        if(window.metrion.consent_manager.cookiebot_storage_get("localStorage", "ucData") !== null){
1861            cookiebot_version = "uc-version-modern";
1862            window.metrion.consent_manager.cmp_version = cookiebot_version;
1863
1864            // UC dataLayer
1865            if (window.dataLayer &&
1866                Object.prototype.toString.apply(window.dataLayer) === '[object Array]') {
1867                for (var i = 0; i < window.dataLayer.length; i++) {
1868                    var item = window.dataLayer[i];
1869                    if (item &&
1870                        typeof item === 'object' &&
1871                        item.hasOwnProperty('ucCategory') &&
1872                        item.hasOwnProperty('type') &&
1873                        item.hasOwnProperty('action')
1874                    ) {
1875                            // UC has posted data to the dataLayer
1876                            window.metrion.helpers.log_debug("CMP Cookiebot UC detected in dataLayer", "log");
1877                            // UC has explicit consent
1878                            if(window.metrion.consent_manager.cookiebot_is_consent_type(item['type'], 'explicit')){
1879                                cookiebot_explicit_consent = true;
1880                            }
1881                            // Set initial marketing consent (null means a mixed state, keep the previous value)
1882                            if(item['ucCategory'] && item['ucCategory']["marketing"] === true){
1883                                cookiebot_initial_allow_marketing = "1";
1884                            }
1885                            if(item['ucCategory'] && item['ucCategory']["marketing"] === false){
1886                                cookiebot_initial_allow_marketing = "0";
1887                            }
1888                    }
1889                }
1890            } else {
1891                window.metrion.helpers.log_debug("CMP Cookiebot UC datalayer check fails, no UC dataLayer", "log");
1892            }
1893            // UC explicit consent was given
1894            if(cookiebot_explicit_consent === true && window.metrion.consent_manager.initialized === false){
1895                window.metrion.helpers.log_debug("CMP Cookiebot UC explicit consent found in dataLayer", "log");
1896                //Prevent this script from running everytime
1897                window.metrion.consent_manager.initialized = true;
1898                // Sync/mirror the Metrion cookie based on the UC consent state
1899                window.metrion.consent_manager.cookiebot_write_consent_cookie(cookiebot_initial_allow_marketing, "1");
1900                // Explicit consent exists: open the floodgate, same as the Cookiebot legacy branch does
1901                window.metrion.consent_manager.cookiebot_open_floodgate(cookiebot_initial_allow_marketing);
1902            }
1903
1904            // Modern usercentrics: the (configurable) UC window event mirrors the dataLayer object
1905            window.metrion.consent_manager.cookiebot_add_listener_once(window, 'UC_UI_INITIALIZED', function(event) {
1906                window.metrion.consent_manager.cookiebot_add_listener_once(window, 'uc-event', function (uc_event) {
1907                    var uc_detail = uc_event ? uc_event.detail : null;
1908                    if(!uc_detail || uc_detail.event !== 'consent_status'){
1909                        return;
1910                    }
1911                    window.metrion.consent_manager.cmp_version = "uc-version-modern";
1912                    // No explicit consent given yet
1913                    if (window.metrion.consent_manager.cookiebot_is_consent_type(uc_detail.type, 'implicit')) {
1914                        window.metrion.helpers.log_debug("CMP Cookiebot UC first visit with implicit consent state", "log");
1915                        return;
1916                    }
1917                    // Explicit consent given  > Update Metrion cookie
1918                    if (window.metrion.consent_manager.cookiebot_is_consent_type(uc_detail.type, 'explicit')) {
1919                        window.metrion.helpers.log_debug("CMP Cookiebot UC has explicit consent", "log");
1920                        window.metrion.consent_manager.cookiebot_apply_uc_consent(uc_detail);
1921                    }
1922                }, "uc-event");
1923            }, "UC_UI_INITIALIZED:modern");
1924        }
1925        return "uc-version-modern";
1926    }
1927
1928    // 3. LEGACY COOKIEBOT
1929    function cookiebot_legacy_init(){
1930        if(window.metrion.consent_manager.cmp_version === "cookiebot-legacy"){
1931            // If the CookieConsent cookie is available (!== null), then sync this cookie with Metrion consent cookie
1932            var raw_cookiebot_cookie = window.metrion.helpers.get_cookie_value("CookieConsent");
1933            if (raw_cookiebot_cookie !== null) {
1934                // Read Cookiebot's consent cookie
1935                var cookiebot_cookie = decodeURIComponent(raw_cookiebot_cookie);
1936                var cookiebot_allow_marketing = Number(cookiebot_cookie.indexOf("marketing:true") > -1).toString();
1937                var cookiebot_allow_necessary = Number(cookiebot_cookie.indexOf("necessary:true") > -1).toString();
1938
1939                // Set Metrion consent cookie
1940                window.metrion.consent_manager.cookiebot_write_consent_cookie(cookiebot_allow_marketing, cookiebot_allow_necessary);
1941                window.metrion.consent_manager.cookiebot_last_synced_consent = raw_cookiebot_cookie;
1942
1943                // Update Metrion consent settings after setting the consent cookie
1944                window.metrion.consent_manager.cookiebot_open_floodgate(cookiebot_allow_marketing);
1945            }
1946        }
1947        // Nonetheless of the settings, create listeners for CMP consent updates
1948        window.metrion.consent_manager.cmp_update_listener("CookiebotOnAccept", window);
1949        window.metrion.consent_manager.cmp_update_listener("CookiebotOnDecline", window);
1950        return "cookiebot-legacy";
1951    }
1952
1953    // Run all init functions
1954    usercentrics_legacy_init();
1955    usercentrics_modern_init();
1956    cookiebot_legacy_init();
1957    window.metrion.helpers.log_debug(("Set the consent update listeners for: " + window.metrion.configuration.cmp_selection), "log");
1958    return "cmp init finished";
1959};
1960
1961// Function that adds event listeners for the chosen CMP
1962window.metrion.consent_manager.cmp_update_listener = function(cmp_update_trigger, context) {
1963    var trigger_uc_listeners = false;
1964    if(window.metrion.consent_manager.listeners_initialized === false){
1965        window.metrion.consent_manager.listeners_initialized = true;
1966        trigger_uc_listeners = true;
1967    }
1968
1969    var cookiebot_version = "cookiebot-legacy";
1970    // Only check for the ucData element for cmp update listeners
1971    if(window.metrion.consent_manager.cookiebot_storage_get("localStorage", "ucData") !== null){
1972        cookiebot_version = "uc-version-modern";
1973    }
1974
1975    // Legacy cookiebot listener
1976    if(cookiebot_version === "cookiebot-legacy"){
1977        // FOR LEGACY COOIEBOT
1978        window.metrion.consent_manager.cookiebot_add_listener_once(context, cmp_update_trigger, function () {
1979            // Check current status of consent cookie
1980            var metrion_consent_cookie = window.metrion.helpers.get_cookie_value(window.metrion.configuration.consent_cookie_name);
1981            window.metrion.helpers.log_debug(("Event listener " + cmp_update_trigger + " triggered with metrion consent cookie value: " + (metrion_consent_cookie || "null")), "log");
1982
1983            // Cookiebot fires CookiebotOnAccept/OnDecline on every page load with existing consent.
1984            // Skip that re-fire when the update was already handled AND the C
1984ookiebot cookie is
1985            // unchanged since it was mirrored. A changed cookie is a real (re)decision, including a
1986            // withdrawal on the same page, and is always processed.
1987            var current_cookiebot_cookie = window.metrion.helpers.get_cookie_value("CookieConsent");
1988            if (window.metrion.configuration.cmp_update_handled &&
1989                current_cookiebot_cookie === window.metrion.consent_manager.cookiebot_last_synced_consent) {
1990                // Extend timeout
1991                window.metrion.consent_manager.timeout_consent_listener_updates();
1992                return;
1993            }
1994
1995            // update Metrion consent cookie
1996            window.metrion.helpers.log_debug("Trigger the initial consent enforcement after CMP update event listener", "log");
1997            window.metrion.consent_manager.initial_consent_enforcement();
1998        });
1999    }
2000
2001    if(trigger_uc_listeners){
2002        // The UC consent change event listener
2003        window.metrion.consent_manager.cookiebot_add_listener_once(window, 'UC_CONSENT', function (event) {
2004            window.metrion.helpers.log_debug("Cookiebot UC consent changed", "log");
2005            window.metrion.helpers.log_debug(event, "log");
2006            window.metrion.consent_manager.cookiebot_apply_uc_consent(event ? event.detail : null);
2007        });
2008    }
2009};
2010
2011// Check CMP consent status
2012window.metrion.consent_manager.has_explicit_cmp_consent = function(){
2013    var has_explicit_consent = false;
2014
2015    // UC Legacy
2016    if(window.metrion.consent_manager.cookiebot_storage_get("localStorage", "uc_user_interaction") === "true"){
2017        has_explicit_consent = true;
2018    }
2019
2020    // UC modern: an explicit consent_status entry in the dataLayer
2021    if(!has_explicit_consent && window.dataLayer && Object.prototype.toString.apply(window.dataLayer) === '[object Array]'){
2022        for (var i = 0; i < window.dataLayer.length; i++) {
2023            var item = window.dataLayer[i];
2024            if (item && typeof item === 'object' && item.event === "consent_status" &&
2025                window.metrion.consent_manager.cookiebot_is_consent_type(item.type, 'explicit')) {
2026                has_explicit_consent = true;
2027                break;
2028            }
2029        }
2030    }
2031
2032    // LEGACY COOKIEBOT
2033    if(!has_explicit_consent){
2034        has_explicit_consent = window.metrion.helpers.get_cookie_value("CookieConsent") !== null;
2035    }
2036    return has_explicit_consent;
2037};
2038
2039
2040// This block should run ONLY ONCE on page load (e.g., in your main Metrion script initialization).
2041// It is wrapped in an IIFE so every wrapper keeps its own reference to the push
2042// it replaced. With a global "var original_push" a second evaluation of this
2043// file rebinds that single global to the first wrapper, which then calls itself
2044// endlessly (RangeError: Maximum call stack size exceeded).
2045(function () {
2046    window.dataLayer = window.dataLayer || [];
2047
2048    // Already patched by an earlier evaluation of this file: do nothing.
2049    if (typeof window.dataLayer.push === "function" && window.dataLayer.push.metrion_patched === true) {
2050        return;
2051    }
2052
2053    var data_layer = window.dataLayer;
2054    var original_push = data_layer.push;
2055    if (typeof original_push !== "function") {
2056        original_push = Array.prototype.push;
2057    }
2058
2059    var metrion_push = function () {
2060        // CRITICAL: Call the original push function exactly once, on the array
2061        // (an unbound call would otherwise push onto window). Push FIRST so the
2062        // dataLayer scan in cmp_init() can see the entry that triggered this.
2063        var target = (this && this !== window) ? this : data_layer;
2064        var result = original_push.apply(target, arguments);
2065
2066        // Check if the push call contains a relevant Usercentrics event
2067        try {
2068            if(arguments.length > 0 && typeof(arguments[0]) === "object" && arguments[0] !== null && typeof(arguments[0].event) !== "undefined"){
2069                var event_object = arguments[0];
2070                // Only proceed if it is an explicit consent update event
2071                if(event_object.event === "consent_status" &&
2072                    window.metrion && window.metrion.consent_manager &&
2073                    window.metrion.consent_manager.cookiebot_is_consent_type(event_object.type, 'explicit')){
2074                    // --- Custom Logic Triggered ONLY HERE ---
2075                    // Trigger initial consent enforcement again
2076                    if (typeof window.metrion.consent_manager.initial_consent_enforcement === "function") {
2077                        window.metrion.consent_manager.initial_consent_enforcement();
2078                    }
2079                }
2080            }
2081        } catch (e) {
2082            // Never let Metrion logic break another script's dataLayer.push call
2083        }
2084        return result;
2085    };
2086
2087    metrion_push.metrion_patched = true;
2088    window.dataLayer.push = metrion_push;
2089})();
2090
2091;
2092
2093(function() {
2094    if (window.metrion && window.metrion_api) {  
2095        // Check if there is a mismatch in CMP selection vs the code in the bundle
2096        if (window.metrion.configuration.cmp_selection !== window.metrion.consent_manager.cmp_js_in_bundle) {
2097            window.metrion.helpers.log_debug("CMP selection mismatch: " + window.metrion.configuration.cmp_selection + " vs " + window.metrion.consent_manager.cmp_js_in_bundle, "log");
2098            
2099
2100            // Get Metrion metadata      
2101            var api_url = metrion_api.api_url.replace(/\/?$/, "/");
2102            var cmp_bundle_path = "cmp";
2103            var ver = metrion_api.bundle_version ? "?ver=" + metrion_api.bundle_version : "";
2104            var cmp_bundle_url = api_url + cmp_bundle_path + ver;
2105
2106            // Async load the fallback CMP JS
2107            var s = document.createElement('script');
2108            s.type = 'text/javascript';
2109            s.async = true; 
2110            s.defer = true;
2111            s.src = cmp_bundle_url;
2112            var x = document.getElementsByTagName('script')[0];        
2113            
2114            // Insert the new script before the existing one
2115            if (x && x.parentNode) {
2116                x.parentNode.insertBefore(s, x);
2117            } else {
2118                document.head.appendChild(s); // Safe fallback just in case
2119            }
2120
2121
2122            // Send status event for missing mismatch JS with settings from Metrion sync platform
2123            window.metrion.send_event("status_event", {
2124                "message": "CMP mismatch fallback required",
2125                "id": "fallback_cmp_mismatch_js"
2126            }, {});
2127        }
2128    }
2129})();  
2130
2131;
2132
2133// Prevent overwriting of objects and preserve existing properties
2134window.metrion = window.metrion || {};
2135// Set the flag globally on the window to retain its state across page reloads
2136window.metrion.woocommerce_purchase_logic_triggered = false;
2137
2138// Key conversion front-end monitoring
2139window.metrion.purchase_conversion_network_monitoring = function(target_input, timeout_ms) {
2140    var duration = timeout_ms || 10000;
2141    
2142    // Normalize input so it's ALWAYS an array of objects
2143    var raw_targets = Array.isArray(target_input) ? target_input : [target_input];
2144    var new_targets = [];
2145    
2146    for (var k = 0; k < raw_targets.length; k++) {
2147        var item = raw_targets[k];
2148        if (typeof item === 'string') {
2149            new_targets.push({ target: item }); 
2150        } else if (item && item.target) {
2151            new_targets.push(item); 
2152        }
2153    }
2154
2155    if (new_targets.length === 0) return;
2156
2157    // --- Domain Filtering Helpers ---
2158    var get_root_domain = function(hostname) {
2159        var parts = hostname.split('.');
2160        if (parts.length <= 2) return hostname;
2161        return parts.slice(-2).join('.');
2162    };
2163
2164    var current_root = get_root_domain(window.location.hostname);
2165
2166    var is_external = function(url) {
2167        if (!url) return false;
2168        if (url.indexOf('//') === -1 && url.indexOf('http') !== 0) return false;
2169        
2170        try {
2171            var url_host = new URL(url, window.location.origin).hostname;
2172            return get_root_domain(url_host) !== current_root;
2173        } catch (e) {
2174            return url.indexOf(current_root) === -1;
2175        }
2176    };
2177    // -------------------------------------
2178
2179    // 1. If already active, safely add NEW target objects
2180    if (window.__network_monitor) {
2181        for (var i = 0; i < new_targets.length; i++) {
2182            var exists = false;
2183            for (var j = 0; j < window.__network_monitor.active_targets.length; j++) {
2184                if (window.__network_monitor.active_targets[j].target === new_targets[i].target) {
2185                    exists = true;
2186                    break;
2187                }
2188            }
2189            if (!exists) {
2190                window.__network_monitor.active_targets.push(new_targets[i]);
2191            }
2192        }
2193        window.__network_monitor.reset_timer(duration);
2194        window.metrion.helpers.log_debug("[NetworkListener] Added targets to active session.");
2195        return;
2196    }
2197
2198    // 2. Setup the Monitor State
2199    var originals = {
2200        fetch: window.fetch,
2201        xhr_open: XMLHttpRequest.prototype.open,
2202        xhr_send: XMLHttpRequest.prototype.send,
2203        beacon: navigator.sendBeacon
2204    };
2205
2206    window.__network_monitor = {
2207        active_targets: new_targets,
2208        timer: null,
2209        reset_timer: function(ms) {
2210            if (this.timer) clearTimeout(this.timer);
2211            this.timer = setTimeout(function() {
2212                window.metrion.helpers.log_debug("[Network listener] Timeout reached.");
2213                window.__network_monitor.deactivate();
2214            }, ms);
2215        },
2216        deactivate: function() {
2217            if (this.timer) clearTimeout(this.timer);
2218            if (originals.fetch) window.fetch = originals.fetch;
2219            XMLHttpRequest.prototype.open = originals.xhr_open;
2220            XMLHttpRequest.prototype.send = originals.xhr_send;
2221            if (originals.beacon) navigator.sendBeacon = originals.beacon;
2222            
2223            delete window.__network_monitor;
2224            window.metrion.helpers.log_debug("[Monitor] Deactivated and chain restored.");
2225        }
2226    };
2227
2228    var check_match = function(data, url_context) {
2229        var state = window.__network_monitor;
2230        if (!data || !state) return;
2231
2232        if (!is_external(url_context)) return;
2233        
2234        var content = (typeof data === 'string') ? data : JSON.stringify(data);
2235        var targets = state.active_targets;
2236
2237        for (var i = targets.length - 1; i >= 0; i--) {
2238            var target_obj = targets[i];
2239            var search_str = target_obj.target; 
2240            
2241            if (content.indexOf(search_str) !== -1) {
2242                window.metrion.helpers.log_debug("[Network listener] MATCH: " + search_str + (url_context ? " | URL: " + url_context : ""));
2243                
2244                target_obj.matched_url = url_context || "Unknown URL";
2245                
2246                window.metrion.send_event("purchase_network_request_found", target_obj);
2247                
2248                targets.splice(i, 1);
2249                if (targets.length === 0) state.deactivate();
2250            }
2251        }
2252    };
2253
2254    // --- Hijack Logic (Only happens ONCE) ---
2255    if (window.fetch) {
2256        window.fetch = function(input, init) {
2257            var url = (typeof input === 'string') ? input : input.url;
2258            check_match(url, url);
2259            if (init) check_match(init.body, url);
2260            return originals.fetch.apply(this, arguments);
2261        };
2262    }
2263
2264    XMLHttpRequest.prototype.open = function(method, url) {
2265        this.__metrion_url = url;
2266        check_match(url, url);
2267        return originals.xhr_open.apply(this, arguments);
2268    };
2269
2270    XMLHttpRequest.prototype.send = function(body) {
2271        check_match(body, this.__metrion_url);
2272        return originals.xhr_send.apply(this, arguments);
2273    };
2274
2275    if (navigator.sendBeacon) {
2276        navigator.sendBeacon = function(url, data) {
2277            check_match(url, url);
2278            check_match(data, url);
2279            return originals.beacon.apply(this, arguments);
2280        };
2281    }
2282
2283    var target_names = [];
2284    for (var t = 0; t < new_targets.length; t++) target_names.push(new_targets[t].target);
2285
2286    window.__network_monitor.reset_timer(duration);
2287    window.metrion.helpers.log_debug("[Monitor] Started. Watching EXTERNAL requests for: " + target_names.join(", "));
2288};
2289
2290// Woocommerce Purchase event logic
2291window.metrion.woocommerce_purchase_logic = function (){
2292    
2293    // Wait to check if jQuery is ready
2294    // Function to check if metrion_purchase_data is available
2295    function check_purchase_data() {
2296        // Early exit if no purchase data exists
2297        if (typeof window.metrion_purchase_data === "undefined") {
2298            return;
2299        }
2300
2301        // Purchase
2302        // Ensure purchase_data is available
2303        if (
2304            typeof window.metrion_purchase_data !== "undefined" && 
2305            Array.isArray(window.metrion_purchase_data.items) && 
2306            window.metrion_purchase_data.items.length > 0
2307        ) {
2308            var purchase_event_body = {
2309                "event": "purchase",
2310                "trigger_type": "front-end",
2311                "order_id": window.metrion_purchase_data.order_id,
2312                "order_total": window.metrion_purchase_data.order_total,
2313                "order_total_tax": window.metrion_purchase_data.order_total_tax,
2314                "order_total_shipping": window.metrion_purchase_data.order_total_shipping,
2315                "currency": window.metrion_purchase_data.currency,
2316                "items": window.metrion_purchase_data.items,
2317                "coupons": window.metrion_purchase_data.coupons
2318            }
2319
2320            // Example: Send purchase data to an analytics system
2321            window.metrion.send_event("purchase", purchase_event_body);
2322            window.metrion.woocommerce_purchase_logic_triggered = true;
2323        } else {
2324            window.metrion.helpers.log_debug("Purchase data is not available.", "log");
2325        }
2326    }
2327    
2328    // Wait for DOMContentLoaded first
2329    if (document.readyState === "loading") {
2330        document.addEventListener("DOMContentLoaded", function () {
2331            if(!window.metrion.woocommerce_purchase_logic_triggered){
2332                check_purchase_data(); // Call the function once DOM is ready
2333            }
2334        });
2335    } else {
2336        if(!window.metrion.woocommerce_purchase_logic_triggered){
2337            // If DOM is already loaded, just run the function immediately
2338            check_purchase_data();
2339        }
2340    }
2341    // Fallback: In case DOMContentLoaded isn't triggered (very rare case), use window.onload
2342    window.addEventListener('load', function () {
2343        if (!window.metrion.woocommerce_purchase_logic_triggered) {
2344            check_purchase_data();
2345        }
2346    });
2347
2348    // Final trigger method is after jQuery is ready
2349    window.metrion.helpers.wait_for_jquery(function(){
2350        if(!window.metrion.woocommerce_purchase_logic_triggered){
2351            check_purchase_data();
2352        }
2353    });
2354
2355};
2356
2357// Call the function
2358window.metrion.woocommerce_purchase_logic();
2359;
2360
2361// Prevent overwriting of objects and preserve existing properties
2362window.metrion = window.metrion || {};
2363
2364// JS Woocommerce other event logic
2365window.metrion.woocommerce_event_logic = function () {
2366    // Wait to check if jQuery is ready
2367    window.metrion.helpers.wait_for_jquery(function(){
2368        // jQuery is required for Woocommerce
2369        jQuery(function ($) {
2370            // Add-to-cart listener
2371            $("body").on("click", ".add_to_cart_button, .single_add_to_cart_button", function (event) {
2372                var google_analytics_enabled = window.metrion.google_analytics !== undefined;
2373                var event_unix = Date.now();
2374                var engagement_time_msec = 500;               
2375                if(google_analytics_enabled){
2376                    engagement_time_msec = (event_unix - window.metrion.google_analytics.latest_engagement_unix);
2377                }
2378                
2379                try {
2380                    var product_id, product_name, product_brand, product_url,product_price, product_regular_price, product_price_incl_vat, product_price_excl_vat, product_variation_id, product_ean, product_gtin, product_sku, category_1, category_2, category_3, category_4, quantity = 1;
2381                    var currency = $(this).data("currency") || "EUR"; // Default currency
2382        
2383                    // Determine the source of the metrion_item_data span
2384                    var product_data_span;
2385        
2386                    if ($(this).hasClass("single_add_to_cart_button")) {
2387                        // For single product pages, get the span from the footer
2388                        product_data_span = $("#metrion_item_data_single").find(".metrion_item_data_single");
2389                    } else {
2390                        // For product loops, get the span from the closest product container
2391                        product_data_span = $(this).closest(".product").find(".metrion_item_data_loop");
2392                    }
2393        
2394                    // Ensure the span exists before proceeding
2395                    if (!product_data_span.length || product_data_span.length <= 0) {
2396                        //console.error("No metrion_item_data span found for this product.");
2397                        window.metrion.helpers.log_debug("No metrion_item_data span found for this product.", "log");
2398                        return;
2399                    }
2400        
2401                    // Extract data correctly
2402                    product_id = product_data_span.attr("data-item_id");
2403                    product_name = product_data_span.attr("data-item_name");
2404                    product_price = product_data_span.attr("data-item_price");
2405                    product_price_incl_vat = product_data_span.attr("data-item_price_incl_vat");
2406                    product_price_excl_vat = product_data_span.attr("data-item_price_excl_vat");
2407                    product_regular_price = product_data_span.attr("data-item_regular_price");
2408                    product_sku = product_data_span.attr("data-item_sku");
2409                    product_brand = product_data_span.attr("data-item_brand");
2410                    product_gtin = product_data_span.attr("data-item_gtin");
2411                    product_ean = product_data_span.attr("data-item_ean");
2412                    product_url = product_data_span.attr("data-item_url");
2413                    product_variation_id = product_data_span.attr("data-item_variation_id") || null;
2414                    category_1 = product_data_span.attr("data-item_category_1") || null;
2415                    category_2 = product_data_span.attr("data-item_category_2") || null;
2416                    category_3 = product_data_span.attr("data-item_category_3") || null;
2417                    category_4 = product_data_span.attr("data-item_category_4") || null;
2418        
2419                    // If a quantity input exists, update the quantity
2420                    var quantity_input = $(this).closest("form.cart").find("input.qty");
2421                    if (quantity_input.length) {
2422                        quantity = parseInt(quantity_input.val()) || 1;
2423                    }
2424        
2425                    // Ensure we have the necessary data
2426                    if (!product_id || !product_name || !product_price) {
2427                        window.metrion.helpers.log_debug("Item data is missing. Cannot send event to Metrion.", "log");
2428                        return;
2429                    }
2430        
2431                    var product_data = {
2432                        "type": "product",
2433                        "id": window.metrion.helpers.safe_to_string(product_id),
2434                        "gtin": window.metrion.helpers.safe_to_string(product_gtin),
2435                        "ean": window.metrion.helpers.safe_to_string(product_ean),
2436                        "variation_id": window.metrion.helpers.safe_to_string(product_variation_id),
2437                        "name": window.metrion.helpers.safe_to_string(product_name),
2438                        "price": window.metrion.helpers.safe_to_string(product_price),
2439                        "price_incl_vat": window.metrion.helpers.safe_to_string(product_price_incl_vat),
2440                        "price_excl_vat": window.metrion.helpers.safe_to_string(product_price_excl_vat),
2441                        "regular_price": window.metrion.helpers.safe_to_string(product_regular_price),
2442                        "quantity": window.metrion.helpers.safe_to_string(quantity),
2443                        "sku": window.metrion.helpers.safe_to_string(product_sku),
2444                        "url": window.metrion.helpers.safe_to_string(product_url),
2445                        "currency": currency,
2446                        "category_1": window.metrion.helpers.safe_to_string(category_1),
2447                        "category_2": window.metrion.helpers.safe_to_string(category_2),
2448                        "category_3": window.metrion.helpers.safe_to_string(category_3),
2449                        "category_4": window.metrion.helpers.safe_to_string(category_4),
2450                        "brand": window.metrion.helpers.safe_to_string(product_brand)
2451                    };
2452        
2453                    // Send data to Metrion
2454                    if (typeof metrion !== "undefined" && typeof metrion.send_event === "function") {
2455                        metrion.send_event("add_to_cart", {
2456                            "items": [product_data],
2457                            "trigger_type": "front-end",
2458                            "engaged_time_ms": engagement_time_msec
2459                        });
2460                    } else {
2461                        window.metrion.helpers.log_debug("Metrion is not available or send_event function is missing.", "log");
2462                    }
2463                } catch (error) {
2464                    window.metrion.helpers.log_debug("Error in Add to Cart event: " + error.message, "log");
2465                }
2466            });
2467
2468            // Item view event for single product pages
2469            if ($("body").hasClass("single-product")) {
2470                try {
2471                    var product_id, product_name, product_brand, product_url, product_price, product_regular_price, product_price_incl_vat, product_price_excl_vat, product_variation_id, product_ean, product_gtin, product_sku, category_1, category_2, category_3, category_4, quantity = 1;
2472                    var currency = "EUR"; // Default currency
2473
2474                    // Get data from the metrion_item_data_single span in the footer
2475                    var product_data_span = $("#metrion_item_data_single").find(".metrion_item_data_single");
2476
2477                    if (product_data_span.length) {
2478                        product_id = window.metrion.helpers.safe_to_string(product_data_span.data("item_id"));
2479                        product_name = window.metrion.helpers.safe_to_string(product_data_span.data("item_name"));
2480                        product_price = window.metrion.helpers.safe_to_string(product_data_span.data("item_price"));
2481                        product_url = window.metrion.helpers.safe_to_string(product_data_span.data("item_url"));
2482                        product_brand = window.metrion.helpers.safe_to_string(product_data_span.data("item_brand"));
2483                        product_price_incl_vat = window.metrion.helpers.safe_to_string(product_data_span.data("item_price_incl_vat"));
2484                        product_price_excl_vat = window.metrion.helpers.safe_to_string(product_data_span.data("item_price_excl_vat"));
2485                        product_regular_price = window.metrion.helpers.safe_to_string(product_data_span.data("item_regular_price"));
2486                        product_sku = window.metrion.helpers.safe_to_string(product_data_span.data("item_sku"));
2487                        product_ean = window.metrion.helpers.safe_to_string(product_data_span.data("item_ean"));
2488                        product_gtin = window.metrion.helpers.safe_to_string(product_data_span.data("item_gtin"));
2489                        product_variation_id = window.metrion.helpers.safe_to_string(product_data_span.data("item_variation_id")) || null;
2490                        category_1 = product_data_span.data("item_category_1") || null;
2491                        category_2 = product_data_span.data("item_category_2") || null;
2492                        category_3 = product_data_span.data("item_category_3") || null;
2493                        category_4 = product_data_span.data("item_category_4") || null;
2494                        currency = product_data_span.data("currency") || currency;
2495                    }
2496
2497                    // Ensure we have the necessary data
2498                    if (product_id && product_name && product_price) {
2499                        var product_data = {
2500                            "type": "product",
2501                            "id": window.metrion.helpers.safe_to_string(product_id),
2502                            "name": window.metrion.helpers.safe_to_string(product_name),
2503                            "price": window.metrion.helpers.safe_to_string(product_price),
2504                            "price_incl_vat": window.metrion.helpers.safe_to_string(product_price_incl_vat),
2505                            "price_excl_vat": window.metrion.helpers.safe_to_string(product_price_excl_vat),
2506                            "ean": window.metrion.helpers.safe_to_string(product_ean),
2507                            "gtin": window.metrion.helpers.safe_to_string(product_gtin),
2508                            "variation_id": window.metrion.helpers.safe_to_string(product_variation_id),
2509                            "regular_price": window.metrion.helpers.safe_to_string(product_regular_price),
2510                            "quantity": window.metrion.helpers.safe_to_string(quantity),
2511                            "sku": window.metrion.helpers.safe_to_string(product_sku),
2512                            "url": product_url, // The URL of the item page
2513                            "currency": currency,
2514                            "category_1": window.metrion.helpers.safe_to_string(category_1),
2515                            "category_2": window.metrion.helpers.safe_to_string(category_2),
2516                            "category_3": window.metrion.helpers.safe_to_string(category_3),
2517                            "category_4": window.metrion.helpers.safe_to_string(category_4),
2518                            "brand": window.metrion.helpers.safe_to_string(product_brand)
2519                        };
2520
2521                        // Send data to Metrion for item view event
2522                        if (typeof metrion !== "undefined" && typeof metrion.send_event === "function") {
2523                            metrion.send_event("item_view", {
2524                                "items": [product_data],
2525                                "trigger_type": "front-end"
2526                            });
2527                        } else {
2528                            window.metrion.helpers.log_debug("Metrion is not available or send_event function is missing.", "log");
2529                        }
2530                    } else {
2531                        window.metrion.helpers.log_debug("Item data is missing. Cannot send event to Metrion.", "log");
2532                    }
2533                } catch (error) {
2534                    window.metrion.helpers.log_debug("Error in Item View event: " + error.message, "log");
2535                }
2536            }
2537
2538            // Item lists / search results
2539            if (typeof window.metrion_loop !== "undefined"
2540                && typeof window.metrion_basket_items === "undefined"
2541                && typeof window.metrion_checkout_items === "undefined"
2542                && typeof window.metrion_purchase_data === "undefined") {
2543                // Event name logic
2544                var loop_event_name = "view_item_list";
2545                if (window.metrion_loop.is_search_page) {
2546                    loop_event_name = "view_search_results";
2547                }
2548
2549                // Event body logic
2550                var loop_event_body = {
2551                    "items": window.metrion_loop.loop_items,
2552                    "trigger_type": "front-end"
2553                }
2554                // Category page context
2555                if (window.metrion_is_category_page) {
2556                    loop_event_body["is_category_page"] = window.metrion_is_category_page;
2557                    if (window.metrion_category_hierarchy && window.metrion_category_hierarchy.length > 0) {
2558                        loop_event_body["category_hierarchy"] = window.metrion_category_hierarchy.join(", ");
2559
2560                    }
2561                }
2562                // Search page context
2563                if (window.metrion_loop.is_search_page && typeof window.metrion_loop.search_term !== "undefined") {
2564                    loop_event_body["is_search_page"] = window.metrion_loop.is_search_page;
2565                    loop_event_body["search_term"] = window.metrion_loop.search_term;
2566                }
2567
2568                // Trigger the event
2569                window.metrion.send_event(loop_event_name, loop_event_body);
2570
2571            }
2572
2573            // Basket view
2574            // Ensure metrion_basket_items is available 
2575            if (typeof window.metrion_basket_items !== "undefined") {
2576                window.metrion.send_event("basket_view", {
2577                    "items": window.metrion_basket_items.items,
2578                    "trigger_type": "front-end"
2579                });
2580            } else {
2581                window.metrion.helpers.log_debug("No basket view items available for begin_checkout.", "log");
2582            }
2583
2584            // Begin checkout
2585            // Ensure metrion_checkout_items is available 
2586            if (typeof window.metrion_checkout_items !== "undefined") {
2587                window.metrion.send_event("begin_checkout", {
2588                    "items": window.metrion_checkout_items.items,
2589                    "trigger_type": "front-end"
2590                });
2591            } else {
2592                window.metrion.helpers.log_debug("No checkout items available for begin_checkout.", "log");
2593            }
2594        });
2595    });
2596};
2597
2598// Call the function
2599window.metrion.woocommerce_event_logic();
2600;
2601
2602// Initialization
2603window.metrion.initialisation_sequence = function(){
2604    // Check if the user id cookie exists
2605    if (window.metrion.helpers.get_cookie_value(metrion_api.user_cookie_name + "_js") === null) {
2606        // Only start this process if cookie and data placement is allowed
2607        if (window.metrion.configuration.allow_cookie_placement_before_explicit_consent === "1") {
2608            window.metrion.user_manager.ensure_user_cookie_existance(function () {
2609                window.metrion.consent_manager.initial_consent_enforcement();
2610                //window.metrion.consent_manager.evaluate_consent_floodgate();
2611                window.metrion.session_event_logic();
2612                window.metrion.page_view_event_logic();
2613            });
2614        }
2615        else {
2616            // Check if consent is already provided, but only Metrion is not initialized properly yet
2617            var has_explicit_cmp_consent = window.metrion.consent_manager.has_explicit_cmp_consent(window.metrion.configuration.cmp_selection);
2618            if(has_explicit_cmp_consent){
2619                window.metrion.user_manager.ensure_user_cookie_existance(function () {
2620                    window.metrion.consent_manager.initial_consent_enforcement();
2621                    window.metrion.session_event_logi
2621c();
2622                    window.metrion.page_view_event_logic();
2623                });
2624            }
2625            // Metrion is not initialized yet, there is no user id and no permission for placement before consent. There is also no explicit consent found for the CMP yet. Floodgate everything
2626            else{
2627                window.metrion.consent_manager.initial_consent_enforcement();
2628                window.metrion.session_event_logic();
2629                window.metrion.page_view_event_logic();
2630            }
2631        }
2632    }
2633    else {
2634        window.metrion.consent_manager.initial_consent_enforcement();
2635        // window.metrion.consent_manager.evaluate_consent_floodgate();
2636        window.metrion.session_event_logic();
2637        window.metrion.page_view_event_logic();
2638    }
2639};
2640
2641window.metrion.initialisation_sequence();
2642;
2643
2644//Prevent overwriting of objects and preserve existing properties
2645window.metrion.google_ads = window.metrion.google_ads || {};
2646
2647//Initialize consent mode
2648window.metrion.google_ads.init_consent_mode = function(){
2649    // Define dataLayer and the gtag function.
2650    window.dataLayer = window.dataLayer || [];
2651
2652    // Check if the gtag function is already available or not
2653    if(typeof window.gtag === "undefined"){
2654        function gtag(){dataLayer.push(arguments);}
2655        // Make the gtag function global
2656        window.gtag = gtag;
2657    }
2658
2659    // Set default consent to 'denied' as a placeholder
2660    window.gtag('consent', 'default', {
2661        'ad_storage': 'denied',
2662        'ad_user_data': 'denied',
2663        'ad_personalization': 'denied',
2664        'analytics_storage': 'denied'
2665    });
2666};
2667window.metrion.google_ads.init_consent_mode();
2668
2669//Function to update consent mode
2670window.metrion.google_ads.set_consent_mode_to_granted = function(){
2671    if(typeof window.gtag !== "undefined"){
2672        // Set consent mode values to 'granted'
2673        window.gtag('consent', 'update', {
2674            'ad_storage': 'granted',
2675            'ad_user_data': 'granted',
2676            'ad_personalization': 'granted',
2677            'analytics_storage': 'granted'
2678        });
2679    }
2680};
2681
2682;
2683
2684//JS file containing the user engagement to capture the time elapsed variable
2685//Prevent overwriting of objects and preserve existing properties
2686window.metrion.google_analytics = window.metrion.google_analytics || {};
2687// Set base value for the elapsed time metric in miliseconds
2688window.metrion.google_analytics.latest_engagement_unix =  Date.now();
2689window.metrion.google_analytics.initialize_event_listeners = function(){
2690
2691    'use strict'; // Enables standard compliant mode
2692    // Replaces the modern .closest() method using a standard while loop
2693    function getParentAnchor(element) {
2694        var current = element;
2695        // Walk up the DOM tree until we find an anchor or hit the document root
2696        while (current && current.nodeType === 1) {
2697        if (current.tagName === 'A') {
2698            return current;
2699        }
2700        current = current.parentNode;
2701        }
2702        return null;
2703    }
2704
2705    // Click engagements
2706    document.addEventListener('click', function(event) {
2707        var event_unix = Date.now();
2708        // Standard event.target (no deprecated srcElement)
2709        var target = event.target;
2710        var link = getParentAnchor(target);
2711        if (link && link.href) {
2712            // 1. Ignore "javascript:" pseudo-protocols
2713            var isScript = link.href.indexOf('javascript:') === 0;
2714            // 2. Ignore pure hash anchors (e.g. href="#top") which don't reload page
2715            var rawHref = link.getAttribute('href');
2716            // 3. Detect Modifier Keys (Ctrl/Cmd+Click) which open new tabs
2717            var isNewTab = event.metaKey || event.ctrlKey || event.shiftKey || (link.target === '_blank');
2718            // 4. Detect Download attributes
2719            var isDownload = link.hasAttribute('download');
2720            var click_metadata = {
2721                id: target.id || null,
2722                // 'className' is the standard property, not 'class'
2723                classes: target.className || null, 
2724                // Useful for tracking buttons like "Buy Now"
2725                text: (target.innerText || target.textContent || '').trim().substring(0, 50),
2726                engaged_time_ms: (event_unix - window.metrion.google_analytics.latest_engagement_unix),
2727                is_download: isDownload,
2728                is_new_tab: isNewTab,
2729                is_script: isScript,
2730                href: rawHref
2731            };
2732
2733            // Trigger Metrion event
2734            window.metrion.send_event("link_click", click_metadata);
2735            // Reset engagement unix
2736            window.metrion.google_analytics.latest_engagement_unix = Date.now();
2737        }
2738    });
2739
2740    // Form Submit engagements
2741    document.addEventListener('submit', function(event) {
2742        var form = event.target;
2743        var event_unix = Date.now();
2744        var form_metadata = {
2745            id: form.id,
2746            name: form.name,
2747            destination: form.action, 
2748            method: (form.method || 'GET').toUpperCase(), 
2749            encoding: form.enctype, 
2750            engaged_time_ms: (event_unix - window.metrion.google_analytics.latest_engagement_unix)
2751        };
2752        
2753        //Trigger Metrion event
2754        window.metrion.send_event("form_submit", form_metadata);
2755        // Reset engagement unix
2756        window.metrion.google_analytics.latest_engagement_unix = Date.now();
2757    });
2758
2759    // Visibility change engagements
2760    try {
2761        // 1. Check if the browser supports the API (avoids logic errors)
2762        if (typeof document.visibilityState !== 'undefined') {
2763            // 2. Attach the listener
2764            document.addEventListener('visibilitychange', function() {
2765                var event_unix = Date.now();
2766                if (document.visibilityState === 'hidden') {
2767                    window.metrion.send_event("visibility_change", {
2768                        engaged_time_ms: (event_unix - window.metrion.google_analytics.latest_engagement_unix)
2769                    });
2770                    window.metrion.google_analytics.latest_engagement_unix = Date.now();
2771                } else {
2772                    //Only reset engagement time don't send the hidden engagement time
2773                    window.metrion.google_analytics.latest_engagement_unix = Date.now();
2774                    window.metrion.send_event("visibility_change", {
2775                        "type": "visibility_change",
2776                        engaged_time_ms: 10
2777                    });
2778                }
2779            });
2780        }
2781    } 
2782    catch (e) {
2783        window.metrion.helpers.log_debug('Browser too old for visibility tracking');
2784    }
2785};
2786// Init additional GA4 event listeners
2787window.metrion.google_analytics.initialize_event_listeners();
2788;
2789
2790(function() {
2791    if (window.metrion && window.metrion_api) {
2792        
2793        // Get consent info safely
2794        var cookie_raw = window.metrion.helpers.get_cookie_value(window.metrion_api.consent_cookie_name);
2795        var mtrn_consent = cookie_raw ? JSON.parse(decodeURIComponent(cookie_raw)) : null;
2796
2797        // If marketing consent is given, async load the destination JS
2798        if (mtrn_consent && mtrn_consent.allow_marketing === "1") {
2799            
2800            var ver = metrion_api.bundle_version ? "?ver=" + metrion_api.bundle_version : "";
2801            var api_route_url = metrion_api.api_url + "destinations" + ver;
2802            var direct_file_url = metrion_api.bundle_dir_url + "destinations.js" + ver;
2803
2804            // Helper function to load a script with an optional fallback URL
2805            function dynamic_load_destinations(primary_endpoint, fallback_endpoint) {
2806                var s = document.createElement('script');
2807                s.type = 'text/javascript';
2808                s.async = true; 
2809                s.defer = true;
2810                s.src = primary_endpoint;
2811
2812                // If a fallback is provided, attach an error listener
2813                if (fallback_endpoint) {
2814                    s.onerror = function() {
2815                        // Send the status event silently
2816                        if (window.metrion && typeof window.metrion.send_event === 'function') {
2817                            window.metrion.send_event("status_event", {
2818                                "message": "Direct destination JS load failed, falling back to API/WP-json route.", 
2819                                "id": "fallback_destination_js_through_wp_json"
2820                            }, {});
2821                        }
2822
2823                        // Call the function again with ONLY the fallback URL to prevent infinite loops
2824                        dynamic_load_destinations(fallback_endpoint, null);
2825                    };
2826                }
2827
2828                var x = document.getElementsByTagName('script')[0];        
2829                x.parentNode.insertBefore(s, x);
2830                window.metrion.helpers.log_debug(
2831                    "Destination JS inserted dynamically",
2832                    "log"
2833                );
2834            }
2835
2836            // Determine which route to attempt first based on settings
2837            if (metrion_api.bundle_custom_endpoints === "1" || metrion_api.bundle_custom_endpoints === true) {
2838                // User explicitly enabled API route, just use that
2839                dynamic_load_destinations(api_route_url, null);
2840                window.metrion.helpers.log_debug(
2841                    "Use API route for destination JS loading as per configuration.",
2842                    "log"
2843                );
2844            } else {
2845                // Try the direct path first, fallback to the API route if blocked/failed
2846                dynamic_load_destinations(direct_file_url, api_route_url);
2847                window.metrion.helpers.log_debug(
2848                    "Use Direct JS route for destination JS loading as per configuration.",
2849                    "log"
2850                );
2851            }
2852        }
2853    }
2854})();
2855;
2856
2857// Generated on 2026-10-05 11:43:28 UTC

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.