PageSourceSearch

https://www.treyarch.com/apps/atvi/global/clientlibs.3908e9bde27c6472d5a31a4c4fc89f54.js

js treyarch.com collected 2026-09-24 20:44:06 UTC 160,961 bytes, 4,260 lines download raw bytes

1/*
2 * ADOBE CONFIDENTIAL
3 *
4 * Copyright 2012 Adobe Systems Incorporated
5 * All Rights Reserved.
6 *
7 * NOTICE:  All information contained herein is, and remains
8 * the property of Adobe Systems Incorporated and its suppliers,
9 * if any.  The intellectual and technical concepts contained
10 * herein are proprietary to Adobe Systems Incorporated and its
11 * suppliers and may be covered by U.S. and Foreign Patents,
12 * patents in process, and are protected by trade secret or copyright law.
13 * Dissemination of this information or reproduction of this material
14 * is strictly forbidden unless prior written permission is obtained
15 * from Adobe Systems Incorporated.
16 *
17 */
18(function(factory) {
19    "use strict";
20
21    if (typeof module === "object" && module.exports) {
22        module.exports = factory();
23    } else {
24        var g = window.Granite = window.Granite || {};
25        g.Sling = factory();
26    }
27}(function() {
28    "use strict";
29
30    /**
31     * A helper class providing a set of Sling-related utilities.
32     * @static
33     * @singleton
34     * @class Granite.Sling
35     * @deprecated Using the constants is no longer needed and actually is not a best practice as it is not RESTful,
36     *             where the server should drive the client via hypermedia and the client should not make any
37     *             assumption about the URL.
38     */
39    return {
40        /**
41         * The selector for infinite hierarchy depth when retrieving repository content.
42         * @static
43         * @final
44         * @type String
45         */
46        SELECTOR_INFINITY: ".infinity",
47
48        /**
49         * The parameter name for the used character set.
50         * @static
51         * @final
52         * @type String
53         */
54        CHARSET: "_charset_",
55
56        /**
57         * The parameter name for the status.
58         * @static
59         * @final
60         * @type String
61         */
62        STATUS: ":status",
63
64        /**
65         * The parameter value for the status type "browser".
66         * @static
67         * @final
68         * @type String
69         */
70        STATUS_BROWSER: "browser",
71
72        /**
73         * The parameter name for the operation.
74         * @static
75         * @final
76         * @type String
77         */
78        OPERATION: ":operation",
79
80        /**
81         * The parameter value for the delete operation.
82         * @static
83         * @final
84         * @type String
85         */
86        OPERATION_DELETE: "delete",
87
88        /**
89         * The parameter value for the move operation.
90         * @static
91         * @final
92         * @type String
93         */
94        OPERATION_MOVE: "move",
95
96        /**
97         * The parameter name suffix for deleting.
98         * @static
99         * @final
100         * @type String
101         */
102        DELETE_SUFFIX: "@Delete",
103
104        /**
105         * The parameter name suffix for setting a type hint.
106         * @static
107         * @final
108         * @type String
109         */
110        TYPEHINT_SUFFIX: "@TypeHint",
111
112        /**
113         * The parameter name suffix for copying.
114         * @static
115         * @final
116         * @type String
117         */
118        COPY_SUFFIX: "@CopyFrom",
119
120        /**
121         * The parameter name suffix for moving.
122         * @static
123         * @final
124         * @type String
125         */
126        MOVE_SUFFIX: "@MoveFrom",
127
128        /**
129         * The parameter name for the ordering.
130         * @static
131         * @final
132         * @type String
133         */
134        ORDER: ":order",
135
136        /**
137         * The parameter name for the replace flag.
138         * @static
139         * @final
140         * @type String
141         */
142        REPLACE: ":replace",
143
144        /**
145         * The parameter name for the destination flag.
146         * @static
147         * @final
148         * @type String
149         */
150        DESTINATION: ":dest",
151
152        /**
153         * The parameter name for the save parameter prefix.
154         * @static
155         * @final
156         * @type String
157         */
158        SAVE_PARAM_PREFIX: ":saveParamPrefix",
159
160        /**
161         * The parameter name for input fields that should be ignored by Sling.
162         * @static
163         * @final
164         * @type String
165         */
166        IGNORE_PARAM: ":ignore",
167
168        /**
169         * The parameter name for login requests.
170         * @static
171         * @final
172         * @type String
173         */
174        REQUEST_LOGIN_PARAM: "sling:authRequestLogin",
175
176        /**
177         * The login URL.
178         * @static
179         * @final
180         * @type String
181         */
182        LOGIN_URL: "/system/sling/login.html",
183
184        /**
185         * The logout URL.
186         * @static
187         * @final
188         * @type String
189         */
190        LOGOUT_URL: "/system/sling/logout.html"
191    };
192}));
193
194/*
195 * ADOBE CONFIDENTIAL
196 *
197 * Copyright 2012 Adobe Systems Incorporated
198 * All Rights Reserved.
199 *
200 * NOTICE:  All information contained herein is, and remains
201 * the property of Adobe Systems Incorporated and its suppliers,
202 * if any.  The intellectual and technical concepts contained
203 * herein are proprietary to Adobe Systems Incorporated and its
204 * suppliers and may be covered by U.S. and Foreign Patents,
205 * patents in process, and are protected by trade secret or copyright law.
206 * Dissemination of this information or reproduction of this material
207 * is strictly forbidden unless prior written permission is obtained
208 * from Adobe Systems Incorporated.
209 *
210 */
211(function(factory) {
212    "use strict";
213
214    if (typeof module === "object" && module.exports) {
215        module.exports = factory();
216    } else {
217        var g = window.Granite = window.Granite || {};
218        g.Util = factory();
219    }
220}(function() {
221    "use strict";
222
223    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray#Polyfill
224    var isArray = function(arg) {
225        return Object.prototype.toString.call(arg) === "[object Array]";
226    };
227
228    /**
229     * A helper class providing a set of general utilities.
230     * @static
231     * @singleton
232     * @class Granite.Util
233     */
234    return {
235        /**
236         * Replaces occurrences of <code>{n}</code> in the specified text with the texts from the snippets.
237         *
238         * @example
239         * var text = Granite.Util.patchText("{0} has signed in.", "Jack");
240         * // text = "Jack has signed in."
241         * var text2 = Granite.Util.patchText("{0} {1} has signed in from {2}.", ["Jack", "McFarland", "x.x.x.x"]);
242         * // text2 = "Jack McFarland has signed in from x.x.x.x."
243         *
244         * @param {String} text The text.
245         * @param {String|String[]} snippets The text(s) replacing <code>{n}</code>.
246         * @returns {String} The patched text.
247         */
248        patchText: function(text, snippets) {
249            if (snippets) {
250                if (!isArray(snippets)) {
251                    text = text.replace("{0}", snippets);
252                } else {
253                    for (var i = 0; i < snippets.length; i++) {
254                        text = text.replace(("{" + i + "}"), snippets[i]);
255                    }
256                }
257            }
258            return text;
259        },
260
261        /**
262         * Returns the top most accessible window.
263         * Check {@link .setIFrameMode} to avoid security exception message on WebKit browsers
264         * if this method is called in an iFrame included in a window from different domain.
265         *
266         * @returns {Window} The top window.
267         */
268        getTopWindow: function() {
269            var win = window;
270            if (this.iFrameTopWindow) {
271                return this.iFrameTopWindow;
272            }
273            try {
274                // try to access parent
275                // win.parent.location.href throws an exception if not authorized (e.g. different location in a portlet)
276                while (win.parent && win !== win.parent && win.parent.location.href) {
277                    win = win.parent;
278                }
279            } catch (error) {
280                // ignored
281            }
282            return win;
283        },
284
285        /**
286         * Allows to define if Granite.Util is running in an iFrame and parent window is in another domain
287         * (and optionally define what would be the top window in that case.
288         * This is necessary to use {@link .getTopWindow} in a iFrame on WebKit based browsers because
289         * {@link .getTopWindow} iterates on parent windows to find the top one which triggers a security exception
290         * if one parent window is in a different domain. Exception cannot be caught but is not breaking the JS
291         * execution.
292         *
293         * @param {Window} [topWindow=window] The iFrame top window. Must be running on the same host to avoid
294         * security exception.
295         */
296        setIFrameMode: function(topWindow) {
297            this.iFrameTopWindow = topWindow || window;
298        },
299
300        /**
301         * Applies default properties if non-existent into the base object.
302         * Child objects are merged recursively.
303         * REMARK:
304         *   - objects are recursively merged
305         *   - simple type object properties are copied over the base
306         *   - arrays are cloned and override the base (no value merging)
307         *
308         * @param {Object} base The object.
309         * @param {...Object} pass The objects to be copied onto the base.
310         * @returns {Object} The base object with defaults.
311         */
312        applyDefaults: function() {
313            var override;
314            var base = arguments[0] || {};
315
316            for (var i = 1; i < arguments.length; i++) {
317                override = arguments[i];
318
319                for (var name in override) {
320                    var value = override[name];
321
322                    if (override.hasOwnProperty(name) && value !== undefined) {
323                        if (value !== null && typeof value === "object" && !(value instanceof Array)) {
324                            // nested object
325                            base[name] = this.applyDefaults(base[name], value);
326                        } else if (value instanceof Array) {
327                            // override array
328                            base[name] = value.slice(0);
329                        } else {
330                            // simple type
331                            base[name] = value;
332                        }
333                    }
334                }
335            }
336
337            return base;
338        },
339
340        /**
341         * Returns the keycode from the given event.
342         * It is a normalized value over variation of browsers' inconsistencies.
343         *
344         * @param {UIEvent} event The event.
345         * @returns {Number} The keycode.
346         */
347        getKeyCode: function(event) {
348            return event.keyCode ? event.keyCode : event.which;
349        }
350    };
351}));
352
353/*
354 * ADOBE CONFIDENTIAL
355 *
356 * Copyright 2012 Adobe Systems Incorporated
357 * All Rights Reserved.
358 *
359 * NOTICE:  All information contained herein is, and remains
360 * the property of Adobe Systems Incorporated and its suppliers,
361 * if any.  The intellectual and technical concepts contained
362 * herein are proprietary to Adobe Systems Incorporated and its
363 * suppliers and may be covered by U.S. and Foreign Patents,
364 * patents in process, and are protected by trade secret or copyright law.
365 * Dissemination of this information or reproduction of this material
366 * is strictly forbidden unless prior written permission is obtained
367 * from Adobe Systems Incorporated.
368 *
369 */
370/* global CQURLInfo:false, G_XHR_HOOK:false */
371/* eslint strict: 0 */
372(function(factory) {
373    "use strict";
374
375    if (typeof module === "object" && module.exports) {
376        module.exports = factory(require("@granite/util"), require("jquery"));
377    } else {
378        window.Granite.HTTP = factory(Granite.Util, jQuery);
379    }
380}(function(util, $) {
381    /**
382     * A helper class providing a set of HTTP-related utilities.
383     * @static
384     * @singleton
385     * @class Granite.HTTP
386     */
387    return (function() {
388        /**
389         * The context path used on the server.
390         * May only be set by {@link #detectContextPath}.
391         * @type String
392         */
393        var contextPath = null;
394
395        /**
396         * The regular expression to detect the context path used
397         * on the server using the URL of this script.
398         * @readonly
399         * @type RegExp
400         */
401        // eslint-disable-next-line max-len
402        var SCRIPT_URL_REGEXP = /^(?:http|https):\/\/[^/]+(\/.*)\/(?:etc\.clientlibs|etc(\/.*)*\/clientlibs|libs(\/.*)*\/clientlibs|apps(\/.*)*\/clientlibs|etc\/designs).*\.js(\?.*)?$/;
403
404        /**
405         * The regular expression to match `#` and other non-ASCII characters in a URI.
406         * @readonly
407         * @type RegExp
408         */
409        var ENCODE_PATH_REGEXP = /[^\w-.~%:/?[\]@!$&'()*+,;=]/;
410
411        /**
412         * The regular expression to parse URI.
413         * @readonly
414         * @type RegExp
415         * @see https://tools.ietf.org/html/rfc3986#appendix-B
416         */
417        var URI_REGEXP = /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
418
419        /**
420         * Indicates after a session timeout if a refresh has already been triggered
421         * in order to avoid multiple alerts.
422         * @type String
423         */
424        var loginRedirected = false;
425
426        var self = {};
427
428        /**
429         * Returns the scheme and authority (userinfo, host, port) components of the given URI;
430         * or an empty string if the URI does not have the components.
431         *
432         * This method assumes the URI is valid.
433         *
434         * e.g. `scheme://userinfo@host:80/path?query#fragment` -> `scheme://userinfo@host:80`
435         *
436         * @param {String} uri The URI
437         * @returns {String} The scheme and authority components
438         */
439        self.getSchemeAndAuthority = function(uri) {
440            if (!uri) {
441                return "";
442            }
443
444            var result = URI_REGEXP.exec(uri);
445
446            if (result === null) {
447                return "";
448            }
449
450            return [ result[1], result[3] ].join("");
451        };
452
453        /**
454         * Returns the context path used on the server.
455         *
456         * @returns {String} The context path
457         */
458        self.getContextPath = function() {
459            // Keep cache of calculated path.
460            if (contextPath === null) {
461                contextPath = self.detectContextPath();
462            }
463            return contextPath;
464        };
465
466        /**
467         * Detects the context path used on the server.
468         *
469         * @returns {String} The context path
470         * @private
471         */
472        self.detectContextPath = function() {
473            try {
474                if (window.CQURLInfo) {
475                    contextPath = CQURLInfo.contextPath || "";
476                } else {
477                    var scripts = document.getElementsByTagName("script");
478                    for (var i = 0; i < scripts.length; i++) {
479                        var result = SCRIPT_URL_REGEXP.exec(scripts[i].src);
480                        if (result) {
481                            contextPath = result[1];
482                            return contextPath;
483                        }
484                    }
485                    contextPath = "";
486                }
487            } catch (e) {
488                // ignored
489            }
490
491            return contextPath;
492        };
493
494        /**
495         * Makes sure the specified relative URL starts with the context path
496         * used on the server. If an absolute URL is passed, it will be returned
497         * as-is.
498         *
499         * @param {String} url The URL
500         * @returns {String} The externalized URL
501         */
502        self.externalize = function(url) {
503            try {
504                if (url.indexOf("/") === 0 && self.getContextPath() && url.indexOf(self.getContextPath() + "/") !== 0) {
505                    url = self.getContextPath() + url;
506                }
507            } catch (e) {
508                // ignored
509            }
510            return url;
511        };
512
513        /**
514         * Removes scheme, authority and context path from the specified
515         * absolute URL if it has the same scheme and authority as the
516         * specified document (or the current one). If a relative URL is passed,
517         * the context path will be stripped if present.
518         *
519         * @param {String} url The URL
520         * @param {String} doc (optional) The document
521         * @returns {String} The internalized URL
522         */
523        self.internalize = function(url, doc) {
524            if (url.charAt(0) === "/") {
525                if (contextPath === url) {
526                    return "";
527                } else if (contextPath && url.indexOf(contextPath + "/") === 0) {
528                    return url.substring(contextPath.length);
529                } else {
530                    return url;
531                }
532            }
533
534            if (!doc) {
535                doc = document;
536            }
537            var docHost = self.getSchemeAndAuthority(doc.location.href);
538            var urlHost = self.getSchemeAndAuthority(url);
539            if (docHost === urlHost) {
540                return url.substring(urlHost.length + (contextPath ? contextPath.length : 0));
541            } else {
542                return url;
543            }
544        };
545
546        /**
547         * Removes all parts but the path from the specified URL.
548         * <p>Examples:<pre><code>
549         /x/y.sel.html?param=abc => /x/y
550         </code></pre>
551         * <pre><code>
552         http://www.day.com/foo/bar.html => /foo/bar
553         </code></pre><p>
554         *
555         * @param {String} url The URL, may be empty. If empty <code>window.location.href</code> is taken.
556         * @returns {String} The path
557         */
558        self.getPath = function(url) {
559            if (!url) {
560                if (window.CQURLInfo && CQURLInfo.requestPath) {
561                    return CQURLInfo.requestPath;
562                } else {
563                    url = window.location.pathname;
564                }
565            } else {
566                url = self.removeParameters(url);
567                url = self.removeAnchor(url);
568            }
569
570            url = self.internalize(url);
571            var i = url.indexOf(".", url.lastIndexOf("/"));
572            if (i !== -1) {
573                url = url.substring(0, i);
574            }
575            return url;
576        };
577
578        /**
579         * Removes the fragment component from the given URI.
580         *
581         * This method assumes the URI is valid.
582         *
583         * e.g. `scheme://userinfo@host:80/path?query#fragment` -> `scheme://userinfo@host:80/path?query`
584         *
585         * @param {String} uri The URI
586         * @returns {String} The URI without fragment component
587         */
588        self.removeAnchor = function(uri) {
589            var fragmentIndex = uri.indexOf("#");
590            if (fragmentIndex >= 0) {
591                return uri.substring(0, fragmentIndex);
592            } else {
593                return uri;
594            }
595        };
596
597        /**
598         * Removes the query component and its subsequent fragment component from the given URI.
599         * i.e. When query component exists, the subsequent fragment component is also removed.
600         * However, when query component doesn't exist, fragment component is not removed.
601         *
602         * The assumption here is that the usages of `#` before the `?` are intended as part of the path component
603         * that need to be encoded separately.
604         * This assumption is made because `c.d.cq.commons.jcr.JcrUtil#isValidName` allows `#`.
605         *
606         * e.g. `scheme://userinfo@host:80/path#with#hash?query#fragment` -> `scheme://userinfo@host:80/path#with#hash`
607         *
608         * @param {String} uri The URL
609         * @returns {String} The URI without the query component and its subsequent fragment component
610         */
611        self.removeParameters = function(uri) {
612            var queryIndex = uri.indexOf("?");
613            if (queryIndex >= 0) {
614                return uri.substring(0, queryIndex);
615            } else {
616                return uri;
617            }
618        };
619
620        /**
621         * Encodes the path component of the given URI if it is not already encoded.
622         * See {@link #encodePath} for the details of the encoding.
623         *
624         * e.g. `scheme://userinfo@host:80/path#with#hash?query#fragment`
625         * -> `scheme://userinfo@host:80/path%23with%23hash?query#fragment`
626         *
627         * @param {String} uri The URI to encode
628         * @returns {String} The encoded URI
629         */
630        self.encodePathOfURI = function(uri) {
631            var DELIMS = [ "?", "#" ];
632
633            var parts = [ uri ];
634            var delim;
635            for (var i = 0, ln = DELIMS.length; i < ln; i++) {
636                delim = DELIMS[i];
637                if (uri.indexOf(delim) >= 0) {
638                    parts = uri.split(delim);
639                    break;
640                }
641            }
642
643            if (ENCODE_PATH_REGEXP.test(parts[0])) {
644                parts[0] = self.encodePath(parts[0]);
645            }
646
647            return parts.join(delim);
648        };
649
650        /**
651         * Encodes the given URI using `encodeURI`.
652         *
653         * This method is used to encode URI components from the scheme component up to the path component (inclusive).
654         * Therefore, `?` and `#` are also encoded in addition.
655         *
656         * However `[` and `]` are not encoded.
657         * The assumption here is that the usages of `[` and `]` are only at the host component (for IPv6),
658         * not at the path component.
659         * This assumption is made because `c.d.cq.commons.jcr.JcrUtil#isValidName` disallows `[` and `]`.
660         *
661         * Examples
662         *
663         * * `scheme://userinfo@host:80/path?query#fragment` -> `scheme://userinfo@host:80/path%3Fquery%23fragment`
664         * * `http://[2001:db8:85a3:8d3:1319:8a2e:370:7348]/` -> `http://[2001:db8:85a3:8d3:1319:8a2e:370:7348]/`
665         *
666         * @param {String} uri The URI to encode
667         * @returns {String} The encoded URI
668         */
669        self.encodePath = function(uri) {
670            uri = encodeURI(uri);
671
672            // Decode back `%5B` and `%5D`.
673            // The `[` and `]` are not valid characters at the path component and need to be encoded,
674            // which `encodeURI` does correctly.
675            // However as mentioned in the doc, they are assumed to be used for authority component only.
676            uri = uri.replace(/%5B/g, "[").replace(/%5D/g, "]");
677
678            uri = uri.replace(/\?/g, "%3F");
679            uri = uri.replace(/#/g, "%23");
680
681            return uri;
682        };
683
684        /**
685         * Handles login redirection if needed.
686         */
687        self.handleLoginRedirect = function() {
688            if (!loginRedirected) {
689                loginRedirected = true;
690                alert(Granite.I18n.get("Your request could not be completed because you have been signed out."));
691
692                var l = util.getTopWindow().document.location;
693                l.href = self.externalize("/") + "?resource=" + encodeURIComponent(l.pathname + l.search + l.hash);
694            }
695        };
696
697        /**
698         * Gets the XHR hooked URL if called in a portlet context
699         *
700         * @param {String} url The URL to get
701         * @param {String} method The method to use to retrieve the XHR hooked URL
702         * @param {Object} params The parameters
703         * @returns {String} The XHR hooked URL if available, the provided URL otherwise
704         */
705        self.getXhrHook = function(url, method, params) {
706            method = method || "GET";
707            if (window.G_XHR_HOOK && typeof G_XHR_HOOK === "function") {
708                var p = {
709                    "url": url,
710                    "method": method
711                };
712                if (params) {
713                    p["params"] = params;
714                }
715                return G_XHR_HOOK(p);
716            }
717            return null;
718        };
719
720        /**
721         * Evaluates and returns the body of the specified response object.
722         * Alternatively, a URL can be specified, in which case it will be
723         * requested using a synchronous {@link #get} in order to acquire
724         * the response object.
725         *
726         * @param {Object|String} response The response object or URL
727         * @returns {Object} The evaluated response body
728         * @since 5.3
729         */
730        self.eval = function(response) {
731            if (typeof response !== "object") {
732                response = $.ajax({
733                    url: response,
734                    type: "get",
735                    async: false
736                });
737            }
738            try {
739                // support responseText for backward compatibility (pre 5.3)
740                var text = response.body ? response.body : response.responseText;
741                return JSON.parse(text);
742            } catch (e) {
743                // ignored
744            }
745            return null;
746        };
747
748        return self;
749    }());
750}));
751
752/*
753 * ADOBE CONFIDENTIAL
754 *
755 * Copyright 2012 Adobe Systems Incorporated
756 * All Rights Reserved.
757 *
758 * NOTICE:  All information contained herein is, and remains
759 * the property of Adobe Systems Incorporated and its suppliers,
760 * if any.  The intellectual and technical concepts contained
761 * herein are proprietary to Adobe Systems Incorporated and its
762 * suppliers and may be covered by U.S. and Foreign Patents,
763 * patents in process, and are protected by trade secret or copyright law.
764 * Dissemination of this information or reproduction of this material
765 * is strictly forbidden unless prior written permission is obtained
766 * from Adobe Systems Incorporated.
767 *
768 */
769(function(factory) {
770    "use strict";
771
772    if (typeof module === "object" && module.exports) {
773        module.exports = factory(require("@granite/http"));
774    } else {
775        window.Granite.I18n = factory(window.Granite.HTTP);
776    }
777}(function(HTTP) {
778    "use strict";
779
780    /**
781     * A helper class providing a set of utilities related to internationalization (i18n).
782     *
783     * <h3>Locale Priorities</h3>
784     * <p>The locale is read based on the following priorities:</p>
785     * <ol>
786     *   <li>manually specified locale</li>
787     *   <li><code>document.documentElement.lang</code></li>
788     *   <li><code>Granite.I18n.LOCALE_DEFAULT</code></li>
789     * </ol>
790     *
791     * <h3>Dictionary Priorities</h3>
792     * <p>The dictionary URL is read based on the following priorities:</p>
793     * <ol>
794     *   <li>manually specified URL (<code>urlPrefix</code, <code>urlSuffix</code>)</li>
795     *   <li><code>data-i18n-dictionary-src</code> attribute at &lt;html&gt; element,
796     *       which has the type of <a href="http://tools.ietf.org/html/rfc6570">URI Template</a> string</li>
797     *   <li>The URL resolved from default <code>urlPrefix</code> and <code>urlSuffix</code></li>
798     * </ol>
799     *
800     * <h3>URI Template of data-i18n-dictionary-src</h3>
801     * <p>It expects the variable named <code>locale</code>,
802     * which will be fetched from the locale (based on priorities above).
803     * E.g. <code>&lt;html lang="en" data-i18n-dictionary-src="/libs/cq/i18n/dict.{+locale}.json"&gt;</code>.</p>
804     *
805     * @static
806     * @class Granite.I18n
807     */
808    return (function() {
809        /**
810         * The map where the dictionaries are stored under their locale.
811         * @type Object
812         */
813        var dicts = {};
814
815        /**
816         * The prefix for the URL used to request dictionaries from the server.
817         * @type String
818         */
819        var urlPrefix = "/libs/cq/i18n/dict.";
820
821        /**
822         * The suffix for the URL used to request dictionaries from the server.
823         * @type String
824         */
825        var urlSuffix = ".json";
826
827        /**
828         * The manually specified locale as a String or a function that returns the locale as a string.
829         * @type String
830         */
831        var manualLocale = undefined;
832
833        /**
834         * If the current locale represents pseudo translations.
835         * In that case the dictionary is expected to provide just a special
836         * translation pattern to automatically convert all original strings.
837         */
838        var pseudoTranslations = false;
839
840        var languages = null;
841
842        var self = {};
843
844        /**
845         * Indicates if the dictionary parameters are specified manually.
846         */
847        var manualDictionary = false;
848
849        var getDictionaryUrl = function(locale) {
850            if (manualDictionary) {
851                return urlPrefix + locale + urlSuffix;
852            }
853
854            var dictionarySrc;
855            var htmlEl = document.querySelector("html");
856            if (htmlEl) {
857                dictionarySrc = htmlEl.getAttribute("data-i18n-dictionary-src");
858            }
859
860            if (!dictionarySrc) {
861                return urlPrefix + locale + urlSuffix;
862            }
863
864            // dictionarySrc is a URITemplate
865            // Use simple string replacement for now; for more complicated scenario, please use Granite.URITemplate
866            return dictionarySrc.replace("{locale}", encodeURIComponent(locale)).replace("{+locale}", locale);
867        };
868
869        var patchText = function(text, snippets) {
870            if (snippets) {
871                if (Array.isArray(snippets)) {
872                    for (var i = 0; i < snippets.length; i++) {
873                        text = text.replace("{" + i + "}", snippets[i]);
874                    }
875                } else {
876                    text = text.replace("{0}", snippets);
877                }
878            }
879            return text;
880        };
881
882        /**
883         * The default locale (en).
884         * @readonly
885         * @type String
886         */
887        self.LOCALE_DEFAULT = "en";
888
889        /**
890         * The language code for pseudo translations.
891         * @readonly
892         * @type String
893         */
894        self.PSEUDO_LANGUAGE = "zz";
895
896        /**
897         * The dictionary key for pseudo translation pattern.
898         * @readonly
899         * @type String
900         */
901        self.PSEUDO_PATTERN_KEY = "_pseudoPattern_";
902
903        /**
904         * Initializes I18n with the given config options:
905         * <ul>
906         * <li>locale: the current locale (defaults to "en")</li>
907         * <li>urlPrefix: the prefix for the URL used to request dictionaries from
908         * the server (defaults to "/libs/cq/i18n/dict.")</li>
909         * <li>urlSuffix: the suffix for the URL used to request dictionaries from
910         * the server (defaults to ".json")</li>
911         * </ul>
912         * Sample config. The dictionary would be requested from
913         * "/apps/i18n/dict.fr.json":
914         <code><pre>{
915         "locale": "fr",
916         "urlPrefix": "/apps/i18n/dict.",
917         "urlSuffix": ".json"
918         }</pre></code>
919         *
920         * @param {Object} config The config
921         */
922        self.init = function(config) {
923            config = config || {};
924
925            this.setLocale(config.locale);
926            this.setUrlPrefix(config.urlPrefix);
927            this.setUrlSuffix(config.urlSuffix);
928        };
929
930        /**
931         * Sets the current locale.
932         *
933         * @param {String|Function} locale The locale or a function that returns the locale as a string
934         */
935        self.setLocale = function(locale) {
936            if (!locale) {
937                return;
938            }
939            manualLocale = locale;
940        };
941
942        /**
943         * Returns the current locale based on the priorities.
944         *
945         * @returns {String} The locale
946         */
947        self.getLocale = function() {
948            if (typeof manualLocale === "function") {
949                // execute function first time only and store result in currentLocale
950                manualLocale = manualLocale();
951            }
952            return manualLocale || document.documentElement.lang || self.LOCALE_DEFAULT;
953        };
954
955        /**
956         * Sets the prefix for the URL used to request dictionaries from
957         * the server. The locale and URL suffix will be appended.
958         *
959         * @param {String} prefix The URL prefix
960         */
961        self.setUrlPrefix = function(prefix) {
962            if (!prefix) {
963                return;
964            }
965            urlPrefix = prefix;
966            manualDictionary = true;
967        };
968
969        /**
970         * Sets the suffix for the URL used to request dictionaries from
971         * the server. It will be appended to the URL prefix and locale.
972         *
973         * @param {String} suffix The URL suffix
974         */
975        self.setUrlSuffix = function(suffix) {
976            if (!suffix) {
977                return;
978            }
979            urlSuffix = suffix;
980            manualDictionary = true;
981        };
982
983        /**
984         * Returns the dictionary for the specified locale. This method
985         * will request the dictionary using the URL prefix, the locale,
986         * and the URL suffix. If no locale is specified, the current
987         * locale is used.
988         *
989         * @param {String} locale (optional) The locale
990         * @returns {Object} The dictionary
991         */
992        self.getDictionary = function(locale) {
993            locale = locale || self.getLocale();
994
995            if (!dicts[locale]) {
996                pseudoTranslations = locale.indexOf(self.PSEUDO_LANGUAGE) === 0;
997
998                $.ajax({
999                    url: getDictionaryUrl(locale),
1000                    type: 'GET',
1001                    async: false,
1002                    error: function(){
1003                        return true;
1004                    },
1005                    success: function(data){ 
1006                        dicts[locale] = data;
1007
1008                        if (!dicts[locale]) {
1009                            dicts[locale] = {};
1010                        }
1011                    }
1012                });
1013                //try {
1014
1015                    /*var xhr = new XMLHttpRequest();
1016                    xhr.open("GET", HTTP.externalize(getDictionaryUrl(locale)), false); 
1017                    xhr.send();
1018
1019                    dicts[locale] = JSON.parse(xhr.responseText);*/
1020
1021
1022                //} catch (e) {
1023                    // ignored
1024                //}
1025                /*if (!dicts[locale]) {
1026                    dicts[locale] = {};
1027                }*/
1028            }
1029
1030            return dicts[locale];
1031
1032        };
1033
1034        /**
1035         * Translates the specified text into the current language.
1036         *
1037         * @param {String} text The text to translate
1038         * @param {String[]} snippets The snippets replacing <code>{n}</code> (optional)
1039         * @param {String} note A hint for translators (optional)
1040         * @returns {String} The translated text
1041         */
1042        self.get = function(text, snippets, note) {
1043            var dict;
1044            var newText;
1045            var lookupText;
1046
1047            dict = self.getDictionary();
1048
1049            // note that pseudoTranslations is initialized in the getDictionary() call above
1050            lookupText = pseudoTranslations ? self.PSEUDO_PATTERN_KEY
1051                : note ? text + " ((" + note + "))"
1052                    : text;
1053            if (dict) {
1054                newText = dict[lookupText];
1055            }
1056            if (!newText) {
1057                newText = text;
1058            }
1059            if (pseudoTranslations) {
1060                newText = newText.replace("{string}", text).replace("{comment}", note ? note : "");
1061            }
1062            return patchText(newText, snippets);
1063        };
1064
1065        /**
1066         * Translates the specified text into the current language. Use this
1067         * method to translate String variables, e.g. data from the server.
1068         *
1069         * @param {String} text The text to translate
1070         * @param {String} note A hint for translators (optional)
1071         * @returns {String} The translated text
1072         */
1073        self.getVar = function(text, note) {
1074            if (!text) {
1075                return null;
1076            }
1077            return self.get(text, null, note);
1078        };
1079
1080        /**
1081         * Returns the available languages, including a "title" property with a display name:
1082         * for instance "German" for "de" or "German (Switzerland)" for "de_ch".
1083         *
1084         * @returns {Object} An object with language codes as keys and an object with "title",
1085         *                  "language", "country" and "defaultCountry" members.
1086         */
1087        self.getLanguages = function() {
1088            if (!languages) {
1089                try {
1090                    // use overlay servlet so customers can define /apps/wcm/core/resources/languages
1091                    // TODO: broken!!!
1092                    var url = HTTP.externalize("/libs/wcm/core/resources/languages.overlay.infinity.json");
1093                    var xhr = new XMLHttpRequest();
1094                    xhr.open("GET", url, false);
1095                    xhr.send();
1096
1097                    var json = JSON.parse(xhr.responseText);
1098
1099                    Object.keys(json).forEach(function(prop) {
1100                        var lang = json[prop];
1101                        if (lang.language) {
1102                            lang.title = self.getVar(lang.language);
1103                        }
1104                        if (lang.title && lang.country && lang.country !== "*") {
1105                            lang.title += " (" + self.getVar(lang.country) + ")";
1106                        }
1107                    });
1108                    languages = json;
1109                } catch (e) {
1110                    languages = {};
1111                }
1112            }
1113            return languages;
1114        };
1115
1116        /**
1117         * Parses a language code string such as "de_CH" and returns an object with
1118         * language and country extracted. The delimiter can be "_" or "-".
1119         *
1120         * @param {String} langCode a language code such as "de" or "de_CH" or "de-ch"
1121         * @returns {Object} an object with "code" ("de_CH"), "language" ("de") and "country" ("CH")
1122         *                  (or null if langCode was null)
1123         */
1124        self.parseLocale = function(langCode) {
1125            if (!langCode) {
1126                return null;
1127            }
1128            var pos = langCode.indexOf("_");
1129            if (pos < 0) {
1130                pos = langCode.indexOf("-");
1131            }
1132
1133            var language;
1134            var country;
1135            if (pos < 0) {
1136                language = langCode;
1137                country = null;
1138            } else {
1139                language = langCode.substring(0, pos);
1140                country = langCode.substring(pos + 1);
1141            }
1142            return {
1143                code: langCode,
1144                language: language,
1145                country: country
1146            };
1147        };
1148
1149        return self;
1150    }());
1151})); 
1152
1153/*
1154 * ADOBE CONFIDENTIAL
1155 *
1156 * Copyright 2012 Adobe Systems Incorporated
1157 * All Rights Reserved.
1158 *
1159 * NOTICE:  All information contained herein is, and remains
1160 * the property of Adobe Systems Incorporated and its suppliers,
1161 * if any.  The intellectual and technical concepts contained
1162 * herein are proprietary to Adobe Systems Incorporated and its
1163 * suppliers and may be covered by U.S. and Foreign Patents,
1164 * patents in process, and are protected by trade secret or copyright law.
1165 * Dissemination of this information or reproduction of this material
1166 * is strictly forbidden unless prior written permission is obtained
1167 * from Adobe Systems Incorporated.
1168 *
1169 */
1170(function(factory) {
1171    "use strict";
1172
1173    if (typeof module === "object" && module.exports) {
1174        module.exports = factory();
1175    } else {
1176        var g = window.Granite = window.Granite || {};
1177        g.TouchIndicator = factory();
1178    }
1179}(function() {
1180    "use strict";
1181
1182    function createIndicator() {
1183        var el = document.createElement("div");
1184        el.style.visibility = "hidden";
1185        // fixed would be better, but flickers on ipad while scrolling
1186        el.style.position = "absolute";
1187        el.style.width = "30px";
1188        el.style.height = "30px";
1189        el.style.borderRadius = "20px";
1190        el.style.border = "5px solid orange";
1191        el.style.userSelect = "none";
1192        el.style.opacity = "0.5";
1193        el.style.zIndex = "2000";
1194        el.style.pointerEvents = "none";
1195        return el;
1196    }
1197
1198    var used = {};
1199
1200    var unused = [];
1201
1202    /**
1203     * Implements the "Adobe Dynamic Touch Indicator" that tracks touch events and displays a visual indicator for
1204     * screen sharing and presentation purposes.
1205     *
1206     * To enable it, call <code>Granite.TouchIndicator.init()</code> e.g. on document ready:
1207     * <pre><code>
1208     * Granite.$(document).ready(function() {
1209     *     Granite.TouchIndicator.init();
1210     * });
1211     * </code></pre>
1212     *
1213     * AdobePatentID="2631US01"
1214     */
1215    return {
1216        debugWithMouse: false,
1217
1218        init: function() {
1219            var self = this;
1220
1221            var update = function(e) {
1222                self.update(e.touches);
1223                return true;
1224            };
1225            document.addEventListener("touchstart", update);
1226            document.addEventListener("touchmove", update);
1227            document.addEventListener("touchend", update);
1228
1229            if (this.debugWithMouse) {
1230                document.addEventListener("mousemove", function(e) {
1231                    e.identifer = "fake";
1232                    self.update([ e ]);
1233                    return true;
1234                });
1235            }
1236        },
1237
1238        update: function(touches) {
1239            // go over all touch events present in the array
1240            var retained = {};
1241            for (var i = 0; i < touches.length; i++) {
1242                var touch = touches[i];
1243                var id = touch.identifier;
1244
1245                // check if we already have a indicator with the correct id
1246                var indicator = used[id];
1247                if (!indicator) {
1248                    // if not, check if we have an unused one
1249                    indicator = unused.pop();
1250
1251                    // if not, create a new one and append it to the dom
1252                    if (!indicator) {
1253                        indicator = createIndicator();
1254                        document.body.appendChild(indicator);
1255                    }
1256                }
1257
1258                retained[id] = indicator;
1259                indicator.style.left = (touch.pageX - 20) + "px";
1260                indicator.style.top = (touch.pageY - 20) + "px";
1261                indicator.style.visibility = "visible";
1262            }
1263
1264            // now hide all unused ones and stuff them in the unused array
1265            for (id in used) {
1266                if (used.hasOwnProperty(id) && !retained[id]) {
1267                    indicator = used[id];
1268                    indicator.style.visibility = "hidden";
1269                    unused.push(indicator);
1270                }
1271            }
1272            used = retained;
1273        }
1274    };
1275}));
1276
1277/*
1278 * ADOBE CONFIDENTIAL
1279 *
1280 * Copyright 2012 Adobe Systems Incorporated
1281 * All Rights Reserved.
1282 *
1283 * NOTICE:  All information contained herein is, and remains
1284 * the property of Adobe Systems Incorporated and its suppliers,
1285 * if any.  The intellectual and technical concepts contained
1286 * herein are proprietary to Adobe Systems Incorporated and its
1287 * suppliers and may be covered by U.S. and Foreign Patents,
1288 * patents in process, and are protected by trade secret or copyright law.
1289 * Dissemination of this information or reproduction of this material
1290 * is strictly forbidden unless prior written permission is obtained
1291 * from Adobe Systems Incorporated.
1292 *
1293 */
1294(function(factory) {
1295    "use strict";
1296
1297    if (typeof module === "object" && module.exports) {
1298        module.exports = factory();
1299    } else {
1300        var g = window.Granite = window.Granite || {};
1301        g.OptOutUtil = factory();
1302    }
1303}(function($) {
1304    "use strict";
1305
1306    function trim(s) {
1307        if (String.prototype.trim) {
1308            return s.trim();
1309        }
1310        return s.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "");
1311    }
1312
1313    /**
1314     * A library to determine whether any opt-out cookie is set and whether a given cookie name is white-listed.
1315     *
1316     * The opt-out and white-list cookie names are determined by a server-side configuration
1317     * (<code>com.adobe.granite.security.commons.OptOutService</code>) and provided to this tool by an optionally
1318     * included component (<code>/libs/granite/security/components/optout</code>) which provides a global JSON object
1319     * named <code>GraniteOptOutConfig</code>.
1320     *
1321     * @static
1322     * @class Granite.OptOutUtil
1323     */
1324    return (function() {
1325        var self = {};
1326
1327        /**
1328         * The names of cookies the presence of which indicates the user has opted out.
1329         * @type String[]
1330         */
1331        var optOutCookieNames = [];
1332
1333        /**
1334         * The names of cookies which may still be set in spite of the user having opted out.
1335         * @type String[]
1336         */
1337        var whitelistedCookieNames = [];
1338
1339        /**
1340         * Initializes this tool with an opt-out configuration.
1341         *
1342         * The following options are supported:
1343         * <ul>
1344         *     <li>cookieNames: an array of cookie names representing opt-out cookies. Defaults to empty.</li>
1345         *     <li>whitelistCookieNames: an array of cookies representing white-listed cookies. Defaults to empty.</li>
1346         * </ul>
1347         *
1348         * @param {Object} config The opt-out configuration.
1349         *
1350         * @example
1351         * {
1352         *     "cookieNames": ["omniture_optout","cq-opt-out"],
1353         *     "whitelistCookieNames": ["someAppCookie", "anotherImportantAppCookie"]
1354         * }
1355         */
1356        self.init = function(config) {
1357            if (config) {
1358                optOutCookieNames = config.cookieNames || [];
1359                whitelistedCookieNames = config.whitelistCookieNames || [];
1360            } else {
1361                optOutCookieNames = [];
1362                whitelistedCookieNames = [];
1363            }
1364        };
1365
1366        /**
1367         * Returns the array of configured cookie names representing opt-out cookies.
1368         *
1369         * @returns {String[]} The cookie names.
1370         */
1371        self.getCookieNames = function() {
1372            return optOutCookieNames;
1373        };
1374
1375        /**
1376         * Returns the array of configured cookie names representing white-listed cookies.
1377         *
1378         * @returns {String[]} The cookie names.
1379         */
1380        self.getWhitelistCookieNames = function() {
1381            return whitelistedCookieNames;
1382        };
1383
1384        /**
1385         * Determines whether the user (browser) has elected to opt-out.
1386         * This is indicated by the presence of one of the cookies retrieved through {@link #getCookieNames()}.
1387         *
1388         * @returns {Boolean} <code>true</code> if an opt-cookie was found in the browser's cookies;
1389         *     <code>false</code> otherwise.
1390         */
1391        self.isOptedOut = function() {
1392            var browserCookies = document.cookie.split(";");
1393            for (var i = 0; i < browserCookies.length; i++) {
1394                var cookie = browserCookies[i];
1395                var cookieName = trim(cookie.split("=")[0]);
1396                if (self.getCookieNames().indexOf(cookieName) >= 0) {
1397                    return true;
1398                }
1399            }
1400            return false;
1401        };
1402
1403        /**
1404         * Determines whether the given <code>cookieName</code> may be used to set a cookie.
1405         * This is the case if either opt-out is inactive (<code>{@link #isOptedOut()} === false</code>) or it is
1406         * active and the give cookie name was found in the white-list ({@link #getWhitelistCookieNames()}).
1407         *
1408         * @param {String} cookieName The name of the cookie to check.
1409         * @returns {Boolean} <code>true</code> if a cookie of this name may be used with respect to the opt-out status;
1410         *     <code>false</code> otherwise.
1411         */
1412        self.maySetCookie = function(cookieName) {
1413            return !(self.isOptedOut() && self.getWhitelistCookieNames().indexOf(cookieName) === -1);
1414        };
1415
1416        return self;
1417    }());
1418}));
1419
1420/*
1421 * ADOBE CONFIDENTIAL
1422 *
1423 * Copyright 2012 Adobe Systems Incorporated
1424 * All Rights Reserved.
1425 *
vendor: 17,841 bytes, lines 1426-1451
1426 * NOTICE:  All information contained herein is, and remains
1427 * the property of Adobe Systems Incorporated and its suppliers,
1428 * if any.  The intellectual and technical concepts contained
1429 * herein are proprietary to Adobe Systems Incorporated and its
1430 * suppliers and may be covered by U.S. and Foreign Patents,
1431 * patents in process, and are protected by trade secret or copyright law.
1432 * Dissemination of this information or reproduction of this material
1433 * is strictly forbidden unless prior written permission is obtained
1434 * from Adobe Systems Incorporated.
1435 *
1436 */
1437
1438
1439//------------------------------------------------------------------------------
1440// Initialize the Granite utils library
1441
1442Granite.OptOutUtil.init(window.GraniteOptOutConfig);
1443Granite.HTTP.detectContextPath();
1444
1445
1446/*! Hammer.JS - v2.0.8 - 2016-04-23
1447 * http://hammerjs.github.io/
1448 *
1449 * Copyright (c) 2016 Jorik Tangelder;
1450 * Licensed under the MIT license */
1451!function(a,b,c,d){"use strict";function e(a,b,c){return setTimeout(j(a,c),b)}function f(a,b,c){return Array.isArray(a)?(g(a,c[b],c),!0):!1}function g(a,b,c){var e;if(a)if(a.forEach)a.forEach(b,c);else if(a.length!==d)for(e=0;e<a.length;)b.call(c,a[e],e,a),e++;else for(e in a)a.hasOwnProperty(e)&&b.call(c,a[e],e,a)}function h(b,c,d){var e="DEPRECATED METHOD: "+c+"\n"+d+" AT \n";return function(){var c=new Error("get-stack-trace"),d=c&&c.stack?c.stack.replace(/^[^\(]+?[\n$]/gm,"").replace(/^\s+at\s+/gm,"").replace(/^Object.<anonymous>\s*\(/gm,"{anonymous}()@"):"Unknown Stack Trace",f=a.console&&(a.console.warn||a.console.log);return f&&f.call(a.console,e,d),b.apply(this,arguments)}}function i(a,b,c){var d,e=b.prototype;d=a.prototype=Object.create(e),d.constructor=a,d._super=e,c&&la(d,c)}function j(a,b){return function(){return a.apply(b,arguments)}}function k(a,b){return typeof a==oa?a.apply(b?b[0]||d:d,b):a}function l(a,b){return a===d?b:a}function m(a,b,c){g(q(b),function(b){a.addEventListener(b,c,!1)})}function n(a,b,c){g(q(b),function(b){a.removeEventListener(b,c,!1)})}function o(a,b){for(;a;){if(a==b)return!0;a=a.parentNode}return!1}function p(a,b){return a.indexOf(b)>-1}function q(a){return a.trim().split(/\s+/g)}function r(a,b,c){if(a.indexOf&&!c)return a.indexOf(b);for(var d=0;d<a.length;){if(c&&a[d][c]==b||!c&&a[d]===b)return d;d++}return-1}function s(a){return Array.prototype.slice.call(a,0)}function t(a,b,c){for(var d=[],e=[],f=0;f<a.length;){var g=b?a[f][b]:a[f];r(e,g)<0&&d.push(a[f]),e[f]=g,f++}return c&&(d=b?d.sort(function(a,c){return a[b]>c[b]}):d.sort()),d}function u(a,b){for(var c,e,f=b[0].toUpperCase()+b.slice(1),g=0;g<ma.length;){if(c=ma[g],e=c?c+f:b,e in a)return e;g++}return d}function v(){return ua++}function w(b){var c=b.ownerDocument||b;return c.defaultView||c.parentWindow||a}function x(a,b){var c=this;this.manager=a,this.callback=b,this.element=a.element,this.target=a.options.inputTarget,this.domHandler=function(b){k(a.options.enable,[a])&&c.handler(b)},this.init()}function y(a){var b,c=a.options.inputClass;return new(b=c?c:xa?M:ya?P:wa?R:L)(a,z)}function z(a,b,c){var d=c.pointers.length,e=c.changedPointers.length,f=b&Ea&&d-e===0,g=b&(Ga|Ha)&&d-e===0;c.isFirst=!!f,c.isFinal=!!g,f&&(a.session={}),c.eventType=b,A(a,c),a.emit("hammer.input",c),a.recognize(c),a.session.prevInput=c}function A(a,b){var c=a.session,d=b.pointers,e=d.length;c.firstInput||(c.firstInput=D(b)),e>1&&!c.firstMultiple?c.firstMultiple=D(b):1===e&&(c.firstMultiple=!1);var f=c.firstInput,g=c.firstMultiple,h=g?g.center:f.center,i=b.center=E(d);b.timeStamp=ra(),b.deltaTime=b.timeStamp-f.timeStamp,b.angle=I(h,i),b.distance=H(h,i),B(c,b),b.offsetDirection=G(b.deltaX,b.deltaY);var j=F(b.deltaTime,b.deltaX,b.deltaY);b.overallVelocityX=j.x,b.overallVelocityY=j.y,b.overallVelocity=qa(j.x)>qa(j.y)?j.x:j.y,b.scale=g?K(g.pointers,d):1,b.rotation=g?J(g.pointers,d):0,b.maxPointers=c.prevInput?b.pointers.length>c.prevInput.maxPointers?b.pointers.length:c.prevInput.maxPointers:b.pointers.length,C(c,b);var k=a.element;o(b.srcEvent.target,k)&&(k=b.srcEvent.target),b.target=k}function B(a,b){var c=b.center,d=a.offsetDelta||{},e=a.prevDelta||{},f=a.prevInput||{};b.eventType!==Ea&&f.eventType!==Ga||(e=a.prevDelta={x:f.deltaX||0,y:f.deltaY||0},d=a.offsetDelta={x:c.x,y:c.y}),b.deltaX=e.x+(c.x-d.x),b.deltaY=e.y+(c.y-d.y)}function C(a,b){var c,e,f,g,h=a.lastInterval||b,i=b.timeStamp-h.timeStamp;if(b.eventType!=Ha&&(i>Da||h.velocity===d)){var j=b.deltaX-h.deltaX,k=b.deltaY-h.deltaY,l=F(i,j,k);e=l.x,f=l.y,c=qa(l.x)>qa(l.y)?l.x:l.y,g=G(j,k),a.lastInterval=b}else c=h.velocity,e=h.velocityX,f=h.velocityY,g=h.direction;b.velocity=c,b.velocityX=e,b.velocityY=f,b.direction=g}function D(a){for(var b=[],c=0;c<a.pointers.length;)b[c]={clientX:pa(a.pointers[c].clientX),clientY:pa(a.pointers[c].clientY)},c++;return{timeStamp:ra(),pointers:b,center:E(b),deltaX:a.deltaX,deltaY:a.deltaY}}function E(a){var b=a.length;if(1===b)return{x:pa(a[0].clientX),y:pa(a[0].clientY)};for(var c=0,d=0,e=0;b>e;)c+=a[e].clientX,d+=a[e].clientY,e++;return{x:pa(c/b),y:pa(d/b)}}function F(a,b,c){return{x:b/a||0,y:c/a||0}}function G(a,b){return a===b?Ia:qa(a)>=qa(b)?0>a?Ja:Ka:0>b?La:Ma}function H(a,b,c){c||(c=Qa);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return Math.sqrt(d*d+e*e)}function I(a,b,c){c||(c=Qa);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return 180*Math.atan2(e,d)/Math.PI}function J(a,b){return I(b[1],b[0],Ra)+I(a[1],a[0],Ra)}function K(a,b){return H(b[0],b[1],Ra)/H(a[0],a[1],Ra)}function L(){this.evEl=Ta,this.evWin=Ua,this.pressed=!1,x.apply(this,arguments)}function M(){this.evEl=Xa,this.evWin=Ya,x.apply(this,arguments),this.store=this.manager.session.pointerEvents=[]}function N(){this.evTarget=$a,this.evWin=_a,this.started=!1,x.apply(this,arguments)}function O(a,b){var c=s(a.touches),d=s(a.changedTouches);return b&(Ga|Ha)&&(c=t(c.concat(d),"identifier",!0)),[c,d]}function P(){this.evTarget=bb,this.targetIds={},x.apply(this,arguments)}function Q(a,b){var c=s(a.touches),d=this.targetIds;if(b&(Ea|Fa)&&1===c.length)return d[c[0].identifier]=!0,[c,c];var e,f,g=s(a.changedTouches),h=[],i=this.target;if(f=c.filter(function(a){return o(a.target,i)}),b===Ea)for(e=0;e<f.length;)d[f[e].identifier]=!0,e++;for(e=0;e<g.length;)d[g[e].identifier]&&h.push(g[e]),b&(Ga|Ha)&&delete d[g[e].identifier],e++;return h.length?[t(f.concat(h),"identifier",!0),h]:void 0}function R(){x.apply(this,arguments);var a=j(this.handler,this);this.touch=new P(this.manager,a),this.mouse=new L(this.manager,a),this.primaryTouch=null,this.lastTouches=[]}function S(a,b){a&Ea?(this.primaryTouch=b.changedPointers[0].identifier,T.call(this,b)):a&(Ga|Ha)&&T.call(this,b)}function T(a){var b=a.changedPointers[0];if(b.identifier===this.primaryTouch){var c={x:b.clientX,y:b.clientY};this.lastTouches.push(c);var d=this.lastTouches,e=function(){var a=d.indexOf(c);a>-1&&d.splice(a,1)};setTimeout(e,cb)}}function U(a){for(var b=a.srcEvent.clientX,c=a.srcEvent.clientY,d=0;d<this.lastTouches.length;d++){var e=this.lastTouches[d],f=Math.abs(b-e.x),g=Math.abs(c-e.y);if(db>=f&&db>=g)return!0}return!1}function V(a,b){this.manager=a,this.set(b)}function W(a){if(p(a,jb))return jb;var b=p(a,kb),c=p(a,lb);return b&&c?jb:b||c?b?kb:lb:p(a,ib)?ib:hb}function X(){if(!fb)return!1;var b={},c=a.CSS&&a.CSS.supports;return["auto","manipulation","pan-y","pan-x","pan-x pan-y","none"].forEach(function(d){b[d]=c?a.CSS.supports("touch-action",d):!0}),b}function Y(a){this.options=la({},this.defaults,a||{}),this.id=v(),this.manager=null,this.options.enable=l(this.options.enable,!0),this.state=nb,this.simultaneous={},this.requireFail=[]}function Z(a){return a&sb?"cancel":a&qb?"end":a&pb?"move":a&ob?"start":""}function $(a){return a==Ma?"down":a==La?"up":a==Ja?"left":a==Ka?"right":""}function _(a,b){var c=b.manager;return c?c.get(a):a}function aa(){Y.apply(this,arguments)}function ba(){aa.apply(this,arguments),this.pX=null,this.pY=null}function ca(){aa.apply(this,arguments)}function da(){Y.apply(this,arguments),this._timer=null,this._input=null}function ea(){aa.apply(this,arguments)}function fa(){aa.apply(this,arguments)}function ga(){Y.apply(this,arguments),this.pTime=!1,this.pCenter=!1,this._timer=null,this._input=null,this.count=0}function ha(a,b){return b=b||{},b.recognizers=l(b.recognizers,ha.defaults.preset),new ia(a,b)}function ia(a,b){this.options=la({},ha.defaults,b||{}),this.options.inputTarget=this.options.inputTarget||a,this.handlers={},this.session={},this.recognizers=[],this.oldCssProps={},this.element=a,this.input=y(this),this.touchAction=new V(this,this.options.touchAction),ja(this,!0),g(this.options.recognizers,function(a){var b=this.add(new a[0](a[1]));a[2]&&b.recognizeWith(a[2]),a[3]&&b.requireFailure(a[3])},this)}function ja(a,b){var c=a.element;if(c.style){var d;g(a.options.cssProps,function(e,f){d=u(c.style,f),b?(a.oldCssProps[d]=c.style[d],c.style[d]=e):c.style[d]=a.oldCssProps[d]||""}),b||(a.oldCssProps={})}}function ka(a,c){var d=b.createEvent("Event");d.initEvent(a,!0,!0),d.gesture=c,c.target.dispatchEvent(d)}var la,ma=["","webkit","Moz","MS","ms","o"],na=b.createElement("div"),oa="function",pa=Math.round,qa=Math.abs,ra=Date.now;la="function"!=typeof Object.assign?function(a){if(a===d||null===a)throw new TypeError("Cannot convert undefined or null to object");for(var b=Object(a),c=1;c<arguments.length;c++){var e=arguments[c];if(e!==d&&null!==e)for(var f in e)e.hasOwnProperty(f)&&(b[f]=e[f])}return b}:Object.assign;var sa=h(function(a,b,c){for(var e=Object.keys(b),f=0;f<e.length;)(!c||c&&a[e[f]]===d)&&(a[e[f]]=b[e[f]]),f++;return a},"extend","Use `assign`."),ta=h(function(a,b){return sa(a,b,!0)},"merge","Use `assign`."),ua=1,va=/mobile|tablet|ip(ad|hone|od)|android/i,wa="ontouchstart"in a,xa=u(a,"PointerEvent")!==d,ya=wa&&va.test(navigator.userAgent),za="touch",Aa="pen",Ba="mouse",Ca="kinect",Da=25,Ea=1,Fa=2,Ga=4,Ha=8,Ia=1,Ja=2,Ka=4,La=8,Ma=16,Na=Ja|Ka,Oa=La|Ma,Pa=Na|Oa,Qa=["x","y"],Ra=["clientX","clientY"];x.prototype={handler:function(){},init:function(){this.evEl&&m(this.element,this.evEl,this.domHandler),this.evTarget&&m(this.target,this.evTarget,this.domHandler),this.evWin&&m(w(this.element),this.evWin,this.domHandler)},destroy:function(){this.evEl&&n(this.element,this.evEl,this.domHandler),this.evTarget&&n(this.target,this.evTarget,this.domHandler),this.evWin&&n(w(this.element),this.evWin,this.domHandler)}};var Sa={mousedown:Ea,mousemove:Fa,mouseup:Ga},Ta="mousedown",Ua="mousemove mouseup";i(L,x,{handler:function(a){var b=Sa[a.type];b&Ea&&0===a.button&&(this.pressed=!0),b&Fa&&1!==a.which&&(b=Ga),this.pressed&&(b&Ga&&(this.pressed=!1),this.callback(this.manager,b,{pointers:[a],changedPointers:[a],pointerType:Ba,srcEvent:a}))}});var Va={pointerdown:Ea,pointermove:Fa,pointerup:Ga,pointercancel:Ha,pointerout:Ha},Wa={2:za,3:Aa,4:Ba,5:Ca},Xa="pointerdown",Ya="pointermove pointerup pointercancel";a.MSPointerEvent&&!a.PointerEvent&&(Xa="MSPointerDown",Ya="MSPointerMove MSPointerUp MSPointerCancel"),i(M,x,{handler:function(a){var b=this.store,c=!1,d=a.type.toLowerCase().replace("ms",""),e=Va[d],f=Wa[a.pointerType]||a.pointerType,g=f==za,h=r(b,a.pointerId,"pointerId");e&Ea&&(0===a.button||g)?0>h&&(b.push(a),h=b.length-1):e&(Ga|Ha)&&(c=!0),0>h||(b[h]=a,this.callback(this.manager,e,{pointers:b,changedPointers:[a],pointerType:f,srcEvent:a}),c&&b.splice(h,1))}});var Za={touchstart:Ea,touchmove:Fa,touchend:Ga,touchcancel:Ha},$a="touchstart",_a="touchstart touchmove touchend touchcancel";i(N,x,{handler:function(a){var b=Za[a.type];if(b===Ea&&(this.started=!0),this.started){var c=O.call(this,a,b);b&(Ga|Ha)&&c[0].length-c[1].length===0&&(this.started=!1),this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:za,srcEvent:a})}}});var ab={touchstart:Ea,touchmove:Fa,touchend:Ga,touchcancel:Ha},bb="touchstart touchmove touchend touchcancel";i(P,x,{handler:function(a){var b=ab[a.type],c=Q.call(this,a,b);c&&this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:za,srcEvent:a})}});var cb=2500,db=25;i(R,x,{handler:function(a,b,c){var d=c.pointerType==za,e=c.pointerType==Ba;if(!(e&&c.sourceCapabilities&&c.sourceCapabilities.firesTouchEvents)){if(d)S.call(this,b,c);else if(e&&U.call(this,c))return;this.callback(a,b,c)}},destroy:function(){this.touch.destroy(),this.mouse.destroy()}});var eb=u(na.style,"touchAction"),fb=eb!==d,gb="compute",hb="auto",ib="manipulation",jb="none",kb="pan-x",lb="pan-y",mb=X();V.prototype={set:function(a){a==gb&&(a=this.compute()),fb&&this.manager.element.style&&mb[a]&&(this.manager.element.style[eb]=a),this.actions=a.toLowerCase().trim()},update:function(){this.set(this.manager.options.touchAction)},compute:function(){var a=[];return g(this.manager.recognizers,function(b){k(b.options.enable,[b])&&(a=a.concat(b.getTouchAction()))}),W(a.join(" "))},preventDefaults:function(a){var b=a.srcEvent,c=a.offsetDirection;if(this.manager.session.prevented)return void b.preventDefault();var d=this.actions,e=p(d,jb)&&!mb[jb],f=p(d,lb)&&!mb[lb],g=p(d,kb)&&!mb[kb];if(e){var h=1===a.pointers.length,i=a.distance<2,j=a.deltaTime<250;if(h&&i&&j)return}return g&&f?void 0:e||f&&c&Na||g&&c&Oa?this.preventSrc(b):void 0},preventSrc:function(a){this.manager.session.prevented=!0,a.preventDefault()}};var nb=1,ob=2,pb=4,qb=8,rb=qb,sb=16,tb=32;Y.prototype={defaults:{},set:function(a){return la(this.options,a),this.manager&&this.manager.touchAction.update(),this},recognizeWith:function(a){if(f(a,"recognizeWith",this))return this;var b=this.simultaneous;return a=_(a,this),b[a.id]||(b[a.id]=a,a.recognizeWith(this)),this},dropRecognizeWith:function(a){return f(a,"dropRecognizeWith",this)?this:(a=_(a,this),delete this.simultaneous[a.id],this)},requireFailure:function(a){if(f(a,"requireFailure",this))return this;var b=this.requireFail;return a=_(a,this),-1===r(b,a)&&(b.push(a),a.requireFailure(this)),this},dropRequireFailure:function(a){if(f(a,"dropRequireFailure",this))return this;a=_(a,this);var b=r(this.requireFail,a);return b>-1&&this.requireFail.splice(b,1),this},hasRequireFailures:function(){return this.requireFail.length>0},canRecognizeWith:function(a){return!!this.simultaneous[a.id]},emit:function(a){function b(b){c.manager.emit(b,a)}var c=this,d=this.state;qb>d&&b(c.options.event+Z(d)),b(c.options.event),a.additionalEvent&&b(a.additionalEvent),d>=qb&&b(c.options.event+Z(d))},tryEmit:function(a){return this.canEmit()?this.emit(a):void(this.state=tb)},canEmit:function(){for(var a=0;a<this.requireFail.length;){if(!(this.requireFail[a].state&(tb|nb)))return!1;a++}return!0},recognize:function(a){var b=la({},a);return k(this.options.enable,[this,b])?(this.state&(rb|sb|tb)&&(this.state=nb),this.state=this.process(b),void(this.state&(ob|pb|qb|sb)&&this.tryEmit(b))):(this.reset(),void(this.state=tb))},process:function(a){},getTouchAction:function(){},reset:function(){}},i(aa,Y,{defaults:{pointers:1},attrTest:function(a){var b=this.options.pointers;return 0===b||a.pointers.length===b},process:function(a){var b=this.state,c=a.eventType,d=b&(ob|pb),e=this.attrTest(a);return d&&(c&Ha||!e)?b|sb:d||e?c&Ga?b|qb:b&ob?b|pb:ob:tb}}),i(ba,aa,{defaults:{event:"pan",threshold:10,pointers:1,direction:Pa},getTouchAction:function(){var a=this.options.direction,b=[];return a&Na&&b.push(lb),a&Oa&&b.push(kb),b},directionTest:function(a){var b=this.options,c=!0,d=a.distance,e=a.direction,f=a.deltaX,g=a.deltaY;return e&b.direction||(b.direction&Na?(e=0===f?Ia:0>f?Ja:Ka,c=f!=this.pX,d=Math.abs(a.deltaX)):(e=0===g?Ia:0>g?La:Ma,c=g!=this.pY,d=Math.abs(a.deltaY))),a.direction=e,c&&d>b.threshold&&e&b.direction},attrTest:function(a){return aa.prototype.attrTest.call(this,a)&&(this.state&ob||!(this.state&ob)&&this.directionTest(a))},emit:function(a){this.pX=a.deltaX,this.pY=a.deltaY;var b=$(a.direction);b&&(a.additionalEvent=this.options.event+b),this._super.emit.call(this,a)}}),i(ca,aa,{defaults:{event:"pinch",threshold:0,pointers:2},getTouchAction:function(){return[jb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.scale-1)>this.options.threshold||this.state&ob)},emit:function(a){if(1!==a.scale){var b=a.scale<1?"in":"out";a.additionalEvent=this.options.event+b}this._super.emit.call(this,a)}}),i(da,Y,{defaults:{event:"press",pointers:1,time:251,threshold:9},getTouchAction:function(){return[hb]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distance<b.threshold,f=a.deltaTime>b.time;if(this._input=a,!d||!c||a.eventType&(Ga|Ha)&&!f)this.reset();else if(a.eventType&Ea)this.reset(),this._timer=e(function(){this.state=rb,this.tryEmit()},b.time,this);else if(a.eventType&Ga)return rb;return tb},reset:function(){clearTimeout(this._timer)},emit:function(a){this.state===rb&&(a&&a.eventType&Ga?this.manager.emit(this.options.event+"up",a):(this._input.timeStamp=ra(),this.manager.emit(this.options.event,this._input)))}}),i(ea,aa,{defaults:{event:"rotate",threshold:0,pointers:2},getTouchAction:function(){return[jb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.rotation)>this.options.threshold||this.state&ob)}}),i(fa,aa,{defaults:{event:"swipe",threshold:10,velocity:.3,direction:Na|Oa,pointers:1},getTouchAction:function(){return ba.prototype.getTouchAction.call(this)},attrTest:function(a){var b,c=this.options.direction;return c&(Na|Oa)?b=a.overallVelocity:c&Na?b=a.overallVelocityX:c&Oa&&(b=a.overallVelocityY),this._super.attrTest.call(this,a)&&c&a.offsetDirection&&a.distance>this.options.threshold&&a.maxPointers==this.options.pointers&&qa(b)>this.options.velocity&&a.eventType&Ga},emit:function(a){var b=$(a.offsetDirection);b&&this.manager.emit(this.options.event+b,a),this.manager.emit(this.options.event,a)}}),i(ga,Y,{defaults:{event:"tap",pointers:1,taps:1,interval:300,time:250,threshold:9,posThreshold:10},getTouchAction:function(){return[ib]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distance<b.threshold,f=a.deltaT
1451ime<b.time;if(this.reset(),a.eventType&Ea&&0===this.count)return this.failTimeout();if(d&&f&&c){if(a.eventType!=Ga)return this.failTimeout();var g=this.pTime?a.timeStamp-this.pTime<b.interval:!0,h=!this.pCenter||H(this.pCenter,a.center)<b.posThreshold;this.pTime=a.timeStamp,this.pCenter=a.center,h&&g?this.count+=1:this.count=1,this._input=a;var i=this.count%b.taps;if(0===i)return this.hasRequireFailures()?(this._timer=e(function(){this.state=rb,this.tryEmit()},b.interval,this),ob):rb}return tb},failTimeout:function(){return this._timer=e(function(){this.state=tb},this.options.interval,this),tb},reset:function(){clearTimeout(this._timer)},emit:function(){this.state==rb&&(this._input.tapCount=this.count,this.manager.emit(this.options.event,this._input))}}),ha.VERSION="2.0.8",ha.defaults={domEvents:!1,touchAction:gb,enable:!0,inputTarget:null,inputClass:null,preset:[[ea,{enable:!1}],[ca,{enable:!1},["rotate"]],[fa,{direction:Na}],[ba,{direction:Na},["swipe"]],[ga],[ga,{event:"doubletap",taps:2},["tap"]],[da]],cssProps:{userSelect:"none",touchSelect:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}};var ub=1,vb=2;ia.prototype={set:function(a){return la(this.options,a),a.touchAction&&this.touchAction.update(),a.inputTarget&&(this.input.destroy(),this.input.target=a.inputTarget,this.input.init()),this},stop:function(a){this.session.stopped=a?vb:ub},recognize:function(a){var b=this.session;if(!b.stopped){this.touchAction.preventDefaults(a);var c,d=this.recognizers,e=b.curRecognizer;(!e||e&&e.state&rb)&&(e=b.curRecognizer=null);for(var f=0;f<d.length;)c=d[f],b.stopped===vb||e&&c!=e&&!c.canRecognizeWith(e)?c.reset():c.recognize(a),!e&&c.state&(ob|pb|qb)&&(e=b.curRecognizer=c),f++}},get:function(a){if(a instanceof Y)return a;for(var b=this.recognizers,c=0;c<b.length;c++)if(b[c].options.event==a)return b[c];return null},add:function(a){if(f(a,"add",this))return this;var b=this.get(a.options.event);return b&&this.remove(b),this.recognizers.push(a),a.manager=this,this.touchAction.update(),a},remove:function(a){if(f(a,"remove",this))return this;if(a=this.get(a)){var b=this.recognizers,c=r(b,a);-1!==c&&(b.splice(c,1),this.touchAction.update())}return this},on:function(a,b){if(a!==d&&b!==d){var c=this.handlers;return g(q(a),function(a){c[a]=c[a]||[],c[a].push(b)}),this}},off:function(a,b){if(a!==d){var c=this.handlers;return g(q(a),function(a){b?c[a]&&c[a].splice(r(c[a],b),1):delete c[a]}),this}},emit:function(a,b){this.options.domEvents&&ka(a,b);var c=this.handlers[a]&&this.handlers[a].slice();if(c&&c.length){b.type=a,b.preventDefault=function(){b.srcEvent.preventDefault()};for(var d=0;d<c.length;)c[d](b),d++}},destroy:function(){this.element&&ja(this,!1),this.handlers={},this.session={},this.input.destroy(),this.element=null}},la(ha,{INPUT_START:Ea,INPUT_MOVE:Fa,INPUT_END:Ga,INPUT_CANCEL:Ha,STATE_POSSIBLE:nb,STATE_BEGAN:ob,STATE_CHANGED:pb,STATE_ENDED:qb,STATE_RECOGNIZED:rb,STATE_CANCELLED:sb,STATE_FAILED:tb,DIRECTION_NONE:Ia,DIRECTION_LEFT:Ja,DIRECTION_RIGHT:Ka,DIRECTION_UP:La,DIRECTION_DOWN:Ma,DIRECTION_HORIZONTAL:Na,DIRECTION_VERTICAL:Oa,DIRECTION_ALL:Pa,Manager:ia,Input:x,TouchAction:V,TouchInput:P,MouseInput:L,PointerEventInput:M,TouchMouseInput:R,SingleTouchInput:N,Recognizer:Y,AttrRecognizer:aa,Tap:ga,Pan:ba,Swipe:fa,Pinch:ca,Rotate:ea,Press:da,on:m,off:n,each:g,merge:ta,extend:sa,assign:la,inherit:i,bindFn:j,prefixed:u});var wb="undefined"!=typeof a?a:"undefined"!=typeof self?self:{};wb.Hammer=ha,"function"==typeof define&&define.amd?define(function(){return ha}):"undefined"!=typeof module&&module.exports?module.exports=ha:a[c]=ha}(window,document,"Hammer");
1452//# sourceMappingURL=hammer.min.js.map
1453
1454
1455window.ATVI = window.ATVI || {};
1456ATVI.components = ATVI.components || {};
1457
1458// atvi-utils
1459
1460(function($, ATVI) {
1461
1462    var utils = ATVI.utils = {};
1463	var cookieMap, queryMap, idCounter = 0;
1464
1465    utils.renderTemplate = function(template, fieldData, prefix, suffix) {
1466        prefix = prefix || "{{";
1467        suffix = suffix || "}}";
1468        var ret = template;
1469        for(var field in fieldData) {
1470            ret = ret.replace(new RegExp(prefix + field + suffix, "g"), fieldData[field]);
1471        }
1472        return ret;
1473    };
1474
1475	utils.getCookies = function(update) {
1476        if(!cookieMap || update) {
1477            cookieMap = {};
1478            var i, cookies = document.cookie.split(";");
1479            for (i = 0; i < cookies.length; i++) {
1480                var index = cookies[i].indexOf('=');
1481                var x = cookies[i].substr(0, index);
1482                var y = cookies[i].substr(index + 1);
1483                x = x.replace(/^\s+|\s+$/g, '');
1484                if(x) cookieMap[x] = unescape(y);
1485            }
1486        }
1487        return cookieMap;
1488    };
1489
1490    utils.getCookie = function(c, update) {
1491		return this.getCookies(update)[c];
1492    };
1493
1494	utils.setCookie = function(name, value, opts) {
1495        var value = escape(value);
1496        opts = opts || {};
1497
1498        value += ";path=" + (opts.path || "/");
1499
1500		if(opts.domain) value += ";domain=" + opts.domain;
1501
1502        var t = typeof opts.maxAge;
1503        if(t == "number" || t == "string") value += ";max-age=" + opts.maxAge;
1504
1505        var e = opts.expireDate;
1506        if(typeof e == "number") e = new Date((new Date()).getTime() + e * 1000);
1507        if(e) value += ';expires=' + e.toUTCString();
1508
1509		if(opts.secure) value += ";secure";
1510
1511        document.cookie = name + '=' + value;
1512        cookieMap = null;
1513    };
1514
1515    utils.deleteCookie = function(name) {
1516      document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
1517    }
1518
1519    utils.getQueryParameters = function(update) {
1520        if(!queryMap || update) {
1521            queryMap = {};
1522            var q = window.location.href;
1523            var ind = q.indexOf("?");
1524            q = (ind >= 0) ? q.substring(ind + 1) : "";
1525            ind = q.indexOf("#");
1526            if(ind >= 0) q = q.substring(0, ind);
1527            q = q.split("&");
1528            for(var i = 0; i < q.length; i++) {
1529                p = q[i].split("=");
1530                if(p[0]) queryMap[p[0]] = p[1] ? decodeURIComponent(p[1]) : p[1];
1531            }
1532        }
1533        return queryMap;
1534    };
1535
1536    utils.getQueryParameter = function(p, update) {
1537        return this.getQueryParameters(update)[p];
1538    };
1539
1540    utils.uniqueId = function($els) {
1541        $els = $($els);
1542        var prefix = "atvi-unique-" + (new Date().getTime()) + "-";
1543        $els.each(function() {
1544            if(this.id) return;
1545            var id;
1546            while(!id || $("#" + id).length) {
1547                id = prefix + (idCounter++);
1548            }
1549            this.id = id;
1550        });
1551        return $els;
1552    };
1553
1554    utils.parseUrl = function(url) {
1555        if(!url) return;
1556        var ret = {originalUrl: url};
1557        var m = url.match(/^(([^\/:]+:)?\/\/)?(.*)$/);
1558        if(m[1]) ret.protocol = m[2] || window.location.protocol;
1559        else {
1560            ret.protocol = "http:";
1561            var domainNeeded = true;
1562        }
1563        url = m[3];
1564        if(!url) return;
1565        m = url.match(/^(([\w-]+(\.[\w-]+)*)(:0*([1-9][0-9]*))?)?(\/.*)?$/);
1566        ret.host = m[1];
1567        if(!ret.host && domainNeeded) return;
1568        ret.domain = m[2];
1569        ret.port = parseInt(m[5] || 0) || undefined;
1570        ret.usedPort = ret.port || ret.protocol == "http:" ? 80 : 443;
1571        url = m[6];
1572		var ind = url.indexOf("#");
1573        if(ind >= 0) {
1574            ret.hash = url.substring(ind);
1575            ret.hashValue = ret.hash(1);
1576            url = url.substring(0, ind);
1577        }
1578        ind = url.indexOf("?");
1579        if(ind >= 0) {
1580			ret.query = url.substring(ind);
1581            var p = ret.queryParameters = {};
1582            var params = ret.query.substring(1).split("&");
1583            for(var i = 0; i < params.length; i++) {
1584				var e = params[i].split("=");
1585                if(e[0]) {
1586                    var name = e.shift();
1587					params[name] = e.join("+"); 
1588                }
1589            }
1590            url = url.substring(0, ind);
1591        }
1592        return ret;
1593    };
1594
1595    utils.localeRegex = /^\/(\w\w(\/\w\w)?)($|\/.*$)/;
1596    utils.locales = {
1597        en: "en_us",
1598        da: "da_dk",
1599        en_uk: "en_gb",
1600        mx: "es_mx",
1601        pt: "br_pt",
1602        jp: "ja_jp"
1603    };
1604
1605    utils.parseLocalizedPath = function(path) {
1606        var m = path.match(utils.localeRegex);
1607        var n = m ? m[3] || "/" : path || "/";
1608        var lp = m ? m[1] : "";
1609        var loc = (lp || "en").replace(/(\w\w)\/(\w\w)/, "$2_$1");
1610        loc = utils.locales[loc] || loc;
1611        loc = loc.replace(/^(\w\w)$/, "$1_$1");
1612        if(lp) lp = "/" + lp;
1613        return {
1614            normalized: n,
1615            locPart: lp,
1616            locale: loc,
1617            region: loc.substring(3),
1618            language: loc.substring(0, 2)
1619        };
1620    };
1621
1622    utils.base64Map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
1622+/=";
1623    utils.decodeBase64 = function(inp) {
1624        var map = utils.base64Map;
1625        var ret = "";
1626        var in1, in2, in3, in4, out1, out2, out3, i = 0;
1627
1628        inp = inp.replace(/[^a-zA-Z0-9\+\/\=]/g, "");
1629        do {
1630            in1 = map.indexOf(inp.charAt(i++) || "=");
1631            in2 = map.indexOf(inp.charAt(i++) || "=");
1632            in3 = map.indexOf(inp.charAt(i++) || "=");
1633            in4 = map.indexOf(inp.charAt(i++) || "=");
1634
1635            out1 = (in1 << 2) | (in2 >> 4);
1636            out2 = ((in2 & 15) << 4) | (in3 >> 2);
1637            out3 = ((in3 & 3) << 6) | in4;
1638
1639            ret = ret + String.fromCharCode(out1);
1640            if (in3 != 64) ret = ret + String.fromCharCode(out2);
1641            if (in4 != 64) ret = ret + String.fromCharCode(out3);
1642        } while (i < inp.length);
1643
1644        return ret;
1645    };
1646
1647    utils.createRegistry = (function() {
1648
1649        var register = function(r, $el, obj, cl) {
1650			var id;
1651            if(typeof $el == "string") id = $el;
1652            else {
1653                $el = resolve($el, cl);
1654                if(!$el.length) return null;
1655				id = $el[0].id;
1656            }
1657            var c = r.store[id];
1658            if(!c) {
1659                c = r.store[id] = obj || {};
1660            }
1661            return {
1662                $el: $el,
1663                context: c
1664            };
1665        };
1666
1667        var get = function(r, $el, cl) {
1668            var id = typeof $el == "string" ? $el : resolve($el, cl)[0].id;
1669			return r.store[id];
1670        };
1671
1672        var getAll = function(r) {
1673            var ret = [];
1674            for(var id in r.store) {
1675                if(r.store.hasOwnProperty(id)) ret.push({id: id, context: r.store[id]});
1676            }
1677            return ret;
1678        };
1679
1680        var purge = function(r, $el, cl) {
1681            var id = typeof $el == "string" ? $el : resolve($el, cl)[0].id;
1682            var a = r.store[id];
1683            r.store[id] = null;
1684			delete r.store[id];
1685            return !!a;
1686        };
1687
1688        var purgeAll = function(r) {
1689			for(var id in r.store) {
1690                if(r.store.hasOwnProperty(id)) {
1691                    r.store[id] = null;
1692                    delete r.store[id];
1693                }
1694            }
1695        };
1696
1697        var resolve = function($el, cl) {
1698            if(cl && !$el.hasClass(cl)) {
1699                var c = $el.find("." + cl);
1700                if(c.length) $el = c.first();
1701                else {
1702					c = $el.parents("." + cl);
1703                    if(c.length) $el = c.first();
1704                }
1705            }
1706            return utils.uniqueId($el);
1707        };
1708
1709        return function(reqClass) {
1710			var r = {
1711                store: {},
1712                register: function($el, obj) {
1713                    return register(r, $el, obj, reqClass);
1714                },
1715                get: function($el) {
1716					return get(r, $el, reqClass);
1717                },
1718                purge: function($el) {
1719					return purge(r, $el, reqClass);
1720                },
1721                getAll: function() {
1722                    return getAll(r);
1723                },
1724                purgeAll: function() {
1725					return purgeAll(r);
1726                }
1727    	    };
1728            return r;
1729        };
1730
1731    })();
1732
1733    utils.createReadyQueue = function(arr, alwaysAfter) {
1734
1735		var ready = false;
1736        var queue = [];
1737        var onReady = function(callback) {
1738            if(ready) {
1739				if(alwaysAfter) setTimeout(callback, 0);
1740                else callback();
1741            }
1742            else queue.push(callback);
1743        };
1744
1745        var events = arr.slice(0);
1746        
1747        var processQueue = function() {
1748            while(queue.length) queue.shift()();
1749        };
1750        
1751        var trigger = function(ev) {
1752            for(var i = 0; i < events.length; i++) {
1753                if(events[i] == ev) {
1754                    events.splice(i, 1);
1755                    break;
1756                }
1757            }
1758            if(!events.length) {
1759                ready = true;
1760                processQueue();
1761            }
1762        };
1763
1764        var add = function(ev) {
1765			events.push(ev);
1766            ready = false;
1767        };
1768
1769        return {
1770            on: onReady,
1771            trigger: trigger,
1772            add: add,
1773            get: function() { return events.slice(0); }
1774        };
1775    };
1776
1777    utils.assignId = function(str, type) {
1778        var rando = Math.round(Math.random() * 1000000 + 1);
1779		if (str == "" || str == null) return "atvi-" + type + "-" + rando;
1780        else return str + '-' + rando;
1781    };
1782
1783    // Define onYouTubeIframeAPIReady in the global scope
1784    /*window.onYouTubeIframeAPIReady = function() {
1785        // Your existing code here
1786        console.log('YouTube API ready');
1787    };
1788
1789    //Master array to hold all videos added to page
1790    window.ATVIPageVideos = window.ATVIPageVideos || [];
1791    window.ATVIVideoAPIReady = window.ATVIVideoAPIReady || false;
1792
1793    utils.buildYoutubeVideo = function(containerId, youtubeId, configObj) {
1794
1795        var player;
1796
1797        // Move onYouTubeIframeAPIReady inside utils.buildYoutubeVideo
1798        function onYouTubeIframeAPIReady() {
1799
1800            window.ATVIVideoAPIReady = true;
1801
1802            player = new YT.Player(containerId, {
1803                videoId: youtubeId,
1804                playerVars: {
1805                    autoplay: (configObj && configObj.autoplay) ? configObj.autoplay : 0, // Autoplay disabled initially
1806                    controls: 1, // Show video controls
1807                    mute: 0,     // Mute the video initially
1808                },
1809                events: {
1810                    'onReady': function(event) {
1811                        // Optional: Handle player ready event
1812                        console.log('YouTube player ready');
1813
1814                        //Push player object to global pageVideos array to be referenced anytime
1815                        ATVIPageVideos.push({
1816
1817                            iframeId : containerId,
1818                            videoContext: player
1819
1820                        });
1821
1822                        //onPlayReady
1823                        onVideoPlayerReady(player);
1824
1825                    },
1826                    'onStateChange': function(event) {
1827                        // Optional: Handle player state changes
1828                        console.log('Player state changed:', event.data);
1829                        onVideoPlayerStateChange(event);
1830                    }
1831
1832                }
1833            });
1834
1835            //Thumbnail click
1836            var $thumbnail = $("#" + containerId).parent().find(".atvi-video-thumbnail");
1837
1838            $thumbnail.on("click", function() {
1839
1840                //Hide thumbnail, caption, and play icon
1841                $(this).hide();
1842
1843                //Play video
1844				player.playVideo();
1845
1846                //Unmute
1847				player.unMute();
1848            });
1849        }
1850
1851        // Assign onYouTubeIframeAPIReady to the global scope
1852        window.onYouTubeIframeAPIReady = onYouTubeIframeAPIReady;
1853
1854        // Check if the YouTube API is already loaded
1855        //if (typeof YT === 'undefined' || typeof YT.Player === 'undefined') {
1856        if(!window.ATVIVideoAPIReady) {
1857            // Create a script element to load the YouTube API
1858            var tag = document.createElement('script');
1859            tag.src = 'https://www.youtube.com/iframe_api';
1860
1861            // Get the first script element on the page
1862            var firstScriptTag = document.getElementsByTagName('script')[0];
1863
1864            // Insert the YouTube API script before the first script element
1865            firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
1866
1867        } else {
1868            onYouTubeIframeAPIReady();
1869        }
1870    };
1871
1872    utils.getVideoContext = function(containerId) {
1873
1874		for (let i = 0; i < ATVIPageVideos.length; i++) {
1875            if (ATVIPageVideos[i].iframeId === containerId) {
1876                return ATVIPageVideos[i].videoContext;
1877            }
1878        }
1879        return null; // Return null if containerId is not found
1880
1881    };
1882
1883    function onVideoPlayerReady(player) {
1884
1885		setInterval(() => {
1886        	let progress = (player.playerInfo.currentTime / player.playerInfo.duration) * 100;
1887            if ( (progress - Math.floor(progress)) <= 0.5) {
1888                progress = Math.floor(progress);
1889            }
1890            switch (progress) {
1891                case 1:
1892                    console.log("Video started playing from Set Interval Function");
1893                    analytics_handlePlayAnalytics("play", player.playerInfo.videoData.video_id);
1894                    break;
1895                case 25:
1896                    // Video has played 25%
1897                    console.log("Video played 25%");
1898                    analytics_handlePlayAnalytics("25%", player.playerInfo.videoData.video_id);
1899                    break;
1900                case 50:
1901                    // Video has played 50%
1902                    console.log("Video played 50%");
1903                    analytics_handlePlayAnalytics("50%", player.playerInfo.videoData.video_id);
1904                    break;
1905                case 75:
1906                    // Video has played 75%
1907                    console.log("Video played 75%");
1908                    analytics_handlePlayAnalytics("75%", player.playerInfo.videoData.video_id);
1909                    break;
1910                default:
1911                    break;
1912            } 
1913        }, (500));
1914
1915    };
1916
1917    function analytics_handlePlayAnalytics(per, youtubeID) {
1918        if (dataLayer) {
1919            dataLayer.push({
1920                video_provider: "youtube",
1921                label: youtubeID, //this needs to get replaced with the youtube ID of the video
1922                action: per == "play" ? "play" : per,
1923                event: "media",
1924                category: "media",
1925                pageURL: window.location.href,
1926                gameName: dataLayer[0].siteSection,
1927            });
1928        }
1929    };
1930
1931	function analytics_handlePauseAnalytics(youtubeID) {
1932        if (dataLayer) {
1933                dataLayer.push({
1934                video_provider: "youtube",
1935                label: youtubeID, //this needs to get replaced with the youtube ID of the video
1936                action: "pause",
1937                event: "media",
1938                category: "media",
1939                pageURL: window.location.href,
1940                gameName: dataLayer[0].siteSection,
1941            });
1942        }
1943	};
1944
1945    function analytics_handleEndAnalytics(youtubeID) {
1946        if (dataLayer) {
1947            dataLayer.push({
1948                video_provider: "youtube",
1949                label: youtubeID, //this needs to get replaced with the youtube ID of the video
1950                action: "complete",
1951                event: "media",
1952                category: "media",
1953                pageURL: window.location.href,
1954                gameName: dataLayer[0].siteSection,
1955            });
1956    	}
1957    };
1958
1959    function onVideoPlayerStateChange(event) {
1960
1961        // Calculate video progress
1962        const trackVideoProgress = (player) => {
1963            let videoDuration = player.playerInfo.duration;
1964            let currentTime = player.playerInfo.currentTime;
1965            
1966            // Calculate progress as a percentage
1967            let progress = (currentTime / videoDuration) * 100;
1968            
1969            if (progress == 1) {
1970                // Video has begun playing
1971                console.log("Video started playing in the Player State Change");
1972                analytics_handlePlayAnalytics("play", player.playerInfo.videoData.video_id);
1973            } else if (progress == 25) {
1974                // Video has played 25%
1975                console.log("Video played 25%");
1976                analytics_handlePlayAnalytics("25%", player.playerInfo.videoData.video_id);
1977            }
1978            if (progress == 50) {
1979                // Video has played 50%
1980                console.log("Video played 50%");
1981                analytics_handlePlayAnalytics("50%", player.playerInfo.videoData.video_id);
1982            }
1983            if (progress == 75) {
1984                // Video has played 75%
1985                console.log("Video played 75%");
1986                analytics_handlePlayAnalytics("75%", player.playerInfo.videoData.video_id);
1987            }
1988        };
1989
1990		if (event.data == YT.PlayerState.PLAYING) {
1991          // Video is playing
1992          trackVideoProgress(event.target);
1993        } else if (event.data == YT.PlayerState.PAUSED) {
1994          // Video is paused
1995          analytics_handlePauseAnalytics(event.target.playerInfo.videoData.video_id);
1996        } else if (event.data == YT.PlayerState.ENDED) {
1997          // Video has ended
1998          analytics_handleEndAnalytics(event.target.playerInfo.videoData.video_id);
1999        }
2000    };*/
2001
2002    /*utils.buildYoutubeEl = function(youtubeId) {
2003		var elId = utils.assignId('', 'video'),
2004            $wrapperEl = $('<div>', {'id': elId, 'class': 'atvi-video-component', 'data-youtube-id': youtubeId}),
2005            $inner = $('<div>', { 'class': 'player atvi-instrument atvi-instrument-video-player'}),
2006            $embedEl = $('<div>', {'id': elId + '-embed'}),
2007            $el = $wrapperEl.append($inner.append($embedEl)),
2008            configObj = { youtubeId: youtubeId, start: 0, customControls: false };
2009
2010		window.ATVIVideoEls = window.ATVIVideoEls || [];
2011
2012		window.ATVIVideoEls.push({
2013            $el: $el,
2014            config: configObj
2015        });
2016
2017        function generatePlayer() {
2018            ATVI.components.video.generatePlayer($el, configObj);
2019            if (!$el.find('.' + $el.attr('id') + '-embed').children().length) {
2020                setTimeout(function() {
2021                    ATVI.components.video.purgeContext($el);
2022                    ATVI.components.video.generatePlayer($el, configObj);
2023                }, 500);
2024            }
2025        }
2026
2027        ATVI.library.withDependency('atvi-video', function() {
2028            if (ATVI.components.video.YTApiReady) generatePlayer();
2029            else {
2030                document.addEventListener('youtubeApiReady', function() {
2031					generatePlayer();
2032                });
2033            }
2034        });
2035
2036        return $el;
2037    };
2038
2039    utils.purgeYoutubeEl = function($el){
2040        var i;
2041        ATVI.components.video.purgeContext($el);
2042        for (i = 0; i < window.ATVIVideoEls.length; i++) {
2043            if ($el.is(window.ATVIVideoEls[i].$el)) {
2044                window.ATVIVideoEls.splice(i, 1);
2045            }
2046        }
2047    };*/
2048
2049    utils.scrollToTarget = function($el, duration, offsetTop) {
2050
2051        var o = offsetTop || 0;
2052        var d = duration || 0;
2053
2054		$('html, body').animate({
2055          scrollTop: $el.offset().top - o
2056        }, d, function () {
2057            // Callback after animation
2058            // Must change focus!
2059            var $target = $el;
2060            $target.focus();
2061            if ($target.is(":focus")) {
2062                // Checking if the target was focused
2063                return false;
2064            } else {
2065                $target.attr("tabindex", "-1"); // Adding tabindex for elements not focusable
2066                $target.focus(); // Set focus again
2067            }
2068        });
2069
2070    };
2071
2072    utils.isInViewport = function($el) {
2073
2074        let selector = $el; 
2075        if(selector.length == 0) return false; 
2076        let elementTop = selector.offset().top;
2077        let elementBottom = elementTop + selector.outerHeight();
2078        
2079        let viewportTop = $(window).scrollTop();
2080        let viewportBottom = viewportTop + $(window).height();
2081        
2082        return elementBottom > viewportTop && elementTop < viewportBottom; //returns true or false
2083
2084    };
2085
2086    /*utils.interectObserver = function($el) {
2087
2088    	let selector = $el[0] || $el; //if passing jquery selector or js node
2089
2090		//intersection observer call back
2091    	const handleCallback = (entries) => {
2092            entries.forEach( (entry) => {
2093                //if target passes half way in viewport
2094                if (entry.intersectionRatio >= 0.5) {
2095                    const { target } = entry;
2096    
2097                    return true;
2098                }
2099            });
2100        }
2101
2102        //create new intersection observer instance
2103		let observer = new IntersectionObserver(handleCallback, {threshold: 0.5});
2104
2105        observer.observe(selector);
2106    }*/
2107
2108    utils.addPrivacyLinks = function($container) {
2109
2110        var parseRegionStr = function(r) {
2111            var str = r;
2112            if (str == null || str == "") str = "en";
2113            str = str.toLowerCase().replace("-", "_").replace("en_us", "en");
2114    
2115            return str;
2116        };
2117
2118        var ld = ATVI.localeDetector;
2119
2120        //Get page region
2121        var region = parseRegionStr($('html').attr("lang"));
2122
2123        //Set locale for Granite i18n library
2124        Granite.I18n.setLocale(region);
2125
2126        //Declare which i18n keys we want translations for
2127        var yourPrivacyChoiceKey = "global.footer.label.yourPrivacyChoices";
2128        var caPrivacyNoticeKey = "global.caPrivacyNotice";
2129
2130        //Get translations from the keys
2131        var yourPrivacyChoicesText = Granite.I18n.get(yourPrivacyChoiceKey);
2132        var caPrivacyNoticeText = Granite.I18n.get(caPrivacyNoticeKey);
2133
2134        //If for some reason, it can't get i18n translation from keys, then default them to their EN strings
2135        if(yourPrivacyChoicesText == yourPrivacyChoiceKey) yourPrivacyChoicesText = "Your Privacy Choices";
2136        if(caPrivacyNoticeText == caPrivacyNoticeKey) caPrivacyNoticeText = "California Privacy Notice";
2137
2138        //If user is in California, Colorado, Virginia, Connecticut, Utah, Oregon, Texas, Florida, Montana, Iowa, Delaware, Nebraska, New Hampshire, Tennessee, Minnesota, Maryland
2139        const validRegions = ['ca', 'co', 'va', 'ct', 'ut', 'or', 'tx', 'fl', 'mt', 'ia', 'de', 'ne', 'nh', 'nj', 'tn', 'mn', 'md', 'in', 'ky', 'ri'];
2140
2141        if (ld.region && validRegions.includes(ld.region)) {
2142            var anchor = $('<a/>', {
2143                'href': 'https://support.activision.com/privacy/request?st=' + ld.region,
2144                'text': yourPrivacyChoicesText,
2145                'target': '_blank'
2146            });
2147            var item = $('<li/>', { 'class': 'privacy-check' });
2148            item.append(anchor);
2149            $container.append(item);
2150        }
2151        else {
2152            var anchor = $('<a/>', {
2153                'href': 'https://support.activision.com/privacy',
2154                'text': yourPrivacyChoicesText,
2155                'target': '_blank'
2156            });
2157            var item = $('<li/>', { 'class': 'privacy-check' });
2158            item.append(anchor);
2159            $container.append(item);
2160
2161			/*document.addEventListener('localeDetectionReady', function() {
2162
2163                if (ld.region && validRegions.includes(ld.region)) {
2164                    var anchor = $('<a/>', {
2165                        'href': 'https://support.activision.com/privacy/request?st=' + ld.region,
2166                        'text': yourPrivacyChoicesText,
2167                        'target': '_blank'
2168                    });
2169                    var item = $('<li/>', { 'class': 'privacy-check' });
2170                    item.append(anchor);
2171                    $container.append(item);
2172                }
2173            });*/
2174        }
2175
2176        //If user is in California
2177        if(ld.region && ld.region == 'ca') {
2178			var anchor = $('<a/>', { 
2179                	'href':'https://www.activision.com/legal/privacy-policy#toc10b', 
2180                	'text': caPrivacyNoticeText, 
2181                	'target': '_blank' 
2182            }),
2183            item = $('<li/>'); 
2184            item.append(anchor);
2185            $container.append(item);
2186        }
2187        else {
2188			document.addEventListener('localeDetectionReady', function() {
2189                if (ld.region == 'ca') {
2190					var anchor = $('<a/>', { 
2191                        'href':'https://www.activision.com/legal/privacy-policy#toc10b', 
2192                        'text': caPrivacyNoticeText, 
2193                        'target': '_blank' }),
2194                    item = $('<li/>'); 
2195                    item.append(anchor);
2196                    $container.append(item);
2197                }
2198            });
2199        }
2200
2201    };
2202
2203    utils.getElementMarkup = async function(url, selector) {
2204        try {
2205            // Fetch the HTML of the page
2206            const response = await fetch(url);
2207    
2208            // Ensure the request was successful
2209            if (!response.ok) {
2210                throw new Error(`Failed to fetch page: ${response.statusText}`);
2211            }
2212    
2213            // Get the HTML text
2214            const htmlText = await response.text();
2215    
2216            // Parse the HTML string into a document
2217            const parser = new DOMParser();
2218            const doc = parser.parseFromString(htmlText, 'text/html');
2219    
2220            // Query the specified element
2221            const element = doc.querySelector(selector);
2222    
2223            // Return the element's outer HTML, or null if not found
2224            return element ? element.outerHTML : null;
2225        } catch (error) {
2226            console.error(error);
2227            return null;
2228        }
2229    };
2230
2231    utils.initSSO = function(obj = {}) {
2232
2233        /* sample obj input 
2234        obj = {
2235            domain: "atvi",
2236            login: ${".sso-login"),
2237            signUp: ${".sso-signup"),
2238            profile: ${".sso-profile"),
2239            logOut: ${".sso-logout"),
2240            username: ${"#username")
2241		}
2242        */
2243
2244        const {
2245            login,
2246            signUp,
2247            profile,
2248            logOut,
2249            username = $("#username")
2250        } = obj;
2251
2252		const apiOrigin = ATVI.utils.getSSOOrigin();
2253
2254        // Update SSO links
2255        const links = {
2256            login:  login?.attr("href", ATVI.utils.getSSOLink("login")),
2257            signup: signUp?.attr("href", ATVI.utils.getSSOLink("signup")),
2258            profile: profile?.attr("href", ATVI.utils.getSSOLink("profile")),
2259            logout: logOut?.attr("href", ATVI.utils.getSSOLink("logout"))
2260        };
2261
2262        // Reflect login state
2263        const loggedIn = ATVI.utils.isLoggedIn();
2264        $("body").toggleClass("sso-logged-in", loggedIn)
2265                 .toggleClass("sso-logged-out", !loggedIn);
2266    
2267        // Fetch and set username asynchronously
2268        if (username && username.length > 0) {
2269            ATVI.utils.setSSOUsername().then(userName => {
2270                if (userName) username.text(userName);
2271            });
2272
2273        }
2274
2275    };
2276
2277    utils.getEnv = function() {
2278        const url = window.location.href;
2279        if (url.includes("stage.")) return "stage";
2280        if (url.includes("cmsauthor.") || url.includes("preview.") || url.includes("test.")) return "dev";
2281        return "prod";
2282    };
2283    
2284    utils.getSSOOrigin = function() {
2285        switch (ATVI.utils.getEnv()) {
2286            case "stage": return "https://stage-xo-client.activision.com";
2287            case "dev": 
2288            	if(window.location.href.includes("/ko/transactions")) return "https://xo-client.activision.com";
2289            	else return "https://dev-xo-client.activision.com";
2290            default:      return "https://xo-client.activision.com";
2291        }
2292    };
2293    
2294    utils.getSSOPrefix = function() {
2295        switch (ATVI.utils.getEnv()) {
2296            case "stage": return "s-stage";
2297            case "dev":   
2298                if(window.location.href.includes("/ko/transactions")) return "s";
2299                else return "s-dev";
2300            default:      return "s";
2301        }
2302    };
2303    
2304    utils.getSSOCookies = function() {
2305        return {
2306            ssoCookie: ATVI.utils.getCookie("ACT_SSO_COOKIE"),
2307            atkn: ATVI.utils.getCookie("X-xo-atkn"),
2308            rtkn: ATVI.utils.getCookie("X-xo-rtkn")
2309        };
2310    };
2311
2312    utils.setSSOUsername = function(cb) {
2313
2314    	return new Promise((resolve, reject) => {
2315            if (!ATVI.utils.isLoggedIn()) {
2316                ATVI.utils.logUserOut();
2317                return resolve(null);
2318            }
2319
2320            const apiOrigin = ATVI.utils.getSSOOrigin();
2321            const { ssoCookie, atkn, rtkn } = ATVI.utils.getSSOCookies();
2322
2323            if(ssoCookie && atkn && rtkn) {
2324                $.ajax({
2325                    url: `${apiOrigin}/profile/v1`,
2326                    method: "GET",
2327                    headers: {
2328                        "ACT_SSO_COOKIE": ssoCookie,
2329                        "X-xo-atkn": atkn,
2330                        "X-xo-rtkn": rtkn
2331                    }
2332                })
2333                .done(response => {
2334    
2335                    ATVI.utils.userInfo = response;
2336    
2337                    resolve(response?.userName || null);
2338                })
2339                .fail(xhr => {
2340                    if (xhr.status === 401 || xhr.status === 403) ATVI.utils.logUserOut();
2341                    reject(xhr);
2342                });
2343    
2344    		}
2345        });
2346
2347    };
2348
2349    utils.logUserOut = function() {
2350        ATVI.utils.deleteCookie("ACT_SSO_COOKIE");
2351        ATVI.utils.deleteCookie("X-xo-atkn");
2352        ATVI.utils.deleteCookie("X-xo-rtkn");
2353        $("body").removeClass("sso-logged-in").addClass("sso-logged-out");    
2354    };
2355
2356    utils.isLoggedIn = function() {
2357
2358        if(window.location.href.includes("support.")) {
2359			const { ssoCookie } = ATVI.utils.getSSOCookies();
2360            return !!(ssoCookie);
2361        }
2362
2363        else {
2364            const { ssoCookie, atkn, rtkn } = ATVI.sso.getSSOCookies();
2365            return !!(ssoCookie && atkn && rtkn);
2366        }
2367
2368    };
2369
2370	utils.getSSOLink = function(key) {
2371
2372        let envPrefix = ATVI.sso.getSSOPrefix();
2373        const apiOrigin = ATVI.sso.getSSOOrigin();
2374        const currentUrl = encodeURIComponent(window.location.href);
2375    
2376        let locale = (ATVI.pageLocale || "en").replace("-", "_").toLowerCase();
2377        if (locale === "fr_lu") locale = "fr";
2378    
2379        const urls = {
2380            login:  `${apiOrigin}/auth/v1/xLogin/init?redirectUrl=${currentUrl}&locale=${locale}`,
2381            logout: `${apiOrigin}/auth/v1/xLogout?redirectUrl=${currentUrl}`,
2382            signup: "",
2383            profile: ""
2384        };
2385    
2386        const href = window.location.href;
2387    
2388        let brand = "activision";
2389        if (href.includes("crashbandicoot.com") || href.includes("/content/atvi/crash")) {
2390            brand = "crash";
2391        } else if (href.includes("tonyhawkthegame.com") || href.includes("/content/atvi/tony-hawk")) {
2392            brand = "tonyhawk";
2393        } else if (href.includes("callofduty.com") || href.includes("/content/atvi/callofduty")) {
2394            brand = "cod";
2395        }
2396
2397        const redirectMap = {
2398            activision: "https://www.activision.com",
2399            cod: "https://www.callofduty.com",
2400            crash: "https://www.crashbandicoot.com",
2401            tonyhawk: "https://www.tonyhawkthegame.com"
2402        };
2403    
2404        const signupRedirect = encodeURIComponent(redirectMap[brand]);
2405
2406        urls.signup = `https://profile.activision.com/signup?redirectUrl=${signupRedirect}`;
2407
2408        const baseDomains = {
2409            activision: "activision.com/activision",
2410            crash: "crashbandicoot.com/crash",
2411            tonyhawk: "tonyhawkthegame.com/th",
2412            cod: "callofduty.com/cod"
2413        };
2414    
2415        const prefixMap = {
2416            "s-dev": "profile-dev",
2417            "s-stage": "profile-stage",
2418            "s": "profile"
2419        };
2420
2421		if (brand === "cod" && prefixMap[envPrefix]) {
2422            envPrefix = prefixMap[envPrefix]; // this will give profile link a prefix of profile-dev, or profile-stage, or profile
2423        }
2424
2425		//urls.profile = `https://${envPrefix}.${baseDomains[brand]}/profile`;
2426
2427
2428        if (prefixMap[envPrefix] && key == "signup") {
2429            envPrefix = prefixMap[envPrefix];
2430            urls.signup  = `https://${envPrefix}.activision.com/signup?redirectUrl=${signupRedirect}`;
2431        }
2432
2433        //urls.signup  = `https://${envPrefix}.activision.com/signup?redirectUrl=${signupRedirect}`;
2434        urls.profile = `https://${envPrefix}.${baseDomains[brand]}/profile`;
2435    
2436        return urls[key] || "";
2437    };
2438
2439    /*utils.getSSOLink = function(key) {
2440
2441        const envPrefix = ATVI.utils.getSSOPrefix();
2442        const apiOrigin = ATVI.utils.getSSOOrigin();
2443        const currentUrl = encodeURIComponent(window.location.href);
2444        let locale = (ATVI.pageLocale || "en").replace("-", "_").toLowerCase();
2445        if(locale == "fr_lu") locale = "fr"; 
2446
2447        const urls = {
2448            login:  `${apiOrigin}/auth/v1/xLogin/init?redirectUrl=${currentUrl}&locale=${locale}`,
2449            logout: `${apiOrigin}/auth/v1/xLogout?redirectUrl=${currentUrl}`,
2450            signup: "",
2451            profile: ""
2452        };
2453
2454        const baseDomains = {
2455            activision: "activision.com/activision",
2456            crash: "crashbandicoot.com/crash",
2457            tonyhawk: "tonyhawkthegame.com/th"
2458        };
2459
2460        let brand = "activision";
2461        const href = window.location.href;
2462        if (href.includes("crashbandicoot.com") || href.includes("/content/atvi/crash")) brand = "crash";
2463        else if (href.includes("tonyhawkthegame.com") || href.includes("/content/atvi/tony-hawk")) brand = "tonyhawk";
2464    
2465        urls.signup  = `https://${envPrefix}.${baseDomains[brand]}/signup`;
2466        urls.profile = `https://${envPrefix}.${baseDomains[brand]}/profile`;
2467    
2468        return urls[key] || "";
2469
2470    };*/
2471
2472
2473})(jQuery, ATVI);
2474
2475window.ATVI = window.ATVI || {};
2476
2477// atvi-sso
2478
2479(function($, ATVI) {
2480
2481    var sso = ATVI.sso = {};
2482
2483    sso.init = function(obj = {}) {
2484
2485        /* sample obj input 
2486        obj = {
2487            domain: "atvi",
2488            login: ${".sso-login"),
2489            signUp: ${".sso-signup"),
2490            profile: ${".sso-profile"),
2491            logOut: ${".sso-logout"),
2492            username: ${"#username")
2493		}
2494        */
2495
2496        const {
2497            login,
2498            signUp,
2499            profile,
2500            logOut,
2501            username = $("#username")
2502        } = obj;
2503
2504		const apiOrigin = ATVI.sso.getSSOOrigin();
2505
2506        // Update SSO links
2507        const links = {
2508            login:  login?.attr("href", ATVI.sso.getSSOLink("login")),
2509            signup: signUp?.attr("href", ATVI.sso.getSSOLink("signup")),
2510            profile: profile?.attr("href", ATVI.sso.getSSOLink("profile")),
2511            logout: logOut?.attr("href", ATVI.sso.getSSOLink("logout"))
2512        };
2513
2514        // Reflect login state
2515        const loggedIn = ATVI.sso.isLoggedIn();
2516        $("body").toggleClass("sso-logged-in", loggedIn)
2517                 .toggleClass("sso-logged-out", !loggedIn);
2518
2519        // Set user info
2520        if(loggedIn) ATVI.sso.setUserInfo(username);
2521    
2522        // Fetch and set username asynchronously
2523        /*if (username && username.length > 0) {
2524            ATVI.sso.setSSOUsername().then(userName => {
2525                if (userName) username.text(userName);
2526            });
2527
2528        }*/
2529
2530    };
2531
2532    sso.getEnv = function() {
2533        const url = window.location.href;
2534        if (url.includes("stage.")) return "stage";
2535        if (url.includes("cmsauthor.") || url.includes("preview.") || url.includes("test.")) return "dev";
2536        return "prod";
2537    };
2538
2539    sso.getSSOOrigin = function() {
2540        switch (ATVI.sso.getEnv()) {
2541            case "stage": return "https://stage-xo-client.activision.com";
2542            case "dev": 
2543            	if(window.location.href.includes("/ko/transactions")) return "https://xo-client.activision.com";
2544            	else return "https://dev-xo-client.activision.com";
2545            default:      return "https://xo-client.activision.com";
2546        }
2547    };
2548    
2549    sso.getSSOPrefix = function() {
2550        switch (ATVI.sso.getEnv()) {
2551            case "stage": return "s-stage";
2552            case "dev":   
2553                if(window.location.href.includes("/ko/transactions")) return "s";
2554                else return "s-dev";
2555            default:      return "s";
2556        }
2557    };
2558    
2559    sso.getSSOCookies = function() {
2560        return {
2561            ssoCookie: ATVI.utils.getCookie("ACT_SSO_COOKIE"),
2562            atkn: ATVI.utils.getCookie("X-xo-atkn"),
2563            rtkn: ATVI.utils.getCookie("X-xo-rtkn")
2564        };
2565    };
2566
2567    sso.setSSOUsername = function(cb) {
2568
2569    	return new Promise((resolve, reject) => {
2570            if (!ATVI.sso.isLoggedIn()) {
2571                ATVI.sso.logUserOut();
2572                return resolve(null);
2573            }
2574
2575            const apiOrigin = ATVI.sso.getSSOOrigin();
2576            const { ssoCookie, atkn, rtkn } = ATVI.sso.getSSOCookies();
2577
2578            if(ssoCookie && atkn && rtkn) {
2579                $.ajax({
2580                    url: `${apiOrigin}/profile/v1`,
2581                    method: "GET",
2582                    headers: {
2583                        "ACT_SSO_COOKIE": ssoCookie,
2584                        "X-xo-atkn": atkn,
2585                        "X-xo-rtkn": rtkn
2586                    }
2587                })
2588                .done(response => {
2589    
2590                    ATVI.sso.userInfo = response;
2591    
2592                    resolve(response?.userName || null);
2593                })
2594                .fail(xhr => {
2595                    if (xhr.status === 401 || xhr.status === 403) ATVI.sso.logUserOut();
2596                    reject(xhr);
2597                });
2598    
2599    		}
2600        });
2601
2602    };
2603
2604    sso.setUserInfo = function(username) {
2605
2606		let apiOrigin = ATVI.sso.getSSOOrigin();
2607        let { ssoCookie, atkn, rtkn } = ATVI.sso.getSSOCookies();
2608
2609        if(ssoCookie && atkn && rtkn) {
2610                $.ajax({
2611                    url: `${apiOrigin}/profile/v1`,
2612                    method: "GET",
2613                    headers: {
2614                        "ACT_SSO_COOKIE": ssoCookie,
2615                        "X-xo-atkn": atkn,
2616                        "X-xo-rtkn": rtkn
2617                    }
2618                })
2619                .done(response => {
2620
2621                    ATVI.sso.userInfo = response;
2622
2623                    //trigger custom event and pass data
2624            		$(document).trigger("sso:userInfoReady", [response]);
2625
2626                    //Set username in username element
2627                    if (username && username.length > 0) {
2628						username.text(response.userName);
2629                	}
2630                })
2631                .fail(xhr => {
2632                    $(document).trigger("sso:userInfoError", [xhr]);
2633                });
2634    
2635   		}
2636
2637    };
2638
2639    sso.logUserOut = function() {
2640        ATVI.utils.deleteCookie("ACT_SSO_COOKIE");
2641        ATVI.utils.deleteCookie("X-xo-atkn");
2642        ATVI.utils.deleteCookie("X-xo-rtkn");
2643        $("body").removeClass("sso-logged-in").addClass("sso-logged-out");    
2644    };
2645
2646    sso.isLoggedIn = function() {
2647
2648        if(window.location.href.includes("support.")) {
2649			const { ssoCookie } = ATVI.sso.getSSOCookies();
2650            return !!(ssoCookie);
2651        }
2652
2653        else {
2654            const { ssoCookie, atkn, rtkn } = ATVI.sso.getSSOCookies();
2655            return !!(ssoCookie && atkn && rtkn);
2656        }
2657
2658    };
2659
2660    /*sso.getSSOLink = function(key) {
2661
2662        let envPrefix = ATVI.sso.getSSOPrefix();
2663        const apiOrigin = ATVI.sso.getSSOOrigin();
2664        const currentUrl = encodeURIComponent(window.location.href);
2665        let locale = (ATVI.pageLocale || "en").replace("-", "_").toLowerCase();
2666        if(locale == "fr_lu") locale = "fr"; 
2667
2668        const urls = {
2669            login:  `${apiOrigin}/auth/v1/xLogin/init?redirectUrl=${currentUrl}&locale=${locale}`,
2670            logout: `${apiOrigin}/auth/v1/xLogout?redirectUrl=${currentUrl}`,
2671            signup: "",
2672            profile: ""
2673        };
2674
2675        const baseDomains = {
2676            activision: "activision.com/activision",
2677            crash: "crashbandicoot.com/crash",
2678            tonyhawk: "tonyhawkthegame.com/th",
2679            cod: "callofduty.com/cod"
2680        };
2681
2682        let brand = "activision";
2683        const href = window.location.href;
2684        if (href.includes("crashbandicoot.com") || href.includes("/content/atvi/crash")) brand = "crash";
2685        else if (href.includes("tonyhawkthegame.com") || href.includes("/content/atvi/tony-hawk")) brand = "tonyhawk";
2686		else if (href.includes("callofduty.com") || href.includes("/contenta/atvi/callofduty")) brand = "cod";
2687
2688		//cod specific
2689		const prefixMap = {
2690          "s-dev": "profile-dev",
2691          "s-stage": "profile-stage",
2692          "s": "profile"
2693        };
2694        
2695        if (brand === "cod" && prefixMap[envPrefix]) {
2696          envPrefix = prefixMap[envPrefix];
2697        }
2698
2699        urls.signup  = `https://${envPrefix}.${baseDomains[brand]}/signup`;
2700        urls.profile = `https://${envPrefix}.${baseDomains[brand]}/profile`;
2701    
2702        return urls[key] || "";
2703
2704    };*/
2705
2706	sso.getSSOLink = function(key) {
2707
2708        let envPrefix = ATVI.sso.getSSOPrefix();
2709        const apiOrigin = ATVI.sso.getSSOOrigin();
2710        const currentUrl = encodeURIComponent(window.location.href);
2711    
2712        let locale = (ATVI.pageLocale || "en").replace("-", "_").toLowerCase();
2713        if (locale === "fr_lu") locale = "fr";
2714    
2715        const urls = {
2716            login:  `${apiOrigin}/auth/v1/xLogin/init?redirectUrl=${currentUrl}&locale=${locale}`,
2717            logout: `${apiOrigin}/auth/v1/xLogout?redirectUrl=${currentUrl}`,
2718            signup: "",
2719            profile: ""
2720        };
2721    
2722        const href = window.location.href;
2723    
2724        let brand = "activision";
2725        if (href.includes("crashbandicoot.com") || href.includes("/content/atvi/crash")) {
2726            brand = "crash";
2727        } else if (href.includes("tonyhawkthegame.com") || href.includes("/content/atvi/tony-hawk")) {
2728            brand = "tonyhawk";
2729        } else if (href.includes("callofduty.com") || href.includes("/content/atvi/callofduty")) {
2730            brand = "cod";
2731        }
2732
2733        const redirectMap = {
2734            activision: "https://www.activision.com",
2735            cod: "https://www.callofduty.com",
2736            crash: "https://www.crashbandicoot.com",
2737            tonyhawk: "https://www.tonyhawkthegame.com"
2738        };
2739    
2740        const signupRedirect = encodeURIComponent(redirectMap[brand]);
2741
2742        urls.signup = `https://profile.activision.com/signup?redirectUrl=${signupRedirect}`; //default prod
2743
2744        const baseDomains = {
2745            activision: "activision.com/activision",
2746            crash: "crashbandicoot.com/crash",
2747            tonyhawk: "tonyhawkthegame.com/th",
2748            cod: "callofduty.com/cod"
2749        };
2750    
2751        const prefixMap = {
2752            "s-dev": "profile-dev",
2753            "s-stage": "profile-stage",
2754            "s": "profile"
2755        };
2756
2757        if (prefixMap[envPrefix] && key == "signup") {
2758			envPrefix = prefixMap[envPrefix];
2759            urls.signup = `https://${envPrefix}.activision.com/signup?redirectUrl=${signupRedirect}`;
2760        }
2761
2762        else if (brand == "cod" && prefixMap[envPrefix] && key == "signup") {
2763            envPrefix = prefixMap[envPrefix];
2764            urls.signup = `https://${envPrefix}.activision.com/signup?redirectUrl=${signupRedirect}`;
2765        }
2766
2767		else if (brand === "cod" && prefixMap[envPrefix]) {
2768            envPrefix = prefixMap[envPrefix]; // this will give profile link a prefix of profile-dev, or profile-stage, or profile
2769        }
2770
2771		urls.profile = `https://${envPrefix}.${baseDomains[brand]}/profile`;
2772
2773
2774        /*if (prefixMap[envPrefix]) {
2775            envPrefix = prefixMap[envPrefix];
2776        }
2777
2778        urls.signup  = `https://${envPrefix}.activision.com/signup?redirectUrl=${signupRedirect}`;
2779        urls.profile = `https://${envPrefix}.${baseDomains[brand]}/profile`;*/
2780    
2781        return urls[key] || "";
2782    };
2783
2784})(jQuery, ATVI);
2785window.ATVI = window.ATVI || {};
2786ATVI.components = ATVI.components || {};
2787
2788var dataLayer = dataLayer || undefined,
2789    digitalData = digitalData || undefined;
2790
2791ATVI.franchiseMap = {
2792    vanguard: "vgd",
2793    blackopscoldwar: "bocw",
2794    modernwarfare: "mw",
2795    modernwarfare2: "mw2",
2796    modernwarfare3: "mw3",
2797    warzone: "wz",
2798    warzone2: "wz",
2799    warzonemobile: "wzm",
2800    tonyhawkthegame: "thps",
2801    alcatraz: "thps",
2802    crash: "crash",
2803    "/crash/quantum": "crash 4",
2804    crash4: "crash 4",
2805    lava: "rumble",
2806    crashontherun: "crash on the run",
2807    crashteamracing: "crash team racing",
2808    "nsane-trilogy": "nsane trilogy",
2809    sekirothegame: "sekiro",
2810    spyrothedragon: "spyro rt",
2811    "/1+2": "thps-1-2",
2812    "/3+4": "thps-3-4",
2813};
2814
2815ATVI.dataLayerGameName = "";
2816
2817(function ($, ATVI) {
2818    var url = window.location.href,
2819        franchises = Object.keys(ATVI.franchiseMap),
2820        i;
2821
2822    for (i = 0; i < franchises.length; i++) {
2823        if (url.indexOf(franchises[i]) > -1) {
2824            ATVI.dataLayerGameName = ATVI.franchiseMap[franchises[i]];
2825        }
2826    }
2827    // NOTE: Should we continue to default to cod or modify the code/site map to give better results?
2828    if (!ATVI.dataLayerGameName) ATVI.dataLayerGameName = "cod";
2829
2830    ATVI.definePageView = function () {
2831        if (!digitalData) return;
2832        var url = window.location.href;
2833
2834        if (
2835            //url.indexOf("stage.callofduty.com") > -1 ||
2836            url.indexOf("callofduty.com/store") > -1
2837        )
2838            return;
2839        var d = digitalData.page,
2840            obj = {},
2841            siteSubsectionStr = d.pageInfo.siteSubsection;
2842        if (
2843            siteSubsectionStr == "hub" &&
2844            ATVI.dataLayerGameName.indexOf("crash") > -1
2845        )
2846            siteSubsectionStr = "home";
2847        if (d.pageInfo.pageName.indexOf("callofduty:store:bundles:") >= 0)
2848            siteSubsectionStr = "bundles";
2849        obj.event = "pageView";
2850        obj.site = d.pageInfo.site;
2851        obj.siteSection = d.pageInfo.siteSection;
2852        obj.siteSubsection = siteSubsectionStr;
2853        obj.pageType = d.pageCategory.pageType;
2854        obj.pageName = d.pageInfo.pageName;
2855        obj.name = d.targetEntity.name;
2856        obj.description = d.targetEntity.description;
2857        //obj.pageURL = d.targetEntity.pageURL;
2858        obj.pageURL = window.location.href;
2859        obj.country = d.pageInfo.country;
2860        obj.locale = d.targetEntity.locale;
2861        obj.language = d.pageInfo.language;
2862        obj.charSet = d.pageInfo.charSet;
2863        obj.skill = d.targetEntity.skill;
2864
2865        /*if(url.includes("callofduty")) {
2866        	obj.loggedIn = (ATVI.utils.getCookie("ACT_SSO_COOKIE") && ATVI.utils.getCookie("atkn")) ? true : false;
2867        }
2868        else {
2869
2870        	obj.loggedIn = ATVI.sso.isLoggedIn();
2871        }*/
2872        //obj.loggedIn = ATVI.utils.getCookie("ACT_SSO_COOKIE") ? true : false;
2873        obj.loggedIn = ATVI.sso.isLoggedIn();
2874
2875        //cod store only
2876        if (url.indexOf("callofduty.com") > 0 && url.indexOf("/store") > 0)
2877            obj.event = "page_view";
2878
2879
2880
2881        //CODE
2882        if (digitalData.page.pageInfo.siteSection == "endowment") {
2883            obj.site = "endowment";
2884            obj.siteSubsection = digitalData.page.pageInfo.siteSubsection;
2885            obj.siteSection = digitalData.page.pageInfo.siteSubsection;
2886
2887            if (
2888                obj.siteSubsection == "about" ||
2889                obj.siteSubsection == "leadership" ||
2890                obj.siteSubsection == "our_founding_story"
2891            )
2892                obj.siteSection = "about";
2893            else if (
2894                obj.siteSubsection == "veteran_support" ||
2895                obj.siteSubsection == "us_veteran_support" ||
2896                obj.siteSubsection == "uk_veteran_support" ||
2897                obj.siteSubsection == "veteran_testimonials" ||
2898                obj.siteSubsection == "research"
2899            )
2900                obj.siteSection = "veterans";
2901            else if (
2902                obj.siteSubsection == "media_center" ||
2903                obj.siteSubsection == "in_the_news" ||
2904                obj.siteSubsection == "blog" ||
2905                obj.siteSubsection == "awards"
2906            )
2907                obj.siteSection = "news";
2908            else if (window.location.href.indexOf("awards") > -1)
2909                obj.siteSection = "awards";
2910
2911            if (obj.siteSubsection == "about")
2912                obj.siteSubsection = "our mission";
2913        }
2914
2915        //COD BRAND
2916        if (digitalData.page.pageInfo.siteSection == "brand") {
2917            if (
2918                digitalData.page.pageInfo.siteSubsection ==
2919                    "logos-and-wordmark" ||
2920                digitalData.page.pageInfo.siteSubsection == "media-center"
2921            ) {
2922                obj.siteSubsection = "home";
2923                obj.pageType = "home";
2924            }
2925
2926            if (
2927                digitalData.page.pageInfo.siteSubsection == "typeface" ||
2928                digitalData.page.pageInfo.siteSubsection ==
2929                    "building-creative" ||
2930                digitalData.page.pageInfo.siteSubsection == "types-in-use"
2931            ) {
2932                obj.siteSubsection = "typography";
2933            }
2934        }
2935
2936        //THPS
2937        if (digitalData.page.pageInfo.site == "tony-hawk") {
2938            if (digitalData.page.pageInfo.siteSection == "alcatraz-v2") {
2939                obj.siteSection = "thps-1-2";
2940            }
2941
2942            if (digitalData.page.pageInfo.siteSection == "chicago") {
2943                obj.siteSection = "thps-3-4";
2944            }
2945        }
2946
2947        //PROMOTIONS: VERDANSK REPLAY / BETA STATS CAMPAIGN
2948        if (digitalData.page.pageInfo.siteSection === "promotions") {
2949            if (
2950                digitalData.page.targetEntity.pageURL.includes(
2951                    "verdansk-replay"
2952                ) ||
2953                digitalData.page.targetEntity.pageURL.includes("verdanskreplay")
2954            ) {
2955                obj.pageName = "callofduty:promotions:verdansk-replay:home";
2956            }
2957            if (
2958                digitalData.page.targetEntity.pageURL.includes(
2959                    "bo7-beta-stats"
2960                ) ||
2961                digitalData.page.targetEntity.pageURL.includes("bo7betastats")
2962            ) {
2963                obj.pageName = "callofduty:promotions:home";
2964            }
2965        }
2966
2967        //WARZONE
2968        if (digitalData.page.pageInfo.siteSection === "warzone2") {
2969            obj.siteSection = "warzone";
2970        }
2971
2972        $(window).on("load", function() {
2973
2974            //If logged in
2975            if(obj.loggedIn) {
2976
2977                var id;
2978
2979                //if on cod site
2980                if(url.includes("callofduty")) {
2981
2982                    //check if sso identities is available
2983                    if (Array.isArray(ssobar?.user?.identities)) {
2984
2985                        //get provider that equals to uno
2986                        const unoIdentity = ssobar.user.identities.find(id => id.provider === "uno");
2987
2988                        //if uno id is available
2989                        if (unoIdentity?.accountID) {
2990                            id = unoIdentity.accountID;
2991                            hashId(id);
2992                        }
2993    
2994                    }
2995    
2996                }
2997                else {
2998
2999                    //if on support atvi site
3000                    if(window.location.href.includes("support.activision")) {
3001						hashId();
3002                    }
3003
3004                    else {                
3005
3006                        if(ATVI.sso.userInfo) {
3007							hashId(ATVI.sso.userInfo.unoID);
3008                        }
3009                        else {
3010							hashId();
3011                        }
3012
3013                    }
3014                }
3015
3016            }
3017
3018            else {
3019            	//Push to data layer once page is fully loaded
3020     			dataLayer.push(obj);  
3021            }
3022
3023		});
3024
3025        function hashId(id) {
3026
3027            if(id) {
3028
3029                var salt = "ATVI_SALT";
3030                var saltedId = `${salt}:${id}`; // Concatenate UnoID and salt with colon
3031        
3032                var encoder = new TextEncoder();
3033
3034                var data = encoder.encode(saltedId);
3035
3036                window.crypto.subtle.digest("SHA-256", data)
3037                    .then((hashBuffer) => {
3038                        // Convert digest to hex string first
3039                        const hashArray = Array.from(new Uint8Array(hashBuffer));
3040                        const hexString = hashArray
3041                          .map((b) => b.toString(16).padStart(2, "0"))
3042                          .join("");
3043
3044                        // Then base64-encode that hex string
3045                        const base64String = btoa(hexString);
3046                        const base64NoPadding = base64String.replace(/=+$/, "");
3047
3048                        obj.userId = base64NoPadding; 
3049        
3050                        // Push to data layer
3051                        dataLayer.push(obj);
3052                    })
3053                    .catch((error) => {
3054                        console.error("Hashing error:", error);
3055                    });
3056    
3057            }
3058            else {
3059				dataLayer.push(obj);
3060            }
3061        
3062        }
3063
3064        //Logged In
3065        var loggedInObj = {};
3066
3067        loggedInObj.event = "login";
3068        loggedInObj.category = "sso";
3069    };
3070
3071    ATVI.definePageView();
3072})(jQuery, ATVI);
3073
3074// add callback methods for any components affected by cookie acceptance/denial changes
3075window.onload = () => {
3076    ATVI.cookiesAccepted = window.OptanonActiveGroups;
3077    document.addEventListener('OneTrustGroupsUpdated', function() {
3078        if (ATVI.components.video) ATVI.components.video.handleOptanonChange();
3079		ATVI.cookiesAccepted = window.OptanonActiveGroups;
3080    });
3081};
3082
3083
3084// banner pop up
3085(function() { 
3086
3087    var init = function() {
3088
3089        //var enableBanner = false;
3090        var banner = $(".atvi-privacy-policy-module"); //set to banner that needs to be active
3091        var cookieName = "atvi-pp"; //name of cookie to check. Change name slightly each time a new update goes live
3092
3093        //if(typeof ATVI.utils.getCookie(cookieName) == "undefined" && enableBanner == true) {
3094        if(typeof ATVI.utils.getCookie(cookieName) == "undefined") {
3095
3096            if(banner.length) {
3097                banner.addClass("show");
3098
3099    			var btn = banner.find(".close-modal");
3100                btn.click(function(e){
3101                    banner.removeClass("show");
3102    				$(this).attr("tabindex","-1");
3103                    setCookie(cookieName);
3104                });
3105            }
3106
3107        }
3108
3109    };
3110
3111    var setCookie = function(cName) {
3112		ATVI.utils.setCookie(cName, true, {expireDate: (3600 * 24 * 365)});
3113    };
3114
3115    $(init);
3116
3117})();
3118
3119
3120
3121
3122(function($, ATVI) {
3123
3124    var lib = ATVI.library = {};
3125
3126    var dependencies = {
3127        jScrollPane: "basic-ui"
3128    };
3129
3130    var loaded = {};
3131    var onLoadHandlers = {};
3132    var loading = {};
3133
3134    lib.registerLibrary = function(n) {
3135		loaded[n] = true;
3136		getOnLoadQueue(n).trigger("load");
3137        var q = loading[n] || [];
3138        while(q.length) {
3139			q.shift()();
3140        }
3141    };
3142
3143    lib.loadDependencies = function() {
3144        for(var i = 0; i < arguments.length; i++) {
3145			lib.withDependency(arguments[i]);
3146        }
3147    };
3148
3149    lib.withDependency = function(deps, enableCookies = false, callback) {
3150        var i, library, types = "";
3151        if($.isArray(deps)) {
3152			var evs = [];
3153            for(i = 0; i < deps.length; i++) {
3154                var dep = deps[i];
3155                var depName = typeof dep == "object" ? dep.name : dep;
3156				if(evs.indexOf(depName) >= 0) continue;
3157                var library = dependencies[depName] || depName;
3158                if(loaded[library]) continue;
3159                evs.push(dep);
3160            }
3161            if(!evs.length) {
3162				if(callback) callback();
3163                return;
3164            }
3165			var q = ATVI.utils.createReadyQueue(evs);
3166            if(callback) q.on(callback);
3167            for(i = 0; i < evs.length; i++) {
3168                var cb = (function(l) {
3169                    return function() {
3170                        q.trigger(l);
3171                    };
3172                })(evs[i]);
3173                lib.withDependency(evs[i], false, cb);
3174            }
3175			return;
3176        }
3177
3178        if(typeof deps == "object") {
3179            var o = deps;
3180            depName = o.name;
3181            types = o.types;
3182        } else {
3183            depName = deps;
3184        }
3185		library = dependencies[depName] || depName;
3186        if(loaded[library]) {
3187			if(callback) callback();
3188            return;
3189        }
3190
3191		var a = loading[library];
3192        if(!a) {
3193            var doLoad = true;
3194        	a = loading[library] = [];
3195        }
3196        if(callback) a.push(callback);
3197        if(doLoad) loadLibrary(library, enableCookies, types);
3198    };
3199
3200    var loadLibrary = function(libName, enableCookies = false, types) {
3201		var urlBase = "/apps/atvi/global/components/content/" + libName;
3202        if(types != "css")
3203            $.ajax({
3204                dataType: "script",
3205                cache: true,
3206                url: urlBase + "/clientlibs.js",
3207                className: (enableCookies) ? 'optanon-category-3': ''
3208            });
3209        if(types != "js")
3210            $("<link>", {"type": "text/css", "rel": "stylesheet", "href": urlBase + "/clientlibs.css"})
3211                .appendTo($('head'));
3212    };
3213
3214    var getOnLoadQueue = function(dep) {
3215		if(!onLoadHandlers[dep]) onLoadHandlers[dep] = ATVI.utils.createReadyQueue(["load"]);
3216		return onLoadHandlers[dep];
3217    };
3218
3219    lib.onDependencyLoad = function(dep, handler) {
3220		getOnLoadQueue(dep).on(handler);
3221    };
3222
3223})(jQuery, ATVI);
3224
3225// browser
3226(function() {
3227    var b = ATVI.browser = {};
3228    b.hasPointerEvents = !!window.PointerEvent;
3229    b.hasTouchEvents = 'ontouchend' in document;
3230    b.isTouch = b.hasPointerEvents || b.hasTouchEvents;
3231
3232    var ua = navigator.userAgent;
3233	b.isAndroid = !!ua.match(/Android/i);
3234    b.isAndroidMobile = b.isAndroid && !!ua.match(/Mobile/i);
3235    b.isAndroidTablet = b.isAndroid && !b.isAndroidMobile;
3236    b.isBlackberry = !!ua.match(/BlackBerry/i);
3237	b.isIPhone = !!ua.match(/iPhone/i);
3238    b.isIPad = !!ua.match(/iPad/i);
3239    b.isIPod = !!ua.match(/iPod/i);
3240    b.isIos = b.isIPhone || b.isIPad || b.isIPod;
3241	b.isOperaMini = !!ua.match(/Opera Mini/i);
3242	b.isIeMobile = !!ua.match(/IEMobile/i);
3243
3244    b.isBot = !!ua.match(/googlebot|yahoo|msnbot|bingbot|slurp|teoma/i);
3245
3246    b.isPhone = b.isAndroidMobile || b.isBlackberry || b.isIPhone || b.isIPod || b.isOperaMini || b.isIeMobile;
3247    b.isTablet = b.isAndroidTablet || b.isIPad;
3248
3249})();
3250
3251
3252// analytics
3253
3254ATVI.analytics = ATVI.analytics || {};
3255(function($, ATVI) {
3256
3257	var ana = ATVI.analytics;
3258
3259    ana.siteId = "cms-generic";
3260    ana.ns_site = "dev";
3261	ana.prefixesToStrip = [];
3262    ana.homePageFilename = "home";
3263    ana.inited = false;
3264
3265    ana.init = function() {
3266        ana.$body = $("body");
3267        ana.setupPageLoad();
3268        var go = function() {
3269            ana.inited = true;
3270	        //ana.setupClickHandlers($("body"));
3271        };
3272
3273        if(window.ssobar && ssobar.onReady) ssobar.onReady(go);
3274        else go();
3275    };
3276
3277    ana.setupClickHandlers = function(root) {
3278        if(!ana.inited) return;
3279        /*
3280        root = $(root);
3281        this.setupTaggedElements(root);
3282        this.setupLinks(root);
3283        */
3284    };
3285
3286    ana.stripPathPrefixes = function(path) {
3287        var ret = path;
3288        for(var i = 0; i < this.prefixesToStrip.length; i++) {
3289            ret = ret.replace(new RegExp("^" + this.prefixesToStrip[i] + "(/.*)?$"), "$1");
3290        }
3291        return ret;
3292    };
3293
3294    ana.splitPath = function(path, includeFileExtension) {
3295        var ret = path.replace(/^\//, "").replace(/\/$/, "");
3296        if(!includeFileExtension) ret = ret.replace(/(.*)\.\w+$/, "$1");
3297        ret = ret.replace(/\./g, '_').replace(/\/+/g, '.');
3298        if(ret.length == 0) ret = this.homePageFilename;
3299        return ret.split('.');
3300    };
3301
3302    ana.getSiteData = function() {
3303        var sitename = ana.siteId;
3304        var locPathname = ana.stripPathPrefixes(window.location.pathname);
3305        var parsed = ATVI.utils.parseLocalizedPath(locPathname);
3306        locPathname = ana.stripPathPrefixes(parsed.normalized);
3307        locPathname = ana.splitPath(locPathname);
3308
3309        var hierarchy = [];
3310        var i = locPathname.length - 4;
3311        if(i < 0) i = 0;
3312        var top = sitename;
3313        for(; i < locPathname.length; i++) {
3314            top += "." + locPathname[i];
3315            hierarchy.push(top);
3316        }
3317        
3318        while(hierarchy.length < 4) {
3319            hierarchy.push(top);
3320        }
3321
3322        return {
3323            csName: top,
3324            csSection: hierarchy[0],
3325            csSubSection: hierarchy[1],
3326            csCtitle: hierarchy[2],
3327            csCtype: hierarchy[0],
3328            csPathLocale: parsed.locale
3329        };
3330    };
3331    
3332    ana.setupPageLoad = function() {
3333        if (location.hostname.indexOf("activision") == -1  && location.hostname.indexOf("guitarhero") == -1) {
3334            var cookies = ATVI.utils.getCookies(true);
3335            var instr = {};
3336            if(cookies.ATVI_INSTRUMENT) {
3337                try {
3338                    instr = JSON.parse(cookies.ATVI_INSTRUMENT);
3339                } catch(e) {
3340                    instr = {};
3341                }
3342            }
3343
3344            var siteData = this.getSiteData();
3345            
3346            var prevPage = instr.page;
3347            instr.page = siteData.csName;
3348            
3349            var pageData = {
3350                site: this.siteId,
3351                language: cookies.ACT_SSO_LOCALE || "en_US",
3352                "name": siteData.csName,
3353                previous_page: prevPage,
3354                c_type: siteData.csCtype,
3355                c_title: siteData.csCtitle,
3356                section: siteData.csSection,
3357                sub_section: siteData.csSubSection,
3358                path_locale: siteData.csPathLocale
3359            };
3360            
3361            var eventCookie = cookies.ACT_SSO_EVENT;
3362            if(eventCookie) {
3363                eventCookie = eventCookie.replace(/^\"(.*)\"$/, "$1");
3364                if(instr.event != eventCookie) {
3365                    instr.event = eventCookie;
3366                    eventCookie = eventCookie.split(":");
3367                    if(eventCookie[0])
3368                        pageData.sso_event = eventCookie[0];
3369                }
3370            }
3371    
3372            //ATVI.utils.setCookie("ATVI_INSTRUMENT", JSON.stringify(instr));
3373            //this.sendData(pageData);
3374        }
3375    };
3376
3377    ana.setupTaggedElements = function(root) {
3378        /*
3379        var self = this;
3380		root.find(".atvi-instrument").click(function() {
3381            var classes = this.className.split(/\s+/);
3382            var className;
3383
3384            for(i in classes) {
3385                if(classes[i].indexOf("atvi-instrument-") >= 0) {
3386                    className = classes[i];
3387                    className = className.substring("atvi-instrument-".length);
3388                    break;
3389                }
3390            }
3391
3392            if(className) {
3393
3394                var $this = $(this);
3395                var id = ana.findComponentId($this);
3396                var strippedId = id.replace(/^(.+)-analytics-suffix-.*$/, "$1");
3397
3398                var data = {
3399                    action_type: className,
3400                    action_details: strippedId,
3401                    ns_type: "hidden"
3402                };
3403
3404                var go = function() {
3405					ana.sendData(data);
3406                };
3407
3408                if(ana.customData[className]) {
3409					if(!ana.customData[className]($this, data, go)) go();
3410                } else go();
3411            }
3412        });
3413        */
3414    };
3415
3416    // add to this for component handling
3417    ana.customData = {}
3418	// e.g.
3419    ana.customData.wheretobuy = ana.customData.wheretobuy ||function($el, data) {};
3420
3421    ana.setupLinks = function(root) {
3422
3423        root.find("a").not(".atvi-instrument").not(".atvi-no-instrument").click(function() {
3424            
3425            var href = this.href;
3426            var $this = $(this);
3427            
3428            var data = {
3429                action_type: "atvi-anchor",
3430                href: href,
3431                ns_type: "hidden"
3432            };
3433            
3434            var detail = "";
3435            var id = ana.findComponentId($this);
3436            if(id) {
3437                var strippedId = id.replace(/^(.+)-analytics-suffix-.*$/, "$1");
3438                detail += strippedId + ": ";
3439            }
3440            var linkText = $this.text().substring(0, 30);
3441            if(linkText.length >= 30) linkText += "...";
3442            detail += linkText;
3443            data.action_details = detail;
3444            
3445            //ana.sendData(data);
3446            
3447        });
3448    };
3449
3450    ana.findComponentId = function($el, selector) {
3451		var id = $el.attr("id");
3452        if(id && !$el.hasClass("ignore-id")) return id;
3453        var i, p = $el.parents(selector);
3454        for(i = 0; i < p.length; i++) {
3455            id = p[i].id;
3456			if(id && !p.eq(i).hasClass("ignore-id")) return id;
3457        }
3458		return "";
3459    };
3460
3461    ana.sendEvent = function(actionType, actionDetails, params) {
3462        var data = {
3463            action_type: actionType,
3464            action_details: actionDetails,
3465            ns_type: "hidden"
3466        };
3467        params = params || {};
3468        for(var i in params) {
3469            if(!params.hasOwnProperty(i)) continue;
3470            data[i] = params[i];
3471        }
3472        //this.sendData(data);
3473
3474        var ev = document.createEvent("CustomEvent");
3475        ev.initCustomEvent("atviInstrumentEvent", true, true, { type: actionType, details: actionDetails, data: data });
3476        document.body.dispatchEvent(ev);
3477    };
3478
3479    ana.sendData = function (data) {
3480        /**
3481        var loc = 'http' + (document.location.href.charAt(4) == 's' ? 's://sb' : '://b') + '.scorecardresearch.com/p?c1=2&c2=14880931';
3482        
3483        // common values
3484        data.visitorID = this.getVisitorId();
3485        data.anonVisitorID = this.getAnonVisitorId();
3486        data.ns__t = "" + new Date().getTime();
3487        data.ns_c = document.characterSet || document.defaultCharset || "";
3488        data.c8 = document.title;
3489        data.c7 = document.location.href || document.URL;
3490        data.c9 = document.referrer;
3491        
3492        if(ATVI.uxTest && ATVI.uxTest.campaigns) {
3493            var campaigns = ATVI.uxTest.campaigns;
3494            var campaignNames = [], campaignIds = [];
3495            var recipeNames = [], recipeIds = [];
3496            var offerNames = [], offerIds = [];
3497            var mboxNames = [];
3498            for(var i = 0; i < campaigns.length; i++) {
3499                campaignNames.push(campaigns[i].campaignName);
3500                campaignIds.push(campaigns[i].campaignId);
3501                recipeNames.push(campaigns[i].recipeName);
3502                recipeIds.push(campaigns[i].recipeId);
3503                offerNames.push(campaigns[i].offerName);
3504                offerIds.push(campaigns[i].offerId);
3505                mboxNames.push(campaigns[i].mboxName);
3506            }
3507            data.campaignName = campaignNames.join(",");
3508            data.campaignId = campaignIds.join(",");
3509            data.recipeName = recipeNames.join(",");
3510            data.recipeId = recipeIds.join(",");
3511            data.offerName = offerNames.join(",");
3512            data.offerId = offerIds.join(",");
3513            data.mboxName = mboxNames.join(",");
3514        }
3515        
3516        var cookies = ATVI.utils.getCookies(true);
3517        if(cookies.comScore) data.comScore = cookies.comScore; 
3518        
3519        data.ns_site = ATVI.pageEnv == "prod" ? (this.ns_site || "dev") : "dev";
3520        
3521        for(var i in data) {
3522            loc += "&" + i + "=" + encodeURIComponent(data[i]);
3523        }
3524        
3525        if (loc.length > 2048) {
3526            var s = loc.substr(0, 2040).lastIndexOf("&");
3527            loc = (loc.substring(0, s) + "&ns_cut=" + encodeURIComponent(loc.substring(s + 1))).substr(0, 2048);
3528        }
3529
3530        if(!ana.$container) ana.$container = $('<div>').css({height: 0, width: 0, overflow: "hidden"}).appendTo(ana.$body);
3531        	$('<div>').css({height: 0, width: 0, overflow: "hidden"}).appendTo(ana.$container)
3532        	.append('<img src="' + loc + '" height="1" width="1" alt="*" />' );
3533        **/
3534    };
3535
3536    ana.getVisitorId = function() {
3537        var c = ATVI.utils.getCookies(true);
3538
3539        var s = c.ACT_SSO_COOKIE || c.s_ACT_SSO_COOKIE; 
3540
3541        if(s) {
3542            var dec = ATVI.utils.decodeBase64(s);
3543            var index = dec.indexOf(":");
3544            if(index >= 0) dec = dec.substring(0, index);
3545            return dec;
3546        }
3547
3548        return this.getAnonVisitorId();
3549    };
3550
3551    ana.getAnonVisitorId = function() {
3552
3553        var c = ATVI.utils.getCookies(true);
3554        if(c.ATVI_VISITOR_ID) return c.ATVI_VISITOR_ID;
3555
3556        var date = new Date();
3557        var anonId = "anon-" + date.getTime() + "-" + Math.random();
3558
3559        date.setTime(date.getTime() + 5 * 356 * 24 * 60 * 60000);
3560        ATVI.utils.setCookie("ATVI_VISITOR_ID", anonId, date);
3561
3562        return anonId;
3563    };
3564
3565
3566    $(function() {
3567        ana.init();
3568    });
3569
3570})(jQuery, ATVI);
3571
3572var ATVI = ATVI || {};
3573
3574(function($, ATVI) {
3575
3576    let a = ATVI.tagging = {};
3577
3578    let init = function() {
3579
3580        if (!digitalData || !dataLayer) return;
3581        var d = digitalData.page;
3582
3583        //////////////////////////////////////
3584
3585        // CTA LINK ANALYTICS CLICK HANDLER
3586
3587        //////////////////////////////////////
3588
3589        /**
3590        	Give the class name .atvi-cta-item to any <a> or <button> element that will act as an interactable CTA link/button.
3591        	This class is automatically added to the ATVI CTA component's <a> and <button> tags
3592        **/
3593
3594        //Get all elements with .atvi-cta-item class except those with .atvi-exempt-analytics class
3595        let ctaItems = $(".atvi-cta-item:not(.atvi-exempt-analytics)"); 
3596
3597        ctaItems.each(function() {
3598
3599            var $el = $(this);
3600
3601			$el.on("click", function() {
3602
3603                //Get href value. If item is not a link, then it's a button
3604                let curHref = $(this).attr("href") || 'button'; 
3605    
3606                //Build url with https: and domain name in front
3607                let fullHref = (curHref.startsWith("https:") || curHref == 'button') ? curHref : window.location.origin + curHref;
3608
3609                //Check if link is social platform link
3610                var socialPlatform = '';
3611    
3612                if(fullHref.includes("facebook.com"))       socialPlatform = "facebook";
3613                else if(fullHref.includes("twitter.com"))   socialPlatform = "twitter";
3614                else if(fullHref.includes("instagram.com")) socialPlatform = "instagram";
3615                else if(fullHref.includes("youtube.com"))   socialPlatform = "youtube";
3616                else if(fullHref.includes("tiktok.com"))    socialPlatform = "tiktok";
3617                else if(fullHref.includes("linkedin.com"))  socialPlatform = "linkedin";
3618                else if(fullHref.includes("discord.gg"))    socialPlatform = "discord";
3619                else if(fullHref.includes("twitch.tv"))     socialPlatform = "twitch";
3620                else if(fullHref.includes("reddit.com"))    socialPlatform = "reddit";
3621
3622
3623                //If data-extext exists, then set cta name to this english cta name. If not defined, then use the inner text of cta element 
3624                let ctaName = $(this).attr("data-entext") ? $(this).attr("data-entext").replace(":", " ") : $(this).text().trim().replace(":", " "); //text in cta
3625    
3626                //Get closest parent element with class .atvi-module-container[data-analytics-container]
3627                let parentModule = ($(this).closest(".atvi-module-container[data-analytics-container]").length > 0) ? $(this).closest(".atvi-module-container[data-analytics-container]") : $(this).closest(".atvi-module-container[id]"); //get closest element that has data-analytics-container or .atvi-module-container element that has ID attribute
3628
3629                //Get module name from either the data-analytics-container attribute or the id attribute or by default it will be atvi-module
3630                let moduleName = parentModule.data("analytics-container") || parentModule.attr("id") || "atvi-module"; 
3631
3632                //If this button is a video, let's get the title
3633                let videoTitle = $(this).attr("data-youtube-title");
3634
3635                //If socialPlatform is empty string, then this is a regular CTA link or button
3636                if(socialPlatform == '') {
3637
3638                    //If CTA button opens a video modal
3639                    if(videoTitle != null && videoTitle != '') {
3640
3641                        dataLayer.push({
3642                            event: 'interaction', 
3643                            action: moduleName + ":" + ctaName,
3644                            category: 'interaction:' + d.pageInfo.pageName,
3645                            label: fullHref,
3646                            video_title: videoTitle,
3647                            video_provider: "youtube",
3648                            module: moduleName
3649                        });
3650
3651                    }
3652
3653                    //Else it's a regular link or button
3654                    else {
3655
3656                        dataLayer.push({
3657                            event: 'interaction', 
3658                            action: moduleName + ":" + ctaName,
3659                            category: 'interaction:' + d.pageInfo.pageName,
3660                            label: fullHref,
3661                            module: moduleName
3662                        });
3663
3664                    }
3665                }
3666    
3667                //Else this is a social link
3668                else {
3669    
3670                    dataLayer.push({
3671        
3672                        event: "social",
3673                        category: "social",
3674                        action: socialPlatform,
3675                        label: fullHref
3676        
3677                    });
3678    
3679                }
3680    
3681            });
3682
3683        });
3684
3685        ////////////////////////////////////
3686
3687        // MODULE ANALYTICS SCROLL HANDLER
3688
3689        ////////////////////////////////////
3690
3691        //select all elements that have a data-analytics-container attribute
3692        let containers = document.querySelectorAll("*[data-analytics-container]");
3693
3694        //if we find at least 1 element, create an observer for the elements
3695        if(containers.length > 0) createObserver(containers, handleCallback, {threshold: 0.5});
3696
3697    };
3698
3699    let createObserver = function(selectors, callback, options = {}) {
3700
3701        //create new intersection observer instance
3702		let observer = new IntersectionObserver(callback, options);
3703
3704        //for each selector, create an observer
3705        selectors.forEach( (selector) => {
3706        	observer.observe(selector);
3707        });
3708    };
3709
3710    const handleCallback = (entries) => {
3711        entries.forEach( (entry) => {
3712        	//if target passes half way in viewport
3713    		if (entry.intersectionRatio >= 0.5) {
3714            	const { target } = entry;
3715
3716        		//call updateScrollDataLayer method and pass the data-analytics-container value
3717    			updateScrollDataLayer($(target).data("analytics-container"));
3718			}
3719		});
3720	};
3721
3722    let updateScrollDataLayer = function(module) {
3723
3724    	//if dataDigital or dataLayer do not exist, then stop execution of rest of code
3725        var url = window.location.href;
3726        var d = digitalData.page, obj = {};
3727
3728    	//create analytics object using predefined values
3729		obj.event = "scroll";
3730		obj.category = "scroll";
3731        obj.action = d.pageInfo.pageName;
3732        obj.label = module;
3733
3734    	//append object to dataLayer
3735        dataLayer.push(obj);
3736
3737    };
3738
3739
3740    $(init);
3741
3742
3743})(jQuery,ATVI);
3744
3745
3746// touch
3747
3748ATVI.touch = {};
3749(function($, ATVI) {
3750
3751    var touch = ATVI.touch;
3752	var touchDist = ATVI.browser.isPhone ? 35 : 60;
3753
3754    touch.onSimpleHorizontal = function($el, opts) {
3755
3756        var h = opts.hammer || Hammer($el[0], { swipe_velocity: opts.swipeVelocity || .2 });
3757        
3758        h.on("swipeleft swiperight dragleft dragright dragend dragstart", function(ev) {
3759			var t = ev.type, dx = Math.abs(ev.deltaX), dy = Math.abs(ev.deltaY) + .1, rat = dx / dy, dt = ev.deltaTime;
3760
3761            if(t != "dragstart" && t != "dragend") {
3762                ev.preventDefault();
3763            }
3764
3765            if(t == "dragleft" && opts.dragLeft) opts.dragLeft(ev);
3766            if(t == "dragright" && opts.dragRight) opts.dragRight(ev);
3767            if(t == "dragstart" && opts.dragStart) opts.dragStart(ev);
3768            if(t == "dragend" && opts.dragEnd) opts.dragEnd(ev);
3769
3770            if((t == "dragleft" && dx > touchDist && rat > 2 && dt < 700) || t == "swipeleft") {
3771                if(opts.swipeLeft) opts.swipeLeft(ev);
3772                //ev.stopDetect();
3773            }
3774            if((t == "dragright" && dx > touchDist && rat > 2 && dt < 700) || t == "swiperight") {
3775                if(opts.swipeRight) opts.swipeRight(ev);
3776                //ev.stopDetect();
3777            }
3778        });
3779
3780        return {
3781            hammerObj: h
3782        };
3783    };
3784
3785})(jQuery, ATVI);
3786
3787
3788// country codes
3789ATVI.countryCodes = {};
3790(function() {
3791
3792    ATVI.countryCodes = {
3793        "af"	: "Afghanistan",
3794        "al"	: "Albania",
3795        "dz"	: "Algeria",
3796        "as"	: "American Samoa",
3797        "ad"	: "Andorra",
3798        "ao"	: "Angola",
3799        "ag"	: "Antigua and Barbuda",
3800        "ar"	: "Argentina",
3801        "am"	: "Armenia",
3802        "aw"	: "Aruba",
3803        "au"	: "Australia",
3804        "at"	: "Austria",
3805        "az"	: "Azerbaijan",
3806        "bs"	: "Bahamas",
3807        "bh"	: "Bahrain",
3808        "bd"	: "Bangladesh",
3809        "bb"	: "Barbados",
3810        "by"	: "Belarus",
3811        "be"	: "Belgium",
3812        "be-fr" : "Belgium French",
3813        "bz"	: "Belize",
3814        "bj"	: "Benin",
3815        "bm"	: "Bermuda",
3816        "bt"	: "Bhutan",
3817        "bo"	: "Bolivia",
3818        "ba"	: "Bosnia and Herzegovina",
3819        "bw"	: "Botswana",
3820        "bv"	: "Bouvet Island",
3821        "br"	: "Brazil",
3822        "io"	: "British Indian Ocean Territory",
3823        "bn"	: "Brunei Daarussalam",
3824        "bg"	: "Bulgaria",
3825        "bf"	: "Burkina Faso",
3826        "bi"	: "Burundi",
3827        "kh"	: "Cambodia",
3828        "cm"	: "Cameroon",
3829        "ca"	: "Canada",
3830        "ca-fr"	: "Le Canada Français",
3831        "cv"	: "Cape Verde",
3832        "ky"	: "Cayman Islands",
3833        "cf"	: "Central AFrican Republic",
3834        "td"	: "Chad",
3835        "cl"	: "Chile",
3836        "cn"	: "繁體中文",
3837        "cn-s"	: "简体中文",
3838        "cx"	: "Christmas Island",
3839        "cc"	: "Cocos Islands",
3840        "co"	: "Colombia",
3841        "km"	: "Comoros",
3842        "cg"	: "Congo",
3843        "cd"	: "The Democratic Republic of Congo",
3844        "ck"	: "Cook Islands",
3845        "cr"	: "Costa Rica",
3846        "ci"	: "Côte d'Ivoire",
3847        "hr"	: "Croatia",
3848        "cu"	: "Cuba",
3849        "cy"	: "Cypress",
3850        "cz"	: "Czech Republic",
3851        "dk"	: "Danmark",
3852        "dj"	: "Djibouti",
3853        "dm"	: "Dominica",
3854        "do"	: "Dominican Republic",
3855        "ec"	: "Ecuador",
3856        "eg"	: "Egypt",
3857        "sv"	: "El Salvador",
3858        "gq"	: "Equatorial Guinea",
3859        "er"	: "Eritrea",
3860        "ee"	: "Estonia",
3861        "et"	: "Ethiopia",
3862        "fk"	: "Falkland Islands",
3863        "fo"	: "Faroe Islands",
3864        "fj"	: "Fiji",
3865        "fi"	: "Suomi",
3866        "fr"	: "France",
3867        "gf"	: "French Guiana",
3868        "pf"	: "French Polynesia",
3869        "tf"	: "French Southern Territories",
3870        "ga"	: "Gabon",
3871        "gm"	: "Gambia",
3872        "ge"	: "Georgia",
3873        "de"	: "Deutschland",
3874        "gh"	: "Ghana",
3875        "gi"	: "Gibraltar",
3876        "gr"	: "Greece",
3877        "gl"	: "Greenland",
3878        "gd"	: "Grenada",
3879        "gp"	: "Guadaloupe",
3880        "gu"	: "Guam",
3881        "gt"	: "Guatemala",
3882        "gn"	: "Guinea",
3883        "gw"	: "Guinea-Bissau",
3884        "gy"	: "Guyana",
3885        "ht"	: "Haiti",
3886        "hm"	: "Heard Island and Mcdonald Islands",
3887        "hn"	: "Honduras",
3888        "hk"	: "Hong Kong",
3889        "hk-s"	: "Hong Kong 简体中文",
3890        "hu"	: "Hungary",
3891        "is"	: "Iceland",
3892        "in"	: "India",
3893        "id"	: "Indonesia",
3894        "ir"	: "Iran",
3895        "iq"	: "Iraq",
3896        "ie"	: "Ireland",
3897        "il"	: "Israel",
3898        "it"	: "Italia",
3899        "jm"	: "Jamaica",
3900        "jp"	: "日本",
3901        "jo"	: "Jordan",
3902        "kz"	: "Kazakhstan",
3903        "ke"	: "Kenya",
3904        "ki"	: "Kiribati",
3905        "kp"	: "Korea 조선민주주의인민공화국",
3906        "kr"	: "대한민국",
3907        "xk"	: "Kosovo",
3908        "kw"	: "Kuwait",
3909        "kg"	: "Kyrgyzstan",
3910        "la"	: "Laos",
3911        "lv"	: "Latvia",
3912        "lb"	: "Lebanon",
3913        "ls"	: "Lesotho",
3914        "lr"	: "Liberia",
3915        "ly"	: "Libyan Arab Jamahiriya",
3916        "li"	: "Liechtenstein",
3917        "lt"	: "Lithuania",
3918        "lu"	: "Luxembourg",
3919        "lu-de"	: "Luxemburg",
3920        "lu-fr"	: "Luxembourg",
3921        "mo"	: "Macao",
3922        "mk"	: "Macedonia",
3923        "mg"	: "Madagascar",
3924        "mw"	: "Malawi",
3925        "my"	: "Malaysia",
3926        "mv"	: "Maldives",
3927        "ml"	: "Mali",
3928        "mt"	: "Malta",
3929        "mh"	: "Marshall Islands",
3930        "mq"	: "Martinique",
3931        "mu"	: "Mauritius",
3932        "yt"	: "Mayotte",
3933        "mx"	: "México",
3934        "fm"	: "Micronesia",
3935        "md"	: "Moldova",
3936        "mc"	: "Monaco",
3937        "mn"	: "Mongolia",
3938        "me"	: "Montenegro",
3939        "ms"	: "Montserrat",
3940        "ma"	: "Morocco",
3941        "mz"	: "Mozambique",
3942        "mm"	: "Myanmar",
3943        "na"	: "Namibia",
3944        "nr"	: "Nauru",
3945        "np"	: "Nepal",
3946        "nl"	: "Netherlands",
3947        "an"	: "Netherlands Antilles",
3948        "nc"	: "New Caledonia",
3949        "nz"	: "New Zealand",
3950        "ni"	: "Nicaragua",
3951        "ne"	: "Niger",
3952        "ng"	: "Nigeria",
3953        "nu"	: "Niue",
3954        "nf"	: "Norfolk Islands",
3955        "mp"	: "Northern Mariana Islands",
3956        "no"	: "Norge",
3957        "om"	: "Oman",
3958        "pk"	: "Pakistan",
3959        "pw"	: "Palau",
3960        "ps"	: "Palestinian Territory",
3961        "pa"	: "Panama",
3962        "pg"	: "Papua New Guinea",
3963        "py"	: "Paraguay",
3964        "pe"	: "Peru",
3965        "ph"	: "Philippines",
3966        "pn"	: "Pitcairn",
3967        "pl"	: "Polska",
3968        "pl-en"	: "Poland",
3969        "pt"	: "Portugal",
3970        "pr"	: "Puerto Rico",
3971        "qa"	: "Qatar",
3972        "re"	: "Réunion",
3973        "ro"	: "Romania",
3974        "ru"	: "Росси́я",
3975        "rw"	: "Rwanda",
3976        "sh"	: "Saint Helena",
3977        "kn"	: "Saint Kitts and Nevis",
3978        "lc"	: "Saint Lucia",
3979        "pm"	: "Saint Pierre and Miquelon",
3980        "vc"	: "Saint Vincent and the Grenadines",
3981        "ws"	: "Samoa",
3982        "sm"	: "San Marino",
3983        "st"	: "Sao Tome and Principe",
3984        "sa"	: "Saudi Arabia",
3985        "sn"	: "Senegal",
3986        "rs"	: "Serbia",
3987        "sc"	: "Seychelles",
3988        "sl"	: "Sierra Leone",
3989        "sg"	: "Singapore",
3990        "sk"	: "Slovakia",
3991        "si"	: "Slovenia",
3992        "sb"	: "Solomon Islands",
3993        "so"	: "Somalia",
3994        "za"	: "South Africa",
3995        "gs"	: "South Georgia and the South Sandwich Islands",
3996        "es"	: "España",
3997        "lk"	: "Sri Lanka",
3998        "sd"	: "Sudan",
3999        "sr"	: "Suriname",
4000        "sj"	: "Svalbard and Jan Mayen",
4001        "sz"	: "Swaziland",
4002        "se"	: "Sverige",
4003        "ch"	: "Switzerland",
4004        "ch-de"	: "Schweizerische Eidgenossenschaft",
4005        "ch-fr"	: "Confédération Suisse",
4006        "ch-it"	: "Confederazione Svizzera",
4007        "ch-ro"	: "Confederaziun Svizra",
4008        "sy"	: "Syrian Arab Republic",
4009        "tw"	: "Taiwan",
4010        "tj"	: "Tajikistan",
4011        "tz"	: "Tanzania",
4012        "th"	: "Thailand",
4013        "tl"	: "Timor-Leste",
4014        "tg"	: "Togo",
4015        "tk"	: "Tokelau",
4016        "to"	: "Tonga",
4017        "tt"	: "Trinidad and Tobago",
4018        "tn"	: "Tunisia",
4019        "tr"	: "Turkey",
4020        "tm"	: "Turkmenistan",
4021        "tc"	: "Turks and Caicos Islands",
4022        "tv"	: "Tuvalu",
4023        "ug"	: "Uganda",
4024        "ua"	: "Ukraine",
4025        "ua-ru"	: "Ukraine - Russian",
4026        "ae"	: "United Arab Emirates",
4027        "gb"	: "United Kingdom",
4028        "us"	: "United States",
4029        "um"	: "United States Minor Outlying Islands",
4030        "uy"	: "Uruguay",
4031        "uz"	: "Uzbekistan",
4032        "vu"	: "Vanuatu",
4033        "ve"	: "Venezuela",
4034        "vn"	: "Viet Nam",
4035        "vg"	: "British Virgin Islands",
4036        "vi"	: "U.S. Virgin Islands",
4037        "wf"	: "Wallis and Futuna",
4038        "eh"	: "Western Sahara",
4039        "ye"	: "Yemen",
4040        "zm"	: "Zambia",
4041        "zw"	: "Zimbabwe"
4042    };
4043
4044})();
4045var ATVI = ATVI || {};
4046
4047(function($, ATVI) {
4048
4049    var ld = ATVI.localeDetector = {},
4050        headers = [{id: 'x-activision-countrycode', type: 'country'}, {id: 'X-Activision-Regioncode', type: 'region'}];
4051
4052    ld.country;
4053    ld.region;
4054
4055    ld.requestXCode = function() {
4056		var request = new XMLHttpRequest();
4057		request.open('GET', window.location.href);
4058        request.onreadystatechange = function() {
4059            if(this.readyState == this.HEADERS_RECEIVED) {
4060                var i;
4061                for (i = 0; i < headers.length; i++) {
4062					var d = request.getResponseHeader(headers[i].id) || "";
4063                    ld[headers[i].type] = d.toLowerCase();
4064                }
4065                ld.fireEvent();
4066            }
4067        };
4068        request.send();
4069    };
4070
4071    ld.fireEvent = function() {
4072        var e = new CustomEvent('localeDetectionReady');
4073		document.dispatchEvent(e);
4074    };
4075
4076    ld.getCountry = function(cb) {
4077		if (ld.country && cb) cb(ld.country);
4078        else {
4079            document.addEventListener('localeDetectionReady', function() {
4080                cb(ld.country);
4081            });
4082        }
4083    };
4084
4085    ld.getRegion = function(cb) {
4086        if (ld.region && cb) cb(ld.region);
4087        else {
4088            document.addEventListener('localeDetectionReady', function() {
4089                cb(ld.region);
4090            });
4091        }
4092    };
4093
4094    ld.requestXCode();
4095
4096})(jQuery, ATVI);
4097ATVI.modal = {};
4098
4099(function($, ATVI) {
4100
4101	var m = ATVI.modal;
4102
4103    var class_bodyOpenModal = 'modal-open',
4104        class_modalOpen = 'active';
4105
4106    var init = function() {
4107		m.$modals = $('.atvi-modal');
4108        m.addHandlers();
4109    };
4110
4111    m.addHandlers = function() {
4112        m.$modals.each(function() {
4113			var $thisModal = $(this),
4114                $closeButton = $thisModal.find('.button.close, .close-button'),
4115                $bg = $thisModal.find('.background-container'),
4116                $handles = $closeButton.add($bg);
4117            $handles.on('click', function(e) {
4118				e.preventDefault();
4119                m.closeModal($thisModal);
4120            });
4121        });
4122    };
4123
4124    m.openModal = function($wrapper, ms) {
4125        var $b = $('body'),
4126            ms = (ms) ? ms : 300,
4127            $modals = (m.$modals.length) ? m.$modals : $('.atvi-modal');
4128        if ($b.hasClass(class_bodyOpenModal)) {
4129        	$b.removeClass(class_bodyOpenModal);
4130			$modals.removeClass(class_modalOpen);
4131            setTimeout(function() {
4132				$b.addClass(class_bodyOpenModal);
4133                $wrapper.addClass(class_modalOpen);
4134            }, ms);
4135        } else {
4136			$b.addClass(class_bodyOpenModal);
4137            $wrapper.addClass(class_modalOpen);
4138        }
4139    };
4140
4141    m.closeModal = function($wrapper) {
4142		var $b = $('body'),
4143            $modals = (m.$modals.length) ? m.$modals : $('.atvi-modal');
4144        $b.removeClass(class_bodyOpenModal);
4145        $modals.removeClass(class_modalOpen);
4146    };
4147
4148    $(init);
4149
4150})(jQuery, ATVI);
4151(function($, ATVI) {
4152    
4153    var ld = ATVI.localeDetector,
4154        noShowArr = ['us', 'ca', 'mx'],
4155        targetSitesArr = ['www.activision.com', 
4156                          'www.callofduty.com', 
4157                          'www.tonyhawkthegame.com', 
4158                          'www.crashbandicoot.com',
4159                          'www.sekirothegame.com',
4160                          'www.spyrothedragon.com'],
4161        devSitesArr = [...targetSitesArr.map(site => 'preview'+site.substring(3))],
4162        hostname = window.location.hostname;
4163
4164
4165    var init = function() {
4166        if (ld.country && noShowArr.indexOf(ld.country) == -1) showEulaBanner();
4167        else {
4168            document.addEventListener('localeDetectionReady', function() {
4169                if (noShowArr.indexOf(ld.country) == -1) showEulaBanner();
4170            });
4171        }
4172    };
4173
4174    var showEulaBanner = function() {
4175
4176        if (typeof ATVI.utils.getCookie('atvi-eula-update') == 'undefined') {
4177			var $el = $('.eula-banner-module');
4178            if ($el.length) {
4179                $el.addClass('show');
4180                $el.find('.close-modal').on('click', function() {
4181					$el.removeClass('show');
4182                    $(this).attr("tabindex","-1");
4183                    setCookie('atvi-eula-update');
4184                });
4185            }
4186        }
4187    };
4188
4189    var setCookie = function(cookieName) {
4190		ATVI.utils.setCookie(cookieName, true, {expireDate: (3600 * 24 * 365)});
4191    };
4192
4193    // only use on select sites
4194    /*if (targetSitesArr.indexOf(hostname) > -1 || devSitesArr.indexOf(hostname) > -1) {
4195    	$(init);
4196    }*/
4197
4198})(jQuery, ATVI);
4199(function () {
4200
4201    let init = function () {
4202
4203        const ld = ATVI.localeDetector;
4204        const region = ld?.region;
4205        /*const user = ssobar?.user;
4206        const userInfo = user?.userInfo;*/
4207
4208        const teenRegions = [
4209            'ct', 'nj', 'de', 'co', 'ca', 'tn', 'nh', 'ia', 'tx', 'mt',
4210            'va', 'fl', 'or', 'ut', 'ne', 'ny', 'mn', 'md', 'in', 'ky', 'ri'
4211        ];
4212
4213        const isTeenRegion = region && teenRegions.includes(region);
4214
4215
4216        const isTeenUser = (ATVI.utils.userInfo && ATVI.utils.userInfo.isChild == false) ? true : false;
4217        const isChildUser = (ATVI.utils.userInfo && ATVI.utils.userInfo.isChild == true) ? true : false;
4218
4219        const shouldRejectCookies = (isTeenRegion && isTeenUser) || (!isTeenRegion && isChildUser);
4220
4221        if (shouldRejectCookies) {
4222            rejectCookies();
4223        }
4224    };
4225
4226    let rejectCookies = function () {
4227        // Reject all non-essential cookies
4228        OneTrust.RejectAll();
4229
4230        // Disable toggles
4231        document.querySelectorAll('.ot-tgl label').forEach((label) => {
4232            label.style.pointerEvents = 'none';
4233            label.style.opacity = '0.5';
4234        });
4235    };
4236
4237    //$(window).on("load", init);
4238
4239})();
4240(function() {
4241
4242    var init = function() {
4243
4244        $(".cf-icon-toggle").on("click", function() {
4245
4246			$(this).next(".cf-modal").show();
4247
4248        });
4249
4250        $(".cf-modal-close").on("click", function() {
4251
4252			$(this).closest(".cf-modal").hide();
4253
4254        });
4255
4256    };
4257
4258	$(init);
4259
4260})();

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.