PageSourceSearch

https://peterscott.com/js/script.js

js peterscott.com collected 2026-10-04 07:26:14 UTC 45,333 bytes, 1,386 lines download raw bytes

1"use strict";
2(function () {
3	// Global variables
4	var
5		userAgent = navigator.userAgent.toLowerCase(),
6		initialDate = new Date(),
7
8		$document = $(document),
9		$window = $(window),
10		$html = $("html"),
11		$body = $("body"),
12
13		isDesktop = $html.hasClass("desktop"),
14		isIE = userAgent.indexOf("msie") !== -1 ? parseInt(userAgent.split("msie")[1], 10) : userAgent.indexOf("trident") !== -1 ? 11 : userAgent.indexOf("edge") !== -1 ? 12 : false,
15		isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),
16		windowReady = false,
17		isNoviBuilder = false,
18		livedemo = false,
19
20		plugins = {
21			bootstrapTooltip:        $( '[data-toggle="tooltip"]' ),
22			bootstrapModal:          $( '.modal' ),
23			bootstrapTabs:           $( '.tabs-custom' ),
24			customToggle:            $( '[data-custom-toggle]' ),
25			captcha:                 $( '.recaptcha' ),
26			campaignMonitor:         $( '.campaign-mailform' ),
27			copyrightYear:           $( '.copyright-year' ),
28			checkbox:                $( 'input[type="checkbox"]' ),
29			isotope:                 $( '.isotope-wrap' ),
30			lightGallery:            $( '[data-lightgallery="group"]' ),
31			lightGalleryItem:        $( '[data-lightgallery="item"]' ),
32			lightDynamicGalleryItem: $( '[data-lightgallery="dynamic"]' ),
33			materialParallax:        $( '.parallax-container' ),
34			mailchimp:               $( '.mailchimp-mailform' ),
35			owl:                     $( '.owl-carousel' ),
36			popover:                 $( '[data-toggle="popover"]' ),
37			preloader:               $( '.preloader' ),
38			rdNavbar:                $( '.rd-navbar' ),
39			rdMailForm:              $( '.rd-mailform' ),
40			rdInputLabel:            $( '.form-label' ),
41			regula:                  $( '[data-constraints]' ),
42			radio:                   $( 'input[type="radio"]' ),
43			statefulButton:          $( '.btn-stateful' ),
44			viewAnimate:             $( '.view-animate' ),
45			wow:                     $( '.wow' ),
46			maps:                    $( '.google-map-container' ),
47			counter:                 document.querySelectorAll( '.counter' ),
48			progressLinear:          document.querySelectorAll( '.progress-linear' ),
49			progressCircle:          document.querySelectorAll( '.progress-circle' ),
50			countdown:               document.querySelectorAll( '.countdown' )
51		};
52
53	/**
54	 * @desc Check the element was been scrolled into the view
55	 * @param {object} elem - jQuery object
56	 * @return {boolean}
57	 */
58	function isScrolledIntoView ( elem ) {
59		if ( isNoviBuilder ) return true;
60		return elem.offset().top + elem.outerHeight() >= $window.scrollTop() && elem.offset().top <= $window.scrollTop() + $window.height();
61	}
62
63	/**
64	 * @desc Calls a function when element has been scrolled into the view
65	 * @param {object} element - jQuery object
66	 * @param {function} func - init function
67	 */
68	function lazyInit( element, func ) {
69		var scrollHandler = function () {
70			if ( ( !element.hasClass( 'lazy-loaded' ) && ( isScrolledIntoView( element ) ) ) ) {
71				func.call( element );
72				element.addClass( 'lazy-loaded' );
73			}
74		};
75
76		scrollHandler();
77		$window.on( 'scroll', scrollHandler );
78	}
79
80	// Initialize scripts that require a loaded window
81	$window.on('load', function () {
82		// Page loader & Page transition
83		if (plugins.preloader.length && !isNoviBuilder) {
84			pageTransition({
85				target: document.querySelector( '.page' ),
86				delay: 0,
87				duration: 500,
88				classIn: 'fadeIn',
89				classOut: 'fadeOut',
90				classActive: 'animated',
91				conditions: function (event, link) {
92					return link && !/(\#|javascript:void\(0\)|callto:|tel:|mailto:|:\/\/)/.test(link) && !event.currentTarget.hasAttribute('data-lightgallery');
93				},
94				onTransitionStart: function ( options ) {
95					setTimeout( function () {
96						plugins.preloader.removeClass('loaded');
97					}, options.duration * .75 );
98				},
99				onReady: function () {
100					plugins.preloader.addClass('loaded');
101					windowReady = true;
102				}
103			});
104		}
105
106		// Counter
107		if ( plugins.counter ) {
108			for ( var i = 0; i < plugins.counter.length; i++ ) {
109				var
110					node = plugins.counter[i],
111					counter = aCounter({
112						node: node,
113						duration: node.getAttribute( 'data-duration' ) || 1000
114					}),
115					scrollHandler = (function() {
116						if ( Util.inViewport( this ) && !this.classList.contains( 'animated-first' ) ) {
117							this.counter.run();
118							this.classList.add( 'animated-first' );
119						}
120					}
120).bind( node ),
121					blurHandler = (function() {
122						this.counter.params.to = parseInt( this.textContent, 10 );
123						this.counter.run();
124					}).bind( node );
125
126				if ( isNoviBuilder ) {
127					node.counter.run();
128					node.addEventListener( 'blur', blurHandler );
129				} else {
130					scrollHandler();
131					window.addEventListener( 'scroll', scrollHandler );
132				}
133			}
134		}
135
136		// Progress Bar
137		if ( plugins.progressLinear ) {
138			for ( var i = 0; i < plugins.progressLinear.length; i++ ) {
139				var
140					container = plugins.progressLinear[i],
141					counter = aCounter({
142						node: container.querySelector( '.progress-linear-counter' ),
143						duration: container.getAttribute( 'data-duration' ) || 1000,
144						onStart: function() {
145							this.custom.bar.style.width = this.params.to + '%';
146						}
147					});
148
149				counter.custom = {
150					container: container,
151					bar: container.querySelector( '.progress-linear-bar' ),
152					onScroll: (function() {
153						if ( ( Util.inViewport( this.custom.container ) && !this.custom.container.classList.contains( 'animated' ) ) || isNoviBuilder ) {
154							this.run();
155							this.custom.container.classList.add( 'animated' );
156						}
157					}).bind( counter ),
158					onBlur: (function() {
159						this.params.to = parseInt( this.params.node.textContent, 10 );
160						this.run();
161					}).bind( counter )
162				};
163
164				if ( isNoviBuilder ) {
165					counter.run();
166					counter.params.node.addEventListener( 'blur', counter.custom.onBlur );
167				} else {
168					counter.custom.onScroll();
169					document.addEventListener( 'scroll', counter.custom.onScroll );
170				}
171			}
172		}
173
174		// Progress Circle
175		if ( plugins.progressCircle ) {
176			for ( var i = 0; i < plugins.progressCircle.length; i++ ) {
177				var
178					container = plugins.progressCircle[i],
179					counter = aCounter({
180						node: container.querySelector( '.progress-circle-counter' ),
181						duration: 500,
182						onUpdate: function( value ) {
183							this.custom.bar.render( value * 3.6 );
184						}
185					});
186
187				counter.params.onComplete = counter.params.onUpdate;
188
189				counter.custom = {
190					container: container,
191					bar: aProgressCircle({ node: container.querySelector( '.progress-circle-bar' ) }),
192					onScroll: (function() {
193						if ( Util.inViewport( this.custom.container ) && !this.custom.container.classList.contains( 'animated' ) ) {
194							this.run();
195							this.custom.container.classList.add( 'animated' );
196						}
197					}).bind( counter ),
198					onBlur: (function() {
199						this.params.to = parseInt( this.params.node.textContent, 10 );
200						this.run();
201					}).bind( counter )
202				};
203
204				if ( isNoviBuilder ) {
205					counter.run();
206					counter.params.node.addEventListener( 'blur', counter.custom.onBlur );
207				} else {
208					counter.custom.onScroll();
209					window.addEventListener( 'scroll', counter.custom.onScroll );
210				}
211			}
212		}
213
214		// Isotope
215		if ( plugins.isotope.length ) {
216			for ( var i = 0; i < plugins.isotope.length; i++ ) {
217				var
218					wrap = plugins.isotope[ i ],
219					filterHandler = function ( event ) {
220						event.preventDefault();
221						for ( var n = 0; n < this.isoGroup.filters.length; n++ ) this.isoGroup.filters[ n ].classList.remove( 'active' );
222						this.classList.add( 'active' );
223						this.isoGroup.isotope.arrange( { filter: this.getAttribute( "data-isotope-filter" ) !== '*' ? '[data-filter*="' + this.getAttribute( "data-isotope-filter" ) + '"]' : '*' } );
224					},
225					resizeHandler = function () {
226						this.isoGroup.isotope.layout();
227					};
228
229				wrap.isoGroup = {};
230				wrap.isoGroup.filters = wrap.querySelectorAll( '[data-isotope-filter]' );
231				wrap.isoGroup.node = wrap.querySelector( '.isotope' );
232				wrap.isoGroup.layout = wrap.isoGroup.node.getAttribute( 'data-isotope-layout' ) ? wrap.isoGroup.node.getAttribute( 'data-isotope-layout' ) : 'masonry';
233				wrap.isoGroup.isotope = new Isotope( wrap.isoGroup.node, {
234					itemSelector: '.isotope-item',
235					layoutMode: wrap.isoGroup.layout,
236					filter: '*',
237					columnWidth: ( function() {
238						if ( wrap.isoGroup.node.hasAttribute('data-column-class') ) return wrap.isoGroup.node.getAttribute('data-column-class');
239						if ( wrap.isoGroup.node.hasAttribute('data-column-width') ) return parseFloat( wrap.isoGroup.node.getAttribute('data-column-width') );
240					}() )
241				} );
242
243				for ( var n = 0; n < wrap.isoGroup.filters.length; n++ ) {
244					var filter = wrap.isoGroup.filters[ n ];
245					filter.isoGroup = wrap.isoGroup;
246					filter.addEventListener( 'click', filterHandler );
247				}
248
249				window.addEventListener( 'resize', resizeHandler.bind( wrap ) );
250			}
251		}
252
253		// Material Parallax
254		if ( plugins.materialParallax.length ) {
255			if ( !isNoviBuilder && !isIE && !isMobile) {
256				plugins.materialParallax.parallax();
257			} else {
258				for ( var i = 0; i < plugins.materialParallax.length; i++ ) {
259					var $parallax = $(plugins.materialParallax[i]);
260
261					$parallax.addClass( 'parallax-disabled' );
262					$parallax.css({ "background-image": 'url('+ $parallax.data("parallax-img") +')' });
263				}
264			}
265		}
266	});
267
268	// Initialize scripts that require a finished document
269	$(function () {
270		isNoviBuilder = window.xMode;
271
272		/**
273		 * @desc Initialize owl carousel plugin
274		 * @param {object} carousel - carousel jQuery object
275		 */
276		function initOwlCarousel ( carousel ) {
277			var
278				aliaces = [ '-', '-sm-', '-md-', '-lg-', '-xl-', '-xxl-' ],
279				values = [ 0, 576, 768, 992, 1200, 1600 ],
280				responsive = {};
281
282			for ( var j = 0; j < values.length; j++ ) {
283				responsive[ values[ j ] ] = {};
284				for ( var k = j; k >= -1; k-- ) {
285					if ( !responsive[ values[ j ] ][ 'items' ] && carousel.attr( 'data' + aliaces[ k ] + 'items' ) ) {
286						responsive[ values[ j ] ][ 'items' ] = k < 0 ? 1 : parseInt( carousel.attr( 'data' + aliaces[ k ] + 'items' ), 10 );
287					}
288					if ( !responsive[ values[ j ] ][ 'stagePadding' ] && responsive[ values[ j ] ][ 'stagePadding' ] !== 0 && carousel.attr( 'data' + aliaces[ k ] + 'stage-padding' ) ) {
289						responsive[ values[ j ] ][ 'stagePadding' ] = k < 0 ? 0 : parseInt( carousel.attr( 'data' + aliaces[ k ] + 'stage-padding' ), 10 );
290					}
291					if ( !responsive[ values[ j ] ][ 'margin' ] && responsive[ values[ j ] ][ 'margin' ] !== 0 && carousel.attr( 'data' + aliaces[ k ] + 'margin' ) ) {
292						responsive[ values[ j ] ][ 'margin' ] = k < 0 ? 30 : parseInt( carousel.attr( 'data' + aliaces[ k ] + 'margin' ), 10 );
293					}
294				}
295			}
296
297			// Enable custom pagination
298			if ( carousel.attr( 'data-dots-custom' ) ) {
299				carousel.on( 'initialized.owl.carousel', function ( event ) {
300					var
301						carousel = $( event.currentTarget ),
302						customPag = $( carousel.attr( 'data-dots-custom' ) ),
303						active = 0;
304
305					if ( carousel.attr( 'data-active' ) ) {
306						active = parseInt( carousel.attr( 'data-active' ), 10 );
307					}
308
309					carousel.trigger( 'to.owl.carousel', [ active, 300, true ] );
310					customPag.find( '[data-owl-item="' + active + '"]' ).addClass( 'active' );
311
312					customPag.find( '[data-owl-item]' ).on( 'click', function ( event ) {
313						event.preventDefault();
314						carousel.trigger( 'to.owl.carousel', [ parseInt( this.getAttribute( 'data-owl-item' ), 10 ), 300, true ] );
315					} );
316
317					carousel.on( 'translate.owl.carousel', function ( event ) {
318						customPag.find( '.active' ).removeClass( 'active' );
319						customPag.find( '[data-owl-item="' + event.item.index + '"]' ).addClass( 'active' )
320					} );
321				} );
322			}
323
324			// Initialize lightgallery items in cloned owl items
325			carousel.on( 'initialized.owl.carousel', function () {
326				initLightGalleryItem( carousel.find( '[data-lightgallery="item"]' ), 'lightGallery-in-carousel' );
327			} );
328
329			carousel.owlCarousel( {
330				autoplay:           isNoviBuilder ? false : carousel.attr( 'data-autoplay' ) !== 'false',
331				autoplayTimeout:    carousel.attr( "data-autoplay" ) ? Number( carousel.attr( "data-autoplay" ) ) : 3000,
332				autoplayHoverPause: true,
333				loop:               isNoviBuilder ? false : carousel.attr( 'data-loop' ) !== 'false',
334				items:              1,
335				center:             carousel.attr( 'data-center' ) === 'true',
336				dotsContainer:      carousel.attr( 'data-pagination-class' ) || false,
337				navContainer:       carousel.attr( 'data-navigation-class' ) || false,
338				mouseDrag:          isNoviBuilder ? false : carousel.attr( 'data-mouse-drag' ) !== 'false',
339				nav:                carousel.attr( 'data-nav' ) === 'true',
340				dots:               carousel.attr( 'data-dots' ) === 'true',
341				dotsEach:           carousel.attr( 'data-dots-each' ) ? parseInt( carousel.attr( 'data-dots-each' ), 10 ) : false,
342				animateIn:          carousel.attr( 'data-animation-in' ) ? carousel.attr( 'data-animation-in' ) : false,
343				animateOut:         carousel.attr( 'data-animation-out' ) ? carousel.attr( 'data-animation-out' ) : false,
344				responsive:         responsive,
345				navText:            carousel.attr( 'data-nav-text' ) ? $.parseJSON( carousel.attr( 'data-nav-text' ) ) : [],
346				navClass:           carousel.attr( 'data-nav-class' ) ? $.parseJSON( carousel.attr( 'data-nav-class' ) ) : [ 'owl-prev', 'owl-next' ]
347			} );
348		}
349
350
351		/**
352		 * @desc Attach form validation to elements
353		 * @param {object} elements - jQuery object
354		 */
355		function attachFormValidator(elements) {
356			// Custom validator - phone number
357			regula.custom({
358				name: 'PhoneNumber',
359				defaultMessage: 'Invalid phone number format',
360				validator: function() {
361					if ( this.value === '' ) return true;
362					else return /^(\+\d)?[0-9\-\(\) ]{5,}$/i.test( this.value );
363				}
364			});
365
366			for (var i = 0; i < elements.length; i++) {
367				var o = $(elements[i]), v;
368				o.addClass("form-control-has-validation").after("<span class='form-validation'></span>");
369				v = o.parent().find(".form-validation");
370				if (v.is(":last-child")) o.addClass("form-control-last-child");
371			}
372
373			elements.on('input change propertychange blur', function (e) {
374				var $this = $(this), results;
375
376				if (e.type !== "blur") if (!$this.parent().hasClass("has-error")) return;
377				if ($this.parents('.rd-mailform').hasClass('success')) return;
378
379				if (( results = $this.regula('validate') ).length) {
380					for (i = 0; i < results.length; i++) {
381						$this.siblings(".form-validation").text(results[i].message).parent().addClass("has-error");
382					}
383				} else {
384					$this.siblings(".form-validation").text("").parent().removeClass("has-error")
385				}
386			}).regula('bind');
387
388			var regularConstraintsMessages = [
389				{
390					type: regula.Constraint.Required,
391					newMessage: "The text field is required."
392				},
393				{
394					type: regula.Constraint.Email,
395					newMessage: "The email is not a valid email."
396				},
397				{
398					type: regula.Constraint.Numeric,
399					newMessage: "Only numbers are required"
400				},
401				{
402					type: regula.Constraint.Selected,
403					newMessage: "Please choose an option."
404				}
405			];
406
407
408			for (var i = 0; i < regularConstraintsMessages.length; i++) {
409				var regularConstraint = regularConstraintsMessages[i];
410
411				regula.override({
412					constraintType: regularConstraint.type,
413					defaultMessage: regularConstraint.newMessage
414				});
415			}
416		}
417
418		/**
419		 * @desc Check if all elements pass validation
420		 * @param {object} elements - object of items for validation
421		 * @param {object} captcha - captcha object for validation
422		 * @return {boolean}
423		 */
424		function isValidated(elements, captcha) {
425			var results, errors = 0;
426
427			if (elements.length) {
428				for (var j = 0; j < elements.length; j++) {
429
430					var $input = $(elements[j]);
431					if ((results = $input.regula('validate')).length) {
432						for (k = 0; k < results.length; k++) {
433							errors++;
434							$input.siblings(".form-validation").text(results[k].message).parent().addClass("has-error");
435						}
436					} else {
437						$input.siblings(".form-validation").text("").parent().removeClass("has-error")
438					}
439				}
440
441				if (captcha) {
442					if (captcha.length) {
443						return validateReCaptcha(captcha) && errors === 0
444					}
445				}
446
447				return errors === 0;
448			}
449			return true;
450		}
451
452		/**
453		 * @desc Validate google reCaptcha
454		 * @param {object} captcha - captcha object for validation
455		 * @return {boolean}
456		 */
457		function validateReCaptcha(captcha) {
458			var captchaToken = captcha.find('.g-recaptcha-response').val();
459
460			if (captchaToken.length === 0) {
461				captcha
462					.siblings('.form-validation')
463					.html('Please, prove that you are not robot.')
464					.addClass('active');
465				captcha
466					.closest('.form-wrap')
467					.addClass('has-error');
468
469				captcha.on('propertychange', function () {
470					var $this = $(this),
471						captchaToken = $this.find('.g-recaptcha-response').val();
472
473					if (captchaToken.length > 0) {
474						$this
475							.closest('.form-wrap')
476							.removeClass('has-error');
477						$this
478							.siblings('.form-validation')
479							.removeClass('active')
480							.html('');
481						$this.off('propertychange');
482					}
483				});
484
485				return false;
486			}
487
488			return true;
489		}
490
491		/**
492		 * @desc Initialize Google reCaptcha
493		 */
494		window.onloadCaptchaCallback = function () {
495			for (var i = 0; i < plugins.captcha.length; i++) {
496				var
497					$captcha = $(plugins.captcha[i]),
498					resizeHandler = (function() {
499						var
500							frame = this.querySelector( 'iframe' ),
501							inner = this.firstElementChild,
502							inner2 = inner.firstElementChild,
503							containerRect = null,
504							frameRect = null,
505							scale = null;
506
507						inner2.style.transform = '';
508						inner.style.height = 'auto';
509						inner.style.width = 'auto';
510
511						containerRect = this.getBoundingClientRect();
512						frameRect = frame.getBoundingClientRect();
513						scale = containerRect.width/frameRect.width;
514
515						if ( scale < 1 ) {
516							inner2.style.transform = 'scale('+ scale +')';
517							inner.style.height = ( frameRect.height * scale ) + 'px';
518							inner.style.width = ( frameRect.width * scale ) + 'px';
519						}
520					}).bind( plugins.captcha[i] );
521
522				grecaptcha.render(
523					$captcha.attr('id'),
524					{
525						sitekey: $captcha.attr('data-sitekey'),
526						size: $captcha.attr('data-size') ? $captcha.attr('data-size') : 'normal',
527						theme: $captcha.attr('data-theme') ? $captcha.attr('data-theme') : 'light',
528						callback: function () {
529							$('.recaptcha').trigger('propertychange');
530						}
531					}
532				);
533
534				$captcha.after("<span class='form-validation'></span>");
535
536				if ( plugins.captcha[i].hasAttribute( 'data-auto-size' ) ) {
537					resizeHandler();
538					window.addEventListener( 'resize', resizeHandler );
539				}
540			}
541		};
542
543		/**
544		 * @desc Initialize Bootstrap tooltip with required placement
545		 * @param {string} tooltipPlacement
546		 */
547		function initBootstrapTooltip(tooltipPlacement) {
548			plugins.bootstrapTooltip.tooltip('dispose');
549
550			if (window.innerWidth < 576) {
551				plugins.bootstrapTooltip.tooltip({placement: 'bottom'});
552			} else {
553				plugins.bootstrapTooltip.tooltip({placement: tooltipPlacement});
554			}
555		}
556
557		/**
558		 * @desc Initialize the gallery with set of images
559		 * @param {object} itemsToInit - jQuery object
560		 * @param {string} [addClass] - additional gallery class
561		 */
562		function initLightGallery ( itemsToInit, addClass ) {
563			if ( !isNoviBuilder ) {
564				$( itemsToInit ).lightGallery( {
565					thumbnail: $( itemsToInit ).attr( "data-lg-thumbnail" ) !== "false",
566					selector: "[data-lightgallery='item']",
567					autoplay: $( itemsToInit ).attr( "data-lg-autoplay" ) === "true",
568					pause: parseInt( $( itemsToInit ).attr( "data-lg-autoplay-delay" ) ) || 5000,
569					addClass: addClass,
570					mode: $( itemsToInit ).attr( "data-lg-animation" ) || "lg-slide",
571					loop: $( itemsToInit ).attr( "data-lg-loop" ) !== "false"
572				} );
573			}
574		}
575
576		/**
577		 * @desc Initialize the gallery with dynamic addition of images
578		 * @param {object} itemsToInit - jQuery object
579		 * @param {string} [addClass] - additional gallery class
580		 */
581		function initDynamicLightGallery ( itemsToInit, addClass ) {
582			if ( !isNoviBuilder ) {
583				$( itemsToInit ).on( "click", function () {
584					$( itemsToInit ).lightGallery( {
585						thumbnail: $( itemsToInit ).attr( "data-lg-thumbnail" ) !== "false",
586						selector: "[data-lightgallery='item']",
587						autoplay: $( itemsToInit ).attr( "data-lg-autoplay" ) === "true",
588						pause: parseInt( $( itemsToInit ).attr( "data-lg-autoplay-delay" ) ) || 5000,
589						addClass: addClass,
590						mode: $( itemsToInit ).attr( "data-lg-animation" ) || "lg-slide",
591						loop: $( itemsToInit ).attr( "data-lg-loop" ) !== "false",
592						dynamic: true,
593						dynamicEl: JSON.parse( $( itemsToInit ).attr( "data-lg-dynamic-elements" ) ) || []
594					} );
595				} );
596			}
597		}
598
599		/**
600		 * @desc Initialize the gallery with one image
601		 * @param {object} itemToInit - jQuery object
602		 * @param {string} [addClass] - additional gallery class
603		 */
604		function initLightGalleryItem ( itemToInit, addClass ) {
605			if ( !isNoviBuilder ) {
606				$( itemToInit ).lightGallery( {
607					selector: "this",
608					addClass: addClass,
609					counter: false,
610					youtubePlayerParams: {
611						modestbranding: 1,
612						showinfo: 0,
613						rel: 0,
614						controls: 0
615					},
616					vimeoPlayerParams: {
617						byline: 0,
618						portrait: 0
619					}
620				} );
621			}
622		}
623
624		/**
625		 * @desc Google map function for getting latitude and longitude
626		 */
627		function getLatLngObject(str, marker, map, callback) {
628			var coordinates = {};
629			try {
630				coordinates = JSON.parse(str);
631				callback(new google.maps.LatLng(
632					coordinates.lat,
633					coordinates.lng
634				), marker, map)
635			} catch (e) {
636				map.geocoder.geocode({'address': str}, function (results, status) {
637					if (status === google.maps.GeocoderStatus.OK) {
638						var latitude = results[0].geometry.location.lat();
639						var longitude = results[0].geometry.location.lng();
640
641						callback(new google.maps.LatLng(
642							parseFloat(latitude),
643							parseFloat(longitude)
644						), marker, map)
645					}
646				})
647			}
648		}
649
650		/**
651		 * @desc Initialize Google maps
652		 */
653		function initMaps() {
654			var key;
655
656			for ( var i = 0; i < plugins.maps.length; i++ ) {
657				if ( plugins.maps[i].hasAttribute( "data-key" ) ) {
658					key = plugins.maps[i].getAttribute( "data-key" );
659					break;
660				}
661			}
662
663			$.getScript('//maps.google.com/maps/api/js?'+ ( key ? 'key='+ key + '&' : '' ) +'sensor=false&libraries=geometry,places&v=quarterly', function () {
664				var head = document.getElementsByTagName('head')[0],
665					insertBefore = head.insertBefore;
666
667				head.insertBefore = function (newElement, referenceElement) {
668					if (newElement.href && newElement.href.indexOf('//fonts.googleapis.com/css?family=Roboto') !== -1 || newElement.innerHTML.indexOf('gm-style') !== -1) {
669						return;
670					}
671					insertBefore.call(head, newElement, referenceElement);
672				};
673				var geocoder = new google.maps.Geocoder;
674				for (var i = 0; i < plugins.maps.length; i++) {
675					var zoom = parseInt(plugins.maps[i].getAttribute("data-zoom"), 10) || 11;
676					var styles = plugins.maps[i].hasAttribute('data-styles') ? JSON.parse(plugins.maps[i].getAttribute("data-styles")) : [];
677					var center = plugins.maps[i].getAttribute("data-center") || "New York";
678
679					// Initialize map
680					var map = new google.maps.Map(plugins.maps[i].querySelectorAll(".google-map")[0], {
681						zoom: zoom,
682						styles: styles,
683						scrollwheel: false,
684						center: {lat: 0, lng: 0}
685					});
686
687					// Add map object to map node
688					plugins.maps[i].map = map;
689					plugins.maps[i].geocoder = geocoder;
690					plugins.maps[i].keySupported = true;
691					plugins.maps[i].google = google;
692
693					// Get Center coordinates from attribute
694					getLatLngObject(center, null, plugins.maps[i], function (location, markerElement, mapElement) {
695						mapElement.map.setCenter(location);
696					});
697
698					// Add markers from google-map-markers array
699					var markerItems = plugins.maps[i].querySelectorAll(".google-map-markers li");
700
701					if (markerItems.length){
702						var markers = [];
703						for (var j = 0; j < markerItems.length; j++){
704							var markerElement = markerItems[j];
705							getLatLngObject(markerElement.getAttribute("data-location"), markerElement, plugins.maps[i], function(location, markerElement, mapElement){
706								var icon = markerElement.getAttribute("data-icon") || mapElement.getAttribute("data-icon");
707								var activeIcon = markerElement.getAttribute("data-icon-active") || mapElement.getAttribute("data-icon-active");
708								var info = markerElement.getAttribute("data-description") || "";
709								var infoWindow = new google.maps.InfoWindow({
710									content: info
711								});
712								markerElement.infoWindow = infoWindow;
713								var markerData = {
714									position: location,
715									map: mapElement.map
716								}
717								if (icon){
718									markerData.icon = icon;
719								}
720								var marker = new google.maps.Marker(markerData);
721								markerElement.gmarker = marker;
722								markers.push({markerElement: markerElement, infoWindow: infoWindow});
723								marker.isActive = false;
724								// Handle infoWindow close click
725								google.maps.event.addListener(infoWindow,'closeclick',(function(markerElement, mapElement){
726									var markerIcon = null;
727									markerElement.gmarker.isActive = false;
728									markerIcon = markerElement.getAttribute("data-icon") || mapElement.getAttribute("data-icon");
729									markerElement.gmarker.setIcon(markerIcon);
730								}).bind(this, markerElement, mapElement));
731
732
733								// Set marker active on Click and open infoWindow
734								google.maps.event.addListener(marker, 'click', (function(markerElement, mapElement) {
735									if (markerElement.infoWindow.getContent().length === 0) return;
736									var gMarker, currentMarker = markerElement.gmarker, currentInfoWindow;
737									for (var k =0; k < markers.length; k++){
738										var markerIcon;
739										if (markers[k].markerElement === markerElement){
740											currentInfoWindow = markers[k].infoWindow;
741										}
742										gMarker = markers[k].markerElement.gmarker;
743										if (gMarker.isActive && markers[k].markerElement !== markerElement){
744											gMarker.isActive = false;
745											markerIcon = markers[k].markerElement.getAttribute("data-icon") || mapElement.getAttribute("data-icon")
746											gMarker.setIcon(markerIcon);
747											markers[k].infoWindow.close();
748										}
749									}
750
751									currentMarker.isActive = !currentMarker.isActive;
752									if (currentMarker.isActive) {
753										if (markerIcon = markerElement.getAttribute("data-icon-active") || mapElement.getAttribute("data-icon-active")){
754											currentMarker.setIcon(markerIcon);
755										}
756
757										currentInfoWindow.open(map, marker);
758									}else{
759										if (markerIcon = markerElement.getAttribute("data-icon") || mapElement.getAttribute("data-icon")){
760											currentMarker.setIcon(markerIcon);
761										}
762										currentInfoWindow.close();
763									}
764								}).bind(this, markerElement, mapElement))
765							})
766						}
767					}
768				}
769			});
770		}
771
772		// Google ReCaptcha
773		if (plugins.captcha.length) {
774			$.getScript("//www.google.com/recaptcha/api.js?onload=onloadCaptchaCallback&render=explicit&hl=en");
775		}
776
777		// Additional class on html if mac os.
778		if (navigator.platform.match(/(Mac)/i)) {
779			$html.addClass("mac-os");
780		}
781
782		// Adds some loosing functionality to IE browsers (IE Polyfills)
783		if (isIE) {
784			if (isIE === 12) $html.addClass("ie-edge");
785			if (isIE === 11) $html.addClass("ie-11");
786			if (isIE < 10) $html.addClass("lt-ie-10");
787			if (isIE < 11) $html.addClass("ie-10");
788		}
789
790		// Bootstrap Tooltips
791		if (plugins.bootstrapTooltip.length) {
792			var tooltipPlacement = plugins.bootstrapTooltip.attr('data-placement');
793			initBootstrapTooltip(tooltipPlacement);
794
795			$window.on('resize orientationchange', function () {
796				initBootstrapTooltip(tooltipPlacement);
797			})
798		}
799
800		// Bootstrap Modal
801		if (plugins.bootstrapModal.length) {
802			for (var i = 0; i < plugins.bootstrapModal.length; i++) {
803				var modalItem = $(plugins.bootstrapModal[i]);
804
805				modalItem.on('hidden.bs.modal', $.proxy(function () {
806					var activeModal = $(this),
807						rdVideoInside = activeModal.find('video'),
808						youTubeVideoInside = activeModal.find('iframe');
809
810					if (rdVideoInside.length) {
811						rdVideoInside[0].pause();
812					}
813
814					if (youTubeVideoInside.length) {
815						var videoUrl = youTubeVideoInside.attr('src');
816
817						youTubeVideoInside
818							.attr('src', '')
819							.attr('src', videoUrl);
820					}
821				}, modalItem))
822			}
823		}
824
825		// Popovers
826		if (plugins.popover.length) {
827			if (window.innerWidth < 767) {
828				plugins.popover.attr('data-placement', 'bottom');
829				plugins.popover.popover();
830			}
831			else {
832				plugins.popover.popover();
833			}
834		}
835
836		// Bootstrap Buttons
837		if (plugins.statefulButton.length) {
838			$(plugins.statefulButton).on('click', function () {
839				var statefulButtonLoading = $(this).button('loading');
840
841				setTimeout(function () {
842					statefulButtonLoading.button('reset')
843				}, 2000);
844			})
845		}
846
847		// Bootstrap tabs
848		if (plugins.bootstrapTabs.length) {
849			for (var i = 0; i < plugins.bootstrapTabs.length; i++) {
850				var bootstrapTab = $(plugins.bootstrapTabs[i]);
851
852				//If have slick carousel inside tab - resize slick carousel on click
853				if (bootstrapTab.find('.slick-slider').length) {
854					bootstrapTab.find('.tabs-custom-list > li > a').on('click', $.proxy(function () {
855						var $this = $(this);
856						var setTimeOutTime = isNoviBuilder ? 1500 : 300;
857
858						setTimeout(function () {
859							$this.find('.tab-content .tab-pane.active .slick-slider').slick('setPosition');
860						}, setTimeOutTime);
861					}, bootstrapTab));
862				}
863
864				var tabs = plugins.bootstrapTabs[i].querySelectorAll( '.nav li a' );
865
866				for ( var t = 0; t < tabs.length; t++ ) {
867					var tab = tabs[ t ];
868
869					if ( t === 0 ) {
870						tab.parentElement.classList.remove( 'active' );
871						$( tab ).tab( 'show' );
872					}
873
874					tab.addEventListener( 'click', function( event ) {
875						event.preventDefault();
876						$( this ).tab( 'show' );
877					});
878				}
879			}
880		}
881
882		// Copyright Year (Evaluates correct copyright year)
883		if (plugins.copyrightYear.length) {
884			plugins.copyrightYear.text(initialDate.getFullYear());
885		}
886
887		// Google maps
888		if( plugins.maps.length ) {
889			lazyInit( plugins.maps, initMaps );
890		}
891
892		// Add custom styling options for input[type="radio"]
893		if (plugins.radio.length) {
894			for (var i = 0; i < plugins.radio.length; i++) {
895				$(plugins.radio[i]).addClass("radio-custom").after("<span class='radio-custom-dummy'></span>")
896			}
897		}
898
899		// Add custom styling options for input[type="checkbox"]
900		if (plugins.checkbox.length) {
901			for (var i = 0; i < plugins.checkbox.length; i++) {
902				$(plugins.checkbox[i]).addClass("checkbox-custom").after("<span class='checkbox-custom-dummy'></span>")
903			}
904		}
905
906		// UI To Top
907		if (isDesktop && !isNoviBuilder) {
908			$().UItoTop({
909				easingType: 'easeOutQuad',
910				containerClass: 'ui-to-top fa fa-angle-up'
911			});
912		}
913
914		// RD Navbar
915		if ( plugins.rdNavbar.length ) {
916			var
917				navbar = plugins.rdNavbar,
918				aliases = { '-': 0, '-sm-': 576, '-md-': 768, '-lg-': 992, '-xl-': 1200, '-xxl-': 1600 },
919				responsive = {};
920
921			for ( var alias in aliases ) {
922				var link = responsive[ aliases[ alias ] ] = {};
923				if ( navbar.attr( 'data'+ alias +'layout' ) )          link.layout        = navbar.attr( 'data'+ alias +'layout' );
924				if ( navbar.attr( 'data'+ alias +'device-layout' ) )   link.deviceLayout  = navbar.attr( 'data'+ alias +'device-layout' );
925				if ( navbar.attr( 'data'+ alias +'hover-on' ) )        link.focusOnHover  = navbar.attr( 'data'+ alias +'hover-on' ) === 'true';
926				if ( navbar.attr( 'data'+ alias +'auto-height' ) )     link.autoHeight    = navbar.attr( 'data'+ alias +'auto-height' ) === 'true';
927				if ( navbar.attr( 'data'+ alias +'stick-up-offset' ) ) link.stickUpOffset = navbar.attr( 'data'+ alias +'stick-up-offset' );
928				if ( navbar.attr( 'data'+ alias +'stick-up' ) )        link.stickUp       = navbar.attr( 'data'+ alias +'stick-up' ) === 'true';
929				if ( isNoviBuilder ) link.stickUp = false;
930				else if ( navbar.attr( 'data'+ alias +'stick-up' ) )   link.stickUp       = navbar.attr( 'data'+ alias +'stick-up' ) === 'true';
931			}
932
933			plugins.rdNavbar.RDNavbar({
934				anchorNav: !isNoviBuilder,
935				stickUpClone: (plugins.rdNavbar.attr("data-stick-up-clone") && !isNoviBuilder) ? plugins.rdNavbar.attr("data-stick-up-clone") === 'true' : false,
936				responsive: responsive,
937				callbacks: {
938					onStuck: function () {
939						var navbarSearch = this.$element.find('.rd-search input');
940
941						if (navbarSearch) {
942							navbarSearch.val('').trigger('propertychange');
943						}
944					},
945					onDropdownOver: function () {
946						return !isNoviBuilder;
947					},
948					onUnstuck: function () {
949						if (this.$clone === null)
950							return;
951
952						var navbarSearch = this.$clone.find('.rd-search input');
953
954						if (navbarSearch) {
955							navbarSearch.val('').trigger('propertychange');
956							navbarSearch.trigger('blur');
957						}
958
959					}
960				}
961			});
962		}
963
964		$('a[href="#"]').on('click', function () {
965			if ( $(this).data('target') ) {
966			} else {
967				$('.rd-nav-item').removeClass('active').first().addClass('active');
968			}
969		})
970
971
972		// Add class in viewport
973		if (plugins.viewAnimate.length) {
974			for (var i = 0; i < plugins.viewAnimate.length; i++) {
975				var $view = $(plugins.viewAnimate[i]).not('.active');
976				$document.on("scroll", $.proxy(function () {
977					if (isScrolledIntoView(this)) {
978						this.addClass("active");
979					}
980				}, $view))
981					.trigger("scroll");
982			}
983		}
984
985
986		// Owl carousel
987		if ( plugins.owl.length ) {
988			for ( var i = 0; i < plugins.owl.length; i++ ) {
989				var carousel = $( plugins.owl[ i ] );
990				plugins.owl[ i ].owl = carousel;
991				initOwlCarousel( carousel );
992			}
993		}
994
995		// WOW
996		if ($html.hasClass("wow-animation") && plugins.wow.length && !isNoviBuilder && isDesktop) {
997			new WOW().init();
998		}
999
1000		// RD Input Label
1001		if (plugins.rdInputLabel.length) {
1002			plugins.rdInputLabel.RDInputLabel();
1003		}
1004
1005		// Regula
1006		if (plugins.regula.length) {
1007			attachFormValidator(plugins.regula);
1008		}
1009
1010		// MailChimp Ajax subscription
1011		if (plugins.mailchimp.length) {
1012			for (i = 0; i < plugins.mailchimp.length; i++) {
1013				var $mailchimpItem = $(plugins.mailchimp[i]),
1014					$email = $mailchimpItem.find('input[type="email"]');
1015
1016				// Required by MailChimp
1017				$mailchimpItem.attr('novalidate', 'true');
1018				$email.attr('name', 'EMAIL');
1019
1020				$mailchimpItem.on('submit', $.proxy( function ( $email, event ) {
1021					event.preventDefault();
1022
1023					var $this = this;
1024
1025					var data = {},
1026						url = $this.attr('action').replace('/post?', '/post-json?').concat('&c=?'),
1027						dataArray = $this.serializeArray(),
1028						$output = $("#" + $this.attr("data-form-output"));
1029
1030					for (i = 0; i < dataArray.length; i++) {
1031						data[dataArray[i].name] = dataArray[i].value;
1032					}
1033
1034					$.ajax({
1035						data: data,
1036						url: url,
1037						dataType: 'jsonp',
1038						error: function (resp, text) {
1039							$output.html('Server error: ' + text);
1040
1041							setTimeout(function () {
1042								$output.removeClass("active");
1043							}, 4000);
1044						},
1045						success: function (resp) {
1046							$output.html(resp.msg).addClass('active');
1047							$email[0].value = '';
1048							var $label = $('[for="'+ $email.attr( 'id' ) +'"]');
1049							if ( $label.length ) $label.removeClass( 'focus not-empty' );
1050
1051							setTimeout(function () {
1052								$output.removeClass("active");
1053							}, 6000);
1054						},
1055						beforeSend: function (data) {
1056							var isNoviBuilder = window.xMode;
1057
1058							var isValidated = (function () {
1059								var results, errors = 0;
1060								var elements = $this.find('[data-constraints]');
1061								var captcha = null;
1062								if (elements.length) {
1063									for (var j = 0; j < elements.length; j++) {
1064
1065										var $input = $(elements[j]);
1066										if ((results = $input.regula('validate')).length) {
1067											for (var k = 0; k < results.length; k++) {
1068												errors++;
1069												$input.siblings(".form-validation").text(results[k].message).parent().addClass("has-error");
1070											}
1071										} else {
1072											$input.siblings(".form-validation").text("").parent().removeClass("has-error")
1073										}
1074									}
1075
1076									if (captcha) {
1077										if (captcha.length) {
1078											return validateReCaptcha(captcha) && errors === 0
1079										}
1080									}
1081
1082									return errors === 0;
1083								}
1084								return true;
1085							})();
1086
1087							// Stop request if builder or inputs are invalide
1088							if (isNoviBuilder || !isValidated)
1089								return false;
1090
1091							$output.html('Submitting...').addClass('active');
1092						}
1093					});
1094
1095					return false;
1096				}, $mailchimpItem, $email ));
1097			}
1098		}
1099
1100		// Campaign Monitor ajax subscription
1101		if (plugins.campaignMonitor.length) {
1102			for (i = 0; i < plugins.campaignMonitor.length; i++) {
1103				var $campaignItem = $(plugins.campaignMonitor[i]);
1104
1105				$campaignItem.on('submit', $.proxy(function (e) {
1106					var data = {},
1107						url = this.attr('action'),
1108						dataArray = this.serializeArray(),
1109						$output = $("#" + plugins.campaignMonitor.attr("data-form-output")),
1110						$this = $(this);
1111
1112					for (i = 0; i < dataArray.length; i++) {
1113						data[dataArray[i].name] = dataArray[i].value;
1114					}
1115
1116					$.ajax({
1117						data: data,
1118						url: url,
1119						dataType: 'jsonp',
1120						error: function (resp, text) {
1121							$output.html('Server error: ' + text);
1122
1123							setTimeout(function () {
1124								$output.removeClass("active");
1125							}, 4000);
1126						},
1127						success: function (resp) {
1128							$output.html(resp.Message).addClass('active');
1129
1130							setTimeout(function () {
1131								$output.removeClass("active");
1132							}, 6000);
1133						},
1134						beforeSend: function (data) {
1135							// Stop request if builder or inputs are invalide
1136							if (isNoviBuilder || !isValidated($this.find('[data-constraints]')))
1137								return false;
1138
1139							$output.html('Submitting...').addClass('active');
1140						}
1141					});
1142
1143					// Clear inputs after submit
1144					var inputs = $this[0].getElementsByTagName('input');
1145					for (var i = 0; i < inputs.length; i++) {
1146						inputs[i].value = '';
1147						var label = document.querySelector( '[for="'+ inputs[i].getAttribute( 'id' ) +'"]' );
1148						if( label ) label.classList.remove( 'focus', 'not-empty' );
1149					}
1150
1151					return false;
1152				}, $campaignItem));
1153			}
1154		}
1155
1156		// RD Mailform
1157		if (plugins.rdMailForm.length) {
1158			var i, j, k,
1159				msg = {
1160					'MF000': 'Successfully sent!',
1161					'MF001': 'Recipients are not set!',
1162					'MF002': 'Form will not work locally!',
1163					'MF003': 'Please, define email field in your form!',
1164					'MF004': 'Please, define type of your form!',
1165					'MF254': 'Something went wrong with PHPMailer!',
1166					'MF255': 'Aw, snap! Something went wrong.'
1167				};
1168
1169			for (i = 0; i < plugins.rdMailForm.length; i++) {
1170				var $form = $(plugins.rdMailForm[i]),
1171					formHasCaptcha = false;
1172
1173				$form.attr('novalidate', 'novalidate').ajaxForm({
1174					data: {
1175						"form-type": $form.attr("data-form-type") || "contact",
1176						"counter": i
1177					},
1178					beforeSubmit: function (arr, $form, options) {
1179						if (isNoviBuilder)
1180							return;
1181
1182						var form = $(plugins.rdMailForm[this.extraData.counter]),
1183							inputs = form.find("[data-constraints]"),
1184							output = $("#" + form.attr("data-form-output")),
1185							captcha = form.find('.recaptcha'),
1186							captchaFlag = true;
1187
1188						output.removeClass("active error success");
1189
1190						if (isValidated(inputs, captcha)) {
1191
1192							// veify reCaptcha
1193							if (captcha.length) {
1194								var captchaToken = captcha.find('.g-recaptcha-response').val(),
1195									captchaMsg = {
1196										'CPT001': 'Please, setup you "site key" and "secret key" of reCaptcha',
1197										'CPT002': 'Something wrong with google reCaptcha'
1198									};
1199
1200								formHasCaptcha = true;
1201
1202								$.ajax({
1203									method: "POST",
1204									url: "bat/reCaptcha.php",
1205									data: {'g-recaptcha-response': captchaToken},
1206									async: false
1207								})
1208									.done(function (responceCode) {
1209										if (responceCode !== 'CPT000') {
1210											if (output.hasClass("snackbars")) {
1211												output.html('<p><span class="icon text-middle mdi mdi-check icon-xxs"></span><span>' + captchaMsg[responceCode] + '</span></p>')
1212
1213												setTimeout(function () {
1214													output.removeClass("active");
1215												}, 3500);
1216
1217												captchaFlag = false;
1218											} else {
1219												output.html(captchaMsg[responceCode]);
1220											}
1221
1222											output.addClass("active");
1223										}
1224									});
1225							}
1226
1227							if (!captchaFlag) {
1228								return false;
1229							}
1230
1231							form.addClass('form-in-process');
1232
1233							if (output.hasClass("snackbars")) {
1234								output.html('<p><span class="icon text-middle fa fa-circle-o-notch fa-spin icon-xxs"></span><span>Sending</span></p>');
1235								output.addClass("active");
1236							}
1237						} else {
1238							return false;
1239						}
1240					},
1241					error: function (result) {
1242						if (isNoviBuilder)
1243							return;
1244
1245						var output = $("#" + $(plugins.rdMailForm[this.extraData.counter]).attr("data-form-output")),
1246							form = $(plugins.rdMailForm[this.extraData.counter]);
1247
1248						output.text(msg[result]);
1249						form.removeClass('form-in-process');
1250
1251						if (formHasCaptcha) {
1252							grecaptcha.reset();
1253						}
1254					},
1255					success: function (result) {
1256						if (isNoviBuilder)
1257							return;
1258
1259						var form = $(plugins.rdMailForm[this.extraData.counter]),
1260							output = $("#" + form.attr("data-form-output")),
1261							select = form.find('select');
1262
1263						form
1264							.addClass('success')
1265							.removeClass('form-in-process');
1266
1267						if (formHasCaptcha) {
1268							grecaptcha.reset();
1269						}
1270
1271						result = result.length === 5 ? result : 'MF255';
1272						output.text(msg[result]);
1273
1274						if (result === "MF000") {
1275							if (output.hasClass("snackbars")) {
1276								output.html('<p><span class="icon text-middle mdi mdi-check icon-xxs"></span><span>' + msg[result] + '</span></p>');
1277							} else {
1278								output.addClass("active success");
1279							}
1280						} else {
1281							if (output.hasClass("snackbars")) {
1282								output.html(' <p class="snackbars-left"><span class="icon icon-xxs mdi mdi-alert-outline text-middle"></span><span>' + msg[result] + '</span></p>');
1283							} else {
1284								output.addClass("active error");
1285							}
1286						}
1287
1288						form.clearForm();
1289
1290						if (select.length) {
1291							select.select2("val", "");
1292						}
1293
1294						form.find('input, textarea').trigger('blur');
1295
1296						setTimeout(function () {
1297							output.removeClass("active error success");
1298							form.removeClass('success');
1299						}, 3500);
1300					}
1301				});
1302			}
1303		}
1304
1305		// lightGallery
1306		if (plugins.lightGallery.length) {
1307			for (var i = 0; i < plugins.lightGallery.length; i++) {
1308				initLightGallery(plugins.lightGallery[i]);
1309			}
1310		}
1311
1312		// lightGallery item
1313		if (plugins.lightGalleryItem.length) {
1314			// Filter carousel items
1315			var notCarouselItems = [];
1316
1317			for (var z = 0; z < plugins.lightGalleryItem.length; z++) {
1318				if (!$(plugins.lightGalleryItem[z]).parents('.owl-carousel').length &&
1319					!$(plugins.lightGalleryItem[z]).parents('.swiper-slider').length &&
1320					!$(plugins.lightGalleryItem[z]).parents('.slick-slider').length) {
1321					notCarouselItems.push(plugins.lightGalleryItem[z]);
1322				}
1323			}
1324
1325			plugins.lightGalleryItem = notCarouselItems;
1326
1327			for (var i = 0; i < plugins.lightGalleryItem.length; i++) {
1328				initLightGalleryItem(plugins.lightGalleryItem[i]);
1329			}
1330		}
1331
1332		// Dynamic lightGallery
1333		if (plugins.lightDynamicGalleryItem.length) {
1334			for (var i = 0; i < plugins.lightDynamicGalleryItem.length; i++) {
1335				initDynamicLightGallery(plugins.lightDynamicGalleryItem[i]);
1336			}
1337		}
1338
1339		// Custom Toggles
1340		if (plugins.customToggle.length) {
1341			for (var i = 0; i < plugins.customToggle.length; i++) {
1342				var $this = $(plugins.customToggle[i]);
1343
1344				$this.on('click', $.proxy(function (event) {
1345					event.preventDefault();
1346
1347					var $ctx = $(this);
1348					$($ctx.attr('data-custom-toggle')).add(this).toggleClass('active');
1349				}, $this));
1350
1351				if ($this.attr("data-custom-toggle-hide-on-blur") === "true") {
1352					$body.on("click", $this, function (e) {
1353						if (e.target !== e.data[0]
1354							&& $(e.data.attr('data-custom-toggle')).find($(e.target)).length
1355							&& e.data.find($(e.target)).length === 0) {
1356							$(e.data.attr('data-custom-toggle')).add(e.data[0]).removeClass('active');
1357						}
1358					})
1359				}
1360
1361				if ($this.attr("data-custom-toggle-disable-on-blur") === "true") {
1362					$body.on("click", $this, function (e) {
1363						if (e.target !== e.data[0] && $(e.data.attr('data-custom-toggle')).find($(e.target)).length === 0 && e.data.find($(e.target)).length === 0) {
1364							$(e.data.attr('data-custom-toggle')).add(e.data[0]).removeClass('active');
1365						}
1366					})
1367				}
1368			}
1369		}
1370
1371		// Countdown
1372		if ( plugins.countdown.length ) {
1373			for ( var i = 0; i < plugins.countdown.length; i++) {
1374				var
1375					node = plugins.countdown[i],
1376					countdown = aCountdown({
1377						node:  node,
1378						from:  node.getAttribute( 'data-from' ),
1379						to:    node.getAttribute( 'data-to' ),
1380						count: node.getAttribute( 'data-count' ),
1381						tick:  100,
1382					});
1383			}
1384		}
1385	});
1386}());

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.