PageSourceSearch

https://vds.de/typo3temp/assets/compressed/merged-f2f8a0820e027ea0…899514186cae621825181e35804cd.js?1729163057

js vds.de collected 2026-10-02 10:39:56 UTC 71,280 bytes, 1,664 lines download raw bytes

1
2/**
3 * released under MIT license by Insites
4 * https://github.com/insites/cookieconsen
5 * small changes by Die Medialen
6 */
7
8function isTrackingAllowed() {
9    if (window.cookieconsent) return cookieconsent.utils.isTrackingAllowed();
10    else return false;
11}
12
13(function (cc) {
14    // stop from running again, if accidently included more than once.
15    if (cc.hasInitialised) return;
16
17    var util = {
18            // http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
19            escapeRegExp: function (str) {
20                return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
21            },
22
23            hasClass: function (element, selector) {
24                var s = ' ';
25                return element.nodeType === 1 &&
26                    (s + element.className + s).replace(/[\n\t]/g, s).indexOf(s + selector + s) >= 0;
27            },
28
29            addClass: function (element, className) {
30                element.className += ' ' + className;
31            },
32
33            removeClass: function (element, className) {
34                var regex = new RegExp('\\b' + this.escapeRegExp(className) + '\\b');
35                element.className = element.className.replace(regex, '');
36            },
37
38            interpolateString: function (str, callback) {
39                var marker = /{{([a-z][a-z0-9\-_]*)}}/ig;
40                return str.replace(marker, function (matches) {
41                    return callback(arguments[1]) || '';
42                })
43            },
44
45            getCookie: function (name) {
46                var value = '; ' + document.cookie;
47                var parts = value.split('; ' + name + '=');
48                return parts.length != 2 ?
49                    undefined : parts.pop().split(';').shift();
50            },
51
52            setCookie: function (name, value, expiryDays, domain, path) {
53                var exdate = new Date();
54                exdate.setDate(exdate.getDate() + (expiryDays || 365));
55
56                var cookie = [
57                    name + '=' + value,
58                    'expires=' + exdate.toUTCString(),
59                    'path=' + (path || '/')
60                ];
61
62                if (domain) {
63                    cookie.push('domain=' + domain);
64                }
65                document.cookie = cookie.join(';');
66            },
67
68            // only used for extending the initial options
69            deepExtend: function (target, source) {
70                for (var prop in source) {
71                    if (source.hasOwnProperty(prop)) {
72                        if (prop in target && this.isPlainObject(target[prop]) && this.isPlainObject(source[prop])) {
73                            this.deepExtend(target[prop], source[prop]);
74                        } else {
75                            target[prop] = source[prop];
76                        }
77                    }
78                }
79                return target;
80            }
81            ,
82
83            // only used for throttling the 'mousemove' event (used for animating the revoke button when `animateRevokable` is true)
84            throttle: function (callback, limit) {
85                var wait = false;
86                return function () {
87                    if (!wait) {
88                        callback.apply(this, arguments);
89                        wait = true;
90                        setTimeout(function () {
91                            wait = false;
92                        }, limit);
93                    }
94                }
95            }
96            ,
97
98            // only used for hashing json objects (used for hash mapping palette objects, used when custom colours are passed through JavaScript)
99            hash: function (str) {
100                var hash = 0,
101                    i, chr, len;
102                if (str.length === 0) return hash;
103                for (i = 0, len = str.length; i < len; ++i) {
104                    chr = str.charCodeAt(i);
105                    hash = ((hash << 5) - hash) + chr;
106                    hash |= 0;
107                }
108                return hash;
109            }
110            ,
111
112            normaliseHex: function (hex) {
113                if (hex[0] == '#') {
114                    hex = hex.substr(1);
115                }
116                if (hex.length == 3) {
117                    hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
118                }
119                return hex;
120            }
121            ,
122
123            // used to get text colors if not set
124            getContrast: function (hex) {
125                hex = this.normaliseHex(hex);
126                var r = parseInt(hex.substr(0, 2), 16);
127                var g = parseInt(hex.substr(2, 2), 16);
128                var b = parseInt(hex.substr(4, 2), 16);
129                var yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
130                return (yiq >= 128) ? '#000' : '#fff';
131            }
132            ,
133
134            // used to change color on highlight
135            getLuminance: function (hex) {
136                var num = parseInt(this.normaliseHex(hex), 16),
137                    amt = 38,
138                    R = (num >> 16) + amt,
139                    B = (num >> 8 & 0x00FF) + amt,
140                    G = (num & 0x0000FF) + amt;
141                var newColour = (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + (B < 255 ? B < 1 ? 0 : B : 255) * 0x100 + (G < 255 ? G < 1 ? 0 : G : 255)).toString(16).slice(1);
142                return '#' + newColour;
143            }
144            ,
145
146            isMobile: function () {
147                return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
148            }
149            ,
150
151            isPlainObject: function (obj) {
152                // The code "typeof obj === 'object' && obj !== null" allows Array objects
153                return typeof obj === 'object' && obj !== null && obj.constructor == Object;
154            }
155            ,
156            isTrackingAllowed: function() {
157                var cookieValue = util.getCookie("tracking_cookie_consent");
158                return (navigator.doNotTrack != 1) && (["dismiss", "allow"].includes(cookieValue));
159            }
160        }
161    ;
162
163    // valid cookie values
164    cc.status = {
165        deny: 'deny',
166        allow: 'allow',
167        dismiss: 'dismiss'
168    };
169
170    // detects the `transitionend` event name
171    cc.transitionEnd = (function () {
172        var el = document.createElement('div');
173        var trans = {
174            t: "transitionend",
175            OT: "oTransitionEnd",
176            msT: "MSTransitionEnd",
177            MozT: "transitionend",
178            WebkitT: "webkitTransitionEnd",
179        };
180
181        for (var prefix in trans) {
182            if (trans.hasOwnProperty(prefix) && typeof el.style[prefix + 'ransition'] != 'undefined') {
183                return trans[prefix];
184            }
185        }
186        return '';
187    }());
188
189    cc.hasTransition = !!cc.transitionEnd;
190
191    // array of valid regexp escaped statuses
192    var __allowedStatuses = Object.keys(cc.status).map(util.escapeRegExp);
193
194    // contains references to the custom <style> tags
195    cc.customStyles = {};
196
197    cc.Popup = (function () {
198
199        var defaultOptions = {
200
201            // if false, this prevents the popup from showing (useful for giving to control to another piece of code)
202            enabled: true,
203
204            // optional (expecting a HTML element) if passed, the popup is appended to this element. default is `document.body`
205            container: null,
206
207            // defaults cookie options - it is RECOMMENDED to set these values to correspond with your server
208            cookie: {
209                // This is the name of this cookie - you can ignore this
210                name: 'tracking_cookie_consent',
211
212                // This is the url path that the cookie 'name' belongs to. The cookie can only be read at this location
213                path: '/',
214
215                // This is the domain that the cookie 'name' belongs to. The cookie can only be read on this domain.
216                //  - Guide to cookie domains - http://erik.io/blog/2014/03/04/definitive-guide-to-cookie-domains/
217                domain: '',
218
219                // The cookies expire date, specified in days (specify -1 for no expiry)
220                expiryDays: 365,
221            },
222
223            // these callback hooks are called at certain points in the program execution
224            onPopupOpen: function () {
225            },
226            onPopupClose: function () {
227            },
228            onInitialise: function (status) {
229            },
230            onStatusChange: function (status, chosenBefore) {
231            },
232            onRevokeChoice: function () {
233            },
234            // each item defines the inner text for the element that it references
235            content: {
236                header: 'Cookies used on the website!',
237                message: 'This website uses cookies to ensure you get the best experience on our website.',
238                dismiss: 'OK',
239                allow: 'OK',
240                deny: 'Decline',
241                link: 'Learn more',
242                href: 'http://cookiesandyou.com',
243                close: '&#x274c;',
244                optout_text: 'Von anonymer Nutzeranalyse abmelden',
245                checkbox_text: 'Tracking unterbinden',
246                dnt_text: 'Do Not Track ist in Ihrem Browser gesetzt'
247            },
248
249            // This is the HTML for the elements above. The string {{header}} will be replaced with the equivalent text below.
250            // You can remove "{{header}}" and write the content directly inside the HTML if you want.
251            //
252            //  - ARIA rules suggest to ensure controls are tabbable (so the browser can find the first control),
253            //    and to set the focus to the first interactive control (http://w3c.github.io/aria-in-html/)
254            elements: {
255                header: '<span class="cc-header">{{header}}</span>&nbsp;',
256                message: '<span id="cookieconsent:desc" class="cc-message">{{message}}</span>',
257                messagelink: '<span id="cookieconsent:desc" class="cc-message">{{message}} <a aria-label="learn more about cookies" role=button tabindex="0" class="cc-link" href="{{href}}" rel="noopener noreferrer nofollow" target="_blank">{{link}}</a></span>',
258                dismiss: '<a aria-label="dismiss cookie message" role=button tabindex="0" class="cc-btn cc-dismiss">{{dismiss}}</a>',
259                allow: '<a aria-label="allow cookies" role=button tabindex="0"  class="cc-btn cc-allow">{{allow}}</a>',
260                deny: '<a aria-label="deny cookies" role=button tabindex="0" class="cc-btn cc-deny">{{deny}}</a>',
261                link: '<a aria-label="learn more about cookies" role=button tabindex="0" class="cc-link" href="{{href}}" target="_blank">{{link}}</a>',
262                close: '<span aria-label="dismiss cookie message" role=button tabindex="0" class="cc-close">{{close}}</span>',
263                slideout: '<div class="slideout"><input type="checkbox" name="cc-tracking-checkbox" id="cc-tracking-checkbox" /><label for="cc-tracking-checkbox">{{checkbox_text}}</label></div>',
264                messageoptout: '<span id="cookieconsent:desc" class="cc-message">{{message}} <a aria-label="learn more about cookies" role=button tabindex="0" class="cc-link" href="{{href}}" rel="noopener noreferrer nofollow" target="_blank">{{link}}</a><span class="cc-link cookieaccordion">{{optout_text}}</span></span>'
265                //compliance: compliance is also an element, but it is generated by the application, depending on `type` below
266            },
267
268            // The placeholders {{classes}} and {{children}} both get replaced during initialisation:
269            //  - {{classes}} is where additional classes get added
270            //  - {{children}} is where the HTML children are placed
271            window: '<div role="dialog" aria-live="polite" aria-label="cookieconsent" aria-describedby="cookieconsent:desc" class="cc-window {{classes}}"><!--googleoff: all-->{{children}}<!--googleon: all--></div>',
272
273            // This is the html for the revoke button. This only shows up after the user has selected their level of consent
274            // It can be enabled of disabled using the `revokable` option
275            revokeBtn: '<div class="cc-revoke {{classes}}">Cookie Policy</div>',
276
277            // define types of 'compliance' here. '{{value}}' strings in here are linked to `elements`
278            compliance: {
279                'info': '<div class="cc-compliance">{{dismiss}}</div>',
280                'opt-in': '<div class="cc-compliance cc-highlight">{{dismiss}}{{allow}}</div>',
281                'opt-out': '<div class="cc-compliance cc-highlight">{{deny}}{{dismiss}}</div>',
282            },
283
284            // select your type of popup here
285            type: 'info', // refers to `compliance` (in other words, the buttons that are displayed)
286
287            // define layout layouts here
288            layouts: {
289                // the 'block' layout tend to be for square floating popups
290                'basic': '{{messagelink}}{{compliance}}',
291                'basic-slideout': '{{messageoptout}}{{compliance}}{{slideout}}',
292                'basic-close': '{{messagelink}}{{compliance}}{{close}}',
293                'basic-header': '{{header}}{{message}}{{link}}{{compliance}}',
294
295                // add a custom layout here, then add some new css with the class '.cc-layout-my-cool-layout'
296                //'my-cool-layout': '<div class="my-special-layout">{{message}}{{compliance}}</div>{{close}}',
297            },
298
299            // default layout (see above)
300            layout: 'basic-slideout',
301
302            // this refers to the popup windows position. we currently support:
303            //  - banner positions: top, bottom
304            //  - floating positions: top-left, top-right, bottom-left, bottom-right
305            //
306            // adds a class `cc-floating` or `cc-banner` which helps when styling
307            position: 'bottom', // default position is 'bottom'
308
309            // Available styles
310            //    -block (default, no extra classes)
311            //    -edgeless
312            //    -classic
313            // use your own style name and use `.cc-theme-STYLENAME` class in CSS to edit.
314            // Note: style "wire" is used for the configurator, but has no CSS styles of its own, only palette is used.
315            theme: 'block',
316
317            // The popup is `fixed` by default, but if you want it to be static (inline with the page content), set this to fal
317se
318            // Note: by default, we animate the height of the popup from 0 to full size
319            static: false,
320
321            // if you want custom colours, pass them in here. this object should look like this.
322            // ideally, any custom colours/themes should be created in a separate style sheet, as this is more efficient.
323            //   {
324            //     popup: {background: '#000000', text: '#fff', link: '#fff'},
325            //     button: {background: 'transparent', border: '#f8e71c', text: '#f8e71c'},
326            //     highlight: {background: '#f8e71c', border: '#f8e71c', text: '#000000'},
327            //   }
328            // `highlight` is optional and extends `button`. if it exists, it will apply to the first button
329            // only background needs to be defined for every element. if not set, other colors can be calculated from it
330            palette: null,
331
332            // Some countries REQUIRE that a user can change their mind. You can configure this yourself.
333            // Most of the time this should be false, but the `cookieconsent.law` can change this to `true` if it detects that it should
334            revokable: false,
335
336            // if true, the revokable button will tranlate in and out
337            animateRevokable: true,
338
339            // used to disable link on existing layouts
340            // replaces element messagelink with message and removes content of link
341            showLink: true,
342
343            // set value as scroll range to enable
344            dismissOnScroll: false,
345
346            // set value as time in milliseconds to autodismiss after set time
347            dismissOnTimeout: false,
348
349            // The application automatically decide whether the popup should open.
350            // Set this to false to prevent this from happening and to allow you to control the behaviour yourself
351            autoOpen: true,
352
353            // By default the created HTML is automatically appended to the container (which defaults to <body>). You can prevent this behaviour
354            // by setting this to false, but if you do, you must attach the `element` yourself, which is a public property of the popup instance:
355            //
356            //     var instance = cookieconsent.factory(options);
357            //     document.body.appendChild(instance.element);
358            //
359            autoAttach: true,
360
361            // simple whitelist/blacklist for pages. specify page by:
362            //   - using a string : '/index.html'           (matches '/index.html' exactly) OR
363            //   - using RegExp   : /\/page_[\d]+\.html/    (matched '/page_1.html' and '/page_2.html' etc)
364            whitelistPage: [],
365            blacklistPage: [],
366
367            // If this is defined, then it is used as the inner html instead of layout. This allows for ultimate customisation.
368            // Be sure to use the classes `cc-btn` and `cc-allow`, `cc-deny` or `cc-dismiss`. They enable the app to register click
369            // handlers. You can use other pre-existing classes too. See `src/styles` folder.
370            overrideHTML: null,
371        };
372
373        function CookiePopup() {
374            this.initialise.apply(this, arguments);
375            $('.cc-window .cc-message .cookieaccordion').on('click', function () {
376                $('.cc-window .slideout').slideToggle();
377            });
378        }
379
380        CookiePopup.prototype.initialise = function (options) {
381            if (this.options) {
382                this.destroy(); // already rendered
383            }
384
385            // set options back to default options
386            util.deepExtend(this.options = {}, defaultOptions);
387
388            // merge in user options
389            if (util.isPlainObject(options)) {
390                util.deepExtend(this.options, options);
391            }
392
393            // returns true if `onComplete` was called
394            if (checkCallbackHooks.call(this)) {
395                // user has already answered
396                this.options.enabled = false;
397            }
398
399            // apply blacklist / whitelist
400            if (arrayContainsMatches(this.options.blacklistPage, location.pathname)) {
401                this.options.enabled = false;
402            }
403            if (arrayContainsMatches(this.options.whitelistPage, location.pathname)) {
404                this.options.enabled = true;
405            }
406
407            // the full markup either contains the wrapper or it does not (for multiple instances)
408            var cookiePopup = this.options.window
409                .replace('{{classes}}', getPopupClasses.call(this).join(' '))
410                .replace('{{children}}', getPopupInnerMarkup.call(this));
411
412            // if user passes html, use it instead
413            var customHTML = this.options.overrideHTML;
414            if (typeof customHTML == 'string' && customHTML.length) {
415                cookiePopup = customHTML;
416            }
417
418            // if static, we need to grow the element from 0 height so it doesn't jump the page
419            // content. we wrap an element around it which will mask the hidden content
420            if (this.options.static) {
421                // `grower` is a wrapper div with a hidden overflow whose height is animated
422                var wrapper = appendMarkup.call(this, '<div class="cc-grower">' + cookiePopup + '</div>');
423
424                wrapper.style.display = ''; // set it to visible (because appendMarkup hides it)
425                this.element = wrapper.firstChild; // get the `element` reference from the wrapper
426                this.element.style.display = 'none';
427                util.addClass(this.element, 'cc-invisible');
428            } else {
429                this.element = appendMarkup.call(this, cookiePopup);
430            }
431
432            applyAutoDismiss.call(this);
433
434            applyRevokeButton.call(this);
435
436            if (this.options.autoOpen) {
437                this.autoOpen();
438            }
439        };
440
441        CookiePopup.prototype.destroy = function () {
442            if (this.onButtonClick && this.element) {
443                this.element.removeEventListener('click', this.onButtonClick);
444                this.onButtonClick = null;
445            }
446
447            if (this.dismissTimeout) {
448                clearTimeout(this.dismissTimeout);
449                this.dismissTimeout = null;
450            }
451
452            if (this.onWindowScroll) {
453                window.removeEventListener('scroll', this.onWindowScroll);
454                this.onWindowScroll = null;
455            }
456
457            if (this.onMouseMove) {
458                window.removeEventListener('mousemove', this.onMouseMove);
459                this.onMouseMove = null;
460            }
461
462            if (this.element && this.element.parentNode) {
463                this.element.parentNode.removeChild(this.element);
464            }
465            this.element = null;
466
467            if (this.revokeBtn && this.revokeBtn.parentNode) {
468                this.revokeBtn.parentNode.removeChild(this.revokeBtn);
469            }
470            this.revokeBtn = null;
471
472            removeCustomStyle(this.options.palette);
473            this.options = null;
474        };
475
476        CookiePopup.prototype.open = function (callback) {
477            if (!this.element) return;
478
479            if (!this.isOpen()) {
480                if (cc.hasTransition) {
481                    this.fadeIn();
482                } else {
483                    this.element.style.display = '';
484                }
485
486                if (this.options.revokable) {
487                    this.toggleRevokeButton();
488                }
489                this.options.onPopupOpen.call(this);
490                attachCheckboxHandler('cc-tracking-checkbox', this);
491            }
492
493            return this;
494        };
495        CookiePopup.prototype.close = function (showRevoke) {
496            if (!this.element) return;
497
498            if (this.isOpen()) {
499                if (cc.hasTransition) {
500                    this.fadeOut();
501                } else {
502                    this.element.style.display = 'none';
503                }
504
505                if (showRevoke && this.options.revokable) {
506                    this.toggleRevokeButton(true);
507                }
508                this.options.onPopupClose.call(this);
509            }
510
511            return this;
512        };
513
514        CookiePopup.prototype.fadeIn = function () {
515            var el = this.element;
516
517            if (!cc.hasTransition || !el)
518                return;
519
520            // This should always be called AFTER fadeOut (which is governed by the 'transitionend' event).
521            // 'transitionend' isn't all that reliable, so, if we try and fadeIn before 'transitionend' has
522            // has a chance to run, then we run it ourselves
523            if (this.afterTransition) {
524                afterFadeOut.call(this, el)
525            }
526
527            if (util.hasClass(el, 'cc-invisible')) {
528                el.style.display = '';
529
530                if (this.options.static) {
531                    var height = this.element.clientHeight;
532                    this.element.parentNode.style.maxHeight = '100%';
533                }
534
535                var fadeInTimeout = 20; // (ms) DO NOT MAKE THIS VALUE SMALLER. See below
536
537                // Although most browsers can handle values less than 20ms, it should remain above this value.
538                // This is because we are waiting for a "browser redraw" before we remove the 'cc-invisible' class.
539                // If the class is remvoed before a redraw could happen, then the fadeIn effect WILL NOT work, and
540                // the popup will appear from nothing. Therefore we MUST allow enough time for the browser to do
541                // its thing. The actually difference between using 0 and 20 in a set timeout is neglegible anyway
542                this.openingTimeout = setTimeout(afterFadeIn.bind(this, el), fadeInTimeout);
543            }
544        };
545
546        CookiePopup.prototype.fadeOut = function () {
547            var el = this.element;
548
549            if (!cc.hasTransition || !el)
550                return;
551
552            if (this.openingTimeout) {
553                clearTimeout(this.openingTimeout);
554                afterFadeIn.bind(this, el);
555            }
556
557            if (!util.hasClass(el, 'cc-invisible')) {
558                if (this.options.static) {
559                    this.element.parentNode.style.maxHeight = '';
560                }
561
562                this.afterTransition = afterFadeOut.bind(this, el);
563                el.addEventListener(cc.transitionEnd, this.afterTransition);
564
565                util.addClass(el, 'cc-invisible');
566            }
567        };
568
569        CookiePopup.prototype.isOpen = function () {
570            return this.element && this.element.style.display == '' && (cc.hasTransition ? !util.hasClass(this.element, 'cc-invisible') : true);
571        };
572
573        CookiePopup.prototype.toggleRevokeButton = function (show) {
574            if (this.revokeBtn) this.revokeBtn.style.display = show ? '' : 'none';
575        };
576
577        CookiePopup.prototype.revokeChoice = function (preventOpen) {
578            this.options.enabled = true;
579            this.clearStatus();
580
581            this.options.onRevokeChoice.call(this);
582
583            if (!preventOpen) {
584                this.autoOpen();
585            }
586        };
587
588        // returns true if the cookie has a valid value
589        CookiePopup.prototype.hasAnswered = function (options) {
590            return Object.keys(cc.status).indexOf(this.getStatus()) >= 0;
591        };
592
593        // returns true if the cookie indicates that consent has been given
594        CookiePopup.prototype.hasConsented = function (options) {
595            var val = this.getStatus();
596            return val == cc.status.allow || val == cc.status.dismiss;
597        };
598
599        // opens the popup if no answer has been given
600        CookiePopup.prototype.autoOpen = function (options) {
601            !this.hasAnswered() && this.options.enabled && this.open();
602        };
603
604        CookiePopup.prototype.setStatus = function (status) {
605            var c = this.options.cookie;
606            var value = util.getCookie(c.name);
607            var chosenBefore = Object.keys(cc.status).indexOf(value) >= 0;
608
609            // if `status` is valid
610            if (Object.keys(cc.status).indexOf(status) >= 0) {
611
612                util.setCookie(c.name, status, c.expiryDays, c.domain, c.path);
613
614                this.options.onStatusChange.call(this, status, chosenBefore);
615            } else {
616                this.clearStatus();
617            }
618        };
619
620        CookiePopup.prototype.getStatus = function () {
621            return util.getCookie(this.options.cookie.name);
622        };
623
624        CookiePopup.prototype.clearStatus = function () {
625            var c = this.options.cookie;
626            util.setCookie(c.name, '', -1, c.domain, c.path);
627        };
628
629        // This needs to be called after 'fadeIn'. This is the code that actually causes the fadeIn to work
630        // There is a good reason why it's called in a timeout. Read 'fadeIn';
631        function afterFadeIn(el) {
632            this.openingTimeout = null;
633            util.removeClass(el, 'cc-invisible');
634        }
635
636        // This is called on 'transitionend' (only on the transition of the fadeOut). That's because after we've faded out, we need to
637        // set the display to 'none' (so there aren't annoying invisible popups all over the page). If for whenever reason this function
638        // is not called (lack of support), the open/close mechanism will still work.
639        function afterFadeOut(el) {
640            el.style.display = 'none'; // after close and before open, the display should be none
641            el.removeEventListener(cc.transitionEnd, this.afterTransition);
642            this.afterTransition = null;
643        }
644
645        // this function calls the `onComplete` hook and returns true (if needed) and returns false otherwise
646        function checkCallbackHooks() {
647            var complete = this.options.onInitialise.bind(this);
648
649            if (!window.navigator.cookieEnabled) {
650                complete(cc.status.deny);
651                return true;
652            }
653
654            if (window.CookiesOK || window.navigator.CookiesOK) {
655                complete(cc.status.allow);
656                return true;
657            }
658
659            var allowed = Object.keys(cc.status);
660            var answer = this.getStatus();
661            var match = allowed.indexOf(answer) >= 0;
662
663            if (match) {
664                complete(answer);
665            }
666            return match;
667        }
668
669        function attachCheckboxHandler(checkboxId, popup) {
670            var cbox = document.getElementById(checkboxId);
671
672            if (cbox != undefined) {
673                //checkbox anhand cookies und dnt setzen
674                if (navigator.doNotTrack == 1) {
675                    //opt-out mandatory with DNT set
676                    cbox.checked = "checked";
677                    if (document.querySelector) {
678                        var label = document.querySelector("label[for=" + "cc-tracking-checkbox" + "]");
679                        label.innerHTML = popup.options.content.dnt_text;
680
681                    }
682                }
683                else if (util.getCookie("tracking_cookie_consent")!="deny" && navigator.doNotTrack != 1) {
684                    cbox.checked = false;
685                }
686                cbox.onclick = function () {
687                    if (navigator.doNotTrack == 1) {
688                        this.checked = "checked"; //opt-out mandatory with DNT set
689                    }
690                    else if (this.checked) {
691                        util.setCookie("tracking_cookie_consent", "deny", 365);
692                    }
693                    else {
694                        util.setCookie("tracking_cookie_consent", "", 365);
695                    }
696                    // popup.close(true);
697                };
698            }
699        };
700
701        function getPositionClasses() {
702            var positions = this.options.position.split('-'); // top, bottom, left, right
703            var classes = [];
704
705            // top, left, right, bottom
706            positions.forEach(function (cur) {
707                classes.push('cc-' + cur);
708            });
709
710            return classes;
711        }
712
713        function getPopupClasses() {
714            var opts = this.options;
715            var positionStyle = (opts.position == 'top' || opts.position == 'bottom') ? 'banner' : 'floating';
716
717            if (util.isMobile()) {
718                positionStyle = 'floating';
719            }
720
721            var classes = [
722                'cc-' + positionStyle, // floating or banner
723                'cc-type-' + opts.type, // add the compliance type
724                'cc-theme-' + opts.theme, // add the theme
725            ];
726
727            if (opts.static) {
728                classes.push('cc-static');
729            }
730
731            classes.push.apply(classes, getPositionClasses.call(this));
732
733            // we only add extra styles if `palette` has been set to a valid value
734            var didAttach = attachCustomPalette.call(this, this.options.palette);
735
736            // if we override the palette, add the class that enables this
737            if (this.customStyleSelector) {
738                classes.push(this.customStyleSelector);
739            }
740
741            return classes;
742        }
743
744        function getPopupInnerMarkup() {
745            var interpolated = {};
746            var opts = this.options;
747
748            // removes link if showLink is false
749            if (!opts.showLink) {
750                opts.elements.link = '';
751                opts.elements.messagelink = opts.elements.message;
752            }
753
754            Object.keys(opts.elements).forEach(function (prop) {
755                interpolated[prop] = util.interpolateString(opts.elements[prop], function (name) {
756                    var str = opts.content[name];
757                    return (name && typeof str == 'string' && str.length) ? str : '';
758                })
759            });
760
761            // checks if the type is valid and defaults to info if it's not
762            var complianceType = opts.compliance[opts.type];
763            if (!complianceType) {
764                complianceType = opts.compliance.info;
765            }
766
767            // build the compliance types from the already interpolated `elements`
768            interpolated.compliance = util.interpolateString(complianceType, function (name) {
769                return interpolated[name];
770            });
771
772            // checks if the layout is valid and defaults to basic if it's not
773            var layout = opts.layouts[opts.layout];
774            if (!layout) {
775                layout = opts.layouts.basic;
776            }
777
778            return util.interpolateString(layout, function (match) {
779                return interpolated[match];
780            });
781        }
782
783        function appendMarkup(markup) {
784            var opts = this.options;
785            var div = document.createElement('div');
786            var cont = (opts.container && opts.container.nodeType === 1) ? opts.container : document.body;
787
788            div.innerHTML = markup;
789
790            var el = div.children[0];
791
792            el.style.display = 'none';
793
794            if (util.hasClass(el, 'cc-window') && cc.hasTransition) {
795                util.addClass(el, 'cc-invisible');
796            }
797
798            // save ref to the function handle so we can unbind it later
799            this.onButtonClick = handleButtonClick.bind(this);
800
801            el.addEventListener('click', this.onButtonClick);
802
803            if (opts.autoAttach) {
804                if (!cont.firstChild) {
805                    cont.appendChild(el);
806                } else {
807                    cont.insertBefore(el, cont.firstChild)
808                }
809            }
810
811            return el;
812        }
813
814        function handleButtonClick(event) {
815            var targ = event.target;
816			var fin=false;
817            if (util.hasClass(targ, 'cc-btn')) {
818                var matches = targ.className.match(new RegExp("\\bcc-(" + __allowedStatuses.join('|') + ")\\b"));
819                var match = (matches && matches[1]) || false;
820                if (match == "dismiss" && util.getCookie("tracking_cookie_consent") == "deny") match = "deny";
821                if (match) {
822                    this.setStatus(match);
823                    this.close(true);
824                }
825                if (match == "dismiss" && util.getCookie("tracking_cookie_consent") !== "deny") fin=true;
826            }
827            if (util.hasClass(targ, 'cc-close')) {
828                if (util.isTrackingAllowed()) {
829                    this.setStatus(cc.status.allow);
830                }
831                else {
832                    this.setStatus(cc.status.deny);
833                }
834                this.close(true);
835            }
836            if (util.hasClass(targ, 'cc-revoke')) {
837                this.revokeChoice();
838            }
839			if(fin) location.reload(); 
840        }
841
842        // I might change this function to use inline styles. I originally chose a stylesheet be
842cause I could select many elements with a
843        // single rule (something that happened a lot), the apps has changed slightly now though, so inline styles might be more applicable.
844        function attachCustomPalette(palette) {
845            var hash = util.hash(JSON.stringify(palette));
846            var selector = 'cc-color-override-' + hash;
847            var isValid = util.isPlainObject(palette);
848
849            this.customStyleSelector = isValid ? selector : null;
850
851            if (isValid) {
852                addCustomStyle(hash, palette, '.' + selector);
853            }
854            return isValid;
855        }
856
857        function addCustomStyle(hash, palette, prefix) {
858
859            // only add this if a style like it doesn't exist
860            if (cc.customStyles[hash]) {
861                // custom style already exists, so increment the reference count
862                ++cc.customStyles[hash].references;
863                return;
864            }
865            var colorStyles = {};
866            var popup = palette.popup;
867            var button = palette.button;
868            var highlight = palette.highlight;
869            var deny = palette.deny;
870
871            // needs background colour, text and link will be set to black/white if not specified
872            if (popup) {
873                // assumes popup.background is set
874                popup.text = popup.text ? popup.text : util.getContrast(popup.background);
875                popup.link = popup.link ? popup.link : popup.text;
876                colorStyles[prefix + '.cc-window'] = [
877                    'color: ' + popup.text,
878                    'background-color: ' + popup.background
879                ];
880                colorStyles[prefix + '.cc-revoke'] = [
881                    'color: ' + popup.text,
882                    'background-color: ' + popup.background
883                ];
884                colorStyles[prefix + ' .cc-link,' + prefix + ' .cc-link:active,' + prefix + ' .cc-link:visited'] = [
885                    'color: ' + popup.link
886                ];
887
888                if (button) {
889                    // assumes button.background is set
890                    button.text = button.text ? button.text : util.getContrast(button.background);
891                    button.border = button.border ? button.border : 'transparent';
892                    colorStyles[prefix + ' .cc-btn'] = [
893                        'color: ' + button.text,
894                        'border-color: ' + button.border,
895                        'background-color: ' + button.background
896                    ];
897
898                    if (button.background != 'transparent')
899                        colorStyles[prefix + ' .cc-btn:hover, ' + prefix + ' .cc-btn:focus'] = [
900                            'background-color: ' + getHoverColour(button.background)
901                        ];
902
903                    if (highlight) {
904                        //assumes highlight.background is set
905                        highlight.text = highlight.text ? highlight.text : util.getContrast(highlight.background);
906                        highlight.border = highlight.border ? highlight.border : 'transparent';
907                        colorStyles[prefix + ' .cc-highlight .cc-btn:first-child'] = [
908                            'color: ' + highlight.text,
909                            'border-color: ' + highlight.border,
910                            'background-color: ' + highlight.background
911                        ];
912                    }
913                }
914                if (deny) {
915                    // assumes button.background is set
916                    deny.text = deny.text ? deny.text : util.getContrast(deny.background);
917                    deny.border = deny.border ? deny.border : 'transparent';
918                    colorStyles[prefix + ' .cc-deny'] = [
919                        'color: ' + deny.text,
920                        'border-color: ' + deny.border,
921                        'background-color: ' + deny.background
922                    ];
923
924                    if (deny.background != 'transparent')
925                        colorStyles[prefix + ' .cc-deny:hover, ' + prefix + ' .cc-deny:focus'] = [
926                            'background-color: ' + getHoverColour(deny.background)
927                        ];
928
929                    if (highlight) {
930                        //assumes highlight.background is set
931                        highlight.text = highlight.text ? highlight.text : util.getContrast(highlight.background);
932                        highlight.border = highlight.border ? highlight.border : 'transparent';
933                        colorStyles[prefix + ' .cc-highlight .cc-btn:first-child'] = [
934                            'color: ' + highlight.text,
935                            'border-color: ' + highlight.border,
936                            'background-color: ' + highlight.background
937                        ];
938                    }
939                }
940
941            }
942
943            // this will be interpretted as CSS. the key is the selector, and each array element is a rule
944            var style = document.createElement('style');
945            document.head.appendChild(style);
946
947            // custom style doesn't exist, so we create it
948            cc.customStyles[hash] = {
949                references: 1,
950                element: style.sheet
951            };
952
953            var ruleIndex = -1;
954            for (var prop in colorStyles) {
955                if (colorStyles.hasOwnProperty(prop)) {
956                    style.sheet.insertRule(prop + '{' + colorStyles[prop].join(';') + '}', ++ruleIndex);
957                }
958            }
959        }
960
961        function getHoverColour(hex) {
962            hex = util.normaliseHex(hex);
963            // for black buttons
964            if (hex == '000000') {
965                return '#222';
966            }
967            return util.getLuminance(hex);
968        }
969
970        function removeCustomStyle(palette) {
971            if (util.isPlainObject(palette)) {
972                var hash = util.hash(JSON.stringify(palette));
973                var customStyle = cc.customStyles[hash];
974                if (customStyle && !--customStyle.references) {
975                    var styleNode = customStyle.element.ownerNode;
976                    if (styleNode && styleNode.parentNode) {
977                        styleNode.parentNode.removeChild(styleNode);
978                    }
979                    cc.customStyles[hash] = null;
980                }
981            }
982        }
983
984        function arrayContainsMatches(array, search) {
985            for (var i = 0, l = array.length; i < l; ++i) {
986                var str = array[i];
987                // if regex matches or string is equal, return true
988                if ((str instanceof RegExp && str.test(search)) ||
989                    (typeof str == 'string' && str.length && str === search)) {
990                    return true;
991                }
992            }
993            return false;
994        }
995
996        function applyAutoDismiss() {
997            var setStatus = this.setStatus.bind(this);
998
999            var delay = this.options.dismissOnTimeout;
1000            if (typeof delay == 'number' && delay >= 0) {
1001                this.dismissTimeout = window.setTimeout(function () {
1002                    setStatus(cc.status.dismiss);
1003                }, Math.floor(delay));
1004            }
1005
1006            var scrollRange = this.options.dismissOnScroll;
1007            if (typeof scrollRange == 'number' && scrollRange >= 0) {
1008                var onWindowScroll = function (evt) {
1009                    if (window.pageYOffset > Math.floor(scrollRange)) {
1010                        setStatus(cc.status.dismiss);
1011
1012                        window.removeEventListener('scroll', onWindowScroll);
1013                        this.onWindowScroll = null;
1014                    }
1015                };
1016
1017                this.onWindowScroll = onWindowScroll;
1018                window.addEventListener('scroll', onWindowScroll);
1019            }
1020        }
1021
1022        function applyRevokeButton() {
1023            // revokable is true if advanced compliance is selected
1024            if (this.options.type != 'info') this.options.revokable = true;
1025            // animateRevokable false for mobile devices
1026            if (util.isMobile()) this.options.animateRevokable = false;
1027
1028            if (this.options.revokable) {
1029                var classes = getPositionClasses.call(this);
1030                if (this.options.animateRevokable) {
1031                    classes.push('cc-animate');
1032                }
1033                if (this.customStyleSelector) {
1034                    classes.push(this.customStyleSelector)
1035                }
1036                var revokeBtn = this.options.revokeBtn.replace('{{classes}}', classes.join(' '));
1037                this.revokeBtn = appendMarkup.call(this, revokeBtn);
1038
1039                var btn = this.revokeBtn;
1040                if (this.options.animateRevokable) {
1041                    var wait = false;
1042                    var onMouseMove = util.throttle(function (evt) {
1043                        var active = false;
1044                        var minY = 20;
1045                        var maxY = (window.innerHeight - 20);
1046
1047                        if (util.hasClass(btn, 'cc-top') && evt.clientY < minY) active = true;
1048                        if (util.hasClass(btn, 'cc-bottom') && evt.clientY > maxY) active = true;
1049
1050                        if (active) {
1051                            if (!util.hasClass(btn, 'cc-active')) {
1052                                util.addClass(btn, 'cc-active');
1053                            }
1054                        } else {
1055                            if (util.hasClass(btn, 'cc-active')) {
1056                                util.removeClass(btn, 'cc-active');
1057                            }
1058                        }
1059                    }, 200);
1060
1061                    this.onMouseMove = onMouseMove;
1062                    window.addEventListener('mousemove', onMouseMove);
1063                }
1064            }
1065        }
1066
1067        return CookiePopup
1068    }());
1069
1070    cc.Location = (function () {
1071
1072        // An object containing all the location services we have already set up.
1073        // When using a service, it could either return a data structure in plain text (like a JSON object) or an executable script
1074        // When the response needs to be executed by the browser, then `isScript` must be set to true, otherwise it won't work.
1075
1076        // When the service uses a script, the chances are that you'll have to use the script to make additional requests. In these
1077        // cases, the services `callback` property is called with a `done` function. When performing async operations, this must be called
1078        // with the data (or Error), and `cookieconsent.locate` will take care of the rest
1079        var defaultOptions = {
1080
1081            // The default timeout is 5 seconds. This is mainly needed to catch JSONP requests that error.
1082            // Otherwise there is no easy way to catch JSONP errors. That means that if a JSONP fails, the
1083            // app will take `timeout` milliseconds to react to a JSONP network error.
1084            timeout: 5000,
1085
1086            // the order that services will be attempted in
1087            services: [
1088                'freegeoip',
1089                'ipinfo',
1090                'maxmind'
1091
1092                /*
1093
1094                // 'ipinfodb' requires some options, so we define it using an object
1095                // this object will be passed to the function that defines the service
1096
1097                {
1098                  name: 'ipinfodb',
1099                  interpolateUrl: {
1100                    // obviously, this is a fake key
1101                    api_key: 'vOgI3748dnIytIrsJcxS7qsDf6kbJkE9lN4yEDrXAqXcKUNvjjZPox3ekXqmMMld'
1102                  },
1103                },
1104
1105                // as well as defining an object, you can define a function that returns an object
1106
1107                function () {
1108                  return {name: 'ipinfodb'};
1109                },
1110
1111                */
1112            ],
1113
1114            serviceDefinitions: {
1115
1116                freegeoip: function () {
1117                    return {
1118                        // This service responds with JSON, but they do not have 
1118CORS set, so we must use JSONP and provide a callback
1119                        // The `{callback}` is automatically rewritten by the tool
1120                        url: '//freegeoip.net/json/?callback={callback}',
1121                        isScript: true, // this is JSONP, therefore we must set it to run as a script
1122                        callback: function (done, response) {
1123                            try {
1124                                var json = JSON.parse(response);
1125                                return json.error ? toError(json) : {
1126                                    code: json.country_code
1127                                };
1128                            } catch (err) {
1129                                return toError({error: 'Invalid response (' + err + ')'});
1130                            }
1131                        }
1132                    }
1133                },
1134
1135                ipinfo: function () {
1136                    return {
1137                        // This service responds with JSON, so we simply need to parse it and return the country code
1138                        url: '//ipinfo.io',
1139                        headers: ['Accept: application/json'],
1140                        callback: function (done, response) {
1141                            try {
1142                                var json = JSON.parse(response);
1143                                return json.error ? toError(json) : {
1144                                    code: json.country
1145                                };
1146                            } catch (err) {
1147                                return toError({error: 'Invalid response (' + err + ')'});
1148                            }
1149                        }
1150                    }
1151                },
1152
1153                // This service requires an option to define `key`. Options are proived using objects or functions
1154                ipinfodb: function (options) {
1155                    return {
1156                        // This service responds with JSON, so we simply need to parse it and return the country code
1157                        url: '//api.ipinfodb.com/v3/ip-country/?key={api_key}&format=json&callback={callback}',
1158                        isScript: true, // this is JSONP, therefore we must set it to run as a script
1159                        callback: function (done, response) {
1160                            try {
1161                                var json = JSON.parse(response);
1162                                return json.statusCode == 'ERROR' ? toError({error: json.statusMessage}) : {
1163                                    code: json.countryCode
1164                                };
1165                            } catch (err) {
1166                                return toError({error: 'Invalid response (' + err + ')'});
1167                            }
1168                        }
1169                    }
1170                },
1171
1172                maxmind: function () {
1173                    return {
1174                        // This service responds with a JavaScript file which defines additional functionality. Once loaded, we must
1175                        // make an additional AJAX call. Therefore we provide a `done` callback that can be called asynchronously
1176                        url: '//js.maxmind.com/js/apis/geoip2/v2.1/geoip2.js',
1177                        isScript: true, // this service responds with a JavaScript file, so it must be run as a script
1178                        callback: function (done) {
1179                            // if everything went okay then `geoip2` WILL be defined
1180                            if (!window.geoip2) {
1181                                done(new Error('Unexpected response format. The downloaded script should have exported `geoip2` to the global scope'));
1182                                return;
1183                            }
1184
1185                            geoip2.country(function (location) {
1186                                try {
1187                                    done({
1188                                        code: location.country.iso_code
1189                                    });
1190                                } catch (err) {
1191                                    done(toError(err));
1192                                }
1193                            }, function (err) {
1194                                done(toError(err));
1195                            });
1196
1197                            // We can't return anything, because we need to wait for the second AJAX call to return.
1198                            // Then we can 'complete' the service by passing data or an error to the `done` callback.
1199                        }
1200                    }
1201                },
1202            },
1203        };
1204
1205        function Location(options) {
1206            // Set up options
1207            util.deepExtend(this.options = {}, defaultOptions);
1208
1209            if (util.isPlainObject(options)) {
1210                util.deepExtend(this.options, options);
1211            }
1212
1213            this.currentServiceIndex = -1; // the index (in options) of the service we're currently using
1214        }
1215
1216        Location.prototype.getNextService = function () {
1217            var service;
1218
1219            do {
1220                service = this.getServiceByIdx(++this.currentServiceIndex);
1221            } while (this.currentServiceIndex < this.options.services.length && !service);
1222
1223            return service;
1224        };
1225
1226        Location.prototype.getServiceByIdx = function (idx) {
1227            // This can either be the name of a default locationService, or a function.
1228            var serviceOption = this.options.services[idx];
1229
1230            // If it's a string, use one of the location services.
1231            if (typeof serviceOption === 'function') {
1232                var dynamicOpts = serviceOption();
1233                if (dynamicOpts.name) {
1234                    util.deepExtend(dynamicOpts, this.options.serviceDefinitions[dynamicOpts.name](dynamicOpts));
1235                }
1236                return dynamicOpts;
1237            }
1238
1239            // If it's a string, use one of the location services.
1240            if (typeof serviceOption === 'string') {
1241                return this.options.serviceDefinitions[serviceOption]();
1242            }
1243
1244            // If it's an object, assume {name: 'ipinfo', ...otherOptions}
1245            // Allows user to pass in API keys etc.
1246            if (util.isPlainObject(serviceOption)) {
1247                return this.options.serviceDefinitions[serviceOption.name](serviceOption);
1248            }
1249
1250            return null;
1251        };
1252
1253        // This runs the service located at index `currentServiceIndex`.
1254        // If the service fails, `runNextServiceOnError` will continue trying each service until all fail, or one completes successfully
1255        Location.prototype.locate = function (complete, error) {
1256            var service = this.getNextService();
1257
1258            if (!service) {
1259                error(new Error('No services to run'));
1260                return;
1261            }
1262
1263            this.callbackComplete = complete;
1264            this.callbackError = error;
1265
1266            this.runService(service, this.runNextServiceOnError.bind(this));
1267        };
1268
1269        // Potentially adds a callback to a url for jsonp.
1270        Location.prototype.setupUrl = function (service) {
1271            var serviceOpts = this.getCurrentServiceOpts();
1272            return service.url.replace(/\{(.*?)\}/g, function (_, param) {
1273                if (param === 'callback') {
1274                    var tempName = 'callback' + Date.now();
1275                    window[tempName] = function (res) {
1276                        service.__JSONP_DATA = JSON.stringify(res);
1277                    }
1278                    return tempName;
1279                }
1280                if (param in serviceOpts.interpolateUrl) {
1281                    return serviceOpts.interpolateUrl[param];
1282                }
1283            });
1284        };
1285
1286        // requires a `service` object that defines at least a `url` and `callback`
1287        Location.prototype.runService = function (service, complete) {
1288            var self = this;
1289
1290            // basic check to ensure it resembles a `service`
1291            if (!service || !service.url || !service.callback) {
1292                return;
1293            }
1294
1295            // we call either `getScript` or `makeAsyncRequest` depending on the type of resource
1296            var requestFunction = service.isScript ? getScript : makeAsyncRequest;
1297
1298            var url = this.setupUrl(service);
1299
1300            // both functions have similar signatures so we can pass the same arguments to both
1301            requestFunction(url, function (xhr) {
1302                // if `!xhr`, then `getScript` function was used, so there is no response text
1303                var responseText = xhr ? xhr.responseText : '';
1304
1305                // if the resource is a script, then this function is called after the script has been run.
1306                // if the script is JSONP, then a time defined function `callback_{Date.now}` has already
1307                // been called (as the JSONP callback). This callback sets the __JSONP_DATA property
1308                if (service.__JSONP_DATA) {
1309                    responseText = service.__JSONP_DATA;
1310                    delete service.__JSONP_DATA;
1311                }
1312
1313                // call the service callback with the response text (so it can parse the response)
1314                self.runServiceCallback.call(self, complete, service, responseText);
1315
1316            }, this.options.timeout, service.data, service.headers);
1317
1318            // `service.data` and `service.headers` are optional (they only count if `!service.isScript` anyway)
1319        };
1320
1321        // The service request has run (and possibly has a `responseText`) [no `responseText` if `isScript`]
1322        // We need to run its callback which determines if its successful or not
1323        // `complete` is called on success or failure
1324        Location.prototype.runServiceCallback = function (complete, service, responseText) {
1325            var self = this;
1326            // this is the function that is called if the service uses the async callback in its handler method
1327            var serviceResultHandler = function (asyncResult) {
1328                // if `result` is a valid value, then this function shouldn't really run
1329                // even if it is called by `service.callback`
1330                if (!result) {
1331                    self.onServiceResult.call(self, complete, asyncResult)
1332                }
1333            };
1334
1335            // the function `service.callback` will either extract a country code from `responseText` and return it (in `result`)
1336            // or (if it has to make additional requests) it will call a `done` callback with the country code when it is ready
1337            var result = service.callback(serviceResultHandler, responseText);
1338
1339            if (result) {
1340                this.onServiceResult.call(this, complete, result);
1341            }
1342        };
1343
1344        // This is called with the `result` from `service.callback` regardless of how it provided that result (sync or async).
1345        // `result` will be whatever is returned from `service.callback`. A service callback should provide an object with data
1346        Location.prototype.onServiceResult = function (complete, result) {
1347            // convert result to nodejs style async callback
1348            if (result instanceof Error || (result && result.error)) {
1349                complete.call(this, result, null);
1350            } else {
1351                complete.call(this, null, result);
1352            }
1353        };
1354
1355        // if `err` is set, the next service handler is called
1356        // if `err` is null, the `onComplete` handler is called with `data`
1357        Location.prototype.runNextServiceOnError = function (err, data) {
1358            if (err) {
1359                this.logError(err);
1360
1361                var nextService = this.getNextService();
1362
1363                if (nextService) {
1364                    this.runService(nextService, this.runNextServiceOnError.bind(this));
1365                } else {
1366                    this.completeService.call(this, this.callbackError, new Error('All services failed'));
1367                }
1368            } else {
1369                this.completeService.call(this, this.callbackComplete, data);
1370            }
1371        };
1372
1373        Location.prototype.getCurrentServiceOpts = function () {
1374            var val = this.options.services[this.currentServiceIndex];
1375
1376            if (typeof val == 'string') {
1377                return {name: val};
1378            }
1379
1380            if (typeof val == 'function') {
1381                return val();
1382            }
1383
1384            if (util.isPlainObject(val)) {
1385                return val;
1386            }
1387
1388            return {};
1389        };
1390
1391        // calls the `onComplete` callback after resetting the `currentServiceIndex`
1392        Location.prototype.completeService = function (fn, data) {
1393            this.currentServiceIndex = -1;
1394
1395            fn && fn(data);
1396        };
1397
1398        Location.prototype.logError = function (err) {
1399            var idx = this.currentServiceIndex;
1400            var service = this.getServiceByIdx(idx);
1401
1402            console.error('The service[' + idx + '] (' + service.url + ') responded with the following error', err);
1403        };
1404
1405        function getScript(url, callback, timeout) {
1406            var timeoutIdx, s = document.createElement('script');
1407
1408            s.type = 'text/' + (url.type || 'javascript');
1409            s.src = url.src || url;
1410            s.async = false;
1411
1412            s.onreadystatechange = s.onload = function () {
1413                // this code handles two scenarios, whether called by onload or onreadystatechange
1414                var state = s.readyState;
1415
1416                clearTimeout(timeoutIdx);
1417
1418                if (!callback.done && (!state || /loaded|complete/.test(state))) {
1419                    callback.done = true;
1420                    callback();
1421                    s.onreadystatechange = s.onload = null;
1422                }
1423            };
1424
1425            document.body.appendChild(s);
1426
1427            // You can't catch JSONP Errors, because it's handled by the script tag
1428            // one way is to use a timeout
1429            timeoutIdx = setTimeout(function () {
1430                callback.done = true;
1431                callback();
1432                s.onreadystatechange = s.onload = null;
1433            }, timeout);
1434        }
1435
1436        function makeAsyncRequest(url, onComplete, timeout, postData, requestHeaders) {
1437            var xhr = new (window.XMLHttpRequest || window.ActiveXObject)('MSXML2.XMLHTTP.3.0');
1438
1439            xhr.open(postData ? 'POST' : 'GET', url, 1);
1440
1441            xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
1442            xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
1443
1444            if (Array.isArray(requestHeaders)) {
1445                for (var i = 0, l = requestHeaders.length; i < l; ++i) {
1446                    var split = requestHeaders[i].split(':', 2)
1447                    xhr.setRequestHeader(split[0].replace(/^\s+|\s+$/g, ''), split[1].replace(/^\s+|\s+$/g, ''));
1448                }
1449            }
1450
1451            if (typeof onComplete == 'function') {
1452                xhr.onreadystatechange = function () {
1453                    if (xhr.readyState > 3) {
1454                        onComplete(xhr);
1455                    }
1456                };
1457            }
1458
1459            xhr.send(postData);
1460        }
1461
1462        function toError(obj) {
1463            return new Error('Error [' + (obj.code || 'UNKNOWN') + ']: ' + obj.error);
1464        }
1465
1466        return Location;
1467    }());
1468
1469    cc.Law = (function () {
1470
1471        var defaultOptions = {
1472            // Make this false if you want to disable all regional overrides for settings.
1473            // If true, options can differ by country, depending on their cookie law.
1474            // It does not affect hiding the popup for countries that do not have cookie law.
1475            regionalLaw: true,
1476
1477            // countries that enforce some version of a cookie law
1478            hasLaw: ['AT', 'BE', 'BG', 'HR', 'CZ', 'CY', 'DK', 'EE', 'FI', 'FR', 'DE', 'EL', 'HU', 'IE', 'IT', 'LV', 'LT', 'LU', 'MT', 'NL', 'PL', 'PT', 'SK', '
1478SI', 'ES', 'SE', 'GB', 'UK'],
1479
1480            // countries that say that all cookie consent choices must be revokable (a user must be able too change their mind)
1481            revokable: ['HR', 'CY', 'DK', 'EE', 'FR', 'DE', 'LV', 'LT', 'NL', 'PT', 'ES'],
1482
1483            // countries that say that a person can only "consent" if the explicitly click on "I agree".
1484            // in these countries, consent cannot be implied via a timeout or by scrolling down the page
1485            explicitAction: ['HR', 'IT', 'ES'],
1486        };
1487
1488        function Law(options) {
1489            this.initialise.apply(this, arguments);
1490        }
1491
1492        Law.prototype.initialise = function (options) {
1493            // set options back to default options
1494            util.deepExtend(this.options = {}, defaultOptions);
1495
1496            // merge in user options
1497            if (util.isPlainObject(options)) {
1498                util.deepExtend(this.options, options);
1499            }
1500        };
1501
1502        Law.prototype.get = function (countryCode) {
1503            var opts = this.options;
1504            return {
1505                hasLaw: opts.hasLaw.indexOf(countryCode) >= 0,
1506                revokable: opts.revokable.indexOf(countryCode) >= 0,
1507                explicitAction: opts.explicitAction.indexOf(countryCode) >= 0,
1508            };
1509        };
1510
1511        Law.prototype.applyLaw = function (options, countryCode) {
1512            var country = this.get(countryCode);
1513
1514            if (!country.hasLaw) {
1515                // The country has no cookie law
1516                options.enabled = false;
1517            }
1518
1519            if (this.options.regionalLaw) {
1520                if (country.revokable) {
1521                    // We must provide an option to revoke consent at a later time
1522                    options.revokable = true;
1523                }
1524
1525                if (country.explicitAction) {
1526                    // The user must explicitly click the consent button
1527                    options.dismissOnScroll = false;
1528                    options.dismissOnTimeout = false;
1529                }
1530            }
1531            return options;
1532        };
1533
1534        return Law;
1535    }());
1536
1537    // This function initialises the app by combining the use of the Popup, Locator and Law modules
1538    // You can string together these three modules yourself however you want, by writing a new function.
1539    cc.initialise = function (options, complete, error) {
1540
1541
1542        var law = new cc.Law(options.law);
1543
1544        if (!complete) complete = function () {
1545        };
1546        if (!error) error = function () {
1547        };
1548
1549        cc.getCountryCode(options, function (result) {
1550            // don't need the law or location options anymore
1551            delete options.law;
1552            delete options.location;
1553
1554            if (result.code) {
1555                options = law.applyLaw(options, result.code);
1556            }
1557
1558            complete(new cc.Popup(options));
1559        }, function (err) {
1560            // don't need the law or location options anymore
1561            delete options.law;
1562            delete options.location;
1563
1564            error(err, new cc.Popup(options));
1565        });
1566    };
1567
1568    // This function tries to find your current location. It either grabs it from a hardcoded option in
1569    // `options.law.countryCode`, or attempts to make a location service request. This function accepts
1570    // options (which can configure the `law` and `location` modules) and fires a callback with which
1571    // passes an object `{code: countryCode}` as the first argument (which can have undefined properties)
1572    cc.getCountryCode = function (options, complete, error) {
1573        if (options.law && options.law.countryCode) {
1574            complete({
1575                code: options.law.countryCode
1576            });
1577            return;
1578        }
1579        if (options.location) {
1580            var locator = new cc.Location(options.location);
1581            locator.locate(function (serviceResult) {
1582                complete(serviceResult || {});
1583            }, error);
1584            return;
1585        }
1586        complete({});
1587    };
1588
1589    // export utils (no point in hiding them, so we may as well expose them)
1590    cc.utils = util;
1591
1592    // prevent this code from being run twice
1593    cc.hasInitialised = true;
1594
1595    window.cookieconsent = cc;
1596
1597}(window.cookieconsent || {}));
1598window.addEventListener("load", function() {
1599    var consentType = cookieConsentType;
1600    var position = cookieConsentPosition;
1601    var static = false;
1602    var revokable = (cookieConsentOptOut == 1);
1603    var layout = (consentType == "info") ? "basic-slideout" : "basic";
1604    window.cookieconsent.initialise({
1605        "palette": {
1606            "popup": {
1607                "background": cookieConsentPopupBackgroundColor,
1608                "text": cookieConsentPopupTextColor
1609            },
1610            "button": {
1611                "background": cookieConsentButtonBackgroundColor,
1612                "text": cookieConsentButtonTextColor
1613            },
1614            "deny": {
1615                "background": cookieConsentDisagreeButtonBackgroundColor,
1616                "text": cookieConsentDisagreeButtonTextColor
1617            }
1618        },
1619        "type": consentType,
1620        "layout": layout,
1621        "theme": "edgeless",
1622        "position": position,
1623        "static": static,
1624        "revokable": revokable,
1625        "content": {
1626            "message": cookieConsentMessage,
1627            "dismiss": cookieConsentConfirm,
1628            "deny": cookieConsentDeny,
1629            "allow": cookieConsentConfirm,
1630            "link": cookieConsentLinkText,
1631            "href": cookieConsentUrl,
1632            "optout_text":  cookieConsentOptOutText,
1633            "checkbox_text":  cookieConsentCheckboxText,
1634            "dnt_text":  cookieConsentDoNotTrackSetText
1635        },
1636        "slideout": "<div class='optOut-slideout'><input type='checkbox' name='cc-checkbox' id='cc-checkbox' /><label for='cc-checkbox'>{{checkbox_text}}</label></div>'"
1637
1638    });
1639    var cclink = (document.getElementsByClassName("cc-link")) ? document.getElementsByClassName("cc-link") : [];
1640
1641    for (var i = 0; i < cclink.length; i++) {
1642        cclink[i].style.color = cookieConsentPopupTextColor;
1643    }
1644
1645});
1646
1647var cookieConsentUrl = "/datenschutz/";
1648            var cookieConsentMessage = "Wir würden gerne Cookies verwenden, um die Präferenzen unserer Nutzer zu erkennen und diese Website optimal gestalten zu können. Detaillierte Informationen und wie Sie Ihre Einwilligung jederzeit widerrufen können, erhalten Sie in unserer";
1649            var cookieConsentButtonTextColor = '#213a8f';
1650            var cookieConsentButtonBackgroundColor = '#fff';
1651            var cookieConsentPopupTextColor = '#ffffff';
1652            var cookieConsentPopupBackgroundColor = '#2598d5';
1653            var cookieConsentLinkText = "Datenschutzerklärung";
1654            var cookieConsentConfirm = "Akzeptieren";
1655            var cookieConsentDeny = "Ablehnen";
1656            var cookieConsentOptOut = 1;
1657            var cookieConsentPosition = 'bottom';
1658            var cookieConsentOptOutText = "Von anonymer Nutzeranalyse abmelden";
1659            var cookieConsentCheckboxText = "Tracking unterbinden";
1660            var cookieConsentDoNotTrackSetText = "Do not Track ist in Ihrem Browser aktiviert";
1661            var cookieConsentType = 'opt-out';
1662            var cookieConsentDisagreeButtonTextColor = '#003C8D';
1663            var cookieConsentDisagreeButtonBackgroundColor = '#fff';
1664cookieConsentMessage = "<div class=\"Header\">Einsatz von Cookies</div><div class=\"Message\">Wir würden gerne Cookies verwenden, um die Präferenzen unserer Nutzer zu erkennen und diese Website optimal gestalten zu können. Detaillierte Informationen und wie Sie Ihre Einwilligung jederzeit widerrufen können, erhalten Sie in unserer</div>";

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.