PageSourceSearch

https://ebcitizen.com/_static/??-eJyNkEtuwzAMRC9UWW0TIMmi6FECWqId2…//xdjicTsfj/n0/fAMI/dSb

js ebcitizen.com collected 2026-09-24 19:38:54 UTC 107,483 bytes, 2,550 lines download raw bytes

1/**
2 * Comment Likes - JavaScript
3 *
4 * This handles liking and unliking comments, as well as viewing who has
5 * liked a particular comment.
6 *
7 * @dependency  Swipe (dynamically loaded when needed)
8 *
9 * @package     Comment_Likes
10 * @subpackage  JavaScript
11 */
12(function () {
13	function init() {
14		let extWin;
15		let extWinCheck;
16		let commentLikeEvent;
17
18		// Only run once.
19		if (window.comment_likes_loaded) {
20			return;
21		}
22		window.comment_likes_loaded = true;
23
24		// Client-side cache of who liked a particular comment to avoid
25		// having to hit the server multiple times for the same data.
26		const commentLikeCache = {};
27
28		let swipeLibPromise;
29
30		// Load the Swipe library, if it's not already loaded.
31		function swipeLibLoader() {
32			if (!swipeLibPromise) {
33				swipeLibPromise = new Promise((resolve, reject) => {
34					if (window.Swipe) {
35						resolve(window.Swipe);
36					} else {
37						const swipeScript = document.createElement('script');
38						swipeScript.src = comment_like_text.swipeUrl;
39						swipeScript.async = true;
40						document.body.appendChild(swipeScript);
41						swipeScript.addEventListener('load', () => resolve(window.Swipe));
42						swipeScript.addEventListener('error', error => reject(error));
43					}
44				});
45			}
46			return swipeLibPromise;
47		}
48
49		/**
50		 * Parse the comment ID from a comment like link.
51		 */
52		function getCommentId(link) {
53			const commentId =
54				link && link.getAttribute('href') && link.getAttribute('href').split('like_comment=');
55			return commentId[1].split('&_wpnonce=')[0];
56		}
57
58		/**
59		 * Handle an ajax action on the comment like link.
60		 */
61		function handleLinkAction(link, action, commentId, callback) {
62			const nonce =
63				link && link.getAttribute('href') && link.getAttribute('href').split('_wpnonce=')[1];
64
65			fetch('/wp-admin/admin-ajax.php', {
66				method: 'POST',
67				body: new URLSearchParams({
68					action: action,
69					_wpnonce: nonce,
70					like_comment: commentId,
71					blog_id: Number(link.dataset.blog),
72				}),
73				headers: {
74					'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
75					'X-Requested-With': 'XMLHttpRequest',
76					Accept: 'application/json',
77					'cache-control': 'no-cache',
78					pragma: 'no-cache',
79				},
80			})
81				.then(response => response.json())
82				.then(callback);
83		}
84
85		function startPolling() {
86			// Append cookie polling login iframe to this window to wait for user to finish logging in (or cancel)
87			const loginIframe = document.createElement('iframe');
88			loginIframe.id = 'wp-login-polling-iframe';
89			loginIframe.src = 'https://wordpress.com/public.api/connect/?iframe=true';
90			document.body.appendChild(loginIframe);
91			loginIframe.style.display = 'none';
92		}
93
94		function stopPolling() {
95			const iframe = document.querySelector('#wp-login-polling-iframe');
96			if (iframe) {
97				iframe.remove();
98			}
99		}
100
101		function hide(el) {
102			if (el && el.style) {
103				el.style.display = 'none';
104			}
105		}
106
107		function show(el) {
108			if (el && el.style) {
109				el.style.removeProperty('display');
110			}
111		}
112
113		// Overlay used for displaying comment like info.
114		class Overlay {
115			constructor() {
116				// Overlay element.
117				this.el = document.createElement('div');
118				this.el.classList.add('comment-likes-overlay');
119				document.body.appendChild(this.el);
120				hide(this.el);
121
122				this.el.addEventListener('mouseenter', () => {
123					// Don't hide the overlay if the user is mousing over it.
124					overlay.cancelHide();
125				});
126
127				this.el.addEventListener('mouseleave', () => overlay.requestHide());
128
129				// Inner contents of overlay.
130				this.innerEl = null;
131
132				// Instance of the Swipe library.
133				this.swipe = null;
134
135				// Timeout used for hiding the overlay.
136				this.hideTimeout = null;
137			}
138
139			// Initialise the overlay for use, removing any old content.
140			clear() {
141				// Unload any previous instance of Swipe (to avoid leaking a global
142				// event handler). This is done before clearing the contents of the
143				// overlay because Swipe expects the slides to still be present.
144				if (this.swipe) {
145					this.swipe.kill();
146					this.swipe = null;
147				}
148				this.el.innerHTML = '';
149				this.innerEl = document.createElement('div');
150				this.innerEl.classList.add('inner');
151				this.el.appendChild(this.innerEl);
152			}
153
154			/**
155			 * Construct a list (<ul>) of user (gravatar, name) details.
156			 *
157			 * @param  data     liker data returned from the server
158			 * @param  klass    CSS class to apply to the <ul> element
159			 * @param  start    index of user to start at
160			 * @param  length   number of users to include in the list
161			 *
162			 * @return          A container element with the list
163			 */
164			getUserBits(data, klass, start, length) {
165				start = start || 0;
166				let last = start + (length || data.length);
167				last = last > data.length ? data.length : last;
168				const container = document.createElement('div');
169				container.classList.add('liker-list');
170				let html = `<ul class="${klass || ''}">`;
171				for (let i = start; i < last; ++i) {
172					const user = data[i];
173					html += `
174						<li>
175							<a rel="nofollow" title="${user.display_name_esc}" href="${user.profile_url_esc}">
176								<img src="${user.avatar_url_esc}" alt="${user.display_name_esc}" />
177								<span class="user-name">${user.display_name_esc}</span>
178							</a>
179						</li>
180					`;
181				}
182				html += '</ul>';
183				container.innerHTML = html;
184				return container;
185			}
186
187			/**
188			 * Render the display of who has liked this comment. The type of
189			 * display depends on how many people have liked the comment.
190			 * If more than 10 people have liked the comment, this function
191			 * renders navigation controls and sets up the Swipe library for
192			 * changing between pages.
193			 *
194			 * @param link  the element over which the user is hovering
195			 * @param data  the results retrieved from the server
196			 */
197			showLikes(link, data) {
198				this.clear();
199
200				link.dataset.likeCount = data.length;
201				if (data.length === 0) {
202					// No likers after all.
203					hide(this.el);
204					return;
205				}
206
207				this.innerEl.style.padding = '12px';
208
209				if (data.length < 6) {
210					// Only one column needed.
211					this.innerEl.style.maxWidth = '200px';
212					this.innerEl.innerHTML = '';
213					this.innerEl.appendChild(this.getUserBits(data, 'single'));
214					this.setPosition(link);
215				} else if (data.length < 11) {
216					// Two columns, but only one page.
217					this.innerEl.innerHTML = '';
218					this.innerEl.appendChild(this.getUserBits(data, 'double'));
219					this.setPosition(link);
220				} else {
221					// Multiple pages.
222					this.renderLikesWithPagination(data, link);
223				}
224			}
225
226			/**
227			 * Render multiple pages of likes with pagination controls.
228			 * This function is intended to be called by `showLikes` above.
229			 *
230			 * @param data  the results retrieved from the server
231			 */
232			renderLikesWithPagination(data, link) {
233				swipeLibLoader().then(() => {
234					const page_count = Math.ceil(data.length / 10);
235					// Swipe requires two nested containers.
236					const swipe = document.createElement('div');
237					swipe.classList.add('swipe');
238					this.innerEl.appendChild(swipe);
239
240					const wrap = document.createElement('div');
241					wrap.classList.add('swipe-wrap');
242					swipe.appendChild(wrap);
243
244					for (let i = 0; i < page_count; ++i) {
245						wrap.appendChild(this.getUserBits(data, 'double', i * 10, 10));
246					}
247
248					/**
249					 * Navigation controls.
250					 * This is based on the Newdash controls found in
251					 *    reader/recommendations-templates.php
252					 */
253					const nav = document.createElement('nav');
254					nav.classList.add('slider-nav');
255
256					let navContents = `
257						<a href="#" class="prev">
258							<span class="noticon noticon-previous" title="Previous" alt="<"></span>
259						</a>
260						<span class="position">
261					`;
262					for (let i = 0; i < page_count; ++i) {
263						navContents += `<em data-page="${i}" class="${i === 0 ? 'on' : ''}">&bull;</em>`;
264					}
265					navContents += `
266						</span>
267						<a href="#" class="next">
268							<span class="noticon noticon-next" title="Next" alt=">"></span>
269						</a>
270					`;
271					this.innerEl.appendChild(nav);
272					nav.innerHTML = navContents;
273
274					/** Set up Swipe. **/
275					// Swipe cannot be set up successfully unless its container
276					// is visible, so we show it now.
277					show(this.el);
278					this.setPosition(link);
279
280					this.swipe = new Swipe(swipe, {
281						callback: function (pos) {
282							// Update the pagination indicators.
283							//
284							// If there are exactly two pages, Swipe has a weird
285							// special case where it duplicates both pages and
286							// can return index 2 and 3 even though those aren't
287							// real pages (see swipe.js, line 47). To deal with
288							// this, we use the expression `pos % page_count`.
289							pos = pos % page_count;
290							nav.querySelectorAll('em').forEach(em => {
291								const page = Number(em.dataset.page);
292								em.setAttribute('class', pos === page ? 'on' : '');
293							});
294						},
295					});
296
297					nav.querySelectorAll('em').forEach(em => {
298						em.addEventListener('click', e => {
299							// Go to the page corresponding to the indicator clicked.
300							this.swipe.slide(Number(em.dataset.page));
301							e.preventDefault();
302						});
303					});
304					// Previous and next buttons.
305					nav.querySelector('.prev').addEventListener('click', e => {
306						this.swipe.prev();
307						e.preventDefault();
308					});
309					nav.querySelector('.next').addEventListener('click', e => {
310						this.swipe.next();
311						e.preventDefault();
312					});
313				});
314			}
315
316			/**
317			 * Open the overlay and show a loading message.
318			 */
319			showLoadingMessage(link) {
320				this.clear();
321				this.innerEl.textContent = comment_like_text.loading;
322				this.setPosition(link);
323			}
324
325			/**
326			 * Position the overlay near the current comment.
327			 *
328			 * @param link  element near which to position the overlay
329			 */
330			setPosition(link) {
331				// Prepare a down arrow icon for the bottom of the overlay.
332				const icon = document.createElement('span');
333				this.el.appendChild(icon);
334				icon.classList.add('icon', 'noticon', 'noticon-downarrow');
335				icon.style.textShadow = '0px 1px 1px rgb(223, 223, 223)';
336
337				const rect = link.getBoundingClientRect();
338				const win = document.defaultView;
339				const offset = {
340					top: rect.top + win.scrollY,
341					left: rect.left + win.scrollX,
342				};
343
344				// Take measurements with the element fully visible.
345				show(this.el);
346				let left = offset.left - (this.el.offsetWidth - link.offsetWidth) / 2;
347				left = left < 5 ? 5 : left;
348				let top = offset.top - this.el.offsetHeight + 5;
349				hide(this.el);
350
351				const adminBar = document.querySelector('#wpadminbar');
352
353				// Check if the overlay would appear off the screen.
354				if (top < win.scrollY + ((adminBar && adminBar.offsetHeight) || 0)) {
355					// We'll display the overlay beneath the link instead.
356					top = offset.top + link.offsetHeight;
357					// Instead of using the down arrow icon, use an up arrow.
358					icon.remove();
359					this.el.prepend(icon);
360					icon.classList.remove('noticon-downarrow');
361					icon.classList.add('noticon-uparrow');
362					icon.style.textShadow = '0px -1px 1px rgb(223, 223, 223)';
363					icon.style.verticalAlign = 'bottom';
364				}
365
366				this.el.style.left = `${left}px`;
367				this.el.style.top = `${top}px`;
368				show(this.el);
369
370				// The height of the arrow icon differs slightly between browsers,
371				// so we compute the margin here to make sure it isn't disjointed
372				// from the overlay.
373				icon.style.marginTop = `${icon.scrollHeight - 26}px`;
374				icon.style.marginBottom = `${20 - icon.scrollHeight}px`;
375
376				// Position the arrow to be horizontally centred on the link.
377				icon.style.paddingLeft = `${
378					offset.left - left + (link.offsetWidth - icon.scrollWidth) / 2
379				}px`;
380			}
381
382			/**
383			 * Return whether the overlay is visible.
384			 */
385			isVisible() {
386				return this.el.style.getPropertyValue('display') !== 'none';
387			}
388
389			/**
390			 * Request that the overlay be hidden after a short delay.
391			 */
392			requestHide() {
393				if (this.hideTimeout !== null) {
394					return;
395				}
396				this.hideTimeout = setTimeout(() => {
397					hide(this.el);
398					this.clear();
399				}, 300);
400			}
401
402			/**
403			 * Cancel a request to hide the overlay.
404			 */
405			cancelHide() {
406				if (this.hideTimeout !== null) {
407					clearTimeout(this.hideTimeout);
408					this.hideTimeout = null;
409				}
410			}
411		}
412
413		// Overlay used for displaying comment like info.
414		const overlay = new Overlay();
415
416		// The most recent comment for which the user has requested to see
417		// who liked it.
418		var relevantComment;
419
420		// Precache after this timeout.
421		var precacheTimeout = null;
422
423		/**
424		 * Fetch the like data for a particular comment.
425		 */
426		function fetchLikeData(link, commentId) {
427			commentLikeCache[commentId] = null;
428
429			const container = link && link.parentElement && link.parentElement.parentElement;
430			const star = container.querySelector('a.comment-like-link');
431			star &&
432				handleLinkAction(star, 'view_comment_likes', commentId, data => {
433					// Populate the cache.
434					commentLikeCache[commentId] = data;
435
436					// Only show the overlay if the user is interested.
437					if (overlay.isVisible() && relevantComment === commentId) {
438						overlay.showLikes(link, data);
439					}
440				});
441		}
442
443		function readCookie(c) {
444			const nameEQ = c + '=';
445			const cookieStrings = document.cookie.split(';');
446
447			for (let i = 0; i < cookieStrings.length; i++) {
448				let cookieString = cookieStrings[i];
449				while (cookieString.charAt(0) === ' ') {
450					cookieString = cookieString.substring(1, cookieString.length);
451				}
452				if (cookieString.indexOf(nameEQ) === 0) {
453					const chunk = cookieString.substring(nameEQ.length, cookieString.length);
454					const pairs = chunk.split('&');
455					const cookieData = {};
456					for (let num = pairs.length - 1; num >= 0; num--) {
457						const pair = pairs[num].split('=');
458						cookieData[pair[0]] = decodeURIComponent(pair[1]);
459					}
460					return cookieData;
461				}
462			}
463			return null;
464		}
465
466		function getServiceData() {
467			const data = readCookie('wpc_wpc');
468			if (data === null || typeof data.access_token === 'undefined' || !data.access_token) {
469				return false;
470			}
471			return data;
472		}
473
474		function readMessage(msg) {
475			const event = msg.data;
476
477			if (typeof event.event === 'undefined') {
478				return;
479			}
480
481			if (event.event === 'login' && event.success) {
482				extWinCheck = setInterval(function () {
483					if (!extWin || extWin.closed) {
484						clearInterval(extWinCheck);
485						if (getServiceData()) {
486							// Load page in an iframe to get the current comment nonce
487							const nonceIframe = document.createElement('iframe');
488							nonceIframe.id = 'wp-login-comment-nonce-iframe';
489							nonceIframe.style.display = 'none';
490							nonceIframe.src = commentLikeEvent + '';
491							document.body.appendChild(nonceIframe);
492
493							const commentLikeId = (commentLikeEvent + '')
494								.split('like_comment=')[1]
495								.split('&_wpnonce=')[0];
496							let c;
497
498							// Set a 5 second timeout to redirect to the comment page without doing the Like as a fallback
499							const commentLikeTimeout = setTimeout(() => {
500								window.location = commentLikeEvent;
501							}, 5000);
502
503							// Check for a new nonced redirect and use that if available before timing out
504							const commentLikeCheck = setInterval(() => {
505								const iframe = document.querySelector('#wp-login-comment-nonce-iframe');
506								if (iframe) {
507									c = iframe.querySelector(`#comment-like-${commentLikeId} .comment-like-link`);
508								}
509								if (c && typeof c.href !== 'undefined') {
510									clearTimeout(commentLikeTimeout);
511									clearInterval(commentLikeCheck);
512									window.location = c.href;
513								}
514							}, 100);
515						}
516					}
517				}, 100);
518
519				if (extWin) {
520					if (!extWin.closed) {
521						extWin.close();
522					}
523					extWin = false;
524				}
525
526				stopPolling();
527			}
528		}
529
530		if (typeof window.postMessage !== 'undefined') {
531			window.addEventListener('message', e => {
532				let message = e && e.data;
533				if (typeof message === 'string') {
534					try {
535						message = JSON.parse(message);
536					} catch (err) {
537						return;
538					}
539				}
540
541				const type = message && message.type;
542				if (type === 'loginMessage') {
543					readMessage(message);
544				}
545			});
546		}
547
548		document.body.addEventListener('click', e => {
549			let target = e.target;
550
551			// Don't do anything when clicking on the "X people" link.
552			if (target.matches('p.comment-likes a.view-likers')) {
553				e.preventDefault();
554				return;
555			}
556
557			// Retrieve the surrounding paragraph to the star, if it hasn't been liked.
558			const notLikedPar = target.closest('p.comment-not-liked');
559
560			// Return if not clicking on star or surrounding paragraph.
561			if (!target.matches('a.comment-like-link') && !notLikedPar) {
562				return;
563			}
564
565			// When a comment hasn't been liked, make the text clickable, too.
566			if (notLikedPar) {
567				target = notLikedPar.querySelector('a.comment-like-link');
568				if (!target) {
569					return;
570				}
571			}
572
573			if (target.classList.contains('needs-login')) {
574				e.preventDefault();
575				commentLikeEvent = target;
576				if (extWin) {
577					if (!extWin.closed) {
578						extWin.close();
579					}
580					extWin = false;
581				}
582
583				stopPolling();
584
585				const url = 'https://wordpress.com/public.api/connect/?action=request&service=wordpress';
586				extWin = window.open(
587					url,
588					'likeconn',
589					'status=0,toolbar=0,location=1,menubar=0,directories=0,resizable=1,scrollbars=1,height=560,width=500'
590				);
591
592				startPolling();
593
594				return false;
595			}
596
597			// Record that the user likes or does not like this comment.
598			const commentId = getCommentId(target);
599			target.classList.add('loading');
600
601			let commentEl = document.querySelector(`p#comment-like-${commentId}`);
602			// Determine whether to like or unlike based on whether the comment is
603			// currently liked.
604			const action =
605				commentEl && commentEl.dataset.liked === 'comment-liked'
606					? 'unlike_comment'
607					: 'like_comment';
608			handleLinkAction(target, action, commentId, data => {
609				// Invalidate the like cache for this comment.
610				delete commentLikeCache[commentId];
611
612				const countEl = document.querySelector(`#comment-like-count-${data.context}`);
613				if (countEl) {
614					countEl.innerHTML = data.display;
615				}
616
617				commentEl = document.querySelector(`p#comment-like-${data.context}`);
618				if (action === 'like_comment') {
619					commentEl.classList.remove('comment-not-liked');
620					commentEl.classList.add('comment-liked');
621					commentEl.dataset.liked = 'comment-liked';
622				} else {
623					commentEl.classList.remove('comment-liked');
624					commentEl.classList.add('comment-not-liked');
625					commentEl.dataset.liked = 'comment-not-liked';
626				}
627
628				// Prefetch new data for this comment (if there are likers left).
629				const parent = target.closest('.comment-likes');
630				const link = parent && parent.querySelector('a.view-likers');
631				if (link) {
632					fetchLikeData(link, commentId);
633				}
634
635				target.classList.remove('loading');
636			});
637			e.preventDefault();
638			e.stopPropagation();
639		});
640
641		document.body.addEventListener(
642			'mouseenter',
643			function (e) {
644				if (!e.target.matches('p.comment-likes a.view-likers')) {
645					return;
646				}
647				// Show the user a list of who has liked this comment.
648
649				const link = e.target;
650				if (Number(link.dataset.likeCount || 0) === 0) {
651					// No one has liked this comment.
652					return;
653				}
654
655				// Don't hide the overlay.
656				overlay.cancelHide();
657
658				// Get the comment ID.
659				const container = link.parentElement && link.parentElement.parentElement;
660				const star = container && container.querySelector('a.comment-like-link');
661				const commentId = star && getCommentId(star);
662				relevantComment = commentId;
663
664				// Check if the list of likes for this comment is already in
665				// the cache.
666				if (commentId in commentLikeCache) {
667					const entry = commentLikeCache[commentId];
668					// Only display the likes if the ajax request is
669					// actually done.
670					if (entry !== null) {
671						overlay.showLikes(link, entry);
672					} else {
673						// Make sure the overlay is visible (in case
674						// the user moved the mouse away while loading
675						// but then came back before it finished
676						// loading).
677						overlay.showLoadingMessage(link);
678					}
679					return;
680				}
681
682				// Position the "Loading..." overlay.
683				overlay.showLoadingMessage(link);
684
685				// Fetch the data.
686				fetchLikeData(link, commentId);
687			},
688			true
689		);
690
691		document.body.addEventListener(
692			'mouseleave',
693			e => {
694				if (!e.target.matches('p.comment-likes a.view-likers')) {
695					return;
696				}
697				// User has moved cursor away - hide the overlay.
698				overlay.requestHide();
699			},
700			true
701		);
702
703		document.body.addEventListener(
704			'mouseenter',
705			e => {
706				if (!e.target.matches('.comment') || !e.target.querySelector('a.comment-like-link')) {
707					return;
708				}
709				// User is moving over a comment - precache the comment like data.
710				if (precacheTimeout !== null) {
711					clearTimeout(precacheTimeout);
712					precacheTimeout = null;
713				}
714
715				const star = e.target.querySelector('a.comment-like-link');
716				const parent = star.closest('.comment-likes');
717				const link = parent && parent.querySelector('a.view-likers');
718				if (!link || Number(link.dataset.likeCount || 0) === 0) {
719					// No likes.
720					return;
721				}
722				const commentId = getCommentId(star);
723				if (commentId in commentLikeCache) {
724					// Already in cache.
725					return;
726				}
727
728				precacheTimeout = setTimeout(() => {
729					precacheTimeout = null;
730					if (commentId in commentLikeCache) {
731						// Was cached in the interim.
732						return;
733					}
734					fetchLikeData(link, commentId);
735				}, 1000);
736			},
737			true
738		);
739	}
740
741	if (document.readyState !== 'loading') {
742		init();
743	} else {
744		document.addEventListener('DOMContentLoaded', init);
745	}
746})();
747;
748/**
749 * File skip-link-focus-fix.js.
750 *
751 * Helps with accessibility for keyboard only users.
752 *
753 * Learn more: https://git.io/vWdr2
754 */
755( function() {
756	var isWebkit = navigator.userAgent.toLowerCase().indexOf( 'webkit' ) > -1,
757	    isOpera  = navigator.userAgent.toLowerCase().indexOf( 'opera' )  > -1,
758	    isIe     = navigator.userAgent.toLowerCase().indexOf( 'msie' )   > -1;
759
760	if ( ( isWebkit || isOpera || isIe ) && document.getElementById && window.addEventListener ) {
761		window.addEventListener( 'hashchange', function() {
762			var id = location.hash.substring( 1 ),
763				element;
764
765			if ( ! ( /^[A-z0-9_-]+$/.test( id ) ) ) {
766				return;
767			}
768
769			element = document.getElementById( id );
770
771			if ( element ) {
772				if ( ! ( /^(?:a|select|input|button|textarea)$/i.test( element.tagName ) ) ) {
773					element.tabIndex = -1;
774				}
775
776				element.focus();
777			}
778		}, false );
779	}
780})();;
781/*
782 * jQuery FlexSlider v2.4.0
783 * Copyright 2012 WooThemes
784 * Contributing Author: Tyler Smith
785 */
786;
787(function ($) {
788
789  //FlexSlider: Object Instance
790  $.flexslider = function(el, options) {
791    var slider = $(el);
792
793    // making variables public
794    slider.vars = $.extend({}, $.flexslider.defaults, options);
795
796    var namespace = slider.vars.namespace,
797        msGesture = window.navigator && window.navigator.msPointerEnabled && window.MSGesture,
798        touch = (( "ontouchstart" in window ) || msGesture || window.DocumentTouch && document instanceof DocumentTouch) && slider.vars.touch,
799        // depricating this idea, as devices are being released with both of these events
800        //eventType = (touch) ? "touchend" : "click",
801        eventType = "click touchend MSPointerUp keyup",
802        watchedEvent = "",
803        watchedEventClearTimer,
804        vertical = slider.vars.direction === "vertical",
805        reverse = slider.vars.reverse,
806        carousel = (slider.vars.itemWidth > 0),
807        fade = slider.vars.animation === "fade",
808        asNav = slider.vars.asNavFor !== "",
809        methods = {},
810        focused = true;
811
812    // Store a reference to the slider object
813    $.data(el, "flexslider", slider);
814
815    // Private slider methods
816    methods = {
817      init: function() {
818        slider.animating = false;
819        // Get current slide and make sure it is a number
820        slider.currentSlide = parseInt( ( slider.vars.startAt ? slider.vars.startAt : 0), 10 );
821        if ( isNaN( slider.currentSlide ) ) { slider.currentSlide = 0; }
822        slider.animatingTo = slider.currentSlide;
823        slider.atEnd = (slider.currentSlide === 0 || slider.currentSlide === slider.last);
824        slider.containerSelector = slider.vars.selector.substr(0,slider.vars.selector.search(' '));
825        slider.slides = $(slider.vars.selector, slider);
826        slider.container = $(slider.containerSelector, slider);
827        slider.count = slider.slides.length;
828        // SYNC:
829        slider.syncExists = $(slider.vars.sync).length > 0;
830        // SLIDE:
831        if (slider.vars.animation === "slide") { slider.vars.animation = "swing"; }
832        slider.prop = (vertical) ? "top" : "marginLeft";
833        slider.args = {};
834        // SLIDESHOW:
835        slider.manualPause = false;
836        slider.stopped = false;
837        //PAUSE WHEN INVISIBLE
838        slider.started = false;
vendor: 44,878 bytes, lines 839-1881
839        slider.startTimeout = null;
840        // TOUCH/USECSS:
841        slider.transitions = !slider.vars.video && !fade && slider.vars.useCSS && (function() {
842          var obj = document.createElement('div'),
843              props = ['perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective'];
844          for (var i in props) {
845            if ( obj.style[ props[i] ] !== undefined ) {
846              slider.pfx = props[i].replace('Perspective','').toLowerCase();
847              slider.prop = "-" + slider.pfx + "-transform";
848              return true;
849            }
850          }
851          return false;
852        }());
853        slider.ensureAnimationEnd = '';
854        // CONTROLSCONTAINER:
855        if (slider.vars.controlsContainer !== "") slider.controlsContainer = $(slider.vars.controlsContainer).length > 0 && $(slider.vars.controlsContainer);
856        // MANUAL:
857        if (slider.vars.manualControls !== "") slider.manualControls = $(slider.vars.manualControls).length > 0 && $(slider.vars.manualControls);
858
859        // RANDOMIZE:
860        if (slider.vars.randomize) {
861          slider.slides.sort(function() { return (Math.round(Math.random())-0.5); });
862          slider.container.empty().append(slider.slides);
863        }
864
865        slider.doMath();
866
867        // INIT
868        slider.setup("init");
869
870        // CONTROLNAV:
871        if (slider.vars.controlNav) { methods.controlNav.setup(); }
872
873        // DIRECTIONNAV:
874        if (slider.vars.directionNav) { methods.directionNav.setup(); }
875
876        // KEYBOARD:
877        if (slider.vars.keyboard && ($(slider.containerSelector).length === 1 || slider.vars.multipleKeyboard)) {
878          $(document).bind('keyup', function(event) {
879            var keycode = event.keyCode;
880            if (!slider.animating && (keycode === 39 || keycode === 37)) {
881              var target = (keycode === 39) ? slider.getTarget('next') :
882                           (keycode === 37) ? slider.getTarget('prev') : false;
883              slider.flexAnimate(target, slider.vars.pauseOnAction);
884            }
885          });
886        }
887        // MOUSEWHEEL:
888        if (slider.vars.mousewheel) {
889          slider.bind('mousewheel', function(event, delta, deltaX, deltaY) {
890            event.preventDefault();
891            var target = (delta < 0) ? slider.getTarget('next') : slider.getTarget('prev');
892            slider.flexAnimate(target, slider.vars.pauseOnAction);
893          });
894        }
895
896        // PAUSEPLAY
897        if (slider.vars.pausePlay) { methods.pausePlay.setup(); }
898
899        //PAUSE WHEN INVISIBLE
900        if (slider.vars.slideshow && slider.vars.pauseInvisible) { methods.pauseInvisible.init(); }
901
902        // SLIDSESHOW
903        if (slider.vars.slideshow) {
904          if (slider.vars.pauseOnHover) {
905            slider.hover(function() {
906              if (!slider.manualPlay && !slider.manualPause) { slider.pause(); }
907            }, function() {
908              if (!slider.manualPause && !slider.manualPlay && !slider.stopped) { slider.play(); }
909            });
910          }
911          // initialize animation
912          //If we're visible, or we don't use PageVisibility API
913          if(!slider.vars.pauseInvisible || !methods.pauseInvisible.isHidden()) {
914            (slider.vars.initDelay > 0) ? slider.startTimeout = setTimeout(slider.play, slider.vars.initDelay) : slider.play();
915          }
916        }
917
918        // ASNAV:
919        if (asNav) { methods.asNav.setup(); }
920
921        // TOUCH
922        if (touch && slider.vars.touch) { methods.touch(); }
923
924        // FADE&&SMOOTHHEIGHT || SLIDE:
925        if (!fade || (fade && slider.vars.smoothHeight)) { $(window).bind("resize orientationchange focus", methods.resize); }
926
927        slider.find("img").attr("draggable", "false");
928
929        // API: start() Callback
930        setTimeout(function(){
931          slider.vars.start(slider);
932        }, 200);
933      },
934      asNav: {
935        setup: function() {
936          slider.asNav = true;
937          slider.animatingTo = Math.floor(slider.currentSlide/slider.move);
938          slider.currentItem = slider.currentSlide;
939          slider.slides.removeClass(namespace + "active-slide").eq(slider.currentItem).addClass(namespace + "active-slide");
940          if(!msGesture){
941              slider.slides.on(eventType, function(e){
942                e.preventDefault();
943                var $slide = $(this),
944                    target = $slide.index();
945                var posFromLeft = $slide.offset().left - $(slider).scrollLeft(); // Find position of slide relative to left of slider container
946                if( posFromLeft <= 0 && $slide.hasClass( namespace + 'active-slide' ) ) {
947                  slider.flexAnimate(slider.getTarget("prev"), true);
948                } else if (!$(slider.vars.asNavFor).data('flexslider').animating && !$slide.hasClass(namespace + "active-slide")) {
949                  slider.direction = (slider.currentItem < target) ? "next" : "prev";
950                  slider.flexAnimate(target, slider.vars.pauseOnAction, false, true, true);
951                }
952              });
953          }else{
954              el._slider = slider;
955              slider.slides.each(function (){
956                  var that = this;
957                  that._gesture = new MSGesture();
958                  that._gesture.target = that;
959                  that.addEventListener("MSPointerDown", function (e){
960                      e.preventDefault();
961                      if(e.currentTarget._gesture) {
962                        e.currentTarget._gesture.addPointer(e.pointerId);
963                      }
964                  }, false);
965                  that.addEventListener("MSGestureTap", function (e){
966                      e.preventDefault();
967                      var $slide = $(this),
968                          target = $slide.index();
969                      if (!$(slider.vars.asNavFor).data('flexslider').animating && !$slide.hasClass('active')) {
970                          slider.direction = (slider.currentItem < target) ? "next" : "prev";
971                          slider.flexAnimate(target, slider.vars.pauseOnAction, false, true, true);
972                      }
973                  });
974              });
975          }
976        }
977      },
978      controlNav: {
979        setup: function() {
980          if (!slider.manualControls) {
981            methods.controlNav.setupPaging();
982          } else { // MANUALCONTROLS:
983            methods.controlNav.setupManual();
984          }
985        },
986        setupPaging: function() {
987          var type = (slider.vars.controlNav === "thumbnails") ? 'control-thumbs' : 'control-paging',
988              j = 1,
989              item,
990              slide;
991
992          slider.controlNavScaffold = $('<ol class="'+ namespace + 'control-nav ' + namespace + type + '"></ol>');
993
994          if (slider.pagingCount > 1) {
995            for (var i = 0; i < slider.pagingCount; i++) {
996              slide = slider.slides.eq(i);
997
998              if ( undefined === slide.attr( 'data-thumb-alt' ) ) { 
999                slide.attr( 'data-thumb-alt', '' ); 
1000              }
1001              
1002              item = $( '<a></a>' ).attr( 'href', '#' ).text( j );
1003              if ( slider.vars.controlNav === "thumbnails" ) {
1004                item = $( '<img/>' ).attr( 'src', slide.attr( 'data-thumb' ) );
1005              }
1006              
1007              if ( '' !== slide.attr( 'data-thumb-alt' ) ) {
1008                item.attr( 'alt', slide.attr( 'data-thumb-alt' ) );
1009              }
1010
1011              if ( 'thumbnails' === slider.vars.controlNav && true === slider.vars.thumbCaptions ) {
1012                var captn = slide.attr( 'data-thumbcaption' );
1013                if ( '' !== captn && undefined !== captn ) { 
1014                  var caption = $('<span></span>' ).addClass( namespace + 'caption' ).text( captn );
1015                  item.append( caption );
1016                }
1017              }
1018              
1019              var liElement = $( '<li>' );
1020              item.appendTo( liElement );
1021              liElement.append( '</li>' );
1022
1023              slider.controlNavScaffold.append(liElement);
1024              j++;
1025            }
1026          }
1027
1028          // CONTROLSCONTAINER:
1029          (slider.controlsContainer) ? $(slider.controlsContainer).append(slider.controlNavScaffold) : slider.append(slider.controlNavScaffold);
1030          methods.controlNav.set();
1031
1032          methods.controlNav.active();
1033
1034          slider.controlNavScaffold.delegate('a, img', eventType, function(event) {
1035            event.preventDefault();
1036
1037            if (watchedEvent === "" || watchedEvent === event.type) {
1038              var $this = $(this),
1039                  target = slider.controlNav.index($this);
1040
1041              if (!$this.hasClass(namespace + 'active')) {
1042                slider.direction = (target > slider.currentSlide) ? "next" : "prev";
1043                slider.flexAnimate(target, slider.vars.pauseOnAction);
1044              }
1045            }
1046
1047            // setup flags to prevent event duplication
1048            if (watchedEvent === "") {
1049              watchedEvent = event.type;
1050            }
1051            methods.setToClearWatchedEvent();
1052
1053          });
1054        },
1055        setupManual: function() {
1056          slider.controlNav = slider.manualControls;
1057          methods.controlNav.active();
1058
1059          slider.controlNav.bind(eventType, function(event) {
1060            event.preventDefault();
1061
1062            if (watchedEvent === "" || watchedEvent === event.type) {
1063              var $this = $(this),
1064                  target = slider.controlNav.index($this);
1065
1066              if (!$this.hasClass(namespace + 'active')) {
1067                (target > slider.currentSlide) ? slider.direction = "next" : slider.direction = "prev";
1068                slider.flexAnimate(target, slider.vars.pauseOnAction);
1069              }
1070            }
1071
1072            // setup flags to prevent event duplication
1073            if (watchedEvent === "") {
1074              watchedEvent = event.type;
1075            }
1076            methods.setToClearWatchedEvent();
1077          });
1078        },
1079        set: function() {
1080          var selector = (slider.vars.controlNav === "thumbnails") ? 'img' : 'a';
1081          slider.controlNav = $('.' + namespace + 'control-nav li ' + selector, (slider.controlsContainer) ? slider.controlsContainer : slider);
1082        },
1083        active: function() {
1084          slider.controlNav.removeClass(namespace + "active").eq(slider.animatingTo).addClass(namespace + "active");
1085        },
1086        update: function(action, pos) {
1087          if (slider.pagingCount > 1 && action === "add") {
1088            slider.controlNavScaffold.append($('<li><a>' + slider.count + '</a></li>'));
1089          } else if (slider.pagingCount === 1) {
1090            slider.controlNavScaffold.find('li').remove();
1091          } else {
1092            slider.controlNav.eq(pos).closest('li').remove();
1093          }
1094          methods.controlNav.set();
1095          (slider.pagingCount > 1 && slider.pagingCount !== slider.controlNav.length) ? slider.update(pos, action) : methods.controlNav.active();
1096        }
1097      },
1098      directionNav: {
1099        setup: function() {
1100          var directionNavScaffold = $('<ul class="' + namespace + 'direction-nav"><li class="' + namespace + 'nav-prev"><a class="' + namespace + 'prev" href="#">' + slider.vars.prevText + '</a></li><li class="' + namespace + 'nav-next"><a class="' + namespace + 'next" href="#">' + slider.vars.nextText + '</a></li></ul>');
1101
1102          // CONTROLSCONTAINER:
1103          if (slider.controlsContainer) {
1104            $(slider.controlsContainer).append(directionNavScaffold);
1105            slider.directionNav = $('.' + namespace + 'direction-nav li a', slider.controlsContainer);
1106          } else {
1107            slider.append(directionNavScaffold);
1108            slider.directionNav = $('.' + namespace + 'direction-nav li a', slider);
1109          }
1110
1111          methods.directionNav.update();
1112
1113          slider.directionNav.bind(eventType, function(event) {
1114            event.preventDefault();
1115            var target;
1116
1117            if (watchedEvent === "" || watchedEvent === event.type) {
1118              target = ($(this).hasClass(namespace + 'next')) ? slider.getTarget('next') : slider.getTarget('prev');
1119              slider.flexAnimate(target, slider.vars.pauseOnAction);
1120            }
1121
1122            // setup flags to prevent event duplication
1123            if (watchedEvent === "") {
1124              watchedEvent = event.type;
1125            }
1126            methods.setToClearWatchedEvent();
1127          });
1128        },
1129        update: function() {
1130          var disabledClass = namespace + 'disabled';
1131          if (slider.pagingCount === 1) {
1132            slider.directionNav.addClass(disabledClass).attr('tabindex', '-1');
1133          } else if (!slider.vars.animationLoop) {
1134            if (slider.animatingTo === 0) {
1135              slider.directionNav.removeClass(disabledClass).filter('.' + namespace + "prev").addClass(disabledClass).attr('tabindex', '-1');
1136            } else if (slider.animatingTo === slider.last) {
1137              slider.directionNav.removeClass(disabledClass).filter('.' + namespace + "next").addClass(disabledClass).attr('tabindex', '-1');
1138            } else {
1139              slider.directionNav.removeClass(disabledClass).removeAttr('tabindex');
1140            }
1141          } else {
1142            slider.directionNav.removeClass(disabledClass).removeAttr('tabindex');
1143          }
1144        }
1145      },
1146      pausePlay: {
1147        setup: function() {
1148          var pausePlayScaffold = $('<div class="' + namespace + 'pauseplay"><a></a></div>');
1149
1150          // CONTROLSCONTAINER:
1151          if (slider.controlsContainer) {
1152            slider.controlsContainer.append(pausePlayScaffold);
1153            slider.pausePlay = $('.' + namespace + 'pauseplay a', slider.controlsContainer);
1154          } else {
1155            slider.append(pausePlayScaffold);
1156            slider.pausePlay = $('.' + namespace + 'pauseplay a', slider);
1157          }
1158
1159          methods.pausePlay.update((slider.vars.slideshow) ? namespace + 'pause' : namespace + 'play');
1160
1161          slider.pausePlay.bind(eventType, function(event) {
1162            event.preventDefault();
1163
1164            if (watchedEvent === "" || watchedEvent === event.type) {
1165              if ($(this).hasClass(namespace + 'pause')) {
1166                slider.manualPause = true;
1167                slider.manualPlay = false;
1168                slider.pause();
1169              } else {
1170                slider.manualPause = false;
1171                slider.manualPlay = true;
1172                slider.play();
1173              }
1174            }
1175
1176            // setup flags to prevent event duplication
1177            if (watchedEvent === "") {
1178              watchedEvent = event.type;
1179            }
1180            methods.setToClearWatchedEvent();
1181          });
1182        },
1183        update: function(state) {
1184          (state === "play") ? slider.pausePlay.removeClass(namespace + 'pause').addClass(namespace + 'play').html(slider.vars.playText) : slider.pausePlay.removeClass(namespace + 'play').addClass(namespace + 'pause').html(slider.vars.pauseText);
1185        }
1186      },
1187      touch: function() {
1188        var startX,
1189          startY,
1190          offset,
1191          cwidth,
1192          dx,
1193          startT,
1194          scrolling = false,
1195          localX = 0,
1196          localY = 0,
1197          accDx = 0;
1198
1199        if(!msGesture){
1200            el.addEventListener('touchstart', onTouchStart, false);
1201
1202            function onTouchStart(e) {
1203              if (slider.animating) {
1204                e.preventDefault();
1205              } else if ( ( window.navigator.msPointerEnabled ) || e.touches.length === 1 ) {
1206                slider.pause();
1207                // CAROUSEL:
1208                cwidth = (vertical) ? slider.h : slider. w;
1209                startT = Number(new Date());
1210                // CAROUSEL:
1211
1212                // Local vars for X and Y points.
1213                localX = e.touches[0].pageX;
1214                localY = e.touches[0].pageY;
1215
1216                offset = (carousel && reverse && slider.animatingTo === slider.last) ? 0 :
1217                         (carousel && reverse) ? slider.limit - (((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo) :
1218                         (carousel && slider.currentSlide === slider.last) ? slider.limit :
1219                         (carousel) ? ((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.currentSlide :
1220                         (reverse) ? (slider.last - slider.currentSlide + slider.cloneOffset) * cwidth : (slider.currentSlide + slider.cloneOffset) * cwidth;
1221                startX = (vertical) ? localY : localX;
1222                startY = (vertical) ? localX : localY;
1223
1224                el.addEventListener('touchmove', onTouchMove, false);
1225                el.addEventListener('touchend', onTouchEnd, false);
1226              }
1227            }
1228
1229            function onTouchMove(e) {
1230              // Local vars for X and Y points.
1231
1232              localX = e.touches[0].pageX;
1233              localY = e.touches[0].pageY;
1234
1235              dx = (vertical) ? startX - localY : startX - localX;
1236              scrolling = (vertical) ? (Math.abs(dx) < Math.abs(localX - startY)) : (Math.abs(dx) < Math.abs(localY - startY));
1237
1238              var fxms = 500;
1239
1240              if ( ! scrolling || Number( new Date() ) - startT > fxms ) {
1241                e.preventDefault();
1242                if (!fade && slider.transitions) {
1243                  if (!slider.vars.animationLoop) {
1244                    dx = dx/((slider.currentSlide === 0 && dx < 0 || slider.currentSlide === slider.last && dx > 0) ? (Math.abs(dx)/cwidth+2) : 1);
1245                  }
1246                  slider.setProps(offset + dx, "setTouch");
1247                }
1248              }
1249            }
1250
1251            function onTouchEnd(e) {
1252              // finish the touch by undoing the touch session
1253              el.removeEventListener('touchmove', onTouchMove, false);
1254
1255              if (slider.animatingTo === slider.currentSlide && !scrolling && !(dx === null)) {
1256                var updateDx = (reverse) ? -dx : dx,
1257                    target = (updateDx > 0) ? slider.getTarget('next') : slider.getTarget('prev');
1258
1259                if (slider.canAdvance(target) && (Number(new Date()) - startT < 550 && Math.abs(updateDx) > 50 || Math.abs(updateDx) > cwidth/2)) {
1260                  slider.flexAnimate(target, slider.vars.pauseOnAction);
1261                } else {
1262                  if (!fade) { slider.flexAnimate(slider.currentSlide, slider.vars.pauseOnAction, true); }
1263                }
1264              }
1265              el.removeEventListener('touchend', onTouchEnd, false);
1266
1267              startX = null;
1268              startY = null;
1269              dx = null;
1270              offset = null;
1271            }
1272        }else{
1273            el.style.msTouchAction = "none";
1274            el._gesture = new MSGesture();
1275            el._gesture.target = el;
1276            el.addEventListener("MSPointerDown", onMSPointerDown, false);
1277            el._slider = slider;
1278            el.addEventListener("MSGestureChange", onMSGestureChange, false);
1279            el.addEventListener("MSGestureEnd", onMSGestureEnd, false);
1280
1281            function onMSPointerDown(e){
1282                e.stopPropagation();
1283                if (slider.animating) {
1284                    e.preventDefault();
1285                }else{
1286                    slider.pause();
1287                    el._gesture.addPointer(e.pointerId);
1288                    accDx = 0;
1289                    cwidth = (vertical) ? slider.h : slider. w;
1290                    startT = Number(new Date());
1291                    // CAROUSEL:
1292
1293                    offset = (carousel && reverse && slider.animatingTo === slider.last) ? 0 :
1294                        (carousel && reverse) ? slider.limit - (((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo) :
1295                            (carousel && slider.currentSlide === slider.last) ? slider.limit :
1296                                (carousel) ? ((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.currentSlide :
1297                                    (reverse) ? (slider.last - slider.currentSlide + slider.cloneOffset) * cwidth : (slider.currentSlide + slider.cloneOffset) * cwidth;
1298                }
1299            }
1300
1301            function onMSGestureChange(e) {
1302                e.stopPropagation();
1303                var slider = e.target._slider;
1304                if(!slider){
1305                    return;
1306                }
1307                var transX = -e.translationX,
1308                    transY = -e.translationY;
1309
1310                //Accumulate translations.
1311                accDx = accDx + ((vertical) ? transY : transX);
1312                dx = accDx;
1313                scrolling = (vertical) ? (Math.abs(accDx) < Math.abs(-transX)) : (Math.abs(accDx) < Math.abs(-transY));
1314
1315                if(e.detail === e.MSGESTURE_FLAG_INERTIA){
1316                    setImmediate(function (){
1317                        el._gesture.stop();
1318                    });
1319
1320                    return;
1321                }
1322
1323                if (!scrolling || Number(new Date()) - startT > 500) {
1324                    e.preventDefault();
1325                    if (!fade && slider.transitions) {
1326                        if (!slider.vars.animationLoop) {
1327                            dx = accDx / ((slider.currentSlide === 0 && accDx < 0 || slider.currentSlide === slider.last && accDx > 0) ? (Math.abs(accDx) / cwidth + 2) : 1);
1328                        }
1329                        slider.setProps(offset + dx, "setTouch");
1330                    }
1331                }
1332            }
1333
1334            function onMSGestureEnd(e) {
1335                e.stopPropagation();
1336                var slider = e.target._slider;
1337                if(!slider){
1338                    return;
1339                }
1340                if (slider.animatingTo === slider.currentSlide && !scrolling && !(dx === null)) {
1341                    var updateDx = (reverse) ? -dx : dx,
1342                        target = (updateDx > 0) ? slider.getTarget('next') : slider.getTarget('prev');
1343
1344                    if (slider.canAdvance(target) && (Number(new Date()) - startT < 550 && Math.abs(updateDx) > 50 || Math.abs(updateDx) > cwidth/2)) {
1345                        slider.flexAnimate(target, slider.vars.pauseOnAction);
1346                    } else {
1347                        if (!fade) { slider.flexAnimate(slider.currentSlide, slider.vars.pauseOnAction, true); }
1348                    }
1349                }
1350
1351                startX = null;
1352                startY = null;
1353                dx = null;
1354                offset = null;
1355                accDx = 0;
1356            }
1357        }
1358      },
1359      resize: function() {
1360        if (!slider.animating && slider.is(':visible')) {
1361          if (!carousel) { slider.doMath(); }
1362
1363          if (fade) {
1364            // SMOOTH HEIGHT:
1365            methods.smoothHeight();
1366          } else if (carousel) { //CAROUSEL:
1367            slider.slides.width(slider.computedW);
1368            slider.update(slider.pagingCount);
1369            slider.setProps();
1370          }
1371          else if (vertical) { //VERTICAL:
1372            slider.viewport.height(slider.h);
1373            slider.setProps(slider.h, "setTotal");
1374          } else {
1375            // SMOOTH HEIGHT:
1376            if (slider.vars.smoothHeight) { methods.smoothHeight(); }
1377            slider.newSlides.width(slider.computedW);
1378            slider.setProps(slider.computedW, "setTotal");
1379          }
1380        }
1381      },
1382      smoothHeight: function(dur) {
1383        if (!vertical || fade) {
1384          var $obj = (fade) ? slider : slider.viewport;
1385          (dur) ? $obj.animate({"height": slider.slides.eq(slider.animatingTo).height()}, dur) : $obj.height(slider.slides.eq(slider.animatingTo).height());
1386        }
1387      },
1388      sync: function(action) {
1389        var $obj = $(slider.vars.sync).data("flexslider"),
1390            target = slider.animatingTo;
1391
1392        switch (action) {
1393          case "animate": $obj.flexAnimate(target, slider.vars.pauseOnAction, false, true); break;
1394          case "play": if (!$obj.playing && !$obj.asNav) { $obj.play(); } break;
1395          case "pause": $obj.pause(); break;
1396        }
1397      },
1398      uniqueID: function($clone) {
1399        // Append _clone to current level and children elements with id attributes
1400        $clone.filter( '[id]' ).add($clone.find( '[id]' )).each(function() {
1401          var $this = $(this);
1402          $this.attr( 'id', $this.attr( 'id' ) + '_clone' );
1403        });
1404        return $clone;
1405      },
1406      pauseInvisible: {
1407        visProp: null,
1408        init: function() {
1409          var visProp = methods.pauseInvisible.getHiddenProp();
1410          if (visProp) {
1411            var evtname = visProp.replace(/[H|h]idden/,'') + 'visibilitychange';
1412            document.addEventListener(evtname, function() {
1413              if (methods.pauseInvisible.isHidden()) {
1414                if(slider.startTimeout) {
1415                  clearTimeout(slider.startTimeout); //If clock is ticking, stop timer and prevent from starting while invisible
1416                } else { 
1417                  slider.pause(); //Or just pause
1418                }
1419              }
1420              else {
1421                if(slider.started) {
1422                  slider.play(); //Initiated before, just play
1423                } else { 
1424                  if (slider.vars.initDelay > 0) { 
1425                    setTimeout(slider.play, slider.vars.initDelay);
1426                  } else {
1427                    slider.play(); //Didn't init before: simply init or wait for it
1428                  } 
1429                }
1430              }
1431            });
1432          }
1433        },
1434        isHidden: function() {
1435          var prop = methods.pauseInvisible.getHiddenProp();
1436          if (!prop) {
1437            return false;
1438          }
1439          return document[prop];
1440        },
1441        getHiddenProp: function() {
1442          var prefixes = ['webkit','moz','ms','o'];
1443          // if 'hidden' is natively supported just return it
1444          if ('hidden' in document) {
1445            return 'hidden';
1446          }
1447          // otherwise loop over all the known prefixes until we find one
1448          for ( var i = 0; i < prefixes.length; i++ ) {
1449              if ((prefixes[i] + 'Hidden') in document) {
1450                return prefixes[i] + 'Hidden';
1451              }
1452          }
1453          // otherwise it's not supported
1454          return null;
1455        }
1456      },
1457      setToClearWatchedEvent: function() {
1458        clearTimeout(watchedEventClearTimer);
1459        watchedEventClearTimer = setTimeout(function() {
1460          watchedEvent = "";
1461        }, 3000);
1462      }
1463    };
1464
1465    // public methods
1466    slider.flexAnimate = function(target, pause, override, withSync, fromNav) {
1467      if (!slider.vars.animationLoop && target !== slider.currentSlide) {
1468        slider.direction = (target > slider.currentSlide) ? "next" : "prev";
1469      }
1470
1471      if (asNav && slider.pagingCount === 1) slider.direction = (slider.currentItem < target) ? "next" : "prev";
1472
1473      if (!slider.animating && (slider.canAdvance(target, fromNav) || override) && slider.is(":visible")) {
1474        if (asNav && withSync) {
1475          var master = $(slider.vars.asNavFor).data('flexslider');
1476          slider.atEnd = target === 0 || target === slider.count - 1;
1477          master.flexAnimate(target, true, false, true, fromNav);
1478          slider.direction = (slider.currentItem < target) ? "next" : "prev";
1479          master.direction = slider.direction;
1480
1481          if (Math.ceil((target + 1)/slider.visible) - 1 !== slider.currentSlide && target !== 0) {
1482            slider.currentItem = target;
1483            slider.slides.removeClass(namespace + "active-slide").eq(target).addClass(namespace + "active-slide");
1484            target = Math.floor(target/slider.visible);
1485          } else {
1486            slider.currentItem = target;
1487            slider.slides.removeClass(namespace + "active-slide").eq(target).addClass(namespace + "active-slide");
1488            return false;
1489          }
1490        }
1491
1492        slider.animating = true;
1493        slider.animatingTo = target;
1494
1495        // SLIDESHOW:
1496        if (pause) { slider.pause(); }
1497
1498        // API: before() animation Callback
1499        slider.vars.before(slider);
1500
1501        // SYNC:
1502        if (slider.syncExists && !fromNav) { methods.sync("animate"); }
1503
1504        // CONTROLNAV
1505        if (slider.vars.controlNav) { methods.controlNav.active(); }
1506
1507        // !CAROUSEL:
1508        // CANDIDATE: slide active class (for add/remove slide)
1509        if (!carousel) { slider.slides.removeClass(namespace + 'active-slide').eq(target).addClass(namespace + 'active-slide'); }
1510
1511        // INFINITE LOOP:
1512        // CANDIDATE: atEnd
1513        slider.atEnd = target === 0 || target === slider.last;
1514
1515        // DIRECTIONNAV:
1516        if (slider.vars.directionNav) { methods.directionNav.update(); }
1517
1518        if (target === slider.last) {
1519          // API: end() of cycle Callback
1520          slider.vars.end(slider);
1521          // SLIDESHOW && !INFINITE LOOP:
1522          if (!slider.vars.animationLoop) { slider.pause(); }
1523        }
1524
1525        // SLIDE:
1526        if (!fade) {
1527          var dimension = (vertical) ? slider.slides.filter(':first').height() : slider.computedW,
1528              margin, slideString, calcNext;
1529
1530          // INFINITE LOOP / REVERSE:
1531          if (carousel) {
1532            //margin = (slider.vars.itemWidth > slider.w) ? slider.vars.itemMargin * 2 : slider.vars.itemMargin;
1533            margin = slider.vars.itemMargin;
1534            calcNext = ((slider.itemW + margin) * slider.move) * slider.animatingTo;
1535            slideString = (calcNext > slider.limit && slider.visible !== 1) ? slider.limit : calcNext;
1536          } else if (slider.currentSlide === 0 && target === slider.count - 1 && slider.vars.animationLoop && slider.direction !== "next") {
1537            slideString = (reverse) ? (slider.count + slider.cloneOffset) * dimension : 0;
1538          } else if (slider.currentSlide === slider.last && target === 0 && slider.vars.animationLoop && slider.direction !== "prev") {
1539            slideString = (reverse) ? 0 : (slider.count + 1) * dimension;
1540          } else {
1541            slideString = (reverse) ? ((slider.count - 1) - target + slider.cloneOffset) * dimension : (target + slider.cloneOffset) * dimension;
1542          }
1543          slider.setProps(slideString, "", slider.vars.animationSpeed);
1544          if (slider.transitions) {
1545            if (!slider.vars.animationLoop || !slider.atEnd) {
1546              slider.animating = false;
1547              slider.currentSlide = slider.animatingTo;
1548            }
1549            
1550            // Unbind previous transitionEnd events and re-bind new transitionEnd event
1551            slider.container.unbind("webkitTransitionEnd transitionend");
1552            slider.container.bind("webkitTransitionEnd transitionend", function() {
1553              clearTimeout(slider.ensureAnimationEnd);
1554              slider.wrapup(dimension);
1555            });
1556
1557            // Insurance for the ever-so-fickle transitionEnd event
1558            clearTimeout(slider.ensureAnimationEnd);
1559            slider.ensureAnimationEnd = setTimeout(function() {
1560              slider.wrapup(dimension);
1561            }, slider.vars.animationSpeed + 100);
1562
1563          } else {
1564            slider.container.animate(slider.args, slider.vars.animationSpeed, slider.vars.easing, function(){
1565              slider.wrapup(dimension);
1566            });
1567          }
1568        } else { // FADE:
1569          if (!touch) {
1570            //slider.slides.eq(slider.currentSlide).fadeOut(slider.vars.animationSpeed, slider.vars.easing);
1571            //slider.slides.eq(target).fadeIn(slider.vars.animationSpeed, slider.vars.easing, slider.wrapup);
1572
1573            slider.slides.eq(slider.currentSlide).css({"zIndex": 1}).animate({"opacity": 0}, slider.vars.animationSpeed, slider.vars.easing);
1574            slider.slides.eq(target).css({"zIndex": 2}).animate({"opacity": 1}, slider.vars.animationSpeed, slider.vars.easing, slider.wrapup);
1575
1576          } else {
1577            slider.slides.eq(slider.currentSlide).css({ "opacity": 0, "zIndex": 1 });
1578            slider.slides.eq(target).css({ "opacity": 1, "zIndex": 2 });
1579            slider.wrapup(dimension);
1580          }
1581        }
1582        // SMOOTH HEIGHT:
1583        if (slider.vars.smoothHeight) { methods.smoothHeight(slider.vars.animationSpeed); }
1584      }
1585    };
1586    slider.wrapup = function(dimension) {
1587      // SLIDE:
1588      if (!fade && !carousel) {
1589        if (slider.currentSlide === 0 && slider.animatingTo === slider.last && slider.vars.animationLoop) {
1590          slider.setProps(dimension, "jumpEnd");
1591        } else if (slider.currentSlide === slider.last && slider.animatingTo === 0 && slider.vars.animationLoop) {
1592          slider.setProps(dimension, "jumpStart");
1593        }
1594      }
1595      slider.animating = false;
1596      slider.currentSlide = slider.animatingTo;
1597      // API: after() animation Callback
1598      slider.vars.after(slider);
1599    };
1600
1601    // SLIDESHOW:
1602    slider.animateSlides = function() {
1603      if (!slider.animating && focused ) { slider.flexAnimate(slider.getTarget("next")); }
1604    };
1605    // SLIDESHOW:
1606    slider.pause = function() {
1607      clearInterval(slider.animatedSlides);
1608      slider.animatedSlides = null;
1609      slider.playing = false;
1610      // PAUSEPLAY:
1611      if (slider.vars.pausePlay) { methods.pausePlay.update("play"); }
1612      // SYNC:
1613      if (slider.syncExists) { methods.sync("pause"); }
1614    };
1615    // SLIDESHOW:
1616    slider.play = function() {
1617      if (slider.playing) { clearInterval(slider.animatedSlides); }
1618      slider.animatedSlides = slider.animatedSlides || setInterval(slider.animateSlides, slider.vars.slideshowSpeed);
1619      slider.started = slider.playing = true;
1620      // PAUSEPLAY:
1621      if (slider.vars.pausePlay) { methods.pausePlay.update("pause"); }
1622      // SYNC:
1623      if (slider.syncExists) { methods.sync("play"); }
1624    };
1625    // STOP:
1626    slider.stop = function () {
1627      slider.pause();
1628      slider.stopped = true;
1629    };
1630    slider.canAdvance = function(target, fromNav) {
1631      // ASNAV:
1632      var last = (asNav) ? slider.pagingCount - 1 : slider.last;
1633      return (fromNav) ? true :
1634             (asNav && slider.currentItem === slider.count - 1 && target === 0 && slider.direction === "prev") ? true :
1635             (asNav && slider.currentItem === 0 && target === slider.pagingCount - 1 && slider.direction !== "next") ? false :
1636             (target === slider.currentSlide && !asNav) ? false :
1637             (slider.vars.animationLoop) ? true :
1638             (slider.atEnd && slider.currentSlide === 0 && target === last && slider.direction !== "next") ? false :
1639             (slider.atEnd && slider.currentSlide === last && target === 0 && slider.direction === "next") ? false :
1640             true;
1641    };
1642    slider.getTarget = function(dir) {
1643      slider.direction = dir;
1644      if (dir === "next") {
1645        return (slider.currentSlide === slider.last) ? 0 : slider.currentSlide + 1;
1646      } else {
1647        return (slider.currentSlide === 0) ? slider.last : slider.currentSlide - 1;
1648      }
1649    };
1650
1651    // SLIDE:
1652    slider.setProps = function(pos, special, dur) {
1653      var target = (function() {
1654        var posCheck = (pos) ? pos : ((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo,
1655            posCalc = (function() {
1656              if (carousel) {
1657                return (special === "setTouch") ? pos :
1658                       (reverse && slider.animatingTo === slider.last) ? 0 :
1659                       (reverse) ? slider.limit - (((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo) :
1660                       (slider.animatingTo === slider.last) ? slider.limit : posCheck;
1661              } else {
1662                switch (special) {
1663                  case "setTotal": return (reverse) ? ((slider.count - 1) - slider.currentSlide + slider.cloneOffset) * pos : (slider.currentSlide + slider.cloneOffset) * pos;
1664                  case "setTouch": return (reverse) ? pos : pos;
1665                  case "jumpEnd": return (reverse) ? pos : slider.count * pos;
1666                  case "jumpStart": return (reverse) ? slider.count * pos : pos;
1667                  default: return pos;
1668                }
1669              }
1670            }());
1671
1672            return (posCalc * -1) + "px";
1673          }());
1674
1675      if (slider.transitions) {
1676        target = (vertical) ? "translate3d(0," + target + ",0)" : "translate3d(" + target + ",0,0)";
1677        dur = (dur !== undefined) ? (dur/1000) + "s" : "0s";
1678        slider.container.css("-" + slider.pfx + "-transition-duration", dur);
1679         slider.container.css("transition-duration", dur);
1680      }
1681
1682      slider.args[slider.prop] = target;
1683      if (slider.transitions || dur === undefined) { slider.container.css(slider.args); }
1684
1685      slider.container.css('transform',target);
1686    };
1687
1688    slider.setup = function(type) {
1689      // SLIDE:
1690      if (!fade) {
1691        var sliderOffset, arr;
1692
1693        if (type === "init") {
1694          slider.viewport = $('<div class="' + namespace + 'viewport"></div>').css({"overflow": "hidden", "position": "relative"}).appendTo(slider).append(slider.container);
1695          // INFINITE LOOP:
1696          slider.cloneCount = 0;
1697          slider.cloneOffset = 0;
1698          // REVERSE:
1699          if (reverse) {
1700            arr = $.makeArray(slider.slides).reverse();
1701            slider.slides = $(arr);
1702            slider.container.empty().append(slider.slides);
1703          }
1704        }
1705        // INFINITE LOOP && !CAROUSEL:
1706        if (slider.vars.animationLoop && !carousel) {
1707          slider.cloneCount = 2;
1708          slider.cloneOffset = 1;
1709          // clear out old clones
1710          if (type !== "init") { slider.container.find('.clone').remove(); }
1711          slider.container.append(methods.uniqueID(slider.slides.first().clone().addClass('clone')).attr('aria-hidden', 'true'))
1712                          .prepend(methods.uniqueID(slider.slides.last().clone().addClass('clone')).attr('aria-hidden', 'true'));
1713        }
1714        slider.newSlides = $(slider.vars.selector, slider);
1715
1716        sliderOffset = (reverse) ? slider.count - 1 - slider.currentSlide + slider.cloneOffset : slider.currentSlide + slider.cloneOffset;
1717        // VERTICAL:
1718        if (vertical && !carousel) {
1719          slider.container.height((slider.count + slider.cloneCount) * 200 + "%").css("position", "absolute").width("100%");
1720          setTimeout(function(){
1721            slider.newSlides.css({"display": "block"});
1722            slider.doMath();
1723            slider.viewport.height(slider.h);
1724            slider.setProps(sliderOffset * slider.h, "init");
1725          }, (type === "init") ? 100 : 0);
1726        } else {
1727          slider.container.width((slider.count + slider.cloneCount) * 200 + "%");
1728          slider.setProps(sliderOffset * slider.computedW, "init");
1729          setTimeout(function(){
1730            slider.doMath();
1731            slider.newSlides.css({"width": slider.computedW, "float": "left", "display": "block"});
1732            // SMOOTH HEIGHT:
1733            if (slider.vars.smoothHeight) { methods.smoothHeight(); }
1734          }, (type === "init") ? 100 : 0);
1735        }
1736      } else { // FADE:
1737        slider.slides.css({"width": "100%", "float": "left", "marginRight": "-100%", "position": "relative"});
1738        if (type === "init") {
1739          if (!touch) {
1740            //slider.slides.eq(slider.currentSlide).fadeIn(slider.vars.animationSpeed, slider.vars.easing);
1741            if (slider.vars.fadeFirstSlide == false) {
1742              slider.slides.css({ "opacity": 0, "display": "block", "zIndex": 1 }).eq(slider.currentSlide).css({"zIndex": 2}).css({"opacity": 1});
1743            } else {
1744              slider.slides.css({ "opacity": 0, "display": "block", "zIndex": 1 }).eq(slider.currentSlide).css({"zIndex": 2}).animate({"opacity": 1},slider.vars.animationSpeed,slider.vars.easing);
1745            }
1746          } else {
1747            slider.slides.css({ "opacity": 0, "display": "block", "webkitTransition": "opacity " + slider.vars.animationSpeed / 1000 + "s ease", "zIndex": 1 }).eq(slider.currentSlide).css({ "opacity": 1, "zIndex": 2});
1748          }
1749        }
1750        // SMOOTH HEIGHT:
1751        if (slider.vars.smoothHeight) { methods.smoothHeight(); }
1752      }
1753      // !CAROUSEL:
1754      // CANDIDATE: active slide
1755      if (!carousel) { slider.slides.removeClass(namespace + "active-slide").eq(slider.currentSlide).addClass(namespace + "active-slide"); }
1756
1757      //FlexSlider: init() Callback
1758      slider.vars.init(slider);
1759    };
1760
1761    slider.doMath = function() {
1762      var slide = slider.slides.first(),
1763          slideMargin = slider.vars.itemMargin,
1764          minItems = slider.vars.minItems,
1765          maxItems = slider.vars.maxItems;
1766
1767      slider.w = (slider.viewport===undefined) ? slider.width() : slider.viewport.width();
1768      slider.h = slide.height();
1769      slider.boxPadding = slide.outerWidth() - slide.width();
1770
1771      // CAROUSEL:
1772      if (carousel) {
1773        slider.itemT = slider.vars.itemWidth + slideMargin;
1774        slider.minW = (minItems) ? minItems * slider.itemT : slider.w;
1775        slider.maxW = (maxItems) ? (maxItems * slider.itemT) - slideMargin : slider.w;
1776        slider.itemW = (slider.minW > slider.w) ? (slider.w - (slideMargin * (minItems - 1)))/minItems :
1777                       (slider.maxW < slider.w) ? (slider.w - (slideMargin * (maxItems - 1)))/maxItems :
1778                       (slider.vars.itemWidth > slider.w) ? slider.w : slider.vars.itemWidth;
1779
1780        slider.visible = Math.floor(slider.w/(slider.itemW));
1781        slider.move = (slider.vars.move > 0 && slider.vars.move < slider.visible ) ? slider.vars.move : slider.visible;
1782        slider.pagingCount = Math.ceil(((slider.count - slider.visible)/slider.move) + 1);
1783        slider.last =  slider.pagingCount - 1;
1784        slider.limit = (slider.pagingCount === 1) ? 0 :
1785                       (slider.vars.itemWidth > slider.w) ? (slider.itemW * (slider.count - 1)) + (slideMargin * (slider.count - 1)) : ((slider.itemW + slideMargin) * slider.count) - slider.w - slideMargin;
1786      } else {
1787        slider.itemW = slider.w;
1788        slider.pagingCount = slider.count;
1789        slider.last = slider.count - 1;
1790      }
1791      slider.computedW = slider.itemW - slider.boxPadding;
1792    };
1793
1794    slider.update = function(pos, action) {
1795      slider.doMath();
1796
1797      // update currentSlide and slider.animatingTo if necessary
1798      if (!carousel) {
1799        if (pos < slider.currentSlide) {
1800          slider.currentSlide += 1;
1801        } else if (pos <= slider.currentSlide && pos !== 0) {
1802          slider.currentSlide -= 1;
1803        }
1804        slider.animatingTo = slider.currentSlide;
1805      }
1806
1807      // update controlNav
1808      if (slider.vars.controlNav && !slider.manualControls) {
1809        if ((action === "add" && !carousel) || slider.pagingCount > slider.controlNav.length) {
1810          methods.controlNav.update("add");
1811        } else if ((action === "remove" && !carousel) || slider.pagingCount < slider.controlNav.length) {
1812          if (carousel && slider.currentSlide > slider.last) {
1813            slider.currentSlide -= 1;
1814            slider.animatingTo -= 1;
1815          }
1816          methods.controlNav.update("remove", slider.last);
1817        }
1818      }
1819      // update directionNav
1820      if (slider.vars.directionNav) { methods.directionNav.update(); }
1821
1822    };
1823
1824    slider.addSlide = function(obj, pos) {
1825      var $obj = $(obj);
1826
1827      slider.count += 1;
1828      slider.last = slider.count - 1;
1829
1830      // append new slide
1831      if (vertical && reverse) {
1832        (pos !== undefined) ? slider.slides.eq(slider.count - pos).after($obj) : slider.container.prepend($obj);
1833      } else {
1834        (pos !== undefined) ? slider.slides.eq(pos).before($obj) : slider.container.append($obj);
1835      }
1836
1837      // update currentSlide, animatingTo, controlNav, and directionNav
1838      slider.update(pos, "add");
1839
1840      // update slider.slides
1841      slider.slides = $(slider.vars.selector + ':not(.clone)', slider);
1842      // re-setup the slider to accomdate new slide
1843      slider.setup();
1844
1845      //FlexSlider: added() Callback
1846      slider.vars.added(slider);
1847    };
1848    slider.removeSlide = function(obj) {
1849      var pos = (isNaN(obj)) ? slider.slides.index($(obj)) : obj;
1850
1851      // update count
1852      slider.count -= 1;
1853      slider.last = slider.count - 1;
1854
1855      // remove slide
1856      if (isNaN(obj)) {
1857        $(obj, slider.slides).remove();
1858      } else {
1859        (vertical && reverse) ? slider.slides.eq(slider.last).remove() : slider.slides.eq(obj).remove();
1860      }
1861
1862      // update currentSlide, animatingTo, controlNav, and directionNav
1863      slider.doMath();
1864      slider.update(pos, "remove");
1865
1866      // update slider.slides
1867      slider.slides = $(slider.vars.selector + ':not(.clone)', slider);
1868      // re-setup the slider to accomdate new slide
1869      slider.setup();
1870
1871      // FlexSlider: removed() Callback
1872      slider.vars.removed(slider);
1873    };
1874
1875    //FlexSlider: Initialize
1876    methods.init();
1877  };
1878
1879  // Ensure the slider isn't focussed if the window loses focus.
1880  $( window ).blur( function ( e ) {
1881    focused = false;
1882  }).focus( function ( e ) {
1883    focused = true;
1884  });
1885
1886  //FlexSlider: Default Settings
1887  $.flexslider.defaults = {
1888    namespace: "flex-",             //{NEW} String: Prefix string attached to the class of every element generated by the plugin
1889    selector: ".slides > li",       //{NEW} Selector: Must match a simple pattern. '{container} > {slide}' -- Ignore pattern at your own peril
1890    animation: "fade",              //String: Select your animation type, "fade" or "slide"
1891    easing: "swing",                //{NEW} String: Determines the easing method used in jQuery transitions. jQuery easing plugin is supported!
1892    direction: "horizontal",        //String: Select the sliding direction, "horizontal" or "vertical"
1893    reverse: false,                 //{NEW} Boolean: Reverse the animation direction
1894    animationLoop: true,            //Boolean: Should the animation loop? If false, directionNav will received "disable" classes at either end
1895    smoothHeight: false,            //{NEW} Boolean: Allow height of the slider to animate smoothly in horizontal mode
1896    startAt: 0,                     //Integer: The slide that the slider should start on. Array notation (0 = first slide)
1897    slideshow: true,                //Boolean: Animate slider automatically
1898    slideshowSpeed: 7000,           //Integer: Set the speed of the slideshow cycling, in milliseconds
1899    animationSpeed: 600,            //Integer: Set the speed of animations, in milliseconds
1900    initDelay: 0,                   //{NEW} Integer: Set an initialization delay, in milliseconds
1901    randomize: false,               //Boolean: Randomize slide order
1902    fadeFirstSlide: true,           //Boolean: Fade in the first slide when animation type is "fade"
1903    thumbCaptions: false,           //Boolean: Whether or not to put captions on thumbnails when using the "thumbnails" controlNav.
1904
1905    // Usability features
1906    pauseOnAction: true,            //Boolean: Pause the slideshow when interacting with control elements, highly recommended.
1907    pauseOnHover: false,            //Boolean: Pause the slideshow when hovering over slider, then resume when no longer hovering
1908    pauseInvisible: true,   		//{NEW} Boolean: Pause the slideshow when tab is invisible, resume when visible. Provides better UX, lower CPU usage.
1909    useCSS: true,                   //{NEW} Boolean: Slider will use CSS3 transitions if available
1910    touch: true,                    //{NEW} Boolean: Allow touch swipe navigation of the slider on touch-enabled devices
1911    video: false,                   //{NEW} Boolean: If using video in the slider, will prevent CSS3 3D Transforms to avoid graphical glitches
1912
1913    // Primary Controls
1914    controlNav: true,               //Boolean: Create navigation for paging control of each slide? Note: Leave true for manualControls usage
1915    directionNav: true,             //Boolean: Create navigation for previous/next navigation? (true/false)
1916    prevText: "Previous",           //String: Set the text for the "previous" directionNav item
1917    nextText: "Next",               //String: Set the text for the "next" directionNav item
1918
1919    // Secondary Navigation
1920    keyboard: true,                 //Boolean: Allow slider navigating via keyboard left/right keys
1921    multipleKeyboard: false,        //{NEW} Boolean: Allow keyboard navigation to affect multiple sliders. Default behavior cuts out keyboard navigation with more than one slider present.
1922    mousewheel: false,              //{UPDATED} Boolean: Requires jquery.mousewheel.js (https://github.com/brandonaaron/jquery-mousewheel) - Allows slider navigating via mousewheel
1923    pausePlay: false,               //Boolean: Create pause/play dynamic element
1924    pauseText: "Pause",             //String: Set the text for the "pause" pausePlay item
1925    playText: "Play",               //String: Set the text for the "play" pausePlay item
1926
1927    // Special properties
1928    controlsContainer: "",          //{UPDATED} jQuery Object/Selector: Declare which container the navigation elements should be appended too. Default container is the FlexSlider element. Example use would be $(".flexslider-container"). Property is ignored if given element is not found.
1929    manualControls: "",             //{UPDATED} jQuery Object/Selector: Declare custom control navigation. Examples would be $(".flex-control-nav li") or "#tabs-nav li img", etc. The number of elements in your controlNav should match the number of slides/tabs.
1930    sync: "",                       //{NEW} Selector: Mirror the actions performed on this slider with another slider. Use with care.
1931    asNavFor: "",                   //{NEW} Selector: Internal property exposed for turning the slider into a thumbnail navigation for another slider
1932
1933    // Carousel Options
1934    itemWidth: 0,                   //{NEW} Integer: Box-model width of individual carousel items, including horizontal borders and padding.
1935    itemMargin: 0,                  //{NEW} Integer: Margin between carousel items.
1936    minItems: 1,                    //{NEW} Integer: Minimum number of carousel items that should be visible. Items will resize fluidly when below this.
1937    maxItems: 0,                    //{NEW} Integer: Maxmimum number of carousel items that should be visible. Items will resize fluidly when above this limit.
1938    move: 0,                        //{NEW} Integer: Number of carousel items that should move on animation. If 0, slider will move all visible items.
1939    allowOneSlide: true,           //{NEW} Boolean: Whether or not to allow a slider comprised of a single slide
1940
1941    // Callback API
1942    start: function(){},            //Callback: function(slider) - Fires when the slider loads the first slide
1943    before: function(){},           //Callback: function(slider) - Fires asynchronously with each slider animation
1944    after: function(){},            //Callback: function(slider) - Fires after each slider animation completes
1945    end: function(){},              //Callback: function(slider) - Fires when the slider reaches the last slide (asynchronous)
1946    added: function(){},            //{NEW} Callback: function(slider) - Fires after a slide is added
1947    removed: function(){},           //{NEW} Callback: function(slider) - Fires after a slide is removed
1948    init: function() {}             //{NEW}
1948 Callback: function(slider) - Fires after the slider is initially setup
1949  };
1950
1951  //FlexSlider: Plugin Function
1952  $.fn.flexslider = function(options) {
1953    if (options === undefined) { options = {}; }
1954
1955    if (typeof options === "object") {
1956      return this.each(function() {
1957        var $this = $(this),
1958            selector = (options.selector) ? options.selector : ".slides > li",
1959            $slides = $this.find(selector);
1960
1961      if ( ( $slides.length === 1 && options.allowOneSlide === true ) || $slides.length === 0 ) {
1962          $slides.fadeIn(400);
1963          if (options.start) { options.start($this); }
1964        } else if ($this.data('flexslider') === undefined) {
1965          new $.flexslider(this, options);
1966        }
1967      });
1968    } else {
1969      // Helper strings to quickly perform functions on the slider
1970      var $slider = $(this).data('flexslider');
1971      switch (options) {
1972        case "play": $slider.play(); break;
1973        case "pause": $slider.pause(); break;
1974        case "stop": $slider.stop(); break;
1975        case "next": $slider.flexAnimate($slider.getTarget("next"), true); break;
1976        case "prev":
1977        case "previous": $slider.flexAnimate($slider.getTarget("prev"), true); break;
1978        default: if (typeof options === "number") { $slider.flexAnimate(options, true); }
1979      }
1980    }
1981  };
1982})(jQuery);
1983;
1984/*
1985	By Osvaldas Valutis, www.osvaldas.info
1986	Available for use under the MIT License
1987*/
1988
1989
1990
1991;(function( $, window, document, undefined )
1992{
1993	$.fn.doubleTapToGo = function( params )
1994	{
1995		if( !( 'ontouchstart' in window ) &&
1996			!navigator.msMaxTouchPoints &&
1997			!navigator.userAgent.toLowerCase().match( /windows phone os 7/i ) ) return false;
1998
1999		this.each( function()
2000		{
2001			var curItem = false;
2002
2003			$( this ).on( 'click', function( e )
2004			{
2005				var item = $( this );
2006				if( item[ 0 ] != curItem[ 0 ] )
2007				{
2008					e.preventDefault();
2009					curItem = item;
2010				}
2011			});
2012
2013			$( document ).on( 'click touchstart MSPointerDown', function( e )
2014			{
2015				var resetItem = true,
2016					parents	= $( e.target ).parents();
2017
2018				for( var i = 0; i < parents.length; i++ )
2019					if( parents[ i ] == curItem[ 0 ] )
2020						resetItem = false;
2021
2022				if( resetItem )
2023					curItem = false;
2024			});
2025		});
2026		return this;
2027	};
2028})( jQuery, window, document );;
2029/**
2030 * global.js
2031 *
2032 * Handles various UI actions
2033 * - Mobile menu
2034 * - Search form show/hide
2035 * - Touch device dropdowns (requires: doubletaptogo.js)
2036 * - Flexslider (requires: flexslider.js)
2037 * - Scroll to top
2038 * - Smooth page load
2039 *
2040 * @package Rowling
2041 */
2042( function( $ ) {
2043
2044/**
2045 * On ready
2046 */
2047	$( document ).ready( function() {
2048		var windowWidth = $( window ).width();
2049
2050
2051		// Toggle mobile menu
2052		$( ".nav-toggle" ).on( "click", function() {
2053			$( this ).toggleClass( "active" );
2054			$( ".header-bottom-menu" ).slideToggle();
2055			if ( $( ".search-toggle" ).hasClass( "active" ) ) {
2056				$( ".search-toggle" ).removeClass( "active" );
2057				$( ".search-container" ).slideToggle();
2058			}
2059			return false;
2060		});
2061
2062
2063		// Toggle search container
2064		$( ".search-toggle" ).on( "click", function() {
2065			$( this ).toggleClass( "active" );
2066			$( ".search-container" ).slideToggle();
2067			if ( $( ".nav-toggle" ).hasClass( "active" ) ) {
2068				$( ".nav-toggle" ).removeClass( "active" );
2069				$( ".header-bottom-menu" ).slideToggle();
2070			}
2071			return false;
2072		});
2073
2074		$( window ).resize( function() {
2075
2076			// Prevent the Android keyboard from triggering the following code
2077			if ( windowWidth !== $( window ).width() ) {
2078
2079				// Hide mobile menu/search container at resize
2080				if ( $(window).width() >= 851 ) {
2081					$( ".nav-toggle" ).removeClass( "active" );
2082					$( ".header-bottom-menu" ).show();
2083				}
2084
2085				if ( $(window).width() <= 850 ) {
2086					$( ".search-toggle" ).removeClass( "active" );
2087					$( ".search-container" ).hide();
2088				}
2089
2090				// Dropdown menus on touch devices, excluding mobile menu
2091				if ( $(window).width() <= 851 ) {
2092					$( ".header-bottom-menu li:has(ul)" ).doubleTapToGo();
2093					$( ".header-top-menu li:has(ul)" ).doubleTapToGo();
2094				}
2095
2096				if ( $(window).width() >= 850 ) {
2097					$( ".header-bottom-menu li:has(ul)" ).unbind();
2098					$( ".header-top-menu li:has(ul)" ).unbind();
2099				}
2100			}
2101
2102			windowWidth = $( window ).width();
2103
2104		}).resize();
2105
2106		// Load Flexslider
2107		$( ".flexslider" ).flexslider( {
2108			animation: "slide",
2109			controlNav: false,
2110			prevText: "",
2111			nextText: "",
2112			smoothHeight: true
2113		});
2114
2115		// smooth scroll to the top
2116		$( ".to-the-top" ).click( function() {
2117			$( "html, body" ).animate( { scrollTop: 0 }, 500 );
2118				return false;
2119		});
2120
2121	});
2122
2123
2124	/**
2125	 * On load
2126	 */
2127	$( document.body ).on( 'post-load', function () {
2128
2129		// Load Flexslider after new posts have been added to the page.
2130		$( ".flexslider" ).flexslider( {
2131			animation: "slide",
2132			controlNav: false,
2133			prevText: "",
2134			nextText: "",
2135			smoothHeight: true
2136		});
2137
2138	});
2139
2140} ) ( jQuery );
2141;
2142/*! This file is auto-generated */
2143window.addComment=function(v){var I,C,h,E=v.document,b={commentReplyClass:"comment-reply-link",commentReplyTitleId:"reply-title",cancelReplyId:"cancel-comment-reply-link",commentFormId:"commentform",temporaryFormId:"wp-temp-form-div",parentIdFieldId:"comment_parent",postIdFieldId:"comment_post_ID"},e=v.MutationObserver||v.WebKitMutationObserver||v.MozMutationObserver,r="querySelector"in E&&"addEventListener"in v,n=!!E.documentElement.dataset;function t(){d(),e&&new e(o).observe(E.body,{childList:!0,subtree:!0})}function d(e){if(r&&(I=g(b.cancelReplyId),C=g(b.commentFormId),I)){I.addEventListener("touchstart",l),I.addEventListener("click",l);function t(e){if((e.metaKey||e.ctrlKey)&&13===e.keyCode&&"a"!==E.activeElement.tagName.toLowerCase())return C.removeEventListener("keydown",t),e.preventDefault(),C.submit.click(),!1}C&&C.addEventListener("keydown",t);for(var n,d=function(e){var t=b.commentReplyClass;e&&e.childNodes||(e=E);e=E.getElementsByClassName?e.getElementsByClassName(t):e.querySelectorAll("."+t);return e}(e),o=0,i=d.length;o<i;o++)(n=d[o]).addEventListener("touchstart",a),n.addEventListener("click",a)}}function l(e){var t,n,d=g(b.temporaryFormId);d&&h&&(g(b.parentIdFieldId).value="0",t=d.textContent,d.parentNode.replaceChild(h,d),this.style.display="none",n=(d=(d=g(b.commentReplyTitleId))&&d.firstChild)&&d.nextSibling,d&&d.nodeType===Node.TEXT_NODE&&t&&(n&&"A"===n.nodeName&&n.id!==b.cancelReplyId&&(n.style.display=""),d.textContent=t),e.preventDefault())}function a(e){var t=g(b.commentReplyTitleId),t=t&&t.firstChild.textContent,n=this,d=m(n,"belowelement"),o=m(n,"commentid"),i=m(n,"respondelement"),r=m(n,"postid"),n=m(n,"replyto")||t;d&&o&&i&&r&&!1===v.addComment.moveForm(d,o,i,r,n)&&e.preventDefault()}function o(e){for(var t=e.length;t--;)if(e[t].addedNodes.length)return void d()}function m(e,t){return n?e.dataset[t]:e.getAttribute("data-"+t)}function g(e){return E.getElementById(e)}return r&&"loading"!==E.readyState?t():r&&v.addEventListener("DOMContentLoaded",t,!1),{init:d,moveForm:function(e,t,n,d,o){var i,r,l,a,m,c,s,e=g(e),n=(h=g(n),g(b.parentIdFieldId)),y=g(b.postIdFieldId),p=g(b.commentReplyTitleId),u=(p=p&&p.firstChild)&&p.nextSibling;if(e&&h&&n){void 0===o&&(o=p&&p.textContent),a=h,m=b.temporaryFormId,c=g(m),s=(s=g(b.commentReplyTitleId))?s.firstChild.textContent:"",c||((c=E.createElement("div")).id=m,c.style.display="none",c.textContent=s,a.parentNode.insertBefore(c,a)),d&&y&&(y.value=d),n.value=t,I.style.display="",e.parentNode.insertBefore(h,e.nextSibling),p&&p.nodeType===Node.TEXT_NODE&&(u&&"A"===u.nodeName&&u.id!==b.cancelReplyId&&(u.style.display="none"),p.textContent=o),I.onclick=function(){return!1};try{for(var f=0;f<C.elements.length;f++)if(i=C.elements[f],r=!1,"getComputedStyle"in v?l=v.getComputedStyle(i):E.documentElement.currentStyle&&(l=i.currentStyle),(i.offsetWidth<=0&&i.offsetHeight<=0||"hidden"===l.visibility)&&(r=!0),"hidden"!==i.type&&!i.disabled&&!r){i.focus();break}}catch(e){}return!1}}}}(window);;
2144!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.JetpackScriptDataModule=t():e.JetpackScriptDataModule=t()}(globalThis,()=>(()=>{"use strict";var e={729(e,t,r){r.d(t,{$8:()=>n.$8,IT:()=>n.IT,KS:()=>n.KS,L2:()=>n.L2,Sy:()=>n.Sy,au:()=>n.au,d_:()=>n.d_,e5:()=>n.e5,hT:()=>n.hT,lI:()=>n.lI,mH:()=>n.mH,oQ:()=>n.oQ,sV:()=>n.sV});var n=r(336)},336(e,t,r){function n(){return window.JetpackScriptData}function o(){return n()?.site}function i(e=""){return`${n()?.site.admin_url}${e}`}function a(e=""){return i(`admin.php?page=jetpack${e}`)}function u(e=""){return i(`admin.php?page=my-jetpack${e}`)}function p(){return n()?.site.plan?.features?.active??[]}function c(e){return-1!==p().indexOf(e)}function s(){return"wpcom"===n()?.site?.host}function f(){return"woa"===n()?.site?.host}function d(){return n()?.site?.is_wpcom_platform}function l(){return"unknown"===n()?.site?.host}function S(){return s()?"simple":f()?"woa":"jetpack"}function m(e){return n()?.user.current_user.capabilities[e]}r.d(t,{$8:()=>d,IT:()=>c,KS:()=>S,L2:()=>l,Sy:()=>s,au:()=>n,d_:()=>m,e5:()=>u,hT:()=>i,lI:()=>f,mH:()=>p,oQ:()=>a,sV:()=>o})}},t={};function r(n){var o=t[n];if(void 0!==o)return o.exports;var i=t[n]={exports:{}};return e[n](i,i.exports,r),i.exports}r.d=(e,t)=>{for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}
2144),Object.defineProperty(e,"__esModule",{value:!0})};var n={};r.r(n),r.d(n,{currentUserCan:()=>o.d_,getActiveFeatures:()=>o.mH,getAdminUrl:()=>o.hT,getJetpackAdminPageUrl:()=>o.oQ,getMyJetpackUrl:()=>o.e5,getScriptData:()=>o.au,getSiteData:()=>o.sV,getSiteType:()=>o.KS,isJetpackSelfHostedSite:()=>o.L2,isSimpleSite:()=>o.Sy,isWoASite:()=>o.lI,isWpcomPlatformSite:()=>o.$8,siteHasFeature:()=>o.IT});var o=r(729);return n})());;
2145/**
2146 * Observe how the user enters content into the comment form in order to determine whether it's a bot or not.
2147 *
2148 * Note that no actual input is being saved here, only counts and timings between events.
2149 */
2150
2151( function() {
2152	// Passive event listeners are guaranteed to never call e.preventDefault(),
2153	// but they're not supported in all browsers.  Use this feature detection
2154	// to determine whether they're available for use.
2155	var supportsPassive = false;
2156
2157	try {
2158		var opts = Object.defineProperty( {}, 'passive', {
2159			get : function() {
2160				supportsPassive = true;
2161			}
2162		} );
2163
2164		window.addEventListener( 'testPassive', null, opts );
2165		window.removeEventListener( 'testPassive', null, opts );
2166	} catch ( e ) {}
2167
2168	function init() {
2169		var input_begin = '';
2170
2171		var keydowns = {};
2172		var lastKeyup = null;
2173		var lastKeydown = null;
2174		var keypresses = [];
2175
2176		var modifierKeys = [];
2177		var correctionKeys = [];
2178
2179		var lastMouseup = null;
2180		var lastMousedown = null;
2181		var mouseclicks = [];
2182		var mouseclickCoordinates = [];
2183
2184		var mousemoveTimer = null;
2185		var lastMousemoveX = null;
2186		var lastMousemoveY = null;
2187		var lastMousemoveTime = null;
2188		var mousemoveStart = null;
2189		var mousemoves = [];
2190		var intervalsBetweenMousemovesAndClicks = [];
2191
2192		var touchmoveCountTimer = null;
2193		var touchmoveCount = 0;
2194
2195		var lastTouchEnd = null;
2196		var lastTouchStart = null;
2197		var touchEvents = [];
2198
2199		var scrollCountTimer = null;
2200		var scrollCount = 0;
2201
2202		var correctionKeyCodes = [ 'Backspace', 'Delete', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End', 'PageUp', 'PageDown' ];
2203		var modifierKeyCodes = [ 'Shift', 'CapsLock' ];
2204
2205		var forms = document.querySelectorAll( 'form[method=post]' );
2206
2207		for ( var i = 0; i < forms.length; i++ ) {
2208			var form = forms[i];
2209
2210			var formAction = form.getAttribute( 'action' );
2211
2212			// Ignore forms that POST directly to other domains; these could be things like payment forms.
2213			if ( formAction ) {
2214				// Check that the form is posting to an external URL, not a path.
2215				if ( formAction.indexOf( 'http://' ) == 0 || formAction.indexOf( 'https://' ) == 0 ) {
2216					if ( formAction.indexOf( 'http://' + window.location.hostname + '/' ) != 0 && formAction.indexOf( 'https://' + window.location.hostname + '/' ) != 0 ) {
2217						continue;
2218					}
2219				}
2220			}
2221
2222			form.addEventListener( 'submit', function () {
2223				var ak_bkp = prepare_array_for_request( keypresses );
2224				var ak_bmc = prepare_array_for_request( mouseclicks );
2225				var ak_bte = prepare_array_for_request( touchEvents );
2226				var ak_bmm = prepare_array_for_request( mousemoves );
2227				var ak_bcc = prepare_array_for_request( mouseclickCoordinates );
2228				var ak_bibmac = intervalsBetweenMousemovesAndClicks.slice( 0, 100 ).join( ';' );
2229
2230				var input_fields = {
2231					// When did the user begin entering any input?
2232					'bib': input_begin,
2233
2234					// When was the form submitted?
2235					'bfs': Date.now(),
2236
2237					// How many keypresses did they make?
2238					'bkpc': keypresses.length,
2239
2240					// How quickly did they press a sample of keys, and how long between them?
2241					'bkp': ak_bkp,
2242
2243					// How quickly did they click the mouse, and how long between clicks?
2244					'bmc': ak_bmc,
2245
2246					// How many mouseclicks did they make?
2247					'bmcc': mouseclicks.length,
2248
2249					// When did they press modifier keys (like Shift or Capslock)?
2250					'bmk': modifierKeys.join( ';' ),
2251
2252					// When did they correct themselves? e.g., press Backspace, or use the arrow keys to move the cursor back
2253					'bck': correctionKeys.join( ';' ),
2254
2255					// How many times did they move the mouse?
2256					'bmmc': mousemoves.length,
2257
2258					// How many times did they move around using a touchscreen?
2259					'btmc': touchmoveCount,
2260
2261					// How many times did they scroll?
2262					'bsc': scrollCount,
2263
2264					// How quickly did they perform touch events, and how long between them?
2265					'bte': ak_bte,
2266
2267					// How many touch events were there?
2268					'btec' : touchEvents.length,
2269
2270					// How quickly did they move the mouse, and how long between moves?
2271					'bmm' : ak_bmm,
2272
2273					// Click coordinates
2274					'bcc' : ak_bcc,
2275
2276					// Milliseconds between last mouse movement and each click
2277					'bibmac' : ak_bibmac
2278				};
2279
2280				var akismet_field_prefix = 'ak_';
2281
2282				if ( this.getElementsByClassName ) {
2283					// Check to see if we've used an alternate field name prefix. We store this as an attribute of the container around some of the Akismet fields.
2284					var possible_akismet_containers = this.getElementsByClassName( 'akismet-fields-container' );
2285
2286					for ( var containerIndex = 0; containerIndex < possible_akismet_containers.length; containerIndex++ ) {
2287						var container = possible_akismet_containers.item( containerIndex );
2288
2289						if ( container.getAttribute( 'data-prefix' ) ) {
2290							akismet_field_prefix = container.getAttribute( 'data-prefix' );
2291							break;
2292						}
2293					}
2294				}
2295
2296				for ( var field_name in input_fields ) {
2297					var field = document.createElement( 'input' );
2298					field.setAttribute( 'type', 'hidden' );
2299					field.setAttribute( 'name', akismet_field_prefix + field_name );
2300					field.setAttribute( 'value', input_fields[ field_name ] );
2301					this.appendChild( field );
2302				}
2303			}, supportsPassive ? { passive: true } : false  );
2304
2305			form.addEventListener( 'keydown', function ( e ) {
2306				// If you hold a key down, some browsers send multiple keydown events in a row.
2307				// Ignore any keydown events for a key that hasn't come back up yet.
2308				if ( e.key in keydowns ) {
2309					return;
2310				}
2311
2312				var keydownTime = ( new Date() ).getTime();
2313				keydowns[ e.key ] = [ keydownTime ];
2314
2315				if ( ! input_begin ) {
2316					input_begin = keydownTime;
2317				}
2318
2319				// In some situations, we don't want to record an interval since the last keypress -- for example,
2320				// on the first keypress, or on a keypress after focus has changed to another element. Normally,
2321				// we want to record the time between the last keyup and this keydown. But if they press a
2322				// key while already pressing a key, we want to record the time between the two keydowns.
2323
2324				var lastKeyEvent = Math.max( lastKeydown, lastKeyup );
2325
2326				if ( lastKeyEvent ) {
2327					keydowns[ e.key ].push( keydownTime - lastKeyEvent );
2328				}
2329
2330				lastKeydown = keydownTime;
2331			}, supportsPassive ? { passive: true } : false  );
2332
2333			form.addEventListener( 'keyup', function ( e ) {
2334				if ( ! ( e.key in keydowns ) ) {
2335					// This key was pressed before this script was loaded, or a mouseclick happened during the keypress, or...
2336					return;
2337				}
2338
2339				var keyupTime = ( new Date() ).getTime();
2340
2341				if ( 'TEXTAREA' === e.target.nodeName || 'INPUT' === e.target.nodeName ) {
2342					if ( -1 !== modifierKeyCodes.indexOf( e.key ) ) {
2343						modifierKeys.push( keypresses.length - 1 );
2344					} else if ( -1 !== correctionKeyCodes.indexOf( e.key ) ) {
2345						correctionKeys.push( keypresses.length - 1 );
2346					} else {
2347						// ^ Don't record timings for keys like Shift or backspace, since they
2348						// typically get held down for longer than regular typing.
2349
2350						var keydownTime = keydowns[ e.key ][0];
2351
2352						var keypress = [];
2353
2354						// Keypress duration.
2355						keypress.push( keyupTime - keydownTime );
2356
2357						// Amount of time between this keypress and the previous keypress.
2358						if ( keydowns[ e.key ].length > 1 ) {
2359							keypress.push( keydowns[ e.key ][1] );
2360						}
2361
2362						keypresses.push( keypress );
2363					}
2364				}
2365
2366				delete keydowns[ e.key ];
2367
2368				lastKeyup = keyupTime;
2369			}, supportsPassive ? { passive: true } : false  );
2370
2371			form.addEventListener( "focusin", function ( e ) {
2372				lastKeydown = null;
2373				lastKeyup = null;
2374				keydowns = {};
2375			}, supportsPassive ? { passive: true } : false  );
2376
2377			form.addEventListener( "focusout", function ( e ) {
2378				lastKeydown = null;
2379				lastKeyup = null;
2380				keydowns = {};
2381			}, supportsPassive ? { passive: true } : false  );
2382		}
2383
2384		document.addEventListener( 'mousedown', function ( e ) {
2385			lastMousedown = ( new Date() ).getTime();
2386
2387			if ( lastMousemoveTime ) {
2388				intervalsBetweenMousemovesAndClicks.push( lastMousedown - lastMousemoveTime );
2389			}
2390
2391			var mouseclickCoordinate = [];
2392
2393			var rect = e.target.getBoundingClientRect();
2394			var relativeX = e.clientX - rect.left;
2395			var relativeY = e.clientY - rect.top;
2396
2397			// Pixel offset of the click within the target element.
2398			mouseclickCoordinate.push( Math.round( relativeX ) );
2399			mouseclickCoordinate.push( Math.round( relativeY ) );
2400
2401			// Percentage offset of the click within the target element.
2402			mouseclickCoordinate.push( rect.width > 0 ? Math.round( relativeX / rect.width * 100 ) : 0 );
2403			mouseclickCoordinate.push( rect.height > 0 ? Math.round( relativeY / rect.height * 100 ) : 0 );
2404
2405			mouseclickCoordinates.push( mouseclickCoordinate );
2406		}, supportsPassive ? { passive: true } : false  );
2407
2408		document.addEventListener( 'mouseup', function ( e ) {
2409			if ( ! lastMousedown ) {
2410				// If the mousedown happened before this script was loaded, but the mouseup happened after...
2411				return;
2412			}
2413
2414			var now = ( new Date() ).getTime();
2415
2416			var mouseclick = [];
2417			mouseclick.push( now - lastMousedown );
2418
2419			if ( lastMouseup ) {
2420				mouseclick.push( lastMousedown - lastMouseup );
2421			}
2422
2423			mouseclicks.push( mouseclick );
2424
2425			lastMouseup = now;
2426
2427			// If the mouse has been clicked, don't record this time as an interval between keypresses.
2428			lastKeydown = null;
2429			lastKeyup = null;
2430			keydowns = {};
2431		}, supportsPassive ? { passive: true } : false  );
2432
2433		document.addEventListener( 'mousemove', function ( e ) {
2434			lastMousemoveTime = ( new Date() ).getTime();
2435
2436			if ( mousemoveTimer ) {
2437				clearTimeout( mousemoveTimer );
2438				mousemoveTimer = null;
2439			}
2440			else {
2441				mousemoveStart = lastMousemoveTime;
2442				lastMousemoveX = e.offsetX;
2443				lastMousemoveY = e.offsetY;
2444			}
2445
2446			mousemoveTimer = setTimeout( function ( theEvent, originalMousemoveStart ) {
2447				var now = ( new Date() ).getTime() - 500; // To account for the timer delay.
2448
2449				var mousemove = [];
2450				mousemove.push( now - originalMousemoveStart );
2451				mousemove.push(
2452					Math.round(
2453						Math.sqrt(
2454							Math.pow( theEvent.offsetX - lastMousemoveX, 2 ) +
2455							Math.pow( theEvent.offsetY - lastMousemoveY, 2 )
2456						)
2457					)
2458				);
2459
2460				if ( mousemove[1] > 0 ) {
2461					// If there was no measurable distance, then it wasn't really a move.
2462					mousemoves.push( mousemove );
2463				}
2464
2465				mousemoveStart = null;
2466				mousemoveTimer = null;
2467			}, 500, e, mousemoveStart );
2468		}, supportsPassive ? { passive: true } : false  );
2469
2470		document.addEventListener( 'touchmove', function ( e ) {
2471			if ( touchmoveCountTimer ) {
2472				clearTimeout( touchmoveCountTimer );
2473			}
2474
2475			touchmoveCountTimer = setTimeout( function () {
2476				touchmoveCount++;
2477			}, 500 );
2478		}, supportsPassive ? { passive: true } : false );
2479
2480		document.addEventListener( 'touchstart', function ( e ) {
2481			lastTouchStart = ( new Date() ).getTime();
2482		}, supportsPassive ? { passive: true } : false );
2483
2484		document.addEventListener( 'touchend', function ( e ) {
2485			if ( ! lastTouchStart ) {
2486				// If the touchstart happened before this script was loaded, but the touchend happened after...
2487				return;
2488			}
2489
2490			var now = ( new Date() ).getTime();
2491
2492			var touchEvent = [];
2493			touchEvent.push( now - lastTouchStart );
2494
2495			if ( lastTouchEnd ) {
2496				touchEvent.push( lastTouchStart - lastTouchEnd );
2497			}
2498
2499			touchEvents.push( touchEvent );
2500
2501			lastTouchEnd = now;
2502
2503			// Don't record this time as an interval between keypresses.
2504			lastKeydown = null;
2505			lastKeyup = null;
2506			keydowns = {};
2507		}, supportsPassive ? { passive: true } : false );
2508
2509		document.addEventListener( 'scroll', function ( e ) {
2510			if ( scrollCountTimer ) {
2511				clearTimeout( scrollCountTimer );
2512			}
2513
2514			scrollCountTimer = setTimeout( function () {
2515				scrollCount++;
2516			}, 500 );
2517		}, supportsPassive ? { passive: true } : false );
2518	}
2519
2520	/**
2521	 * For the timing/coordinate data that is collected, don't send more than `limit` data points in the request.
2522	 * Choose a random slice and send those, with each batch separated by semicolons and the items in each batch
2523	 * separated by commas.
2524	 */
2525	function prepare_array_for_request( a, limit ) {
2526		if ( ! limit ) {
2527			limit = 100;
2528		}
2529
2530		var rv = '';
2531
2532		if ( a.length > 0 ) {
2533			var random_starting_point = Math.max( 0, Math.floor( Math.random() * a.length - limit ) );
2534
2535			for ( var i = 0; i < limit && i < a.length; i++ ) {
2536				var entry = a[ random_starting_point + i ];
2537				rv += entry.join( ',' ) + ';';
2538			}
2539		}
2540
2541		return rv;
2542	}
2543
2544	if ( document.readyState !== 'loading' ) {
2545		init();
2546	} else {
2547		document.addEventListener( 'DOMContentLoaded', init );
2548	}
2549})();;
2550!function(){var e=document.currentScript;function t(t){var n=document.createElement("script"),o=e||document.getElementsByTagName("script")[0];n.setAttribute("async",!0),n.setAttribute("src",t),o.parentNode.insertBefore(n,o)}function n(e,t){return Element.prototype.matches?e.matches(t):Element.prototype.msMatchesSelector?e.msMatchesSelector(t):void 0}function o(e,t){if(e.closest)return e.closest(t);var o=e;do{if(n(o,t))return o;o=o.parentElement||o.parentNode}while(null!==o&&1===o.nodeType);return null}function i(e,t){for(var n=0;n<e.length;n++)t(e[n],n,e)}var r=".sharing-hidden .inner",s="data-sharing-more-button-id";function a(e){this.button=e,this.pane=o(e,"div").querySelector(r),this.openedBy=null,this.recentlyOpenedByHover=!1,a.instances.push(this),this.pane.setAttribute(s,a.instances.length-1),this.attachHandlers()}if(a.instances=[],a.hoverOpenDelay=200,a.recentOpenDelay=400,a.hoverCloseDelay=300,a.instantiateOrReuse=function(e){var t=o(e,"div").querySelector(r),n=t&&t.getAttribute(s),i=a.instances[n];return i||new a(e)},a.getButtonInstanceFromPane=function(e){var t=e&&e.getAttribute(s);return a.instances[t]},a.closeAll=function(){for(var e=0;e<a.instances.length;e++)a.instances[e].close()},a.prototype.open=function(){var e,t,n=[0,0];function o(e){var t=e.getBoundingClientRect();return[t.left+(window.scrollX||window.pageXOffset||0),t.top+(window.scrollY||window.pageYOffset||0)]}function i(e,t){return parseInt(getComputedStyle(e).getPropertyValue(t)||0)}for(e=o(this.button),t=this.button.offsetParent||document.documentElement;t&&(t===document.body||t===document.documentElement)&&"static"===getComputedStyle(t).getPropertyValue("position");)t=t.parentNode;t&&t!==this.button&&1===t.nodeType&&(n=[(n=o(t))[0]+i(t,"border-left-width"),n[1]+i(t,"border-top-width")]);var r,s=e[0]-n[0]-i(this.button,"margin-left"),a=e[1]-n[1]-i(this.button,"margin-top");this.pane.style.left=s+"px",this.pane.style.top=a+this.button.offsetHeight+3+"px",(r=this.pane)&&r.style.removeProperty("display")},a.prototype.close=function(){var e;(e=this.pane)&&(e.style.display="none"),this.openedBy=null},a.prototype.toggle=function(){var e;(e=this.pane)&&"none"!==e.style.display?this.close():this.open()},a.prototype.nonHoverOpen=function(){clearTimeout(this.openTimer),clearTimeout(this.closeTimer),this.recentlyOpenedByHover?(this.recentlyOpenedByHover=!1,clearTimeout(this.hoverOpenTimer),this.open()):this.toggle()},a.prototype.resetCloseTimer=function(){clearTimeout(this.closeTimer),this.closeTimer=setTimeout(this.close.bind(this),a.hoverCloseDelay)},a.prototype.attachHandlers=function(){this.buttonClick=function(e){e.preventDefault(),e.stopPropagation(),this.openedBy="click",this.nonHoverOpen()}.bind(this),this.buttonKeydown=function(e){13!==e.keyCode&&32!==e.keyCode||(e.preventDefault(),e.stopPropagation(),this.openedBy="keydown",this.nonHoverOpen())}.bind(this),this.buttonEnter=function(){this.openedBy||(this.openTimer=setTimeout(function(){this.open(),this.openedBy="hover",this.recentlyOpenedByHover=!0,this.hoverOpenTimer=setTimeout(function(){this.recentlyOpenedByHover=!1}.bind(this),a.recentOpenDelay)}.bind(this),a.hoverOpenDelay)),clearTimeout(this.closeTimer)}.bind(this),this.buttonLeave=function(){"hover"===this.openedBy&&this.resetCloseTimer(),clearTimeout(this.openTimer)}.bind(this),this.paneEnter=function(){clearTimeout(this.closeTimer)}.bind(this),this.paneLeave=function(){"hover"===this.openedBy&&this.resetCloseTimer()}.bind(this),this.documentClick=function(){this.close()}.bind(this),this.button.addEventListener("click",this.buttonClick),this.button.addEventListener("keydown",this.buttonKeydown),document.addEventListener("click",this.documentClick),void 0===document.ontouchstart&&(this.button.addEventListener("mouseenter",this.buttonEnter),this.button.addEventListener("mouseleave",this.buttonLeave),this.pane.addEventListener("mouseenter",this.paneEnter),this.pane.addEventListener("mouseleave",this.paneLeave))},window.sharing_js_options&&window.sharing_js_options.counts){var c={done_urls:[],get_counts:function(){var e,n,o,i,r;if("undefined"!=typeof WPCOM_sharing_counts)for(e in WPCOM_sharing_counts)if(o=WPCOM_sharing_counts[e],void 0===c.done_urls[o]){for(i in n={pinterest:[window.location.protocol+"//api.pinterest.com/v1/urls/count.json?callback=WPCOMSharing.update_pinterest_count&url="+encodeURIComponent(e)]})if(document.querySelector("a[data-shared=sharing-"+i+"-"+o+"]")){for(;r=n[i].pop();)t(r);window.sharing_js_options.is_stats_active&&c.bump_sharing_count_stat(i)}c.done_urls[o]=!0}},update_pinterest_count:function(e){void 0!==e.count&&1*e.count>0&&c.inject_share_count("sharing-pinterest-"+WPCOM_sharing_counts[e.url],e.count)},inject_share_count:function(e,t){i(document.querySelectorAll("a[data-shared="+e+"] > span"),function(e){var n,o=e.querySelector(".share-count");(n=o)&&n.parentNode&&n.parentNode.removeChild(n);var i=document.createElement("span");
2550i.className="share-count",i.textContent=c.format_count(t),e.appendChild(i)})},format_count:function(e){return e<1e3?e:e>=1e3&&e<1e4?String(e).substring(0,1)+"K+":"10K+"},bump_sharing_count_stat:function(e){(new Image).src=document.location.protocol+"//pixel.wp.com/g.gif?v=wpcom-no-pv&x_sharing-count-request="+e+"&r="+Math.random()}};window.WPCOMSharing=c}function u(e,t){e.setAttribute("jetpack-share-click-count",t)}function d(e){var t=e.getAttribute("jetpack-share-click-count");return null===t?0:parseInt(t,10)}function l(e,t){var n,o=new XMLHttpRequest;o.open("POST",e,!0),o.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8"),o.setRequestHeader("x-requested-with","XMLHttpRequest"),o.send((n=t,(encodeURIComponent("email-share-nonce")+"="+encodeURIComponent(n)).replace(/%20/g,"+")))}function h(){p()}function p(){window.WPCOMSharing&&window.WPCOMSharing.get_counts(),i(document.querySelectorAll(".sharedaddy a"),function(e){var t=e.getAttribute("href");t&&-1!==t.indexOf("share=")&&-1===t.indexOf("&nb=1")&&e.setAttribute("href",t+"&nb=1")}),i(document.querySelectorAll(".sharedaddy a.sharing-anchor"),function(e){a.instantiateOrReuse(e)}),void 0!==document.ontouchstart&&document.body.classList.add("jp-sharing-input-touch"),i(document.querySelectorAll(".sharedaddy ul"),function(e){"true"!==e.getAttribute("data-sharing-events-added")&&(e.setAttribute("data-sharing-events-added","true"),i(e.querySelectorAll("a.share-print"),function(e){e.addEventListener("click",function(t){t.preventDefault(),t.stopPropagation();var n=e.getAttribute("href")||"",i=function(){if(-1===n.indexOf("#print")){var e=(new Date).getTime();t=e,o=n,(i=document.createElement("iframe")).setAttribute("style","position:fixed; top:100; left:100; height:1px; width:1px; border:none;"),i.setAttribute("id","printFrame-"+t),i.setAttribute("name",i.getAttribute("id")),i.setAttribute("src",o),i.setAttribute("onload",'frames["printFrame-'+t+'"].focus();frames["printFrame-'+t+'"].print();'),document.body.appendChild(i)}else window.print();var t,o,i},s=o(e,r);if(s){var c=a.getButtonInstanceFromPane(s);c&&(c.close(),i())}else i()})}),i(e.querySelectorAll("a.share-press-this"),function(e){e.addEventListener("click",function(t){t.preventDefault(),t.stopPropagation();var n="";if(window.getSelection?n=window.getSelection():document.getSelection?n=document.getSelection():document.selection&&(n=document.selection.createRange().text),n){var o=e.getAttribute("href");e.setAttribute("href",o+"&sel="+encodeURI(n))}window.open(e.getAttribute("href"),"t","toolbar=0,resizable=1,scrollbars=1,status=1,width=720,height=570")||(document.location.href=e.getAttribute("href"))})}),i(e.querySelectorAll("a.share-email"),function(t){u(t,0);var n,o,r=t.getAttribute("data-email-share-nonce"),s=t.getAttribute("data-email-share-track-url");r&&s&&(n=s,o=window.location.protocol+"//"+window.location.hostname+"/",0===String(n).indexOf(o))&&t.addEventListener("click",function(){var n;u(n=t,d(n)+1),d(t)>2&&function(e,t){var n=t.parentElement;if(n.classList.contains("sd-content")){i(n.querySelectorAll(".share-email-error"),function(e){e.parentElement.removeChild(e)});var o=document.createElement("div");o.className="share-email-error";var r=document.createElement("h6");r.className="share-email-error-title",r.innerText=e.getAttribute("data-email-share-error-title"),o.appendChild(r);var s=document.createElement("p");s.className="share-email-error-text",s.innerText=e.getAttribute("data-email-share-error-text"),o.appendChild(s),n.appendChild(o)}}(t,e),l(s,r)})}))}),i(document.querySelectorAll("li.share-email, li.share-custom a.sharing-anchor"),function(e){e.classList.add("share-service-visible")})}"loading"!==document.readyState?h():document.addEventListener("DOMContentLoaded",h),document.body.addEventListener("is.post-load",p)}();;

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.