PageSourceSearch

https://blocktradedirect.com/js-2/main.js

js blocktradedirect.com collected 2026-10-04 02:39:38 UTC 104,857 bytes, 2,551 lines download raw bytes

1
2//gsap highlight element
3document.addEventListener("DOMContentLoaded", (event) => {
4    const highlight = document.getElementById("highlight-style"); //set this id highlight-style to style object
5
6    gsap.registerPlugin(ScrollTrigger);
7
8    gsap.utils.toArray(".text-highlight").forEach((highlight) => { //add the highlight element css property to the element
9        ScrollTrigger.create({
10            trigger: highlight,
11            start: "-100px center",
12            onEnter: () => highlight.classList.add("active") //start highlighting immediately
13        });
14    });
15
16    //coin scroll trigger
17    gsap.utils.toArray(".attribute").forEach(function(elem, i) { //for each attribute  element we need to add the attribute
18
19        const dx = [600, -400, -500, 300, 800, -120];
20        const dy = [-50, 20, -150, -120, -80, 40];
21        const dr = [-190, 200, 60, -290, 230, -540];
22      
23      
24        let tl = gsap.timeline({
25          scrollTrigger: {
26            trigger: elem,
27            start: "top 500",
28            scrub: 0.2,
29          },
30        })
31        .to( elem, {
32          x: dx[i],
33          y: dy[i],
34          rotation: dr[i],
35        } )
36    });
37
38    const setHighlightStyle = (value) =>
39    document.body.setAttribute("data-highlight", value); //set the highlight style to style object from the document body attribute value
40
41    highlight.addEventListener("change", (e) => setHighlightStyle(e.target.value)); //set highlight style to value attribute on change
42
43    setHighlightStyle(highlight.value);
44});
45
46//Scroll Trigger animation
47document.addEventListener("DOMContentLoaded", (event) => {
48    const scroller = new LocomotiveScroll({
49        el: document.querySelector('[data-scroll-container]'), //use locomotive scroll
50        smooth: true
51    });
52});
53
54// Cursor Mousemove:
55document.addEventListener("DOMContentLoaded", (event) => {
56    const cursorBox = $(".cursor");
57
58    gsap.set($(cursorBox), { xPercent: -50, yPercent: -50 });
59    let xTo = gsap.quickTo($(cursorBox), "x", { duration: 0.6, ease: "power3" }),
60        yTo = gsap.quickTo($(cursorBox), "y", { duration: 0.6, ease: "power3" });
61
62    window.addEventListener("mousemove", (e) => {
63        // xTo(e.pageX);
64        // yTo(e.pageY);
65        xTo(e.clientX);
66        yTo(e.clientY);
67    });
68
69    const links = $("a");
70    var mouseInAnimation = false;
71    links.on({
72        mouseover: function () {
73            mouseInAnimation = gsap.to($(cursorBox), {
74                duration: 1,
75                height: 90,
76                width: 90,
77                backgroundColor: "transparent",
78                ease: Elastic.easeOut,
79            });
80        },
81        mouseleave: function () {
82            var delay = 0;
83            if (mouseInAnimation.isActive()) {
84                delay = 0.25;
85            }
86            gsap.to($(cursorBox), {
87                duration: 0.5,
88                delay: delay,
89                height: 4,
90                width: 4,
91                backgroundColor: "#00c288",
92                ease: "power3",
93            });
94        },
95    });
96});
97
98// Initialize slider:
99document.addEventListener("DOMContentLoaded", (event) => {
100    $(document).ready(function () {
101        $(".noUi-handle").on("click", function () {
102            $(this).width(50);
103        });
104        var rangeSlider = document.getElementById("slider-range");
105        var moneyFormat = wNumb({
106            decimals: 0,
107            thousand: ",",
108            prefix: "$",
109        });
110        noUiSlider.create(rangeSlider, {
111            start: [500000, 1000000],
112            step: 1,
113            range: {
114                min: [100000],
115                max: [1000000],
116            },
117            format: moneyFormat,
118            connect: true,
119        });
120
121        // Set visual min and max values and also update value hidden form inputs
122        rangeSlider.noUiSlider.on("update", function (values, handle) {
123            document.getElementById("slider-range-value1").innerHTML = values[0];
124            document.getElementById("slider-range-value2").innerHTML = values[1];
125            document.getElementsByName("min-value").value = moneyFormat.from(values[0]);
126            document.getElementsByName("max-value").value = moneyFormat.from(values[1]);
127        });
128    });
129
130    // https://refreshless.com/nouislider/
131    /*! nouislider - 8.3.0 - 2016-02-14 17:37:19 */
132    (function (factory) {
133        if (typeof define === "function" && define.amd) {
134            // AMD. Register as an anonymous module.
135            define([], factory);
136        } else if (typeof exports === "object") {
137            // Node/CommonJS
138            module.exports = factory();
139        } else {
140            // Browser globals
141            window.noUiSlider = factory();
142        }
143    })(function () {
144        "use strict";
145        // Removes duplicates from an array.
146        function unique(array) {
147            return array.filter(function (a) {
148                return !this[a] ? (this[a] = true) : false;
149            }, {});
150        }
151        // Round a value to the closest 'to'.
152
153        function closest(value, to) {
154            return Math.round(value / to) * to;
155        }
156        // Current position of an element relative to the document.
157
158        function offset(elem) {
159            var rect = elem.getBoundingClientRect(),
160                doc = elem.ownerDocument,
161                docElem = doc.documentElement,
162                pageOffset = getPageOffset();
163            // getBoundingClientRect contains left scroll in Chrome on Android.
164            // I haven't found a feature detection that proves this. Worst case
165            // scenario on mis-match: the 'tap' feature on horizontal sliders breaks.
166            if (/webkit.*Chrome.*Mobile/i.test(navigator.userAgent)) {
167                pageOffset.x = 0;
168            }
169            return {
170                top: rect.top + pageOffset.y - docElem.clientTop,
171                left: rect.left + pageOffset.x - docElem.clientLeft,
172            };
173        }
174        // Checks whether a value is numerical.
175
176        function isNumeric(a) {
177            return typeof a === "number" && !isNaN(a) && isFinite(a);
178        }
179        // Rounds a number to 7 supported decimals.
180
181        function accurateNumber(number) {
182            var p = Math.pow(10, 7);
183            return Number((Math.round(number * p) / p).toFixed(7));
184        }
185        // Sets a class and removes it after [duration] ms.
186
187        function addClassFor(element, className, duration) {
188            addClass(element, className);
189            setTimeout(function () {
190                removeClass(element, className);
191            }, duration);
192        }
193        // Limits a value to 0 - 100
194
195        function limit(a) {
196            return Math.max(Math.min(a, 100), 0);
197        }
198        // Wraps a variable as an array, if it isn't one yet.
199
200        function asArray(a) {
201            return Array.isArray(a) ? a : [a];
202        }
203        // Counts decimals
204
205        function countDecimals(numStr) {
206            var pieces = numStr.split(".");
207            return pieces.length > 1 ? pieces[1].length : 0;
208        }
209        // http://youmightnotneedjquery.com/#add_class
210
211        function addClass(el, className) {
212            if (el.classList) {
213                el.classList.add(className);
214            } else {
215                el.className += " " + className;
216            }
217        }
218        // http://youmightnotneedjquery.com/#remove_class
219
220        function removeClass(el, className) {
221            if (el.classList) {
222                el.classList.remove(className);
223            } else {
224                el.className = el.className.replace(new RegExp("(^|\\b)" + className.split(" ").join("|") + "(\\b|$)", "gi"), " ");
225            }
226        }
227        // https://plainjs.com/javascript/attributes/adding-removing-and-testing-for-classes-9/
228
229        function hasClass(el, className) {
230            return el.classList ? el.classList.contains(className) : new RegExp("\\b" + className + "\\b").test(el.className);
231        }
232        // https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollY#Notes
233
234        function getPageOffset() {
235            var supportPageOffset = window.pageXOffset !== undefined,
236                isCSS1Compat = (document.compatMode || "") === "CSS1Compat",
237                x = supportPageOffset ? window.pageXOffset : isCSS1Compat ? document.documentElement.scrollLeft : document.body.scrollLeft,
238                y = supportPageOffset ? window.pageYOffset : isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop;
239            return {
240                x: x,
241                y: y,
242            };
243        }
244        // Shorthand for stopPropagation so we don't have to create a dynamic method
245
246        function stopPropagation(e) {
247            e.stopPropagation();
248        }
249        // todo
250
251        function addCssPrefix(cssPrefix) {
252            return function (className) {
253                return cssPrefix + className;
254            };
255        }
256        var // Determine the events to bind. IE11 implements pointerEvents without
257            // a prefix, which breaks compatibility with the IE10 implementation.
258            /** @const */
259            actions = window.navigator.pointerEnabled
260                ? {
261                      start: "pointerdown",
262                      move: "pointermove",
263                      end: "pointerup",
264                  }
265                : window.navigator.msPointerEnabled
266                ? {
267                      start: "MSPointerDown",
268                      move: "MSPointerMove",
269                      end: "MSPointerUp",
270                  }
271                : {
272                      start: "mousedown touchstart",
273                      move: "mousemove touchmove",
274                      end: "mouseup touchend",
275                  },
276            defaultCssPrefix = "noUi-";
277        // Value calculation
278        // Determine the size of a sub-range in relation to a full range.
279        function subRangeRatio(pa, pb) {
280            return 100 / (pb - pa);
281        }
282        // (percentage) How many percent is this value of this range?
283
284        function fromPercentage(range, value) {
285            return (value * 100) / (range[1] - range[0]);
286        }
287        // (percentage) Where is this value on this range?
288
289        function toPercentage(range, value) {
290            return fromPercentage(range, range[0] < 0 ? value + Math.abs(range[0]) : value - range[0]);
291        }
292        // (value) How much is this percentage on this range?
293
294        function isPercentage(range, value) {
295            return (value * (range[1] - range[0])) / 100 + range[0];
296        }
297        // Range conversion
298
299        function getJ(value, arr) {
300            var j = 1;
301            while (value >= arr[j]) {
302                j += 1;
303            }
304            return j;
305        }
306        // (percentage) Input a value, find where, on a scale of 0-100, it applies.
307
308        function toStepping(xVal, xPct, value) {
309            if (value >= xVal.slice(-1)[0]) {
310                return 100;
311            }
312            var j = getJ(value, xVal),
313                va,
314                vb,
315                pa,
316                pb;
317            va = xVal[j - 1];
318            vb = xVal[j];
319            pa = xPct[j - 1];
320            pb = xPct[j];
321            return pa + toPercentage([va, vb], value) / subRangeRatio(pa, pb);
322        }
323        // (value) Input a percentage, find where it is on the specified range.
324
325        function fromStepping(xVal, xPct, value) {
326            // There is no range group that fits 100
327            if (value >= 100) {
328                return xVal.slice(-1)[0];
329            }
330            var j = getJ(value, xPct),
331                va,
332                vb,
333                pa,
334                pb;
335            va = xVal[j - 1];
336            vb = xVal[j];
337            pa = xPct[j - 1];
338            pb = xPct[j];
339            return isPercentage([va, vb], (value - pa) * subRangeRatio(pa, pb));
340        }
341        // (percentage) Get the step that applies at a certain value.
342
343        function getStep(xPct, xSteps, snap, value) {
344            if (value === 100) {
345                return value;
346            }
347            var j = getJ(value, xPct),
348                a,
349                b;
350            // If 'snap' is set, steps are used as fixed points on the slider.
351            if (snap) {
352                a = xPct[j - 1];
353                b = xPct[j];
354                // Find the closest position, a or b.
355                if (value - a > (b - a) / 2) {
356                    return b;
357                }
358                return a;
359            }
360            if (!xSteps[j - 1]) {
361                return value;
362            }
363            return xPct[j - 1] + closest(value - xPct[j - 1], xSteps[j - 1]);
364        }
365        // Entry parsing
366
367        function handleEntryPoint(index, value, that) {
368            var percentage;
369            // Wrap numerical input in an array.
370            if (typeof value === "number") {
371                value = [value];
372            }
373            // Reject any invalid input, by testing whether value is an array.
374            if (Object.prototype.toString.call(value) !== "[object Array]") {
375                throw new Error("noUiSlider: 'range' contains invalid value.");
376            }
377            // Covert min/max syntax to 0 and 100.
378            if (index === "min") {
379                percentage = 0;
380            } else if (index === "max") {
381                percentage = 100;
382            } else {
383                percentage = parseFloat(index);
384            }
385            // Check for correct input.
386            if (!isNumeric(percentage) || !isNumeric(value[0])) {
387                throw new Error("noUiSlider: 'range' value isn't numeric.");
388            }
389            // Store values.
390            that.xPct.push(percentage);
391            that.xVal.push(value[0]);
392            // NaN will evaluate to false too, but to keep
393            // logging clear, set step explicitly. Make sure
394            // not to override the 'step' setting with false.
395            if (!percentage) {
396                if (!isNaN(value[1])) {
397                    that.xSteps[0] = value[1];
398                }
399            } else {
400                that.xSteps.push(isNaN(value[1]) ? false : value[1]);
401            }
402        }
403
404        function handleStepPoint(i, n, that) {
405            // Ignore 'false' stepping.
406            if (!n) {
407                return true;
408            }
409            // Factor to range ratio
410            that.xSteps[i] = fromPercentage([that.xVal[i], that.xVal[i + 1]], n) / subRangeRatio(that.xPct[i], that.xPct[i + 1]);
411        }
412        // Interface
413        // The interface to Spectrum handles all direction-based
414        // conversions, so the above values are unaware.
415
416        function Spectrum(entry, snap, direction, singleStep) {
417            this.xPct = [];
418            this.xVal = [];
419            this.xSteps = [singleStep || false];
420            this.xNumSteps = [false];
421            this.snap = snap;
422            this.direction = direction;
423            var index,
424                ordered = [
425                    /* [0, 'min'], [1, '50%'], [2, 'max'] */
426                ];
427            // Map the object keys to an array.
428            for (index in entry) {
429                if (entry.hasOwnProperty(index)) {
430                    ordered.push([entry[index], index]);
431                }
432            }
433            // Sort all entries by value (numeric sort).
434            if (ordered.length && typeof ordered[0][0] === "object") {
435                ordered.sort(function (a, b) {
436                    return a[0][0] - b[0][0];
437                });
438            } else {
439                ordered.sort(function (a, b) {
440                    return a[0] - b[0];
441                });
442            }
443            // Convert all entries to subranges.
444            for (index = 0; index < ordered.length; index++) {
445                handleEntryPoint(ordered[index][1], ordered[index][0], this);
446            }
447            // Store the actual step values.
448            // xSteps is sorted in the same order as xPct and xVal.
449            this.xNumSteps = this.xSteps.slice(0);
450            // Convert all numeric steps to the percentage of the subrange they represent.
451            for (index = 0; index < this.xNumSteps.length; index++) {
452                handleStepPoint(index, this.xNumSteps[index], this);
453            }
454        }
455        Spectrum.prototype.getMargin = function (value) {
456            return this.xPct.length === 2 ? fromPercentage(this.xVal, value) : false;
457        };
458        Spectrum.prototype.toStepping = function (value) {
459            value = toStepping(this.xVal, this.xPct, value);
460            // Invert the value if this is a right-to-left slider.
461            if (this.direction) {
462                value = 100 - value;
463            }
464            return value;
465        };
466        Spectrum.prototype.fromStepping = function (value) {
467            // Invert the value if this is a right-to-left slider.
468            if (this.direction) {
469                value = 100 - value;
470            }
471            return accurateNumber(fromStepping(this.xVal, this.xPct, value));
472        };
473        Spectrum.prototype.getStep = function (value) {
474            // Find the proper step for rtl sliders by search in inverse direction.
475            // Fixes issue #262.
476            if (this.direction) {
477                value = 100 - value;
478            }
479            value = getStep(this.xPct, this.xSteps, this.snap, value);
480            if (this.direction) {
481                value = 100 - value;
482            }
483            return value;
484        };
485        Spectrum.prototype.getApplicableStep = function (value) {
486            // If the value is 100%, return the negative step twice.
487            var j = getJ(value, this.xPct),
488                offset = value === 100 ? 2 : 1;
489            return [this.xNumSteps[j - 2], this.xVal[j - offset], this.xNumSteps[j - offset]];
490        };
491        // Outside testing
492        Spectrum.prototype.convert = function (value) {
493            return this.getStep(this.toStepping(value));
494        };
495        /*	Every input option is tested and parsed. This'll prevent
496          endless validation in internal methods. These tests are
497          structured with an item for every option available. An
498          option can be marked as required by setting the 'r' flag.
499          The testing function is provided with three arguments:
500              - The provided value for the option;
501              - A reference to the options object;
502              - The name for the option;
503      
504          The testing function returns false when an error is detected,
505          or true when everything is OK. It can also modify the option
506          object, to make sure all values can be correctly looped elsewhere. */
507        var defaultFormatter = {
508            to: function (value) {
509                return value !== undefined && value.toFixed(2);
510            },
511            from: Number,
512        };
513
514        function testStep(parsed, entry) {
515            if (!isNumeric(entry)) {
516                throw new Error("noUiSlider: 'step' is not numeric.");
517            }
518            // The step option can still be used to set stepping
519            // for linear sliders. Overwritten if set in 'range'.
520            parsed.singleStep = entry;
521        }
522
523        function testRange(parsed, entry) {
524            // Filter incorrect input.
525            if (typeof entry !== "object" || Array.isArray(entry)) {
526                throw new Error("noUiSlider: 'range' is not an object.");
527            }
528            // Catch missing start or end.
529            if (entry.min === undefined || entry.max === undefined) {
530                throw new Error("noUiSlider: Missing 'min' or 'max' in 'range'.");
531            }
532            // Catch equal start or end.
533            if (entry.min === entry.max) {
534                throw new Error("noUiSlider: 'range' 'min' and 'max' cannot be equal.");
535            }
536            parsed.spectrum = new Spectrum(entry, parsed.snap, parsed.dir, parsed.singleStep);
537        }
538
539        function testStart(parsed, entry) {
540            entry = asArray(entry);
541            // Validate input. Values aren't tested, as the public .val method
542            // will always provide a valid location.
543            if (!Array.isArray(entry) || !entry.length || entry.length > 2) {
544                throw new Error("noUiSlider: 'start' option is incorrect.");
545            }
546            // Store the number of handles.
547            parsed.handles = entry.length;
548            // When the slider is initialized, the .val method will
549            // be called with the start options.
550            parsed.start = entry;
551        }
552
553        function testSnap(parsed, entry) {
554            // Enforce 100% stepping within subranges.
555            parsed.snap = entry;
556            if (typeof entry !== "boolean") {
557                throw new Error("noUiSlider: 'snap' option must be a boolean.");
558            }
559        }
560
561        function testAnimate(parsed, entry) {
562            // Enforce 100% stepping within subranges.
563            parsed.animate = entry;
564            if (typeof entry !== "boolean") {
565                throw new Error("noUiSlider: 'animate' option must be a boolean.");
566            }
567        }
568
569        function testConnect(parsed, entry) {
570            if (entry === "lower" && parsed.handles === 1) {
571                parsed.connect = 1;
572            } else if (entry === "upper" && parsed.handles === 1) {
573                parsed.connect = 2;
574            } else if (entry === true && parsed.handles === 2) {
575                parsed.connect = 3;
576            } else if (entry === false) {
577                parsed.connect = 0;
578            } else {
579                throw new Error("noUiSlider: 'connect' option doesn't match handle count.");
580            }
581        }
582
583        function testOrientation(parsed, entry) {
584            // Set orientation to an a numerical value for easy
585            // array selection.
586            switch (entry) {
587                case "horizontal":
588                    parsed.ort = 0;
589                    break;
590                case "vertical":
591                    parsed.ort = 1;
592                    break;
593                default:
594                    throw new Error("noUiSlider: 'orientation' option is invali
594d.");
595            }
596        }
597
598        function testMargin(parsed, entry) {
599            if (!isNumeric(entry)) {
600                throw new Error("noUiSlider: 'margin' option must be numeric.");
601            }
602            // Issue #582
603            if (entry === 0) {
604                return;
605            }
606            parsed.margin = parsed.spectrum.getMargin(entry);
607            if (!parsed.margin) {
608                throw new Error("noUiSlider: 'margin' option is only supported on linear sliders.");
609            }
610        }
611
612        function testLimit(parsed, entry) {
613            if (!isNumeric(entry)) {
614                throw new Error("noUiSlider: 'limit' option must be numeric.");
615            }
616            parsed.limit = parsed.spectrum.getMargin(entry);
617            if (!parsed.limit) {
618                throw new Error("noUiSlider: 'limit' option is only supported on linear sliders.");
619            }
620        }
621
622        function testDirection(parsed, entry) {
623            // Set direction as a numerical value for easy parsing.
624            // Invert connection for RTL sliders, so that the proper
625            // handles get the connect/background classes.
626            switch (entry) {
627                case "ltr":
628                    parsed.dir = 0;
629                    break;
630                case "rtl":
631                    parsed.dir = 1;
632                    parsed.connect = [0, 2, 1, 3][parsed.connect];
633                    break;
634                default:
635                    throw new Error("noUiSlider: 'direction' option was not recognized.");
636            }
637        }
638
639        function testBehaviour(parsed, entry) {
640            // Make sure the input is a string.
641            if (typeof entry !== "string") {
642                throw new Error("noUiSlider: 'behaviour' must be a string containing options.");
643            }
644            // Check if the string contains any keywords.
645            // None are required.
646            var tap = entry.indexOf("tap") >= 0,
647                drag = entry.indexOf("drag") >= 0,
648                fixed = entry.indexOf("fixed") >= 0,
649                snap = entry.indexOf("snap") >= 0,
650                hover = entry.indexOf("hover") >= 0;
651            // Fix #472
652            if (drag && !parsed.connect) {
653                throw new Error("noUiSlider: 'drag' behaviour must be used with 'connect': true.");
654            }
655            parsed.events = {
656                tap: tap || snap,
657                drag: drag,
658                fixed: fixed,
659                snap: snap,
660                hover: hover,
661            };
662        }
663
664        function testTooltips(parsed, entry) {
665            var i;
666            if (entry === false) {
667                return;
668            } else if (entry === true) {
669                parsed.tooltips = [];
670                for (i = 0; i < parsed.handles; i++) {
671                    parsed.tooltips.push(true);
672                }
673            } else {
674                parsed.tooltips = asArray(entry);
675                if (parsed.tooltips.length !== parsed.handles) {
676                    throw new Error("noUiSlider: must pass a formatter for all handles.");
677                }
678                parsed.tooltips.forEach(function (formatter) {
679                    if (typeof formatter !== "boolean" && (typeof formatter !== "object" || typeof formatter.to !== "function")) {
680                        throw new Error("noUiSlider: 'tooltips' must be passed a formatter or 'false'.");
681                    }
682                });
683            }
684        }
685
686        function testFormat(parsed, entry) {
687            parsed.format = entry;
688            // Any object with a to and from method is supported.
689            if (typeof entry.to === "function" && typeof entry.from === "function") {
690                return true;
691            }
692            throw new Error("noUiSlider: 'format' requires 'to' and 'from' methods.");
693        }
694
695        function testCssPrefix(parsed, entry) {
696            if (entry !== undefined && typeof entry !== "string") {
697                throw new Error("noUiSlider: 'cssPrefix' must be a string.");
698            }
699            parsed.cssPrefix = entry;
700        }
701        // Test all developer settings and parse to assumption-safe values.
702
703        function testOptions(options) {
704            // To prove a fix for #537, freeze options here.
705            // If the object is modified, an error will be thrown.
706            // Object.freeze(options);
707            var parsed = {
708                    margin: 0,
709                    limit: 0,
710                    animate: true,
711                    format: defaultFormatter,
712                },
713                tests;
714            // Tests are executed in the order they are presented here.
715            tests = {
716                step: {
717                    r: false,
718                    t: testStep,
719                },
720                start: {
721                    r: true,
722                    t: testStart,
723                },
724                connect: {
725                    r: true,
726                    t: testConnect,
727                },
728                direction: {
729                    r: true,
730                    t: testDirection,
731                },
732                snap: {
733                    r: false,
734                    t: testSnap,
735                },
736                animate: {
737                    r: false,
738                    t: testAnimate,
739                },
740                range: {
741                    r: true,
742                    t: testRange,
743                },
744                orientation: {
745                    r: false,
746                    t: testOrientation,
747                },
748                margin: {
749                    r: false,
750                    t: testMargin,
751                },
752                limit: {
753                    r: false,
754                    t: testLimit,
755                },
756                behaviour: {
757                    r: true,
758                    t: testBehaviour,
759                },
760                format: {
761                    r: false,
762                    t: testFormat,
763                },
764                tooltips: {
765                    r: false,
766                    t: testTooltips,
767                },
768                cssPrefix: {
769                    r: false,
770                    t: testCssPrefix,
771                },
772            };
773            var defaults = {
774                connect: false,
775                direction: "ltr",
776                behaviour: "tap",
777                orientation: "horizontal",
778            };
779            // Run all options through a testing mechanism to ensure correct
780            // input. It should be noted that options might get modified to
781            // be handled properly. E.g. wrapping integers in arrays.
782            Object.keys(tests).forEach(function (name) {
783                // If the option isn't set, but it is required, throw an error.
784                if (options[name] === undefined && defaults[name] === undefined) {
785                    if (tests[name].r) {
786                        throw new Error("noUiSlider: '" + name + "' is required.");
787                    }
788                    return true;
789                }
790                tests[name].t(parsed, options[name] === undefined ? defaults[name] : options[name]);
791            });
792            // Forward pips options
793            parsed.pips = options.pips;
794            // Pre-define the styles.
795            parsed.style = parsed.ort ? "top" : "left";
796            return parsed;
797        }
798
799        function closure(target, options) {
800            // All variables local to 'closure' are prefixed with 'scope_'
801            var scope_Target = target,
802                scope_Locations = [-1, -1],
803                scope_Base,
804                scope_Handles,
805                scope_Spectrum = options.spectrum,
806                scope_Values = [],
807                scope_Events = {},
808                scope_Self;
809            var cssClasses = [
810                /*  0 */
811                "target",
812                /*  1 */
813                "base",
814                /*  2 */
815                "origin",
816                /*  3 */
817                "handle",
818                /*  4 */
819                "horizontal",
820                /*  5 */
821                "vertical",
822                /*  6 */
823                "background",
824                /*  7 */
825                "connect",
826                /*  8 */
827                "ltr",
828                /*  9 */
829                "rtl",
830                /* 10 */
831                "draggable",
832                /* 11 */
833                "",
834                /* 12 */
835                "state-drag",
836                /* 13 */
837                "",
838                /* 14 */
839                "state-tap",
840                /* 15 */
841                "active",
842                /* 16 */
843                "",
844                /* 17 */
845                "stacking",
846                /* 18 */
847                "tooltip",
848                /* 19 */
849                "",
850                /* 20 */
851                "pips",
852                /* 21 */
853                "marker",
854                /* 22 */
855                "value",
856            ].map(addCssPrefix(options.cssPrefix || defaultCssPrefix));
857            // Delimit proposed values for handle positions.
858            function getPositions(a, b, delimit) {
859                // Add movement to current position.
860                var c = a + b[0],
861                    d = a + b[1];
862                // Only alter the other position on drag,
863                // not on standard sliding.
864                if (delimit) {
865                    if (c < 0) {
866                        d += Math.abs(c);
867                    }
868                    if (d > 100) {
869                        c -= d - 100;
870                    }
871                    // Limit values to 0 and 100.
872                    return [limit(c), limit(d)];
873                }
874                return [c, d];
875            }
876            // Provide a clean event with standardized offset values.
877
878            function fixEvent(e, pageOffset) {
879                // Prevent scrolling and panning on touch events, while
880                // attempting to slide. The tap event also depends on this.
881                e.preventDefault();
882                // Filter the event to register the type, which can be
883                // touch, mouse or pointer. Offset changes need to be
884                // made on an event specific basis.
885                var touch = e.type.indexOf("touch") === 0,
886                    mouse = e.type.indexOf("mouse") === 0,
887                    pointer = e.type.indexOf("pointer") === 0,
888                    x,
889                    y,
890                    event = e;
891                // IE10 implemented pointer events with a prefix;
892                if (e.type.indexOf("MSPointer") === 0) {
893                    pointer = true;
894                }
895                if (touch) {
896                    // noUiSlider supports one movement at a time,
897                    // so we can select the first 'changedTouch'.
898                    x = e.changedTouches[0].pageX;
899                    y = e.changedTouches[0].pageY;
900                }
901                pageOffset = pageOffset || getPageOffset();
902                if (mouse || pointer) {
903                    x = e.clientX + pageOffset.x;
904                    y = e.clientY + pageOffset.y;
905                }
906                event.pageOffset = pageOffset;
907                event.points = [x, y];
908                event.cursor = mouse || pointer; // Fix #435
909                return event;
910            }
911            // Append a handle to the base.
912
913            function addHandle(direction, index) {
914                var origin = document.createElement("div"),
915                    handle = document.createElement("div"),
916                    additions = ["-lower", "-upper"];
917                if (direction) {
918                    additions.reverse();
919                }
920                addClass(handle, cssClasses[3]);
921                addClass(handle, cssClasses[3] + additions[index]);
922                addClass(origin, cssClasses[2]);
923                origin.appendChild(handle);
924                return origin;
925            }
926            // Add the proper connection classes.
927
928            function addConnection(connect, target, handles) {
929                // Apply the required connection classes to the elements
930                // that need them. Some classes are made up for several
931                // segments listed in the class list, to allow easy
932                // renaming and provide a minor compression benefit.
933                switch (connect) {
934                    case 1:
935                        addClass(target, cssClasses[7]);
936                        addClass(handles[0], cssClasses[6]);
937                        break;
938                    case 3:
939                        addClass(handles[1], cssClasses[6]);
940                    /* falls through */
941                    case 2:
942                        addClass(handles[0], cssClasses[7]);
943                    /* falls through */
944                    case 0:
945                        addClass(target, cssClasses[6]);
946                        break;
947                }
948            }
949            // Add handles to the slider base.
950
951            function addHandles(nrHandles, direction, base) {
952                var index,
953                    handles = [];
954                // Append handles.
955                for (index = 0; index < nrHandles; index += 1) {
956                    // Keep a list of all added handles.
957                    handles.push(base.appendChild(addHandle(direction, index)));
958                }
959                return handles;
960            }
961            // Initialize a single slider.
962
963            function addSlider(direction, orientation, target) {
964                // Apply classes and data to the target.
965                addClass(target, cssClasses[0]);
966                addClass(target, cssClasses[8 + direction]);
967                addClass(target, cssClasses[4 + orientation]);
968                var div = document.createElement("div");
969                addClass(div, cssClasses[1]);
970                target.appendChild(div);
971                return div;
972            }
973
974            function addTooltip(handle, index) {
975                if (!options.tooltips[index]) {
976                    return false;
977                }
978                var element = document.createElement("div");
979                element.className = cssClasses[18];
980                return handle.firstChild.appendChild(element);
981            }
982            // The tooltips option is a shorthand for using the 'update' event.
983
984            function tooltips() {
985                if (options.dir) {
986                    options.tooltips.reverse();
987                }
988                // Tooltips are added with options.tooltips in original order.
989                var tips = scope_Handles.map(addTooltip);
990                if (options.dir) {
991                    tips.reverse();
992                    options.tooltips.reverse();
993                }
994                bindEvent("update", function (f, o, r) {
995                    if (tips[o]) {
996                        tips[o].innerHTML = options.tooltips[o] === true ? f[o] : options.tooltips[o].to(r[o]);
997                    }
998                });
999            }
1000
1001            function getGroup(mode, values, stepped) {
1002                // Use the range.
1003                if (mode === "range" || mode === "steps") {
1004                    return scope_Spectrum.xVal;
1005                }
1006                if (mode === "count") {
1007                    // Divide 0 - 100 in 'count' parts.
1008                    var spread = 100 / (values - 1),
1009                        v,
1010                        i = 0;
1011                    values = [];
1012                    // List these parts and have them handled as 'positions'.
1013                    while ((v = i++ * spread) <= 100) {
1014                        values.push(v);
1015                    }
1016                    mode = "positions";
1017                }
1018                if (mode === "positions") {
1019                    // Map all percentages to on-range values.
1020                    return values.map(function (value) {
1021                        return scope_Spectrum.fromStepping(stepped ? scope_Spectrum.getStep(value) : value);
1022                    });
1023                }
1024                if (mode === "values") {
1025                    // If the value must be stepped, it needs to be converted to a percentage first.
1026                    if (stepped) {
1027                        return values.map(function (value) {
1028                            // Convert to percentage, apply step, return to value.
1029                            return scope_Spectrum.fromStepping(scope_Spectrum.getStep(scope_Spectrum.toStepping(value)));
1030                        });
1031                    }
1032                    // Otherwise, we can simply use the values.
1033                    return values;
1034                }
1035            }
1036
1037            function generateSpread(density, mode, group) {
1038                function safeIncrement(value, increment) {
1039                    // Avoid floating point variance by dropping the smallest decimal places.
1040                    return (value + increment).toFixed(7) / 1;
1041                }
1042                var originalSpectrumDirection = scope_Spectrum.direction,
1043                    indexes = {},
1044                    firstInRange = scope_Spectrum.xVal[0],
1045                    lastInRange = scope_Spectrum.xVal[scope_Spectrum.xVal.length - 1],
1046                    ignoreFirst = false,
1047                    ignoreLast = false,
1048                    prevPct = 0;
1049                // This function loops the spectrum in an ltr linear fashion,
1050                // while the toStepping method is direction aware. Trick it into
1051                // believing it is ltr.
1052                scope_Spectrum.direction = 0;
1053                // Create a copy of the group, sort it and filter away all duplicates.
1054                group = unique(
1055                    group.slice().sort(function (a, b) {
1056                        return a - b;
1057                    })
1058                );
1059                // Make sure the range starts with the first element.
1060                if (group[0] !== firstInRange) {
1061                    group.unshift(firstInRange);
1062                    ignoreFirst = true;
1063                }
1064                // Likewise for the last one.
1065                if (group[group.length - 1] !== lastInRange) {
1066                    group.push(lastInRange);
1067                    ignoreLast = true;
1068                }
1069                group.forEach(function (current, index) {
1070                    // Get the current step and the lower + upper positions.
1071                    var step,
1072                        i,
1073                        q,
1074                        low = current,
1075                        high = group[index + 1],
1076                        newPct,
1077                        pctDifference,
1078                        pctPos,
1079                        type,
1080                        steps,
1081                        realSteps,
1082                        stepsize;
1083                    // When using 'steps' mode, use the provided steps.
1084                    // Otherwise, we'll step on to the next subrange.
1085                    if (mode === "steps") {
1086                        step = scope_Spectrum.xNumSteps[index];
1087                    }
1088                    // Default to a 'full' step.
1089                    if (!step) {
1090                        step = high - low;
1091                    }
1092                    // Low can be 0, so test for false. If high is undefined,
1093                    // we are at the last subrange. Index 0 is already handled.
1094                    if (low === false || high === undefined) {
1095                        return;
1096                    }
1097                    // Find all steps in the subrange.
1098                    for (i = low; i <= high; i = safeIncrement(i, step)) {
1099                        // Get the percentage value for the current step,
1100                        // calculate the size for the subrange.
1101                        newPct = scope_Spectrum.toStepping(i);
1102                        pctDifference = newPct - prevPct;
1103                        steps = pctDifference / density;
1104                        realSteps = Math.round(steps);
1105                        // This ratio represents the ammount of percentage-space a point indicates.
1106                        // For a density 1 the points/percentage = 1. For density 2, that percentage needs to be re-devided.
1107                        // Round the percentage offset to an even number, then divide by two
1108                        // to spread the offset on both sides of the range.
1109                        stepsize = pctDifference / realSteps;
1110                        // Divide all points evenly, adding the correct number to this subrange.
1111                        // Run up to <= so that 100% gets a point, event if ignoreLast is set.
1112                        for (q = 1; q <= realSteps; q += 1) {
1113                            // The ratio between the rounded value and the actual size might be ~1% off.
1114                            // Correct the percentage offset by the number of points
1115                            // per subrange. density = 1 will result in 100 points on the
1116                            // full range, 2 for 50, 4 for 25, etc.
1117                            pctPos = prevPct + q * stepsize;
1118                            indexes[pctPos.toFixed(5)] = ["x", 0];
1119                        }
1120                        // Determine the point type.
1121                        type = group.indexOf(i) > -1 ? 1 : mode === "steps" ? 2 : 0;
1122                        // Enforce the 'ignoreFirst' option by overwriting the type for 0.
1123                        if (!index && ignoreFirst) {
1124                            type = 0;
1125                        }
1126                        if (!(i === high && ignoreLast)) {
1127                            // Mark the 'type' of this point. 0 = plain, 1 = real value, 2 = step value.
1128                            indexes[newPct.toFixed(5)] = [i, type];
1129                        }
1130                        // Update the percentage count.
1131                        prevPct = newPct;
1132                    }
1133                });
1134                // Reset the spectrum.
1135                scope_Spectrum.direction = originalSpectrumDirection;
1136                return indexes;
1137            }
1138
1139            function addMarking(spread, filterFunc, formatter) {
1140                var style = ["horizontal", "vertical"][options.ort],
1141                    element = document.createElement("div"),
1142                    out = "";
1143                addClass(element, cssClasses[20]);
1144                addClass(element, cssClasses[20] + "-" + style);
1145
1146                function getSize(type) {
1147                    return ["-normal", "-large", "-sub"][type];
1148                }
1149
1150                function getTags(offset, source, values) {
1151                    return 'class="' + source + " " + source + "-" + style + " " + source + getSize(values[1]) + '" style="' + options.style + ": " + offset + '%"';
1152                }
1153
1154                function addSpread(offset, values) {
1155                    if (scope_Spectrum.direction) {
1156                        offset = 100 - offset;
1157                    }
1158                    // Apply the filter function, if it is set.
1159                    values[1] = values[1] && filterFunc ? filterFunc(values[0], values[1]) : values[1];
1160                    // Add a marker for every point
1161                    out += "<div " + getTags(offset, cssClasses[21], values) + "></div>";
1162                    // Values are only appended for points marked '1' or '2'.
1163                    if (values[1]) {
1164                        out += "<div " + getTags(offset, cssClasses[22], values) + ">" + formatter.to(values[0]) + "</div>";
1165                    }
1166                }
1167                // Append all points.
1168                Object.keys(spread).forEach(function (a) {
1169                    addSpread(a, spread[a]);
1170                });
1171                element.innerHTML = out;
1172                return element;
1173            }
1174
1175            function pips(grid) {
1176                var mode = grid.mode,
1177                    density = grid.density || 1,
1178                    filter = grid.filter || false,
1179                    values = grid.values || false,
1180                    stepped = grid.stepped || false,
1181                    group = getGroup(mode, values, stepped),
1182                    spread = generateSpread(density, mode, group),
1183                    format = grid.format || {
1184                        to: Math.round,
1185                    };
1186                return scope_Target.appendChild(addMarking(spread, filter, format));
1187            }
1188            // Shorthand for base dimensions.
1189
1190            function baseSize() {
1191                var rect = scope_Base.getBoundingClientRect(),
1192                    alt = "offset" + ["Width", "Height"][options.ort];
1193                return options.ort === 0 ? rect.width || scope_Base[alt] : rect.height || scope_Base[alt];
1194            }
1195            // External event handling
1196
1197            function fireEvent(event, handleNumber, tap) {
1198                if (handleNumber !== undefined && options.handles !== 1) {
1199                    handleNumber = Math.abs(handleNumber - options.dir);
1200                }
1201                Object.keys(scope_Events).forEach(function (targetEvent) {
1202                    var eventType = targetEvent.split(".")[0];
1203                    if (event === eventType) {
1204                        scope_Events[targetEvent].forEach(function (callback) {
1205                            callback.call(
1206                                // Use the slider public API as the scope ('this')
1207                                scope_Self,
1208                                // Return values as array, so arg_1[arg_2] is always valid.
1209                                asArray(valueGet()),
1210                                // Handle index, 0 or 1
1211                                handleNumber,
1212                                // Unformatted slider values
1213                                asArray(inSliderOrder(Array.prototype.slice.call(scope_Values))),
1214                                // Event is fired by tap, true or false
1215                                tap || false,
1216                                // Left offset of the handle, in relation to the slider
1217                                scope_Locations
1218                            );
1219                        });
1220                    }
1221                });
1222            }
1223            // Returns the input array, respecting the slider direction configuration.
1224
1225            function inSliderOrder(values) {
1226                // If only one handle is used, return a single value.
1227                if (values.length === 1) {
1228                    return values[0];
1229                }
1230                if (options.dir) {
1231                    return values.reverse();
1232                }
1233                return values;
1234            }
1235            // Handler for attaching events trough a proxy.
1236
1237            function attach(events, element, callback, data) {
1238                // This function can be used to 'filter' events to the slider.
1239                // element is a node, not a nodeList
1240                var method = function (e) {
1241                        if (scope_Target.hasAttribute("disabled")) {
1242                            return false;
1243                        }
1244                        // Stop if an active 'tap' transition is taking place.
1245                        if (hasClass(scope_Target, cssClasses[14])) {
1246                            return false;
1247                        }
1248                        e = fixEvent(e, data.pageOffset);
1249                        // Ignore right or middle clicks on start #454
1250                        if (events === actions.start && e.buttons !== undefined && e.buttons > 1) {
1251                            return false;
1252                        }
1253                        // Ignore right or middle clicks on start #454
1254                        if (data.hover && e.buttons) {
1255                            return false;
1256                        }
1257                        e.calcPoint = e.points[options.ort];
1258                        // Call the event handler with the event [ and additional data ].
1259                        callback(e, data);
1260                    },
1261                    methods = [];
1262                // Bind a closure on the target for every event type.
1263                events.split(" ").forEach(function (eventName) {
1264                    element.addEventListener(eventName, method, false);
1265                    methods.push([eventName, method]);
1266                });
1267                return methods;
1268            }
1269            // Handle movement on document for handle and range drag.
1270
1271            function move(event, data) {
1272                // Fix #498
1273                // Check value of .buttons in 'start' to work around a bug in IE10 mobile (data.buttonsProperty).
1274                // https://connect.microsoft.com/IE/feedback/details/927005/mobile-ie10-windows-phone-buttons-property-of-pointermove-event-always-zero
1275                // IE9 has .buttons and .which zero on mousemove.
1276                // Firefox breaks the spec MDN defines.
1277                if (navigator.appVersion.indexOf("MSIE 9") === -1 && event.buttons === 0 && data.buttonsProperty !== 0) {
1278                    return end(event, data);
1279                }
1280                var handles = data.handles || scope_Handles,
1281                    positions,
1282                    state = false,
1283                    proposal = ((event.calcPoint - data.start) * 100) / data.baseSize,
1284                    handleNumber = handles[0] === scope_Handles[0] ? 0 : 1,
1285                    i;
1286                // Calculate relative positions for the handles.
1287                positions = getPositions(proposal, data.positions, handles.length > 1);
1288                state = setHandle(handles[0], positions[handleNumber], handles.length === 1);
1289                if (handles.length > 1) {
1290                    state = setHandle(handles[1], positions[handleNumber ? 0 : 1], false) || state;
1291                    if (state) {
1292                        // fire for both handles
1293                        for (i = 0; i < data.handles.length; i++) {
1294                            fireEvent("slide", i);
1295                        }
1296                    }
1297                } else if (state) {
1298                    // Fire for a single handle
1299                    fireEvent("slide", handleNumber);
1300                }
1301            }
1302            // Unbind move events on document, call callbacks.
1303
1304            function end(event, data) {
1305                // The handle is no longer active, so remove the class.
1306                var active = scope_Base.querySelector("." + cssClasses[15]),
1307                    handleNumber = data.handles[0] === scope_Handles[0] ? 0 : 1;
1308                if (active !== null) {
1309                    removeClass(active, cssClasses[15]);
1310                }
1311                // Remove cursor styles and text-selection events bound to the body.
1312                if (event.cursor) {
1313                    document.body.style.cursor = "";
1314                    document.body.removeEventListener("selectstart", document.body.noUiListener);
1315                }
1316                var d = document.documentElement;
1317                // Unbind the move and end events, which are added on 'start'.
1318                d.noUiListeners.forEach(function (c) {
1319                    d.removeEventListener(c[0], c[1]);
1320                });
1321                // Remove dragging class.
1322                removeClass(scope_Target, cssClasses[12]);
1323                // Fire the change and set events.
1324                fireEvent("set", handleNumber);
1325                fireEvent("change", handleNumber);
1326                // If this is a standard handle movement, fire the end event.
1327                if (data.handleNumber !== undefined) {
1328                    fireEvent("end", data.handleNumber);
1329                }
1330            }
1331            // Fire 'end' when a mouse or pen leaves the document.
1332
1333            function documentLeave(event, data) {
1334                if (event.type === "mouseout" && event.target.nodeName === "HTML" && event.relatedTarget === null) {
1335                    end(event, data);
1336                }
1337            }
1338            // Bind move events on document.
1339
1340            function start(event, data) {
1341                var d = document.documentElement;
1342                // Mark the handle as 'active' so it can be styled.
1343                if (data.handles.length === 1) {
1344                    addClass(data.handles[0].children[0], cssClasses[15]);
1345                    // Support 'disabled' handles
1346                    if (data.handles[0].hasAttribute("disabled")) {
1347                        return false;
1348                    }
1349                }
1350                // Fix #551, where a handle gets selected instead of dragged.
1351                event.preventDefault();
1352                // A drag should never propagate up to the 'tap' event.
1353                event.stopPropagation();
1354                // Attach the move and end events.
1355                var moveEvent = attach(actions.move, d, move, {
1356                        start: event.calcPoint,
1357                        baseSize: baseSize(),
1358                        pageOffset: event.pageOffset,
1359                        handles: data.handles,
1360                        handleNumber: data.handleNumber,
1361                        buttonsProperty: event.buttons,
1362                        positions: [scope_Locations[0], scope_Locations[scope_Handles.length - 1]],
1363                    }),
1364                    endEvent = attach(actions.end, d, end, {
1365                        handles: data.handles,
1366                        handleNumber: data.handleNumber,
1367                    });
1368                var outEvent = attach("mouseout", d, documentLeave, {
1369                    handles: data.handles,
1370                    handleNumber: data.handleNumber,
1371                });
1372                d.noUiListeners = moveEvent.concat(endEvent, outEvent);
1373                // Text selection isn't an issue on touch devices,
1374                // so adding cursor styles can be skipped.
1375                if (event.cursor) {
1376                    // Prevent the 'I' cursor and extend the range-drag cursor.
1377                    document.body.style.cursor = getComputedStyle(event.target).cursor;
1378                    // Mark the target with a dragging state.
1379                    if (scope_Handles.length > 1) {
1380                        addClass(scope_Target, cssClasses[12]);
1381                    }
1382                    var f = function () {
1383                        return false;
1384                    };
1385                    document.body.noUiListener = f;
1386                    // Prevent text selection when dragging the handles.
1387                    document.body.addEventListener("selectstart", f, false);
1388                }
1389                if (data.handleNumber !== undefined) {
1390                    fireEvent("start", data.handleNumber);
1391                }
1392            }
1393            // Move closest handle to tapped location.
1394
1395            function tap(event) {
1396                var location = event.calcPoint,
1397                    total = 0,
1398                    handleNumber,
1399                    to;
1400                // The tap event shouldn't propagate up and cause 'edge' to run.
1401                event.stopPropagation();
1402                // Add up the handle offsets.
1403                scope_Handles.forEach(function (a) {
1404                    total += offset(a)[options.style];
1405                });
1406                // Find the handle closest to the tapped position.
1407                handleNumber = location < total / 2 || scope_Handles.length === 1 ? 0 : 1;
1408                // Check if handler is not disablet if yes set number to the next handler
1409                if (scope_Handles[handleNumber].hasAttribute("disabled")) {
1410                    handleNumber = handleNumber ? 0 : 1;
1411                }
1412                location -= offset(scope_Base)[options.style];
1413                // Calculate the new position.
1414                to = (location * 100) / baseSize();
1415                if (!options.events.snap) {
1416                    // Flag the slider as it is now in a transitional state.
1417                    // Transition takes 300 ms, so re-enable the slider afterwards.
1418                    addClassFor(scope_Target, cssClasses[14], 300);
1419                }
1420                // Support 'disabled' handles
1421                if (scope_Handles[handleNumber].hasAttribute("disabled")) {
1422                    return false;
1423                }
1424                // Find the closest handle and calculate the tapped point.
1425                // The set handle to the new position.
1426                setHandle(scope_Handles[handleNumber], to);
1427                fireEvent("slide", handleNumber, true);
1428                fireEvent("set", handleNumber, true);
1429                fireEvent("change", handleNumber, true);
1430                if (options.events.snap) {
1431                    start(event, {
1432                        handles: [scope_Handles[handleNumber]],
1433                    });
1434                }
1435            }
1436            // Fires a 'hover' event for a hovered mouse/pen position.
1437
1438            function hover(event) {
1439                var location = event.calcPoint - offset(scope_Base)[options.style],
1440                    to = scope_Spectrum.getStep((location * 100) / baseSize()),
1441                    value = scope_Spectrum.fromStepping(to);
1442                Object.keys(scope_Events).forEach(function (targetEvent) {
1443                    if ("hover" === targetEvent.split(".")[0]) {
1444                        scope_Events[targetEvent].forEach(function (callback) {
1445                            callback.call(scope_Self, value);
1446                        });
1447                    }
1448                });
1449            }
1450            // Attach events to several slider parts.
1451
1452            function events(behaviour) {
1453                var i, drag;
1454                // Attach the standard drag event to the handles.
1455                if (!behaviour.fixed) {
1456                    for (i = 0; i < scope_Handles.length; i += 1) {
1457                        // These events are only bound to the visual handle
1458                        // element, not the 'real' origin element.
1459                        attach(actions.start, scope_Handles[i].children[0], start, {
1460                            handles: [scope_Handles[i]],
1461                            handleNumber: i,
1462                        });
1463                    }
1464                }
1465                // Attach the tap event to the slider base.
1466                if (behaviour.tap) {
1467                    attach(actions.start, scope_Base, tap, {
1468                        handles: scope_Handles,
1469                    });
1470                }
1471                // Fire hover events
1472                if (behaviour.hover) {
1473                    attach(actions.move, scope_Base, hover, {
1474                        hover: true,
1475                    });
1476                    for (i = 0; i < scope_Handles.length; i += 1) {
1477                        ["mousemove MSPointerMove pointermove"].forEach(function (eventName) {
1478                            scope_Handles[i].children[0].addEventListener(eventName, stopPropagation, false);
1479                        });
1480                    }
1481                }
1482                // Make the range draggable.
1483                if (behaviour.drag) {
1484                    drag = [scope_Base.querySelector("." + cssClasses[7])];
1485                    addClass(drag[0], cssClasses[10]);
1486                    // When the range is fixed, the entire range can
1487                    // be dragged by the handles. The handle in the first
1488                    // origin will propagate the start event upward,
1489                    // but it needs to be bound manually on the other.
1490                    if (behaviour.fixed) {
1491                        drag.push(scope_Handles[drag[0] === scope_Handles[0] ? 1 : 0].children[0]);
1492                    }
1493                    drag.forEach(function (element) {
1494                        attach(actions.start, element, start, {
1495                            handles: scope_Handles,
1496                        });
1497                    });
1498                }
1499            }
1500            // Test suggested values and apply margin, step.
1501
1502            function setHandle(handle, to, noLimitOption) {
1503                var trigger = handle !== scope_Handles[0] ? 1 : 0,
1504                    lowerMargin = scope_Locations[0] + options.margin,
1505                    upperMargin = scope_Locations[1] - options.margin,
1506                    lowerLimit = scope_Locations[0] + options.limit,
1507                    upperLimit = scope_Locations[1] - options.limit;
1508                // For sliders with multiple handles,
1509                // limit movement to the other handle.
1510                // Apply the margin option by adding it to the handle positions.
1511                if (scope_Handles.length > 1) {
1512                    to = trigger ? Math.max(to, lowerMargin) : Math.min(to, upperMargin);
1513                }
1514                // The limit option has the opposite effect, limiting handles to a
1515                // maximum distance from another. Limit must be > 0, as otherwise
1516                // handles would be unmoveable. 'noLimitOption' is set to 'false'
1517                // for the .val() method, except for pass 4/4.
1518                if (noLimitOption !== false && options.limit && scope_Handles.length > 1) {
1519                    to = trigger ? Math.min(to, lowerLimit) : Math.max(to, upperLimit);
1520                }
1521                // Handle the step option.
1522                to = scope_Spectrum.getStep(to);
1523                // Limit to 0/100 for .val input, trim anything beyond 7 digits, as
1524                // JavaScript has some issues in its floating point implementation.
1525                to = limit(parseFloat(to.toFixed(7)));
1526                // Return false if handle can't move
1527                if (to === scope_Locations[trigger]) {
1528                    return false;
1529                }
1530                // Set the handle to the new position.
1531                // Use requestAnimationFrame for efficient painting.
1532                // No significant effect in Chrome, Edge sees dramatic
1533                // performace improvements.
1534                if (window.requestAnimationFrame) {
1535                    window.requestAnimationFrame(function () {
1536                        handle.style[options.style] = to + "%";
1537                    });
1538                } else {
1539                    handle.style[options.style] = to + "%";
1540                }
1541                // Force proper handle stacking
1542                if (!handle.previousSibling) {
1543                    removeClass(handle, cssClasses[17]);
1544                    if (to > 50) {
1545                        addClass(handle, cssClasses[17]);
1546                    }
1547                }
1548                // Update locations.
1549                scope_Locations[trigger] = to;
1550                // Convert the value to the slider stepping/range.
1551                scope_Values[trigger] = scope_Spectrum.fromStepping(to);
1552                fireEvent("update", trigger);
1553                return true;
1554            }
1555            // Loop values from value method and apply them.
1556
1557            function setValues(count, values) {
1558                var i, trigger, to;
1559                // With the limit option, we'll need another limiting pass.
1560                if (options.limit) {
1561                    count += 1;
1562                }
1563                // If there are multiple handles to be set run the setting
1564                // mechanism twice for the first handle, to make sure it
1565                // can be bounced of the second one properly.
1566                for (i = 0; i < count; i += 1) {
1567                    trigger = i % 2;
1568                    // Get the current argument from the array.
1569                    to = values[trigger];
1570                    // Setting with null indicates an 'ignore'.
1571                    // Inputting 'false' is invalid.
1572                    if (to !== null && to !== false) {
1573                        // If a formatted number was passed, attemt to decode it.
1574                        if (typeof to === "number") {
1575                            to = String(to);
1576                        }
1577                        to = options.format.from(to);
1578                        // Request an update for all links if the value was invali
1578d.
1579                        // Do so too if setting the handle fails.
1580                        if (to === false || isNaN(to) || setHandle(scope_Handles[trigger], scope_Spectrum.toStepping(to), i === 3 - options.dir) === false) {
1581                            fireEvent("update", trigger);
1582                        }
1583                    }
1584                }
1585            }
1586            // Set the slider value.
1587
1588            function valueSet(input) {
1589                var count,
1590                    values = asArray(input),
1591                    i;
1592                // The RTL settings is implemented by reversing the front-end,
1593                // internal mechanisms are the same.
1594                if (options.dir && options.handles > 1) {
1595                    values.reverse();
1596                }
1597                // Animation is optional.
1598                // Make sure the initial values where set before using animated placement.
1599                if (options.animate && scope_Locations[0] !== -1) {
1600                    addClassF
1600or(scope_Target, cssClasses[14], 300);
1601                }
1602                // Determine how often to set the handles.
1603                count = scope_Handles.length > 1 ? 3 : 1;
1604                if (values.length === 1) {
1605                    count = 1;
1606                }
1607                setValues(count, values);
1608                // Fire the 'set' event for both handles.
1609                for (i = 0; i < scope_Handles.length; i++) {
1610                    // Fire the event only for handles that received a new value, as per #579
1611                    if (values[i] !== null) {
1612                        fireEvent("set", i);
1613                    }
1614                }
1615            }
1616            // Get the slider value.
1617
1618            function valueGet() {
1619                var i,
1620                    retour = [];
1621                // Get the value from all handles.
1622                for (i = 0; i < options.handles; i += 1) {
1623                    retour[i] = options.format.to(scope_Values[i]);
1624                }
1625                return inSliderOrder(retour);
1626            }
1627            // Removes classes from the root and empties it.
1628
1629            function destroy() {
1630                cssClasses.forEach(function (cls) {
1631                    if (!cls) {
1632                        return;
1633                    } // Ignore empty classes
1634                    removeClass(scope_Target, cls);
1635                });
1636                while (scope_Target.firstChild) {
1637                    scope_Target.removeChild(scope_Target.firstChild);
1638                }
1639                delete scope_Target.noUiSlider;
1640            }
1641            // Get the current step size for the slider.
1642
1643            function getCurrentStep() {
1644                // Check all locations, map them to their stepping point.
1645                // Get the step point, then find it in the input list.
1646                var retour = scope_Locations.map(function (location, index) {
1647                    var step = scope_Spectrum.getApplicableStep(location),
1648                        // As per #391, the comparison for the decrement step can have some rounding issues.
1649                        // Round the value to the precision used in the step.
1650                        stepDecimals = countDecimals(String(step[2])),
1651                        // Get the current numeric value
1652                        value = scope_Values[index],
1653                        // To move the slider 'one step up', the current step value needs to be added.
1654                        // Use null if we are at the maximum slider value.
1655                        increment = location === 100 ? null : step[2],
1656                        // Going 'one step down' might put the slider in a different sub-range, so we
1657                        // need to switch between the current or the previous step.
1658                        prev = Number((value - step[2]).toFixed(stepDecimals)),
1659                        // If the value fits the step, return the current step value. Otherwise, use the
1660                        // previous step. Return null if the slider is at its minimum value.
1661                        decrement = location === 0 ? null : prev >= step[1] ? step[2] : step[0] || false;
1662                    return [decrement, increment];
1663                });
1664                // Return values in the proper order.
1665                return inSliderOrder(retour);
1666            }
1667            // Attach an event to this slider, possibly including a namespace
1668
1669            function bindEvent(namespacedEvent, callback) {
1670                scope_Events[namespacedEvent] = scope_Events[namespacedEvent] || [];
1671                scope_Events[namespacedEvent].push(callback);
1672                // If the event bound is 'update,' fire it immediately for all handles.
1673                if (namespacedEvent.split(".")[0] === "update") {
1674                    scope_Handles.forEach(function (a, index) {
1675                        fireEvent("update", index);
1676                    });
1677                }
1678            }
1679            // Undo attachment of event
1680
1681            function removeEvent(namespacedEvent) {
1682                var event = namespacedEvent.split(".")[0],
1683                    namespace = namespacedEvent.substring(event.length);
1684                Object.keys(scope_Events).forEach(function (bind) {
1685                    var tEvent = bind.split(".")[0],
1686                        tNamespace = bind.substring(tEvent.length);
1687                    if ((!event || event === tEvent) && (!namespace || namespace === tNamespace)) {
1688                        delete scope_Events[bind];
1689                    }
1690                });
1691            }
1692            // Updateable: margin, limit, step, range, animate, snap
1693
1694            function updateOptions(optionsToUpdate) {
1695                var v = valueGet(),
1696                    i,
1697                    newOptions = testOptions({
1698                        start: [0, 0],
1699                        margin: optionsToUpdate.margin,
1700                        limit: optionsToUpdate.limit,
1701                        step: optionsToUpdate.step,
1702                        range: optionsToUpdate.range,
1703                        animate: optionsToUpdate.animate,
1704                        snap: optionsToUpdate.snap === undefined ? options.snap : optionsToUpdate.snap,
1705                    });
1706                ["margin", "limit", "step", "range", "animate"].forEach(function (name) {
1707                    if (optionsToUpdate[name] !== undefined) {
1708                        options[name] = optionsToUpdate[name];
1709                    }
1710                });
1711                // Save current spectrum direction as testOptions in testRange call
1712                // doesn't rely on current direction
1713                newOptions.spectrum.direction = scope_Spectrum.direction;
1714                scope_Spectrum = newOptions.spectrum;
1715                // Invalidate the current positioning so valueSet forces an update.
1716                scope_Locations = [-1, -1];
1717                valueSet(v);
1718                for (i = 0; i < scope_Handles.length; i++) {
1719                    fireEvent("update", i);
1720                }
1721            }
1722            // Throw an error if the slider was already initialized.
1723            if (scope_Target.noUiSlider) {
1724                throw new Error("Slider was already initialized.");
1725            }
1726            // Create the base element, initialise HTML and set classes.
1727            // Add handles and links.
1728            scope_Base = addSlider(options.dir, options.ort, scope_Target);
1729            scope_Handles = addHandles(options.handles, options.dir, scope_Base);
1730            // Set the connect classes.
1731            addConnection(options.connect, scope_Target, scope_Handles);
1732            if (options.pips) {
1733                pips(options.pips);
1734            }
1735            if (options.tooltips) {
1736                tooltips();
1737            }
1738            scope_Self = {
1739                destroy: destroy,
1740                steps: getCurrentStep,
1741                on: bindEvent,
1742                off: removeEvent,
1743                get: valueGet,
1744                set: valueSet,
1745                updateOptions: updateOptions,
1746                options: options, // Issue #600
1747                target: scope_Target, // Issue #597
1748                pips: pips, // Issue #594
1749            };
1750            // Attach user events.
1751            events(options.events);
1752            return scope_Self;
1753        }
1754        // Run the standard initializer
1755
1756        function initialize(target, originalOptions) {
1757            if (!target.nodeName) {
1758                throw new Error("noUiSlider.create requires a single element.");
1759            }
1760            // Test the options and create the slider environment;
1761            var options = testOptions(originalOptions, target),
1762                slider = closure(target, options);
1763            // Use the public value method to set the start values.
1764            slider.set(options.start);
1765            target.noUiSlider = slider;
1766            return slider;
1767        }
1768        // Use an object instead of a function for future expansibility;
1769        return {
1770            create: initialize,
1771        };
1772    });
1773    // wNumb number formatter: https://refreshless.com/wnumb/
1774    (function () {
1775        "use strict";
1776        var /** @const */
1777            FormatOptions = ["decimals", "thousand", "mark", "prefix", "postfix", "encoder", "decoder", "negativeBefore", "negative", "edit", "undo"];
1778        // General
1779        // Reverse a string
1780        function strReverse(a) {
1781            return a.split("").reverse().join("");
1782        }
1783        // Check if a string starts with a specified prefix.
1784
1785        function strStartsWith(input, match) {
1786            return input.substring(0, match.length) === match;
1787        }
1788        // Check is a string ends in a specified postfix.
1789
1790        function strEndsWith(input, match) {
1791            return input.slice(-1 * match.length) === match;
1792        }
1793        // Throw an error if formatting options are incompatible.
1794
vendor: 5,571 bytes, lines 1795-1927
1795        function throwEqualError(F, a, b) {
1796            if ((F[a] || F[b]) && F[a] === F[b]) {
1797                throw new Error(a);
1798            }
1799        }
1800        // Check if a number is finite and not NaN
1801
1802        function isValidNumber(input) {
1803            return typeof input === "number" && isFinite(input);
1804        }
1805        // Provide rounding-accurate toFixed method.
1806
1807        function toFixed(value, decimals) {
1808            var scale = Math.pow(10, decimals);
1809            return (Math.round(value * scale) / scale).toFixed(decimals);
1810        }
1811        // Formatting
1812        // Accept a number as input, output formatted string.
1813
1814        function formatTo(decimals, thousand, mark, prefix, postfix, encoder, decoder, negativeBefore, negative, edit, undo, input) {
1815            var originalInput = input,
1816                inputIsNegative,
1817                inputPieces,
1818                inputBase,
1819                inputDecimals = "",
1820                output = "";
1821            // Apply user encoder to the input.
1822            // Expected outcome: number.
1823            if (encoder) {
1824                input = encoder(input);
1825            }
1826            // Stop if no valid number was provided, the number is infinite or NaN.
1827            if (!isValidNumber(input)) {
1828                return false;
1829            }
1830            // Rounding away decimals might cause a value of -0
1831            // when using very small ranges. Remove those cases.
1832            if (decimals !== false && parseFloat(input.toFixed(decimals)) === 0) {
1833                input = 0;
1834            }
1835            // Formatting is done on absolute numbers,
1836            // decorated by an optional negative symbol.
1837            if (input < 0) {
1838                inputIsNegative = true;
1839                input = Math.abs(input);
1840            }
1841            // Reduce the number of decimals to the specified option.
1842            if (decimals !== false) {
1843                input = toFixed(input, decimals);
1844            }
1845            // Transform the number into a string, so it can be split.
1846            input = input.toString();
1847            // Break the number on the decimal separator.
1848            if (input.indexOf(".") !== -1) {
1849                inputPieces = input.split(".");
1850                inputBase = inputPieces[0];
1851                if (mark) {
1852                    inputDecimals = mark + inputPieces[1];
1853                }
1854            } else {
1855                // If it isn't split, the entire number will do.
1856                inputBase = input;
1857            }
1858            // Group numbers in sets of three.
1859            if (thousand) {
1860                inputBase = strReverse(inputBase).match(/.{1,3}/g);
1861                inputBase = strReverse(inputBase.join(strReverse(thousand)));
1862            }
1863            // If the number is negative, prefix with negation symbol.
1864            if (inputIsNegative && negativeBefore) {
1865                output += negativeBefore;
1866            }
1867            // Prefix the number
1868            if (prefix) {
1869                output += prefix;
1870            }
1871            // Normal negative option comes after the prefix. Defaults to '-'.
1872            if (inputIsNegative && negative) {
1873                output += negative;
1874            }
1875            // Append the actual number.
1876            output += inputBase;
1877            output += inputDecimals;
1878            // Apply the postfix.
1879            if (postfix) {
1880                output += postfix;
1881            }
1882            // Run the output through a user-specified post-formatter.
1883            if (edit) {
1884                output = edit(output, originalInput);
1885            }
1886            // All done.
1887            return output;
1888        }
1889        // Accept a sting as input, output decoded number.
1890
1891        function formatFrom(decimals, thousand, mark, prefix, postfix, encoder, decoder, negativeBefore, negative, edit, undo, input) {
1892            var originalInput = input,
1893                inputIsNegative,
1894                output = "";
1895            // User defined pre-decoder. Result must be a non empty string.
1896            if (undo) {
1897                input = undo(input);
1898            }
1899            // Test the input. Can't be empty.
1900            if (!input || typeof input !== "string") {
1901                return false;
1902            }
1903            // If the string starts with the negativeBefore value: remove it.
1904            // Remember is was there, the number is negative.
1905            if (negativeBefore && strStartsWith(input, negativeBefore)) {
1906                input = input.replace(negativeBefore, "");
1907                inputIsNegative = true;
1908            }
1909            // Repeat the same procedure for the prefix.
1910            if (prefix && strStartsWith(input, prefix)) {
1911                input = input.replace(prefix, "");
1912            }
1913            // And again for negative.
1914            if (negative && strStartsWith(input, negative)) {
1915                input = input.replace(negative, "");
1916                inputIsNegative = true;
1917            }
1918            // Remove the postfix.
1919            // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice
1920            if (postfix && strEndsWith(input, postfix)) {
1921                input = input.slice(0, -1 * postfix.length);
1922            }
1923            // Remove the thousand grouping.
1924            if (thousand) {
1925                input = input.split(thousand).join("");
1926            }
1927            // Set the decimal separator back to period.
1928            if (mark) {
1929                input = input.replace(mark, ".");
1930            }
1931            // Prepend the negative symbol.
1932            if (inputIsNegative) {
1933                output += "-";
1934            }
1935            // Add the number
1936            output += input;
1937            // Trim all non-numeric characters (allow '.' and '-');
1938            output = output.replace(/[^0-9\.\-.]/g, "");
1939            // The value contains no parse-able number.
1940            if (output === "") {
1941                return false;
1942            }
1943            // Covert to number.
1944            output = Number(output);
1945            // Run the user-specified post-decoder.
1946            if (decoder) {
1947                output = decoder(output);
1948            }
1949            // Check is the output is valid, otherwise: return false.
1950            if (!isValidNumber(output)) {
1951                return false;
1952            }
1953            return output;
1954        }
1955        // Framework
1956        // Validate formatting options
1957
1958        function validate(inputOptions) {
1959            var i,
1960                optionName,
1961                optionValue,
1962                filteredOptions = {};
1963            for (i = 0; i < FormatOptions.length; i += 1) {
1964                optionName = FormatOptions[i];
1965                optionValue = inputOptions[optionName];
1966                if (optionValue === undefined) {
1967                    // Only default if negativeBefore isn't set.
1968                    if (optionName === "negative" && !filteredOptions.negativeBefore) {
1969                        filteredOptions[optionName] = "-";
1970                        // Don't set a default for mark when 'thousand' is set.
1971                    } else if (optionName === "mark" && filteredOptions.thousand !== ".") {
1972                        filteredOptions[optionName] = ".";
1973                    } else {
1974                        filteredOptions[optionName] = false;
1975                    }
1976                    // Floating points in JS are stable up to 7 decimals.
1977                } else if (optionName === "decimals") {
1978                    if (optionValue >= 0 && optionValue < 8) {
1979                        filteredOptions[optionName] = optionValue;
1980                    } else {
1981                        throw new Error(optionName);
1982                    }
1983                    // These options, when provided, must be functions.
1984                } else if (optionName === "encoder" || optionName === "decoder" || optionName === "edit" || optionName === "undo") {
1985                    if (typeof optionValue === "function") {
1986                        filteredOptions[optionName] = optionValue;
1987                    } else {
1988                        throw new Error(optionName);
1989                    }
1990                    // Other options are strings.
1991                } else {
1992                    if (typeof optionValue === "string") {
1993                        filteredOptions[optionName] = optionValue;
1994                    } else {
1995                        throw new Error(optionName);
1996                    }
1997                }
1998            }
1999            // Some values can't be extracted from a
2000            // string if certain combinations are present.
2001            throwEqualError(filteredOptions, "mark", "thousand");
2002            throwEqualError(filteredOptions, "prefix", "negative");
2003            throwEqualError(filteredOptions, "prefix", "negativeBefore");
2004            return filteredOptions;
2005        }
2006        // Pass all options as function arguments
2007
2008        function passAll(options, method, input) {
2009            var i,
2010                args = [];
2011            // Add all options in order of FormatOptions
2012            for (i = 0; i < FormatOptions.length; i += 1) {
2013                args.push(options[FormatOptions[i]]);
2014            }
2015            // Append the input, then call the method, presenting all
2016            // options as arguments.
2017            args.push(input);
2018            return method.apply("", args);
2019        }
2020        /** @constructor */
2021
2022        function wNumb(options) {
2023            if (!(this instanceof wNumb)) {
2024                return new wNumb(options);
2025            }
2026            if (typeof options !== "object") {
2027                return;
2028            }
2029            options = validate(options);
2030            // Call 'formatTo' with proper arguments.
2031            this.to = function (input) {
2032                return passAll(options, formatTo, input);
2033            };
2034            // Call 'formatFrom' with proper arguments.
2035            this.from = function (input) {
2036                return passAll(options, formatFrom, input);
2037            };
2038        }
2039        /** @export */
2040        window.wNumb = wNumb;
2041    })();
2042});
2043
2044// Timer
2045document.addEventListener('DOMContentLoaded', (event) => {
2046  // Set the date we're counting down to
2047  var countDownDate = new Date("May 5, 2025 15:37:25").getTime();
2048
2049  // Update the count down every 1 second
2050  var x = setInterval(function() {
2051
2052      // Get today's date and time
2053      var now = new Date().getTime();
2054
2055      // Find the distance between now and the count down date
2056      var distance = countDownDate - now;
2057
2058      // Time calculations for days, hours, minutes and seconds
2059      var days = Math.floor(distance / (1000 * 60 * 60 * 24));
2060      var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
2061      var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
2062      var seconds = Math.floor((distance % (1000 * 60)) / 1000);
2063
2064      // Output the result in an element with id="countdown"
2065      document.getElementById("countdown").innerHTML = days + "d " + hours + "h " +
2066          minutes + "m " + seconds + "s ";
2067
2068      // If the count down is over, write some text
2069      if (distance < 0) {
2070          clearInterval(x);
2071          document.getElementById("countdown").innerHTML = "EXPIRED";
2072      }
2073  }, 1000);
2074});
2075
2076// Dark Mode
2077document.addEventListener('DOMContentLoaded', (event) => {
2078    const toggleBtn = document.getElementById('darkMode');
2079    const body = document.body;
2080
2081    // Check for saved theme preference in localStorage
2082    const savedTheme = localStorage.getItem('theme');
2083    if (savedTheme) {
2084        body.className=savedTheme;
2085    } else {
2086    // If no theme preference is saved, default to light mode
2087    body.className='crypt-dark';
2088    }
2089
2090    toggleBtn.addEventListener('click', () => {
2091    if (body.classList.contains('crypt-light')) {
2092        body.classList.replace('crypt-light', 'crypt-dark');
2093        localStorage.setItem('theme', 'crypt-dark'); // Save the theme to localStorage
2094    } else {
2095        body.classList.replace('crypt-dark', 'crypt-light');
2096        localStorage.setItem('theme', 'crypt-light'); // Save the theme to localStorage
2097    }
2098    });
2099});
2100
2101// Dark Mode button
2102document.addEventListener("DOMContentLoaded", (event) => {
2103    //check to see if this current container is within viewport
2104    document.querySelector(".mode").addEventListener("click", () => {
2105        document.querySelector(".sun-logo").classList.toggle("animate-sun");
2106        document.querySelector(".moon-logo").classList.toggle("animate-moon");
2107        document.querySelector("body").classList.toggle("theme");
2108    })
2109});
2110
2111/* Scroll-based animations */
2112document.addEventListener('DOMContentLoaded', (event) => {
2113  let $animation_elements = $('.animation-element');
2114  let $window = $(window);
2115
2116  function check_if_in_view() {
2117      let window_height = $window.height();
2118      let window_top_position = $window.scrollTop();
2119      let window_bottom_position = (window_top_position + window_height);
2120
2121      $.each($animation_elements, function() {
2122          let $element = $(this);
2123          let element_height = $element.outerHeight();
2124          let element_top_position = $element.offset().top;
2125          let element_bottom_position = (element_top_position + element_height);
2126
2127          //check to see if this current container is within viewport
2128          if ((element_bottom_position >= window_top_position) &&
2129              (element_top_position <= window_bottom_position)) {
2130              $element.addClass('in-view');
2131          } else {
2132              $element.removeClass('in-view');
2133          }
2134      });
2135  }
2136
2137  $window.on('scroll resize', check_if_in_view);
2138  $('#myModal').on('shown.bs.modal', function(e) {
2139      check_if_in_view();
2140  });
2141  $window.trigger('scroll');
2142});
2143
2144/* Tooltip Trigger */
2145document.addEventListener('DOMContentLoaded', (event) => {
2146  const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
2147  const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))
2148});
2149
2150/* Encrypt Value */
2151document.addEventListener('DOMContentLoaded', (event) => {
2152  let crypt_state = false;
2153  let _el = document.getElementById('encrypt');
2154  if (_el) {
2155      _el.addEventListener('click', function() {
2156          crypt_state = !crypt_state;
2157          let elements = document.querySelectorAll(".encrypted");
2158          elements.forEach((el) => el.innerText = crypt_state ? "***" : el.dataset.content);
2159      });
2160  }
2161
2162  window.addEventListener("DOMContentLoaded", function() {
2163      let elements = document.querySelectorAll(".encrypted");
2164      elements.forEach((el) => el.setAttribute("data-content", el.innerText));
2165  })
2166});
2167
2168/*--- Chart ---*/
2169document.addEventListener('DOMContentLoaded', (event) => {
2170  // colors
2171  var colors = ['#007bff', '#28a745', '#ffcd2d', '#7000f0', '#dc3545', '#c90097'];
2172
2173  var donutOptions = {
2174      cutoutPercentage: 60,
2175      legend: {
2176          position: 'right',
2177          padding: 0,
2178          labels: {
2179              pointStyle: 'circle',
2180              usePointStyle: true
2181          }
2182      }
2183  };
2184
2185  // Configuration
2186  var chDonutData = {
2187      labels: ['BTC', 'DOT', 'ETH', 'DOGE'],
2188      datasets: [{
2189          backgroundColor: colors.slice(0, 4),
2190          borderWidth: 0,
2191          data: [40, 11, 40, 20]
2192      }]
2193  };
2194
2195  var chDonut = document.getElementById("chDonut");
2196  if (chDonut) {
2197      new Chart(chDonut, {
2198          type: 'pie',
2199          data: chDonutData,
2200          options: donutOptions
2201      });
2202  }
2203});
2204
2205/*--- Dropdown on Hover ---*/
2206document.addEventListener('DOMContentLoaded', (event) => {
2207  $(document).ready(function() {
2208      $('.dropdown').hover(function() {
2209          $(this).addClass('show');
2210          $(this).find('.dropdown-menu-shows').addClass('show');
2211      }, function() {
2212          $(this).removeClass('show');
2213          $(this).find('.dropdown-menu-shows').removeClass('show');
2214      });
2215  });
2216
2217  $(document).ready(function() {
2218      $('.dropdown').hover(function() {
2219          $(this).find('.dropdown-menu-shows')
2220              .stop(true, true).delay(50).fadeIn(200);
2221      }, function() {
2222          $(this).find('.dropdown-menu-shows')
2223              .stop(true, true).delay(50).fadeOut(200);
2224      });
2225  });
2226});
2227
2228// Favorite Button
2229document.addEventListener('DOMContentLoaded', (event) => {
2230  $('.favme').click(function() {
2231      $(this).toggleClass('active');
2232  });
2233
2234  /* when a user clicks, toggle the 'is-animating' class */
2235  $(".favme").on('click touchstart', function() {
2236      $(this).toggleClass('is_animating');
2237  });
2238
2239  /*when the animation is over, remove the class*/
2240  $(".favme").on('animationend', function() {
2241      $(this).toggleClass('is_animating');
2242  });
2243});
2244
2245// Scrollspy
2246document.addEventListener('DOMContentLoaded', (event) => {
2247  document.querySelectorAll('#nav-tab>[data-bs-toggle="tab"]').forEach(el => {
2248      el.addEventListener('shown.bs.tab', () => {
2249          const target = el.getAttribute('data-bs-target')
2250          const scrollElem = document.querySelector(`${target} [data-bs-spy="scroll"]`)
2251          bootstrap.ScrollSpy.getOrCreateInstance(scrollElem).refresh()
2252      })
2253  })
2254});
2255
2256// ApexChart
2257document.addEventListener('DOMContentLoaded', (event) => {
2258  const chartOptions = {
2259      chart: {
2260          type: "area",
2261          height: 120,
2262          toolbar: {
2263              show: false
2264          },
2265          zoom: {
2266              enabled: false
2267          }
2268      },
2269      colors: ["#0d6efd"],
2270      series: [{
2271          name: "Total Assets",
2272          data: [0.00, 0.00, 4.55, 0.00, 0.00, 0.00]
2273      }],
2274      dataLabels: {
2275          enabled: false
2276      },
2277      stroke: {
2278          width: 3,
2279          curve: "smooth"
2280      },
2281      fill: {
2282          type: "gradient",
2283          gradient: {
2284              shadeIntensity: 0,
2285              opacityFrom: 0.4,
2286              opacityTo: 0,
2287              stops: [0, 90, 100]
2288          }
2289      },
2290      xaxis: {
2291          categories: ["Feb", "Apr", "Jun", "Aug", "Oct", "Dec"],
2292          axisBorder: {
2293              show: false
2294          },
2295          labels: {
2296              style: {
2297                  colors: "#adb5bd",
2298                  fontFamily: "inter"
2299              }
2300          }
2301      },
2302      yaxis: {
2303          show: false
2304      },
2305      grid: {
2306          borderColor: "rgba(0, 0, 0, 0, 0)",
2307          padding: {
2308              top: -30,
2309              bottom: -8,
2310              left: 12,
2311              right: 12
2312          }
2313      },
2314      tooltip: {
2315          enabled: true,
2316          y: {
2317              formatter: value => `${value} BTC`
2318          },
2319          style: {
2320              fontFamily: "inter"
2321          }
2322      },
2323      markers: {
2324          show: true
2325      }
2326  }
2327
2328  const chart = new ApexCharts(document.querySelector(".chart-area"), chartOptions)
2329  chart.render()
2330});
2331
2332//Piechart
2333document.addEventListener('DOMContentLoaded', (event) => {
2334    var chart;
2335var legend;
2336
2337var chartData = [{
2338    country: "Ecosystem",
2339    value: 260},
2340{
2341    country: "Airdrop",
2342    value: 201},
2343{
2344    country: "Private Sale",
2345    value: 65},
2346{
2347    country: "Contibutors",
2348    value: 39},
2349{
2350    country: "Advisory",
2351    value: 19},
2352{
2353    country: "Launchpool",
2354    value: 10}];
2355
2356AmCharts.ready(function() {
2357    // PIE CHART
2358    chart = new AmCharts.AmPieChart();
2359    chart.dataProvider = chartData;
2360    chart.titleField = "country";
2361    chart.valueField = "value";
2362    chart.outlineColor = "";
2363    chart.outlineAlpha = 0.8;
2364    chart.outlineThickness = 2;
2365    // this makes the chart 3D
2366    chart.depth3D = 20;
2367    chart.angle = 30;
2368    
2369    // WRITE
2370    chart.write("chartdiv");
2371});
2372});
2373
2374// Price Meter
2375document.addEventListener('DOMContentLoaded', (event) => {
2376  (function() {
2377      var leaseMeter, meterBar, meterBarWidth, meterValue, progressNumber;
2378
2379      /*Get value of value attribute*/
2380      var valueGetter = function() {
2381          leaseMeter = document.getElementsByClassName('leaseMeter');
2382          for (var i = 0; i < leaseMeter.length; i++) {
2383              meterValue = leaseMeter[i].getAttribute('value');
2384              return meterValue;
2385          }
2386      }
2387
2388      /*Convert value of value attribute to percentage*/
2389      var getPercent = function() {
2390          meterBarWidth = parseInt(valueGetter()) * 0.10;
2391          meterBarWidth.toString;
2392          meterBarWidth = meterBarWidth + "%";
2393          return meterBarWidth;
2394      }
2395
2396      /*Apply percentage to width of .meterBar*/
2397      var adjustWidth = function() {
2398          meterBar = document.getElementsByClassName('meterBar');
2399          for (var i = 0; i < meterBar.length; i++) {
2400              meterBar[i].style['width'] = getPercent();
2401          }
2402      }
2403
2404      /*Update value indicator*/
2405      var indicUpdate = function() {
2406          progressNumber = document.getElementsByClassName('progressNumber');
2407          for (var i = 0; i < progressNumber.length; i++) {
2408              progressNumber[i].innerHTML = valueGetter();
2409          }
2410      }
2411
2412      adjustWidth();
2413      indicUpdate();
2414  })();
2415});
2416
2417// Validation
2418document.addEventListener('DOMContentLoaded', (event) => {
2419  (() => {
2420      'use strict'
2421
2422      // Fetch all the forms we want to apply custom Bootstrap validation styles to
2423      const forms = document.querySelectorAll('.needs-validation')
2424
2425      // Loop over them and prevent submission
2426      Array.from(forms).forEach(form => {
2427          form.addEventListener('submit', event => {
2428              if (!form.checkValidity()) {
2429                  event.preventDefault()
2430                  event.stopPropagation()
2431              }
2432
2433              form.classList.add('was-validated')
2434          }, false)
2435      })
2436  })();
2437});
2438
2439// Password Strength
2440document.addEventListener('DOMContentLoaded', (event) => {
2441  $('#password').keyup(function(e) {
2442      var strongRegex = new RegExp("^(?=.{8,})(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*\\W).*$", "g");
2443      var mediumRegex = new RegExp("^(?=.{7,})(((?=.*[A-Z])(?=.*[a-z]))|((?=.*[A-Z])(?=.*[0-9]))|((?=.*[a-z])(?=.*[0-9]))).*$", "g");
2444      var enoughRegex = new RegExp("(?=.{6,}).*", "g");
2445      if (false == enoughRegex.test($(this).val())) {
2446          $('#passstrength').html('More characters');
2447          document.getElementById("passstrength").style.color = "#dc3545";
2448      } else if (strongRegex.test($(this).val())) {
2449        document.getElementById("passstrength").style.color = "#0d6efd";
2450          $('#passstrength').html('Strong!');
2451      } else if (mediumRegex.test($(this).val())) {
2452        document.getElementById("passstrength").style.color = "#0dcaf0";
2453          $('#passstrength').html('Medium!');
2454      } else {
2455          document.getElementById("passstrength").style.color = "#ffc107";
2456          $('#passstrength').html('Weak!');
2457      }
2458      return true;
2459  });
2460});
2461
2462
2463// Password Visibility
2464var state = false;
2465
2466function toggle() {
2467    if (state) {
2468        document.getElementById("password").setAttribute("type", "password");
2469        document.getElementById("eye").style.color = "#7a797e";
2470        state = false;
2471    } else {
2472        document.getElementById("password").setAttribute("type", "text");
2473        document.getElementById("eye").style.color = "#0d6efd";
2474        state = true;
2475    }
2476}
2477
2478
2479// Newsletter Signup Button
2480document.addEventListener('DOMContentLoaded', (event) => {
2481    (function () {
2482        $(document).mousemove(function (e) {
2483            var mX = e.pageX;
2484            var mY = e.pageY;
2485            var from = { x: mX, y: mY };
2486            var $n = $(".signup-btn");
2487            var off = $n.offset(),
2488                nx1 = off.left,
2489                ny1 = off.top,
2490                nx2 = nx1 + $n.outerWidth(),
2491                ny2 = ny1 + $n.outerHeight(),
2492                maxX1 = Math.max(mX, nx1),
2493                minX2 = Math.min(mX, nx2),
2494                maxY1 = Math.max(mY, ny1),
2495                minY2 = Math.min(mY, ny2),
2496                intersectX = minX2 >= maxX1,
2497                intersectY = minY2 >= maxY1,
2498                to = {
2499                    x: intersectX ? mX : nx2 < mX ? nx2 : nx1,
2500                    y: intersectY ? mY : ny2 < mY ? ny2 : ny1,
2501                };
2502            var distX = to.x - from.x,
2503                distY = to.y - from.y,
2504                hypot = Math.sqrt(distX * distX + distY * distY);
2505            final = Math.round(hypot);
2506    
2507            $("#distance_text").text(final); //this will output 0 when next to your element.
2508    
2509            if (final == 0) {
2510                // document.getElementById("news").style.color = "yellow"
2511                document.getElementById("news").classList.add("active");
2512            } else {
2513                // document.getElementById("news").style.color = "black"
2514                document.getElementById("news").classList.remove("active");
2515            }
2516        });
2517    })();
2518});
2519
2520// Popovers
2521document.addEventListener('DOMContentLoaded', (event) => {
2522    const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="popover"]')
2523    const popoverList = [...popoverTriggerList].map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl))
2524});
2525
2526//Sidebar Collapse
2527document.addEventListener("DOMContentLoaded", function() {
2528    let arrow_el = document.getElementById("sidebar-collapse");
2529    let body_el = document.querySelector("body");
2530    if(!arrow_el || !body_el) return null;
2531  
2532    arrow_el.addEventListener("click", function() {
2533      body_el.classList.toggle("sidebar-close");
2534    });
2535  });
2536
2537
2538//mobile sidebar toggle
2539  document.addEventListener("DOMContentLoaded", function() {
2540    let arrow_el = document.getElementById("sidebar-mobile-toggle");
2541    let body_el = document.querySelector("body");
2542    if(!arrow_el || !body_el) return null;
2543  
2544    arrow_el.addEventListener("click", function() {
2545      body_el.classList.toggle("sidebar-mobile-close");
2546    });
2547  });
2548  
2549
2550  
2551  

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.