PageSourceSearch

https://politikenadvertorial.dk/static/js/jppolcmp.js?d=f38a3a15

js politikenadvertorial.dk collected 2026-10-08 07:39:34 UTC 80,868 bytes, 1,623 lines download raw bytes

1if (location.hash === '#cmpDebug') {
2    console.log('cmp is loaded', window.jppolCmpConfig);
3}
4
5/**
6 * If ATT-modal (Apple Tracking Transparency) has been rejected, we auto decline cookies. If rejected, then this value
7 * is stored in a separate cookie, "cookiesHasBeenAutoDeclined". In the case that the user changes ATT-settings, we
8 * utilize this cookie's existence to check if we want to show the CMP-modal.
9 *
10 * Since this cookie always gets deleted if it exists, and it only gets set if ATT is rejected, we can make sure
11 * the CMP-modal only shows once, if the user switched ATT-settings.
12 *
13 * This will only run if device === app, due to "autoDeclineCookies" only gets send from the native app client.
14 */
15
16const doesAutoDeclineCookieExist = document.cookie.indexOf('cookiesHasBeenAutoDeclined=true') !== -1
17
18if (doesAutoDeclineCookieExist && window.hasOwnProperty("Cookiebot")) {
19    document.cookie = "cookiesHasBeenAutoDeclined= ; expires = Thu, 01 Jan 1970 00:00:00 GMT" // Delete cookie
20    window.Cookiebot.show()
21}
22
23if (jppolCmpConfig.autoDeclineCookies) {
24    document.cookie = "cookiesHasBeenAutoDeclined=true";
25    if (window.hasOwnProperty("Cookiebot") && window.Cookiebot.hasOwnProperty("submitCustomConsent")) {
26        const optinPreferences = false
27        const optinStatistics = false
28        const optinMarketing = false
29        window.Cookiebot.submitCustomConsent(optinPreferences, optinStatistics, optinMarketing)
30    }
31}
32
33if (window.jppolPerf && window.jppolPerf.browserMeasureSupported) {
34    window.performance.measure('jppolCMP:start');
35}
36
37window.jppolCMPVendorCategories = {
38    necessary: 'necessary',
39    preferences: 'preferences',
40    statistics: 'statistics',
41    marketing: 'marketing',
42    translateCategories: function (cat) {
43        switch (cat) {
44            case jppolCMPVendorCategories.necessary:
45                return 'nødvendige';
46            case jppolCMPVendorCategories.preferences:
47                return 'præferencer';
48            case jppolCMPVendorCategories.statistics:
49                return 'statistik';
50            case jppolCMPVendorCategories.marketing:
51                return 'marketing';
52            default:
53                return cat;
54        }
55    }
56};
57window.jppolCMP = {
58    relevanceId: null,
59    externalId: null,
60    debug: false || location.hash === '#cmpDebug',
61    html: {
62        backgroundImage: '<div style="height:210px;background-image: url(/static/assets/images/gdpr/exo_cmp_embed_background_desktop.png);background-position: center; background-repeat: no-repeat;background-size: 100% 100%"></div>',
63        backgroundImageRed: '<div style="width:100%;height:147px;
63background: center url(/static/assets/images/gdpr/embed-background-red.png) no-repeat;"></div>',
64        consentButton: '<button onclick="window.Cookiebot.show()" role="button" style="background-color: #439e5c; display: flex; padding: 0.5rem; border-radius: 3px; align-items: center; border:0; color:white" class="js-gdpr-button-inline"  style="fill: white">' +
65            'Administrer samtykke' +
66            '</button>',
67        ATTModalConsentButton: '<button role="button" data-auto-decline-cookies="true" style="background-color: #439e5c; display: flex; padding: 0.5rem; border-radius: 0.125rem; align-items: center; fill: white; border:0">' +
68            'Administrér samtykke <svg style="height: 0.75rem; margin-left: 0.5rem;" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 162.1 169.3" xml:space="preserve"> <g> <path d="M159.9,105.1c0.9,0.5,1.5,1.1,1.9,2c0.3,0.9,0.4,1.8,0.2,2.7c-3.9,12.1-10.1,22.8-18.8,32.1c-0.7,0.7-1.5,1.1-2.4,1.4 c-0.9,0.2-1.8,0.1-2.7-0.3l-14.3-8.5c-6.1,5.2-13.1,9.2-20.8,11.9v16.7c0,0.9-0.3,1.8-0.9,2.6s-1.3,1.3-2.2,1.5 c-12.5,2.7-25,2.7-37.6,0c-0.9-0.2-1.6-0.7-2.2-1.5s-0.9-1.6-0.9-2.6v-16.7c-7.7-2.7-14.7-6.7-20.8-11.9L24,143 c-0.9,0.5-1.8,0.6-2.7,0.3s-1.7-0.7-2.4-1.4c-8.6-9.3-14.9-20-18.8-32.1c-0.2-0.9-0.2-1.8,0.2-2.7s1-1.6,1.9-2l14.3-8.5 c-1.4-8-1.4-15.9,0-23.9L2.2,64.2c-0.9-0.5-1.5-1.1-1.9-2c-0.3-0.9-0.4-1.8-0.2-2.7C4,47.3,10.3,36.6,18.9,27.3 c0.7-0.7,1.5-1.1,2.4-1.4c0.9-0.2,1.8-0.1,2.7,0.3l14.3,8.5c6.1-5.2,13.1-9.2,20.8-11.9V6.1c0-0.9,0.3-1.8,0.9-2.6s1.3-1.3,2.2-1.5 c12.5-2.7,25-2.7,37.6,0c0.9,0.2,1.6,0.7,2.2,1.5s0.9,1.6,0.9,2.6v16.7c7.7,2.7,14.7,6.7,20.8,11.9l14.3-8.5 c0.9-0.5,1.8-0.6,2.7-0.3c0.9,0.2,1.7,0.7,2.4,1.4c8.6,9.3,14.9,20,18.8,32.1c0.2,0.9,0.2,1.8-0.2,2.7c-0.3,0.9-1,1.6-1.9,2 l-14.3,8.5c1.4,8,1.4,15.9,0,23.9L159.9,105.1z M100.3,65.4c-5.3-5.3-11.8-8-19.3-8s-13.9,2.7-19.3,8s-8,11.8-8,19.3 c0,7.5,2.7,13.9,8,19.3c5.3,5.3,11.8,8,19.3,8s13.9-2.7,19.3-8c5.3-5.3,8-11.8,8-19.3C108.4,77.1,105.7,70.7,100.3,65.4z"></path> </g> </svg>' +
69            '</button>',
70    },
71    embedHtmlNoConsent: function (vendorName_message_Obj, embed_body_elements) {
72        const isDesktop = window?.polContext__?.page?.deviceType === "desktop";
73        const textStyle = isDesktop
74            ? "margin:0 10px 8px;max-width:70%;text-align:center;"
75            : "margin:0 10px 10px;max-width:275px;text-align:center;";
76
77        const displayATTSettingsInsteadOfCMP_consentButton =
78            window.polContext__?.page?.displayATTSettingsInsteadOfCMP
79                ? jppolCMP.html.ATTModalConsentButton
80                : jppolCMP.html.consentButton;
81
82        const consentButton = window.polContext__?.page?.isApp
83            ? displayATTSettingsInsteadOfCMP_consentButton
84            : jppolCMP.html.consentButton;
85
86        const vendorUrl =
87            vendorName_message_Obj?.url && vendorName_message_Obj.url.length > 0
88                ? (isDesktop
89                    ? `<span style='margin-top: 0.5rem; display: flex; flex-direction: column; align-items: center; text-align: center; max-width: 70%; font-size: 14px;'>
90                        Du kan også se indholdet ved gå direkte til <br>
91                        <a style='text-decoration: underline' href='${vendorName_message_Obj.url}' target='_blank'>
92                            ${vendorName_message_Obj.vendorName} (Ã¥bner i ny fane)
93                        </a>
94                   </span>`
95                    : `<span style='margin-top: 0.5rem; display: flex; flex-direction: column; align-items: center; text-align: center; font-size: 14px;'>
96                        Du kan også se indholdet ved gå direkte til <br>
97                        <a style='text-decoration: underline' attribute='external' href='${vendorName_message_Obj.url}' target='_blank'>
98                            ${vendorName_message_Obj.vendorName} (Ã¥bner i ny fane)
99                        </a>
100                   </span>`)
101                : "<div></div>";
102
103        return `
104            <div>
105                ${embed_body_elements}
106            </div>
107            <div style='position: relative;'>
108                ${jppolCMP.html.backgroundImage}
109                <div style='position: absolute; bottom: 0; top: 0; left: 0; right: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; font-family: flamabook; font-size: 16px; line-height:1.2; color: white;'>
110                    <span style='${textStyle}' class='ui-font'>
111                        Du kan kun se indhold fra vores<br> samarbejdspartner ${vendorName_message_Obj.vendorName}, hvis du giver samtykke til ${vendorName_message_Obj.message}
112                    </span>
113                    ${consentButton}
114                    ${vendorUrl}
115                </div>
116            </div>`;
117    },
118    embedHtmlVendorNotFound: function () {
119        let textStyle = "margin:0 10px 15px;max-width:250px;font-size:16px;text-align:center;";
120        if (window.polContext__) {
121            if (window.polContext__.page) {
122                if (window.polContext__.page.deviceType === "mobile") {
123                    textStyle = "margin:0 10px 15px;max-width:220px;font-size:14px;text-align:center;";
124                }
125            }
126        }
127        return "" +
128            jppolCMP.html.backgroundImageRed +
129            "<div class='u-position-bg u-flex u-flex--col u-flex--align-items-center u-flex--justify-content-center' style='color:#FFFFFF;'>" +
130            "<span style='" + textStyle + "' class='ui-font'>Her er indlejret et element, der kan sætte ukendte cookies, og vi har derfor blokeret det</span>" +
131            "</div>";
132    },
133    fullConsent: false, /* used to determine if scripts from Google Tag Manager and other tracking-scripts can run */
134    /* populated as HTML renders, if any embedded-code is found during paint.
135     object must contain: {id: String, html: String, loaded: Boolean}
136    */
137    embedVendors: {
138        politiken: {
139            name: "Politiken.dk",
140            sources: ["politiken.dk", "navne.politiken", "misc-politiken-articles.s3"],
141            required: []
142        },
143        // used for pixel tracking only
144        doubleclick: {
145            name: "Google Doubleclick",
146            sources: ["pubads.g.doubleclick.net"],
147            required: []
148        },
149        // tool-vendors - internal/editorial tools
150        ritzau: {
151            name: "Ritzau",
152            sources: ["ritzau.dk"],
153            required: []
154        },
155        datawrapper: {
156            name: "Datawrapper",
157            sources: ["datawrapper"],
158            required: []
159        },
160        flourish: {
161            name: "Flourish",
162            sources: ["flourish", "flo.uri.sh"],
163            required: []
164        },
165        riddle: {
166            name: "Riddle Technologies AG",
167            sources: ["riddle"],
168            required: []
169        },
170        kennedk: {
171            name: "kenne.dk",
172            sources: ["vapor-farm-c1.com"],
173            required: []
174        },
175        rockContent: {
176            name: "Rock Content Technologies",
177            sources: ["rockcontent.com", "embed.scribblelive.com"],
178            required: [window.jppolCMPVendorCategories.statistics]
179        },
180        dpaSportsLive: {
181            name: "dpa SportsLive",
182            sources: ["core.dpa-infocom.net", "dpa-sportslive.com", "dpa-infocom.s3", "d2c0cdjj8gf5hk.cloudfront.net"],
183            required: []
184        },
185        // others...
186        facebook: {
187            name: "Facebook",
188            sources: ["facebook"],
189            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
190        },
191        instagram: {
192            name: "Instagram",
193            sources: ["instagram"],
194            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
195        },
196        threads: {
197            name: "Threads",
198            sources: ["threads"],
199            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
200        },
201        telegram: {
202            name: "Telegram",
203            sources: ["telegram"],
204            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
205        },
206        linkedin: {
207            name: "LinkedIn",
208            sources: ["linkedin"],
209            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
210        },
211        youtube: {
212            name: "YouTube",
213            sources: ["youtube", "youtu.be"],
214            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
215        },
216        leadfamly: {
217            name: "LeadFamily ApS",
218            sources: ["leadfamly"],
219            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
220        },
221        etrack: {
222            name: "etrack1",
223            sources: ["webservice/etrack", "etrack1.com"],
224            required: []
225        },
226        codespace: {
227            name: "Codespace",
228            sources: ["codespace.dk"],
229            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
230        },
231        playbuzz: {
232            name: "Playbuzz UK Limited",
233            sources: ["playbuzz.com"],
234            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
235        },
236        tableau: {
237            name: "Tableau Software, Inc.",
238            sources: ["tableau.com"],
239            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
240        },
241        contenttools: {
242            name: "Content Tools",
243            sources: ["contenttools"],
244            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
245        },
246        vimeo: {
247            name: "Vimeo",
248            sources: ["vimeo.com"],
249            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
250        },
251        tiktok: {
252            name: "TikTok",
253            sources: ["tiktok.com"],
254            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
255        },
256        spotify: {
257            name: "Spotify AB",
258            sources: ["spotify.com"],
259            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
260        },
261        soundcloud: {
262            name: "soundcloud",
263            sources: ["soundcloud"],
264            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
265        },
266        tidal: {
267            name: "Tidal",
268            sources: ["tidal"],
269            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
270        },
271        appleMusic: {
272            name: "Apple Music",
273            sources: ["music.apple.com"],
274            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
275        },
276        reddit: {
277            name: "Reddit, Inc.",
278            sources: ["reddit.com"],
279            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
280        },
281        tumblr: {
282            name: "Tumblr, Inc.",
283            sources: ["tumblr.com"],
284            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
285        },
286        truthSocial: {
287            name: "Truth Social",
288            sources: ["truthsocial.com"],
289            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
290        },
291        giphy: {
292            name: "Giphy, Inc.",
293            sources: ["giphy.com"],
294            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
295        },
296        imgur: {
297            name: "Imgur, Inc. og Imgur, LLC.",
298            sources: ["imgur.com"],
299            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
300        },
301        googleMaps: {
302            name: "Google Maps",
303            sources: ["google.com/maps"],
304            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
305        },
306        dropbox: {
307            name: "Dropbox, Inc.",
308            sources: ["dropbox"],
309            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
310        },
311        airbnb: {
312            name: "Airbnb",
313            sources: ["airbnb"],
314            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
315        },
316        flickr: {
317            name: "Flickr",
318            sources: ["flickr.com", "flic.kr"],
319            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
320        },
321        myspace: {
322            name: "Myspace",
323            sources: ["myspace"],
324            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
325        },
326        Bandcamp: {
327            name: "bandcamp",
328            sources: ["bandcamp"],
329            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
330        },
331        audible: {
332            name: "Audible",
333            sources: ["audible"],
334            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
335        },
336        ebay: {
337            name: "eBay, Inc.",
338            sources: ["ebay.com", "ebay.co.uk", "ebay.de"],
339            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
340        },
341        yelp: {
342            name: "Yelp Inc.",
343            sources: ["yelp.com"],
344            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
345        },
346        trustpilot: {
347            name: "Trustpilot",
348            sources: ["trustpilot"],
349            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
350        },
351        podimo: {
352            name: "Podimo",
353            sources: ["podimo"],
354            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
355        },
356        podbean: {
357            name: "Podbean",
358            sources: ["podbean"],
359            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
360        },
361        figma: {
362            name: "Figma",
363            sources: ["figma"],
364            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
365        },
366        momondo: {
367            name: "Momondo",
368            sources: ["momondo"],
369            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
370        },
371        bbc: {
372            name: "BBC",
373            sources: ["bbc.com"],
374            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
375        },
376        aws: {
377            name: "Amazon.com, Inc.",
378            sources: ["amazonaws.com"],
379            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
380        },
381        audienceproject: {
382            name: "AudienceProject ApS",
383            sources: ["userreport.com"],
384            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
385        },
386        adform: {
387            name: "Adform",
388            sources: ["adform.net"],
389            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
390        },
391        googleAdManager: {
392            name: "Google Inc.",
393            sources: ["admanager.google.com"],
394            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
395        },
396        hubspot: {
397            name: "HubSpot, Inc.",
398            sources: ["hsforms.com"],
399            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
400        },
401        lexi: {
402            name: "Lexi ApS",
403            sources: ["lexi"],
404            required: []
405        },
406        // We keep Twitter in the CMP to handle legacy embeds
407        twitter: {
408            name: "X", // Twitters new name is 'X', and we are required to show this in the UI.
409            sources: ["twitter.com"],
410            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
411        },
412        x: {
413            name: "X",
414            sources: ["x.com"],
415            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
416        },
417        bluesky: {
418            name: "Bluesky",
419            sources: ["bsky.app"],
420            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
421        }
422        /*
423        disabled
424        heyrobot: {
425          name: "HeyRobot",
426          sources: ["heyrobot"],
427          required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing]
428        },
429        */
430    },
431    vendors: {
432        norkon: {
433            name: "Norkon Live blog",
434            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing],
435            loaded: false,
436            load: async function () {
437                const valid = jppolCMP.checkConsentsByCategory(this.required);
438
439                if (valid) {
440                    const liveBlogConfigs = document.querySelectorAll('[data-live-blog-config]')
441
442                    // Hack to make it work specifically for Norkon, due to last script needs prior scripts to download, parse and execute.
443                    const loadScriptSequentially = async (scriptData) => {
444                        await new Promise((resolve, reject) => {
445                            let script = document.createElement('script')
446
447                            script.onload = () => resolve(scriptData.src)
448                            script.onerror = () => reject(new Error(`❌ Failed to load script: ${scriptData.src || 'inline'}`))
449
450                            if (scriptData.src) {
451                                script.async = false
452                                script.src = scriptData.src
453                            } else {
454                                script.innerHTML = scriptData.content
455                                script.type = 'text/javascript'
456                                resolve() // Inline scripts execute immediately
457                            }
458
459                            document.head.appendChild(script);
460                        })
461                    }
462
463                    for (const liveBlogConfig of liveBlogConfigs) {
464                        const liveBlogScriptLinks = JSON.parse(liveBlogConfig.dataset.liveBlogConfig).scripts
465
466                        // Load scripts sequentially
467                        for (const script of liveBlogScriptLinks) {
468                            await loadScriptSequentially(script)
469                        }
470                    }
471
472                    this.loaded = true;
473                } else {
474                    jppolCMP.debug ? console.log('jppolCMP - "' + this.name + "' will not load") : null;
475                }
476            }
477        },
478        adnami: {
479            name: "Adnami A/S",
480            required: [],
481            loaded: false,
482            load: function () {
483                jppolCMP.debug ? console.log('jppolCMP - "' + this.name + '" requires consent from:', this.required) : null;
484
485                const valid = jppolCMP.checkConsentsByCategory(this.required);
486
487                if (valid) {
488                    jppolCMP.createScript("https://macro.adnami.io/macro/spec/adsm.macro.749a71e5-eaa5-48b7-82a4-e9a28a048987.js", true, function () {
489                        window.adsmtag = adsmtag || {};
490                        adsmtag.cmd = adsmtag.cmd || [];
491                    });
492
493                    jppolCMP.createScript("https://macro.adnami.io/macro/gen/adnm.sonar-autotag.js", true, () => {}, null, [{
494                        name: "data-adnm-gid",
495                        value: "teczefybndby3w"
496                    }, {
497                        name: "data-adnm-sample",
498                        value: "70"
499                    }]);
500
501                    this.loaded = true;
502                } else {
503                    jppolCMP.debug ? console.log('jppolCMP - "' + this.name + "' will not load") : null;
504                }
505            }
506        },
507        brandmetrics: {
508            name: "Brand Metrics Sweden AB",
509            required: [],
510            loaded: false,
511            load: function () {
512                jppolCMP.debug ? console.log('jppolCMP - "' + this.name + '" requires consent from:', this.required) : null;
513
514                const valid = jppolCMP.checkConsentsByCategory(this.required);
515
516                if (valid) {
517                    jppolCMP.createScript("https://cdn.brandmetrics.com/tag/17fdf9b7-dfbf-4c2a-8a7d-868b496fb116/politike
517n.dk.js", true);
518                    this.loaded = true;
519                } else {
520                    jppolCMP.debug ? console.log('jppolCMP - "' + this.name + "' will not load") : null;
521                }
522            }
523        },
524        chartbeat: {
525            name: "Chartbeat",
526            required: [window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing],
527            loaded: false,
528            load: function () {
529                jppolCMP.debug ? console.log('jppolCMP - "' + this.name + '" requires consent from:', this.required) : null;
530
531                const valid = jppolCMP.checkConsentsByCategory(this.required);
532
533                if (valid) {
534                    jppolCMP.onReady(function () {
535                        jppolCMP.createScript("/static/js/chartbeat.js?d=" + jppolCmpConfig.cachekey, true, function () {
536                            window._sf_startpt = (new Date()).getTime();
537                        });
538                    });
539                    this.loaded = true;
540                } else {
541                    jppolCMP.debug ? console.log('jppolCMP - "' + this.name + "' will not load") : null;
542                }
543            }
544        },
545        echobox: {
546            name: "EchoBox",
547            required: [],
548            loaded: false,
549            load: function () {
550                jppolCMP.debug ? console.log('jppolCMP - "' + this.name + '" requires consent from:', this.required) : null;
551
552                const valid = jppolCMP.checkConsentsByCategory(this.required);
553
554                if (valid) {
555                    jppolCMP.createScript("https://applets.ebxcdn.com/ebx.js", true, () => {}, "ebx");
556                    this.loaded = true;
557                } else {
558                    jppolCMP.debug ? console.log('jppolCMP - "' + this.name + "' will not load") : null;
559                }
560            }
561        },
562        SupWiz: {
563            name: "SupWiz",
564            required: [],
565            loaded: false,
566            load: function () {
567                jppolCMP.debug ? console.log('jppolCMP - "' + this.name + '" requires consent from:', this.required) : null;
568
569                const valid = jppolCMP.checkConsentsByCategory(this.required);
570
571                if (valid && window.hasOwnProperty("polContext__")
572                    && window.polContext__.hasOwnProperty("page")
573                    && window.polContext__.page.hasOwnProperty("sectionId")) {
574
575                    const sectionId = window.polContext__.page.sectionId;
576
577                    jppolCMP.onReady(() => {
578                        if (sectionId === 4528) { //Politiken kundecenter
579                            jppolCMP.createScript("https://supchat.politiken.supwizapp.com/widget/main.js", true);
580                            jppolCMP.createScript("https://supchat.politiken.supwizapp.com/static/widget-configs/1.js", true, function () {
581                                try {
582                                    let ssoIdForSupChat = '';
583                                    let userNameForSupChat = 'anonym';
584                                    if (window.polContext__.hasOwnProperty("user")
585                                        && window.polContext__.user.hasOwnProperty("isAuthenticated")
586                                        && window.polContext__.user.hasOwnProperty("name")
587                                        && window.polContext__.user.hasOwnProperty("ssoId")
588                                        && window.polContext__.user.isAuthenticated) {
589                                        ssoIdForSupChat = window.polContext__.user.ssoId;
590                                        userNameForSupChat = window.polContext__.user.name;
591                                    }
592                                    if (window.config?.visitorInfo?.fields?.push) {
593                                        window.config.visitorInfo.fields.push({
594                                            name: userNameForSupChat,
595                                            type: 'hidden',
596                                            defaultValue: ssoIdForSupChat
597                                        });
598                                    } else {
599                                        console.warn('SupWiz widget: config.visitorInfo.fields ikke tilgængelig');
600                                    }
601
602                                    if (typeof configureWidget === 'function' && typeof config !== 'undefined') {
603                                        window.widgetObj = configureWidget(config);
604                                    } else {
605                                        console.warn('SupWiz widget: configureWidget eller config ikke tilgængelig');
606                                    }
607                                } catch (e) {
608                                    console.error('Fejl ved initialisering af SupWiz (config 1):', e);
609                                }
610                            });
611                        } else if (sectionId === 4877) { //Borneavisen kundecenter
612                            jppolCMP.createScript("https://supchat.politiken.supwizapp.com/widget/main.js", true);
613                            jppolCMP.createScript("https://supchat.politiken.supwizapp.com/static/widget-configs/3.js", true, function () {
614                                try {
615                                    if (typeof configureWidget === 'function' && typeof config !== 'undefined') {
616                                        window.widgetObj = configureWidget(config);
617                                    } else {
618                                        console.warn('SupWiz widget: configureWidget eller config ikke tilgængelig');
619                                    }
620                                } catch (e) {
621                                    console.error('Fejl ved initialisering af SupWiz widget:', e);
622                                }
623                            });
624                        }
625                    });
626                    this.loaded = true;
627                }
628            }
629        },
630        snowplow: {
631            name: "snowplow",
632            required: [],
633            loaded: false,
634            /**
635             * Snowplow consent settings will by default be set to noConsent.
636             * later depending on consent level, they can be changed and then applied.
637             */
638            snowplowConsentSettings: {
639                anonymousTracking: {
640                    withSessionTracking: true,
641                    withServerAnonymisation: true,
642                },
643                respectDoNotTrack: false,
644                sessionCookieTimeout: 0,
645                stateStorageStrategy: "none"
646            },
647            determineUserAuthorization: function (context) {
648                if (!context.user.ipAccessFor) {
649                    return "ip"
650                } else if (!context.page.sharedKey) {
651                    return "gift"
652                } else {
653                    return "login"
654                }
655            },
656            load: function () {
657                jppolCMP.debug ? console.log('jppolCMP - "' + this.name + '" requires consent from:', this.required) : null;
658
659                const snowplowConfig = window.jppolCmpConfig.snowplowConfig
660                if (!snowplowConfig.useSnowplow && !window.polSnowplowEventHandler) {
661                    jppolCMP.debug ? console.log("jppolCMP - Snowplow was disabled from the backend or the polSnowplowHandler was not found...") : null;
662                    return;
663                }
664
665                function mapUserTypeToSnowplowTypes(userType) {
666                    switch (userType) {
667                        case "subscriber":
668                        case "registered":
669                            return userType;
670
671                        default:
672                            return "anon";
673                    }
674                }
675
676                const customTrackerName = "snowplow-pol-escenic-tracker"; // this name is for internal use only
677                const collectorUrl = snowplowConfig.collectorUrl ?? null;
678                const appId = snowplowConfig.appId ?? null;
679                const snowplowPlatformType = "web"
680
681                const snowplowConsentState = this.getSnowplowConsentState()
682                if (snowplowConsentState === "hasConsent") {
683                    // We set the snowplow config to be full consent compatible
684                    this.updateSnowplowSettingsFullConsent();
685                }
686
687                if (!collectorUrl && !appId) {
688                    jppolCMP.debug ? console.error("SnowplowConfig did not include a collectorUrl") : null;
689                    return;
690                }
691
692                let schemaData = {};
693                if (window.polContext__) {
694                    const context = window.polContext__
695
696                    let accessType = context.user.access.brands[0] && context.user.access.brands[0].brandAccessAgreements[0] && context.user.access.brands[0].brandAccessAgreements[0].accessAgreementName || "";
697                    let accessId = context.user.access.brands[0] && context.user.access.brands[0].brandAccessAgreements[0] && context.user.access.brands[0].brandAccessAgreements[0].accessAgreementId || "";
698                    let accountNumber = context.user.access.brands[0] && context.user.access.brands[0].brandAccessAgreements[0] && context.user.access.brands[0].brandAccessAgreements[0].accountNumber || "";
699                    let accessAuthorizationType = this.determineUserAuthorization(context) || "";
700
701                    schemaData.access = {
702                        access_type: !accessType ? "ANON" : accessType,
703                        access_id: accessId,
704                        account_number: accountNumber,
705                        access_authorization_type: accessAuthorizationType
706                    }
707                    schemaData.user = {
708                        user_id: context.user.ssoId ?? "",
709                        anon_id: "ANON", // We don't have any useful ANON id, so we send ANON, which is inline with data team
710                        user_authenticated: window.polSnowplowEventHandler.convertBoolToYesOrNo(context.user.isAuthenticated) ?? "",
711                        user_type: mapUserTypeToSnowplowTypes(context.user.userType)
712                    }
713                    schemaData.content = {
714                        content_id: context.page?.articleId?.toString() ?? "null", // If there are no articleId, like on a authors page, then we return "null"
715                        content_label: !context.page.articleTitle ? "null" : context.page.articleTitle, // If there are no articleTitle, like on a authors page, then we return "null"
716                        content_section_id: context.page.sectionId.toString() ?? "",
717                        content_type: context.page.pageType ?? "null"
718                    }
719                    schemaData.page = {
720                        page_restricted: window.polSnowplowEventHandler.convertBoolToYesOrNo(context.page.isPremium) ?? "",
721                        page_section_id: context.page.sectionId.toString() ?? "",
722                        page_type: context.page.pageType ?? ""
723                    }
724                }
725
726                // new tracker object
727                const snowplowTrackerConfig = {
728                    useSnowplow: snowplowConfig.useSnowplow,
729                    snowplowTrackers: [{
730                        appId: appId,
731                        collectorUrl: collectorUrl,
732                        customTrackerName: customTrackerName,
733                        platformType: snowplowPlatformType,
734                        trackerSettings: {
735                            sessionCookieTimeout: this.snowplowConsentSettings.sessionCookieTimeout,
736                            respectDoNotTrack: this.snowplowConsentSettings.respectDoNotTrack,
737                            anonymousTracking: {
738                                withSessionTracking: this.snowplowConsentSettings.anonymousTracking.withSessionTracking,
739                                withServerAnonymisation: this.snowplowConsentSettings.anonymousTracking.withServerAnonymisation,
740                            },
741                            stateStorageStrategy: this.snowplowConsentSettings.stateStorageStrategy,
742                        },
743                        trackerEvents: {
744                            usePageview: true,
745                            useLinkClickTracking: true,
746                            useButtonClickTracking: true,
747                            useFormTracking: true,
748                        },
749                    }],
750                    schemaTypes: schemaData
751                }
752
753                // Start snowplow tracking
754                window.polSnowplowEventHandler.initSnowplow(snowplowTrackerConfig, window.Cookiebot);
755
756                this.loaded = true;
757            },
758            updateSnowplowSettingsFullConsent: function () {
759                if (window.jppolCMP.fullConsent || (window.Cookiebot?.consent?.marketing && window.Cookiebot?.consent?.statistics)) {
760                    this.snowplowConsentSettings.sessionCookieTimeout = 1800;
761                    this.snowplowConsentSettings.anonymousTracking.withServerAnonymisation = false;
762                    this.snowplowConsentSettings.stateStorageStrategy = "cookieAndLocalStorage";
763
764                    jppolCMP.debug ? console.log("SNOWPLOW: We updated snowplow to have a full consent session", this.snowplowConsentSettings) : null;
765                }
766            },
767            setSnowplowConsentState: function (value) {
768                window.localStorage.setItem("snowplow_state", value.toString());
769            },
770            getSnowplowConsentState: function () {
771                return window.localStorage.getItem("snowplow_state")
772            }
773        },
774        GTM: {
775            name: "Google Tag Manager",
776            required: [],
777            loaded: false,
778            load: function () {
779                if (window.jppolCmpConfig.tagManagerId.trim().length === 0){
780                    return;
781                }
782                jppolCMP.debug ? console.log('jppolCMP - "' + this.name + '" requires consent from:', this.required) : null;
783
784                const valid = jppolCMP.checkConsentsByCategory(this.required);
785
786                if (valid) {
787                    (function (w, d, s, l, i) {
788                        w[l] = w[l] || [];
789                        w[l].push({'gtm.start': new Date().getTime(), event: 'gtm.js'});
790                        const f = d.getElementsByTagName(s)[0], j = d.createElement(s),
791                            dl = l !== 'dataLayer' ? '&l=' + l : '';
792                        j.async = true;
793                        //j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl + window.jppolCmpConfig.tagManagerId;
794                        j.src = '/proxy/pza?id=' + i + dl + window.jppolCmpConfig.tagManagerId;
795                        f.parentNode.insertBefore(j, f);
796
797                        // Set control pixel, as extra data gathering
798                        jppolCMP.setCMPTrackingPixel();
799
800                    })(window, document, 'script', 'dataLayer', 'GTM-TPRSNTR');
801                    this.loaded = true;
802                } else {
803                    jppolCMP.debug ? console.log('jppolCMP - "' + this.name + "' will not load") : null;
804                }
805            }
806        },
807        adModule: {
808            name: "Ad Module",
809            required: [],
810            loaded: false,
811            bannerData: [],
812            load: async function () {
813                if (!window.jppolCmpConfig.useAdModule) {
814                    console.log("window.jppolCmpConfig.useAdModule was false")
815                    return;
816                }
817                jppolCMP.debug ? console.log('jppolCMP - "' + this.name + '" NOW STARTING UP') : null;
818
819                // We initialise the ad server scripts, which is needed before we initialise the rest of the ad module
820                try {
821                    await window.polAdModuleHandler.setAndInitAdServerScripts()
822                } catch (e) {
823                    console.error("Failed to set Ad Script...", e)
824                    return;
825                }
826
827                const context = window?.polContext__
828                if (!context) {
829                    jppolCMP.debug ? console.error("polContext was not found...") : null;
830                    return;
831                }
832
833                if (this.bannerData.length === 0) {
834                    jppolCMP.debug ? console.error("bannerdata was 0, so we return ads...") : null;
835                    return;
836                }
837
838                const bannerDataArray = this.bannerData.map((data) => {
839                    return {
840                        placementCode: data?.targetId,
841                        adSize: data?.sizes
842                    }
843                });
844
845                const adModuleConfig = {
846                    fullConsent: jppolCMP.fullConsent,
847                    deviceType: context.page.deviceType,
848                    currentSection: context.page.section,
849                    targetingValues: {
850                        bloomreachSegment: context?.user.bloomreachSegments,
851                        activeFeatures: context?.user.access.activeFeatures,
852                        articleId: context?.page.articleId,
853                        isPremium: context?.page.isPremium,
854                        publisherName: context?.page.subbrand,
855                        currentSection: context?.page?.section,
856                        subscriptionFeatures: context?.user?.access.subscriptionFeatures,
857                        suggestedTags: context?.page.suggestedTags,
858                        articleTags: context?.page.articleTags,
859                        articleTitle: context?.page.articleTitle,
860                        articleSubTitle: context?.page.articleSubtitle,
861                        articleAuthors: context?.page.articleAuthors,
862                        usertype: context?.user.userType,
863                        newsletters: context?.user.newsletters
864                    },
865                    bannerData: bannerDataArray,
866                }
867                window.polAdModuleHandler.initAdModule(adModuleConfig)
868
869                this.loaded = true;
870            }
871        },
872        bloomreach: {
873            name: "Bloomreach",
874            required: [jppolCMPVendorCategories.preferences, window.jppolCMPVendorCategories.statistics, window.jppolCMPVendorCategories.marketing],
875            loaded: false,
876            load: function () {
877                if (!window.jppolCmpConfig.useBloomreach) {
878                    return;
879                }
880                jppolCMP.debug = true;
881                jppolCMP.debug ? console.log('jppolCMP - "' + this.name + '" requires consent from:', this.required) : null;
882                const valid = jppolCMP.checkConsentsByCategory(this.required);
883                if (valid) {
884                    jppolCMP.onReady(function () {
885                        function startBloomreach() {
886                            const Bloomreach = window.require("module/common/bloomreach");
887                            const initResult = Bloomreach.init();
888
889                            const customer = {};
890
891                            // temporary_id must always be defined for us to track all events.
892                            // This check is here to provide backwards compatibility, for
893                            // when clients for some reason get a new version of this,
894                            // but a cached version of module/common/bloomreach, whose
895                            // init function returns undefined.
896                            if (initResult && initResult.temporaryId) {
897                                customer.temporary_id = initResult.temporaryId;
898                            }
899
900                            // When not logged in, users get a temporary ssoId. Using this
901                            // as composite_key (our bloomreach "hard id"), prevents
902                            // bloomreach from merging customers based on their "soft ids"
903                            // (__exponea_etc__ cookie). For this reason, we rely solely on
904                            // the cookie id, until the user logs in. See
905                            // https://documentation.bloomreach.com/engagement/docs/merging
906                            // for details
907                            if (window.polContext__.user.isAuthenticated) {
908                                customer.composite_key = window.polContext__.page.cdpBrandName + "_" + window.polContext__.user.ssoId;
909                            }
910
911                            !function(e,n,t,i,o,r){function a(e){if("number"!=typeof e)return e;var n=new Date;return new Date(n.getTime()+1e3*e)}var c=4e3,s="xnpe_async_hide";function p(e){return e.reduce((function(e,n){return e[n]=function(){e._.push([n.toString(),arguments])},e}),{_:[]})}function m(e,n,t){var i=t.createElement(n);i.src=e;var o=t.getElementsByTagName(n)[0];return o.parentNode.insertBefore(i,o),i}function u(e){return"[object Date]"===Object.prototype.toString.call(e)}r.target=r.target||"https://api.exponea.com",r.file_path=r.file_path||r.target+"/js/exponea.min.js",o[n]=p(["anonymize","initialize","identify","getSegments","update","track","trackLink","trackEnhancedEcommerce","getHtml","showHtml","showBanner","showWebLayer","ping","getAbTest","loadDependency","getRecommendation","reloadWebLayers","_preInitialize"]),o[n].notifications=p(["isAvailable","isSubscribed","subscribe","unsubscribe"]),o[n]["snippetVersion"]="v2.5.0",function(e,n,t){e[n]["_"+t]={},e[n]["_"+t].nowFn=Date.now,e[n]["_"+t].snippetStartTime=e[n]["_"+t].nowFn()}(o,n,"performance"),function(e,n,t,i,o,r){e[o]={sdk:e[i],sdkObjectName:i,skipExperiments:!!t.new_experiments,sign:t.token+"/"+(r.exec(n.cookie)||["","new"])[1],path:t.target}}(o,e,r,n,i,RegExp("__exponea_etc__"+"=([\\w-]+)")),function(e,n,t){m(e.file_path,n,t)}(r,t,e),function(e,n,t,i,o,r,p){if(e.new_experiments){!0===e.new_experiments&&(e.new_experiments={});var l,f=e.new_experiments.hide_class||s,_=e.new_experiments.timeout||c,d=encodeURIComponent(r.location.href.split("#")[0]);e.cookies&&e.cookies.expires&&("number"==typeof e.cookies.expires||u(e.cookies.expires)?l=a(e.cookies.expires):e.cookies.expires.tracking&&("number"==typeof e.cookies.expires.tracking||u(e.cookies.expires.tracking))&&(l=a(e.cookies.expires.tracking))),l&&l<new Date&&(l=void 0);var x=e.target+"/webxp/"+n+"/"+r[t].sign+"/modifications.min.js?http-referer="+d+"&timeout="+_+"ms"+(l?"&cookie-expires="+Math.floor(l.getTime()/1e3):"");"sync"===e.new_experiments.mode&&r.localStorage.getItem("__exponea__sync_modifications__")?function(e,n,t,i,o){t[o][n]="<"+n+' src="'+e+'"></'+n+">",i.writeln(t[o][n]),i.writeln("<"+n+">!"+o+".init && document.writeln("+o+"."+n+'.replace("/'+n+'/", "/'+n+'-async/").replace("><", " async><"))</'+n+">")}(x,n,r,p,t):function(e,n,t,i,o,r,a,c){r.documentElement.classList.add(e);var s=m(t,i,r);function p(){o[c].init||m(t.replace("/"+i+"/","/"+i+"-async/"),i,r)}function u(){r.documentElement.classList.remove(e)}s.onload=p,s.onerror=p,o.setTimeout(u,n),o[a]._revealPage=u}(f,_,x,n,r,p,o,t)}}(r,t,i,0,n,o,e),function(e,n,t){var i;(null===(i=t.experimental)||void 0===i?void 0:i.non_personalized_weblayers)&&e[n]._preInitialize(t),e[n].start=function(i){i&&Object.keys(i).forEac
911h((function(e){return t[e]=i[e]})),e[n].initialize(t)}}(o,n,r)}(document,"exponea","script","webxpClient",window,{
912                                target: jppolCmpConfig.cdpProjectBaseUrl,
913                                token: jppolCmpConfig.cdpProjectToken,
914                                customer,
915                                cookies: {
916                                    cross_subdomain: false,
917                                },
918                                track: {
919                                    google_analytics: false,
920                                },
921                            });
922                            window.exponea.start();
923                        };
924
925                        function startBloomreachIfReady() {
926                            if (!(window.require && window.require.defined("module/common/bloomreach"))) {
927                                return false;
928                            }
929
930                            if (jppolCMP.debug) {
931                                console.log("jppolCMP - initializing bloomreach module");
932                            }
933
934                            startBloomreach();
935                            return true;
936                        };
937
938                        if(!startBloomreachIfReady()) {
939                            if (jppolCMP.debug) {
940                                console.log("jppolCMP - can't initialize bloomreach module yet. Will retry");
941                            }
942                            const intervalId = setInterval(function () {
943                                if (startBloomreachIfReady()) {
944                                    clearInterval(intervalId);
945                                } else {
946                                    if (jppolCMP.debug) {
947                                        console.log("jppolCMP - can't initialize bloomreach module yet. Will retry");
948                                    }
949                                }
950                            }, 200);
951                        }
952                    });
953                    this.loaded = true;
954                }
955            }
956        }
957    },
958    init: function () {
959        if (window.hasOwnProperty("jppolPerf") && window.jppolPerf.browserMeasureSupported) {
960            window.performance.measure('jppolCmp:init:start');
961        }
962
963        // set relevaceId, also used in "cookieless environments"
964        let id = "";
965        if (window.hasOwnProperty("polContext__")
966            && window.polContext__.hasOwnProperty("user")
967            && window.polContext__.user.hasOwnProperty("relevanceId")
968            && window.polContext__.user.relevanceId !== "") {
969            id = window.polContext__.user.relevanceId;
970        } else {
971            // check localStorage for ID
972            id = window.localStorage.getItem("_ls_value");
973        }
974        window.jppolCMP.relevanceId = id;
975
976        // load consented vendor-scripts
977        for (const p in jppolCMP.vendors) {
978            if (jppolCMP.vendors.hasOwnProperty(p)) {
979                const v = jppolCMP.vendors[p];
980                if (v.hasOwnProperty('load') && v.hasOwnProperty('loaded')) {
981                    if (v.loaded) {
982                        jppolCMP.debug ? console.log('Vendor: ', p, 'has already been loaded') : null;
983                    } else {
984                        v.load();
985                    }
986                }
987            }
988        }
989        // load embeds
990        jppolCMP.onReady(function () {
991            for (let i = 0; i < window.jppolCmpConfig.embeds.length; i++) {
992                const embed = window.jppolCmpConfig.embeds[i];
993                if (embed.loaded) {
994                    jppolCMP.debug ? console.log('Embed with "id":', embed.id, 'has already been loaded') : null;
995                } else {
996                    jppolCMP.createEmbed(embed.id, embed.html, embed.bodyElements);
997                }
998            }
999
1000        });
1001    },
1002    onReady: function (callback) {
1003        if (typeof (callback) !== "function") {
1004            jppolCMP.debug ? console.log("jppolCMP.onReady - 'callback' in not a function:", typeof (callback)) : null;
1005            return false
1006        }
1007        if (/complete|interactive/.test(document.readyState)) {
1008            callback();
1009        } else {
1010            document.addEventListener('DOMContentLoaded', function () {
1011                callback();
1012            });
1013        }
1014    },
1015    checkConsentsByCategory: function (array) {
1016        if (Array.isArray(array) && array.length === 0) {
1017            return true;
1018        }
1019        if (window.hasOwnProperty("Cookiebot") && window.Cookiebot.hasOwnProperty("consent")) {
1020            for (let i = 0; i < array.length; i++) {
1021                const category = array[i];
1022                if (window.Cookiebot.consent.hasOwnProperty(category) && window.Cookiebot.consent[category]) {
1023                    // continue
1024                } else {
1025                    jppolCMP.debug ? console.log("jppolCMP - consent: '" + category + "' not found or false") : null;
1026                    return false;
1027                }
1028            }
1029            return true;
1030        }
1031        return false;
1032    },
1033    checkFullConsent: function () {
1034        if (window.hasOwnProperty("Cookiebot") && window.Cookiebot.hasOwnProperty("consent")
1035            && window.Cookiebot.consent.hasOwnProperty('necessary') && window.Cookiebot.consent.necessary
1036            && window.Cookiebot.consent.hasOwnProperty('preferences') && window.Cookiebot.consent.preferences
1037            && window.Cookiebot.consent.hasOwnProperty('statistics') && window.Cookiebot.consent.statistics
1038            && window.Cookiebot.consent.hasOwnProperty('marketing') && window.Cookiebot.consent.marketing) {
1039            return true
1040        }
1041        return false;
1042    },
1043    createScript: function (src, async, callback = () => {}, id, attributes = []) {
1044        if (src !== null && typeof (src) !== "undefined") {
1045            const s = document.createElement("script");
1046            s.src = src;
1047            (async !== null && typeof (async) !== "undefined") ? s.async = (async === true) : false;
1048            if (typeof (callback) === "function") {
1049                s.onload = function () {
1050                    callback();
1051                    jppolCMP.debug ? console.log("jppolCMP - callback done:", src) : null;
1052                }
1053            }
1054            if (id !== null && typeof (id) !== "undefined") {
1055                s.id = id;
1056            }
1057            if (attributes != null && Array.isArray(attributes)) {
1058                for (let i = 0; i < attributes.length; i++) {
1059                    const attribute = attributes[i];
1060                    if ((attribute != null) && (typeof attribute === "object")) {
1061                        s.setAttribute(attribute.name, attribute.value);
1062                    }
1063                }
1064            }
1065            const t = document.getElementsByTagName("script")[0];
1066            t.parentNode.insertBefore(s, t);
1067            jppolCMP.debug ? console.log("jppolCMP - created script:", src) : null;
1068        } else {
1069            console.log("jppolCMP - 'src' is invalid");
1070        }
1071    },
1072
1073    /**
1074     *
1075     * Due to legislative initiatives, we need to offer the read a direct link to the embedded content
1076     * - if users have not accepted cookies. This logic extracts the direct url to the content, from the provided embed code, from CUE.
1077     *
1078     * Due to the quite diverse opportunities for content embedding, each embed provider handles embedding differently, hence the logic below.
1079     * The logic works by finding the correct vendor, which we need to handle a url from. Then we get the url from a querySelector
1080     * @see embedQuery
1081     * From this query, we can extract the correct url to make sure we pass this url to the component, that informs people about their missing consent.
1082     *
1083     * @return string - if nothing is found, this defaults to an empty string.
1084     *
1085     * @param doc - the document of the page, but parsed to an object.
1086     * @param vendor - an object, that contains information about the embed vendor. The value contains the vendor name (string) and the permission level required (array with strings).
1087     *
1088     */
1089    getUrlFromEmbedCode: function (doc, vendor) {
1090        let contentUrl = "";
1091        const embedQuery = doc.querySelector("iframe, blockquote, div, script")
1092
1093        if (embedQuery) {
1094            const vendorName = vendor.name;
1095
1096            // As embeds are different, we iterate through each case, to make sure we get the correct URL value.
1097            if (vendorName.toLowerCase().includes("reddit") || vendorName.indexOf("reddit") !== -1) {
1098                /**
1099                 * Reddit offers multiple links, for the users, comments etc.
1100                 * We take the firstChild, and it's href, as this links to the directly embedded post.
1101                 */
1102                contentUrl = embedQuery.firstChild.href;
1103            }
1104            else if (vendorName.toLowerCase().includes("twitter") || vendorName.indexOf("twitter") !== -1 ) {
1105                // This case is a fallback case, in case we have old twitter embeds.
1106                contentUrl = embedQuery.childNodes[2].href ? embedQuery.childNodes[2].href : embedQuery.querySelector("a").href ? embedQuery.querySelector("a").href : "";
1107            }
1108            else if (vendorName.toLowerCase().includes("x") || vendorName.indexOf("x") !== -1 ) {
1109                contentUrl = embedQuery.childNodes[2].href ? embedQuery.childNodes[2].href : embedQuery.querySelector("a").href ? embedQuery.querySelector("a").href : "";
1110            }
1111            else if (vendorName.toLowerCase().includes("bluesky") || vendorName.indexOf("bluesky") !== -1 ) {
1112                const getUrlValue = embedQuery.querySelector("a").href ? embedQuery.querySelector("a").href : embedQuery.children[3].href;
1113                if (getUrlValue) {
1114                    contentUrl = getUrlValue;
1115                }
1116            }
1117            else if (vendorName.toLowerCase().includes("youtube") || vendorName.indexOf("youtube") !== -1) {
1118                contentUrl = embedQuery.src;
1119            }
1120            else if (vendorName.toLowerCase().includes("facebook") || vendorName.indexOf("facebook") !== -1) {
1121                contentUrl = embedQuery.src;
1122            }
1123            else if (vendorName.toLowerCase().includes("instagram") || vendorName.indexOf("instagram") !== -1) {
1124                contentUrl = embedQuery.dataset.instgrmPermalink;
1125            }
1126            else if (vendorName.toLowerCase().includes("tiktok") || vendorName.indexOf("tiktok") !== -1) {
1127                contentUrl = embedQuery.cite;
1128            }
1129            else if (vendorName.toLowerCase().includes("threads") || vendorName.indexOf("threads") !== -1) {
1130                contentUrl = embedQuery.dataset.textPostPermalink;
1131            }
1132            else if (vendorName.toLowerCase().includes("tumblr") || vendorName.indexOf("tumblr") !== -1) {
1133                contentUrl = embedQuery.dataset.href;
1134            }
1135            else if (vendorName.toLowerCase().includes("spotify") || vendorName.indexOf("spotify") !== -1) {
1136                contentUrl = embedQuery.src;
1137            }
1138            else if (vendorName.toLowerCase().includes("vimeo") || vendorName.indexOf("vimeo") !== -1) {
1139                contentUrl = embedQuery.src;
1140            }
1141            else if (vendorName.toLowerCase().includes("imgur") || vendorName.indexOf("imgur") !== -1) {
1142                contentUrl = embedQuery.firstChild.href;
1143            }
1144            else if (vendorName.toLowerCase().includes("giphy") || vendorName.indexOf("giphy") !== -1) {
1145                contentUrl = embedQuery.src;
1146            }
1147            else if (vendorName.toLowerCase().includes("google maps") || vendorName.indexOf("google maps") !== -1) {
1148                const googleMapsQuery = embedQuery.src;
1149
1150                /**
1151                 * This regex query looks for the values in between the string values '2d' and '3d'.
1152                 * The values in between a seperate by a question mark, which is the regex query also handles, by only taking values in between.
1153                 * The collected values are our longitude and latitude values, which we need to create the correct link for Google Maps.
1154                 *
1155                 * The collected 2d value: this is related to the longitude coordinates
1156                 * The collected 3d value: this is related to the latitude coordinates
1157                 * @type {RegExp}
1158                 */
1159                const regex = /!2d([-+]?\d*\.?\d+)!3d([-+]?\d*\.?\d+)/;
1160                const googleMapsUrlRegexMatch = googleMapsQuery.match(regex);
1161
1162                if (googleMapsUrlRegexMatch) {
1163                    const longitude = googleMapsUrlRegexMatch[1];
1164                    const latitude = googleMapsUrlRegexMatch[2];
1165                    const mapZoomLevel = 14; // the range goes from 0 to the 21 - 0 being the whole world and 21 extremely zoomed. 14 is picked as a sweet spot in between.
1166
1167                    /**
1168                     * This string is composed with inspiration from Googles api: https://developers.google.com/maps/documentation/urls/get-started#search-action
1169                     * And is the final string, that we send the frontend, for users to view.
1170                     * @type {string}
1171                     */
1172                    const googleMapsUrlWithCoordinates = `https://www.google.com/maps/@?api=1&map_action=map&center=${latitude}%2C${longitude}&zoom=${mapZoomLevel}`;
1173                    contentUrl = googleMapsUrlWithCoordinates
1174                }
1175            }
1176            else if (vendorName.toLowerCase().includes("figma") || vendorName.indexOf("figma") !== -1) {
1177                contentUrl = embedQuery.src;
1178            }
1179            else if (vendorName.toLowerCase().includes("truth social") || vendorName.indexOf("truth social") !== -1) {
1180                contentUrl = embedQuery.src;
1181            }
1182            else if (vendorName.toLowerCase().includes("telegram") || vendorName.indexOf("telegram") !== -1) {
1183                const baseTelegramUrl = "https://t.me/";
1184                const pathToContent = embedQuery.dataset.telegramPost;
1185
1186                if (pathToContent) {
1187                    contentUrl = baseTelegramUrl + pathToContent
1188                }
1189            }
1190            else {
1191                jppolCMP.debug ? console.log("jppolCMP - could not locate a url from the provided embedded query: ", embedQuery) : null;
1192            }
1193        }
1194
1195        return contentUrl;
1196    },
1197
1198    createEmbed: function (id, script, description) {
1199        let i;
1200        let valid;
1201        let vendor;
1202        const div = document.getElementById(id);
1203        if (div === null) {
1204            jppolCMP.debug ? console.log("jppolCMP - createEmbed() could not find element with 'id':", id) : null;
1205            return false;
1206        }
1207
1208        const doc = new window.DOMParser().parseFromString(script, "text/html");
1209
1210        let vendorSrc = doc.head.innerHTML.match(/[\s.]src="(.*?)"/i);
1211        if (typeof (vendorSrc) === "undefined" || vendorSrc === null) {
1212            vendorSrc = doc.body.innerHTML.match(/[\s.]src="(.*?)"/i);
1213        }
1214
1215        if (vendorSrc && vendorSrc.length && vendorSrc.length > 1) {
1216            const str = vendorSrc[1].toLowerCase();
1217
1218            // http or external src
1219            if (/https?:\/\//.test(str) || /\/\//.test(str)) {
1220
1221                vendor = jppolCMP.findEmbedVendorsFromString(str);
1222
1223                // don't show unknown vendors
1224                if (!vendor.hasOwnProperty('name')) {
1225                    jppolCMP.debug ? console.log("jppolCMP - Could not find vendor using String 'str':", str) : null;
1226                    div.innerHTML = jppolCMP.embedHtmlVendorNotFound();
1227                    return false;
1228                }
1229
1230                valid = true;
1231                if (vendor.hasOwnProperty("required")) {
1232                    valid = jppolCMP.checkConsentsByCategory(vendor.required);
1233                }
1234
1235                // don't show vendors without consent
1236                if (!valid) {
1237                    jppolCMP.debug ? console.log("jppolCMP - no consent for embed with 'id'", id, "found vendor:", vendor) : null;
1238
1239                    let vendorName = "Indlejret indhold";
1240                    if (vendor.hasOwnProperty("name") && typeof (vendor.name) === "string") {
1241                        vendorName = vendor.name;
1242                    }
1243
1244                    // no need to tell the user to accept already accepted categories
1245                    let requiredString = "";
1246                    const noConsentCategories = [];
1247
1248                    for (i = 0; i < vendor.required.length; i++) {
1249                        const category = vendor.required[i];
1250                        if (!Cookiebot.consent[category]) {
1251                            noConsentCategories.push(category);
1252                        }
1253                    }
1254                    for (i = 0; i < noConsentCategories.length; i++) {
1255                        // over 2 items and last loop?
1256                        const cat = window.jppolCMPVendorCategories.translateCategories(noConsentCategories[i]);
1257                        if (noConsentCategories.length >= 2 && (i + 1) === noConsentCategories.length) {
1258                            requiredString += " og " + cat;
1259                        } else {
1260                            requiredString += cat;
1261                        }
1262                    }
1263
1264                    // getting direct url to embed, from embed code
1265                    const urlFromEmbed = this.getUrlFromEmbedCode(doc, vendor)
1266
1267                    // Building vendor object for modal, and assigning url value to object
1268                    const vendorObject = this.buildRequiredMessage(vendor)
1269                    vendorObject["url"] = urlFromEmbed;
1270
1271                    div.innerHTML = jppolCMP.embedHtmlNoConsent(vendorObject, description);
1272                    return false;
1273                }
1274            }
1275            // eTrack specific logic
1276            else if (str.indexOf("/webservice/etrack")) {
1277                vendor = jppolCMP.findEmbedVendorsFromString(str);
1278
1279                valid = true;
1280                if (vendor.hasOwnProperty("required") && Array.isArray(vendor.required)) {
1281                    valid = jppolCMP.checkConsentsByCategory(vendor.required);
1282                }
1283
1284                if (valid) {
1285                    div.innerHTML = script;
1286                } else {
1287                    div.innerHTML = jppolCMP.embedHtmlNoConsent(jppolCMP.buildRequiredMessage(vendor), description);
1288                }
1289                jppolCMP.debug ? console.log('jppolCMP - Embedded eTrack iframe') : null;
1290                return true;
1291            }
1292        } else {
1293            jppolCMP.debug ? console.log('jppolCMP - no "vendorSrc" found for "id":', id) : null;
1294        }
1295
1296        // find scripts inside embedded html
1297        const scripts = [];
1298        let x = 0;
1299
1300        const headScripts = doc.head.getElementsByTagName('script');
1301        for (x = 0; x < headScripts.length; x++) {
1302            const s = headScripts[x];
1303            scripts.push({
1304                "src": s.src,
1305                "async": s.async,
1306                "code": (s.text || s.textContent || s.innerHTML || ""),
1307                "attributes" : s.attributes
1308            });
1309
1310            // TODO: Is this correct? Scripts should be removed, but can we do this while looping?
1311            s.remove();
1312        }
1313
1314        const bodyScripts = doc.body.getElementsByTagName('script');
1315        for (x = 0; x < bodyScripts.length; x++) {
1316            const p = bodyScripts[x];
1317            scripts.push({
1318                "src": p.src,
1319                "async": p.async,
1320                "code": (p.text || p.textContent || p.innerHTML || ""),
1321                "attributes" : p.attributes
1322            });
1323
1324            // TODO: Is this correct? Scripts should be removed, but can we do this while looping?
1325            p.remove();
1326        }
1327
1328        // append html after scripts has been removed
1329        div.innerHTML = (description || "") + doc.body.innerHTML;
1330        jppolCMP.debug ? console.log("jppolCMP - creating scripts for id: ", id, scripts) : null;
1331
1332        // create and run scripts from "doc" in "this.document"
1333        for (i = 0; i < scripts.length; i++) {
1334            const r = scripts[i];
1335            if (r.code !== "" || r.attributes.length) {
1336                var newScript = document.createElement("script");
1337
1338                /* Since some embeds like Telegrams only contains a script with no content, but rather fetches it's content,
1339                we need to link the attributes and src and embed it inline, since said script creates its iframe next to the
1340                original scripts placement in the DOM */
1341                if (r.src) {
1342                    newScript.src = r.src
1343                }
1344
1345                const attributes = r.attributes;
1346
1347                for (let i = 0; i < attributes.length; i++) {
1348                    const attribute = attributes[i];
1349                    if (attribute.name.startsWith('data-')) {
1350                        newScript.setAttribute(attribute.name, attribute.value);
1351                    }
1352                }
1353
1354                newScript.appendChild(document.createTextNode(r.code));
1355                div.parentElement.insertBefore(newScript, div);
1356                jppolCMP.debug ? console.log("jppolCMP - created local-script for id: ", id) : null;
1357            } else {
1358                jppolCMP.createScript(r.src, r.async, function () {
1359                    jppolCMP.debug ? console.log('jppolCMP - embedded script with "src":', r.src) : null;
1360                });
1361            }
1362        }
1363
1364        // set embed as loaded, to prevent double loading the same embed
1365        for (i = 0; i < window.jppolCmpConfig.embeds.length; i++) {
1366            const embed = window.jppolCmpConfig.embeds[i];
1367            if (embed.id === id) {
1368                embed.loaded = true;
1369                break;
1370            }
1371        }
1372    },
1373    buildRequiredMessage: function (vendor) {
1374        let requiredString = "";
1375        let i;
1376        const noConsentCategories = [];
1377
1378        let vendorName = "Indlejret indhold";
1379        if (vendor.hasOwnProperty("name") && typeof (vendor.name) === "string") {
1380            vendorName = vendor.name;
1381        }
1382
1383        for (i = 0; i < vendor.required.length; i++) {
1384            const category = vendor.required[i];
1385            if (!Cookiebot.consent[category]) {
1386                noConsentCategories.push(category);
1387            }
1388        }
1389        for (i = 0; i < noConsentCategories.length; i++) {
1390            // over 2 items and last loop?
1391            const cat = window.jppolCMPVendorCategories.translateCategories(noConsentCategories[i]);
1392            if (noConsentCategories.length >= 2 && (i + 1) === noConsentCategories.length) {
1393                requiredString += " og " + cat;
1394            } else {
1395                requiredString += cat;
1396            }
1397        }
1398        return {vendorName: vendorName, message: requiredString};
1399    },
1400    findEmbedVendorsFromString: function (string) {
1401        for (const p in jppolCMP.embedVendors) {
1402            if (jppolCMP.embedVendors.hasOwnProperty(p)) {
1403
1404                const vendor = jppolCMP.embedVendors[p];
1405                if (vendor.hasOwnProperty("sources")) {
1406
1407                    const src = vendor.sources;
1408                    if (Array.isArray(src)) {
1409                        for (let i = 0; i < src.length; i++) {
1410                            if (string.indexOf(src[i]) !== -1) {
1411                                return vendor;
1412                            }
1413                        }
1414                    }
1415                }
1416            }
1417        }
1418        return {};
1419    },
1420    removeHtmlCollection: function (htmlCollection) {
1421        if (htmlCollection.length > 0) {
1422            for (let i = (htmlCollection.length - 1); i > -1; i--) {
1423                htmlCollection[i].remove();
1424                // TODO: create polyfill: https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/remove
1425            }
1426        }
1427    },
1428    getExternalUid: function (response) {
1429        if (response.hasOwnProperty("uid")) {
1430            window.jppolCMP.externalId = response.uid;
1431        } else {
1432            console.log("invalid response:", response);
1433        }
1434    },
1435    setCMPTrackingPixel: function () {
1436        const context = window?.polContext__;
1437        // Set control pixel, as extra data gathering
1438        const endpoint = "https://w2w52itmtj.execute-api.eu-west-1.amazonaws.com/test"
1439
1440        const data = {
1441            tb: "event",
1442            t: "pizza",
1443            cd2: context.user.ssoId ? context.user.ssoId.toString() : "",
1444            cd3: context.user.type ? context.user.type.toString() : "",
1445            cd5: context.page.articleId ? context.page.articleId.toString() : "",
1446            cd7: context.page.sectionName ? context.page.sectionName.toString() : "",
1447            cd8: context.page.sectionHierarchy ? context.page.sectionHierarchy.toString() : "",
1448            cd9: context.page.contentType ? context.page.contentType.toString() : "",
1449            cd67: context.user.isPremium ? context.user.isPremium.toString() : "",
1450            cd68: context.page.currentURL ? context.page.currentURL.toString() : "",
1451            cd70: "old", // we set old, to establish the pixel is sat by our old platform
1452            cd71: "false", // we set false, to establish the pixel is not a bf_cache pixel
1453            cd82: window.sessionStorage.getItem("hashed_session") ? window.sessionStorage.getItem("hashed_session").toString() : "",
1454            cd83: navigator.userAgent ? navigator.userAgent.toString() : "",
1455            cd87: context.page.deviceType ? context.page.deviceType.toString().toLowerCase() : "",
1456            region: context.geo.stateName ? context.geo.stateName.toString() : "",
1457            country: context.geo.countryName ? context.geo.countryName.toString() : "",
1458        }
1459
1460        const params = new URLSearchParams(data)
1461        const url = new URL(endpoint)
1462        url.search = params.toString()
1463
1464        const pixel = document.createElement("img")
1465        pixel.height = 0
1466        pixel.width = 0
1467        pixel.style = "display: none";
1468        pixel.src = url.toString()
1469    },
1470    updateConsentModeV2: function () {
1471        function gtag() {
1472            window.dataLayer.push(arguments);
1473        }
1474
1475        // If a user gives full consent, we set all values to 'granted'
1476        if (window.jppolCMP.checkFullConsent()) {
1477            gtag('consent', 'update', {
1478                'ad_user_data': 'granted',
1479                'ad_personalization': 'granted',
1480                'ad_storage': 'granted',
1481                'analytics_storage': 'granted',
1482                'functionality_storage': 'granted',
1483                'personalization_storage': 'granted',
1484                'security_storage': 'granted',
1485            })
1486        } else {
1487            // If we don't have full cookie permission, we need to be selective about what we grant permission to.
1488            const consentModeAttributes = {
1489                'ad_personalization': 'denied',
1490                'ad_storage': 'denied',
1491                'ad_user_data': 'denied',
1492                'analytics_storage': 'denied',
1493                'functionality_storage': 'denied',
1494                'personalization_storage': 'denied',
1495                'security_storage': 'granted',
1496            }
1497
1498            if (window.Cookiebot?.consent?.marketing === true) {
1499                // Update attributes, to enable marketing related consent mode permission
1500                consentModeAttributes.ad_user_data = 'granted';
1501                consentModeAttributes.ad_personalization = 'granted';
1502                consentModeAttributes.ad_storage = 'granted';
1503            }
1504            if (window.Cookiebot?.consent?.statistics === true) {
1505                // Update attributes, to enable statistics related consent mode permission
1506                consentModeAttributes.analytics_storage = 'granted';
1507            }
1508            if (window.Cookiebot?.consent?.preferences === true) {
1509                // Update attributes, to enable preferences related consent mode permission
1510                consentModeAttributes.functionality_storage = 'granted'
1511                consentModeAttributes.personalization_storage = 'granted'
1512            }
1513
1514            // After setting consent mode v2 permission, we can now set them in the dataLayer with the gtag function,
1515            gtag('consent', 'update', consentModeAttributes)
1516        }
1517    }
1518};
1519
1520window.addEventListener('CookiebotOnConsentReady', function () {
1521
1522    // prevent cookiebot cookie from expiring after 7 days in Safari
1523    let c = Cookiebot,
1524        d = document,
1525        cookies = d.cookie.split(";"),
1526        consentCookie = "",
1527        consentDate = c.consentUTC,
1528        consentExpiry = new Date(consentDate.setMonth(consentDate.getMonth() + 12)),
1529        now = new Date();
1530
1531    for (let i = 0; i < cookies.length; i++) {
1532        if (/^CookieConsent/g.test(cookies[i])) {
1533            consentCookie = cookies[i];
1534        }
1535        if (consentCookie !== "" && now < consentExpiry) {
1536            d.cookie = consentCookie + ";expires=" + consentExpiry.toUTCString() + ";path=/";
1537        }
1538    }
1539
1540    // since we have to load fonts before we know what the user has consented to,
1541    // we have to place a cookie, to let the font-script know, if it's ok to store fonts in localstorage
1542    // for subsequent visits
1543    if ('localStorage' in window) {
1544        if (window.hasOwnProperty("Cookiebot")
1545            && window.Cookiebot.hasOwnProperty("consent")
1546            && window.Cookiebot.consent.hasOwnProperty("preferences")
1547            && window.Cookiebot.consent.preferences) {
1548            localStorage.setItem('isPreferencesAllowed', true);
1549        } else {
1550            localStorage.removeItem('isPreferencesAllowed')
1551        }
1552    }
1553
1554    // scripts in Google Tag Manager will only fire if fullConsent = true
1555    jppolCMP.fullConsent = jppolCMP.checkFullConsent();
1556
1557    // We update Consent Mode v2.
1558    jppolCMP.updateConsentModeV2();
1559
1560    // TODO: quick-fix, find better solution which only runs in our App
1561    if (window.ReactNativeWebView) {
1562        if (jppolCMP.fullConsent) {
1563            window.ReactNativeWebView.postMessage(JSON.stringify({
1564                href: window.location.href,
1565                type: 'FULL_CONSENT',
1566                page: window.polContext__.page,
1567            }));
1568        } else {
1569            window.ReactNativeWebView.postMessage(JSON.stringify({
1570                href: window.location.href,
1571                type: 'LIMITED_CONSENT',
1572                page: window.polContext__.page,
1573            }));
1574        }
1575    }
1576
1577    jppolCMP.init();
1578
1579    if (window.hasOwnProperty("jppolPerf") && window.jppolPerf.browserMeasureSupported) {
1580        window.performance.measure('jppolCmp:init:end');
1581    }
1582}, false);
1583
1584/**
1585 * This event happens when cookiebot registeres that the consent state is
1586 * decline - meaning there has been given no consent.
1587 * This runs on every pageload.
1588 *
1589 * Please notice - this events run after the "CookiebotOnConsentReady" event
1590 */
1591window.addEventListener("CookiebotOnDecline", () => {
1592    const snowplowConsent = window.jppolCMP.vendors.snowplow.getSnowplowConsentState();
1593    if (snowplowConsent === "hasConsent") {
1594        window.jppolCMP.vendors.snowplow.setSnowplowConsentState("noConsent") // This will ensure we don't clear the session on every load.
1595
1596        // When no consent is registered first, we need to clear the session and start a new one.
1597        window.polSnowplowEventHandler.clearExistingSnowplowSessionAndStartNew();
1598        window.jppolCMP.debug ? console.log("SNOWPLOW: We cleared the current snowplow session and started a new one.", window.jppolCMP.vendors.snowplow.snowplowConsentSettings) : null;
1599    } else if (!snowplowConsent) {
1600        // We set consent state to noConsent, since this else case would be the initial load, without previous consent registered for Snowplow
1601        window.jppolCMP.vendors.snowplow.setSnowplowConsentState("noConsent")
1602    }
1603});
1604
1605/**
1606 * This event happens when cookiebot registers that the consent state is
1607 * accepted - meaning there has been given consent.
1608 * Note: This runs even when there is given consent to one parameter - like marketing.
1609 * So it can not be used to trust there is full consent for all c
1609ookies.
1610 * This runs on every pageload.
1611 *
1612 * Please notice - this events run after the "CookiebotOnConsentReady" event
1613 */
1614window.addEventListener("CookiebotOnAccept", () => {
1615    const snowplowConsent = window.jppolCMP.vendors.snowplow.getSnowplowConsentState();
1616    if (snowplowConsent === "noConsent") {
1617        window.jppolCMP.vendors.snowplow.setSnowplowConsentState("hasConsent") // flip the consent, to ensure it's not repeating.
1618        window.jppolCMP.debug ? console.log("SNOWPLOW: Consent was given - the tracking can now track with full consent") : null
1619    } else if (!snowplowConsent) {
1620        // We set consent state to hasConsent, since this else case would be the initial load, without previous consent registered for Snowplow
1621        window.jppolCMP.vendors.snowplow.setSnowplowConsentState("hasConsent");
1622    }
1623});

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.