PageSourceSearch

https://melaniewindridge.co.uk/wp-content/themes/brooklyn/js/modernizr.js?ver=2.6.2

js melaniewindridge.co.uk collected 2026-10-05 04:39:09 UTC 102,408 bytes, 3,204 lines download raw bytes

vendor: 10,922 bytes, lines 1-290
1/*!
2 * modernizr v3.2.0
3 * Build http://modernizr.com/download?-applicationcache-audio-backgroundsize-bgsizecover-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-preserve3d-requestanimationframe-rgba-sessionstorage-smil-svg-svgclippaths-svgfilters-textshadow-touchevents-video-webgl-webglextensions-websockets-websqldatabase-webworkers-addtest-domprefixes-hasevent-mq-prefixed-prefixes-shiv-testallprops-testprop-teststyles-dontmin
4 *
5 * Copyright (c)
6 *  Faruk Ates
7 *  Paul Irish
8 *  Alex Sexton
9 *  Ryan Seddon
10 *  Patrick Kettner
11 *  Stu Cox
12 *  Richard Herrera
13
14 * MIT License
15 */
16
17/*
18 * Modernizr tests which native CSS3 and HTML5 features are available in the
19 * current UA and makes the results available to you in two ways: as properties on
20 * a global `Modernizr` object, and as classes on the `<html>` element. This
21 * information allows you to progressively enhance your pages with a granular level
22 * of control over the experience.
23*/
24
25;(function(window, document, undefined){
26  var classes = [];
27  
28
29  /**
30   * docElement is a convenience wrapper to grab the root element of the document
31   *
32   * @access private
33   * @returns {HTMLElement|SVGElement} The root element of the document
34   */
35
36  var docElement = document.documentElement;
37  
38
39  /**
40   * A convenience helper to check if the document we are running in is an SVG document
41   *
42   * @access private
43   * @returns {boolean}
44   */
45
46  var isSVG = docElement.nodeName.toLowerCase() === 'svg';
47  
48
49/**
50  * @optionName html5shiv
51  * @optionProp html5shiv
52  */
53
54  // Take the html5 variable out of the html5shiv scope so we can return it.
55  var html5;
56  if (!isSVG) {
57    /**
58     * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
59     */
60    ;(function(window, document) {
61      /*jshint evil:true */
62      /** version */
63      var version = '3.7.3';
64
65      /** Preset options */
66      var options = window.html5 || {};
67
68      /** Used to skip problem elements */
69      var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
70
71      /** Not all elements can be cloned in IE **/
72      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;
73
74      /** Detect whether the browser supports default html5 styles */
75      var supportsHtml5Styles;
76
77      /** Name of the expando, to work with multiple documents or to re-shiv one document */
78      var expando = '_html5shiv';
79
80      /** The id for the the documents expando */
81      var expanID = 0;
82
83      /** Cached data for each document */
84      var expandoData = {};
85
86      /** Detect whether the browser supports unknown elements */
87      var supportsUnknownElements;
88
89      (function() {
90        try {
91          var a = document.createElement('a');
92          a.innerHTML = '<xyz></xyz>';
93          //if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles
94          supportsHtml5Styles = ('hidden' in a);
95
96          supportsUnknownElements = a.childNodes.length == 1 || (function() {
97            // assign a false positive if unable to shiv
98            (document.createElement)('a');
99            var frag = document.createDocumentFragment();
100            return (
101              typeof frag.cloneNode == 'undefined' ||
102                typeof frag.createDocumentFragment == 'undefined' ||
103                typeof frag.createElement == 'undefined'
104            );
105          }());
106        } catch(e) {
107          // assign a false positive if detection fails => unable to shiv
108          supportsHtml5Styles = true;
109          supportsUnknownElements = true;
110        }
111
112      }());
113
114      /*--------------------------------------------------------------------------*/
115
116      /**
117       * Creates a style sheet with the given CSS text and adds it to the document.
118       * @private
119       * @param {Document} ownerDocument The document.
120       * @param {String} cssText The CSS text.
121       * @returns {StyleSheet} The style element.
122       */
123      function addStyleSheet(ownerDocument, cssText) {
124        var p = ownerDocument.createElement('p'),
125          parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
126
127        p.innerHTML = 'x<style>' + cssText + '</style>';
128        return parent.insertBefore(p.lastChild, parent.firstChild);
129      }
130
131      /**
132       * Returns the value of `html5.elements` as an array.
133       * @private
134       * @returns {Array} An array of shived element node names.
135       */
136      function getElements() {
137        var elements = html5.elements;
138        return typeof elements == 'string' ? elements.split(' ') : elements;
139      }
140
141      /**
142       * Extends the built-in list of html5 elements
143       * @memberOf html5
144       * @param {String|Array} newElements whitespace separated list or array of new element names to shiv
145       * @param {Document} ownerDocument The context document.
146       */
147      function addElements(newElements, ownerDocument) {
148        var elements = html5.elements;
149        if(typeof elements != 'string'){
150          elements = elements.join(' ');
151        }
152        if(typeof newElements != 'string'){
153          newElements = newElements.join(' ');
154        }
155        html5.elements = elements +' '+ newElements;
156        shivDocument(ownerDocument);
157      }
158
159      /**
160       * Returns the data associated to the given document
161       * @private
162       * @param {Document} ownerDocument The document.
163       * @returns {Object} An object of data.
164       */
165      function getExpandoData(ownerDocument) {
166        var data = expandoData[ownerDocument[expando]];
167        if (!data) {
168          data = {};
169          expanID++;
170          ownerDocument[expando] = expanID;
171          expandoData[expanID] = data;
172        }
173        return data;
174      }
175
176      /**
177       * returns a shived element for the given nodeName and document
178       * @memberOf html5
179       * @param {String} nodeName name of the element
180       * @param {Document|DocumentFragment} ownerDocument The context document.
181       * @returns {Object} The shived element.
182       */
183      function createElement(nodeName, ownerDocument, data){
184        if (!ownerDocument) {
185          ownerDocument = document;
186        }
187        if(supportsUnknownElements){
188          return ownerDocument.createElement(nodeName);
189        }
190        if (!data) {
191          data = getExpandoData(ownerDocument);
192        }
193        var node;
194
195        if (data.cache[nodeName]) {
196          node = data.cache[nodeName].cloneNode();
197        } else if (saveClones.test(nodeName)) {
198          node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
199        } else {
200          node = data.createElem(nodeName);
201        }
202
203        // Avoid adding some elements to fragments in IE < 9 because
204        // * Attributes like `name` or `type` cannot be set/changed once an element
205        //   is inserted into a document/fragment
206        // * Link elements with `src` attributes that are inaccessible, as with
207        //   a 403 response, will cause the tab/window to crash
208        // * Script elements appended to fragments will execute when their `src`
209        //   or `text` property is set
210        return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node;
211      }
212
213      /**
214       * returns a shived DocumentFragment for the given document
215       * @memberOf html5
216       * @param {Document} ownerDocument The context document.
217       * @returns {Object} The shived DocumentFragment.
218       */
219      function createDocumentFragment(ownerDocument, data){
220        if (!ownerDocument) {
221          ownerDocument = document;
222        }
223        if(supportsUnknownElements){
224          return ownerDocument.createDocumentFragment();
225        }
226        data = data || getExpandoData(ownerDocument);
227        var clone = data.frag.cloneNode(),
228          i = 0,
229          elems = getElements(),
230          l = elems.length;
231        for(;i<l;i++){
232          clone.createElement(elems[i]);
233        }
234        return clone;
235      }
236
237      /**
238       * Shivs the `createElement` and `createDocumentFragment` methods of the document.
239       * @private
240       * @param {Document|DocumentFragment} ownerDocument The document.
241       * @param {Object} data of the document.
242       */
243      function shivMethods(ownerDocument, data) {
244        if (!data.cache) {
245          data.cache = {};
246          data.createElem = ownerDocument.createElement;
247          data.createFrag = ownerDocument.createDocumentFragment;
248          data.frag = data.createFrag();
249        }
250
251
252        ownerDocument.createElement = function(nodeName) {
253          //abort shiv
254          if (!html5.shivMethods) {
255            return data.createElem(nodeName);
256          }
257          return createElement(nodeName, ownerDocument, data);
258        };
259
260        ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
261                                                        'var n=f.cloneNode(),c=n.createElement;' +
262                                                        'h.shivMethods&&(' +
263                                                        // unroll the `createElement` calls
264                                                        getElements().join().replace(/[\w\-:]+/g, function(nodeName) {
265          data.createElem(nodeName);
266          data.frag.createElement(nodeName);
267          return 'c("' + nodeName + '")';
268        }) +
269          ');return n}'
270                                                       )(html5, data.frag);
271      }
272
273      /*--------------------------------------------------------------------------*/
274
275      /**
276       * Shivs the given document.
277       * @memberOf html5
278       * @param {Document} ownerDocument The document to shiv.
279       * @returns {Document} The shived document.
280       */
281      function shivDocument(ownerDocument) {
282        if (!ownerDocument) {
283          ownerDocument = document;
284        }
285        var data = getExpandoData(ownerDocument);
286
287        if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) {
288          data.hasCSS = !!addStyleSheet(ownerDocument,
289                                        // corrects block display not defined in IE6/7/8/9
290                                        'article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{dis
290play:block}' +
291                                        // adds styling not present in IE6/7/8/9
292                                        'mark{background:#FF0;color:#000}' +
293                                        // hides non-rendered elements
294                                        'template{display:none}'
295                                       );
296        }
297        if (!supportsUnknownElements) {
298          shivMethods(ownerDocument, data);
299        }
300        return ownerDocument;
301      }
302
303      /*--------------------------------------------------------------------------*/
304
305      /**
306       * The `html5` object is exposed so that more elements can be shived and
307       * existing shiving can be detected on iframes.
308       * @type Object
309       * @example
310       *
311       * // options can be changed before the script is included
312       * html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false };
313       */
314      var html5 = {
315
316        /**
317         * An array or space separated string of node names of the elements to shiv.
318         * @memberOf html5
319         * @type Array|String
320         */
321        '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',
322
323        /**
324         * current version of html5shiv
325         */
326        'version': version,
327
328        /**
329         * A flag to indicate that the HTML5 style sheet should be inserted.
330         * @memberOf html5
331         * @type Boolean
332         */
333        'shivCSS': (options.shivCSS !== false),
334
335        /**
336         * Is equal to true if a browser supports creating unknown/HTML5 elements
337         * @memberOf html5
338         * @type boolean
339         */
340        'supportsUnknownElements': supportsUnknownElements,
341
342        /**
343         * A flag to indicate that the document's `createElement` and `createDocumentFragment`
344         * methods should be overwritten.
345         * @memberOf html5
346         * @type Boolean
347         */
348        'shivMethods': (options.shivMethods !== false),
349
350        /**
351         * A string to describe the type of `html5` object ("default" or "default print").
352         * @memberOf html5
353         * @type String
354         */
355        'type': 'default',
356
357        // shivs the document according to the specified `html5` object options
358        'shivDocument': shivDocument,
359
360        //creates a shived element
361        createElement: createElement,
362
363        //creates a shived documentFragment
364        createDocumentFragment: createDocumentFragment,
365
366        //extends list of elements
367        addElements: addElements
368      };
369
370      /*--------------------------------------------------------------------------*/
371
372      // expose html5
373      window.html5 = html5;
374
375      // shiv the document
376      shivDocument(document);
377
378      if(typeof module == 'object' && module.exports){
379        module.exports = html5;
380      }
381
382    }(typeof window !== "undefined" ? window : this, document));
383  }
384;
385
386  var tests = [];
387  
388
389  /**
390   *
391   * ModernizrProto is the constructor for Modernizr
392   *
393   * @class
394   * @access public
395   */
396
397  var ModernizrProto = {
398    // The current version, dummy
399    _version: '3.2.0',
400
401    // Any settings that don't work as separate modules
402    // can go in here as configuration.
403    _config: {
404      'classPrefix' : '',
405      'enableClasses' : true,
406      'enableJSClass' : true,
407      'usePrefixes' : true
408    },
409
410    // Queue of tests
411    _q: [],
412
413    // Stub these for people who are listening
414    on: function(test, cb) {
415      // I don't really think people should do this, but we can
416      // safe guard it a bit.
417      // -- NOTE:: this gets WAY overridden in src/addTest for actual async tests.
418      // This is in case people listen to synchronous tests. I would leave it out,
419      // but the code to *disallow* sync tests in the real version of this
420      // function is actually larger than this.
421      var self = this;
422      setTimeout(function() {
423        cb(self[test]);
424      }, 0);
425    },
426
427    addTest: function(name, fn, options) {
428      tests.push({name : name, fn : fn, options : options});
429    },
430
431    addAsyncTest: function(fn) {
432      tests.push({name : null, fn : fn});
433    }
434  };
435
436  
437
438  // Fake some of Object.create so we can force non test results to be non "own" properties.
439  var Modernizr = function() {};
440  Modernizr.prototype = ModernizrProto;
441
442  // Leak modernizr globally when you `require` it rather than force it here.
443  // Overwrite name so constructor name is nicer :D
444  Modernizr = new Modernizr();
445
446  
447
448  /**
449   * setClasses takes an array of class names and adds them to the root element
450   *
451   * @access private
452   * @function setClasses
453   * @param {string[]} classes - Array of class names
454   */
455
456  // Pass in an and array of class names, e.g.:
457  //  ['no-webp', 'borderradius', ...]
458  function setClasses(classes) {
459    var className = docElement.className;
460    var classPrefix = Modernizr._config.classPrefix || '';
461
462    if (isSVG) {
463      className = className.baseVal;
464    }
465
466    // Change `no-js` to `js` (independently of the `enableClasses` option)
467    // Handle classPrefix on this too
468    if (Modernizr._config.enableJSClass) {
469      var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)');
470      className = className.replace(reJS, '$1' + classPrefix + 'js$2');
471    }
472
473    if (Modernizr._config.enableClasses) {
474      // Add the new classes
475      className += ' ' + classPrefix + classes.join(' ' + classPrefix);
476      isSVG ? docElement.className.baseVal = className : docElement.className = className;
477    }
478
479  }
480
481  ;
482/*!
483{
484  "name": "Application Cache",
485  "property": "applicationcache",
486  "caniuse": "offline-apps",
487  "tags": ["storage", "offline"],
488  "notes": [{
489    "name": "MDN documentation",
490    "href": "https://developer.mozilla.org/en/docs/HTML/Using_the_application_cache"
491  }],
492  "polyfills": ["html5gears"]
493}
494!*/
495/* DOC
496Detects support for the Application Cache, for storing data to enable web-based applications run offline.
497
498The API has been [heavily criticized](http://alistapart.com/article/application-cache-is-a-douchebag) and discussions are underway to address this.
499*/
500
501  Modernizr.addTest('applicationcache', 'applicationCache' in window);
502
503/*!
504{
505  "name": "Geolocation API",
506  "property": "geolocation",
507  "caniuse": "geolocation",
508  "tags": ["media"],
509  "notes": [{
510    "name": "MDN documentation",
511    "href": "https://developer.mozilla.org/en-US/docs/WebAPI/Using_geolocation"
512  }],
513  "polyfills": [
514    "joshuabell-polyfill",
515    "webshims",
516    "geo-location-javascript",
517    "geolocation-api-polyfill"
518  ]
519}
520!*/
521/* DOC
522Detects support for the Geolocation API for users to provide their location to web applications.
523*/
524
525  // geolocation is often considered a trivial feature detect...
526  // Turns out, it's quite tricky to get right:
527  //
528  // Using !!navigator.geolocation does two things we don't want. It:
529  //   1. Leaks memory in IE9: github.com/Modernizr/Modernizr/issues/513
530  //   2. Disables page caching in WebKit: webk.it/43956
531  //
532  // Meanwhile, in Firefox < 8, an about:config setting could expose
533  // a false positive that would throw an exception: bugzil.la/688158
534
535  Modernizr.addTest('geolocation', 'geolocation' in navigator);
536
537/*!
538{
539  "name": "History API",
540  "property": "history",
541  "caniuse": "history",
542  "tags": ["history"],
543  "authors": ["Hay Kranen", "Alexander Farkas"],
544  "notes": [{
545    "name": "W3C Spec",
546    "href": "http://www.w3.org/TR/html51/browsers.html#the-history-interface"
547  }, {
548    "name": "MDN documentation",
549    "href": "https://developer.mozilla.org/en-US/docs/Web/API/window.history"
550  }],
551  "polyfills": ["historyjs", "html5historyapi"]
552}
553!*/
554/* DOC
555Detects support for the History API for manipulating the browser session history.
556*/
557
558  Modernizr.addTest('history', function() {
559    // Issue #733
560    // The stock browser on Android 2.2 & 2.3, and 4.0.x returns positive on history support
561    // Unfortunately support is really buggy and there is no clean way to detect
562    // these bugs, so we fall back to a user agent sniff :(
563    var ua = navigator.userAgent;
564
565    // We only want Android 2 and 4.0, stock browser, and not Chrome which identifies
566    // itself as 'Mobile Safari' as well, nor Windows Phone (issue #1471).
567    if ((ua.indexOf('Android 2.') !== -1 ||
568        (ua.indexOf('Android 4.0') !== -1)) &&
569        ua.indexOf('Mobile Safari') !== -1 &&
570        ua.indexOf('Chrome') === -1 &&
571        ua.indexOf('Windows Phone') === -1) {
572      return false;
573    }
574
575    // Return the regular check
576    return (window.history && 'pushState' in window.history);
577  });
578
579/*!
580{
581  "name": "postMessage",
582  "property": "postmessage",
583  "caniuse": "x-doc-messaging",
584  "notes": [{
585    "name": "W3C Spec",
586    "href": "http://www.w3.org/TR/html5/comms.html#posting-messages"
587  }],
588  "polyfills": ["easyxdm", "postmessage-jquery"]
589}
590!*/
591/* DOC
592Detects support for the `window.postMessage` protocol for cross-document messaging.
593*/
594
595  Modernizr.addTest('postmessage', 'postMessage' in window);
596
597/*!
598{
599  "name": "SVG",
600  "property": "svg",
601  "caniuse": "svg",
602  "tags": ["svg"],
603  "authors": ["Erik Dahlstrom"],
604  "polyfills": [
605    "svgweb",
606    "raphael",
607    "amplesdk",
608    "canvg",
609    "svg-boilerplate",
610    "sie",
611    "dojogfx",
612    "fabricjs"
613  ]
614}
615!*/
616/* DOC
617Detects support for SVG in `<embed>` or `<object>` elements.
618*/
619
620  Modernizr.addTest('svg', !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect);
621
622/*!
623{
624  "name": "WebSockets Support",
625  "property": "websockets",
626  "authors": ["Phread [fearphage]", "Mike Sherov [mikesherov]", "Burak Yigit Kaya [BYK]"],
627  "caniuse": "websockets",
628  "tags": ["html5"],
629  "warnings": [
630    "This test will reject any old version of WebSockets even if it is not prefixed such as in Safari 5.1"
631  ],
632  "notes": [{
633    "name": "CLOSING State and Spec",
634    "href": "http://www.w3.org/TR/websockets/#the-websocket-interface"
635  }],
636  "polyfills": [
637    "sockjs",
638    "socketio",
639    "kaazing-websocket-gateway",
640    "websocketjs",
641    "atmosphere",
642    "graceful-websocket",
643    "portal",
644    "datachannel"
645  ]
646}
647!*/
648
649  Modernizr.addTest('websockets', 'WebSocket' in window && window.WebSocket.CLOSING === 2);
650
651/*!
652{
653  "name": "Local Storage",
654  "property": "localstorage",
655  "caniuse": "namevalue-storage",
656  "tags": ["storage"],
657  "knownBugs": [],
658  "notes": [],
659  "warnings": [],
660  "polyfills": [
661    "joshuabell-polyfill",
662    "cupcake",
663    "storagepolyfill",
664    "amplifyjs",
665    "yui-cacheoffline"
666  ]
667}
668!*/
669
670  // In FF4, if disabled, window.localStorage should === null.
671
672  // Normally, we could not test that directly and need to do a
673  //   `('localStorage' in window) && ` test first because otherwise Firefox will
674  //   throw bugzil.la/365772 if cookies are disabled
675
676  // Also in iOS5 Private Browsing mode, attempting to use localStorage.setItem
677  // will throw the exception:
678  //   QUOTA_EXCEEDED_ERROR DOM Exception 22.
679  // Peculiarly, getItem and removeItem calls do not throw.
680
681  // Because we are forced to try/catch this, we'll go aggressive.
682
683  // Just FWIW: IE8 Compat mode supports these features completely:
684  //   www.quirksmode.org/dom/html5.html
685  // But IE8 doesn't support either with local files
686
687  Modernizr.addTest('localstorage', function() {
688    var mod = 'modernizr';
689    try {
690      localStorage.setItem(mod, mod);
691      localStorage.removeItem(mod);
692      return true;
693    } catch (e) {
694      return false;
695    }
696  });
697
698/*!
699{
700  "name": "Session Storage",
701  "property": "sessionstorage",
702  "tags": ["storage"],
703  "polyfills": ["joshuabell-polyfill", "cupcake", "sessionstorage"]
704}
705!*/
706
707  // Because we are forced to try/catch this, we'll go aggressive.
708
709  // Just FWIW: IE8 Compat mode supports these features completely:
710  //   www.quirksmode.org/dom/html5.html
711  // But IE8 doesn't support either with local files
712  Modernizr.addTest('sessionstorage', function() {
713    var mod = 'modernizr';
714    try {
715      sessionStorage.setItem(mod, mod);
716      sessionStorage.removeItem(mod);
717      return true;
718    } catch (e) {
719      return false;
720    }
721  });
722
723/*!
724{
725  "name": "Web SQL Database",
726  "property": "websqldatabase",
727  "caniuse": "sql-storage",
728  "tags": ["storage"]
729}
730!*/
731
732  // Chrome incognito mode used to throw an exception when using openDatabase
733  // It doesn't anymore.
734  Modernizr.addTest('websqldatabase', 'openDatabase' in window);
735
736/*!
737{
738  "name": "SVG filters",
739  "property": "svgfilters",
740  "caniuse": "svg-filters",
741  "tags": ["svg"],
742  "builderAliases": ["svg_filters"],
743  "authors": ["Erik Dahlstrom"],
744  "notes": [{
745    "name": "W3C Spec",
746    "href": "http://www.w3.org/TR/SVG11/filters.html"
747  }]
748}
749!*/
750
751  // Should fail in Safari: http://stackoverflow.com/questions/9739955/feature-detecting-support-for-svg-filters.
752  Modernizr.addTest('svgfilters', function() {
753    var result = false;
754    try {
755      result = 'SVGFEColorMatrixElement' in window &&
756        SVGFEColorMatrixElement.SVG_FECOLORMATRIX_TYPE_SATURATE == 2;
757    }
758    catch (e) {}
759    return result;
760  });
761
762/*!
763{
764  "name": "Web Workers",
765  "property": "webworkers",
766  "caniuse" : "webworkers",
767  "tags": ["performance", "workers"],
768  "notes": [{
769    "name": "W3C Reference",
770    "href": "http://www.w3.org/TR/workers/"
771  }, {
772    "name": "HTML5 Rocks article",
773    "href": "http://www.html5rocks.com/en/tutorials/workers/basics/"
774  }, {
775    "name": "MDN documentation",
776    "href": "https://developer.mozilla.org/en-US/docs/Web/Guide/Performance/Using_web_workers"
777  }],
778  "polyfills": ["fakeworker", "html5shims"]
779}
780!*/
781/* DOC
782Detects 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.
783*/
784
785  Modernizr.addTest('webworkers', 'Worker' in window);
786
787
788  /**
789   * List of property values to set for css tests. See ticket #21
790   * http://git.io/vUGl4
791   *
792   * @memberof Modernizr
793   * @name Modernizr._prefixes
794   * @optionName Modernizr._prefixes
795   * @optionProp prefixes
796   * @access public
797   * @example
798   *
799   * Modernizr._prefixes is the internal list of prefixes that we test against
800   * inside of things like [prefixed](#modernizr-prefixed) and [prefixedCSS](#-code-modernizr-prefixedcss). It is simply
801   * an array of kebab-case vendor prefixes you can use within your code.
802   *
803   * Some common use cases include
804   *
805   * Generating all possible prefixed version of a CSS property
806   * ```js
807   * var rule = Modernizr._prefixes.join('transform: rotate(20deg); ');
808   *
809   * rule === 'transform: rotate(20deg); webkit-transform: rotate(20deg); moz-transform: rotate(20deg); o-transform: rotate(20deg); ms-transform: rotate(20deg);'
810   * ```
811   *
812   * Generating all possible prefixed version of a CSS value
813   * ```js
814   * rule = 'display:' +  Modernizr._prefixes.join('flex; display:') + 'flex';
815   *
816   * rule === 'display:flex; display:-webkit-flex; display:-moz-flex; display:-o-flex; display:-ms-flex; display:flex'
817   * ```
818   */
819
820  var prefixes = (ModernizrProto._config.usePrefixes ? ' -webkit- -moz- -o- -ms- '.split(' ') : []);
821
822  // expose these for the plugin API. Look in the source for how to join() them against your input
823  ModernizrProto._prefixes = prefixes;
824
825  
826
827  /**
828   * is returns a boolean if the typeof an obj is exactly type.
829   *
830   * @access private
831   * @function is
832   * @param {*} obj - A thing we want to check the type of
833   * @param {string} type - A string to compare the typeof against
834   * @returns {boolean}
835   */
836
837  function is(obj, type) {
838    return typeof obj === type;
839  }
840  ;
841
842  /**
843   * Run through all tests and detect their support in the current UA.
844   *
845   * @access private
846   */
847
848  function testRunner() {
849    var featureNames;
850    var feature;
851    var aliasIdx;
852    var result;
853    var nameIdx;
854    var featureName;
855    var featureNameSplit;
856
857    for (var featureIdx in tests) {
858      if (tests.hasOwnProperty(featureIdx)) {
859        featureNames = [];
860        feature = tests[featureIdx];
861        // run the test, throw the return value into the Modernizr,
862        // then based on that boolean, define an appropriate className
863        // and push it into an array of classes we'll join later.
864        //
865        // If there is no name, it's an 'async' test that is run,
866        // but not directly added to the object. That should
867        // be done with a post-run addTest call.
868        if (feature.name) {
869          featureNames.push(feature.name.toLowerCase());
870
871          if (feature.options && feature.options.aliases && feature.options.aliases.length) {
872            // Add all the aliases into the names list
873            for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) {
874              featureNames.push(feature.options.aliases[aliasIdx].toLowerCase());
875            }
876          }
877        }
878
879        // Run the test, or use the raw value if it's not a function
880        result = is(feature.fn, 'function') ? feature.fn() : feature.fn;
881
882
883        // Set each of the names on the Modernizr object
884        for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) {
885          featureName = featureNames[nameIdx];
886          // Support dot properties as sub tests. We don't do checking to make sure
887          // that the implied parent tests have been added. You must call them in
888          // order (either in the test, or make the parent test a dependency).
889          //
890          // Cap it to TWO to make the logic simple and because who needs that kind of subtesting
891          // hashtag famous last words
892          featureNameSplit = featureName.split('.');
893
894          if (featureNameSplit.length === 1) {
895            Modernizr[featureNameSplit[0]] = result;
896          } else {
897            // cast to a Boolean, if not one already
898            /* jshint -W053 */
899            if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
900              Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
901            }
902
903            Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result;
904          }
905
906          classes.push((result ? '' : 'no-') + featureNameSplit.join('-'));
907        }
908      }
909    }
910  }
911  ;
912
913  /**
914   * If the browsers follow the spec, then they would expose vendor-specific style as:
915   *   elem.style.WebkitBorderRadius
916   * instead of something like the following, which would be technically incorrect:
917   *   elem.style.webkitBorderRadius
918
919   * Webkit ghosts their properties in lowercase but Opera & Moz do not.
920   * Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
921   *   erik.eae.net/archives/2008/03/10/21.48.10/
922
923   * More here: github.com/Modernizr/Modernizr/issues/issue/21
924   *
925   * @access private
926   * @returns {string} The string representing the vendor-specific style properties
927   */
928
929  var omPrefixes = 'Moz O ms Webkit';
930  
931
932  /**
933   * List of JavaScript DOM values used for tests
934   *
935   * @memberof Modernizr
936   * @name Modernizr._domPrefixes
937   * @optionName Modernizr._domPrefixes
938   * @optionProp domPrefixes
939   * @access public
940   * @example
941   *
942   * Modernizr._domPrefixes is exactly the same as [_prefixes](#modernizr-_prefixes), but rather
943   * than kebab-case properties, all properties are their Capitalized variant
944   *
945   * ```js
946   * Modernizr._domPrefixes === [ "Moz", "O", "ms", "Webkit" ];
947   * ```
948   */
949
950  var domPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.toLowerCase().split(' ') : []);
951  ModernizrProto._domPrefixes = domPrefixes;
952  
953
954  /**
955   * createElement is a convenience wrapper around document.createElement. Since we
956   * use createElement all over the place, this allows for (slightly) smaller code
957   * as well as abstracting away issues with creating elements in contexts other than
958   * HTML documents (e.g. SVG documents).
959   *
960   * @access private
961   * @function createElement
962   * @returns {HTMLElement|SVGElement} An HTML or SVG element
963   */
964
965  function createElement() {
966    if (typeof document.createElement !== 'function') {
967      // This is the case in IE7, where the type of createElement is "object".
968      // For this reason, we cannot call apply() as Object is not a Function.
969      return document.createElement(arguments[0]);
970    } else if (isSVG) {
971      return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]);
972    } else {
973      return document.createElement.apply(document, arguments);
974    }
975  }
976
977  ;
978
979  /**
980   * Modernizr.hasEvent() detects support for a given event
981   *
982   * @memberof Modernizr
983   * @name Modernizr.hasEvent
984   * @optionName Modernizr.hasEvent()
985   * @optionProp hasEvent
986   * @access public
987   * @function hasEvent
988   * @param  {string|*}       eventName  is the name of an event to test for (e.g. "resize")
989   * @param  {Element|string} [element=HTMLDivElement] is the element|document|window|tagName to test on
990   * @returns {boolean}
991   * @example
992   *  `Modernizr.hasEvent` lets you determine if the browser supports a supplied event.
993   *  By default, it does this detection on a div element
994   *
995   * ```js
996   *  hasEvent('blur') // true;
997   * ```
998   *
999   * However, you are able to give an object as a second argument to hasEvent to
1000   * detect an event on something other than a div.
1001   *
1002   * ```js
1003   *  hasEvent('devicelight', window) // true;
1004   * ```
1005   *
1006   */
1007
1008  var hasEvent = (function(undefined) {
1009
1010    // Detect whether event support can be detected via `in`. Test on a DOM element
1011    // using the "blur" event b/c it should always exist. bit.ly/event-detection
1012    var needsFallback = !('onblur' in document.documentElement);
1013
1014    function inner(eventName, element) {
1015
1016      var isSupported;
1017      if (!eventName) { return false; }
1018      if (!element || typeof element === 'string') {
1019        element = createElement(element || 'div');
1020      }
1021
1022      // Testing via the `in` operator is sufficient for modern browsers and IE.
1023      // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and
1024      // "resize", whereas `in` "catches" those.
1025      eventName = 'on' + eventName;
1026      isSupported = eventName in element;
1027
1028      // Fallback technique for old Firefox - bit.ly/event-detection
1029      if (!isSupported && needsFallback) {
1030        if (!element.setAttribute) {
1031          // Switch to generic element if it lacks `setAttribute`.
1032          // It could be the `document`, `window`, or something else.
1033          element = createElement('div');
1034        }
1035
1036        element.setAttribute(eventName, '');
1037        isSupported = typeof element[eventName] === 'function';
1038
1039        if (element[eventName] !== undefined) {
1040          // If property was created, "remove it" by setting value to `undefined`.
1041          element[eventName] = undefined;
1042        }
1043        element.removeAttribute(eventName);
1044      }
1045
1046      return isSupported;
1047    }
1048    return inner;
1049  })();
1050
1051
1052  ModernizrProto.hasEvent = hasEvent;
1053  
1054/*!
1055{
1056  "name": "Hashchange event",
1057  "property": "hashchange",
1058  "caniuse": "hashchange",
1059  "tags": ["history"],
1060  "notes": [{
1061    "name": "MDN documentation",
1062    "href": "https://developer.mozilla.org/en-US/docs/Web/API/window.onhashchange"
1063  }],
1064  "polyfills": [
1065    "jquery-hashchange",
1066    "moo-historymanager",
1067    "jquery-ajaxy",
1068    "hasher",
1069    "shistory"
1070  ]
1071}
1072!*/
1073/* DOC
1074Detects support for the `hashchange` event, fired when the current location fragment changes.
1075*/
1076
1077  Modernizr.addTest('hashchange', function() {
1078    if (hasEvent('hashchange', window) === false) {
1079      return false;
1080    }
1081
1082    // documentMode logic from YUI to filter out IE8 Compat Mode
1083    //   which false positives.
1084    return (document.documentMode === undefined || document.documentMode > 7);
1085  });
1086
1087/*!
1088{
1089  "name" : "HTML5 Audio Element",
1090  "property": "audio",
1091  "tags" : ["html5", "audio", "media"]
1092}
1093!*/
1094/* DOC
1095Detects the audio element
1096*/
1097
1098  // This tests evaluates support of the audio element, as well as
1099  // testing what types of content it supports.
1100  //
1101  // We're using the Boolean constructor here, so that we can extend the value
1102  // e.g.  Modernizr.audio     // true
1103  //       Modernizr.audio.ogg // 'probably'
1104  //
1105  // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
1106  //                     thx to NielsLeenheer and zcorpan
1107
1108  // Note: in some older browsers, "no" was a return value instead of empty string.
1109  //   It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2
1110  //   It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5
1111  Modernizr.addTest('audio', function() {
1112    /* jshint -W053 */
1113    var elem = createElement('audio');
1114    var bool = false;
1115
1116    try {
1117      if (bool = !!elem.canPlayType) {
1118        bool      = new Boolean(bool);
1119        bool.ogg  = elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, '');
1120        bool.mp3  = elem.canPlayType('audio/mpeg; codecs="mp3"')  .replace(/^no$/, '');
1121        bool.opus  = elem.canPlayType('audio/ogg; codecs="opus"') .replace(/^no$/, '');
1122
1123        // Mimetypes accepted:
1124        //   developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements
1125        //   bit.ly/iphoneoscodecs
1126        bool.wav  = elem.canPlayType('audio/wav; codecs="1"')     .replace(/^no$/, '');
1127        bool.m4a  = (elem.canPlayType('audio/x-m4a;')            ||
1128                     elem.canPlayType('audio/aac;'))             .replace(/^no$/, '');
1129      }
1130    } catch (e) { }
1131
1132    return bool;
1133  });
1134
1135/*!
1136{
1137  "name": "Canvas",
1138  "property": "canvas",
1139  "caniuse": "canvas",
1140  "tags": ["canvas", "graphics"],
1141  "polyfills": ["flashcanvas", "excanvas", "slcanvas", "fxcanvas"]
1142}
1143!*/
1144/* DOC
1145Detects support for the `<canvas>` element for 2D drawing.
1146*/
1147
1148  // On the S60 and BB Storm, getContext exists, but always returns undefined
1149  // so we actually have to call getContext() to verify
1150  // github.com/Modernizr/Modernizr/issues/issue/97/
1151  Modernizr.addTest('canvas', function() {
1152    var elem = createElement('canvas');
1153    return !!(elem.getContext && elem.getContext('2d'));
1154  });
1155
1156/*!
1157{
1158  "name": "Canvas text",
1159  "property": "canvastext",
1160  "caniuse": "canvas-text",
1161  "tags": ["canvas", "graphics"],
1162  "polyfills": ["canvastext"]
1163}
1164!*/
1165/* DOC
1166Detects support for the text APIs for `<canvas>` elements.
1167*/
1168
1169  Modernizr.addTest('canvastext',  function() {
1170    if (Modernizr.canvas  === false) {
1171      return false;
1172    }
1173    return typeof createElement('canvas').getContext('2d').fillText == 'function';
1174  });
1175
1176/*!
1177{
1178  "name": "HTML5 Video",
1179  "property": "video",
1180  "caniuse": "video",
1181  "tags": ["html5"],
1182  "knownBugs": [
1183    "Without QuickTime, `Modernizr.video.h264` will be `undefined`; http://github.com/Modernizr/Modernizr/issues/546"
1184  ],
1185  "polyfills": [
1186    "html5media",
1187    "mediaelementjs",
1188    "sublimevideo",
1189    "videojs",
1190    "leanbackplayer",
1191    "videoforeverybody"
1192  ]
1193}
1194!*/
1195/* DOC
1196Detects support for the video element, as well as testing what types of content it supports.
1197
1198Subproperties are provided to describe support for `ogg`, `h264` and `webm` formats, e.g.:
1199
1200```javascript
1201Modernizr.video         // true
1202Modernizr.video.ogg     // 'probably'
1203```
1204*/
1205
1206  // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
1207  //                     thx to NielsLeenheer and zcorpan
1208
1209  // Note: in some older browsers, "no" was a return value instead of empty string.
1210  //   It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2
1211  //   It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5
1212
1213  Modernizr.addTest('video', function() {
1214    /* jshint -W053 */
1215    var elem = createElement('video');
1216    var bool = false;
1217
1218    // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
1219    try {
1220      if (bool = !!elem.canPlayType) {
1221        bool = new Boolean(bool);
1222        bool.ogg = elem.canPlayType('video/ogg; codecs="theora"').replace(/^no$/, '');
1223
1224        // Without QuickTime, this value will be `undefined`. github.com/Modernizr/Modernizr/issues/546
1225        bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/, '');
1226
1227        bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/, '');
1228
1229        bool.vp9 = elem.canPlayType('video/webm; codecs="vp9"').replace(/^no$/, '');
1230
1231        bool.hls = elem.canPlayType('application/x-mpegURL; codecs="avc1.42E01E"').replace(/^no$/, '');
1232      }
1233    } catch (e) {}
1234
1235    return bool;
1236  });
1237
1238/*!
1239{
1240  "name": "WebGL",
1241  "property": "webgl",
1242  "caniuse": "webgl",
1243  "tags": ["webgl", "graphics"],
1244  "polyfills": ["jebgl", "cwebgl", "iewebgl"]
1245}
1246!*/
1247
1248  Modernizr.addTest('webgl', function() {
1249    var canvas = createElement('canvas');
1250    var supports = 'probablySupportsContext' in canvas ? 'probablySupportsContext' :  'supportsContext';
1251    if (supports in canvas) {
1252      return canvas[supports]('webgl') || canvas[supports]('experimental-webgl');
1253    }
1254    return 'WebGLRenderingContext' in window;
1255  });
1256
1257/*!
1258{
1259  "name": "CSS Gradients",
1260  "caniuse": "css-gradients",
1261  "property": "cssgradients",
1262  "tags": ["css"],
1263  "knownBugs": ["False-positives on webOS (https://github.com/Modernizr/Modernizr/issues/202)"],
1264  "notes": [{
1265    "name": "Webkit Gradient Syntax",
1266    "href": "http://webkit.org/blog/175/introducing-css-gradients/"
1267  },{
1268    "name": "Mozilla Linear Gradient Syntax",
1269    "href": "http://developer.mozilla.org/en/CSS/-moz-linear-gradient"
1270  },{
1271    "name": "Mozilla Radial Gradient Syntax",
1272    "href": "http://developer.mozilla.org/en/CSS/-moz-radial-gradient"
1273  },{
1274    "name": "W3C Gradient Spec",
1275    "href": "dev.w3.org/csswg/css3-images/#gradients-"
1276  }]
1277}
1278!*/
1279
1280
1281  Modernizr.addTest('cssgradients', function() {
1282
1283    var str1 = 'background-image:';
1284    var str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));';
1285    var css = '';
1286    var angle;
1287
1288    for (var i = 0, len = prefixes.length - 1; i < len; i++) {
1289      angle = (i === 0 ? 'to ' : '');
1290      css += str1 + prefixes[i] + 'linear-gradient(' + angle + 'left top, #9f9, white);';
1291    }
1292
1293    if (Modernizr._config.usePrefixes) {
1294    // legacy webkit syntax (FIXME: remove when syntax not in use anymore)
1295      css += str1 + '-webkit-' + str2;
1296    }
1297
1298    var elem = createElement('a');
1299    var style = elem.style;
1300    style.cssText = css;
1301
1302    // IE6 returns undefined so cast to string
1303    return ('' + style.backgroundImage).indexOf('gradient') > -1;
1304  });
1305
1306/*!
1307{
1308  "name": "CSS Multiple Backgrounds",
1309  "caniuse": "multibackgrounds",
1310  "property": "multiplebgs",
1311  "tags": ["css"]
1312}
1313!*/
1314
1315  // Setting multiple images AND a color on the background shorthand property
1316  // and then querying the style.background property value for the number of
1317  // occurrences of "url(" is a reliable method for detecting ACTUAL support for this!
1318
1319  Modernizr.addTest('multiplebgs', function() {
1320    var style = createElement('a').style;
1321    style.cssText = 'background:url(https://),url(https://),red url(https://)';
1322
1323    // If the UA supports multiple backgrounds, there should be three occurrences
1324    // of the string "url(" in the return value for elemStyle.background
1325    return (/(url\s*\(.*?){3}/).test(style.background);
1326  });
1327
1328/*!
1329{
1330  "name": "CSS Opacity",
1331  "caniuse": "css-opacity",
1332  "property": "opacity",
1333  "tags": ["css"]
1334}
1335!*/
1336
1337  // Browsers that actually have CSS Opacity implemented have done so
1338  // according to spec, which means their return values are within the
1339  // range of [0.0,1.0] - including the leading zero.
1340
1341  Modernizr.addTest('opacity', function() {
1342    var style = createElement('a').style;
1343    style.cssText = prefixes.join('opacity:.55;');
1344
1345    // The non-literal . in this regex is intentional:
1346    // German Chrome returns this value as 0,55
1347    // github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632
1348    return (/^0.55$/).test(style.opacity);
1349  });
1350
1351/*!
1352{
1353  "name": "CSS rgba",
1354  "caniuse": "css3-colors",
1355  "property": "rgba",
1356  "tags": ["css"],
1357  "notes": [{
1358    "name": "CSSTricks Tutorial",
1359    "href": "http://css-tricks.com/rgba-browser-support/"
1360  }]
1361}
1362!*/
1363
1364  Modernizr.addTest('rgba', function() {
1365    var style = createElement('a').style;
1366    style.cssText = 'background-color:rgba(150,255,150,.5)';
1367
1368    return ('' + style.backgroundColor).indexOf('rgba') > -1;
1369  });
1370
1371/*!
1372{
1373  "name": "Inline SVG",
1374  "property": "inlinesvg",
1375  "caniuse": "svg-html5",
1376  "tags": ["svg"],
1377  "notes": [{
1378    "name": "Test page",
1379    "href": "http://paulirish.com/demo/inline-svg"
1380  }, {
1381    "name": "Test page and results",
1382    "href": "http://codepen.io/eltonmesquita/full/GgXbvo/"
1383  }],
1384  "polyfills": ["inline-svg-polyfill"],
1385  "knownBugs": ["False negative on some Chromia browsers."]
1386}
1387!*/
1388/* DOC
1389Detects support for inline SVG in HTML (not within XHTML).
1390*/
1391
1392  Modernizr.addTest('inlinesvg', function() {
1393    var div = createElement('div');
1394    div.innerHTML = '<svg/>';
1395    return (typeof SVGRect != 'undefined' && div.firstChild && div.firstChild.namespaceURI) == 'http://www.w3.org/2000/svg';
1396  });
1397
1398/*!
1399{
1400  "name": "WebGL Extensions",
1401  "property": "webglextensions",
1402  "tags": ["webgl", "graphics"],
1403  "builderAliases": ["webgl_extensions"],
1404  "async" : true,
1405  "authors": ["Ilmari Heikkinen"],
1406  "knownBugs": [],
1407  "notes": [{
1408    "name": "Kronos extensions registry",
1409    "href": "http://www.khronos.org/registry/webgl/extensions/"
1410  }]
1411}
1412!*/
1413/* DOC
1414Detects support for OpenGL extensions in WebGL. It's `true` if the [WebGL extensions API](https://developer.mozilla.org/en-US/docs/Web/WebGL/Using_Extensions) is supported, then exposes the supported extensions as subproperties, e.g.:
1415
1416```javascript
1417if (Modernizr.webglextensions) {
1418  // WebGL extensions API supported
1419}
1420if ('OES_vertex_array_object' in Modernizr.webglextensions) {
1421  // Vertex Array Objects extension supported
1422}
1423```
1424*/
1425
1426  // based on code from ilmari heikkinen
1427  // code.google.com/p/graphics-detect/source/browse/js/detect.js
1428
1429  // Not Async but handles it's own self
1430  Modernizr.addAsyncTest(function() {
1431    /* jshint -W053 */
1432
1433    // Not a good candidate for css classes, so we avoid addTest stuff
1434    Modernizr.webglextensions = new Boolean(false);
1435
1436    if (!Modernizr.webgl) {
1437      return;
1438    }
1439
1440    var canvas;
1441    var ctx;
1442    var exts;
1443
1444    try {
1445      canvas = createElement('canvas');
1446      ctx = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
1447      exts = ctx.getSupportedExtensions();
1448    }
1449    catch (e) {
1450      return;
1451    }
1452
1453    if (ctx !== undefined) {
1454      Modernizr.webglextensions = new Boolean(true);
1455    }
1456
1457    for (var i = -1, len = exts.length; ++i < len;) {
1458      Modernizr.webglextensions[exts[i]] = true;
1459    }
1460
1461    canvas = undefined;
1462  });
1463
1464
1465  /**
1466   * hasOwnProp is a shim for hasOwnProperty that is needed for Safari 2.0 support
1467   *
1468   * @author kangax
1469   * @access private
1470   * @function hasOwnProp
1471   * @param {object} object - The object to check for a property
1472   * @param {string} property - The property to check for
1473   * @returns {boolean}
1474   */
1475
1476  // hasOwnProperty shim by kangax needed for Safari 2.0 support
1477  var hasOwnProp;
1478
1479  (function() {
1480    var _hasOwnProperty = ({}).hasOwnProperty;
1481    /* istanbul ignore else */
1482    /* we have no way of testing IE 5.5 or safari 2,
1483     * so just assume the else gets hit */
1484    if (!is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined')) {
1485      hasOwnProp = function(object, property) {
1486        return _hasOwnProperty.call(object, property);
1487      };
1488    }
1489    else {
1490      hasOwnProp = function(object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
1491        return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
1492      };
1493    }
1494  })();
1495
1496  
1497
1498
1499   // _l tracks listeners for async tests, as well as tests that execute after the initial run
1500  ModernizrProto._l = {};
1501
1502  /**
1503   * Modernizr.on is a way to listen for the completion of async tests. Being
1504   * asynchronous, they may not finish before your scripts run. As a result you
1505   * will get a possibly false negative `undefined` value.
1506   *
1507   * @memberof Modernizr
1508   * @name Modernizr.on
1509   * @access public
1510   * @function on
1511   * @param {string} feature - String name of the feature detect
1512   * @param {function} cb - Callback function returning a Boolean - true if feature is supported, false if not
1513   * @example
1514   *
1515   * ```js
1516   * Modernizr.on('flash', function( result ) {
1517   *   if (result) {
1518   *    // the browser has flash
1519   *   } else {
1520   *     // the browser does not have flash
1521   *   }
1522   * });
1523   * ```
1524   */
1525
1526  ModernizrProto.on = function(feature, cb) {
1527    // Create the list of listeners if it doesn't exist
1528    if (!this._l[feature]) {
1529      this._l[feature] = [];
1530    }
1531
1532    // Push this test on to the listener list
1533    this._l[feature].push(cb);
1534
1535    // If it's already been resolved, trigger it on next tick
1536    if (Modernizr.hasOwnProperty(feature)) {
1537      // Next Tick
1538      setTimeout(function() {
1539        Modernizr._trigger(feature, Modernizr[feature]);
1540      }, 0);
1541    }
1542  };
1543
1544  /**
1545   * _trigger is the private function used to signal test completion and run any
1546   * callbacks registered through [Modernizr.on](#modernizr-on)
1547   *
1548   * @memberof Modernizr
1549   * @name Modernizr._trigger
1550   * @access private
1551   * @function _trigger
1552   * @param {string} feature - string name of the feature detect
1553   * @param {function|boolean} [res] - A feature detection function, or the boolean =
1554   * result of a feature detection function
1555   */
1556
1557  ModernizrProto._trigger = function(feature, res) {
1558    if (!this._l[feature]) {
1559      return;
1560    }
1561
1562    var cbs = this._l[feature];
1563
1564    // Force async
1565    setTimeout(function() {
1566      var i, cb;
1567      for (i = 0; i < cbs.length; i++) {
1568        cb = cbs[i];
1569        cb(res);
1570      }
1571    }, 0);
1572
1573    // Don't trigger these again
1574    delete this._l[feature];
1575  };
1576
1577  /**
1578   * addTest allows you to define your own feature detects that are not currently
1579   * included in Modernizr (under the covers it's the exact same code Modernizr
1580   * uses for its own [feature detections](https://github.com/Modernizr/Modernizr/tree/master/feature-detects)). Just like the offical detects, the result
1581   * will be added onto the Modernizr object, as well as an appropriate className set on
1582   * the html element when configured to do so
1583   *
1584   * @memberof Modernizr
1585   * @name Modernizr.addTest
1586   * @optionName Modernizr.addTest()
1587   * @optionProp addTest
1588   * @access public
1589   * @function addTest
1590   * @param {string|object} feature - The string name of the feature detect, or an
1591   * object of feature detect names and test
1592   * @param {function|boolean} test - Function returning true if feature is supported,
1593   * false if not. Otherwise a boolean representing the results of a feature detection
1594   * @example
1595   *
1596   * The most common way of creating your own feature detects is by calling
1597   * `Modernizr.addTest` with a string (preferably just lowercase, without any
1598   * punctuation), and a function you want executed that will return a boolean result
1599   *
1600   * ```js
1601   * Modernizr.addTest('itsTuesday', function() {
1602   *  var d = new Date();
1603   *  return d.getDay() === 2;
1604   * });
1605   * ```
1606   *
1607   * When the above is run, it will set Modernizr.itstuesday to `true` when it is tuesday,
1608   * and to `false` every other day of the week. One thing to notice is that the names of
1609   * feature detect functions are always lowercased when added to the Modernizr object. That
1610   * means that `Modernizr.itsTuesday` will not exist, but `Modernizr.itstuesday` will.
1611   *
1612   *
1613   *  Since we only look at the returned value from any feature detection function,
1614   *  you do not need to actually use a function. For simple detections, just passing
1615   *  in a statement that will return a boolean value works just fine.
1616   *
1617   * ```js
1618   * Modernizr.addTest('hasJquery', 'jQuery' in window);
1619   * ```
1620   *
1621   * Just like before, when the above runs `Modernizr.hasjquery` will be true if
1622   * jQuery has been included on the page. Not using a function saves a small amount
1623   * of overhead for the browser, as well as making your code much more readable.
1624   *
1625   * Finally, you also have the ability to pass in an object of feature names and
1626   * their tests. This is handy if you want to add multiple detections in one go.
1627   * The keys should always be a string, and the value can be either a boolean or
1628   * function that returns a boolean.
1629   *
1630   * ```js
1631   * var detects = {
1632   *  'hasjquery': 'jQuery' in window,
1633   *  'itstuesday': function() {
1634   *    var d = new Date();
1635   *    return d.getDay() === 2;
1636   *  }
1637   * }
1638   *
1639   * Modernizr.addTest(detects);
1640   * ```
1641   *
1642   * There is really no difference between the first methods and this one, it is
1643   * just a convenience to let you write more readable code.
1644   */
1645
1646  function addTest(feature, test) {
1647
1648    if (typeof feature == 'object') {
1649      for (var key in feature) {
1650        if (hasOwnProp(feature, key)) {
1651          addTest(key, feature[ key ]);
1652        }
1653      }
1654    } else {
1655
1656      feature = feature.toLowerCase();
1657      var featureNameSplit = feature.split('.');
1658      var last = Modernizr[featureNameSplit[0]];
1659
1660      // Again, we don't check for parent test existence. Get that right, though.
1661      if (featureNameSplit.length == 2) {
1662        last = last[featureNameSplit[1]];
1663      }
1664
1665      if (typeof last != 'undefined') {
1666        // we're going to quit if you're trying to overwrite an existing test
1667        // if we were to allow it, we'd do this:
1668        //   var re = new RegExp("\\b(no-)?" + feature + "\\b");
1669        //   docElement.className = docElement.className.replace( re, '' );
1670        // but, no rly, stuff 'em.
1671        return Modernizr;
1672      }
1673
1674      test = typeof test == 'function' ? test() : test;
1675
1676      // Set the value (this is the magic, right here).
1677      if (featureNameSplit.length == 1) {
1678        Modernizr[featureNameSplit[0]] = test;
1679      } else {
1680        // cast to a Boolean, if not one already
1681        /* jshint -W053 */
1682        if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
1683          Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
1684        }
1685
1686        Modernizr[featureNameSplit[0]][featureNameSplit[1]] = test;
1687      }
1688
1689      // Set a single class (either `feature` or `no-feature`)
1690      /* jshint -W041 */
1691      setClasses([(!!test && test != false ? '' : 'no-') + featureNameSplit.join('-')]);
1692      /* jshint +W041 */
1693
1694      // Trigger the event
1695      Modernizr._trigger(feature, test);
1696    }
1697
1698    return Modernizr; // allow chaining.
1699  }
1700
1701  // After all the tests are run, add self to the Modernizr prototype
1702  Modernizr._q.push(function() {
1703    ModernizrProto.addTest = addTest;
1704  });
1705
1706  
1707
1708
1709  /**
1710   * cssToDOM takes a kebab-case string and converts it to camelCase
1711   * e.g. box-sizing -> boxSizing
1712   *
1713   * @access private
1714   * @function cssToDOM
1715   * @param {string} name - String name of kebab-case prop we want to convert
1716   * @returns {string} The camelCase version of the supplied name
1717   */
1718
1719  function cssToDOM(name) {
1720    return name.replace(/([a-z])-([a-z])/g, function(str, m1, m2) {
1721      return m1 + m2.toUpperCase();
1722    }).replace(/^-/, '');
1723  }
1724  ;
1725
1726
1727  /**
1728   * contains checks to see if a string contains another string
1729   *
1730   * @access private
1731   * @function contains
1732   * @param {string} str - The string we want to check for substrings
1733   * @param {string} substr - The substring we want to search the first string for
1734   * @returns {boolean}
1735   */
1736
1737  function contains(str, substr) {
1738    return !!~('' + str).indexOf(substr);
1739  }
1740
1741  ;
1742/*!
1743{
1744  "name": "CSS HSLA Colors",
1745  "caniuse": "css3-colors",
1746  "property": "hsla",
1747  "tags": ["css"]
1748}
1749!*/
1750
1751  Modernizr.addTest('hsla', function() {
1752    var style = createElement('a').style;
1753    style.cssText = 'background-color:hsla(120,40%,100%,.5)';
1754    return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla');
1755  });
1756
1757
1758  /**
1759   * since we have a fairly large number of input tests that don't mutate the input
1760   * we create a single element that can be shared with all of those tests for a
1761   * minor perf boost
1762   *
1763   * @access private
1764   * @returns {HTMLInputElement}
1765   */
1766  var inputElem = createElement('input');
1767  
1768/*!
1769{
1770  "name": "Input attributes",
1771  "property": "input",
1772  "tags": ["forms"],
1773  "authors": ["Mike Taylor"],
1774  "notes": [{
1775    "name": "WHATWG spec",
1776    "href": "http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary"
1777  }],
1778  "knownBugs": ["Some blackberry devices report false positive for input.multiple"]
1779}
1780!*/
1781/* DOC
1782Detects support for HTML5 `<input>` element attributes and exposes Boolean subproperties with the results:
1783
1784```javascript
1785Modernizr.input.autocomplete
1786Modernizr.input.autofocus
1787Modernizr.input.list
1788Modernizr.input.max
1789Modernizr.input.min
1790Modernizr.input.multiple
1791Modernizr.input.pattern
1792Modernizr.input.placeholder
1793Modernizr.input.required
1794Modernizr.input.step
1795```
1796*/
1797
1798  // Run through HTML5's new input attributes to see if the UA understands any.
1799  // Mike Taylr has created a comprehensive resource for testing these attributes
1800  //   when applied to all input types:
1801  //   miketaylr.com/code/input-type-attr.html
1802
1803  // Only input placeholder is tested while textarea's placeholder is not.
1804  // Currently Safari 4 and Opera 11 have support only for the input placeholder
1805  // Both tests are available in feature-detects/forms-placeholder.js
1806
1807  var inputattrs = 'autocomplete autofocus list placeholder max min multiple pattern required step'.split(' ');
1808  var attrs = {};
1809
1810  Modernizr['input'] = (function(props) {
1811    for (var i = 0, len = props.length; i < len; i++) {
1812      attrs[ props[i] ] = !!(props[i] in inputElem);
1813    }
1814    if (attrs.list) {
1815      // safari false positive's on datalist: webk.it/74252
1816      // see also github.com/Modernizr/Modernizr/issues/146
1817      attrs.list = !!(createElement('datalist') && window.HTMLDataListElement);
1818    }
1819    return attrs;
1820  })(inputattrs);
1821
1822/*!
1823{
1824  "name": "Form input types",
1825  "property": "inputtypes",
1826  "caniuse": "forms",
1827  "tags": ["forms"],
1828  "authors": ["Mike Taylor"],
1829  "polyfills": [
1830    "jquerytools",
1831    "webshims",
1832    "h5f",
1833    "webforms2",
1834    "nwxforms",
1835    "fdslider",
1836    "html5slider",
1837    "galleryhtml5forms",
1838    "jscolor",
1839    "html5formshim",
1840    "selectedoptionsjs",
1841    "formvalidationjs"
1842  ]
1843}
1844!*/
1845/* DOC
1846Detects support for HTML5 form input types and exposes Boolean subproperties with the results:
1847
1848```javascript
1849Modernizr.inputtypes.color
1850Modernizr.inputtypes.date
1851Modernizr.inputtypes.datetime
1852Modernizr.inputtypes['datetime-local']
1853Modernizr.inputtypes.email
1854Modernizr.inputtypes.month
1855Modernizr.inputtypes.number
1856Modernizr.inputtypes.range
1857Modernizr.inputtypes.search
1858Modernizr.inputtypes.tel
1859Modernizr.inputtypes.time
1860Modernizr.inputtypes.url
1861Modernizr.inputtypes.week
1862```
1863*/
1864
1865  // Run through HTML5's new input types to see if the UA understands any.
1866  //   This is put behind the tests runloop because it doesn't return a
1867  //   true/false like all the other tests; instead, it returns an object
1868  //   containing each input type with its corresponding true/false value
1869
1870  // Big thanks to @miketaylr for the html5 forms expertise. miketaylr.com/
1871  var inputtypes = 'search tel url email datetime date month week time datetime-local number range color'.split(' ');
1872  var inputs = {};
1873
1874  Modernizr['inputtypes'] = (function(props) {
1875    var len = props.length;
1876    var smile = ':)';
1877    var inputElemType;
1878    var defaultView;
1879    var bool;
1880
1881    for (var i = 0; i < len; i++) {
1882
1883      inputElem.setAttribute('type', inputElemType = props[i]);
1884      bool = inputElem.type !== 'text' && 'style' in inputElem;
1885
1886      // We first check to see if the type we give it sticks..
1887      // If the type does, we feed it a textual value, which shouldn't be valid.
1888      // If the value doesn't stick, we know there's input sanitization which infers a custom UI
1889      if (bool) {
1890
1891        inputElem.value         = smile;
1892        inputElem.style.cssText = 'position:absolute;visibility:hidden;';
1893
1894        if (/^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined) {
1895
1896          docElement.appendChild(inputElem);
1897          defaultView = document.defaultView;
1898
1899          // Safari 2-4 allows the smiley as a value, despite making a slider
1900          bool =  defaultView.getComputedStyle &&
1901            defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' &&
1902            // Mobile android web browser has false positive, so must
1903            // check the height to see if the widget is actually there.
1904            (inputElem.offsetHeight !== 0);
1905
1906          docElement.removeChild(inputElem);
1907
1908        } else if (/^(search|tel)$/.test(inputElemType)) {
1909          // Spec doesn't define any special parsing or detectable UI
1910          //   behaviors so we pass these through as true
1911
1912          // Interestingly, opera fails the earlier test, so it doesn't
1913          //  even make it here.
1914
1915        } else if (/^(url|email|number)$/.test(inputElemType)) {
1916          // Real url and email support comes with prebaked validation.
1917          bool = inputElem.checkValidity && inputElem.checkValidity() === false;
1918
1919        } else {
1920          // If the upgraded input compontent rejects the :) text, we got a winner
1921          bool = inputElem.value != smile;
1922        }
1923      }
1924
1925      inputs[ props[i] ] = !!bool;
1926    }
1927    return inputs;
1928  })(inputtypes);
1929
1930/*!
1931{
1932  "name": "CSS Supports",
1933  "property": "supports",
1934  "caniuse": "css-featurequeries",
1935  "tags": ["css"],
1936  "builderAliases": ["css_supports"],
1937  "notes": [{
1938    "name": "W3 Spec",
1939    "href": "http://dev.w3.org/csswg/css3-conditional/#at-supports"
1940  },{
1941    "name": "Related Github Issue",
1942    "href": "github.com/Modernizr/Modernizr/issues/648"
1943  },{
1944    "name": "W3 Info",
1945    "href": "http://dev.w3.org/csswg/css3-conditional/#the-csssupportsrule-interface"
1946  }]
1947}
1948!*/
1949
1950  var newSyntax = 'CSS' in window && 'supports' in window.CSS;
1951  var oldSyntax = 'supportsCSS' in window;
1952  Modernizr.addTest('supports', newSyntax || oldSyntax);
1953
1954
1955  /**
1956   * Object.prototype.toString can be used with every object and allows you to
1957   * get its class easily. Abstracting it off of an object prevents situations
1958   * where the toString property has been overridden
1959   *
1960   * @access private
1961   * @function toStringFn
1962   * @returns {function} An abstracted toString function
1963   */
1964
1965  var toStringFn = ({}).toString;
1966  
1967/*!
1968{
1969  "name": "SVG clip paths",
1970  "property": "svgclippaths",
1971  "tags": ["svg"],
1972  "notes": [{
1973    "name": "Demo",
1974    "href": "http://srufaculty.sru.edu/david.dailey/svg/newstuff/clipPath4.svg"
1975  }]
1976}
1977!*/
1978/* DOC
1979Detects support for clip paths in SVG (only, not on HTML content).
1980
1981See [this discussion](http://github.com/Modernizr/Modernizr/issues/213) regarding applying SVG clip paths to HTML content.
1982*/
1983
1984  Modernizr.addTest('svgclippaths', function() {
1985    return !!document.createElementNS &&
1986      /SVGClipPath/.test(toStringFn.call(document.createElementNS('http://www.w3.org/2000/svg', 'clipPath')));
1987  });
1988
1989/*!
1990{
1991  "name": "SVG SMIL animation",
1992  "property": "smil",
1993  "caniuse": "svg-smil",
1994  "tags": ["svg"],
1995  "notes": [{
1996  "name": "W3C Synchronised Multimedia spec",
1997  "href": "http://www.w3.org/AudioVideo/"
1998  }]
1999}
2000!*/
2001
2002  // SVG SMIL animation
2003  Modernizr.addTest('smil', function() {
2004    return !!document.createElementNS &&
2005      /SVGAnimate/.test(toStringFn.call(document.createElementNS('http://www.w3.org/2000/svg', 'animate')));
2006  });
2007
2008
2009  var cssomPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.split(' ') : []);
2010  ModernizrProto._cssomPrefixes = cssomPrefixes;
2011  
2012
2013  /**
2014   * atRule returns a given CSS property at-rule (eg @keyframes), possibly in
2015   * some prefixed form, or false, in the case of an unsupported rule
2016   *
2017   * @memberof Modernizr
2018   * @name Modernizr.atRule
2019   * @optionName Modernizr.atRule()
2020   * @optionProp atRule
2021   * @access public
2022   * @function atRule
2023   * @param {string} prop - String name of the @-rule to test for
2024   * @returns {string|false} The string representing the (possibly prefixed)
2025   * valid version of the @-rule, or `false` when it is unsupported.
2026   * @example
2027   * ```js
2028   *  var keyframes = Modernizr.atRule('@keyframes');
2029   *
2030   *  if (keyframes) {
2031   *    // keyframes are supported
2032   *    // could be `@-webkit-keyframes` or `@keyframes`
2033   *  } else {
2034   *    // keyframes === `false`
2035   *  }
2036   * ```
2037   *
2038   */
2039
2040  var atRule = function(prop) {
2041    var length = prefixes.length;
2042    var cssrule = window.CSSRule;
2043    var rule;
2044
2045    if (typeof cssrule === 'undefined') {
2046      return undefined;
2047    }
2048
2049    if (!prop) {
2050      return false;
2051    }
2052
2053    // remove literal @ from beginning of provided property
2054    prop = prop.replace(/^@/, '');
2055
2056    // CSSRules use underscores instead of dashes
2057    rule = prop.replace(/-/g, '_').toUpperCase() + '_RULE';
2058
2059    if (rule in cssrule) {
2060      return '@' + prop;
2061    }
2062
2063    for (var i = 0; i < length; i++) {
2064      // prefixes gives us something like -o-, and we want O_
2065      var prefix = prefixes[i];
2066      var thisRule = prefix.toUpperCase() + '_' + rule;
2067
2068      if (thisRule in cssrule) {
2069        return '@-' + prefix.toLowerCase() + '-' + prop;
2070      }
2071    }
2072
2073    return false;
2074  };
2075
2076  ModernizrProto.atRule = atRule;
2077
2078  
2079
2080  /**
2081   * getBody returns the body of a document, or an element that can stand in for
2082   * the body if a real body does not exist
2083   *
2084   * @access private
2085   * @function getBody
2086   * @returns {HTMLElement|SVGElement} Returns the real body of a document, or an
2087   * artificially created element that stands in for the body
2088   */
2089
2090  function getBody() {
2091    // After page load injecting a fake body doesn't work so check if body exists
2092    var body = document.body;
2093
2094    if (!body) {
2095      // Can't use the real body create a fake one.
2096      body = createElement(isSVG ? 'svg' : 'body');
2097      body.fake = true;
2098    }
2099
2100    return body;
2101  }
2102
2103  ;
2104
2105  /**
2106   * injectElementWithStyles injects an element with style element and some CSS rules
2107   *
2108   * @access private
2109   * @function injectElementWithStyles
2110   * @param {string} rule - String representing a css rule
2111   * @param {function} callback - A function that is used to test the injected element
2112   * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
2113   * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
2114   * @returns {boolean}
2115   */
2116
2117  function injectElementWithStyles(rule, callback, nodes, testnames) {
2118    var mod = 'modernizr';
2119    var style;
2120    var ret;
2121    var node;
2122    var docOverflow;
2123    var div = createElement('div');
2124    var body = getBody();
2125
2126    if (parseInt(nodes, 10)) {
2127      // In order not to give false positives we create a node for each test
2128      // This also allows the method to scale for unspecified uses
2129      while (nodes--) {
2130        node = createElement('div');
2131        node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
2132        div.appendChild(node);
2133      }
2134    }
2135
2136    style = createElement('style');
2137    style.type = 'text/css';
2138    style.id = 's' + mod;
2139
2140    // 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.
2141    // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
2142    (!body.fake ? div : body).appendChild(style);
2143    body.appendChild(div);
2144
2145    if (style.styleSheet) {
2146      style.styleSheet.cssText = rule;
2147    } else {
2148      style.appendChild(document.createTextNode(rule));
2149    }
2150    div.id = mod;
2151
2152    if (body.fake) {
2153      //avoid crashing IE8, if background image is used
2154      body.style.background = '';
2155      //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
2156      body.style.overflow = 'hidden';
2157      docOverflow = docElement.style.overflow;
2158      docElement.style.overflow = 'hidden';
2159      docElement.appendChild(body);
2160    }
2161
2162    ret = callback(div, rule);
2163    // If this is done after page load we don't want to remove the body so check if body exists
2164    if (body.fake) {
2165      body.parentNode.removeChild(body);
2166      docElement.style.overflow = docOverflow;
2167      // Trigger layout so kinetic scrolling isn't disabled in iOS6+
2168      docElement.offsetHeight;
2169    } else {
2170      div.parentNode.removeChild(div);
2171    }
2172
2173    return !!ret;
2174
2175  }
2176
2177  ;
2178
2179  /**
2180   * Modernizr.mq tests a given media query, live against the current state of the window
2181   * adapted from matchMedia polyfill by Scott Jehl and Paul Irish
2182   * gist.github.com/786768
2183   *
2184   * @memberof Modernizr
2185   * @name Modernizr.mq
2186   * @optionName Modernizr.mq()
2187   * @optionProp mq
2188   * @access public
2189   * @function mq
2190   * @param {string} mq - String of the media query we want to test
2191   * @returns {boolean}
2192   * @example
2193   * Modernizr.mq allows for you to programmatically check if the current browser
2194   * window state matches a media query.
2195   *
2196   * ```js
2197   *  var query = Modernizr.mq('(min-width: 900px)');
2198   *
2199   *  if (query) {
2200   *    // the browser window is larger than 900px
2201   *  }
2202   * ```
2203   *
2204   * Only valid media queries are supported, therefore you must always include values
2205   * with your media query
2206   *
2207   * ```js
2208   * // good
2209   *  Modernizr.mq('(min-width: 900px)');
2210   *
2211   * // bad
2212   *  Modernizr.mq('min-width');
2213   * ```
2214   *
2215   * If you would just like to test that media queries are supported in general, use
2216   *
2217   * ```js
2218   *  Modernizr.mq('only all'); // true if MQ are supported, false if not
2219   * ```
2220   *
2221   *
2222   * Note that if the browser does not support media queries (e.g. old IE) mq will
2223   * always return false.
2224   */
2225
2226  var mq = (function() {
2227    var matchMedia = window.matchMedia || window.msMatchMedia;
2228    if (matchMedia) {
2229      return function(mq) {
2230        var mql = matchMedia(mq);
2231        return mql && mql.matches || false;
2232      };
2233    }
2234
2235    return function(mq) {
2236      var bool = false;
2237
2238      injectElementWithStyles('@media ' + mq + ' { #modernizr { position: absolute; } }', function(node) {
2239        bool = (window.getComputedStyle ?
2240                window.getComputedStyle(node, null) :
2241                node.currentStyle)['position'] == 'absolute';
2242      });
2243
2244      return bool;
2245    };
2246  })();
2247
2248
2249  ModernizrProto.mq = mq;
2250
2251  
2252
2253  /**
2254   * testStyles injects an element with style element and some CSS rules
2255   *
2256   * @memberof Modernizr
2257   * @name Modernizr.testStyles
2258   * @optionName Modernizr.testStyles()
2259   * @optionProp testStyles
2260   * @access public
2261   * @function testStyles
2262   * @param {string} rule - String representing a css rule
2263   * @param {function} callback - A function that is used to test the injected element
2264   * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
2265   * @param {string[]}
2265 [testnames] - An array of strings that are used as ids for the additional nodes
2266   * @returns {boolean}
2267   * @example
2268   *
2269   * `Modernizr.testStyles` takes a CSS rule and injects it onto the current page
2270   * along with (possibly multiple) DOM elements. This lets you check for features
2271   * 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).
2272   *
2273   * ```js
2274   * Modernizr.testStyles('#modernizr { width: 9px; color: papayawhip; }', function(elem, rule) {
2275   *   // elem is the first DOM node in the page (by default #modernizr)
2276   *   // rule is the first argument you supplied - the CSS rule in string form
2277   *
2278   *   addTest('widthworks', elem.style.width === '9px')
2279   * });
2280   * ```
2281   *
2282   * If your test requires multiple nodes, you can include a third argument
2283   * indicating how many additional div elements to include on the page. The
2284   * additional nodes are injected as children of the `elem` that is returned as
2285   * the first argument to the callback.
2286   *
2287   * ```js
2288   * Modernizr.testStyles('#modernizr {width: 1px}; #modernizr2 {width: 2px}', function(elem) {
2289   *   document.getElementById('modernizr').style.width === '1px'; // true
2290   *   document.getElementById('modernizr2').style.width === '2px'; // true
2291   *   elem.firstChild === document.getElementById('modernizr2'); // true
2292   * }, 1);
2293   * ```
2294   *
2295   * By default, all of the additional elements have an ID of `modernizr[n]`, where
2296   * `n` is its index (e.g. the first additional, second overall is `#modernizr2`,
2297   * the second additional is `#modernizr3`, etc.).
2298   * If you want to have more meaningful IDs for your function, you can provide
2299   * them as the fourth argument, as an array of strings
2300   *
2301   * ```js
2302   * Modernizr.testStyles('#foo {width: 10px}; #bar {height: 20px}', function(elem) {
2303   *   elem.firstChild === document.getElementById('foo'); // true
2304   *   elem.lastChild === document.getElementById('bar'); // true
2305   * }, 2, ['foo', 'bar']);
2306   * ```
2307   *
2308   */
2309
2310  var testStyles = ModernizrProto.testStyles = injectElementWithStyles;
2311  
2312/*!
2313{
2314  "name": "Touch Events",
2315  "property": "touchevents",
2316  "caniuse" : "touch",
2317  "tags": ["media", "attribute"],
2318  "notes": [{
2319    "name": "Touch Events spec",
2320    "href": "http://www.w3.org/TR/2013/WD-touch-events-20130124/"
2321  }],
2322  "warnings": [
2323    "Indicates if the browser supports the Touch Events spec, and does not necessarily reflect a touchscreen device"
2324  ],
2325  "knownBugs": [
2326    "False-positive on some configurations of Nokia N900",
2327    "False-positive on some BlackBerry 6.0 builds – https://github.com/Modernizr/Modernizr/issues/372#issuecomment-3112695"
2328  ]
2329}
2330!*/
2331/* DOC
2332Indicates if the browser supports the W3C Touch Events API.
2333
2334This *does not* necessarily reflect a touchscreen device:
2335
2336* Older touchscreen devices only emulate mouse events
2337* Modern IE touch devices implement the Pointer Events API instead: use `Modernizr.pointerevents` to detect support for that
2338* Some browsers & OS setups may enable touch APIs when no touchscreen is connected
2339* Future browsers may implement other event models for touch interactions
2340
2341See this article: [You Can't Detect A Touchscreen](http://www.stucox.com/blog/you-cant-detect-a-touchscreen/).
2342
2343It's recommended to bind both mouse and touch/pointer events simultaneously – see [this HTML5 Rocks tutorial](http://www.html5rocks.com/en/mobile/touchandmouse/).
2344
2345This test will also return `true` for Firefox 4 Multitouch support.
2346*/
2347
2348  // Chrome (desktop) used to lie about its support on this, but that has since been rectified: http://crbug.com/36415
2349  Modernizr.addTest('touchevents', function() {
2350    var bool;
2351    if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
2352      bool = true;
2353    } else {
2354      var query = ['@media (', prefixes.join('touch-enabled),('), 'heartz', ')', '{#modernizr{top:9px;position:absolute}}'].join('');
2355      testStyles(query, function(node) {
2356        bool = node.offsetTop === 9;
2357      });
2358    }
2359    return bool;
2360  });
2361
2362/*!
2363{
2364  "name": "@font-face",
2365  "property": "fontface",
2366  "authors": ["Diego Perini", "Mat Marquis"],
2367  "tags": ["css"],
2368  "knownBugs": [
2369    "False Positive: WebOS http://github.com/Modernizr/Modernizr/issues/342",
2370    "False Postive: WP7 http://github.com/Modernizr/Modernizr/issues/538"
2371  ],
2372  "notes": [{
2373    "name": "@font-face detection routine by Diego Perini",
2374    "href": "http://javascript.nwbox.com/CSSSupport/"
2375  },{
2376    "name": "Filament Group @font-face compatibility research",
2377    "href": "https://docs.google.com/presentation/d/1n4NyG4uPRjAA8zn_pSQ_
2377Ket0RhcWC6QlZ6LMjKeECo0/edit#slide=id.p"
2378  },{
2379    "name": "Filament Grunticon/@font-face device testing results",
2380    "href": "https://docs.google.com/spreadsheet/ccc?key=0Ag5_yGvxpINRdHFYeUJPNnZMWUZKR2ItMEpRTXZPdUE#gid=0"
2381  },{
2382    "name": "CSS fonts on Android",
2383    "href": "http://stackoverflow.com/questions/3200069/css-fonts-on-android"
2384  },{
2385    "name": "@font-face and Android",
2386    "href": "http://archivist.incutio.com/viewlist/css-discuss/115960"
2387  }]
2388}
2389!*/
2390
2391  var blacklist = (function() {
2392    var ua = navigator.userAgent;
2393    var wkvers = ua.match(/applewebkit\/([0-9]+)/gi) && parseFloat(RegExp.$1);
2394    var webos = ua.match(/w(eb)?osbrowser/gi);
2395    var wppre8 = ua.match(/windows phone/gi) && ua.match(/iemobile\/([0-9])+/gi) && parseFloat(RegExp.$1) >= 9;
2396    var oldandroid = wkvers < 533 && ua.match(/android/gi);
2397    return webos || oldandroid || wppre8;
2398  }());
2399  if (blacklist) {
2400    Modernizr.addTest('fontface', false);
2401  } else {
2402    testStyles('@font-face {font-family:"font";src:url("https://")}', function(node, rule) {
2403      var style = document.getElementById('smodernizr');
2404      var sheet = style.sheet || style.styleSheet;
2405      var cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : '';
2406      var bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0;
2407      Modernizr.addTest('fontface', bool);
2408    });
2409  }
2410;
2411/*!
2412{
2413  "name": "CSS Generated Content",
2414  "property": "generatedcontent",
2415  "tags": ["css"],
2416  "warnings": ["Android won't return correct height for anything below 7px #738"],
2417  "notes": [{
2418    "name": "W3C CSS Selectors Level 3 spec",
2419    "href": "http://www.w3.org/TR/css3-selectors/#gen-content"
2420  },{
2421    "name": "MDN article on :before",
2422    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/::before"
2423  },{
2424    "name": "MDN article on :after",
2425    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/::before"
2426  }]
2427}
2428!*/
2429
2430  testStyles('#modernizr{font:0/0 a}#modernizr:after{content:":)";visibility:hidden;font:7px/1 a}', function(node) {
2431    Modernizr.addTest('generatedcontent', node.offsetHeight >= 7);
2432  });
2433
2434
2435  /**
2436   * Create our "modernizr" element that we do most feature tests on.
2437   *
2438   * @access private
2439   */
2440
2441  var modElem = {
2442    elem : createElement('modernizr')
2443  };
2444
2445  // Clean up this element
2446  Modernizr._q.push(function() {
2447    delete modElem.elem;
2448  });
2449
2450  
2451
2452  var mStyle = {
2453    style : modElem.elem.style
2454  };
2455
2456  // kill ref for gc, must happen before mod.elem is removed, so we unshift on to
2457  // the front of the queue.
2458  Modernizr._q.unshift(function() {
2459    delete mStyle.style;
2460  });
2461
2462  
2463
2464  /**
2465   * fnBind is a super small [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) polyfill.
2466   *
2467   * @access private
2468   * @function fnBind
2469   * @param {function} fn - a function you want to change `this` reference to
2470   * @param {object} that - the `this` you want to call the function with
2471   * @returns {function} The wrapped version of the supplied function
2472   */
2473
2474  function fnBind(fn, that) {
2475    return function() {
2476      return fn.apply(that, arguments);
2477    };
2478  }
2479
2480  ;
2481
2482  /**
2483   * testDOMProps is a generic DOM property test; if a browser supports
2484   *   a certain property, it won't return undefined for it.
2485   */
2486  function testDOMProps(props, obj, elem) {
2487    var item;
2488
2489    for (var i in props) {
2490      if (props[i] in obj) {
2491
2492        // return the property name as a string
2493        if (elem === false) {
2494          return props[i];
2495        }
2496
2497        item = obj[props[i]];
2498
2499        // let's bind a function
2500        if (is(item, 'function')) {
2501          // bind to obj unless overriden
2502          return fnBind(item, elem || obj);
2503        }
2504
2505        // return the unbound function or obj or value
2506        return item;
2507      }
2508    }
2509    return false;
2510  }
2511
2512  ;
2513
2514  /**
2515   * domToCSS takes a camelCase string and converts it to kebab-case
2516   * e.g. boxSizing -> box-sizing
2517   *
2518   * @access private
2519   * @function domToCSS
2520   * @param {string} name - String name of camelCase prop we want to convert
2521   * @returns {string} The kebab-case version of the supplied name
2522   */
2523
2524  function domToCSS(name) {
2525    return name.replace(/([A-Z])/g, function(str, m1) {
2526      return '-' + m1.toLowerCase();
2527    }).replace(/^ms-/, '-ms-');
2528  }
2529  ;
2530
2531  /**
2532   * nativeTestProps allows for us to use native feature detection functionality if available.
2533   * some prefixed form, or false, in the case of an unsupported rule
2534   *
2535   * @access private
2536   * @function nativeTestProps
2537   * @param {array} props - An array of property names
2538   * @param {string} value - A string representing the value we want to check via @supports
2539   * @returns {boolean|undefined} A boolean when @supports exists, undefined otherwise
2540   */
2541
2542  // Accepts a list of property names and a single value
2543  // Returns `undefined` if native detection not available
2544  function nativeTestProps (props, value) {
2545    var i = props.length;
2546    // Start with the JS API: http://www.w3.org/TR/css3-conditional/#the-css-interface
2547    if ('CSS' in window && 'supports' in window.CSS) {
2548      // Try every prefixed variant of the property
2549      while (i--) {
2550        if (window.CSS.supports(domToCSS(props[i]), value)) {
2551          return true;
2552        }
2553      }
2554      return false;
2555    }
2556    // Otherwise fall back to at-rule (for Opera 12.x)
2557    else if ('CSSSupportsRule' in window) {
2558      // Build a condition string for every prefixed variant
2559      var conditionText = [];
2560      while (i--) {
2561        conditionText.push('(' + domToCSS(props[i]) + ':' + value + ')');
2562      }
2563      conditionText = conditionText.join(' or ');
2564      return injectElementWithStyles('@supports (' + conditionText 
2564+ ') { #modernizr { position: absolute; } }', function(node) {
2565        return getComputedStyle(node, null).position == 'absolute';
2566      });
2567    }
2568    return undefined;
2569  }
2570  ;
2571
2572  // testProps is a generic CSS / DOM property test.
2573
2574  // In testing support for a given CSS property, it's legit to test:
2575  //    `elem.style[styleName] !== undefined`
2576  // If the property is supported it will return an empty string,
2577  // if unsupported it will return undefined.
2578
2579  // We'll take advantage of this quick test and skip setting a style
2580  // on our modernizr element, but instead just testing undefined vs
2581  // empty string.
2582
2583  // Property names can be provided in either camelCase or kebab-case.
2584
2585  function testProps(props, prefixed, value, skipValueTest) {
2586    skipValueTest = is(skipValueTest, 'undefined') ? false : skipValueTest;
2587
2588    // Try native detect first
2589    if (!is(value, 'undefined')) {
2590      var result = nativeTestProps(props, value);
2591      if (!is(result, 'undefined')) {
2592        return result;
2593      }
2594    }
2595
2596    // Otherwise do it properly
2597    var afterInit, i, propsLength, prop, before;
2598
2599    // If we don't have a style element, that means we're running async or after
2600    // the core tests, so we'll need to create our own elements to use
2601
2602    // inside of an SVG element, in certain browsers, the `style` element is only
2603    // defined for valid tags. Therefore, if `modernizr` does not have one, we
2604    // fall back to a less used element and hope for the best.
2605    var elems = ['modernizr', 'tspan'];
2606    while (!mStyle.style) {
2607      afterInit = true;
2608      mStyle.modElem = createElement(elems.shift());
2609      mStyle.style = mStyle.modElem.style;
2610    }
2611
2612    // Delete the objects if we created them.
2613    function cleanElems() {
2614      if (afterInit) {
2615        delete mStyle.style;
2616        delete mStyle.modElem;
2617      }
2618    }
2619
2620    propsLength = props.length;
2621    for (i = 0; i < propsLength; i++) {
2622      prop = props[i];
2623      before = mStyle.style[prop];
2624
2625      if (contains(prop, '-')) {
2626        prop = cssToDOM(prop);
2627      }
2628
2629      if (mStyle.style[prop] !== undefined) {
2630
2631        // If value to test has been passed in, do a set-and-check test.
2632        // 0 (integer) is a valid property value, so check that `value` isn't
2633        // undefined, rather than just checking it's truthy.
2634        if (!skipValueTest && !is(value, 'undefined')) {
2635
2636          // Needs a try catch block because of old IE. This is slow, but will
2637          // be avoided in most cases because `skipValueTest` will be used.
2638          try {
2639            mStyle.style[prop] = value;
2640          } catch (e) {}
2641
2642          // If the property value has changed, we assume the value used is
2643          // supported. If `value` is empty string, it'll fail here (because
2644          // it hasn't changed), which matches how browsers have implemented
2645          // CSS.supports()
2646          if (mStyle.style[prop] != before) {
2647            cleanElems();
2648            return prefixed == 'pfx' ? prop : true;
2649          }
2650        }
2651        // Otherwise just return true, or the property name if this is a
2652        // `prefixed()` call
2653        else {
2654          cleanElems();
2655          return prefixed == 'pfx' ? prop : true;
2656        }
2657      }
2658    }
2659    cleanElems();
2660    return false;
2661  }
2662
2663  ;
2664
2665  /**
2666   * testProp() investigates whether a given style property is recognized
2667   * Property names can be provided in either camelCase or kebab-case.
2668   *
2669   * @memberof Modernizr
2670   * @name Modernizr.testProp
2671   * @access public
2672   * @optionName Modernizr.testProp()
2673   * @optionProp testProp
2674   * @function testProp
2675   * @param {string} prop - Name of the CSS property to check
2676   * @param {string} [value] - Name of the CSS value to check
2677   * @param {boolean} [useValue] - Whether or not to check the value if @supports isn't supported
2678   * @returns {boolean}
2679   * @example
2680   *
2681   * Just like [testAllProps](#modernizr-testallprops), only it does not check any vendor prefixed
2682   * version of the string.
2683   *
2684   * Note that the property name must be provided in camelCase (e.g. boxSizing not box-sizing)
2685   *
2686   * ```js
2687   * Modernizr.testProp('pointerEvents')  // true
2688   * ```
2689   *
2690   * You can also provide a value as an optional second argument to check if a
2691   * specific value is supported
2692   *
2693   * ```js
2694   * Modernizr.testProp('pointerEvents', 'none') // true
2695   * Modernizr.testProp('pointerEvents', 'penguin') // false
2696   * ```
2697   */
2698
2699  var testProp = ModernizrProto.testProp = function(prop, value, useValue) {
2700    return testProps([prop], undefined, value, useValue);
2701  };
2702  
2703/*!
2704{
2705  "name": "CSS textshadow",
2706  "property": "textshadow",
2707  "caniuse": "css-textshadow",
2708  "tags": ["css"],
2709  "knownBugs": ["FF3.0 will false positive on this test"]
2710}
2711!*/
2712
2713  Modernizr.addTest('textshadow', testProp('textShadow', '1px 1px'));
2714
2715
2716  /**
2717   * testPropsAll tests a list of DOM properties we want to check against.
2718   * We specify literally ALL possible (known and/or likely) properties on
2719   * the element including the non-vendor prefixed one, for forward-
2720   * compatibility.
2721   */
2722  function testPropsAll(prop, prefixed, elem, value, skipValueTest) {
2723
2724    var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
2725    props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
2726
2727    // did they call .prefixed('boxSizing') or are we just testing a prop?
2728    if (is(prefixed, 'string') || is(prefixed, 'undefined')) {
2729      return testProps(props, prefixed, value, skipValueTest);
2730
2731      // otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
2732    } else {
2733      props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
2734      return testDOMProps(props, prefixed, elem);
2735    }
2736  }
2737
2738  // Modernizr.testAllProps() investigates whether a given style property,
2739  // or any of its vendor-prefixed variants, is recognized
2740  //
2741  // Note that the property names must be provided in the camelCase variant.
2742  // Modernizr.testAllProps('boxSizing')
2743  ModernizrProto.testAllProps = testPropsAll;
2744
2745  
2746
2747  /**
2748   * testAllProps determines whether a given CSS property is supported in the browser
2749   *
2750   * @memberof Modernizr
2751   * @name Modernizr.testAllProps
2752   * @optionName Modernizr.testAllProps()
2753   * @optionProp testAllProps
2754   * @access public
2755   * @function testAllProps
2756   * @param {string} prop - String naming the property to test (either camelCase or kebab-case)
2757   * @param {string} [value] - String of the value to test
2758   * @param {boolean} [skipValueTest=false] - Whether to skip testing that the value is supported when using non-native detection
2759   * @example
2760   *
2761   * testAllProps determines whether a given CSS property, in some prefixed form,
2762   * is supported by the browser.
2763   *
2764   * ```js
2765   * testAllProps('boxSizing')  // true
2766   * ```
2767   *
2768   * It can optionally be given a CSS value in string form to test if a property
2769   * value is valid
2770   *
2771   * ```js
2772   * testAllProps('display', 'block') // true
2773   * testAllProps('display', 'penguin') // false
2774   * ```
2775   *
2776   * A boolean can be passed as a third parameter to skip the value check when
2777   * native detection (@supports) isn't available.
2778   *
2779   * ```js
2780   * testAllProps('shapeOutside', 'content-box', true);
2781   * ```
2782   */
2783
2784  function testAllProps (prop, value, skipValueTest) {
2785    return testPropsAll(prop, undefined, undefined, value, skipValueTest);
2786  }
2787  ModernizrProto.testAllProps = testAllProps;
2788  
2789/*!
2790{
2791  "name": "CSS Animations",
2792  "property": "cssanimations",
2793  "caniuse": "css-animation",
2794  "polyfills": ["transformie", "csssandpaper"],
2795  "tags": ["css"],
2796  "warnings": ["Android < 4 will pass this test, but can only animate a single property at a time"],
2797  "notes": [{
2798    "name" : "Article: 'Dispelling the Android CSS animation myths'",
2799    "href": "http://goo.gl/OGw5Gm"
2800  }]
2801}
2802!*/
2803/* DOC
2804Detects whether or not elements can be animated using CSS
2805*/
2806
2807  Modernizr.addTest('cssanimations', testAllProps('animationName', 'a', true));
2808
2809/*!
2810{
2811  "name": "Background Size",
2812  "property": "backgroundsize",
2813  "tags": ["css"],
2814  "knownBugs": ["This will false positive in Opera Mini - http://github.com/Modernizr/Modernizr/issues/396"],
2815  "notes": [{
2816    "name": "Related Issue",
2817    "href": "http://github.com/Modernizr/Modernizr/issues/396"
2818  }]
2819}
2820!*/
2821
2822  Modernizr.addTest('backgroundsize', testAllProps('backgroundSize', '100%', true));
2823
2824/*!
2825{
2826  "name": "Background Size Cover",
2827  "property": "bgsizecover",
2828  "tags": ["css"],
2829  "builderAliases": ["css_backgroundsizecover"],
2830  "notes": [{
2831    "name" : "MDN Docs",
2832    "href": "http://developer.mozilla.org/en/CSS/background-size"
2833  }]
2834}
2835!*/
2836
2837  // Must test value, as this specifically tests the `cover` value
2838  Modernizr.addTest('bgsizecover', testAllProps('backgroundSize', 'cover'));
2839
2840/*!
2841{
2842  "name": "Border Image",
2843  "property": "borderimage",
2844  "caniuse": "border-image",
2845  "polyfills": ["css3pie"],
2846   "knownBugs": ["Android < 2.0 is true, but has a broken implementation"],
2847  "tags": ["css"]
2848}
2849!*/
2850
2851  Modernizr.addTest('borderimage', testAllProps('borderImage', 'url() 1', true));
2852
2853/*!
2854{
2855  "name": "Border Radius",
2856  "property": "borderradius",
2857  "caniuse": "border-radius",
2858  "polyfills": ["css3pie"],
2859  "tags": ["css"],
2860  "notes": [{
2861    "name": "Comprehensive Compat Chart",
2862    "href": "http://muddledramblings.com/table-of-css3-border-radius-compliance"
2863  }]
2864}
2865!*/
2866
2867  Modernizr.addTest('borderradius', testAllProps('borderRadius', '0px', true));
2868
2869/*!
2870{
2871  "name": "Box Shadow",
2872  "property": "boxshadow",
2873  "caniuse": "css-boxshadow",
2874  "tags": ["css"],
2875  "knownBugs": [
2876    "WebOS false positives on this test.",
2877    "The Kindle Silk browser false positives"
2878  ]
2879}
2880!*/
2881
2882  Modernizr.addTest('boxshadow', testAllProps('boxShadow', '1px 1px', true));
2883
2884/*!
2885{
2886  "name": "CSS Columns",
2887  "property": "csscolumns",
2888  "caniuse": "multicolumn",
2889  "polyfills": ["css3multicolumnjs"],
2890  "tags": ["css"]
2891}
2892!*/
2893
2894
2895  (function() {
2896
2897    /* jshint -W053 */
2898    Modernizr.addTest('csscolumns', function() {
2899      var bool = false;
2900      var test = testAllProps('columnCount');
2901      try {
2902        if (bool = !!test) {
2903          bool = new Boolean(bool);
2904        }
2905      } catch (e) {}
2906
2907      return bool;
2908    });
2909
2910    var props = ['Width', 'Span', 'Fill', 'Gap', 'Rule', 'RuleColor', 'RuleStyle', 'RuleWidth', 'BreakBefore', 'BreakAfter', 'BreakInside'];
2911    var name, test;
2912
2913    for (var i = 0; i < props.length; i++) {
2914      name = props[i].toLowerCase();
2915      test = testAllProps('column' + props[i]);
2916
2917      // break-before, break-after & break-inside are not "column"-prefixed in spec
2918      if (name === 'breakbefore' || name === 'breakafter' || name == 'breakinside') {
2919        test = test || testAllProps(props[i]);
2920      }
2921
2922      Modernizr.addTest('csscolumns.' + name, test);
2923    }
2924
2925
2926  })();
2927
2928
2929/*!
2930{
2931  "name": "Flexbox",
2932  "property": "flexbox",
2933  "caniuse": "flexbox",
2934  "tags": ["css"],
2935  "notes": [{
2936    "name": "The _new_ flexbox",
2937    "href": "http://dev.w3.org/csswg/css3-flexbox"
2938  }],
2939  "warnings": [
2940    "A `true` result for this detect does not imply that the `flex-wrap` property is supported; see the `flexwrap` detect."
2941  ]
2942}
2943!*/
2944/* DOC
2945Detects support for the Flexible Box Layout model, a.k.a. Flexbox, which allows easy manipulation of layout order and sizing within a container.
2946*/
2947
2948  Modernizr.addTest('flexbox', testAllProps('flexBasis', '1px', true));
2949
2950/*!
2951{
2952  "name": "CSS Reflections",
2953  "caniuse": "css-reflections",
2954  "property": "cssreflections",
2955  "tags": ["css"]
2956}
2957!*/
2958
2959  Modernizr.addTest('cssreflections', testAllProps('boxReflect', 'above', true));
2960
2961/*!
2962{
2963  "name": "CSS Transforms",
2964  "property": "csstransforms",
2965  "caniuse": "transforms2d",
2966  "tags": ["css"]
2967}
2968!*/
2969
2970  Modernizr.addTest('csstransforms', function() {
2971    // Android < 3.0 is buggy, so we sniff and blacklist
2972    // http://git.io/hHzL7w
2973    return navigator.userAgent.indexOf('Android 2.') === -1 &&
2974           testAllProps('transform', 'scale(1)', true);
2975  });
2976
2977/*!
2978{
2979  "name": "CSS Transforms 3D",
2980  "property": "csstransforms3d",
2981  "caniuse": "transforms3d",
2982  "tags": ["css"],
2983  "warnings": [
2984    "Chrome may occassionally fail this test on some systems; more info: https://code.google.com/p/chromium/issues/detail?id=129004"
2985  ]
2986}
2987!*/
2988
2989  Modernizr.addTest('csstransforms3d', function() {
2990    var ret = !!testAllProps('perspective', '1px', true);
2991    var usePrefix = Modernizr._config.usePrefixes;
2992
2993    // Webkit's 3D transforms are passed off to the browser's own graphics renderer.
2994    //   It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in
2995    //   some conditions. As a result, Webkit typically recognizes the syntax but
2996    //   will sometimes throw a false positive, thus we must do a more thorough check:
2997    if (ret && (!usePrefix || 'webkitPerspective' in docElement.style)) {
2998      var mq;
2999      var defaultStyle = '#modernizr{width:0;height:0}';
3000      // Use CSS Conditional Rules if available
3001      if (Modernizr.supports) {
3002        mq = '@supports (perspective: 1px)';
3003      } else {
3004        // Otherwise, Webkit allows this media query to succeed only if the feature is enabled.
3005        // `@media (transform-3d),(-webkit-transform-3d){ ... }`
3006        mq = '@media (transform-3d)';
3007        if (usePrefix) {
3008          mq += ',(-webkit-transform-3d)';
3009        }
3010      }
3011
3012      mq += '{#modernizr{width:7px;height:18px;margin:0;padding:0;border:0}}';
3013
3014      testStyles(defaultStyle + mq, function(elem) {
3015        ret = elem.offsetWidth === 7 && elem.offsetHeight === 18;
3016      });
3017    }
3018
3019    return ret;
3020  });
3021
3022/*!
3023{
3024  "name": "CSS Transform Style preserve-3d",
3025  "property": "preserve3d",
3026  "authors": ["edmellum"],
3027  "tags": ["css"],
3028  "notes": [{
3029    "name": "MDN Docs",
3030    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/transform-style"
3031  },{
3032    "name": "Related Github Issue",
3033    "href": "https://github.com/Modernizr/Modernizr/issues/762"
3034  }]
3035}
3036!*/
3037/* DOC
3038Detects support for `transform-style: preserve-3d`, for getting a proper 3D perspective on elements.
3039*/
3040
3041  Modernizr.addTest('preserve3d', testAllProps('transformStyle', 'preserve-3d'));
3042
3043/*!
3044{
3045  "name": "CSS Transitions",
3046  "property": "csstransitions",
3047  "caniuse": "css-transitions",
3048  "tags": ["css"]
3049}
3050!*/
3051
3052  Modernizr.addTest('csstransitions', testAllProps('transition', 'all', true));
3053
3054
3055  /**
3056   * prefixed returns the prefixed or nonprefixed property name variant of your input
3057   *
3058   * @memberof Modernizr
3059   * @name Modernizr.prefixed
3060   * @optionName Modernizr.prefixed()
3061   * @optionProp prefixed
3062   * @access public
3063   * @function prefixed
3064   * @param {string} prop - String name of the property to test for
3065   * @param {object} [obj]- An object to test for the prefixed properties on
3066   * @returns {string|false} The string representing the (possibly prefixed) valid
3067   * version of the property, or `false` when it is unsupported.
3068   * @example
3069   *
3070   * Modernizr.prefixed takes a string css value in the DOM style camel
3070Case (as
3071   * opposed to the css style kebab-case) form and returns the (possibly prefixed)
3072   * version of that property that the browser actually supports.
3073   *
3074   * For example, in older Firefox...
3075   * ```js
3076   * prefixed('boxSizing')
3077   * ```
3078   * returns 'MozBoxSizing'
3079   *
3080   * In newer Firefox, as well as any other browser that support the unprefixed
3081   * version would simply return `boxSizing`. Any browser that does not support
3082   * the property at all, it will return `false`.
3083   *
3084   * By default, prefixed is checked against a DOM element. If you want to check
3085   * for a property on another object, just pass it as a second argument
3086   *
3087   * ```js
3088   * var rAF = prefixed('requestAnimationFrame', window);
3089   *
3090   * raf(function() {
3091   *  renderFunction();
3092   * })
3093   * ```
3094   *
3095   * Note that this will return _the actual function_ - not the name of the function.
3096   * If you need the actual name of the property, pass in `false` as a third argument
3097   *
3098   * ```js
3099   * var rAFProp = prefixed('requestAnimationFrame', window, false);
3100   *
3101   * rafProp === 'WebkitRequestAnimationFrame' // in older webkit
3102   * ```
3103   *
3104   * One common use case for prefixed is if you're trying to determine which transition
3105   * end event to bind to, you might do something like...
3106   * ```js
3107   * var transEndEventNames = {
3108   *     'WebkitTransition' : 'webkitTransitionEnd', * Saf 6, Android Browser
3109   *     'MozTransition'    : 'transitionend',       * only for FF < 15
3110   *     'transition'       : 'transitionend'        * IE10, Opera, Chrome, FF 15+, Saf 7+
3111   * };
3112   *
3113   * var transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
3114   * ```
3115   *
3116   * If you want a similar lookup, but in kebab-case, you can use [prefixedCSS](#modernizr-prefixedcss).
3117   */
3118
3119  var prefixed = ModernizrProto.prefixed = function(prop, obj, elem) {
3120    if (prop.indexOf('@') === 0) {
3121      return atRule(prop);
3122    }
3123
3124    if (prop.indexOf('-') != -1) {
3125      // Convert kebab-case to camelCase
3126      prop = cssToDOM(prop);
3127    }
3128    if (!obj) {
3129      return testPropsAll(prop, 'pfx');
3130    } else {
3131      // Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame'
3132      return testPropsAll(prop, obj, elem);
3133    }
3134  };
3135
3136  
3137/*!
3138{
3139  "name": "IndexedDB",
3140  "property": "indexeddb",
3141  "caniuse": "indexeddb",
3142  "tags": ["storage"],
3143  "polyfills": ["indexeddb"]
3144}
3145!*/
3146/* DOC
3147Detects support for the IndexedDB client-side storage API (final spec).
3148*/
3149
3150  // Vendors had inconsistent prefixing with the experimental Indexed DB:
3151  // - Webkit's implementation is accessible through webkitIndexedDB
3152  // - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB
3153  // For speed, we don't test the legacy (and beta-only) indexedDB
3154
3155  var indexeddb = prefixed('indexedDB', window);
3156  Modernizr.addTest('indexeddb', !!indexeddb);
3157
3158  if (!!indexeddb) {
3159    Modernizr.addTest('indexeddb.deletedatabase', 'deleteDatabase' in indexeddb);
3160  }
3161;
3162/*!
3163{
3164  "name": "requestAnimationFrame",
3165  "property": "requestanimationframe",
3166  "aliases": ["raf"],
3167  "caniuse": "requestanimationframe",
3168  "tags": ["animation"],
3169  "authors": ["Addy Osmani"],
3170  "notes": [{
3171    "name": "W3C spec",
3172    "href": "http://www.w3.org/TR/animation-timing/"
3173  }],
3174  "polyfills": ["raf"]
3175}
3176!*/
3177/* DOC
3178Detects support for the `window.requestAnimationFrame` API, for offloading animation repainting to the browser for optimized performance.
3179*/
3180
3181  Modernizr.addTest('requestanimationframe', !!prefixed('requestAnimationFrame', window), {aliases: ['raf']});
3182
3183
3184  // Run each test
3185  testRunner();
3186
3187  // Remove the "no-js" class if it exists
3188  setClasses(classes);
3189
3190  delete ModernizrProto.addTest;
3191  delete ModernizrProto.addAsyncTest;
3192
3193  // Run the things that are supposed to run after the tests
3194  for (var i = 0; i < Modernizr._q.length; i++) {
3195    Modernizr._q[i]();
3196  }
3197
3198  // Leak Modernizr namespace
3199  window.Modernizr = Modernizr;
3200
3201
3202;
3203
3204})(window, document);

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.