PageSourceSearch

https://ensvensktiger.org/_static/??-eJyNzE0OwiAQQOELSSc1jcaF8SxYp…qJ16Dom2XO3qlg2zXYTN77256G/nPrjMKxfge1xrg==

js ensvensktiger.org collected 2026-10-08 09:47:22 UTC 186,973 bytes, 5,356 lines download raw bytes

1/* global wpcom_reblog */
2
3var jetpackLikesWidgetBatch = [];
4var jetpackLikesMasterReady = false;
5
6// Due to performance problems on pages with a large number of widget iframes that need to be loaded,
7// we are limiting the processing at any instant to unloaded widgets that are currently in viewport,
8// plus this constant that will allow processing of widgets above and bellow the current fold.
9// This aim of it is to improve the UX and hide the transition from unloaded to loaded state from users.
10var jetpackLikesLookAhead = 2000; // pixels
11
12// Keeps track of loaded comment likes widget so we can unload them when they are scrolled out of view.
13var jetpackCommentLikesLoadedWidgets = [];
14
15var jetpackLikesDocReadyPromise = new Promise( resolve => {
16	if ( document.readyState !== 'loading' ) {
17		resolve();
18	} else {
19		window.addEventListener( 'DOMContentLoaded', () => resolve() );
20	}
21} );
22
23function JetpackLikesPostMessage( message, target ) {
24	if ( typeof message === 'string' ) {
25		try {
26			message = JSON.parse( message );
27		} catch ( e ) {
28			return;
29		}
30	}
31
32	if ( target && typeof target.postMessage === 'function' ) {
33		try {
34			target.postMessage(
35				JSON.stringify( {
36					type: 'likesMessage',
37					data: message,
38				} ),
39				'*'
40			);
41		} catch ( e ) {
42			return;
43		}
44	}
45}
46
47function JetpackLikesBatchHandler() {
48	const requests = [];
49	document.querySelectorAll( 'div.jetpack-likes-widget-unloaded' ).forEach( widget => {
50		if ( jetpackLikesWidgetBatch.indexOf( widget.id ) > -1 ) {
51			return;
52		}
53
54		if ( ! jetpackIsScrolledIntoView( widget ) ) {
55			return;
56		}
57
58		jetpackLikesWidgetBatch.push( widget.id );
59
60		var regex = /like-(post|comment)-wrapper-(\d+)-(\d+)-(\w+)/,
61			match = regex.exec( widget.id ),
62			info;
63
64		if ( ! match || match.length !== 5 ) {
65			return;
66		}
67
68		info = {
69			blog_id: match[ 2 ],
70			width: widget.width,
71		};
72
73		if ( 'post' === match[ 1 ] ) {
74			info.post_id = match[ 3 ];
75		} else if ( 'comment' === match[ 1 ] ) {
76			info.comment_id = match[ 3 ];
77		}
78
79		info.obj_id = match[ 4 ];
80
81		requests.push( info );
82	} );
83
84	if ( requests.length > 0 ) {
85		JetpackLikesPostMessage(
86			{ event: 'initialBatch', requests: requests },
87			window.frames[ 'likes-master' ]
88		);
89	}
90}
91
92function JetpackLikesMessageListener( event ) {
93	let message = event && event.data;
94	if ( typeof message === 'string' ) {
95		try {
96			message = JSON.parse( message );
97		} catch ( err ) {
98			return;
99		}
100	}
101
102	const type = message && message.type;
103	const data = message && message.data;
104
105	if ( type !== 'likesMessage' || typeof data.event === 'undefined' ) {
106		return;
107	}
108
109	// We only allow messages from one origin
110	const allowedOrigin = 'https://widgets.wp.com';
111	if ( allowedOrigin !== event.origin ) {
112		return;
113	}
114
115	switch ( data.event ) {
116		case 'masterReady':
117			jetpackLikesDocReadyPromise.then( () => {
118				jetpackLikesMasterReady = true;
119
120				const stylesData = {
121					event: 'injectStyles',
122				};
123				const sdTextColor = document.querySelector( '.sd-text-color' );
124				const sdLinkColor = document.querySelector( '.sd-link-color' );
125				const sdTextColorStyles = ( sdTextColor && getComputedStyle( sdTextColor ) ) || {};
126				const sdLinkColorStyles = ( sdLinkColor && getComputedStyle( sdLinkColor ) ) || {};
127
128				// enable reblogs if they are enabled for the page
129				if ( document.body.classList.contains( 'jetpack-reblog-enabled' ) ) {
130					JetpackLikesPostMessage( { event: 'reblogsEnabled' }, window.frames[ 'likes-master' ] );
131				}
132
133				stylesData.textStyles = {
134					color: sdTextColorStyles[ 'color' ],
135					fontFamily: sdTextColorStyles[ 'font-family' ],
136					fontSize: sdTextColorStyles[ 'font-size' ],
137					direction: sdTextColorStyles[ 'direction' ],
138					fontWeight: sdTextColorStyles[ 'font-weight' ],
139					fontStyle: sdTextColorStyles[ 'font-style' ],
140					textDecoration: sdTextColorStyles[ 'text-decoration' ],
141				};
142
143				stylesData.linkStyles = {
144					color: sdLinkColorStyles[ 'color' ],
145					fontFamily: sdLinkColorStyles[ 'font-family' ],
146					fontSize: sdLinkColorStyles[ 'font-size' ],
147					textDecoration: sdLinkColorStyles[ 'text-decoration' ],
148					fontWeight: sdLinkColorStyles[ 'font-weight' ],
149					fontStyle: sdLinkColorStyles[ 'font-style' ],
150				};
151
152				JetpackLikesPostMessage( stylesData, window.frames[ 'likes-master' ] );
153
154				JetpackLikesBatchHandler();
155			} );
156
157			break;
158
159		// We're keeping this for planned future follow ups.
160		// @see: https://github.com/Automattic/jetpack/pull/42361#discussion_r1995338815
161		case 'showLikeWidget':
162			break;
163
164		// We're keeping this for planned future follow ups.
165		// @see: https://github.com/Automattic/jetpack/pull/42361#discussion_r1995338815
166		case 'showCommentLikeWidget':
167			break;
168
169		case 'killCommentLikes':
170			// If kill switch for comment likes is enabled remove all widgets wrappers and `Loading...` placeholders.
171			document
172				.querySelectorAll( '.jetpack-comment-likes-widget-wrapper' )
173				.forEach( wrapper => wrapper.remove() );
174			break;
175
176		case 'clickReblogFlair':
177			if ( wpcom_reblog && typeof wpcom_reblog.toggle_reblog_box_flair === 'function' ) {
178				wpcom_reblog.toggle_reblog_box_flair( data.obj_id, data.post_id );
179			}
180			break;
181
182		case 'hideOtherGravatars': {
183			hideLikersPopover();
184			break;
185		}
186
187		case 'showOtherGravatars': {
188			const container = document.querySelector( '#likes-other-gravatars' );
189
190			if ( ! container ) {
191				break;
192			}
193
194			const list = container.querySelector( 'ul' );
195
196			container.style.display = 'none';
197			list.innerHTML = '';
198
199			container
200				.querySelectorAll( '.likes-text span' )
201				.forEach( item => ( item.textContent = data.totalLikesLabel ) );
202
203			( data.likers || [] ).forEach( async ( liker, index ) => {
204				if ( liker.profile_URL.substr( 0, 4 ) !== 'http' ) {
205					// We only display gravatars with http or https schema
206					return;
207				}
208
209				const element = document.createElement( 'li' );
210				list.append( element );
211
212				element.innerHTML = `
213				<a href="${ encodeURI( liker.profile_URL ) }" rel="nofollow" target="_parent" class="wpl-liker">
214					<img src="${ encodeURI( liker.avatar_URL ) }"
215						alt=""
216						style="width: 28px; height: 28px;" />
217					<span></span>
218				</a>
219				`;
220
221
222				// Add some extra attributes through native methods, to ensure strings are sanitized.
223				element.classList.add( liker.css_class );
224				element.querySelector( 'img' ).alt = data.avatarAltTitle.replace( '%s', liker.name );
225				element.querySelector( 'span' ).innerText = liker.name;
226
227				if ( index === data.likers.length - 1 ) {
228					element.addEventListener( 'keydown', ( e ) => {
229						if ( e.key === 'Tab' && ! e.shiftKey ) {
230							e.preventDefault();
231							hideLikersPopover();
232
233							JetpackLikesPostMessage(
234								{ event: 'focusLikesCount', parent: data.parent },
235								window.frames[ 'likes-master' ]
236							);
237						}
238					} );
239				}
240			} );
241
242			const positionPopup = function() {
243				const containerStyle = getComputedStyle(container);
244				const isRtl = containerStyle.direction === 'rtl';
245
246				const el = document.querySelector( `*[name='${ data.parent }']` );
247				const rect = el.getBoundingClientRect();
248				const win = el.ownerDocument.defaultView;
249
250				const offset = {
251					top: rect.top + win.pageYOffset,
252					left: rect.left + win.pageXOffset,
253				};
254
255				// don't display yet or we get skewed window.innerWidth later
256				container.style.display = 'none';
257
258				let containerLeft = 0;
259				container.style.top = offset.top + data.position.top - 1 + 'px';
260
261				if ( isRtl ) {
262					const visibleAvatarsCount = data && data.likers ? Math.min( data.likers.length, 5 ) : 0;
263					// 24px is the width of the avatar + 4px is the padding between avatars
264					containerLeft = offset.left + data.position.left + 24 * visibleAvatarsCount + 4;
265					container.style.transform = 'translateX(-100%)';
266				} else {
267					containerLeft = offset.left + data.position.left;
268				}
269				container.style.left = containerLeft + 'px';
270
271				// Container width - padding
272				const initContainerWidth = data.width - 20;
273				const rowLength = Math.floor( initContainerWidth / 37 );
274				// # of rows + (avatar + avatar padding) + text above + container padding
275				let height = Math.ceil( data.likers.length / rowLength ) * 37 + 17 + 22;
276				if ( height > 204 ) {
277					height = 204;
278				}
279
280				// If the popup is overflows viewport width, we should show it on the next line
281				// Push it offscreen to calculated rendered width
282				const windowWidth = win.innerWidth;
283				container.style.left = '-9999px';
284				container.style.display = 'block';
285
286				// If the popup exceeds the viewport width,
287				// flip the position of the popup.
288				const containerWidth = container.offsetWidth;
289				const containerRight = containerLeft + containerWidth;
290
291				if ( containerRight > windowWidth && ! isRtl) {
292					containerLeft = rect.left + rect.width - containerWidth;
293				} else if ( containerLeft - containerWidth < 0 && isRtl ) {
294					container.style.transform = 'none';
295					containerLeft = rect.left;
296				}
297				// Set the container left
298				container.style.left = containerLeft + 'px';
299
300				container.setAttribute( 'aria-hidden', 'false' );
301			}
302
303			positionPopup();
304			container.focus();
305
306			const debounce = function( func, wait ) {
307				var timeout;
308				return function() {
309					var context = this;
310					var args = arguments;
311					clearTimeout( timeout );
312					timeout = setTimeout( function() {
313						func.apply( context, args );
314					}, wait );
315				};
316			};
317
318			const debouncedPositionPopup = debounce( positionPopup, 100 );
319
320			// Keep a reference of this function in the element itself
321			// so that we can destroy it later
322			container.__resizeHandler = debouncedPositionPopup;
323
324			// When window is resized, resize the popup.
325			window.addEventListener( "resize", debouncedPositionPopup );
326		}
327	}
328}
329
330window.addEventListener( 'message', JetpackLikesMessageListener );
331
332function hideLikersPopover() {
333	const container = document.querySelector( '#likes-other-gravatars' );
334
335	if ( container ) {
336		container.style.display = 'none';
337		container.setAttribute( 'aria-hidden', 'true' );
338
339		// Remove the resize event listener and cleanup.
340		const resizeHandler = container.__resizeHandler;
341		if ( resizeHandler ) {
342			window.removeEventListener( "resize", resizeHandler );
343			delete container.__resizeHandler;
344		}
345	}
346}
347
348document.addEventListener( 'click', hideLikersPopover );
349
350function JetpackLikesWidgetQueueHandler() {
351	var wrapperID;
352
353	if ( ! jetpackLikesMasterReady ) {
354		setTimeout( JetpackLikesWidgetQueueHandler, 500 );
355		return;
356	}
357
358	// Restore widgets to initial unloaded state when they are scrolled out of view.
359	jetpackUnloadScrolledOutWidgets();
360
361	var unloadedWidgetsInView = jetpackGetUnloadedWidgetsInView();
362
363	if ( unloadedWidgetsInView.length > 0 ) {
364		// Grab any unloaded widgets for a batch request
365		JetpackLikesBatchHandler();
366	}
367
368	for ( var i = 0, length = unloadedWidgetsInView.length; i <= length - 1; i++ ) {
369		wrapperID = unloadedWidgetsInView[ i ].id;
370
371		if ( ! wrapperID ) {
372			continue;
373		}
374
375		jetpackLoadLikeWidgetIframe( wrapperID );
376	}
377}
378
379function jetpackLoadLikeWidgetIframe( wrapperID ) {
380	if ( typeof wrapperID === 'undefined' ) {
381		return;
382	}
383
384	const wrapper = document.querySelector( '#' + wrapperID );
385	wrapper.querySelectorAll( 'iframe' ).forEach( iFrame => iFrame.remove() );
386
387	const placeholder = wrapper.querySelector( '.likes-widget-placeholder' );
388
389	// Post like iframe
390	if ( placeholder && placeholder.classList.contains( 'post-likes-widget-placeholder' ) ) {
391		const postLikesFrame = document.createElement( 'iframe' );
392
393		postLikesFrame.classList.add( 'post-likes-widget', 'jetpack-likes-widget' );
394		postLikesFrame.name = wrapper.dataset.name;
395		postLikesFrame.src = wrapper.dataset.src;
396		postLikesFrame.height = '55px';
397		postLikesFrame.width = '100%';
398		postLikesFrame.frameBorder = '0';
399		postLikesFrame.scrolling = 'no';
400		postLikesFrame.title = wrapper.dataset.title;
401
402		placeholder.after( postLikesFrame );
403	}
404
405	// Comment like iframe
406	if ( placeholder.classList.contains( 'comment-likes-widget-placeholder' ) ) {
407		const commentLikesFrame = document.createElement( 'iframe' );
408
409		commentLikesFrame.class = 'comment-likes-widget-frame jetpack-likes-widget-frame';
410		commentLikesFrame.name = wrapper.dataset.name;
411		commentLikesFrame.src = wrapper.dataset.src;
412		commentLikesFrame.height = '18px';
413		commentLikesFrame.width = '100%';
414		commentLikesFrame.frameBorder = '0';
415		commentLikesFrame.scrolling = 'no';
416
417		wrapper.querySelector( '.comment-like-feedback' ).after( commentLikesFrame );
418
419		jetpackCommentLikesLoadedWidgets.push( commentLikesFrame );
420	}
421
422	wrapper.classList.remove( 'jetpack-likes-widget-unloaded' );
423	wrapper.classList.add( 'jetpack-likes-widget-loading' );
424
425	wrapper.querySelector( 'iframe' ).addEventListener( 'load', e => {
426		JetpackLikesPostMessage(
427			{ event: 'loadLikeWidget', name: e.target.name, width: e.target.width },
428			window.frames[ 'likes-master' ]
429		);
430
431		wrapper.classList.remove( 'jetpack-likes-widget-loading' );
432		wrapper.classList.add( 'jetpack-likes-widget-loaded' );
433	} );
434}
435
436function jetpackGetUnloadedWidgetsInView() {
437	const unloadedWidgets = document.querySelectorAll( 'div.jetpack-likes-widget-unloaded' );
438
439	return [ ...unloadedWidgets ].filter( item => jetpackIsScrolledIntoView( item ) );
440}
441
442function jetpackIsScrolledIntoView( element ) {
443	const top = element.getBoundingClientRect().top;
444	const bottom = element.getBoundingClientRect().bottom;
445
446	// Allow some slack above and bellow the fold with jetpackLikesLookAhead,
447	// with the aim of hiding the transition from unloaded to loaded widget from users.
448	return top + jetpackLikesLookAhead >= 0 && bottom <= window.innerHeight + jetpackLikesLookAhead;
449}
450
451function jetpackUnloadScrolledOutWidgets() {
452	for ( let i = jetpackCommentLikesLoadedWidgets.length - 1; i >= 0; i-- ) {
453		const currentWidgetIframe = jetpackCommentLikesLoadedWidgets[ i ];
454
455		if ( ! jetpackIsScrolledIntoView( currentWidgetIframe ) ) {
456			const widgetWrapper =
457				currentWidgetIframe &&
458				currentWidgetIframe.parentElement &&
459				currentWidgetIframe.parentElement.parentElement;
460
461			// Restore parent class to 'unloaded' so this widget can be picked up by queue manager again if needed.
462			widgetWrapper.classList.remove( 'jetpack-likes-widget-loaded' );
463			widgetWrapper.classList.remove( 'jetpack-likes-widget-loading' );
464			widgetWrapper.classList.add( 'jetpack-likes-widget-unloaded' );
465
466			// Bring back the loading placeholder into view.
467			widgetWrapper
468				.querySelectorAll( '.comment-likes-widget-placeholder' )
469				.forEach( item => ( item.style.display = 'block' ) );
470
471			// Remove it from the list of loaded widgets.
472			jetpackCommentLikesLoadedWidgets.splice( i, 1 );
473
474			// Remove comment like widget iFrame.
475			currentWidgetIframe.remove();
476		}
477	}
478}
479
480var jetpackWidgetsDelayedExec = function ( after, fn ) {
481	var timer;
482	return function () {
483		clearTimeout( timer );
484		timer = setTimeout( fn, after );
485	};
486};
487
488var jetpackOnScrollStopped = jetpackWidgetsDelayedExec( 250, JetpackLikesWidgetQueueHandler );
489
490// Load initial batch of widgets, prior to any scrolling events.
491JetpackLikesWidgetQueueHandler();
492
493// Add event listener to execute queue handler after scroll.
494window.addEventListener( 'scroll', jetpackOnScrollStopped, true );
495;
496/**
497 * Bricklayer - Cascading Grid Layouts
498 * https://github.com/ademilter/bricklayer
499 * Copyright © 2016 Adem İlter
500 *
501 * Permission is hereby granted, free of charge, to any person obtaining
502 * a copy of this software and associated documentation files (the "Software"),
503 * to deal in the Software without restriction, including without limitation
504 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
505 * and/or sell copies of the Software, and to permit persons to whom the
506 * Software is furnished to do so, subject to the following conditions:
507 *
508 * The above copyright notice and this permission notice shall be included
509 * in all copies or substantial portions of the Software.
510 *
511 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
512 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
513 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
514 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
515 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
516 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
517 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
518 */
519(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
520	var __extends = (this && this.__extends) || function (d, b) {
521			for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
522			function __() { this.constructor = d; }
523			d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
524		};
525	var Bricklayer;
526	(function (Bricklayer) {
527		// Helper Functions
528		function toArray(arrayLike) {
529			return [].slice.call(arrayLike);
530		}
531		function triggerEvent(el, eventName, data) {
532			var event;
533			try {
534				event = new CustomEvent(eventName, { detail: data });
535			}
536			catch(err) {
537				event = document.createEvent('CustomEvent');
538				event.initCustomEvent(eventName, true, true, data);
539			}
540			return el.dispatchEvent(event);
541		}
542		var DEFAULTS = {
543			rulerClassName: "bricklayer-column-sizer",
544			columnClassName: "bricklayer-column"
545		};
546		var SimpleElement = (function () {
547			function SimpleElement(className) {
548				this.element = document.createElement("div");
549				this.element.className = className;
550			}
551			SimpleElement.prototype.destroy = function () {
552				this.element.parentNode.removeChild(this.element);
553			};
554			return SimpleElement;
555		}());
556		var Ruler = (function (_super) {
557			__extends(Ruler, _super);
558			function Ruler() {
559				_super.apply(this, arguments);
560			}
561			Ruler.prototype.getWidth = function () {
562				this.element.setAttribute('style', "\n        display: block;\n        visibility: hidden !important;\n        top: -1000px !important;\n      ");
563				var width = this.element.offsetWidth;
564				this.element.removeAttribute('style');
565				return width;
566			};
567			return Ruler;
568		}(SimpleElement));
569		var Column = (function (_super) {
570			__extends(Column, _super);
571			function Column() {
572				_super.apply(this, arguments);
573			}
574			return Column;
575		}(SimpleElement));
576		var Container = (function () {
577			function Container(element, options) {
578				if (options === void 0) { options = DEFAULTS; }
579				this.element = element;
580				this.options = options;
581				this.build();
582				this.buildResponsive();
583			}
584			Container.prototype.append = function (item) {
585				var _this = this;
586				if (Array.isArray(item)) {
587					item.forEach(function (item) { return _this.append(item); });
588					return;
589				}
590				var column = this.findMinHeightColumn();
591				this.elements = toArray(this.elements).concat([item]);
592				this.applyPosition('append', column, item);
593			};
594			Container.prototype.prepend = function (item) {
595				var _this = this;
596				if (Array.isArray(item)) {
597					item.forEach(function (item) { return _this.prepend(item); });
598					return;
599				}
600				var column = this.findMinHeightColumn();
601				this.elements = [item].concat(toArray(this.elements));
602				this.applyPosition('prepend', column, item);
603			};
604			Container.prototype.on = function (eventName, handler) {
605				// eventName may be:
606				// - breakpoint
607				// - afterAppend
608				// - beforeAppend
609				// - afterPrepend
610				// - beforePrepend
611				this.element.addEventListener("bricklayer." + eventName, handler);
612				return this;
613			};
614			Container.prototype.redraw = function () {
615				var columnCount = this.columnCount;
616				this.checkColumnCount(false);
617				this.reorderElements(columnCount);
618				triggerEvent(this.element, "bricklayer.redraw", { columnCount: columnCount });
619			};
620			Container.prototype.destroy = function () {
621				var _this = this;
622				this.ruler.destroy();
623				toArray(this.elements).forEach(function (el) { return _this.element.appendChild(el); });
624				toArray(this.getColumns()).forEach(function (el) { return el.parentNode.removeChild(el); });
625				triggerEvent(this.element, "bricklayer.destroy", {});
626			};
627			Container.prototype.build = function () {
628				this.ruler = new Ruler(this.options.rulerClassName);
629				this.elements = this.getElementsInOrder();
630				this.element.insertBefore(this.ruler.element, this.element.firstChild);
631			};
632			Container.prototype.buildResponsive = function () {
633				var _this = this;
634				window.addEventListener("resize", function (e) { return _this.checkColumnCount(); });
635				this.checkColumnCount();
636				this.on("breakpoint", function (e) { return _this.reorderElements(e.detail.columnCount); });
637				if (this.columnCount >= 1) {
638					this.reorderElements(this.columnCount);
639				}
640			};
641			Container.prototype.getColumns = function() {
642				var _this = this;
643				return Array.prototype.filter.call( _this.element.children, function( element, index, aElements ) {
644					var classNames = element.className.split( ' ' );
645					return classNames.indexOf( _this.options.columnClassName ) > - 1;
646				} );
647			};
648			Container.prototype.findMinHeightColumn = function () {
649				var allColumns = toArray(this.getColumns());
650				var heights = allColumns.map(function (column) { return column.offsetHeight; });
651				var minHeight = Math.min.apply(null, heights);
652				return allColumns[heights.indexOf(minHeight)];
653			};
654			Container.prototype.getElementsInOrder = function() {
655				var _this = this;
656				return Array.prototype.filter.call( _this.element.children, function( element, index, aElements ) {
657					var classNames = element.className.split( ' ' );
658					return classNames.indexOf( _this.options.columnClassName ) == - 1 && classNames.indexOf( _this.options.rulerClassName == - 1 );
659				} );
660			};
661			Container.prototype.checkColumnCount = function (publish) {
662				if (publish === void 0) { publish = true; }
663				var columnCount = this.getColumnCount();
664				if (this.columnCount !== columnCount) {
665					if (publish) {
666						triggerEvent(this.element, "bricklayer.breakpoint", { columnCount: columnCount });
667					}
668					this.columnCount = columnCount;
669				}
670			};
671			Container.prototype.reorderElements = function (columnCount) {
672				var _this = this;
673				if (columnCount === void 0) { columnCount = 1; }
674				var elements = toArray(this.elements).map(function (item) {
675					var element = item.parentNode ? item.parentNode.removeChild(item) : item;
676					return element;
677				});
678				var columns = this.getColumns();
679				for (var i = 0; i < columns.length; i++) {
680					columns[i].parentNode.removeChild(columns[i]);
681				}
682				for (var i = 0; i < columnCount; i++) {
683					var element = (new Column(this.options.columnClassName)).element;
684					this.element.appendChild(element);
685				}
686				elements.forEach(function (item) {
687					var column = _this.findMinHeightColumn();
688					column.appendChild(item);
689				});
690			};
691			Container.prototype.getColumnCount = function () {
692				var containerWidth = this.element.offsetWidth;
693				var columnWidth = this.ruler.getWidth();
694				if (columnWidth == 0) {
695					return 1;
696				}
697				return Math.round(containerWidth / columnWidth);
698			};
699			Container.prototype.applyPosition = function (pos, column, item) {
700				var _this = this;
701				var trigger = function (timing) {
702					var eventName = timing + pos.charAt(0).toUpperCase() + pos.substr(1);
703					triggerEvent(_this.element, "bricklayer." + eventName, { item: item, column: column });
704				};
705				trigger('before');
706				switch (pos) {
707					case 'append':
708						column.appendChild(item);
709						break;
710					case 'prepend':
711						column.insertBefore(item, column.firstChild);
712						break;
713				}
714				trigger('after');
715			};
716			return Container;
717		}());
718		Bricklayer.Container = Container;
719	})(Bricklayer || (Bricklayer = {}));
720	(function (root, factory) {
721		if (typeof define === 'function' && define.amd) {
722			define(function () { return factory(); });
723		}
724		else if (typeof window !== "undefined" && root === window) {
725			root.Bricklayer = factory();
726		}
727		else if (typeof module === 'object' && module.exports) {
728			module.exports = factory();
729		}
730	}(typeof window !== "undefined" ? window : this, function () {
731		return Bricklayer.Container;
732	}));
733
734},{}]},{},[1]);;
735/*!
736 * modernizr v3.3.1
737 * Build http://modernizr.com/download?-applicationcache-audio-backgroundsize-borderimage-borderradius-boxshadow-canvas-canvastext-cssanimations-csscolumns-cssgradients-cssreflections-csstransforms-csstransforms3d-csstransitions-flexbox-fontface-generatedcontent-geolocation-hashchange-history-hsla-indexeddb-inlinesvg-input-inputtypes-localstorage-multiplebgs-opacity-postmessage-rgba-sessionstorage-smil-svg-svgclippaths-textshadow-video-webgl-websockets-websqldatabase-webworkers-addtest-domprefixes-hasevent-mq-prefixed-prefixes-setclasses-shiv-testallprops-testprop-teststyles-dontmin
738 *
739 * Copyright (c)
740 *  Faruk Ates
741 *  Paul Irish
742 *  Alex Sexton
743 *  Ryan Seddon
744 *  Patrick Kettner
745 *  Stu Cox
746 *  Richard Herrera
747
748 * MIT License
749 */
750
751/*
752 * Modernizr tests which native CSS3 and HTML5 features are available in the
753 * current UA and makes the results available to you in two ways: as properties on
754 * a global `Modernizr` object, and as classes on the `<html>` element. This
755 * information allows you to progressively enhance your pages with a granular level
756 * of control over the experience.
757 */
758
759;(function(window, document, undefined){
760    var classes = [];
761
762
763    var tests = [];
764
765
766    /**
767     *
768     * ModernizrProto is the constructor for Modernizr
769     *
770     * @class
771     * @access public
772     */
773
774    var ModernizrProto = {
775        // The current version, dummy
776        _version: '3.3.1',
777
778        // Any settings that don't work as separate modules
779        // can go in here as configuration.
780        _config: {
781            'classPrefix': '',
782            'enableClasses': true,
783            'enableJSClass': true,
784            'usePrefixes': true
785        },
786
787        // Queue of tests
788        _q: [],
789
790        // Stub these for people who are listening
791        on: function(test, cb) {
792            // I don't really think people should do this, but we can
793            // safe guard it a bit.
794            // -- NOTE:: this gets WAY overridden in src/addTest for actual async tests.
795            // This is in case people listen to synchronous tests. I would leave it out,
796            // but the code to *disallow* sync tests in the real version of this
797            // function is actually larger than this.
798            var self = this;
799            setTimeout(function() {
800                cb(self[test]);
801            }, 0);
802        },
803
804        addTest: function(name, fn, options) {
805            tests.push({name: name, fn: fn, options: options});
806        },
807
808        addAsyncTest: function(fn) {
809            tests.push({name: null, fn: fn});
810        }
811    };
812
813
814
815    // Fake some of Object.create so we can force non test results to be non "own" properties.
816    var Modernizr = function() {};
817    Modernizr.prototype = ModernizrProto;
818
819    // Leak modernizr globally when you `require` it rather than force it here.
820    // Overwrite name so constructor name is nicer :D
821    Modernizr = new Modernizr();
822
823
824    /*!
825     {
826     "name": "Application Cache",
827     "property": "applicationcache",
828     "caniuse": "offline-apps",
829     "tags": ["storage", "offline"],
830     "notes": [{
831     "name": "MDN documentation",
832     "href": "https://developer.mozilla.org/en/docs/HTML/Using_the_application_cache"
833     }],
834     "polyfills": ["html5gears"]
835     }
836     !*/
837    /* DOC
838     Detects support for the Application Cache, for storing data to enable web-based applications run offline.
839
840     The API has been [heavily criticized](http://alistapart.com/article/application-cache-is-a-douchebag) and discussions are underway to address this.
841     */
842
843    Modernizr.addTest('applicationcache', 'applicationCache' in window);
844
845    /*!
846     {
847     "name": "Geolocation API",
848     "property": "geolocation",
849     "caniuse": "geolocation",
850     "tags": ["media"],
851     "notes": [{
852     "name": "MDN documentation",
853     "href": "https://developer.mozilla.org/en-US/docs/WebAPI/Using_geolocation"
854     }],
855     "polyfills": [
856     "joshuabell-polyfill",
857     "webshims",
858     "geo-location-javascript",
859     "geolocation-api-polyfill"
860     ]
861     }
862     !*/
863    /* DOC
864     Detects support for the Geolocation API for users to provide their location to web applications.
865     */
866
867    // geolocation is often considered a trivial feature detect...
868    // Turns out, it's quite tricky to get right:
869    //
870    // Using !!navigator.geolocation does two things we don't want. It:
871    //   1. Leaks memory in IE9: github.com/Modernizr/Modernizr/issues/513
872    //   2. Disables page caching in WebKit: webk.it/43956
873    //
874    // Meanwhile, in Firefox < 8, an about:config setting could expose
875    // a false positive that would throw an exception: bugzil.la/688158
876
877    Modernizr.addTest('geolocation', 'geolocation' in navigator);
878
879    /*!
880     {
881     "name": "History API",
882     "property": "history",
883     "caniuse": "history",
884     "tags": ["history"],
885     "authors": ["Hay Kranen", "Alexander Farkas"],
886     "notes": [{
887     "name": "W3C Spec",
888     "href": "https://www.w3.org/TR/html51/browsers.html#the-history-interface"
889     }, {
890     "name": "MDN documentation",
891     "href": "https://developer.mozilla.org/en-US/docs/Web/API/window.history"
892     }],
893     "polyfills": ["historyjs", "html5historyapi"]
894     }
895     !*/
896    /* DOC
897     Detects support for the History API for manipulating the browser session history.
898     */
899
900    Modernizr.addTest('history', function() {
901        // Issue #733
902        // The stock browser on Android 2.2 & 2.3, and 4.0.x returns positive on history support
903        // Unfortunately support is really buggy and there is no clean way to detect
904        // these bugs, so we fall back to a user agent sniff :(
905        var ua = navigator.userAgent;
906
907        // We only want Android 2 and 4.0, stock browser, and not Chrome which identifies
908        // itself as 'Mobile Safari' as well, nor Windows Phone (issue #1471).
909        if ((ua.indexOf('Android 2.') !== -1 ||
910            (ua.indexOf('Android 4.0') !== -1)) &&
911            ua.indexOf('Mobile Safari') !== -1 &&
912            ua.indexOf('Chrome') === -1 &&
913            ua.indexOf('Windows Phone') === -1) {
914            return false;
915        }
916
917        // Return the regular check
918        return (window.history && 'pushState' in window.history);
919    });
920
921    /*!
922     {
923     "name": "postMessage",
924     "property": "postmessage",
925     "caniuse": "x-doc-messaging",
926     "notes": [{
927     "name": "W3C Spec",
928     "href": "http://www.w3.org/TR/html5/comms.html#posting-messages"
929     }],
930     "polyfills": ["easyxdm", "postmessage-jquery"]
931     }
932     !*/
933    /* DOC
934     Detects support for the `window.postMessage` protocol for cross-document messaging.
935     */
936
937    Modernizr.addTest('postmessage', 'postMessage' in window);
938
939    /*!
940     {
941     "name": "SVG",
942     "property": "svg",
943     "caniuse": "svg",
944     "tags": ["svg"],
945     "authors": ["Erik Dahlstrom"],
946     "polyfills": [
947     "svgweb",
948     "raphael",
949     "amplesdk",
950     "canvg",
951     "svg-boilerplate",
952     "sie",
953     "dojogfx",
954     "fabricjs"
955     ]
956     }
957     !*/
958    /* DOC
959     Detects support for SVG in `<embed>` or `<object>` elements.
960     */
961
962    Modernizr.addTest('svg', !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect);
963
964    /*!
965     {
966     "name": "WebSockets Support",
967     "property": "websockets",
968     "authors": ["Phread [fearphage]", "Mike Sherov [mikesherov]", "Burak Yigit Kaya [BYK]"],
969     "caniuse": "websockets",
970     "tags": ["html5"],
971     "warnings": [
972     "This test will reject any old version of WebSockets even if it is not prefixed such as in Safari 5.1"
973     ],
974     "notes": [{
975     "name": "CLOSING State and Spec",
976     "href": "https://www.w3.org/TR/websockets/#the-websocket-interface"
977     }],
978     "polyfills": [
979     "sockjs",
980     "socketio",
981     "kaazing-websocket-gateway",
982     "websocketjs",
983     "atmosphere",
984     "graceful-websocket",
985     "portal",
986     "datachannel"
987     ]
988     }
989     !*/
990
991    Modernizr.addTest('websockets', 'WebSocket' in window && window.WebSocket.CLOSING === 2);
992
993    /*!
994     {
995     "name": "Local Storage",
996     "property": "localstorage",
997     "caniuse": "namevalue-storage",
998     "tags": ["storage"],
999     "knownBugs": [],
1000     "notes": [],
1001     "warnings": [],
1002     "polyfills": [
1003     "joshuabell-polyfill",
1004     "cupcake",
1005     "storagepolyfill",
1006     "amplifyjs",
1007     "yui-cacheoffline"
1008     ]
1009     }
1010     !*/
1011
1012    // In FF4, if disabled, window.localStorage should === null.
1013
1014    // Normally, we could not test that directly and need to do a
1015    //   `('localStorage' in window) && ` test first because otherwise Firefox will
1016    //   throw bugzil.la/365772 if cookies are disabled
1017
1018    // Also in iOS5 Private Browsing mode, attempting to use localStorage.setItem
1019    // will throw the exception:
1020    //   QUOTA_EXCEEDED_ERROR DOM Exception 22.
1021    // Peculiarly, getItem and removeItem calls do not throw.
1022
1023    // Because we are forced to try/catch this, we'll go aggressive.
1024
1025    // Just FWIW: IE8 Compat mode supports these features completely:
1026    //   www.quirksmode.org/dom/html5.html
1027    // But IE8 doesn't support either with local files
1028
1029    Modernizr.addTest('localstorage', function() {
1030        var mod = 'modernizr';
1031        try {
1032            localStorage.setItem(mod, mod);
1033            localStorage.removeItem(mod);
1034            return true;
1035        } catch (e) {
1036            return false;
1037        }
1038    });
1039
1040    /*!
1041     {
1042     "name": "Session Storage",
1043     "property": "sessionstorage",
1044     "tags": ["storage"],
1045     "polyfills": ["joshuabell-polyfill", "cupcake", "sessionstorage"]
1046     }
1047     !*/
1048
1049    // Because we are forced to try/catch this, we'll go aggressive.
1050
1051    // Just FWIW: IE8 Compat mode supports these features completely:
1052    //   www.quirksmode.org/dom/html5.html
1053    // But IE8 doesn't support either with local files
1054    Modernizr.addTest('sessionstorage', function() {
1055        var mod = 'modernizr';
1056        try {
1057            sessionStorage.setItem(mod, mod);
1058            sessionStorage.removeItem(mod);
1059            return true;
1060        } catch (e) {
1061            return false;
1062        }
1063    });
1064
1065    /*!
1066     {
1067     "name": "Web SQL Database",
1068     "property": "websqldatabase",
1069     "caniuse": "sql-storage",
1070     "tags": ["storage"]
1071     }
1072     !*/
1073
1074    // Chrome incognito mode used to throw an exception when using openDatabase
1075    // It doesn't anymore.
1076    Modernizr.addTest('websqldatabase', 'openDatabase' in window);
1077
1078    /*!
1079     {
1080     "name": "Web Workers",
1081     "property": "webworkers",
1082     "caniuse" : "webworkers",
1083     "tags": ["performance", "workers"],
1084     "notes": [{
1085     "name": "W3C Reference",
1086     "href": "https://www.w3.org/TR/workers/"
1087     }, {
1088     "name": "HTML5 Rocks article",
1089     "href": "http://www.html5rocks.com/en/tutorials/workers/basics/"
1090     }, {
1091     "name": "MDN documentation",
1092     "href": "https://developer.mozilla.org/en-US/docs/Web/Guide/Performance/Using_web_workers"
1093     }],
1094     "polyfills": ["fakeworker", "html5shims"]
1095     }
1096     !*/
1097    /* DOC
1098     Detects support for the basic `Worker` API from the Web Workers spec. Web Workers provide a simple means for web content to run scripts in background threads.
1099     */
1100
1101    Modernizr.addTest('webworkers', 'Worker' in window);
1102
1103
1104    /**
1105     * List of property values to set for css tests. See ticket #21
1106     * http://git.io/vUGl4
1107     *
1108     * @memberof Modernizr
1109     * @name Modernizr._prefixes
1110     * @optionName Modernizr._prefixes
1111     * @optionProp prefixes
1112     * @access public
1113     * @example
1114     *
1115     * Modernizr._prefixes is the internal list of prefixes that we test against
1116     * inside of things like [prefixed](#modernizr-prefixed) and [prefixedCSS](#-code-modernizr-prefixedcss). It is simply
1117     * an array of kebab-case vendor prefixes you can use within your code.
1118     *
1119     * Some common use cases include
1120     *
1121     * Generating all possible prefixed version of a CSS property
1122     * ```js
1123     * var rule = Modernizr._prefixes.join('transform: rotate(20deg); ');
1124     *
1125     * rule === 'transform: rotate(20deg); webkit-transform: rotate(20deg); moz-transform: rotate(20deg); o-transform: rotate(20deg); ms-transform: rotate(20deg);'
1126     * ```
1127     *
1128     * Generating all possible prefixed version of a CSS value
1129     * ```js
1130     * rule = 'display:' +  Modernizr._prefixes.join('flex; display:') + 'flex';
1131     *
1132     * rule === 'display:flex; display:-webkit-flex; display:-moz-flex; display:-o-flex; display:-ms-flex; display:flex'
1133     * ```
1134     */
1135
1136    // we use ['',''] rather than an empty array in order to allow a pattern of .`join()`ing prefixes to test
1137    // values in feature detects to continue to work
1138    var prefixes = (ModernizrProto._config.usePrefixes ? ' -webkit- -moz- -o- -ms- '.split(' ') : ['','']);
1139
1140    // expose these for the plugin API. Look in the source for how to join() them against your input
1141    ModernizrProto._prefixes = prefixes;
1142
1143
1144
1145    /**
1146     * is returns a boolean if the typeof an obj is exactly type.
1147     *
1148     * @access private
1149     * @function is
1150     * @param {*} obj - A thing we want to check the type of
1151     * @param {string} type - A string to compare the typeof against
1152     * @returns {boolean}
1153     */
1154
1155    function is(obj, type) {
1156        return typeof obj === type;
1157    }
1158    ;
1159
1160    /**
1161     * Run through all tests and detect their support in the current UA.
1162     *
1163     * @access private
1164     */
1165
1166    function testRunner() {
1167        var featureNames;
1168        var feature;
1169        var aliasIdx;
1170        var result;
1171        var nameIdx;
1172        var featureName;
1173        var featureNameSplit;
1174
1175        for (var featureIdx in tests) {
1176            if (tests.hasOwnProperty(featureIdx)) {
1177                featureNames = [];
1178                feature = tests[featureIdx];
1179                // run the test, throw the return value into the Modernizr,
1180                // then based on that boolean, define an appropriate className
1181                // and push it into an array of classes we'll join later.
1182                //
1183                // If there is no name, it's an 'async' test that is run,
1184                // but not directly added to the object. That should
1185                // be done with a post-run addTest call.
1186                if (feature.name) {
1187                    featureNames.push(feature.name.toLowerCase());
1188
1189                    if (feature.options && feature.options.aliases && feature.options.aliases.length) {
1190                        // Add all the aliases into the names list
1191                        for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) {
1192                            featureNames.push(feature.options.aliases[aliasIdx].toLowerCase());
1193                        }
1194                    }
1195                }
1196
1197                // Run the test, or use the raw value if it's not a function
1198                result = is(feature.fn, 'function') ? feature.fn() : feature.fn;
1199
1200
1201                // Set each of the names on the Modernizr object
1202                for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) {
1203                    featureName = featureNames[nameIdx];
1204                    // Support dot properties as sub tests. We don't do checking to make sure
1205                    // that the implied parent tests have been added. You must call them in
1206                    // order (either in the test, or make the parent test a dependency).
1207                    //
1208                    // Cap it to TWO to make the logic simple and because who needs that kind of subtesting
1209                    // hashtag famous last words
1210                    featureNameSplit = featureName.split('.');
1211
1212                    if (featureNameSplit.length === 1) {
1213                        Modernizr[featureNameSplit[0]] = result;
1214                    } else {
1215                        // cast to a Boolean, if not one already
1216                        /* jshint -W053 */
1217                        if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
1218                            Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
1219                        }
1220
1221                        Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result;
1222                    }
1223
1224                    classes.push((result ? '' : 'no-') + featureNameSplit.join('-'));
1225                }
1226            }
1227        }
1228    }
1229    ;
1230
1231    /**
1232     * docElement is a convenience wrapper to grab the root element of the document
1233     *
1234     * @access private
1235     * @returns {HTMLElement|SVGElement} The root element of the document
1236     */
1237
1238    var docElement = document.documentElement;
1239
1240
1241    /**
1242     * A convenience helper to check if the document we are running in is an SVG document
1243     *
1244     * @access private
1245     * @returns {boolean}
1246     */
1247
1248    var isSVG = docElement.nodeName.toLowerCase() === 'svg';
1249
1250
1251    /**
1252     * setClasses takes an array of class names and adds them to the root element
1253     *
1254     * @access private
1255     * @function setClasses
1256     * @param {string[]} classes - Array of class names
1257     */
1258
1259    // Pass in an and array of class names, e.g.:
1260    //  ['no-webp', 'borderradius', ...]
1261    function setClasses(classes) {
1262        var className = docElement.className;
1263        var classPrefix = Modernizr._config.classPrefix || '';
1264
1265        if (isSVG) {
1266            className = className.baseVal;
1267        }
1268
1269        // Change `no-js` to `js` (independently of the `enableClasses` option)
1270        // Handle classPrefix on this too
1271        if (Modernizr._config.enableJSClass) {
1272            var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)');
1273            className = className.replace(reJS, '$1' + classPrefix + 'js$2');
1274        }
1275
1276        if (Modernizr._config.enableClasses) {
1277            // Add the new classes
1278            className += ' ' + classPrefix + classes.join(' ' + classPrefix);
1279            isSVG ? docElement.className.baseVal = className : docElement.className = className;
1280        }
1281
1282    }
1283
1284    ;
1285
1286    /**
1287     * @optionName html5shiv
1288     * @optionProp html5shiv
1289     */
1290
1291    // Take the html5 variable out of the html5shiv scope so we can return it.
1292    var html5;
1293    if (!isSVG) {
1294        /**
1295         * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
1296         */
1297        ;(function(window, document) {
1298            /*jshint evil:true */
1299            /** version */
1300            var version = '3.7.3';
1301
1302            /** Preset options */
1303            var options = window.html5 || {};
1304
1305            /** Used to skip problem elements */
1306            var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
1307
1308            /** Not all elements can be cloned in IE **/
1309            var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;
1310
1311            /** Detect whether the browser supports default html5 styles */
1312            var supportsHtml5Styles;
1313
1314            /** Name of the expando, to work with multiple documents or to re-shiv one document */
1315            var expando = '_html5shiv';
1316
1317            /** The id for the the documents expando */
1318            var expanID = 0;
1319
1320            /** Cached data for each document */
1321            var expandoData = {};
1322
1323            /** Detect whether the browser supports unknown elements */
1324            var supportsUnknownElements;
1325
1326            (function() {
1327                try {
1328                    var a = document.createElement('a');
1329                    a.innerHTML = '<xyz></xyz>';
1330                    //if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles
1331                    supportsHtml5Styles = ('hidden' in a);
1332
1333                    supportsUnknownElements = a.childNodes.length == 1 || (function() {
1334                            // assign a false positive if unable to shiv
1335                            (document.createElement)('a');
1336                            var frag = document.createDocumentFragment();
1337                            return (
1338                                typeof frag.cloneNode == 'undefined' ||
1339                                typeof frag.createDocumentFragment == 'undefined' ||
1340                                typeof frag.createElement == 'undefined'
1341                            );
1342                        }());
1343                } catch(e) {
1344                    // assign a false positive if detection fails => unable to shiv
1345                    supportsHtml5Styles = true;
1346                    supportsUnknownElements = true;
1347                }
1348
1349            }());
1350
1351            /*--------------------------------------------------------------------------*/
1352
1353            /**
1354             * Creates a style sheet with the given CSS text and adds it to the document.
1355             * @private
1356             * @param {Document} ownerDocument The document.
1357             * @param {String} cssText The CSS text.
1358             * @returns {StyleSheet} The style element.
1359             */
1360            function addStyleSheet(ownerDocument, cssText) {
1361                var p = ownerDocument.createElement('p'),
1362                    parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
1363
1364                p.innerHTML = 'x<style>' + cssText + '</style>';
1365                return parent.insertBefore(p.lastChild, parent.firstChild);
1366            }
1367
1368            /**
1369             * Returns the value of `html5.elements` as an array.
vendor: 6,804 bytes, lines 1370-1527
1370             * @private
1371             * @returns {Array} An array of shived element node names.
1372             */
1373            function getElements() {
1374                var elements = html5.elements;
1375                return typeof elements == 'string' ? elements.split(' ') : elements;
1376            }
1377
1378            /**
1379             * Extends the built-in list of html5 elements
1380             * @memberOf html5
1381             * @param {String|Array} newElements whitespace separated list or array of new element names to shiv
1382             * @param {Document} ownerDocument The context document.
1383             */
1384            function addElements(newElements, ownerDocument) {
1385                var elements = html5.elements;
1386                if(typeof elements != 'string'){
1387                    elements = elements.join(' ');
1388                }
1389                if(typeof newElements != 'string'){
1390                    newElements = newElements.join(' ');
1391                }
1392                html5.elements = elements +' '+ newElements;
1393                shivDocument(ownerDocument);
1394            }
1395
1396            /**
1397             * Returns the data associated to the given document
1398             * @private
1399             * @param {Document} ownerDocument The document.
1400             * @returns {Object} An object of data.
1401             */
1402            function getExpandoData(ownerDocument) {
1403                var data = expandoData[ownerDocument[expando]];
1404                if (!data) {
1405                    data = {};
1406                    expanID++;
1407                    ownerDocument[expando] = expanID;
1408                    expandoData[expanID] = data;
1409                }
1410                return data;
1411            }
1412
1413            /**
1414             * returns a shived element for the given nodeName and document
1415             * @memberOf html5
1416             * @param {String} nodeName name of the element
1417             * @param {Document|DocumentFragment} ownerDocument The context document.
1418             * @returns {Object} The shived element.
1419             */
1420            function createElement(nodeName, ownerDocument, data){
1421                if (!ownerDocument) {
1422                    ownerDocument = document;
1423                }
1424                if(supportsUnknownElements){
1425                    return ownerDocument.createElement(nodeName);
1426                }
1427                if (!data) {
1428                    data = getExpandoData(ownerDocument);
1429                }
1430                var node;
1431
1432                if (data.cache[nodeName]) {
1433                    node = data.cache[nodeName].cloneNode();
1434                } else if (saveClones.test(nodeName)) {
1435                    node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
1436                } else {
1437                    node = data.createElem(nodeName);
1438                }
1439
1440                // Avoid adding some elements to fragments in IE < 9 because
1441                // * Attributes like `name` or `type` cannot be set/changed once an element
1442                //   is inserted into a document/fragment
1443                // * Link elements with `src` attributes that are inaccessible, as with
1444                //   a 403 response, will cause the tab/window to crash
1445                // * Script elements appended to fragments will execute when their `src`
1446                //   or `text` property is set
1447                return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node;
1448            }
1449
1450            /**
1451             * returns a shived DocumentFragment for the given document
1452             * @memberOf html5
1453             * @param {Document} ownerDocument The context document.
1454             * @returns {Object} The shived DocumentFragment.
1455             */
1456            function createDocumentFragment(ownerDocument, data){
1457                if (!ownerDocument) {
1458                    ownerDocument = document;
1459                }
1460                if(supportsUnknownElements){
1461                    return ownerDocument.createDocumentFragment();
1462                }
1463                data = data || getExpandoData(ownerDocument);
1464                var clone = data.frag.cloneNode(),
1465                    i = 0,
1466                    elems = getElements(),
1467                    l = elems.length;
1468                for(;i<l;i++){
1469                    clone.createElement(elems[i]);
1470                }
1471                return clone;
1472            }
1473
1474            /**
1475             * Shivs the `createElement` and `createDocumentFragment` methods of the document.
1476             * @private
1477             * @param {Document|DocumentFragment} ownerDocument The document.
1478             * @param {Object} data of the document.
1479             */
1480            function shivMethods(ownerDocument, data) {
1481                if (!data.cache) {
1482                    data.cache = {};
1483                    data.createElem = ownerDocument.createElement;
1484                    data.createFrag = ownerDocument.createDocumentFragment;
1485                    data.frag = data.createFrag();
1486                }
1487
1488
1489                ownerDocument.createElement = function(nodeName) {
1490                    //abort shiv
1491                    if (!html5.shivMethods) {
1492                        return data.createElem(nodeName);
1493                    }
1494                    return createElement(nodeName, ownerDocument, data);
1495                };
1496
1497                ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
1498                    'var n=f.cloneNode(),c=n.createElement;' +
1499                    'h.shivMethods&&(' +
1500                    // unroll the `createElement` calls
1501                    getElements().join().replace(/[\w\-:]+/g, function(nodeName) {
1502                        data.createElem(nodeName);
1503                        data.frag.createElement(nodeName);
1504                        return 'c("' + nodeName + '")';
1505                    }) +
1506                    ');return n}'
1507                )(html5, data.frag);
1508            }
1509
1510            /*--------------------------------------------------------------------------*/
1511
1512            /**
1513             * Shivs the given document.
1514             * @memberOf html5
1515             * @param {Document} ownerDocument The document to shiv.
1516             * @returns {Document} The shived document.
1517             */
1518            function shivDocument(ownerDocument) {
1519                if (!ownerDocument) {
1520                    ownerDocument = document;
1521                }
1522                var data = getExpandoData(ownerDocument);
1523
1524                if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) {
1525                    data.hasCSS = !!addStyleSheet(ownerDocument,
1526                        // corrects block display not defined in IE6/7/8/9
1527                        'article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{dis
1527play:block}' +
1528                        // adds styling not present in IE6/7/8/9
1529                        'mark{background:#FF0;color:#000}' +
1530                        // hides non-rendered elements
1531                        'template{display:none}'
1532                    );
1533                }
1534                if (!supportsUnknownElements) {
1535                    shivMethods(ownerDocument, data);
1536                }
1537                return ownerDocument;
1538            }
1539
1540            /*--------------------------------------------------------------------------*/
1541
1542            /**
1543             * The `html5` object is exposed so that more elements can be shived and
1544             * existing shiving can be detected on iframes.
1545             * @type Object
1546             * @example
1547             *
1548             * // options can be changed before the script is included
1549             * html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false };
1550             */
1551            var html5 = {
1552
1553                /**
1554                 * An array or space separated string of node names of the elements to shiv.
1555                 * @memberOf html5
1556                 * @type Array|String
1557                 */
1558                'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video',
1559
1560                /**
1561                 * current version of html5shiv
1562                 */
1563                'version': version,
1564
1565                /**
1566                 * A flag to indicate that the HTML5 style sheet should be inserted.
1567                 * @memberOf html5
1568                 * @type Boolean
1569                 */
1570                'shivCSS': (options.shivCSS !== false),
1571
1572                /**
1573                 * Is equal to true if a browser supports creating unknown/HTML5 elements
1574                 * @memberOf html5
1575                 * @type boolean
1576                 */
1577                'supportsUnknownElements': supportsUnknownElements,
1578
1579                /**
1580                 * A flag to indicate that the document's `createElement` and `createDocumentFragment`
1581                 * methods should be overwritten.
1582                 * @memberOf html5
1583                 * @type Boolean
1584                 */
1585                'shivMethods': (options.shivMethods !== false),
1586
1587                /**
1588                 * A string to describe the type of `html5` object ("default" or "default print").
1589                 * @memberOf html5
1590                 * @type String
1591                 */
1592                'type': 'default',
1593
1594                // shivs the document according to the specified `html5` object options
1595                'shivDocument': shivDocument,
1596
1597                //creates a shived element
1598                createElement: createElement,
1599
1600                //creates a shived documentFragment
1601                createDocumentFragment: createDocumentFragment,
1602
1603                //extends list of elements
1604                addElements: addElements
1605            };
1606
1607            /*--------------------------------------------------------------------------*/
1608
1609            // expose html5
1610            window.html5 = html5;
1611
1612            // shiv the document
1613            shivDocument(document);
1614
1615            if(typeof module == 'object' && module.exports){
1616                module.exports = html5;
1617            }
1618
1619        }(typeof window !== "undefined" ? window : this, document));
1620    }
1621    ;
1622
1623    /**
1624     * If the browsers follow the spec, then they would expose vendor-specific style as:
1625     *   elem.style.WebkitBorderRadius
1626     * instead of something like the following, which would be technically incorrect:
1627     *   elem.style.webkitBorderRadius
1628
1629     * Webkit ghosts their properties in lowercase but Opera & Moz do not.
1630     * Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
1631     *   erik.eae.net/archives/2008/03/10/21.48.10/
1632
1633     * More here: github.com/Modernizr/Modernizr/issues/issue/21
1634     *
1635     * @access private
1636     * @returns {string} The string representing the vendor-specific style properties
1637     */
1638
1639    var omPrefixes = 'Moz O ms Webkit';
1640
1641
1642    /**
1643     * List of JavaScript DOM values used for tests
1644     *
1645     * @memberof Modernizr
1646     * @name Modernizr._domPrefixes
1647     * @optionName Modernizr._domPrefixes
1648     * @optionProp domPrefixes
1649     * @access public
1650     * @example
1651     *
1652     * Modernizr._domPrefixes is exactly the same as [_prefixes](#modernizr-_prefixes), but rather
1653     * than kebab-case properties, all properties are their Capitalized variant
1654     *
1655     * ```js
1656     * Modernizr._domPrefixes === [ "Moz", "O", "ms", "Webkit" ];
1657     * ```
1658     */
1659
1660    var domPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.toLowerCase().split(' ') : []);
1661    ModernizrProto._domPrefixes = domPrefixes;
1662
1663
1664    /**
1665     * hasOwnProp is a shim for hasOwnProperty that is needed for Safari 2.0 support
1666     *
1667     * @author kangax
1668     * @access private
1669     * @function hasOwnProp
1670     * @param {object} object - The object to check for a property
1671     * @param {string} property - The property to check for
1672     * @returns {boolean}
1673     */
1674
1675    // hasOwnProperty shim by kangax needed for Safari 2.0 support
1676    var hasOwnProp;
1677
1678    (function() {
1679        var _hasOwnProperty = ({}).hasOwnProperty;
1680        /* istanbul ignore else */
1681        /* we have no way of testing IE 5.5 or safari 2,
1682         * so just assume the else gets hit */
1683        if (!is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined')) {
1684            hasOwnProp = function(object, property) {
1685                return _hasOwnProperty.call(object, property);
1686            };
1687        }
1688        else {
1689            hasOwnProp = function(object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
1690                return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
1691            };
1692        }
1693    })();
1694
1695
1696
1697
1698    // _l tracks listeners for async tests, as well as tests that execute after the initial run
1699    ModernizrProto._l = {};
1700
1701    /**
1702     * Modernizr.on is a way to listen for the completion of async tests. Being
1703     * asynchronous, they may not finish before your scripts run. As a result you
1704     * will get a possibly false negative `undefined` value.
1705     *
1706     * @memberof Modernizr
1707     * @name Modernizr.on
1708     * @access public
1709     * @function on
1710     * @param {string} feature - String name of the feature detect
1711     * @param {function} cb - Callback function returning a Boolean - true if feature is supported, false if not
1712     * @example
1713     *
1714     * ```js
1715     * Modernizr.on('flash', function( result ) {
1716   *   if (result) {
1717   *    // the browser has flash
1718   *   } else {
1719   *     // the browser does not have flash
1720   *   }
1721   * });
1722     * ```
1723     */
1724
1725    ModernizrProto.on = function(feature, cb) {
1726        // Create the list of listeners if it doesn't exist
1727        if (!this._l[feature]) {
1728            this._l[feature] = [];
1729        }
1730
1731        // Push this test on to the listener list
1732        this._l[feature].push(cb);
1733
1734        // If it's already been resolved, trigger it on next tick
1735        if (Modernizr.hasOwnProperty(feature)) {
1736            // Next Tick
1737            setTimeout(function() {
1738                Modernizr._trigger(feature, Modernizr[feature]);
1739            }, 0);
1740        }
1741    };
1742
1743    /**
1744     * _trigger is the private function used to signal test completion and run any
1745     * callbacks registered through [Modernizr.on](#modernizr-on)
1746     *
1747     * @memberof Modernizr
1748     * @name Modernizr._trigger
1749     * @access private
1750     * @function _trigger
1751     * @param {string} feature - string name of the feature detect
1752     * @param {function|boolean} [res] - A feature detection function, or the boolean =
1753     * result of a feature detection function
1754     */
1755
1756    ModernizrProto._trigger = function(feature, res) {
1757        if (!this._l[feature]) {
1758            return;
1759        }
1760
1761        var cbs = this._l[feature];
1762
1763        // Force async
1764        setTimeout(function() {
1765            var i, cb;
1766            for (i = 0; i < cbs.length; i++) {
1767                cb = cbs[i];
1768                cb(res);
1769            }
1770        }, 0);
1771
1772        // Don't trigger these again
1773        delete this._l[feature];
1774    };
1775
1776    /**
1777     * addTest allows you to define your own feature detects that are not currently
1778     * included in Modernizr (under the covers it's the exact same code Modernizr
1779     * uses for its own [feature detections](https://github.com/Modernizr/Modernizr/tree/master/feature-detects)). Just like the offical detects, the result
1780     * will be added onto the Modernizr object, as well as an appropriate className set on
1781     * the html element when configured to do so
1782     *
1783     * @memberof Modernizr
1784     * @name Modernizr.addTest
1785     * @optionName Modernizr.addTest()
1786     * @optionProp addTest
1787     * @access public
1788     * @function addTest
1789     * @param {string|object} feature - The string name of the feature detect, or an
1790     * object of feature detect names and test
1791     * @param {function|boolean} test - Function returning true if feature is supported,
1792     * false if not. Otherwise a boolean representing the results of a feature detection
1793     * @example
1794     *
1795     * The most common way of creating your own feature detects is by calling
1796     * `Modernizr.addTest` with a string (preferably just lowercase, without any
1797     * punctuation), and a function you want executed that will return a boolean result
1798     *
1799     * ```js
1800     * Modernizr.addTest('itsTuesday', function() {
1801   *  var d = new Date();
1802   *  return d.getDay() === 2;
1803   * });
1804     * ```
1805     *
1806     * When the above is run, it will set Modernizr.itstuesday to `true` when it is tuesday,
1807     * and to `false` every other day of the week. One thing to notice is that the names of
1808     * feature detect functions are always lowercased when added to the Modernizr object. That
1809     * means that `Modernizr.itsTuesday` will not exist, but `Modernizr.itstuesday` will.
1810     *
1811     *
1812     *  Since we only look at the returned value from any feature detection function,
1813     *  you do not need to actually use a function. For simple detections, just passing
1814     *  in a statement that will return a boolean value works just fine.
1815     *
1816     * ```js
1817     * Modernizr.addTest('hasJquery', 'jQuery' in window);
1818     * ```
1819     *
1820     * Just like before, when the above runs `Modernizr.hasjquery` will be true if
1821     * jQuery has been included on the page. Not using a function saves a small amount
1822     * of overhead for the browser, as well as making your code much more readable.
1823     *
1824     * Finally, you also have the ability to pass in an object of feature names and
1825     * their tests. This is handy if you want to add multiple detections in one go.
1826     * The keys should always be a string, and the value can be either a boolean or
1827     * function that returns a boolean.
1828     *
1829     * ```js
1830     * var detects = {
1831   *  'hasjquery': 'jQuery' in window,
1832   *  'itstuesday': function() {
1833   *    var d = new Date();
1834   *    return d.getDay() === 2;
1835   *  }
1836   * }
1837     *
1838     * Modernizr.addTest(detects);
1839     * ```
1840     *
1841     * There is really no difference between the first methods and this one, it is
1842     * just a convenience to let you write more readable code.
1843     */
1844
1845    function addTest(feature, test) {
1846
1847        if (typeof feature == 'object') {
1848            for (var key in feature) {
1849                if (hasOwnProp(feature, key)) {
1850                    addTest(key, feature[ key ]);
1851                }
1852            }
1853        } else {
1854
1855            feature = feature.toLowerCase();
1856            var featureNameSplit = feature.split('.');
1857            var last = Modernizr[featureNameSplit[0]];
1858
1859            // Again, we don't check for parent test existence. Get that right, though.
1860            if (featureNameSplit.length == 2) {
1861                last = last[featureNameSplit[1]];
1862            }
1863
1864            if (typeof last != 'undefined') {
1865                // we're going to quit if you're trying to overwrite an existing test
1866                // if we were to allow it, we'd do this:
1867                //   var re = new RegExp("\\b(no-)?" + feature + "\\b");
1868                //   docElement.className = docElement.className.replace( re, '' );
1869                // but, no rly, stuff 'em.
1870                return Modernizr;
1871            }
1872
1873            test = typeof test == 'function' ? test() : test;
1874
1875            // Set the value (this is the magic, right here).
1876            if (featureNameSplit.length == 1) {
1877                Modernizr[featureNameSplit[0]] = test;
1878            } else {
1879                // cast to a Boolean, if not one already
1880                /* jshint -W053 */
1881                if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
1882                    Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
1883                }
1884
1885                Modernizr[featureNameSplit[0]][featureNameSplit[1]] = test;
1886            }
1887
1888            // Set a single class (either `feature` or `no-feature`)
1889            /* jshint -W041 */
1890            setClasses([(!!test && test != false ? '' : 'no-') + featureNameSplit.join('-')]);
1891            /* jshint +W041 */
1892
1893            // Trigger the event
1894            Modernizr._trigger(feature, test);
1895        }
1896
1897        return Modernizr; // allow chaining.
1898    }
1899
1900    // After all the tests are run, add self to the Modernizr prototype
1901    Modernizr._q.push(function() {
1902        ModernizrProto.addTest = addTest;
1903    });
1904
1905
1906
1907
1908    /**
1909     * createElement is a convenience wrapper around document.createElement. Since we
1910     * use createElement all over the place, this allows for (slightly) smaller code
1911     * as well as abstracting away issues with creating elements in contexts other than
1912     * HTML documents (e.g. SVG documents).
1913     *
1914     * @access private
1915     * @function createElement
1916     * @returns {HTMLElement|SVGElement} An HTML or SVG element
1917     */
1918
1919    function createElement() {
1920        if (typeof document.createElement !== 'function') {
1921            // This is the case in IE7, where the type of createElement is "object".
1922            // For this reason, we cannot call apply() as Object is not a Function.
1923            return document.createElement(arguments[0]);
1924        } else if (isSVG) {
1925            return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]);
1926        } else {
1927            return document.createElement.apply(document, arguments);
1928        }
1929    }
1930
1931    ;
1932
1933    /**
1934     * Modernizr.hasEvent() detects support for a given event
1935     *
1936     * @memberof Modernizr
1937     * @name Modernizr.hasEvent
1938     * @optionName Modernizr.hasEvent()
1939     * @optionProp hasEvent
1940     * @access public
1941     * @function hasEvent
1942     * @param  {string|*} eventName - the name of an event to test for (e.g. "resize")
1943     * @param  {Element|string} [element=HTMLDivElement] - is the element|document|window|tagName to test on
1944     * @returns {boolean}
1945     * @example
1946     *  `Modernizr.hasEvent` lets you determine if the browser supports a supplied event.
1947     *  By default, it does this detection on a div element
1948     *
1949     * ```js
1950     *  hasEvent('blur') // true;
1951     * ```
1952     *
1953     * However, you are able to give an object as a second argument to hasEvent to
1954     * detect an event on something other than a div.
1955     *
1956     * ```js
1957     *  hasEvent('devicelight', window) // true;
1958     * ```
1959     *
1960     */
1961
1962    var hasEvent = (function() {
1963
1964        // Detect whether event support can be detected via `in`. Test on a DOM element
1965        // using the "blur" event b/c it should always exist. bit.ly/event-detection
1966        var needsFallback = !('onblur' in document.documentElement);
1967
1968        function inner(eventName, element) {
1969
1970            var isSupported;
1971            if (!eventName) { return false; }
1972            if (!element || typeof element === 'string') {
1973                element = createElement(element || 'div');
1974            }
1975
1976            // Testing via the `in` operator is sufficient for modern browsers and IE.
1977            // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and
1978            // "resize", whereas `in` "catches" those.
1979            eventName = 'on' + eventName;
1980            isSupported = eventName in element;
1981
1982            // Fallback technique for old Firefox - bit.ly/event-detection
1983            if (!isSupported && needsFallback) {
1984                if (!element.setAttribute) {
1985                    // Switch to generic element if it lacks `setAttribute`.
1986                    // It could be the `document`, `window`, or something else.
1987                    element = createElement('div');
1988                }
1989
1990                element.setAttribute(eventName, '');
1991                isSupported = typeof element[eventName] === 'function';
1992
1993                if (element[eventName] !== undefined) {
1994                    // If property was created, "remove it" by setting value to `undefined`.
1995                    element[eventName] = undefined;
1996                }
1997                element.removeAttribute(eventName);
1998            }
1999
2000            return isSupported;
2001        }
2002        return inner;
2003    })();
2004
2005
2006    ModernizrProto.hasEvent = hasEvent;
2007
2008    /*!
2009     {
2010     "name": "Hashchange event",
2011     "property": "hashchange",
2012     "caniuse": "hashchange",
2013     "tags": ["history"],
2014     "notes": [{
2015     "name": "MDN documentation",
2016     "href": "https://developer.mozilla.org/en-US/docs/Web/API/window.onhashchange"
2017     }],
2018     "polyfills": [
2019     "jquery-hashchange",
2020     "moo-historymanager",
2021     "jquery-ajaxy",
2022     "hasher",
2023     "shistory"
2024     ]
2025     }
2026     !*/
2027    /* DOC
2028     Detects support for the `hashchange` event, fired when the current location fragment changes.
2029     */
2030
2031    Modernizr.addTest('hashchange', function() {
2032        if (hasEvent('hashchange', window) === false) {
2033            return false;
2034        }
2035
2036        // documentMode logic from YUI to filter out IE8 Compat Mode
2037        //   which false positives.
2038        return (document.documentMode === undefined || document.documentMode > 7);
2039    });
2040
2041    /*!
2042     {
2043     "name" : "HTML5 Audio Element",
2044     "property": "audio",
2045     "tags" : ["html5", "audio", "media"]
2046     }
2047     !*/
2048    /* DOC
2049     Detects the audio element
2050     */
2051
2052    // This tests evaluates support of the audio element, as well as
2053    // testing what types of content it supports.
2054    //
2055    // We're using the Boolean constructor here, so that we can extend the value
2056    // e.g.  Modernizr.audio     // true
2057    //       Modernizr.audio.ogg // 'probably'
2058    //
2059    // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
2060    //                     thx to NielsLeenheer and zcorpan
2061
2062    // Note: in some older browsers, "no" was a return value instead of empty string.
2063    //   It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2
2064    //   It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5
2065    Modernizr.addTest('audio', function() {
2066        /* jshint -W053 */
2067        var elem = createElement('audio');
2068        var bool = false;
2069
2070        try {
2071            if (bool = !!elem.canPlayType) {
2072                bool      = new Boolean(bool);
2073                bool.ogg  = elem.canPlayType('audio/ogg; codecs="vorbis"') .replace(/^no$/, '');
2074                bool.mp3  = elem.canPlayType('audio/mpeg; codecs="mp3"')   .replace(/^no$/, '');
2075                bool.opus  = elem.canPlayType('audio/ogg; codecs="opus"')  ||
2076                    elem.canPlayType('audio/webm; codecs="opus"') .replace(/^no$/, '');
2077
2078                // Mimetypes accepted:
2079                //   developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements
2080                //   bit.ly/iphoneoscodecs
2081                bool.wav  = elem.canPlayType('audio/wav; codecs="1"')     .replace(/^no$/, '');
2082                bool.m4a  = (elem.canPlayType('audio/x-m4a;')            ||
2083                elem.canPlayType('audio/aac;'))             .replace(/^no$/, '');
2084            }
2085        } catch (e) { }
2086
2087        return bool;
2088    });
2089
2090    /*!
2091     {
2092     "name": "Canvas",
2093     "property": "canvas",
2094     "caniuse": "canvas",
2095     "tags": ["canvas", "graphics"],
2096     "polyfills": ["flashcanvas", "excanvas", "slcanvas", "fxcanvas"]
2097     }
2098     !*/
2099    /* DOC
2100     Detects support for the `<canvas>` element for 2D drawing.
2101     */
2102
2103    // On the S60 and BB Storm, getContext exists, but always returns undefined
2104    // so we actually have to call getContext() to verify
2105    // github.com/Modernizr/Modernizr/issues/issue/97/
2106    Modernizr.addTest('canvas', function() {
2107        var elem = createElement('canvas');
2108        return !!(elem.getContext && elem.getContext('2d'));
2109    });
2110
2111    /*!
2112     {
2113     "name": "Canvas text",
2114     "property": "canvastext",
2115     "caniuse": "canvas-text",
2116     "tags": ["canvas", "graphics"],
2117     "polyfills": ["canvastext"]
2118     }
2119     !*/
2120    /* DOC
2121     Detects support for the text APIs for `<canvas>` elements.
2122     */
2123
2124    Modernizr.addTest('canvastext',  function() {
2125        if (Modernizr.canvas  === false) {
2126            return false;
2127        }
2128        return typeof createElement('canvas').getContext('2d').fillText == 'function';
2129    });
2130
2131    /*!
2132     {
2133     "name": "HTML5 Video",
2134     "property": "video",
2135     "caniuse": "video",
2136     "tags": ["html5"],
2137     "knownBugs": [
2138     "Without QuickTime, `Modernizr.video.h264` will be `undefined`; https://github.com/Modernizr/Modernizr/issues/546"
2139     ],
2140     "polyfills": [
2141     "html5media",
2142     "mediaelementjs",
2143     "sublimevideo",
2144     "videojs",
2145     "leanbackplayer",
2146     "videoforeverybody"
2147     ]
2148     }
2149     !*/
2150    /* DOC
2151     Detects support for the video element, as well as testing what types of content it supports.
2152
2153     Subproperties are provided to describe support for `ogg`, `h264` and `webm` formats, e.g.:
2154
2155     ```javascript
2156     Modernizr.video         // true
2157     Modernizr.video.ogg     // 'probably'
2158     ```
2159     */
2160
2161    // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
2162    //                     thx to NielsLeenheer and zcorpan
2163
2164    // Note: in some older browsers, "no" was a return value instead of empty string.
2165    //   It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2
2166    //   It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5
2167
2168    Modernizr.addTest('video', function() {
2169        /* jshint -W053 */
2170        var elem = createElement('video');
2171        var bool = false;
2172
2173        // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
2174        try {
2175            if (bool = !!elem.canPlayType) {
2176                bool = new Boolean(bool);
2177                bool.ogg = elem.canPlayType('video/ogg; codecs="theora"').replace(/^no$/, '');
2178
2179                // Without QuickTime, this value will be `undefined`. github.com/Modernizr/Modernizr/issues/546
2180                bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/, '');
2181
2182                bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/, '');
2183
2184                bool.vp9 = elem.canPlayType('video/webm; codecs="vp9"').replace(/^no$/, '');
2185
2186                bool.hls = elem.canPlayType('application/x-mpegURL; codecs="avc1.42E01E"').replace(/^no$/, '');
2187            }
2188        } catch (e) {}
2189
2190        return bool;
2191    });
2192
2193    /*!
2194     {
2195     "name": "WebGL",
2196     "property": "webgl",
2197     "caniuse": "webgl",
2198     "tags": ["webgl", "graphics"],
2199     "polyfills": ["jebgl", "cwebgl", "iewebgl"]
2200     }
2201     !*/
2202
2203    Modernizr.addTest('webgl', function() {
2204        var canvas = createElement('canvas');
2205        var supports = 'probablySupportsContext' in canvas ? 'probablySupportsContext' :  'supportsContext';
2206        if (supports in canvas) {
2207            return canvas[supports]('webgl') || canvas[supports]('experimental-webgl');
2208        }
2209        return 'WebGLRenderingContext' in window;
2210    });
2211
2212    /*!
2213     {
2214     "name": "CSS Gradients",
2215     "caniuse": "css-gradients",
2216     "property": "cssgradients",
2217     "tags": ["css"],
2218     "knownBugs": ["False-positives on webOS (https://github.com/Modernizr/Modernizr/issues/202)"],
2219     "notes": [{
2220     "name": "Webkit Gradient Syntax",
2221     "href": "https://webkit.org/blog/175/introducing-css-gradients/"
2222     },{
2223     "name": "Linear Gradient Syntax",
2224     "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient"
2225     },{
2226     "name": "W3C Gradient Spec",
2227     "href": "https://drafts.csswg.org/css-images-3/#gradients"
2228     }]
2229     }
2230     !*/
2231
2232
2233    Modernizr.addTest('cssgradients', function() {
2234
2235        var str1 = 'background-image:';
2236        var str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));';
2237        var css = '';
2238        var angle;
2239
2240        for (var i = 0, len = prefixes.length - 1; i < len; i++) {
2241            angle = (i === 0 ? 'to ' : '');
2242            css += str1 + prefixes[i] + 'linear-gradient(' + angle + 'left top, #9f9, white);';
2243        }
2244
2245        if (Modernizr._config.usePrefixes) {
2246            // legacy webkit syntax (FIXME: remove when syntax not in use anymore)
2247            css += str1 + '-webkit-' + str2;
2248        }
2249
2250        var elem = createElement('a');
2251        var style = elem.style;
2252        style.cssText = css;
2253
2254        // IE6 returns undefined so cast to string
2255        return ('' + style.backgroundImage).indexOf('gradient') > -1;
2256    });
2257
2258    /*!
2259     {
2260     "name": "CSS Multiple Backgrounds",
2261     "caniuse": "multibackgrounds",
2262     "property": "multiplebgs",
2263     "tags": ["css"]
2264     }
2265     !*/
2266
2267    // Setting multiple images AND a color on the background shorthand property
2268    // and then querying the style.background property value for the number of
2269    // occurrences of "url(" is a reliable method for detecting ACTUAL support for this!
2270
2271    Modernizr.addTest('multiplebgs', function() {
2272        var style = createElement('a').style;
2273        style.cssText = 'background:url(https://),url(https://),red url(https://)';
2274
2275        // If the UA supports multiple backgrounds, there should be three occurrences
2276        // of the string "url(" in the return value for elemStyle.background
2277        return (/(url\s*\(.*?){3}/).test(style.background);
2278    });
2279
2280    /*!
2281     {
2282     "name": "CSS Opacity",
2283     "caniuse": "css-opacity",
2284     "property": "opacity",
2285     "tags": ["css"]
2286     }
2287     !*/
2288
2289    // Browsers that actually have CSS Opacity implemented have done so
2290    // according to spec, which means their return values are within the
2291    // range of [0.0,1.0] - including the leading zero.
2292
2293    Modernizr.addTest('opacity', function() {
2294        var style = createElement('a').style;
2295        style.cssText = prefixes.join('opacity:.55;');
2296
2297        // The non-literal . in this regex is intentional:
2298        // German Chrome returns this value as 0,55
2299        // github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632
2300        return (/^0.55$/).test(style.opacity);
2301    });
2302
2303    /*!
2304     {
2305     "name": "CSS rgba",
2306     "caniuse": "css3-colors",
2307     "property": "rgba",
2308     "tags": ["css"],
2309     "notes": [{
2310     "name": "CSSTricks Tutorial",
2311     "href": "https://css-tricks.com/rgba-browser-support/"
2312     }]
2313     }
2314     !*/
2315
2316    Modernizr.addTest('rgba', function() {
2317        var style = createElement('a').style;
2318        style.cssText = 'background-color:rgba(150,255,150,.5)';
2319
2320        return ('' + style.backgroundColor).indexOf('rgba') > -1;
2321    });
2322
2323    /*!
2324     {
2325     "name": "Inline SVG",
2326     "property": "inlinesvg",
2327     "caniuse": "svg-html5",
2328     "tags": ["svg"],
2329     "notes": [{
2330     "name": "Test page",
2331     "href": "https://paulirish.com/demo/inline-svg"
2332     }, {
2333     "name": "Test page and results",
2334     "href": "https://codepen.io/eltonmesquita/full/GgXbvo/"
2335     }],
2336     "polyfills": ["inline-svg-polyfill"],
2337     "knownBugs": ["False negative on some Chromia browsers."]
2338     }
2339     !*/
2340    /* DOC
2341     Detects support for inline SVG in HTML (not within XHTML).
2342     */
2343
2344    Modernizr.addTest('inlinesvg', function() {
2345        var div = createElement('div');
2346        div.innerHTML = '<svg/>';
2347        return (typeof SVGRect != 'undefined' && div.firstChild && div.firstChild.namespaceURI) == 'http://www.w3.org/2000/svg';
2348    });
2349
2350
2351    /**
2352     * cssToDOM takes a kebab-case string and converts it to camelCase
2353     * e.g. box-sizing -> boxSizing
2354     *
2355     * @access private
2356     * @function cssToDOM
2357     * @param {string} name - String name of kebab-case prop we want to convert
2358     * @returns {string} The camelCase version of the supplied name
2359     */
2360
2361    function cssToDOM(name) {
2362        return name.replace(/([a-z])-([a-z])/g, function(str, m1, m2) {
2363            return m1 + m2.toUpperCase();
2364        }).replace(/^-/, '');
2365    }
2366    ;
2367
2368    /**
2369     * since we have a fairly large number of input tests that don't mutate the input
2370     * we create a single element that can be shared with all of those tests for a
2371     * minor perf boost
2372     *
2373     * @access private
2374     * @returns {HTMLInputElement}
2375     */
2376    var inputElem = createElement('input');
2377
2378    /*!
2379     {
2380     "name": "Input attributes",
2381     "property": "input",
2382     "tags": ["forms"],
2383     "authors": ["Mike Taylor"],
2384     "notes": [{
2385     "name": "WHATWG spec",
2386     "href": "https://html.spec.whatwg.org/multipage/forms.html#input-type-attr-summary"
2387     }],
2388     "knownBugs": ["Some blackberry devices report false positive for input.multiple"]
2389     }
2390     !*/
2391    /* DOC
2392     Detects support for HTML5 `<input>` element attributes and exposes Boolean subproperties with the results:
2393
2394     ```javascript
2395     Modernizr.input.autocomplete
2396     Modernizr.input.autofocus
2397     Modernizr.input.list
2398     Modernizr.input.max
2399     Modernizr.input.min
2400     Modernizr.input.multiple
2401     Modernizr.input.pattern
2402     Modernizr.input.placeholder
2403     Modernizr.input.required
2404     Modernizr.input.step
2405     ```
2406     */
2407
2408    // Run through HTML5's new input attributes to see if the UA understands any.
2409    // Mike Taylr has created a comprehensive resource for testing these attributes
2410    //   when applied to all input types:
2411    //   miketaylr.com/code/input-type-attr.html
2412
2413    // Only input placeholder is tested while textarea's placeholder is not.
2414    // Currently Safari 4 and Opera 11 have support only for the input placeholder
2415    // Both tests are available in feature-detects/forms-placeholder.js
2416
2417    var inputattrs = 'autocomplete autofocus list placeholder max min multiple pattern required step'.split(' ');
2418    var attrs = {};
2419
2420    Modernizr.input = (function(props) {
2421        for (var i = 0, len = props.length; i < len; i++) {
2422            attrs[ props[i] ] = !!(props[i] in inputElem);
2423        }
2424        if (attrs.list) {
2425            // safari false positive's on datalist: webk.it/74252
2426            // see also github.com/Modernizr/Modernizr/issues/146
2427            attrs.list = !!(createElement('datalist') && window.HTMLDataListElement);
2428        }
2429        return attrs;
2430    })(inputattrs);
2431
2432    /*!
2433     {
2434     "name": "Form input types",
2435     "property": "inputtypes",
2436     "caniuse": "forms",
2437     "tags": ["forms"],
2438     "authors": ["Mike Taylor"],
2439     "polyfills": [
2440     "jquerytools",
2441     "webshims",
2442     "h5f",
2443     "webforms2",
2444     "nwxforms",
2445     "fdslider",
2446     "html5slider",
2447     "galleryhtml5forms",
2448     "jscolor",
2449     "html5formshim",
2450     "selectedoptionsjs",
2451     "formvalidationjs"
2452     ]
2453     }
2454     !*/
2455    /* DOC
2456     Detects support for HTML5 form input types and exposes Boolean subproperties with the results:
2457
2458     ```javascript
2459     Modernizr.inputtypes.color
2460     Modernizr.inputtypes.date
2461     Modernizr.inputtypes.datetime
2462     Modernizr.inputtypes['datetime-local']
2463     Modernizr.inputtypes.email
2464     Modernizr.inputtypes.month
2465     Modernizr.inputtypes.number
2466     Modernizr.inputtypes.range
2467     Modernizr.inputtypes.search
2468     Modernizr.inputtypes.tel
2469     Modernizr.inputtypes.time
2470     Modernizr.inputtypes.url
2471     Modernizr.inputtypes.week
2472     ```
2473     */
2474
2475    // Run through HTML5's new input types to see if the UA understands any.
2476    //   This is put behind the tests runloop because it doesn't return a
2477    //   true/false like all the other tests; instead, it returns an object
2478    //   containing each input type with its corresponding true/false value
2479
2480    // Big thanks to @miketaylr for the html5 forms expertise. miketaylr.com/
2481    var inputtypes = 'search tel url email datetime date month week time datetime-local number range color'.split(' ');
2482    var inputs = {};
2483
2484    Modernizr.inputtypes = (function(props) {
2485        var len = props.length;
2486        var smile = '1)';
2487        var inputElemType;
2488        var defaultView;
2489        var bool;
2490
2491        for (var i = 0; i < len; i++) {
2492
2493            inputElem.setAttribute('type', inputElemType = props[i]);
2494            bool = inputElem.type !== 'text' && 'style' in inputElem;
2495
2496            // We first check to see if the type we give it sticks..
2497            // If the type does, we feed it a textual value, which shouldn't be valid.
2498            // If the value doesn't stick, we know there's input sanitization which infers a custom UI
2499            if (bool) {
2500
2501                inputElem.value         = smile;
2502                inputElem.style.cssText = 'position:absolute;visibility:hidden;';
2503
2504                if (/^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined) {
2505
2506                    docElement.appendChild(inputElem);
2507                    defaultView = document.defaultView;
2508
2509                    // Safari 2-4 allows the smiley as a value, despite making a slider
2510                    bool =  defaultView.getComputedStyle &&
2511                        defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' &&
2512                        // Mobile android web browser has false positive, so must
2513                        // check the height to see if the widget is actually there.
2514                        (inputElem.offsetHeight !== 0);
2515
2516                    docElement.removeChild(inputElem);
2517
2518                } else if (/^(search|tel)$/.test(inputElemType)) {
2519                    // Spec doesn't define any special parsing or detectable UI
2520                    //   behaviors so we pass these through as true
2521
2522                    // Interestingly, opera fails the earlier test, so it doesn't
2523                    //  even make it here.
2524
2525                } else if (/^(url|email)$/.test(inputElemType)) {
2526                    // Real url and email support comes with prebaked validation.
2527                    bool = inputElem.checkValidity && inputElem.checkValidity() === false;
2528
2529                } else {
2530                    // If the upgraded input compontent rejects the :) text, we got a winner
2531                    bool = inputElem.value != smile;
2532                }
2533            }
2534
2535            inputs[ props[i] ] = !!bool;
2536        }
2537        return inputs;
2538    })(inputtypes);
2539
2540
2541
2542    /**
2543     * contains checks to see if a string contains another string
2544     *
2545     * @access private
2546     * @function contains
2547     * @param {string} str - The string we want to check for substrings
2548     * @param {string} substr - The substring we want to search the first string for
2549     * @returns {boolean}
2550     */
2551
2552    function contains(str, substr) {
2553        return !!~('' + str).indexOf(substr);
2554    }
2555
2556    ;
2557    /*!
2558     {
2559     "name": "CSS HSLA Colors",
2560     "caniuse": "css3-colors",
2561     "property": "hsla",
2562     "tags": ["css"]
2563     }
2564     !*/
2565
2566    Modernizr.addTest('hsla', function() {
2567        var style = createElement('a').style;
2568        style.cssText = 'background-color:hsla(120,40%,100%,.5)';
2569        return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla');
2570    });
2571
2572    /*!
2573     {
2574     "name": "CSS Supports",
2575     "property": "supports",
2576     "caniuse": "css-featurequeries",
2577     "tags": ["css"],
2578     "builderAliases": ["css_supports"],
2579     "notes": [{
2580     "name": "W3 Spec",
2581     "href": "http://dev.w3.org/csswg/css3-conditional/#at-supports"
2582     },{
2583     "name": "Related Github Issue",
2584     "href": "github.com/Modernizr/Modernizr/issues/648"
2585     },{
2586     "name": "W3 Info",
2587     "href": "http://dev.w3.org/csswg/css3-conditional/#the-csssupportsrule-interface"
2588     }]
2589     }
2590     !*/
2591
2592    var newSyntax = 'CSS' in window && 'supports' in window.CSS;
2593    var oldSyntax = 'supportsCSS' in window;
2594    Modernizr.addTest('supports', newSyntax || oldSyntax);
2595
2596
2597    /**
2598     * Object.prototype.toString can be used with every object and allows you to
2599     * get its class easily. Abstracting it off of an object prevents situations
2600     * where the toString property has been overridden
2601     *
2602     * @access private
2603     * @function toStringFn
2604     * @returns {function} An abstracted toString function
2605     */
2606
2607    var toStringFn = ({}).toString;
2608
2609    /*!
2610     {
2611     "name": "SVG clip paths",
2612     "property": "svgclippaths",
2613     "tags": ["svg"],
2614     "notes": [{
2615     "name": "Demo",
2616     "href": "http://srufaculty.sru.edu/david.dailey/svg/newstuff/clipPath4.svg"
2617     }]
2618     }
2619     !*/
2620    /* DOC
2621     Detects support for clip paths in SVG (only, not on HTML content).
2622
2623     See [this discussion](https://github.com/Modernizr/Modernizr/issues/213) regarding applying SVG clip paths to HTML content.
2624     */
2625
2626    Modernizr.addTest('svgclippaths', function() {
2627        return !!document.createElementNS &&
2628            /SVGClipPath/.test(toStringFn.call(document.createElementNS('http://www.w3.org/2000/svg', 'clipPath')));
2629    });
2630
2631    /*!
2632     {
2633     "name": "SVG SMIL animation",
2634     "property": "smil",
2635     "caniuse": "svg-smil",
2636     "tags": ["svg"],
2637     "notes": [{
2638     "name": "W3C Synchronised Multimedia spec",
2639     "href": "https://www.w3.org/AudioVideo/"
2640     }]
2641     }
2642     !*/
2643
2644    // SVG SMIL animation
2645    Modernizr.addTest('smil', function() {
2646        return !!document.createElementNS &&
2647            /SVGAnimate/.test(toStringFn.call(document.createElementNS('http://www.w3.org/2000/svg', 'animate')));
2648    });
2649
2650
2651    /**
2652     * getBody returns the body of a document, or an element that can stand in for
2653     * the body if a real body does not exist
2654     *
2655     * @access private
2656     * @function getBody
2657     * @returns {HTMLElement|SVGElement} Returns the real body of a document, or an
2658     * artificially created element that stands in for the body
2659     */
2660
2661    function getBody() {
2662        // After page load injecting a fake body doesn't work so check if body exists
2663        var body = document.body;
2664
2665        if (!body) {
2666            // Can't use the real body create a fake one.
2667            body = createElement(isSVG ? 'svg' : 'body');
2668            body.fake = true;
2669        }
2670
2671        return body;
2672    }
2673
2674    ;
2675
2676    /**
2677     * injectElementWithStyles injects an element with style element and some CSS rules
2678     *
2679     * @access private
2680     * @function injectElementWithStyles
2681     * @param {string} rule - String representing a css rule
2682     * @param {function} callback - A function that is used to test the injected element
2683     * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
2684     * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
2685     * @returns {boolean}
2686     */
2687
2688    function injectElementWithStyles(rule, callback, nodes, testnames) {
2689        var mod = 'modernizr';
2690        var style;
2691        var ret;
2692        var node;
2693        var docOverflow;
2694        var div = createElement('div');
2695        var body = getBody();
2696
2697        if (parseInt(nodes, 10)) {
2698            // In order not to give false positives we create a node for each test
2699            // This also allows the method to scale for unspecified uses
2700            while (nodes--) {
2701                node = createElement('div');
2702                node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
2703                div.appendChild(node);
2704            }
2705        }
2706
2707        style = createElement('style');
2708        style.type = 'text/css';
2709        style.id = 's' + mod;
2710
2711        // IE6 will false positive on some tests due to the style element inside the test div somehow interfering offsetHeight, so insert it into body or fakebody.
2712        // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
2713        (!body.fake ? div : body).appendChild(style);
2714        body.appendChild(div);
2715
2716        if (style.styleSheet) {
2717            style.styleSheet.cssText = rule;
2718        } else {
2719            style.appendChild(document.createTextNode(rule));
2720        }
2721        div.id = mod;
2722
2723        if (body.fake) {
2724            //avoid crashing IE8, if background image is used
2725            body.style.background = '';
2726            //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
2727            body.style.overflow = 'hidden';
2728            docOverflow = docElement.style.overflow;
2729            docElement.style.overflow = 'hidden';
2730            docElement.appendChild(body);
2731        }
2732
2733        ret = callback(div, rule);
2734        // If this is done after page load we don't want to remove the body so check if body exists
2735        if (body.fake) {
2736            body.parentNode.removeChild(body);
2737            docElement.style.overflow = docOverflow;
2738            // Trigger layout so kinetic scrolling isn't disabled in iOS6+
2739            docElement.offsetHeight;
2740        } else {
2741            div.parentNode.removeChild(div);
2742        }
2743
2744        return !!ret;
2745
2746    }
2747
2748    ;
2749
2750    /**
2751     * Modernizr.mq tests a given media query, live against the current state of the window
2752     * adapted from matchMedia polyfill by Scott Jehl and Paul Irish
2753     * gist.github.com/786768
2754     *
2755     * @memberof Modernizr
2756     * @name Modernizr.mq
2757     * @optionName Modernizr.mq()
2758     * @optionProp mq
2759     * @access public
2760     * @function mq
2761     * @param {string} mq - String of the media query we want to test
2762     * @returns {boolean}
2763     * @example
2764     * Modernizr.mq allows for you to programmatically check if the current browser
2765     * window state matches a media query.
2766     *
2767     * ```js
2768     *  var query = Modernizr.mq('(min-width: 900px)');
2769     *
2770     *  if (query) {
2771   *    // the browser window is larger than 900px
2772   *  }
2773     * ```
2774     *
2775     * Only valid media queries are supported, therefore you must always include values
2776     * with your media query
2777     *
2778     * ```js
2779     * // good
2780     *  Modernizr.mq('(min-width: 900px)');
2781     *
2782     * // bad
2783     *  Modernizr.mq('min-width');
2784     * ```
2785     *
2786     * If you would just like to test that media queries are supported in general, use
2787     *
2788     * ```js
2789     *  Modernizr.mq('only all'); // true if MQ are supported, false if not
2790     * ```
2791     *
2792     *
2793     * Note that if the browser does not support media queries (e.g. old IE) mq will
2794     * always return false.
2795     */
2796
2797    var mq = (function() {
2798        var matchMedia = window.matchMedia || window.msMatchMedia;
2799        if (matchMedia) {
2800            return function(mq) {
2801                var mql = matchMedia(mq);
2802                return mql && mql.matches || false;
2803            };
2804        }
2805
2806        return function(mq) {
2807            var bool = false;
2808
2809            injectElementWithStyles('@media ' + mq + ' { #modernizr { position: absolute; } }', function(node) {
2810                bool = (window.getComputedStyle ?
2811                        window.getComputedStyle(node, null) :
2812                        node.currentStyle).position == 'absolute';
2813            });
2814
2815            return bool;
2816        };
2817    })();
2818
2819
2820    ModernizrProto.mq = mq;
2821
2822
2823
2824    /**
2825     * testStyles injects an element with style element and some CSS rules
2826     *
2827     * @memberof Modernizr
2828     * @name Modernizr.testStyles
2829     * @optionName Modernizr.testStyles()
2830     * @optionProp testStyles
2831     * @access public
2832     * @function testStyles
2833     * @param {string} rule - String representing a css rule
2834     * @param {function} callback - A function that is used to test the injected element
2835     * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
2836     * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
2837     * @returns {boolean}
2838     * @example
2839     *
2840     * `Modernizr.testStyles` takes a CSS rule and injects it onto the current page
2841     * along with (possibly multiple) DOM elements. This lets you check for features
2842     * that can not be detected by simply checking the [IDL](https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Interface_development_guide/IDL_interface_rules).
2843     *
2844     * ```js
2845     * Modernizr.testStyles('#modernizr { width: 9px; color: papayawhip; }', function(elem, rule) {
2846   *   // elem is the first DOM node in the page (by default #modernizr)
2847   *   // rule is the first argument you supplied - the CSS rule in string form
2848   *
2849   *   addTest('widthworks', elem.style.width === '9px')
2850   * });
2851     * ```
2852     *
2853     * If your test requires multiple nodes, you can include a third argument
2854     * indicating how many additional div elements to include on the page. The
2855     * additional nodes are injected as children of the `elem` that is returned as
2856     * the first argument to the callback.
2857     *
2858     * ```js
2859     * Modernizr.testStyles('#modernizr {width: 1px}; #modernizr2 {width: 2px}', function(elem) {
2860   *   document.getElementById('modernizr').style.width === '1px'; // true
2861   *   document.getElementById('modernizr2').style.width === '2px'; // true
2862   *   elem.firstChild === document.getElementById('modernizr2'); // true
2863   * }, 1);
2864     * ```
2865     *
2866     * By default, all of the additional elements have an ID of `modernizr[n]`, where
2867     * `n` is its index (e.g. the first additional, second overall is `#modernizr2`,
2868     * the second additional is `#modernizr3`, etc.).
2869     * If you want to have more meaningful IDs for your function, you can provide
2870     * them as the fourth argument, as an array of strings
2871     *
2872     * ```js
2873     * Modernizr.testStyles('#foo {width: 10px}; #bar {height: 20px}', function(elem) {
2874   *   elem.firstChild === document.getElementById('foo'); // true
2875   *   elem.lastChild === document.getElementById('bar'); // true
2876   * }, 2, ['foo', 'bar']);
2877     * ```
2878     *
2879     */
2880
2881    var testStyles = ModernizrProto.testStyles = injectElementWithStyles;
2882
2883    /*!
2884     {
2885     "name": "@font-face",
2886     "property": "fontface",
2887     "authors": ["Diego Perini", "Mat Marquis"],
2888     "tags": ["css"],
2889     "knownBugs": [
2890     "False Positive: WebOS https://github.com/Modernizr/Modernizr/issues/342",
2891     "False Postive: WP7 https://github.com/Modernizr/Modernizr/issues/538"
2892     ],
2893     "notes": [{
2894     "name": "@font-face detection routine by Diego Perini",
2895     "href": "http://javascript.nwbox.com/CSSSupport/"
2896     },{
2897     "name": "Filament Group @font-face compatibility research",
2898     "href": "https://docs.google.com/presentation/d/1n4NyG4uPRjAA8zn_pSQ_Ket0RhcWC6QlZ6LMjKeECo0/edit#slide=id.p"
2899     },{
2900     "name": "Filament Grunticon/@font-face device testing results",
2901     "href": "https://docs.google.com/spreadsheet/ccc?key=0Ag5_yGvxpINRdHFYeUJPNnZMWUZKR2ItMEpRTXZPdUE#gid=0"
2902     },{
2903     "name": "CSS fonts on Android",
2904     "href": "https://stackoverflow.com/questions/3200069/css-fonts-on-android"
2905     },{
2906     "name": "@font-face and Android",
2907     "href": "http://archivist.incutio.com/viewlist/css-discuss/115960"
2908     }]
2909     }
2910     !*/
2911
2912    var blacklist = (function() {
2913        var ua = navigator.userAgent;
2914        var wkvers = ua.match(/applewebkit\/([0-9]+)/gi) && parseFloat(RegExp.$1);
2915        var webos = ua.match(/w(eb)?osbrowser/gi);
2916        var wppre8 = ua.match(/windows phone/gi) && ua.match(/iemobile\/([0-9])+/gi) && parseFloat(RegExp.$1) >= 9;
2917        var oldandroid = wkvers < 533 && ua.match(/android/gi);
2918        return webos || oldandroid || wppre8;
2919    }());
2920    if (blacklist) {
2921        Modernizr.addTest('fontface', false);
2922    } else {
2923        testStyles('@font-face {font-family:"font";src:url("https://")}', function(node, rule) {
2924            var style = document.getElementById('smodernizr');
2925            var sheet = style.sheet || style.styleSheet;
2926            var cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : '';
2927            var bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0;
2928            Modernizr.addTest('fontface', bool);
2929        });
2930    }
2931    ;
2932    /*!
2933     {
2934     "name": "CSS Generated Content",
2935     "property": "generatedcontent",
2936     "tags": ["css"],
2937     "warnings": ["Android won't return correct height for anything below 7px #738"],
2938     "notes": [{
2939     "name": "W3C CSS Selectors Level 3 spec",
2940     "href": "https://www.w3.org/TR/css3-selectors/#gen-content"
2941     },{
2942     "name": "MDN article on :before",
2943     "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/::before"
2944     },{
2945     "name": "MDN article on :after",
2946     "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/::before"
2947     }]
2948     }
2949     !*/
2950
2951    testStyles('#modernizr{font:0/0 a}#modernizr:after{content:":)";visibility:hidden;font:7px/1 a}', function(node) {
2952        Modernizr.addTest('generatedcontent', node.offsetHeight >= 7);
2953    });
2954
2955
2956    var cssomPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.split(' ') : []);
2957    ModernizrProto._cssomPrefixes = cssomPrefixes;
2958
2959
2960    /**
2961     * atRule returns a given CSS property at-rule (eg @keyframes), possibly in
2962     * some prefixed form, or false, in the case of an unsupported rule
2963     *
2964     * @memberof Modernizr
2965     * @name Modernizr.atRule
2966     * @optionName Modernizr.atRule()
2967     * @optionProp atRule
2968     * @access public
2969     * @function atRule
2970     * @param {string} prop - String name of the @-rule to test for
2971     * @returns {string|boolean} The string representing the (possibly prefixed)
2972     * valid version of the @-rule, or `false` when it is unsupported.
2973     * @example
2974     * ```js
2975     *  var keyframes = Modernizr.atRule('@keyframes');
2976     *
2977     *  if (keyframes) {
2978   *    // keyframes are supported
2979   *    // could be `@-webkit-keyframes` or `@keyframes`
2980   *  } else {
2981   *    // keyframes === `false`
2982   *  }
2983     * ```
2984     *
2985     */
2986
2987    var atRule = function(prop) {
2988        var length = prefixes.length;
2989        var cssrule = window.CSSRule;
2990        var rule;
2991
2992        if (typeof cssrule === 'undefined') {
2993            return undefined;
2994        }
2995
2996        if (!prop) {
2997            return false;
2998        }
2999
3000        // remove literal @ from beginning of provided property
3001        prop = prop.replace(/^@/, '');
3002
3003        // CSSRules use underscores instead of dashes
3004        rule = prop.replace(/-/g, '_').toUpperCase() + '_RULE';
3005
3006        if (rule in cssrule) {
3007            return '@' + prop;
3008        }
3009
3010        for (var i = 0; i < length; i++) {
3011            // prefixes gives us something like -o-, and we want O_
3012            var prefix = prefixes[i];
3013            var thisRule = prefix.toUpperCase() + '_' + rule;
3014
3015            if (thisRule in cssrule) {
3016                return '@-' + prefix.toLowerCase() + '-' + prop;
3017            }
3018        }
3019
3020        return false;
3021    };
3022
3023    ModernizrProto.atRule = atRule;
3024
3025
3026
3027    /**
3028     * fnBind is a super small [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) polyfill.
3029     *
3030     * @access private
3031     * @function fnBind
3032     * @param {function} fn - a function you want to change `this` reference to
3033     * @param {object} that - the `this` you want to call the function with
3034     * @returns {function} The wrapped version of the supplied function
3035     */
3036
3037    function fnBind(fn, that) {
3038        return function() {
3039            return fn.apply(that, arguments);
3040        };
3041    }
3042
3043    ;
3044
3045    /**
3046     * testDOMProps is a generic DOM property test; if a browser supports
3047     *   a certain property, it won't return undefined for it.
3048     *
3049     * @access private
3050     * @function testDOMProps
3051     * @param {array.<string>} props - An array of properties to test for
3052     * @param {object} obj - An object or Element you want to use to test the parameters again
3053     * @param {boolean|object} elem - An Element to bind the property lookup again. Use `false` to prevent the check
3054     */
3055    function testDOMProps(props, obj, elem) {
3056        var item;
3057
3058        for (var i in props) {
3059            if (props[i] in obj) {
3060
3061                // return the property name as a string
3062                if (elem === false) {
3063                    return props[i];
3064                }
3065
3066                item = obj[props[i]];
3067
3068                // let's bind a function
3069                if (is(item, 'function')) {
3070                    // bind to obj unless overriden
3071                    return fnBind(item, elem || obj);
3072                }
3073
3074                // return the unbound function or obj or value
3075                return item;
3076            }
3077        }
3078        return false;
3079    }
3080
3081    ;
3082
3083    /**
3084     * Create our "modernizr" element that we do most feature tests on.
3085     *
3086     * @access private
3087     */
3088
3089    var modElem = {
3090        elem: createElement('modernizr')
3091    };
3092
3093    // Clean up this element
3094    Modernizr._q.push(function() {
3095        delete modElem.elem;
3096    });
3097
3098
3099
3100    var mStyle = {
3101        style: modElem.elem.style
3102    };
3103
3104    // kill ref for gc, must happen before mod.elem is removed, so we unshift on to
3105    // the front of the queue.
3106    Modernizr._q.unshift(function() {
3107        delete mStyle.style;
3108    });
3109
3110
3111
3112    /**
3113     * domToCSS takes a camelCase string and converts it to kebab-case
3114     * e.g. boxSizing -> box-sizing
3115     *
3116     * @access private
3117     * @function domToCSS
3118     * @param {string} name - String name of camelCase prop we want to convert
3119     * @returns {string} The kebab-case version of the supplied name
3120     */
3121
3122    function domToCSS(name) {
3123        return name.replace(/([A-Z])/g, function(str, m1) {
3124            return '-' + m1.toLowerCase();
3125        }).replace(/^ms-/, '-ms-');
3126    }
3127    ;
3128
3129    /**
3130     * nativeTestProps allows for us to use native feature detection functionality if available.
3131     * some prefixed form, or false, in the case of an unsupported rule
3132     *
3133     * @access private
3134     * @function nativeTestProps
3135     * @param {array} props - An array of property names
3136     * @param {string} value - A string representing the value we want to check via @supports
3137     * @returns {boolean|undefined} A boolean when @supports exists, undefined otherwise
3138     */
3139
3140    // Accepts a list of property names and a single value
3141    // Returns `undefined` if native detection not available
3142    function nativeTestProps(props, value) {
3143        var i = props.length;
3144        // Start with the JS API: http://www.w3.org/TR/css3-conditional/#the-css-interface
3145        if ('CSS' in window && 'supports' in window.CSS) {
3146            // Try every prefixed variant of the property
3147            while (i--) {
3148                if (window.CSS.supports(domToCSS(props[i]), value)) {
3149                    return true;
3150                }
3151            }
3152            return false;
3153        }
3154        // Otherwise fall back to at-rule (for Opera 12.x)
3155        else if ('CSSSupportsRule' in window) {
3156            // Build a condition string for every prefixed variant
3157            var conditionText = [];
3158            while (i--) {
3159                conditionText.push('(' + domToCSS(props[i]) + ':' + value + ')');
3160            }
3161            conditionText = conditionText.join(' or ');
3162            return injectElementWithStyles('@supports (' + conditionText + ') { #modernizr { position: absolute; } }', function(node) {
3163                return getComputedStyle(node, null).position == 'absolute';
3164            });
3165        }
3166        return undefined;
3167    }
3168    ;
3169
3170    // testProps is a generic CSS / DOM property test.
3171
3172    // In testing support for a given CSS property, it's legit to test:
3173    //    `elem.style[styleName] !== undefined`
3174    // If the property is supported it will return an empty string,
3175    // if unsupported it will return undefined.
3176
3177    // We'll take advantage of this quick test and skip setting a style
3178    // on our modernizr element, but instead just testing undefined vs
3179    // empty string.
3180
3181    // Property names can be provided in either camelCase or kebab-case.
3182
3183    function testProps(props, prefixed, value, skipValueTest) {
3184        skipValueTest = is(skipValueTest, 'undefined') ? false : skipValueTest;
3185
3186        // Try native detect first
3187        if (!is(value, 'undefined')) {
3188            var result = nativeTestProps(props, value);
3189            if (!is(result, 'undefined')) {
3190                return result;
3191            }
3192        }
3193
3194        // Otherwise do it properly
3195        var afterInit, i, propsLength, prop, before;
3196
3197        // If we don't have a style element, that means we're running async or after
3198        // the core tests, so we'll need to create our own elements to use
3199
3200        // inside of an SVG element, in certain browsers, the `style` element is only
3201        // defined for valid tags. Therefore, if `modernizr` does not have one, we
3202        // fall back to a less used element and hope for the best.
3203        var elems = ['modernizr', 'tspan'];
3204        while (!mStyle.style) {
3205            afterInit = true;
3206            mStyle.modElem = createElement(elems.shift());
3207            mStyle.style = mStyle.modElem.style;
3208        }
3209
3210        // Delete the objects if we created them.
3211        function cleanElems() {
3212            if (afterInit) {
3213                delete mStyle.style;
3214                delete mStyle.modElem;
3215            }
3216        }
3217
3218        propsLength = props.length;
3219        for (i = 0; i < propsLength; i++) {
3220            prop = props[i];
3221            before = mStyle.style[prop];
3222
3223            if (contains(prop, '-')) {
3224                prop = cssToDOM(prop);
3225            }
3226
3227            if (mStyle.style[prop] !== undefined) {
3228
3229                // If value to test has been passed in, do a set-and-check test.
3230                // 0 (integer) is a valid property value, so check that `value` isn't
3231                // undefined, rather than just checking it's truthy.
3232                if (!skipValueTest && !is(value, 'undefined')) {
3233
3234                    // Needs a try catch block because of old IE. This is slow, but will
3235                    // be avoided in most cases because `skipValueTest` will be used.
3236                    try {
3237                        mStyle.style[prop] = value;
3238                    } catch (e) {}
3239
3240                    // If the property value has changed, we assume the value used is
3241                    // supported. If `value` is empty string, it'll fail here (because
3242                    // it hasn't changed), which matches how browsers have implemented
3243                    // CSS.supports()
3244                    if (mStyle.style[prop] != before) {
3245                        cleanElems();
3246                        return prefixed == 'pfx' ? prop : true;
3247                    }
3248                }
3249                // Otherwise just return true, or the property name if this is a
3250                // `prefixed()` call
3251                else {
3252                    cleanElems();
3253                    return prefixed == 'pfx' ? prop : true;
3254                }
3255            }
3256        }
3257        cleanElems();
3258        return false;
3259    }
3260
3261    ;
3262
3263    /**
3264     * testProp() investigates whether a given style property is recognized
3265     * Property names can be provided in either camelCase or kebab-case.
3266     *
3267     * @memberof Modernizr
3268     * @name Modernizr.testProp
3269     * @access public
3270     * @optionName Modernizr.testProp()
3271     * @optionProp testProp
3272     * @function testProp
3273     * @param {string} prop - Name of the CSS property to check
3274     * @param {string} [value] - Name of the CSS value to check
3275     * @param {boolean} [useValue] - Whether or not to check the value if @supports isn't supported
3276     * @returns {boolean}
3277     * @example
3278     *
3279     * Just like [testAllProps](#modernizr-testallprops), only it does not check any vendor prefixed
3280     * version of the string.
3281     *
3282     * Note that the property name must be provided in camelCase (e.g. boxSizing not box-sizing)
3283     *
3284     * ```js
3285     * Modernizr.testProp('pointerEvents')  // true
3286     * ```
3287     *
3288     * You can also provide a value as an optional second argument to check if a
3289     * specific value is supported
3290     *
3291     * ```js
3292     * Modernizr.testProp('pointerEvents', 'none') // true
3293     * Modernizr.testProp('pointerEvents', 'penguin') // false
3294     * ```
3295     */
3296
3297    var testProp = ModernizrProto.testProp = function(prop, value, useValue) {
3298        return testProps([prop], undefined, value, useValue);
3299    };
3300
3301    /*!
3302     {
3303     "name": "CSS textshadow",
3304     "property": "textshadow",
3305     "caniuse": "css-textshadow",
3306     "tags": ["css"],
3307     "knownBugs": ["FF3.0 will false positive on this test"]
3308     }
3309     !*/
3310
3311    Modernizr.addTest('textshadow', testProp('textShadow', '1px 1px'));
3312
3313
3314    /**
3315     * testPropsAll tests a list of DOM properties we want to check against.
3316     * We specify literally ALL possible (known and/or likely) properties on
3317     * the element including the non-vendor prefixed one, for forward-
3318     * compatibility.
3319     *
3320     * @access private
3321     * @function testPropsAll
3322     * @param {string} prop - A string of the property to test for
3323     * @param {string|object} [prefixed] - An object to check the prefixed properties on. Use a string to skip
3324     * @param {HTMLElement|SVGElement} [elem] - An element used to test the property and value against
3325     * @param {string} [value] - A string of a css value
3326     * @param {boolean} [skipValueTest] - An boolean representing if you want to test if value sticks when set
3327     */
3328    function testPropsAll(prop, prefixed, elem, value, skipValueTest) {
3329
3330        var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
3331            props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
3332
3333        // did they call .prefixed('boxSizing') or are we just testing a prop?
3334        if (is(prefixed, 'string') || is(prefixed, 'undefined')) {
3335            return testProps(props, prefixed, value, skipValueTest);
3336
3337            // otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
3338        } else {
3339            props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
3340            return testDOMProps(props, prefixed, elem);
3341        }
3342    }
3343
3344    // Modernizr.testAllProps() investigates whether a given style property,
3345    // or any of its vendor-prefixed variants, is recognized
3346    //
3347    // Note that the property names must be provided in the camelCase variant.
3348    // Modernizr.testAllProps('boxSizing')
3349    ModernizrProto.testAllProps = testPropsAll;
3350
3351
3352
3353    /**
3354     * prefixed returns the prefixed or nonprefixed property name variant of your input
3355     *
3356     * @memberof Modernizr
3357     * @name Modernizr.prefixed
3358     * @optionName Modernizr.prefixed()
3359     * @optionProp prefixed
3360     * @access public
3361     * @function prefixed
3362     * @param {string} prop - String name of the property to test for
3363     * @param {object} [obj] - An object to test for the prefixed properties on
3364     * @param {HTMLElement} [elem] - An element used to test specific properties against
3365     * @returns {string|false} The string representing the (possibly prefixed) valid
3366     * version of the property, or `false` when it is unsupported.
3367     * @example
3368     *
3369     * Modernizr.prefixed takes a string css value in the DOM style camelCase (as
3370     * opposed to the css style kebab-case) form and returns the (possibly prefixed)
3371     * version of that property that the browser actually supports.
3372     *
3373     * For example, in older Firefox...
3374     * ```js
3375     * prefixed('boxSizing')
3376     * ```
3377     * returns 'MozBoxSizing'
3378     *
3379     * In newer Firefox, as well as any other browser that support the unprefixed
3380     * version would simply return `boxSizing`. Any browser that does not support
3381     * the property at all, it will return `false`.
3382     *
3383     * By default, prefixed is checked against a DOM element. If you want to check
3384     * for a property on another object, just pass it as a second argument
3385     *
3386     * ```js
3387     * var rAF = prefixed('requestAnimationFrame', window);
3388     *
3389     * raf(function() {
3390   *  renderFunction();
3391   * })
3392     * ```
3393     *
3394     * Note that this will return _the actual function_ - not the name of the function.
3395     * If you need the actual name of the property, pass in `false` as a third argument
3396     *
3397     * ```js
3398     * var rAFProp = prefixed('requestAnimationFrame', window, false);
3399     *
3400     * rafProp === 'WebkitRequestAnimationFrame' // in older webkit
3401     * ```
3402     *
3403     * One common use case for prefixed is if you're trying to determine which transition
3404     * end event to bind to, you might do something like...
3405     * ```js
3406     * var transEndEventNames = {
3407   *     'WebkitTransition' : 'webkitTransitionEnd', * Saf 6, Android Browser
3408   *     'MozTransition'    : 'transitionend',       * only for FF < 15
3409   *     'transition'       : 'transitionend'        * IE10, Opera, Chrome, FF 15+, Saf 7+
3410   * };
3411     *
3412     * var transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
3413     * ```
3414     *
3415     * If you want a similar lookup, but in kebab-case, you can use [prefixedCSS](#modernizr-prefixedcss).
3416     */
3417
3418    var prefixed = ModernizrProto.prefixed = function(prop, obj, elem) {
3419        if (prop.indexOf('@') === 0) {
3420            return atRule(prop);
3421        }
3422
3423        if (prop.indexOf('-') != -1) {
3424            // Convert kebab-case to camelCase
3425            prop = cssToDOM(prop);
3426        }
3427        if (!obj) {
3428            return testPropsAll(prop, 'pfx');
3429        } else {
3430            // Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame'
3431            return testPropsAll(prop, obj, elem);
3432        }
3433    };
3434
3435
3436    /*!
3437     {
3438     "name": "IndexedDB",
3439     "property": "indexeddb",
3440     "caniuse": "indexeddb",
3441     "tags": ["storage"],
3442     "polyfills": ["indexeddb"]
3443     }
3444     !*/
3445    /* DOC
3446     Detects support for the IndexedDB client-side storage API (final spec).
3447     */
3448
3449    // Vendors had inconsistent prefixing with the experimental Indexed DB:
3450    // - Webkit's implementation is accessible through webkitIndexedDB
3451    // - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB
3452    // For speed, we don't test the legacy (and beta-only) indexedDB
3453
3454    var indexeddb;
3455    try {
3456        indexeddb = prefixed('indexedDB', window);
3457    } catch (e) {
3458    }
3459
3460    Modernizr.addTest('indexeddb', !!indexeddb);
3461
3462    if (!!indexeddb) {
3463        Modernizr.addTest('indexeddb.deletedatabase', 'deleteDatabase' in indexeddb);
3464    }
3465    ;
3466
3467    /**
3468     * testAllProps determines whether a given CSS property is supported in the browser
3469     *
3470     * @memberof Modernizr
3471     * @name Modernizr.testAllProps
3472     * @optionName Modernizr.testAllProps()
3473     * @optionProp testAllProps
3474     * @access public
3475     * @function testAllProps
3476     * @param {string} prop - String naming the property to test (either camelCase or kebab-case)
3477     * @param {string} [value] - String of the value to test
3478     * @param {boolean} [skipValueTest=false] - Whether to skip testing that the value is supported when using non-native detection
3479     * @example
3480     *
3481     * testAllProps determines whether a given CSS property, in some prefixed form,
3482     * is supported by the browser.
3483     *
3484     * ```js
3485     * testAllProps('boxSizing')  // true
3486     * ```
3487     *
3488     * It can optionally be given a CSS value in string form to test if a property
3489     * value is valid
3490     *
3491     * ```js
3492     * testAllProps('display', 'block') // true
3493     * testAllProps('display', 'penguin') // false
3494     * ```
3495     *
3496     * A boolean can be passed as a third parameter to skip the value check when
3497     * native detection (@supports) isn't available.
3498     *
3499     * ```js
3500     * testAllProps('shapeOutside', 'content-box', true);
3501     * ```
3502     */
3503
3504    function testAllProps(prop, value, skipValueTest) {
3505        return testPropsAll(prop, undefined, undefined, value, skipValueTest);
3506    }
3507    ModernizrProto.testAllProps = testAllProps;
3508
3509    /*!
3510     {
3511     "name": "CSS Animations",
3512     "property": "cssanimations",
3513     "caniuse": "css-animation",
3514     "polyfills": ["transformie", "csssandpaper"],
3515     "tags": ["css"],
3516     "warnings": ["Android < 4 will pass this test, but can only animate a single property at a time"],
3517     "notes": [{
3518     "name" : "Article: 'Dispelling the Android CSS animation myths'",
3519     "href": "https://goo.gl/OGw5Gm"
3520     }]
3521     }
3522     !*/
3523    /* DOC
3524     Detects whether or not elements can be animated using CSS
3525     */
3526
3527    Modernizr.addTest('cssanimations', testAllProps('animationName', 'a', true));
3528
3529    /*!
3530     {
3531     "name": "Background Size",
3532     "property": "backgroundsize",
3533     "tags": ["css"],
3534     "knownBugs": ["This will false positive in Opera Mini - https://github.com/Modernizr/Modernizr/issues/396"],
3535     "notes": [{
3536     "name": "Related Issue",
3537     "href": "https://github.com/Modernizr/Modernizr/issues/396"
3538     }]
3539     }
3540     !*/
3541
3542    Modernizr.addTest('backgroundsize', testAllProps('backgroundSize', '100%', true));
3543
3544    /*!
3545     {
3546     "name": "Border Image",
3547     "property": "borderimage",
3548     "caniuse": "border-image",
3549     "polyfills": ["css3pie"],
3550     "knownBugs": ["Android < 2.0 is true, but has a broken implementation"],
3551     "tags": ["css"]
3552     }
3553     !*/
3554
3555    Modernizr.addTest('borderimage', testAllProps('borderImage', 'url() 1', true));
3556
3557    /*!
3558     {
3559     "name": "Border Radius",
3560     "property": "borderradius",
3561     "caniuse": "border-radius",
3562     "polyfills": ["css3pie"],
3563     "tags": ["css"],
3564     "notes": [{
3565     "name": "Comprehensive Compat Chart",
3566     "href": "https://muddledramblings.com/table-of-css3-border-radius-compliance"
3567     }]
3568     }
3569     !*/
3570
3571    Modernizr.addTest('borderradius', testAllProps('borderRadius', '0px', true));
3572
3573    /*!
3574     {
3575     "name": "Box Shadow",
3576     "property": "boxshadow",
3577     "caniuse": "css-boxshadow",
3578     "tags": ["css"],
3579     "knownBugs": [
3580     "WebOS false positives on this test.",
3581     "The Kindle Silk browser false positives"
3582     ]
3583     }
3584     !*/
3585
3586    Modernizr.addTest('boxshadow', testAllProps('boxShadow', '1px 1px', true));
3587
3588    /*!
3589     {
3590     "name": "CSS Columns",
3591     "property": "csscolumns",
3592     "caniuse": "multicolumn",
3593     "polyfills": ["css3multicolumnjs"],
3594     "tags": ["css"]
3595     }
3596     !*/
3597
3598
3599    (function() {
3600
3601        /* jshint -W053 */
3602        Modernizr.addTest('csscolumns', function() {
3603            var bool = false;
3604            var test = testAllProps('columnCount');
3605            try {
3606                if (bool = !!test) {
3607                    bool = new Boolean(bool);
3608                }
3609            } catch (e) {}
3610
3611            return bool;
3612        });
3613
3614        var props = ['Width', 'Span', 'Fill', 'Gap', 'Rule', 'RuleColor', 'RuleStyle', 'RuleWidth', 'BreakBefore', 'BreakAfter', 'BreakInside'];
3615        var name, test;
3616
3617        for (var i = 0; i < props.length; i++) {
3618            name = props[i].toLowerCase();
3619            test = testAllProps('column' + props[i]);
3620
3621            // break-before, break-after & break-inside are not "column"-prefixed in spec
3622            if (name === 'breakbefore' || name === 'breakafter' || name == 'breakinside') {
3623                test = test || testAllProps(props[i]);
3624            }
3625
3626            Modernizr.addTest('csscolumns.' + name, test);
3627        }
3628
3629
3630    })();
3631
3632
3633    /*!
3634     {
3635     "name": "Flexbox",
3636     "property": "flexbox",
3637     "caniuse": "flexbox",
3638     "tags": ["css"],
3639     "notes": [{
3640     "name": "The _new_ flexbox",
3641     "href": "http://dev.w3.org/csswg/css3-flexbox"
3642     }],
3643     "warnings": [
3644     "A `true` result for this detect does not imply that the `flex-wrap` property is supported; see the `flexwrap` detect."
3645     ]
3646     }
3647     !*/
3648    /* DOC
3649     Detects support for the Flexible Box Layout model, a.k.a. Flexbox, which allows easy manipulation of layout order and sizing within a container.
3650     */
3651
3652    Modernizr.addTest('flexbox', testAllProps('flexBasis', '1px', true));
3653
3654    /*!
3655     {
3656     "name": "CSS Reflections",
3657     "caniuse": "css-reflections",
3658     "property": "cssreflections",
3659     "tags": ["css"]
3660     }
3661     !*/
3662
3663    Modernizr.addTest('cssreflections', testAllProps('boxReflect', 'above', true));
3664
3665    /*!
3666     {
3667     "name": "CSS Transforms",
3668     "property": "csstransforms",
3669     "caniuse": "transforms2d",
3670     "tags": ["css"]
3671     }
3672     !*/
3673
3674    Modernizr.addTest('csstransforms', function() {
3675        // Android < 3.0 is buggy, so we sniff and blacklist
3676        // http://git.io/hHzL7w
3677        return navigator.userAgent.indexOf('Android 2.') === -1 &&
3678            testAllProps('transform', 'scale(1)', true);
3679    });
3680
3681    /*!
3682     {
3683     "name": "CSS Transforms 3D",
3684     "property": "csstransforms3d",
3685     "caniuse": "transforms3d",
3686     "tags": ["css"],
3687     "warnings": [
3688     "Chrome may occassionally fail this test on some systems; more info: https://code.google.com/p/chromium/issues/detail?id=129004"
3689     ]
3690     }
3691     !*/
3692
3693    Modernizr.addTest('csstransforms3d', function() {
3694        var ret = !!testAllProps('perspective', '1px', true);
3695        var usePrefix = Modernizr._config.usePrefixes;
3696
3697        // Webkit's 3D transforms are passed off to the browser's own graphics renderer.
3698        //   It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in
3699        //   some conditions. As a result, Webkit typically recognizes the syntax but
3700        //   will sometimes throw a false positive, thus we must do a more thorough check:
3701        if (ret && (!usePrefix || 'webkitPerspective' in docElement.style)) {
3702            var mq;
3703            var defaultStyle = '#modernizr{width:0;height:0}';
3704            // Use CSS Conditional Rules if available
3705            if (Modernizr.supports) {
3706                mq = '@supports (perspective: 1px)';
3707            } else {
3708                // Otherwise, Webkit allows this media query to succeed only if the feature is enabled.
3709                // `@media (transform-3d),(-webkit-transform-3d){ ... }`
3710                mq = '@media (transform-3d)';
3711                if (usePrefix) {
3712                    mq += ',(-webkit-transform-3d)';
3713                }
3714            }
3715
3716            mq += '{#modernizr{width:7px;height:18px;margin:0;padding:0;border:0}}';
3717
3718            testStyles(defaultStyle + mq, function(elem) {
3719                ret = elem.offsetWidth === 7 && elem.offsetHeight === 18;
3720            });
3721        }
3722
3723        return ret;
3724    });
3725
3726    /*!
3727     {
3728     "name": "CSS Transitions",
3729     "property": "csstransitions",
3730     "caniuse": "css-transitions",
3731     "tags": ["css"]
3732     }
3733     !*/
3734
3735    Modernizr.addTest('csstransitions', testAllProps('transition', 'all', true));
3736
3737
3738    // Run each test
3739    testRunner();
3740
3741    // Remove the "no-js" class if it exists
3742    setClasses(classes);
3743
3744    delete ModernizrProto.addTest;
3745    delete ModernizrProto.addAsyncTest;
3746
3747    // Run the things that are supposed to run after the tests
3748    for (var i = 0; i < Modernizr._q.length; i++) {
3749        Modernizr._q[i]();
3750    }
3751
3752    // Leak Modernizr namespace
3753    window.Modernizr = Modernizr;
3754
3755
3756    ;
3757
3758})(window, document);;
3759/**
3760 * File skip-link-focus-fix.js.
3761 *
3762 * Helps with accessibility for keyboard only users.
3763 *
3764 * This is the source file for what is minified in the varia_skip_link_focus_fix() PHP function.
3765 *
3766 * Learn more: https://git.io/vWdr2
3767 */
3768( function() {
3769	var isIe = /(trident|msie)/i.test( navigator.userAgent );
3770
3771	if ( isIe && document.getElementById && window.addEventListener ) {
3772		window.addEventListener( 'hashchange', function() {
3773			var id = location.hash.substring( 1 ),
3774				element;
3775
3776			if ( ! ( /^[A-z0-9_-]+$/.test( id ) ) ) {
3777				return;
3778			}
3779
3780			element = document.getElementById( id );
3781
3782			if ( element ) {
3783				if ( ! ( /^(?:a|select|input|button|textarea)$/i.test( element.tagName ) ) ) {
3784					element.tabIndex = -1;
3785				}
3786
3787				element.focus();
3788			}
3789		}, false );
3790	}
3791} )();
3792;
3793/*! This file is auto-generated */
3794/*!
3795 * imagesLoaded PACKAGED v5.0.0
3796 * JavaScript is all like "You images are done yet or what?"
3797 * MIT License
3798 */
3799!function(t,e){"object"==typeof module&&module.exports?module.exports=e():t.EvEmitter=e()}("undefined"!=typeof window?window:this,(function(){function t(){}let e=t.prototype;return e.on=function(t,e){if(!t||!e)return this;let i=this._events=this._events||{},s=i[t]=i[t]||[];return s.includes(e)||s.push(e),this},e.once=function(t,e){if(!t||!e)return this;this.on(t,e);let i=this._onceEvents=this._onceEvents||{};return(i[t]=i[t]||{})[e]=!0,this},e.off=function(t,e){let i=this._events&&this._events[t];if(!i||!i.length)return this;let s=i.indexOf(e);return-1!=s&&i.splice(s,1),this},e.emitEvent=function(t,e){let i=this._events&&this._events[t];if(!i||!i.length)return this;i=i.slice(0),e=e||[];let s=this._onceEvents&&this._onceEvents[t];for(let n of i){s&&s[n]&&(this.off(t,n),delete s[n]),n.apply(this,e)}return this},e.allOff=function(){return delete this._events,delete this._onceEvents,this},t})),
3800/*!
3801 * imagesLoaded v5.0.0
3802 * JavaScript is all like "You images are done yet or what?"
3803 * MIT License
3804 */
3805function(t,e){"object"==typeof module&&module.exports?module.exports=e(t,require("ev-emitter")):t.imagesLoaded=e(t,t.EvEmitter)}("undefined"!=typeof window?window:this,(function(t,e){let i=t.jQuery,s=t.console;
3805function n(t,e,o){if(!(this instanceof n))return new n(t,e,o);let r=t;var h;("string"==typeof t&&(r=document.querySelectorAll(t)),r)?(this.elements=(h=r,Array.isArray(h)?h:"object"==typeof h&&"number"==typeof h.length?[...h]:[h]),this.options={},"function"==typeof e?o=e:Object.assign(this.options,e),o&&this.on("always",o),this.getImages(),i&&(this.jqDeferred=new i.Deferred),setTimeout(this.check.bind(this))):s.error(`Bad element for imagesLoaded ${r||t}`)}n.prototype=Object.create(e.prototype),n.prototype.getImages=function(){this.images=[],this.elements.forEach(this.addElementImages,this)};const o=[1,9,11];n.prototype.addElementImages=function(t){"IMG"===t.nodeName&&this.addImage(t),!0===this.options.background&&this.addElementBackgroundImages(t);let{nodeType:e}=t;if(!e||!o.includes(e))return;let i=t.querySelectorAll("img");for(let t of i)this.addImage(t);if("string"==typeof this.options.background){let e=t.querySelectorAll(this.options.background);for(let t of e)this.addElementBackgroundImages(t)}};const r=/url\((['"])?(.*?)\1\)/gi;function h(t){this.img=t}function d(t,e){this.url=t,this.element=e,this.img=new Image}return n.prototype.addElementBackgroundImages=function(t){let e=getComputedStyle(t);if(!e)return;let i=r.exec(e.backgroundImage);for(;null!==i;){let s=i&&i[2];s&&this.addBackground(s,t),i=r.exec(e.backgroundImage)}},n.prototype.addImage=function(t){let e=new h(t);this.images.push(e)},n.prototype.addBackground=function(t,e){let i=new d(t,e);this.images.push(i)},n.prototype.check=function(){if(this.progressedCount=0,this.hasAnyBroken=!1,!this.images.length)return void this.complete();let t=(t,e,i)=>{setTimeout((()=>{this.progress(t,e,i)}))};this.images.forEach((function(e){e.once("progress",t),e.check()}))},n.prototype.progress=function(t,e,i){this.progressedCount++,this.hasAnyBroken=this.hasAnyBroken||!t.isLoaded,this.emitEvent("progress",[this,t,e]),this.jqDeferred&&this.jqDeferred.notify&&this.jqDeferred.notify(this,t),this.progressedCount===this.images.length&&this.complete(),this.options.debug&&s&&s.log(`progress: ${i}`,t,e)},n.prototype.complete=function(){let t=this.hasAnyBroken?"fail":"done";if(this.isComplete=!0,this.emitEvent(t,[this]),this.emitEvent("always",[this]),this.jqDeferred){let t=this.hasAnyBroken?"reject":"resolve";this.jqDeferred[t](this)}},h.prototype=Object.create(e.prototype),h.prototype.check=function(){this.getIsImageComplete()?this.confirm(0!==this.img.naturalWidth,"naturalWidth"):(this.proxyImage=new Image,this.img.crossOrigin&&(this.proxyImage.crossOrigin=this.img.crossOrigin),this.proxyImage.addEventListener("load",this),this.proxyImage.addEventListener("error",this),this.img.addEventListener("load",this),this.img.addEventListener("error",this),this.proxyImage.src=this.img.currentSrc||this.img.src)},h.prototype.getIsImageComplete=function(){return this.img.complete&&this.img.naturalWidth},h.prototype.confirm=function(t,e){this.isLoaded=t;let{parentNode:i}=this.img,s="PICTURE"===i.nodeName?i:this.img;this.emitEvent("progress",[this,s,e])},h.prototype.handleEvent=function(t){let e="on"+t.type;this[e]&&this[e](t)},h.prototype.onload=function(){this.confirm(!0,"onload"),this.unbindEvents()},h.prototype.onerror=function(){this.confirm(!1,"onerror"),this.unbindEvents()},h.prototype.unbindEvents=function(){this.proxyImage.removeEventListener("load",this),this.proxyImage.removeEventListener("error",this),this.img.removeEventListener("load",this),this.img.removeEventListener("error",this)},d.prototype=Object.create(h.prototype),d.prototype.check=function(){this.img.addEventListener("load",this),this.img.addEventListener("error",this),this.img.src=this.url,this.getIsImageComplete()&&(this.confirm(0!==this.img.naturalWidth,"naturalWidth"),this.unbindEvents())},d.prototype.unbindEvents=function(){this.img.removeEventListener("load",this),this.img.removeEventListener("error",this)},d.prototype.confirm=function(t,e){this.isLoaded=t,this.emitEvent("progress",[this,this.element,e])},n.makeJQueryPlugin=function(e){(e=e||t.jQuery)&&(i=e,i.fn.imagesLoaded=function(t,e){return new n(this,t,e).jqDeferred.promise(i(this))})},n.makeJQueryPlugin(),n}));;
3806/**
3807 * jQuery plugin to make the main navigation WAI-ARIA compatible
3808 * Inspired by http://simplyaccessible.com/examples/css-menu/option-6/
3809 *
3810 * It needs jquery.hoverIntent
3811 */
3812(function($) {
3813
3814    $.fn.ariaNavigation = function(settings) {
3815
3816        //Map of all the alphanumeric keys so one can jump through submenus by typing the first letter
3817        //Also use the ESC key to close a submenu
3818        var keyCodeMap = {
3819                48: "0",
3820                49: "1",
3821                50: "2",
3822                51: "3",
3823                52: "4",
3824                53: "5",
3825                54: "6",
3826                55: "7",
3827                56: "8",
3828                57: "9",
3829                59: ";",
3830                65: "a",
3831                66: "b",
3832                67: "c",
3833                68: "d",
3834                69: "e",
3835                70: "f",
3836                71: "g",
3837                72: "h",
3838                73: "i",
3839                74: "j",
3840                75: "k",
3841                76: "l",
3842                77: "m",
3843                78: "n",
3844                79: "o",
3845                80: "p",
3846                81: "q",
3847                82: "r",
3848                83: "s",
3849                84: "t",
3850                85: "u",
3851                86: "v",
3852                87: "w",
3853                88: "x",
3854                89: "y",
3855                90: "z",
3856                96: "0",
3857                97: "1",
3858                98: "2",
3859                99: "3",
3860                100: "4",
3861                101: "5",
3862                102: "6",
3863                103: "7",
3864                104: "8",
3865                105: "9"
3866            },
3867            $nav = $(this),
3868            $allLinks = $nav.find('li.menu-item > a, li.page_item > a'),
3869            $topLevelLinks = $nav.find('> li > a'),
3870            subLevelLinks = $topLevelLinks.parent('li').find('ul').find('a');
3871        navWidth = $nav.outerWidth();
3872
3873        //default settings
3874        settings = jQuery.extend({
3875            menuHoverClass: 'show-menu',
3876            topMenuHoverClass: 'hover'
3877        }, settings);
3878
3879
3880        /**
3881         *  First add the needed WAI-ARIA markup - supercharge the menu
3882         */
3883
3884        // Add ARIA role to menubar and menu items
3885        //$nav.find( 'li' ).attr( 'role', 'menuitem' );
3886
3887        $topLevelLinks.each(function() {
3888            //for regular sub-menus
3889            // Set tabIndex to -1 so that links can't receive focus until menu is open
3890            $(this).next('ul')
3891                .attr({
3892                    'aria-hidden': 'true',
3893                    'role': 'menu'
3894                })
3895                .find('a')
3896                .attr('tabIndex', -1);
3897
3898            // Add aria-haspopup for appropriate items
3899            if ($(this).next('ul').length > 0) {
3900                $(this).parent('li').attr('aria-haspopup', 'true');
3901            }
3902
3903            // Set tabIndex to -1 so that links can't receive focus until menu is open
3904            $(this).next('.menu-item-has-children').children('ul')
3905                .attr({
3906                    'aria-hidden': 'true',
3907                    'role': 'menu'
3908                })
3909                .find('a').attr('tabIndex', -1);
3910
3911            $(this).next('.menu-item-has-children')
3912                .find('a').attr('tabIndex', -1);
3913
3914            // Add aria-haspopup for appropriate items
3915            if ($(this).next('.sub-menu').length > 0)
3916                $(this).parent('li').attr('aria-haspopup', 'true');
3917
3918            // Set tabIndex to -1 so that links can't receive focus until menu is open
3919            $(this).next('.page_item_has_children').children('ul')
3920                .attr({
3921                    'aria-hidden': 'true',
3922                    'role': 'menu'
3923                })
3924                .find('a').attr('tabIndex', -1);
3925
3926            $(this).next('.page_item_has_children')
3927                .find('a').attr('tabIndex', -1);
3928
3929            // Add aria-haspopup for appropriate items
3930            if ($(this).next('.children').length > 0)
3931                $(this).parent('li').attr('aria-haspopup', 'true');
3932        });
3933
3934
3935        /**
3936         * Now let's begin binding things to their proper events
3937         */
3938
3939        // First, bind to the hover event
3940        // use hoverIntent to make sure we avoid flicker
3941        $allLinks.closest('li').hoverIntent({
3942            over: function() {
3943                //clean up first
3944                $(this).closest('ul')
3945                    .find('ul.' + settings.menuHoverClass)
3946                    .attr('aria-hidden', 'true')
3947                    .removeClass(settings.menuHoverClass)
3948                    .find('a')
3949                    .attr('tabIndex', -1);
3950
3951                $(this).closest('ul')
3952                    .find('.' + settings.topMenuHoverClass)
3953                    .removeClass(settings.topMenuHoverClass);
3954
3955                //now do things
3956                showSubMenu($(this));
3957
3958            },
3959            out: function() {
3960                hideSubMenu($(this));
3961            },
3962            timeout: 10
3963        });
3964
3965        // Secondly, bind to the focus event - very important for WAI-ARIA purposes
3966        $allLinks.focus(function() {
3967            //clean up first
3968            $(this).closest('ul')
3969                .find('ul.' + settings.menuHoverClass)
3970                .attr('aria-hidden', 'true')
3971                .removeClass(settings.menuHoverClass)
3972                .find('a')
3973                .attr('tabIndex', -1);
3974
3975            $(this).closest('ul')
3976                .find('.' + settings.topMenuHoverClass)
3977                .removeClass(settings.topMenuHoverClass);
3978
3979            //now do things
3980            showSubMenu($(this).closest('li'));
3981
3982        });
3983
3984
3985        // Now bind arrow keys for navigating the menu
3986
3987        // First the top level links (the permanent visible links)
3988        $topLevelLinks.keydown(function(e) {
3989            var $item = $(this);
3990
3991            if (e.keyCode == 37) { //left arrow
3992                e.preventDefault();
3993                // This is the first item
3994                if ($item.parent('li').prev('li').length == 0) {
3995                    $item.parents('ul').find('> li').last().find('a').first().focus();
3996                } else {
3997                    $item.parent('li').prev('li').find('a').first().focus();
3998                }
3999            } else if (e.keyCode == 38) { //up arrow
4000                e.preventDefault();
4001                if ($item.parent('li').find('ul').length > 0) {
4002                    $item.parent('li').find('ul')
4003                        .attr('aria-hidden', 'false')
4004                        .addClass(settings.menuHoverClass)
4005                        .find('a').attr('tabIndex', 0)
4006                        .last().focus();
4007                }
4008            } else if (e.keyCode == 39) { //right arrow
4009                e.preventDefault();
4010
4011                // This is the last item
4012                if ($item.parent('li').next('li').length == 0) {
4013                    $item.parents('ul').find('> li').first().find('a').first().focus();
4014                } else {
4015                    $item.parent('li').next('li').find('a').first().focus();
4016                }
4017            } else if (e.keyCode == 40) { //down arrow
4018                e.preventDefault();
4019                if ($item.parent('li').find('ul').length > 0) {
4020                    $item.parent('li').find('ul')
4021                        .attr('aria-hidden', 'false')
4022                        .addClass(settings.menuHoverClass)
4023                        .find('a').attr('tabIndex', 0)
4024                        .first().focus();
4025                }
4026            } else if (e.keyCode == 32) { //space key
4027                // If submenu is hidden, open it
4028                e.preventDefault();
4029                $item.parent('li').find('ul[aria-hidden=true]')
4030                    .attr('aria-hidden', 'false')
4031                    .addClass(settings.menuHoverClass)
4032                    .find('a').attr('tabIndex', 0)
4033                    .first().focus();
4034            } else if (e.keyCode == 27) { //escape key
4035                e.preventDefault();
4036                $('.' + settings.menuHoverClass)
4037                    .attr('aria-hidden', 'true')
4038                    .removeClass(settings.menuHoverClass)
4039                    .find('a')
4040                    .attr('tabIndex', -1);
4041            } else { //cycle through the child submenu items based on the first letter
4042                $item.parent('li').find('ul[aria-hidden=false] > li > a').each(function() {
4043                    if ($(this).text().substring(0, 1).toLowerCase() == keyCodeMap[e.keyCode]) {
4044                        $(this).focus();
4045                        return false;
4046                    }
4047                });
4048            }
4049        });
4050
4051        // Now do the keys bind for the submenus links
4052        $(subLevelLinks).keydown(function(e) {
4053            var $item = $(this);
4054
4055            if (e.keyCode == 38) { //up arrow
4056                e.preventDefault();
4057                // This is the first item
4058                if ($item.parent('li').prev('li').length == 0) {
4059                    $item.parents('ul').parents('li').find('a').first().focus();
4060                } else {
4061                    $item.parent('li').prev('li').find('a').first().focus();
4062                }
4063            } else if (e.keyCode == 39) { //right arrow
4064                e.preventDefault();
4065
4066                //if it has sub-menus we should go into them
4067                if ($item.parent('li').hasClass('menu-item-has-children')) {
4068                    $item.next('ul').find('> li').first().find('a').first().focus();
4069                } else {
4070                    // This is the last item
4071                    if ($item.parent('li').next('li').length == 0) {
4072                        $item.closest('ul').closest('li').children('a').first().focus();
4073                    } else {
4074                        $item.parent('li').next('li').find('a').first().focus();
4075                    }
4076                }
4077            } else if (e.keyCode == 40) { //down arrow
4078                e.preventDefault();
4079
4080                // This is the last item
4081                if ($item.parent('li').next('li').length == 0) {
4082                    $item.closest('ul').closest('li').children('a').first().focus();
4083                } else {
4084                    $item.parent('li').next('li').find('a').first().focus();
4085                }
4086            } else if (e.keyCode == 27 || e.keyCode == 37) { //escape key or left arrow => jump to the upper level links
4087                e.preventDefault();
4088
4089                //focus on the upper level link
4090                $item.closest('ul').closest('li')
4091                    .children('a').first().focus();
4092
4093            } else if (e.keyCode == 32) { //space key
4094                e.preventDefault();
4095                window.location = $item.attr('href');
4096            } else {
4097
4098                //cycle through the menu items based on the first letter
4099                var found = false;
4100                $item.parent('li').nextAll('li').find('a').each(function() {
4101                    if ($(this).text().substring(0, 1).toLowerCase() == keyCodeMap[e.keyCode]) {
4102                        $(this).focus();
4103                        found = true;
4104                        return false;
4105                    }
4106                });
4107
4108                if (!found) {
4109                    $item.parent('li').prevAll('li').find('a').each(function() {
4110                        if ($(this).text().substring(0, 1).toLowerCase() == keyCodeMap[e.keyCode]) {
4111                            $(this).focus();
4112                            return false;
4113                        }
4114                    });
4115                }
4116            }
4117        });
4118
4119
4120        // Hide menu if click or focus occurs outside of navigation
4121        $nav.find('a').last().keydown(function(e) {
4122            if (e.keyCode == 9) { //tab key
4123                // If the user tabs out of the navigation hide all menus
4124                hideSubMenus();
4125            }
4126        });
4127
4128        //close all menus when pressing ESC key
4129        $(document).keydown(function(e) {
4130            if (e.keyCode == 27) { //esc key
4131                hideSubMenus();
4132            }
4133        });
4134
4135        //close all menus on click outside
4136        $(document).click(function() {
4137            hideSubMenus();
4138        });
4139
4140        $nav.on('click touchstart', function(e) {
4141            e.stopPropagation();
4142        });
4143
4144        function getIOSVersion(ua) {
4145            ua = ua || navigator.userAgent;
4146            return parseFloat(
4147                ('' + (/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec(ua) || [0, ''])[1])
4148                .replace('undefined', '3_2').replace('_', '.').replace('_', '')
4149            ) || false;
4150        }
4151
4152        function showSubMenu($item) {
4153
4154            $item.addClass(settings.topMenuHoverClass);
4155
4156            $item.find('.sub-menu, .children').first() //affect only the first ul found - the one with the submenus, ignore the mega menu items
4157                .attr('aria-hidden', 'false')
4158                .addClass(settings.menuHoverClass);
4159
4160            $item.find('a').attr('tabIndex', 0); //set the tabIndex to 0 so we let the browser figure out the tab order
4161
4162        }
4163
4164        function hideSubMenu($item) {
4165
4166            if ($item.hasClass('menu-item-has-children')) {
4167                $item.children('.sub-menu').css('left', '');
4168            }
4169
4170            if ($item.hasClass('page_item_has_children')) {
4171                $item.children('.children').css('left', '');
4172            }
4173
4174            $item.children('a').first().next('ul')
4175                .attr('aria-hidden', 'true')
4176                .removeClass(settings.menuHoverClass)
4177                .find('a')
4178                .attr('tabIndex', -1);
4179
4180            //when dealing with first level submenus - they are wrapped
4181            $item.children('a').first().next('.sub-menu')
4182                .attr('aria-hidden', 'true')
4183                .removeClass(settings.menuHoverClass)
4184                .find('a')
4185                .attr('tabIndex', -1);
4186
4187            $item.children('a').first().next('.children')
4188                .attr('aria-hidden', 'true')
4189                .removeClass(settings.menuHoverClass)
4190                .find('a')
4191                .attr('tabIndex', -1);
4192
4193            $item.removeClass(settings.topMenuHoverClass);
4194        }
4195
4196        function hideSubMenus() {
4197
4198            $('.' + settings.menuHoverClass)
4199                .attr('aria-hidden', 'true')
4200                .removeClass(settings.menuHoverClass)
4201                .find('a')
4202                .attr('tabIndex', -1);
4203
4204            $('.' + settings.topMenuHoverClass).removeClass(settings.topMenuHoverClass);
4205
4206        }
4207    }
4208
4209})(jQuery);
4210
4211/*!
4212 * hoverIntent v1.8.0 // 2014.06.29 // jQuery v1.9.1+
4213 * http://cherne.net/brian/resources/jquery.hoverIntent.html
4214 *
4215 * You may use hoverIntent under the terms of the MIT license. Basically that
4216 * means you are free to use hoverIntent as long as this header is left intact.
4217 * Copyright 2007, 2014 Brian Cherne
4218 */
4219(function($) {
4220    $.fn.hoverIntent = function(handlerIn, handlerOut, selector) {
4221        var cfg = {
4222            interval: 100,
4223            sensitivity: 6,
4224            timeout: 0
4225        };
4226        if (typeof handlerIn === "object") {
4227            cfg = $.extend(cfg, handlerIn)
4228        } else {
4229            if ($.isFunction(handlerOut)) {
4230                cfg = $.extend(cfg, {
4231                    over: handlerIn,
4232                    out: handlerOut,
4233                    selector: selector
4234                })
4235            } else {
4236                cfg = $.extend(cfg, {
4237                    over: handlerIn,
4238                    out: handlerIn,
4239                    selector: handlerOut
4240                })
4241            }
4242        }
4243        var cX, cY, pX, pY;
4244        var track = function(ev) {
4245            cX = ev.pageX;
4246            cY = ev.pageY
4247        };
4248        var compare = function(ev, ob) {
4249            ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
4250            if (Math.sqrt((pX - cX) * (pX - cX) + (pY - cY) * (pY - cY)) < cfg.sensitivity) {
4251                $(ob).off("mousemove.hoverIntent", track);
4252                ob.hoverIntent_s = true;
4253                return cfg.over.apply(ob, [ev])
4254            } else {
4255                pX = cX;
4256                pY = cY;
4257                ob.hoverIntent_t = setTimeout(function() {
4258                    compare(ev, ob)
4259                }, cfg.interval)
4260            }
4261        };
4262        var delay = function(ev, ob) {
4263            ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
4264            ob.hoverIntent_s = false;
4265            return cfg.out.apply(ob, [ev])
4266        };
4267        var handleHover = function(e) {
4268            var ev = $.extend({}, e);
4269            var ob = this;
4270            if (ob.hoverIntent_t) {
4271                ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t)
4272            }
4273            if (e.type === "mouseenter") {
4274                pX = ev.pageX;
4275                pY = ev.pageY;
4276                $(ob).on("mousemove.hoverIntent", track);
4277                if (!ob.hoverIntent_s) {
4278                    ob.hoverIntent_t = setTimeout(function() {
4279                        compare(ev, ob)
4280                    }, cfg.interval)
4281                }
4282            } else {
4283                $(ob).off("mousemove.hoverIntent", track);
4284                if (ob.hoverIntent_s) {
4285                    ob.hoverIntent_t = setTimeout(function() {
4286                        delay(ev, ob)
4287                    }, cfg.timeout)
4288                }
4289            }
4290        };
4291        return this.on({
4292            "mouseenter.hoverIntent": handleHover,
4293            "mouseleave.hoverIntent": handleHover
4294        }, cfg.selector)
4295    }
4296})(jQuery);
4297// /* ====== Smart Resize Logic ====== */
4298// It's best to debounce the resize event to a void performance hiccups
4299(function($, sr) {
4300
4301    /**
4302     * debouncing function from John Hann
4303     * http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
4304     */
4305    var debounce = function(func, threshold, execAsap) {
4306        var timeout;
4307
4308        return function debounced() {
4309            var obj = this,
4310                args = arguments;
4311
4312            function delayed() {
4313                if (!execAsap) func.apply(obj, args);
4314                timeout = null;
4315            }
4316
4317            if (timeout) clearTimeout(timeout);
4318            else if (execAsap) func.apply(obj, args);
4319
4320            timeout = setTimeout(delayed, threshold || 200);
4321        };
4322    }
4323    // smartresize
4324    jQuery.fn[sr] = function(fn) {
4325        return fn ? this.bind('resize', debounce(fn)) : this.trigger(sr);
4326    };
4327
4328})(jQuery, 'smartresize');
4329(function($, undefined) {
4330    // /* ====== SHARED VARS  - jQuery ====== */
4331    // These depend on jQuery
4332    var $window = $(window),
4333        windowHeight = $window.height(),
4334        windowWidth = $window.width(),
4335        latestKnownScrollY = window.scrollY,
4336        ticking = false,
4337        isTouchDevice = !!('ontouchstart' in window),
4338        $body = $('body'),
4339        isWekbit = ('WebkitAppearance' in document.documentElement.style) ? true : false,
4340        isIE = typeof(is_ie) !== "undefined" || (!(window.ActiveXObject) && "ActiveXObject" in window),
4341        isiele10 = navigator.userAgent.match(/msie (9|([1-9][0-9]))/i);
4342    var Grid = function() {
4343
4344    };
4345
4346    Grid.prototype.refresh = function() {
4347        this.alignTitles();
4348        this.addMargins();
4349        this.adjustCardMeta();
4350        this.offsetFirstColumn();
4351    };
4352
4353    Grid.prototype.alignTitles = function() {
4354
4355        $('.card-title-wrap').each(function(i, obj) {
4356            var $title = $(obj);
4357            $title.closest('.card__wrap').css('paddingBottom', $title.outerHeight() * 0.5);
4358        });
4359
4360    };
4361
4362    Grid.prototype.addMargins = function() {
4363
4364        var $columns = $('.column'),
4365            $compare;
4366
4367        $('.grid__item--mb').removeClass('grid__item--mb');
4368
4369        $columns.each(function(i, column) {
4370            var $column = $(column);
4371
4372            if (i % 2 == 1) {
4373
4374                $column.children('.entry-card--portrait, .entry-card--text').each(function(j, obj) {
4375                    var $obj = $(obj);
4376
4377                    if ($obj.is(':nth-child(2n+1)')) {
4378                        $compare = $columns.eq(i - 1);
4379                    } else {
4380                        $compare = $columns.eq(i + 1);
4381                    }
4382
4383                    if (typeof $compare == "undefined") {
4384                        return;
4385                    }
4386
4387                    var bottom = $obj.offset().top + $obj.outerHeight(),
4388                        $neighbour;
4389
4390                    $compare.children().each(function(j, item) {
4391                        var $item = $(item),
4392                            thisBottom = $(item).offset().top + $(item).outerHeight();
4393
4394                        if (thisBottom < bottom) {
4395                            $neighbour = $item;
4396                        } else {
4397                            return false;
4398                        }
4399                    });
4400
4401                    if (typeof $neighbour !== "undefined") {
4402                        $neighbour.addClass('grid__item--mb');
4403                    }
4404                });
4405            }
4406        });
4407    };
4408
4409    Grid.prototype.showCards = function($cards) {
4410
4411        $cards.each(function(i, obj) {
4412            var $obj = $(obj);
4413
4414            setTimeout(function() {
4415                $obj.addClass('is-visible');
4416            }, i * 150);
4417
4418            setTimeout(function() {
4419                $obj.removeClass('ajax-loaded');
4420            }, 400 + i * 150);
4421
4422            $obj.imagesLoaded(function() {
4423
4424                var $img = $('<img>'),
4425                    $thumbnail = $obj.find('.card__image--large');
4426
4427                $img.attr('src', $thumbnail.data('src'));
4428
4429                $img.imagesLoaded(function() {
4430                    $obj.addClass('is-loaded');
4431                });
4432
4433                $thumbnail.replaceWith($img);
4434            });
4435        });
4436
4437    };
4438
4439    Grid.prototype.adjustCardMeta = function() {
4440
4441        if ($body.is('.singular') || windowWidth < 480) {
4442            $('.card__meta').attr('style', '');
4443        } else {
4444            $('.card--image').each(function(i, obj) {
4445                var $cardMeta = $(obj).find('.card__meta');
4446                $cardMeta.css('marginTop', -1 * $cardMeta.height());
4447            });
4448        }
4449
4450    };
4451
4452    Grid.prototype.offsetFirstColumn = function() {
4453        var $columns = $('.bricklayer-column');
4454        if ($columns.length > 1) {
4455            var height = $('.header .site-branding').outerHeight();
4456            $columns.css('marginTop', '').eq(1).css('marginTop', height);
4457        }
4458    };
4459
4460    Logo = function() {
4461
4462        this.$header = $('.header');
4463        this.$logo = $('.site-branding');
4464        this.$clone = null;
4465        this.distance = null;
4466        this.initialized = false;
4467
4468    };
4469
4470    Logo.prototype.adjustSiteTitle = function() {
4471
4472        $('.site-title').each(function(i, obj) {
4473            var $title = $(obj).removeAttr('style').css('fontSize', ''),
4474                $branding = $title.closest('.site-branding'),
4475                $span = $title.find('span'),
4476                titleWidth = $title.width(),
4477                brandingHeight,
4478                spanWidth = $span.width(),
4479                fontSize = parseInt($title.css('fontSize', '').css('fontSize')),
4480                scaling = spanWidth / parseFloat(titleWidth),
4481                maxLines = $body.is('.singular') ? 3 : 2;
4482
4483            /* if site title is too long use a smaller font size */
4484            if (spanWidth > titleWidth) {
4485                fontSize = parseInt(fontSize / scaling);
4486                $title.css('fontSize', fontSize);
4487            }
4488
4489            var titleHeight = $title.outerHeight();
4490
4491            if ($title.closest('.mobile-logo').length) {
4492                var mobileHeight = $('.mobile-logo').outerHeight();
4493                fontSize = parseInt(fontSize * mobileHeight / titleHeight);
4494                if (mobileHeight < titleHeight) {
4495                    $title.css('fontSize', fontSize);
4496                }
4497                return;
4498            }
4499
4500            brandingHeight = $branding.outerHeight();
4501
4502            /* if site title is too long use a smaller font size */
4503            if (brandingHeight < titleHeight) {
4504                fontSize = parseInt(fontSize * brandingHeight / t
4504itleHeight);
4505                $title.css('fontSize', fontSize);
4506                return;
4507            }
4508
4509            /* if site title is too tall, again, use a smaller font size */
4510            var lineHeight = parseFloat($title.css('lineHeight')) / fontSize,
4511                lines = Math.round(titleHeight / fontSize / lineHeight);
4512
4513            while (lines > maxLines) {
4514                fontSize = fontSize - 1;
4515                $title.css('fontSize', fontSize);
4516                titleHeight = $title.outerHeight();
4517                lines = titleHeight / fontSize / lineHeight;
4518            }
4519        });
4520    };
4521
4522    Logo.prototype.adjustArchiveTitle = function() {
4523
4524        $('.archive-title').each(function(i, obj) {
4525            var $title = $(obj).removeAttr('style').css('fontSize', ''),
4526                fontSize = parseInt($title.css('font-size')),
4527                $span = $title.find('span'),
4528                titleWidth = $title.width(),
4529                spanWidth = $span.width(),
4530                scaling = spanWidth / parseFloat(titleWidth);
4531
4532            /* if site title is too long use a smaller font size */
4533            if (spanWidth > titleWidth) {
4534                fontSize = parseInt(fontSize / scaling);
4535                $title.css('fontSize', fontSize);
4536            }
4537        });
4538
4539    };
4540
4541    Logo.prototype.prepare = function(scrollY) {
4542
4543        var that = this;
4544
4545        scrollY = scrollY || (window.pageYOffset || document.documentElement.scrollTop) - (document.documentElement.clientTop || 0);
4546
4547        if (that.$logo.length) {
4548
4549            that.$logo.imagesLoaded(function() {
4550
4551                if (that.$clone === null) {
4552                    that.$clone = that.$logo.clone().appendTo('.mobile-logo');
4553                } else {
4554                    that.$clone.removeAttr('style');
4555                }
4556
4557                that.logoMid = that.$logo.offset().top + that.$logo.height() / 2;
4558                that.cloneMid = that.$clone.offset().top + that.$clone.height() / 2 - scrollY;
4559                that.distance = that.logoMid - that.cloneMid;
4560
4561                that.initialized = true;
4562
4563                that.update(scrollY);
4564
4565                that.$clone.css('opacity', 1);
4566
4567            });
4568        }
4569    };
4570
4571    Logo.prototype.update = function(scrollY) {
4572
4573        if (!this.initialized) {
4574            return;
4575        }
4576
4577        if (this.distance < scrollY) {
4578            this.$clone.css('transform', 'none');
4579            return;
4580        }
4581
4582        this.$clone.css('transform', 'translateY(' + (this.distance - scrollY) + 'px)');
4583    };
4584
4585    /*!
4586     * pixelgradeTheme v1.0.1
4587     * Copyright (c) 2017 PixelGrade http://www.pixelgrade.com
4588     * Licensed under MIT http://www.opensource.org/licenses/mit-license.php/
4589     */
4590    var pixelgradeTheme = function() {
4591
4592        var _this = this,
4593            windowWidth = window.innerWidth,
4594            windowHeight = window.innerHeight,
4595            lastScrollY = (window.pageYOffset || document.documentElement.scrollTop) - (document.documentElement.clientTop || 0),
4596            orientation = windowWidth > windowHeight ? 'landscape' : 'portrait';
4597
4598        _this.ev = $({});
4599        _this.frameRendered = false;
4600        _this.debug = false;
4601
4602        _this.log = function() {
4603            if (_this.debug) {
4604                console.log.apply(this, arguments)
4605            }
4606        };
4607
4608        _this.getScroll = function() {
4609            return lastScrollY;
4610        };
4611
4612        _this.getWindowWidth = function() {
4613            return windowWidth;
4614        };
4615
4616        _this.getWindowHeight = function() {
4617            return windowHeight;
4618        };
4619
4620        _this.getOrientation = function() {
4621            return orientation;
4622        };
4623
4624        _this.onScroll = function() {
4625            if (_this.frameRendered === false) {
4626                return;
4627            }
4628            lastScrollY = (window.pageYOffset || document.documentElement.scrollTop) - (document.documentElement.clientTop || 0);
4629            _this.frameRendered = false;
4630        };
4631
4632        _this.onResize = function() {
4633            windowWidth = window.innerWidth;
4634            windowHeight = window.innerHeight;
4635
4636            var newOrientation = windowWidth > windowHeight ? 'landscape' : 'portrait';
4637
4638            _this.debouncedResize();
4639
4640            if (orientation !== newOrientation) {
4641                _this.debouncedOrientationChange();
4642            }
4643
4644            orientation = newOrientation;
4645        };
4646
4647        _this.debouncedResize = Util.debounce(function() {
4648            $(window).trigger('pxg:resize');
4649        }, 300);
4650
4651        _this.debouncedOrientationChange = Util.debounce(function() {
4652            $(window).trigger('pxg:orientationchange');
4653        }, 300);
4654
4655        _this.renderLoop = function() {
4656            if (_this.frameRendered === false) {
4657                _this.ev.trigger('render');
4658            }
4659            requestAnimationFrame(function() {
4660                _this.renderLoop();
4661                _this.frameRendered = true;
4662                _this.ev.trigger('afterRender');
4663            });
4664        };
4665
4666        _this.eventHandlers = function() {
4667            $(document).ready(_this.onReady);
4668            $(window)
4669                .on('scroll', _this.onScroll)
4670                .on('resize', _this.onResize)
4671                .on('load', _this.onLoad);
4672        };
4673
4674        _this.eventHandlers();
4675        _this.renderLoop();
4676    };
4677
4678    pixelgradeTheme.prototype.onReady = function() {
4679        $('html').addClass('is-ready');
4680    };
4681
4682    pixelgradeTheme.prototype.onLoad = function() {
4683        $('html').addClass('is-loaded');
4684    };
4685
4686    var Util = {
4687        /**
4688         *
4689         * @returns {boolean}
4690         */
4691        isTouch: function() {
4692            return !!(
4693                "ontouchstart" in window || window.DocumentTouch && document instanceof DocumentTouch
4694            );
4695        },
4696
4697        handleCustomCSS: function($container) {
4698            var $elements = typeof $container !== "undefined" ? $container.find("[data-css]") : $("[data-css]");
4699
4700            if ($elements.length) {
4701                $elements.each(function(i, obj) {
4702                    var $element = $(obj),
4703                        css = $element.data('css');
4704
4705                    if (typeof css !== "undefined") {
4706                        $element.replaceWith('<style type="text/css">' + css + '</style>');
4707                    }
4708                });
4709            }
4710        },
4711
4712
4713        /**
4714         * Search every image that is alone in a p tag and wrap it
4715         * in a figure element to behave like images with captions
4716         *
4717         * @param $container
4718         */
4719        unwrapImages: function($container) {
4720
4721            $container = typeof $container !== "undefined" ? $container : $body;
4722
4723            $container.find('p > img:first-child:last-child, p > a:first-child:last-child > img').each(function(i, obj) {
4724                var $obj = $(obj),
4725                    $image = $obj.closest('img'),
4726                    className = $image.attr('class'),
4727                    $p = $image.closest('p'),
4728                    $figure = $('<figure />').attr('class', className);
4729
4730                if ($.trim($p.text()).length) {
4731                    return;
4732                }
4733
4734                $figure.append($image.removeAttr('class'));
4735                $p.replaceWith($figure);
4736            });
4737        },
4738
4739        wrapEmbeds: function($container) {
4740            $container = typeof $container !== "undefined" ? $container : $('body');
4741            $container.children('iframe, embed, object').wrap('<p>');
4742        },
4743
4744        /**
4745         * Initialize video elements on demand from placeholders
4746         *
4747         * @param $container
4748         */
4749        handleVideos: function($container) {
4750            $container = typeof $container !== "undefined" ? $container : $body;
4751
4752            $container.find('.video-placeholder').each(function(i, obj) {
4753                var $placeholder = $(obj),
4754                    video = document.createElement('video'),
4755                    $video = $(video).addClass('c-hero__video');
4756
4757                // play as soon as possible
4758                video.onloadedmetadata = function() {
4759                    video.play();
4760                };
4761
4762                video.src = $placeholder.data('src');
4763                video.poster = $placeholder.data('poster');
4764                video.muted = true;
4765                video.loop = true;
4766
4767                $placeholder.replaceWith($video);
4768            });
4769        },
4770
4771        smoothScrollTo: function(to, duration, easing) {
4772            to = to || 0;
4773            duration = duration || 1000;
4774            easing = easing || 'swing';
4775
4776            $("html, body").stop().animate({
4777                scrollTop: to
4778            }, duration, easing);
4779
4780        },
4781
4782        // Returns a function, that, as long as it continues to be invoked, will not
4783        // be triggered. The function will be called after it stops being called for
4784        // N milliseconds. If `immediate` is passed, trigger the function on the
4785        // leading edge, instead of the trailing.
4786        debounce: function(func, wait, immediate) {
4787            var timeout;
4788            return function() {
4789                var context = this,
4790                    args = arguments;
4791                var later = function() {
4792                    timeout = null;
4793                    if (!immediate) {
4794                        func.apply(context, args);
4795                    }
4796                };
4797                var callNow = immediate && !timeout;
4798                clearTimeout(timeout);
4799                timeout = setTimeout(later, wait);
4800                if (callNow) {
4801                    func.apply(context, args);
4802                }
4803            };
4804        },
4805
4806        // Returns a function, that, when invoked, will only be triggered at most once
4807        // during a given window of time. Normally, the throttled function will run
4808        // as much as it can, without ever going more than once per `wait` duration;
4809        // but if you'd like to disable the execution on the leading edge, pass
4810        // `{leading: false}`. To disable execution on the trailing edge, ditto.
4811        throttle: function(callback, limit) {
4812            var wait = false;
4813            return function() {
4814                if (!wait) {
4815                    callback.call();
4816                    wait = true;
4817                    setTimeout(function() {
4818                        wait = false;
4819                    }, limit);
4820                }
4821            }
4822        },
4823
4824        mq: function(direction, string) {
4825            var $temp = $('<div class="u-mq-' + direction + '-' + string + '">').appendTo('body'),
4826                response = $temp.is(':visible');
4827
4828            $temp.remove();
4829            return response;
4830        },
4831
4832        below: function(string) {
4833            return this.mq('below', string);
4834        },
4835
4836        above: function(string) {
4837            return this.mq('above', string);
4838        },
4839
4840        getParamFromURL: function(param, url) {
4841            var parameters = (
4842                url.split('?')
4843            )[1];
4844
4845            if (typeof parameters === "undefined") {
4846                return parameters;
4847            }
4848
4849            parameters = parameters.split('&');
4850
4851            for (var i = 0; i < parameters.length; i++) {
4852                var parameter = parameters[i].split('=');
4853                if (parameter[0] === param) {
4854                    return parameter[1];
4855                }
4856            }
4857        },
4858
4859        reloadScript: function(filename) {
4860            var $old = $('script[src*="' + filename + '"]'),
4861                $new = $('<script>'),
4862                src = $old.attr('src');
4863
4864            if (!$old.length) {
4865                return;
4866            }
4867
4868            $old.replaceWith($new);
4869            $new.attr('src', src);
4870        },
4871
4872        // here we change the link of the Edit button in the Admin Bar
4873        // to make sure it reflects the current page
4874        adminBarEditFix: function(id, editString, taxonomy) {
4875            // get the admin ajax url and clean it
4876            var baseEditURL = juliaStrings.ajaxurl.replace('admin-ajax.php', 'post.php'),
4877                baseEditTaxURL = juliaStrings.ajaxurl.replace('admin-ajax.php', 'edit-tags.php'),
4878                $editButton = $('#wp-admin-bar-edit a');
4879
4880            if (!empty($editButton)) {
4881                if (id !== undefined && editString !== undefined) { //modify the current Edit button
4882                    if (!empty(taxonomy)) { //it seems we need to edit a taxonomy
4883                        $editButton.attr('href', baseEditTaxURL + '?tag_ID=' + id + '&taxonomy=' + taxonomy + '&action=edit');
4884                    } else {
4885                        $editButton.attr('href', baseEditURL + '?post=' + id + '&action=edit');
4886                    }
4887                    $editButton.html(editString);
4888                } else { // we have found an edit button but right now we don't need it anymore since we have no id
4889                    $('#wp-admin-bar-edit').remove();
4890                }
4891            } else { // upss ... no edit button
4892                // lets see if we need one
4893                if (id !== undefined && editString !== undefined) { //we do need one after all
4894                    //locate the New button because we need to add stuff after it
4895                    var $newButton = $('#wp-admin-bar-new-content');
4896
4897                    if (!empty($newButton)) {
4898                        if (!empty(taxonomy)) { //it seems we need to generate a taxonomy edit thingy
4899                            $newButton.after('<li id="wp-admin-bar-edit"><a class="ab-item dJAX_internal" href="' + baseEditTaxURL + '?tag_ID=' + id + '&taxonomy=' 
4899+ taxonomy + '&action=edit">' + editString + '</a></li>');
4900                        } else { //just a regular edit
4901                            $newButton.after('<li id="wp-admin-bar-edit"><a class="ab-item dJAX_internal" href="' + baseEditURL + '?post=' + id + '&action=edit">' + editString + '</a></li>');
4902                        }
4903                    }
4904                }
4905            }
4906
4907            //Also we need to fix the (no-)customize-support class on body by running the WordPress inline script again
4908            // The original code is generated by the wp_customize_support_script() function in wp-includes/theme.php @3007
4909            var request, b = document.body,
4910                c = 'className',
4911                cs = 'customize-support',
4912                rcs = new RegExp('(^|\\s+)(no-)?' + cs + '(\\s+|$)');
4913
4914            // No CORS request
4915            request = true;
4916
4917            b[c] = b[c].replace(rcs, ' ');
4918            // The customizer requires postMessage and CORS (if the site is cross domain)
4919            b[c] += (window.postMessage && request ? ' ' : ' no-') + cs;
4920
4921            //Plus, we need to change the url of the Customize button to the current url
4922            var $customizeButton = $('#wp-admin-bar-customize a'),
4923                baseCustomizeURL = juliaStrings.ajaxurl.replace('admin-ajax.php', 'customize.php');
4924            if (!empty($customizeButton)) {
4925                $customizeButton.attr('href', baseCustomizeURL + '?url=' + encodeURIComponent(window.location.href));
4926            }
4927
4928        }
4929
4930    };
4931
4932    var HandleSubmenusOnTouch = (function() {
4933
4934        var $theUsualSuspects,
4935            $theUsualAnchors,
4936            initialInit = false;
4937
4938        function init() {
4939            if (initialInit || !isTouchDevice) return;
4940
4941            $theUsualSuspects = $('li[class*=children]').removeClass('hover');
4942            $theUsualAnchors = $theUsualSuspects.find('> a');
4943
4944            unbind();
4945
4946            $theUsualAnchors.on('click', function(e) {
4947                e.preventDefault();
4948                e.stopPropagation();
4949
4950                if ($(this).hasClass('active')) {
4951                    window.location.href = $(this).attr('href');
4952                }
4953
4954                $theUsualAnchors.removeClass('active');
4955                $(this).addClass('active');
4956
4957                // When a parent menu item is activated,
4958                // close other menu items on the same level
4959                $(this).parent().siblings().removeClass('hover');
4960
4961                // Open the sub menu of this parent item
4962                $(this).parent().addClass('hover');
4963            });
4964
4965            bindOuterNavClick();
4966
4967            initialInit = true;
4968        }
4969
4970        function unbind() {
4971            $theUsualAnchors.unbind();
4972            isHorizontalInitiated = false;
4973        }
4974
4975        // When a sub menu is open, close it by a touch on
4976        // any other part of the viewport than navigation.
4977        // use case: normal, horizontal menu, touch events,
4978        // sub menus are not visible.
4979        function bindOuterNavClick() {
4980            $body.on('touchstart', function(e) {
4981                var container = $('.main-navigation');
4982
4983                if (!container.is(e.target) // if the target of the click isn't the container...
4984                    &&
4985                    container.has(e.target).length === 0) // ... nor a descendant of the container
4986                {
4987                    $theUsualSuspects.removeClass('hover').removeClass('active');
4988                }
4989            });
4990        }
4991
4992        return {
4993            init: init
4994        }
4995    }());
4996
4997    function checkForSmallImageOnSingle() {
4998        if (!$body.hasClass('singular') || $body.hasClass('no-featured-image')) {
4999            return;
5000        }
5001
5002        if (windowWidth > 900) {
5003            if ($('.entry-featured img').width() < 500) {
5004                $body.addClass('has--small-featured-image');
5005                $('.post__content').css('paddingTop', $('.entry-featured').height() + 30);
5006            }
5007        } else {
5008            $('.post__content').removeAttr('style');
5009        }
5010    }
5011
5012    var Gema = new pixelgradeTheme(),
5013        log = Gema.log,
5014        resizeEvent = 'ontouchstart' in window && 'onorientationchange' in window ? 'pxg:orientationchange' : 'pxg:resize',
5015        $html = $('html'),
5016        $body = $('body');
5017
5018    window.bricklayer = null;
5019
5020    Gema.init = function() {
5021        $body.toggleClass('is--webkit', isWekbit);
5022        $body.toggleClass('is--ie', isIE);
5023        $body.toggleClass('is--ie-le10', isiele10);
5024
5025        Gema.Grid = new Grid();
5026        Gema.Logo = new Logo();
5027
5028        checkForSmallImageOnSingle();
5029
5030        HandleSubmenusOnTouch.init();
5031
5032        $('ul.nav-menu').ariaNavigation();
5033
5034        $('.grid, .site-header').css('opacity', 1);
5035
5036        if ($body.is('.singular')) {
5037            prepareSingle();
5038        } else {
5039            prepareArchive();
5040        }
5041
5042        Gema.adjustLayout();
5043    };
5044
5045    Gema.onPostLoad = function(event, data) {
5046        var $elements = $(data.html).filter('.grid__item').addClass('ajax-loaded').each(function(i, obj) {
5047            if ($.fn.mediaelementplayer) {
5048                $(obj).find('audio, video').mediaelementplayer();
5049            }
5050        });
5051
5052        $('.infinite-loader').remove();
5053
5054        if ($('.grid').length && bricklayer !== null) {
5055            bricklayer.append($.makeArray($elements));
5056        }
5057
5058        // Clean up the duplicate posts that are appended
5059        // by default by Jetpack's Infinite Scroll to div#main
5060        // (and also the corresponding HTML comments)
5061        $('#main').contents().each(function() {
5062            if ($(this).is('article') || this.nodeType === Node.COMMENT_NODE) {
5063                $(this).remove();
5064            }
5065        });
5066
5067        Gema.adjustLayout();
5068
5069        Gema.Grid.showCards($elements);
5070    };
5071
5072    Gema.bindEvents = function() {
5073
5074        var $nav = $('ul.nav-menu'),
5075            $document = $(document),
5076            $window = $(window);
5077
5078        $window.on(resizeEvent, Gema.adjustLayout);
5079        $window.on('load', Gema.adjustLayout);
5080        $body.on('post-load', Gema.onPostLoad);
5081
5082        Gema.ev.on('render', Gema.update);
5083
5084        $('.overlay-toggle').on('touchstart click', toggleOverlay);
5085        $('.menu-toggle').on('touchstart click', toggleNav);
5086        $('.sidebar-toggle').on('touchstart click', toggleSidebar);
5087
5088        $document.keydown(function(e) {
5089            // ESC key
5090            if (e.keyCode === 27) {
5091                hidePanels();
5092            }
5093        });
5094
5095        // close all menus on click outside
5096        $('.overlay-shadow').on('touchstart', function(e) {
5097            e.preventDefault();
5098            e.stopPropagation();
5099
5100            hidePanels();
5101        });
5102    }
5103
5104    function hidePanels() {
5105
5106        if ($body.hasClass('nav-is-open')) {
5107            toggleNav();
5108        }
5109
5110        if ($body.hasClass('overlay-is-open')) {
5111            toggleOverlay();
5112        }
5113
5114        if ($body.hasClass('sidebar-is-open')) {
5115            toggleSidebar();
5116        }
5117    }
5118
5119    function toggleOverlay(e) {
5120
5121        if (typeof e !== "undefined") {
5122            e.preventDefault();
5123            e.stopPropagation();
5124        }
5125
5126        if (!$body.hasClass('overlay-is-open')) {
5127            $body.addClass('overlay-is-open');
5128            $body.css({
5129                overflow: 'hidden',
5130                width: $body.width(),
5131            });
5132        } else {
5133            $body.removeClass('overlay-is-open');
5134            $body.css({
5135                overflow: '',
5136                width: '',
5137            });
5138        }
5139
5140    }
5141
5142    function toggleNav(e) {
5143
5144        if (typeof e !== "undefined") {
5145            e.preventDefault();
5146            e.stopPropagation();
5147        }
5148
5149        if ($body.hasClass('nav-is-open')) {
5150            // closing the menu
5151            $('.menu-toggle').attr('aria-expanded', 'false');
5152        } else {
5153            // opening the menu
5154            $('.menu-toggle').attr('aria-expanded', 'true');
5155        }
5156
5157        $body.toggleClass('nav-is-open');
5158    }
5159
5160    function toggleSidebar(e) {
5161
5162        if (typeof e !== "undefined") {
5163            e.preventDefault();
5164            e.stopPropagation();
5165        }
5166
5167        if ($body.hasClass('sidebar-is-open')) {
5168            //closing the sidebar
5169            $('.sidebar-toggle').attr('aria-expanded', 'false');
5170        } else {
5171            // opening the sidebar
5172            $('.sidebar-toggle').attr('aria-expanded', 'true');
5173        }
5174
5175        $body.toggleClass('sidebar-is-open');
5176    }
5177
5178    function prepareArchive() {
5179
5180        var $cards = $('.card');
5181
5182        if ($('.grid').length && bricklayer === null) {
5183            bricklayer = new Bricklayer(document.querySelector('.grid'));
5184            bricklayer.redraw();
5185        }
5186
5187        Gema.Grid.showCards($cards);
5188
5189        $body.css('opacity', 1);
5190    }
5191
5192    function prepareSingle() {
5193
5194        var $mobileHeader = $('.mobile-header-wrapper'),
5195            scrollTo;
5196
5197        if ($mobileHeader.is(':visible')) {
5198            scrollTo = $('.content-area').offset().top - $mobileHeader.outerHeight();
5199            setTimeout(function() {
5200                window.scrollTo(0, scrollTo);
5201                $body.css('opacity', 1);
5202            });
5203        } else {
5204            $body.css('opacity', 1);
5205        }
5206    }
5207
5208    Gema.hidePanels = function() {
5209        $body.removeClass('nav-is-open')
5210            .removeClass('sidebar-is-open')
5211            .removeClass('overlay-is-open')
5212            .css('width', '')
5213            .css('overflow', '');
5214    };
5215
5216    Gema.update = function() {
5217        if (typeof Gema.Logo !== "undefined") {
5218            Gema.Logo.update(Gema.getScroll());
5219        }
5220    };
5221
5222    Gema.alignWideBlocks = function() {
5223        var $header = $('#masthead');
5224        var headerOffset = $header.offset();
5225        var headerBottom = $header.length ? headerOffset.top + $header.outerHeight() : 0;
5226        var headerLeft = $header.length ? headerOffset.left : 0;
5227
5228        var $sidebar = $('#secondary');
5229        var sidebarOffset = $sidebar.offset();
5230        var sidebarPosition = $sidebar.css('position');
5231        var sidebarBottom = ($sidebar.length && 'fixed' !== sidebarPosition) ? sidebarOffset.top + $
5231sidebar.outerHeight() : 0;
5232
5233        var $main = $('#main');
5234        var mainOffset = $main.offset();
5235        var mainLeft = mainOffset.left;
5236        var mainRight = $main.length ? mainOffset.left + $main.outerWidth() : 0;
5237
5238        var bodyWidth = $body.outerWidth();
5239
5240        var $blocks = $('.entry-content').children('.alignfull, .alignwide');
5241
5242        $blocks.removeClass('fill-left fill-right');
5243        $blocks.css({
5244            marginLeft: '',
5245            marginRight: '',
5246        });
5247
5248        $blocks.each(function(i, obj) {
5249            var $block = $(obj);
5250            var blockOffset = $block.offset();
5251            var blockTop = blockOffset.top;
5252            var blockLeft = blockOffset.left;
5253            var blockRight = blockLeft + $block.outerWidth();
5254            var fillLeft = blockTop > headerBottom;
5255            var fillRight = blockTop > sidebarBottom;
5256            var wideToLeft = fillLeft ? headerLeft : mainLeft;
5257            var fullToLeft = fillLeft ? 0 : mainLeft;
5258
5259            $block.toggleClass('fill-left', fillLeft || fillRight);
5260            $block.toggleClass('fill-right', fillRight);
5261
5262            if ($block.is('.alignwide')) {
5263
5264                if (fillLeft || fillRight) {
5265                    $block.css('marginLeft', wideToLeft - blockLeft);
5266                }
5267
5268                if (fillRight) {
5269                    $block.css('marginRight', blockRight - mainRight);
5270                }
5271            }
5272
5273            if ($block.is('.alignfull')) {
5274
5275                if (fillLeft || fillRight) {
5276                    $block.css('marginLeft', fullToLeft - blockLeft);
5277                }
5278
5279                if (fillRight) {
5280                    $block.css('marginRight', blockRight - bodyWidth);
5281                }
5282            }
5283
5284        });
5285    };
5286
5287    Gema.adjustLayout = function() {
5288
5289        if (Gema.getWindowWidth() > 900) {
5290            Gema.hidePanels();
5291        }
5292
5293        // Single
5294        checkForSmallImageOnSingle();
5295        Gema.placeSidebar();
5296
5297        if ($body.is('.singular')) {
5298            Gema.alignWideBlocks();
5299        }
5300
5301        // Archive
5302        Gema.Logo.adjustSiteTitle();
5303        Gema.Logo.adjustArchiveTitle();
5304        Gema.Logo.prepare();
5305
5306        Gema.Grid.offsetFirstColumn();
5307        Gema.Grid.adjustCardMeta();
5308        Gema.Grid.alignTitles();
5309        Gema.Grid.addMargins();
5310    };
5311
5312    Gema.placeSidebar = function() {
5313
5314        if (!$body.hasClass('has-active-sidebar')) {
5315            return;
5316        }
5317
5318        var $sidebar = $('.widget-area'),
5319            $content = $('.content-area');
5320
5321        if (Gema.getWindowWidth() > 900) {
5322
5323            if (!$sidebar.length) {
5324                return;
5325            }
5326
5327            if ($body.hasClass('no-featured-image')) {
5328                $sidebar.addClass('is--placed').css('top', $('.site-main').css('padding-top'));
5329            } else {
5330                // If we are past the breakpoint
5331                var $featuredImage = $('.entry-featured'),
5332                    featuredImageBottom = $featuredImage.height() + parseInt($('.post__content').css('margin-top'), 10);
5333
5334                // position: absolute; on the sidebar(via ".is--placed")
5335                // below the featured image;
5336                if (!$body.hasClass('has--small-featured-image')) {
5337                    $sidebar.addClass('is--placed').css('top', featuredImageBottom);
5338                } else {
5339                    $sidebar.addClass('is--placed').css('top', 108);
5340                }
5341            }
5342
5343            // and set a height on the content so that everything seems in place.
5344            $content.css("minHeight", $sidebar.offset().top + $sidebar.height());
5345        } else {
5346            // Remove the height (possibly) set above.
5347            $content.removeAttr('style');
5348            $sidebar.css('top', '');
5349        }
5350    };
5351
5352    $.Gema = Gema;
5353    $.Gema.init();
5354    Gema.bindEvents();
5355
5356})(jQuery);;

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.