PageSourceSearch

https://kentmorris.com.au/wp-content/themes/eames/assets/js/third-…?id=5a8252e08adacae64f25

js kentmorris.com.au collected 2026-10-04 23:05:45 UTC 72,878 bytes, 2,287 lines download raw bytes

1/*!
2 * modernizr v3.6.0
3 * Build https://modernizr.com/download?-cssanimations-csscalc-csspositionsticky-cssremunit-csstransforms-csstransforms3d-csstransitions-flexbox-fontface-hidden-hsla-mediaqueries-objectfit-sizes-srcset-svg-touchevents-addtest-domprefixes-hasevent-mq-prefixed-prefixes-setclasses-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  var tests = [];
30
31
32  /**
33   *
34   * ModernizrProto is the constructor for Modernizr
35   *
36   * @class
37   * @access public
38   */
39
40  var ModernizrProto = {
41    // The current version, dummy
42    _version: '3.6.0',
43
44    // Any settings that don't work as separate modules
45    // can go in here as configuration.
46    _config: {
47      'classPrefix': '',
48      'enableClasses': true,
49      'enableJSClass': true,
50      'usePrefixes': true
51    },
52
53    // Queue of tests
54    _q: [],
55
56    // Stub these for people who are listening
57    on: function(test, cb) {
58      // I don't really think people should do this, but we can
59      // safe guard it a bit.
60      // -- NOTE:: this gets WAY overridden in src/addTest for actual async tests.
61      // This is in case people listen to synchronous tests. I would leave it out,
62      // but the code to *disallow* sync tests in the real version of this
63      // function is actually larger than this.
64      var self = this;
65      setTimeout(function() {
66        cb(self[test]);
67      }, 0);
68    },
69
70    addTest: function(name, fn, options) {
71      tests.push({name: name, fn: fn, options: options});
72    },
73
74    addAsyncTest: function(fn) {
75      tests.push({name: null, fn: fn});
76    }
77  };
78
79
80
81  // Fake some of Object.create so we can force non test results to be non "own" properties.
82  var Modernizr = function() {};
83  Modernizr.prototype = ModernizrProto;
84
85  // Leak modernizr globally when you `require` it rather than force it here.
86  // Overwrite name so constructor name is nicer :D
87  Modernizr = new Modernizr();
88
89
90/*!
91{
92  "name": "SVG",
93  "property": "svg",
94  "caniuse": "svg",
95  "tags": ["svg"],
96  "authors": ["Erik Dahlstrom"],
97  "polyfills": [
98    "svgweb",
99    "raphael",
100    "amplesdk",
101    "canvg",
102    "svg-boilerplate",
103    "sie",
104    "dojogfx",
105    "fabricjs"
106  ]
107}
108!*/
109/* DOC
110Detects support for SVG in `<embed>` or `<object>` elements.
111*/
112
113  Modernizr.addTest('svg', !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect);
114
115
116  /**
117   * List of property values to set for css tests. See ticket #21
118   * http://git.io/vUGl4
119   *
120   * @memberof Modernizr
121   * @name Modernizr._prefixes
122   * @optionName Modernizr._prefixes
123   * @optionProp prefixes
124   * @access public
125   * @example
126   *
127   * Modernizr._prefixes is the internal list of prefixes that we test against
128   * inside of things like [prefixed](#modernizr-prefixed) and [prefixedCSS](#-code-modernizr-prefixedcss). It is simply
129   * an array of kebab-case vendor prefixes you can use within your code.
130   *
131   * Some common use cases include
132   *
133   * Generating all possible prefixed version of a CSS property
134   * ```js
135   * var rule = Modernizr._prefixes.join('transform: rotate(20deg); ');
136   *
137   * rule === 'transform: rotate(20deg); webkit-transform: rotate(20deg); moz-transform: rotate(20deg); o-transform: rotate(20deg); ms-transform: rotate(20deg);'
138   * ```
139   *
140   * Generating all possible prefixed version of a CSS value
141   * ```js
142   * rule = 'display:' +  Modernizr._prefixes.join('flex; display:') + 'flex';
143   *
144   * rule === 'display:flex; display:-webkit-flex; display:-moz-flex; display:-o-flex; display:-ms-flex; display:flex'
145   * ```
146   */
147
148  // we use ['',''] rather than an empty array in order to allow a pattern of .`join()`ing prefixes to test
149  // values in feature detects to continue to work
150  var prefixes = (ModernizrProto._config.usePrefixes ? ' -webkit- -moz- -o- -ms- '.split(' ') : ['','']);
151
152  // expose these for the plugin API. Look in the source for how to join() them against your input
153  ModernizrProto._prefixes = prefixes;
154
155
156
157  /**
158   * is returns a boolean if the typeof an obj is exactly type.
159   *
160   * @access private
161   * @function is
162   * @param {*} obj - A thing we want to check the type of
163   * @param {string} type - A string to compare the typeof against
164   * @returns {boolean}
165   */
166
167  function is(obj, type) {
168    return typeof obj === type;
169  }
170  ;
171
172  /**
173   * Run through all tests and detect their support in the current UA.
174   *
175   * @access private
176   */
177
178  function testRunner() {
179    var featureNames;
180    var feature;
181    var aliasIdx;
182    var result;
183    var nameIdx;
184    var featureName;
185    var featureNameSplit;
186
187    for (var featureIdx in tests) {
188      if (tests.hasOwnProperty(featureIdx)) {
189        featureNames = [];
190        feature = tests[featureIdx];
191        // run the test, throw the return value into the Modernizr,
192        // then based on that boolean, define an appropriate className
193        // and push it into an array of classes we'll join later.
194        //
195        // If there is no name, it's an 'async' test that is run,
196        // but not directly added to the object. That should
197        // be done with a post-run addTest call.
198        if (feature.name) {
199          featureNames.push(feature.name.toLowerCase());
200
201          if (feature.options && feature.options.aliases && feature.options.aliases.length) {
202            // Add all the aliases into the names list
203            for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) {
204              featureNames.push(feature.options.aliases[aliasIdx].toLowerCase());
205            }
206          }
207        }
208
209        // Run the test, or use the raw value if it's not a function
210        result = is(feature.fn, 'function') ? feature.fn() : feature.fn;
211
212
213        // Set each of the names on the Modernizr object
214        for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) {
215          featureName = featureNames[nameIdx];
216          // Support dot properties as sub tests. We don't do checking to make sure
217          // that the implied parent tests have been added. You must call them in
218          // order (either in the test, or make the parent test a dependency).
219          //
220          // Cap it to TWO to make the logic simple and because who needs that kind of subtesting
221          // hashtag famous last words
222          featureNameSplit = featureName.split('.');
223
224          if (featureNameSplit.length === 1) {
225            Modernizr[featureNameSplit[0]] = result;
226          } else {
227            // cast to a Boolean, if not one already
228            if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
229              Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
230            }
231
232            Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result;
233          }
234
235          classes.push((result ? '' : 'no-') + featureNameSplit.join('-'));
236        }
237      }
238    }
239  }
240  ;
241
242  /**
243   * docElement is a convenience wrapper to grab the root element of the document
244   *
245   * @access private
246   * @returns {HTMLElement|SVGElement} The root element of the document
247   */
248
249  var docElement = document.documentElement;
250
251
252  /**
253   * A convenience helper to check if the document we are running in is an SVG document
254   *
255   * @access private
256   * @returns {boolean}
257   */
258
259  var isSVG = docElement.nodeName.toLowerCase() === 'svg';
260
261
262  /**
263   * setClasses takes an array of class names and adds them to the root element
264   *
265   * @access private
266   * @function setClasses
267   * @param {string[]} classes - Array of class names
268   */
269
270  // Pass in an and array of class names, e.g.:
271  //  ['no-webp', 'borderradius', ...]
272  function setClasses(classes) {
273    var className = docElement.className;
274    var classPrefix = Modernizr._config.classPrefix || '';
275
276    if (isSVG) {
277      className = className.baseVal;
278    }
279
280    // Change `no-js` to `js` (independently of the `enableClasses` option)
281    // Handle classPrefix on this too
282    if (Modernizr._config.enableJSClass) {
283      var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)');
284      className = className.replace(reJS, '$1' + classPrefix + 'js$2');
285    }
286
287    if (Modernizr._config.enableClasses) {
288      // Add the new classes
289      className += ' ' + classPrefix + classes.join(' ' + classPrefix);
290      if (isSVG) {
291        docElement.className.baseVal = className;
292      } else {
293        docElement.className = className;
294      }
295    }
296
297  }
298
299  ;
300
301/**
302  * @optionName html5shiv
303  * @optionProp html5shiv
304  */
305
306  // Take the html5 variable out of the html5shiv scope so we can return it.
307  var html5;
308  if (!isSVG) {
309    /**
310     * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
311     */
312    ;(function(window, document) {
313      /** version */
314      var version = '3.7.3';
315
316      /** Preset options */
317      var options = window.html5 || {};
318
319      /** Used to skip problem elements */
320      var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
321
322      /** Not all elements can be cloned in IE **/
323      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;
324
325      /** Detect whether the browser supports default html5 styles */
326      var supportsHtml5Styles;
327
328      /** Name of the expando, to work with multiple documents or to re-shiv one document */
329      var expando = '_html5shiv';
330
331      /** The id for the the documents expando */
332      var expanID = 0;
333
334      /** Cached data for each document */
335      var expandoData = {};
336
337      /** Detect whether the browser supports unknown elements */
338      var supportsUnknownElements;
339
340      (function() {
341        try {
342          var a = document.createElement('a');
343          a.innerHTML = '<xyz></xyz>';
344          //if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles
345          supportsHtml5Styles = ('hidden' in a);
346
347          supportsUnknownElements = a.childNodes.length == 1 || (function() {
348            // assign a false positive if unable to shiv
349            (document.createElement)('a');
350            var frag = document.createDocumentFragment();
351            return (
352              typeof frag.cloneNode == 'undefined' ||
353                typeof frag.createDocumentFragment == 'undefined' ||
354                typeof frag.createElement == 'undefined'
355            );
356          }());
357        } catch(e) {
358          // assign a false positive if detection fails => unable to shiv
359          supportsHtml5Styles = true;
360          supportsUnknownElements = true;
361        }
362
363      }());
364
365      /*--------------------------------------------------------------------------*/
366
367      /**
368       * Creates a style sheet with the given CSS text and adds it to the document.
369       * @private
370       * @param {Document} ownerDocument The document.
371       * @param {String} cssText The CSS text.
372       * @returns {StyleSheet} The style element.
373       */
374      function addStyleSheet(ownerDocument, cssText) {
375        var p = ownerDocument.createElement('p'),
376          parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
377
378        p.innerHTML = 'x<style>' + cssText + '</style>';
379        return parent.insertBefore(p.lastChild, parent.firstChild);
380      }
381
382      /**
383       * Returns the value of `html5.elements` as an array.
384       * @private
385       * @returns {Array} An array of shived element node names.
386       */
387      function getElements() {
388        var elements = html5.elements;
389        return typeof elements == 'string' ? elements.split(' ') : elements;
390      }
391
392      /**
393       * Extends the built-in list of html5 elements
394       * @memberOf html5
395       * @param {String|Array} newElements whitespace separated list or array of new element names to shiv
396       * @param {Document} ownerDocument The context document.
397       */
398      function addElements(newElements, ownerDocument) {
399        var elements = html5.elements;
400        if(typeof elements != 'string'){
401          elements = elements.join(' ');
402        }
403        if(typeof newElements != 'string'){
404          newElements = newElements.join(' ');
405        }
406        html5.elements = elements +' '+ newElements;
407        shivDocument(ownerDocument);
408      }
409
410      /**
411       * Returns the data associated to the given document
412       * @private
413       * @param {Document} ownerDocument The document.
414       * @returns {Object} An object of data.
415       */
416      function getExpandoData(ownerDocument) {
417        var data = expandoData[ownerDocument[expando]];
418        if (!data) {
419          data = {};
420          expanID++;
421          ownerDocument[expando] = expanID;
422          expandoData[expanID] = data;
423        }
424        return data;
425      }
426
427      /**
428       * returns a shived element for the given nodeName and document
429       * @memberOf html5
430       * @param {String}
vendor: 4,610 bytes, lines 430-541
430 nodeName name of the element
431       * @param {Document|DocumentFragment} ownerDocument The context document.
432       * @returns {Object} The shived element.
433       */
434      function createElement(nodeName, ownerDocument, data){
435        if (!ownerDocument) {
436          ownerDocument = document;
437        }
438        if(supportsUnknownElements){
439          return ownerDocument.createElement(nodeName);
440        }
441        if (!data) {
442          data = getExpandoData(ownerDocument);
443        }
444        var node;
445
446        if (data.cache[nodeName]) {
447          node = data.cache[nodeName].cloneNode();
448        } else if (saveClones.test(nodeName)) {
449          node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
450        } else {
451          node = data.createElem(nodeName);
452        }
453
454        // Avoid adding some elements to fragments in IE < 9 because
455        // * Attributes like `name` or `type` cannot be set/changed once an element
456        //   is inserted into a document/fragment
457        // * Link elements with `src` attributes that are inaccessible, as with
458        //   a 403 response, will cause the tab/window to crash
459        // * Script elements appended to fragments will execute when their `src`
460        //   or `text` property is set
461        return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node;
462      }
463
464      /**
465       * returns a shived DocumentFragment for the given document
466       * @memberOf html5
467       * @param {Document} ownerDocument The context document.
468       * @returns {Object} The shived DocumentFragment.
469       */
470      function createDocumentFragment(ownerDocument, data){
471        if (!ownerDocument) {
472          ownerDocument = document;
473        }
474        if(supportsUnknownElements){
475          return ownerDocument.createDocumentFragment();
476        }
477        data = data || getExpandoData(ownerDocument);
478        var clone = data.frag.cloneNode(),
479          i = 0,
480          elems = getElements(),
481          l = elems.length;
482        for(;i<l;i++){
483          clone.createElement(elems[i]);
484        }
485        return clone;
486      }
487
488      /**
489       * Shivs the `createElement` and `createDocumentFragment` methods of the document.
490       * @private
491       * @param {Document|DocumentFragment} ownerDocument The document.
492       * @param {Object} data of the document.
493       */
494      function shivMethods(ownerDocument, data) {
495        if (!data.cache) {
496          data.cache = {};
497          data.createElem = ownerDocument.createElement;
498          data.createFrag = ownerDocument.createDocumentFragment;
499          data.frag = data.createFrag();
500        }
501
502
503        ownerDocument.createElement = function(nodeName) {
504          //abort shiv
505          if (!html5.shivMethods) {
506            return data.createElem(nodeName);
507          }
508          return createElement(nodeName, ownerDocument, data);
509        };
510
511        ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
512                                                        'var n=f.cloneNode(),c=n.createElement;' +
513                                                        'h.shivMethods&&(' +
514                                                        // unroll the `createElement` calls
515                                                        getElements().join().replace(/[\w\-:]+/g, function(nodeName) {
516                                                          data.createElem(nodeName);
517                                                          data.frag.createElement(nodeName);
518                                                          return 'c("' + nodeName + '")';
519                                                        }) +
520          ');return n}'
521                                                       )(html5, data.frag);
522      }
523
524      /*--------------------------------------------------------------------------*/
525
526      /**
527       * Shivs the given document.
528       * @memberOf html5
529       * @param {Document} ownerDocument The document to shiv.
530       * @returns {Document} The shived document.
531       */
532      function shivDocument(ownerDocument) {
533        if (!ownerDocument) {
534          ownerDocument = document;
535        }
536        var data = getExpandoData(ownerDocument);
537
538        if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) {
539          data.hasCSS = !!addStyleSheet(ownerDocument,
540                                        // corrects block display not defined in IE6/7/8/9
541                                        'article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{dis
541play:block}' +
542                                        // adds styling not present in IE6/7/8/9
543                                        'mark{background:#FF0;color:#000}' +
544                                        // hides non-rendered elements
545                                        'template{display:none}'
546                                       );
547        }
548        if (!supportsUnknownElements) {
549          shivMethods(ownerDocument, data);
550        }
551        return ownerDocument;
552      }
553
554      /*--------------------------------------------------------------------------*/
555
556      /**
557       * The `html5` object is exposed so that more elements can be shived and
558       * existing shiving can be detected on iframes.
559       * @type Object
560       * @example
561       *
562       * // options can be changed before the script is included
563       * html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false };
564       */
565      var html5 = {
566
567        /**
568         * An array or space separated string of node names of the elements to shiv.
569         * @memberOf html5
570         * @type Array|String
571         */
572        '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',
573
574        /**
575         * current version of html5shiv
576         */
577        'version': version,
578
579        /**
580         * A flag to indicate that the HTML5 style sheet should be inserted.
581         * @memberOf html5
582         * @type Boolean
583         */
584        'shivCSS': (options.shivCSS !== false),
585
586        /**
587         * Is equal to true if a browser supports creating unknown/HTML5 elements
588         * @memberOf html5
589         * @type boolean
590         */
591        'supportsUnknownElements': supportsUnknownElements,
592
593        /**
594         * A flag to indicate that the document's `createElement` and `createDocumentFragment`
595         * methods should be overwritten.
596         * @memberOf html5
597         * @type Boolean
598         */
599        'shivMethods': (options.shivMethods !== false),
600
601        /**
602         * A string to describe the type of `html5` object ("default" or "default print").
603         * @memberOf html5
604         * @type String
605         */
606        'type': 'default',
607
608        // shivs the document according to the specified `html5` object options
609        'shivDocument': shivDocument,
610
611        //creates a shived element
612        createElement: createElement,
613
614        //creates a shived documentFragment
615        createDocumentFragment: createDocumentFragment,
616
617        //extends list of elements
618        addElements: addElements
619      };
620
621      /*--------------------------------------------------------------------------*/
622
623      // expose html5
624      window.html5 = html5;
625
626      // shiv the document
627      shivDocument(document);
628
629      if(typeof module == 'object' && module.exports){
630        module.exports = html5;
631      }
632
633    }(typeof window !== 'undefined' ? window : this, document));
634  }
635  ;
636
637  /**
638   * If the browsers follow the spec, then they would expose vendor-specific styles as:
639   *   elem.style.WebkitBorderRadius
640   * instead of something like the following (which is technically incorrect):
641   *   elem.style.webkitBorderRadius
642
643   * WebKit ghosts their properties in lowercase but Opera & Moz do not.
644   * Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
645   *   erik.eae.net/archives/2008/03/10/21.48.10/
646
647   * More here: github.com/Modernizr/Modernizr/issues/issue/21
648   *
649   * @access private
650   * @returns {string} The string representing the vendor-specific style properties
651   */
652
653  var omPrefixes = 'Moz O ms Webkit';
654
655
656  /**
657   * List of JavaScript DOM values used for tests
658   *
659   * @memberof Modernizr
660   * @name Modernizr._domPrefixes
661   * @optionName Modernizr._domPrefixes
662   * @optionProp domPrefixes
663   * @access public
664   * @example
665   *
666   * Modernizr._domPrefixes is exactly the same as [_prefixes](#modernizr-_prefixes), but rather
667   * than kebab-case properties, all properties are their Capitalized variant
668   *
669   * ```js
670   * Modernizr._domPrefixes === [ "Moz", "O", "ms", "Webkit" ];
671   * ```
672   */
673
674  var domPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.toLowerCase().split(' ') : []);
675  ModernizrProto._domPrefixes = domPrefixes;
676
677
678  /**
679   * hasOwnProp is a shim for hasOwnProperty that is needed for Safari 2.0 support
680   *
681   * @author kangax
682   * @access private
683   * @function hasOwnProp
684   * @param {object} object - The object to check for a property
685   * @param {string} property - The property to check for
686   * @returns {boolean}
687   */
688
689  // hasOwnProperty shim by kangax needed for Safari 2.0 support
690  var hasOwnProp;
691
692  (function() {
693    var _hasOwnProperty = ({}).hasOwnProperty;
694    /* istanbul ignore else */
695    /* we have no way of testing IE 5.5 or safari 2,
696     * so just assume the else gets hit */
697    if (!is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined')) {
698      hasOwnProp = function(object, property) {
699        return _hasOwnProperty.call(object, property);
700      };
701    }
702    else {
703      hasOwnProp = function(object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
704        return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
705      };
706    }
707  })();
708
709
710
711
712   // _l tracks listeners for async tests, as well as tests that execute after the initial run
713  ModernizrProto._l = {};
714
715  /**
716   * Modernizr.on is a way to listen for the completion of async tests. Being
717   * asynchronous, they may not finish before your scripts run. As a result you
718   * will get a possibly false negative `undefined` value.
719   *
720   * @memberof Modernizr
721   * @name Modernizr.on
722   * @access public
723   * @function on
724   * @param {string} feature - String name of the feature detect
725   * @param {function} cb - Callback function returning a Boolean - true if feature is supported, false if not
726   * @example
727   *
728   * ```js
729   * Modernizr.on('flash', function( result ) {
730   *   if (result) {
731   *    // the browser has flash
732   *   } else {
733   *     // the browser does not have flash
734   *   }
735   * });
736   * ```
737   */
738
739  ModernizrProto.on = function(feature, cb) {
740    // Create the list of listeners if it doesn't exist
741    if (!this._l[feature]) {
742      this._l[feature] = [];
743    }
744
745    // Push this test on to the listener list
746    this._l[feature].push(cb);
747
748    // If it's already been resolved, trigger it on next tick
749    if (Modernizr.hasOwnProperty(feature)) {
750      // Next Tick
751      setTimeout(function() {
752        Modernizr._trigger(feature, Modernizr[feature]);
753      }, 0);
754    }
755  };
756
757  /**
758   * _trigger is the private function used to signal test completion and run any
759   * callbacks registered through [Modernizr.on](#modernizr-on)
760   *
761   * @memberof Modernizr
762   * @name Modernizr._trigger
763   * @access private
764   * @function _trigger
765   * @param {string} feature - string name of the feature detect
766   * @param {function|boolean} [res] - A feature detection function, or the boolean =
767   * result of a feature detection function
768   */
769
770  ModernizrProto._trigger = function(feature, res) {
771    if (!this._l[feature]) {
772      return;
773    }
774
775    var cbs = this._l[feature];
776
777    // Force async
778    setTimeout(function() {
779      var i, cb;
780      for (i = 0; i < cbs.length; i++) {
781        cb = cbs[i];
782        cb(res);
783      }
784    }, 0);
785
786    // Don't trigger these again
787    delete this._l[feature];
788  };
789
790  /**
791   * addTest allows you to define your own feature detects that are not currently
792   * included in Modernizr (under the covers it's the exact same code Modernizr
793   * uses for its own [feature detections](https://github.com/Modernizr/Modernizr/tree/master/feature-detects)). Just like the offical detects, the result
794   * will be added onto the Modernizr object, as well as an appropriate className set on
795   * the html element when configured to do so
796   *
797   * @memberof Modernizr
798   * @name Modernizr.addTest
799   * @optionName Modernizr.addTest()
800   * @optionProp addTest
801   * @access public
802   * @function addTest
803   * @param {string|object} feature - The string name of the feature detect, or an
804   * object of feature detect names and test
805   * @param {function|boolean} test - Function returning true if feature is supported,
806   * false if not. Otherwise a boolean representing the results of a feature detection
807   * @example
808   *
809   * The most common way of creating your own feature detects is by calling
810   * `Modernizr.addTest` with a string (preferably just lowercase, without any
811   * punctuation), and a function you want executed that will return a boolean result
812   *
813   * ```js
814   * Modernizr.addTest('itsTuesday', function() {
815   *  var d = new Date();
816   *  return d.getDay() === 2;
817   * });
818   * ```
819   *
820   * When the above is run, it will set Modernizr.itstuesday to `true` when it is tuesday,
821   * and to `false` every other day of the week. One thing to notice is that the names of
822   * feature detect functions are always lowercased when added to the Modernizr object. That
823   * means that `Modernizr.itsTuesday` will not exist, but `Modernizr.itstuesday` will.
824   *
825   *
826   *  Since we only look at the returned value from any feature detection function,
827   *  you do not need to actually use a function. For simple detections, just passing
828   *  in a statement that will return a boolean value works just fine.
829   *
830   * ```js
831   * Modernizr.addTest('hasJquery', 'jQuery' in window);
832   * ```
833   *
834   * Just like before, when the above runs `Modernizr.hasjquery` will be true if
835   * jQuery has been included on the page. Not using a function saves a small amount
836   * of overhead for the browser, as well as making your code much more readable.
837   *
838   * Finally, you also have the ability to pass in an object of feature names and
839   * their tests. This is handy if you want to add multiple detections in one go.
840   * The keys should always be a string, and the value can be either a boolean or
841   * function that returns a boolean.
842   *
843   * ```js
844   * var detects = {
845   *  'hasjquery': 'jQuery' in window,
846   *  'itstuesday': function() {
847   *    var d = new Date();
848   *    return d.getDay() === 2;
849   *  }
850   * }
851   *
852   * Modernizr.addTest(detects);
853   * ```
854   *
855   * There is really no difference between the first methods and this one, it is
856   * just a convenience to let you write more readable code.
857   */
858
859  function addTest(feature, test) {
860
861    if (typeof feature == 'object') {
862      for (var key in feature) {
863        if (hasOwnProp(feature, key)) {
864          addTest(key, feature[ key ]);
865        }
866      }
867    } else {
868
869      feature = feature.toLowerCase();
870      var featureNameSplit = feature.split('.');
871      var last = Modernizr[featureNameSplit[0]];
872
873      // Again, we don't check for parent test existence. Get that right, though.
874      if (featureNameSplit.length == 2) {
875        last = last[featureNameSplit[1]];
876      }
877
878      if (typeof last != 'undefined') {
879        // we're going to quit if you're trying to overwrite an existing test
880        // if we were to allow it, we'd do this:
881        //   var re = new RegExp("\\b(no-)?" + feature + "\\b");
882        //   docElement.className = docElement.className.replace( re, '' );
883        // but, no rly, stuff 'em.
884        return Modernizr;
885      }
886
887      test = typeof test == 'function' ? test() : test;
888
889      // Set the value (this is the magic, right here).
890      if (featureNameSplit.length == 1) {
891        Modernizr[featureNameSplit[0]] = test;
892      } else {
893        // cast to a Boolean, if not one already
894        if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
895          Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
896        }
897
898        Modernizr[featureNameSplit[0]][featureNameSplit[1]] = test;
899      }
900
901      // Set a single class (either `feature` or `no-feature`)
902      setClasses([(!!test && test != false ? '' : 'no-') + featureNameSplit.join('-')]);
903
904      // Trigger the event
905      Modernizr._trigger(feature, test);
906    }
907
908    return Modernizr; // allow chaining.
909  }
910
911  // After all the tests are run, add self to the Modernizr prototype
912  Modernizr._q.push(function() {
913    ModernizrProto.addTest = addTest;
914  });
915
916
917
918
919  /**
920   * cssToDOM takes a kebab-case string and converts it to camelCase
921   * e.g. box-sizing -> boxSizing
922   *
923   * @access private
924   * @function cssToDOM
925   * @param {string} name - String name of kebab-case prop we want to convert
926   * @returns {string} The camelCase version of the supplied name
927   */
928
929  function cssToDOM(name) {
930    return name.replace(/([a-z])-([a-z])/g, function(str, m1, m2) {
931      return m1 + m2.toUpperCase();
932    }).replace(/^-/, '');
933  }
934  ;
935
936  /**
937   * createElement is a convenience wrapper around document.createElement. Since we
938   * use createElement all over the place, this allows for (slightly) smaller code
939   * as well as abstracting away issues with creating elements in contexts other than
940   * HTML documents (e.g. SVG documents).
941   *
942   * @access private
943   * @function createElement
944   * @returns {HTMLElement|SVGElement} An HTML or SVG element
945   */
946
947  function createElement() {
948    if (typeof document.createElement !== 'function') {
949      // This is the case in IE7, where the type of createElement is "object".
950      // For this reason, we cannot call apply() as Object is not a Function.
951      return document.createElement(arguments[0]);
952    } else if (isSVG) {
953      return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]);
954    } else {
955      return document.createElement.apply(document, arguments);
956    }
957  }
958
959  ;
960
961  /**
962   * Modernizr.hasEvent() detects support for a given event
963   *
964   * @memberof Modernizr
965   * @name Modernizr.hasEvent
966   * @optionName Modernizr.hasEvent()
967   * @optionProp hasEvent
968   * @access public
969   * @function hasEvent
970   * @param  {string|*} eventName - the name of an event to test for (e.g. "resize")
971   * @param  {Element|string} [element=HTMLDivElement] - is the element|document|window|tagName to test on
972   * @returns {boolean}
973   * @example
974   *  `Modernizr.hasEvent` lets you determine if the browser supports a supplied event.
975   *  By default, it does this detection on a div element
976   *
977   * ```js
978   *  hasEvent('blur') // true;
979   * ```
980   *
981   * However, you are able to give an object as a second argument to hasEvent to
982   * detect an event on something other than a div.
983   *
984   * ```js
985   *  hasEvent('devicelight', window) // true;
986   * ```
987   *
988   */
989
990  var hasEvent = (function() {
991
992    // Detect whether event support can be detected via `in`. Test on a DOM element
993    // using the "blur" event b/c it should always exist. bit.ly/event-detection
994    var needsFallback = !('onblur' in document.documentElement);
995
996    function inner(eventName, element) {
997
998      var isSupported;
999      if (!eventName) { return false; }
1000      if (!element || typeof element === 'string') {
1001        element = createElement(element || 'div');
1002      }
1003
1004      // Testing via the `in` operator is sufficient for modern browsers and IE.
1005      // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and
1006      // "resize", whereas `in` "catches" those.
1007      eventName = 'on' + eventName;
1008      isSupported = eventName in element;
1009
1010      // Fallback technique for old Firefox - bit.ly/event-detection
1011      if (!isSupported && needsFallback) {
1012        if (!element.setAttribute) {
1013          // Switch to generic element if it lacks `setAttribute`.
1014          // It could be the `document`, `window`, or something else.
1015          element = createElement('div');
1016        }
1017
1018        element.setAttribute(eventName, '');
1019        isSupported = typeof element[eventName] === 'function';
1020
1021        if (element[eventName] !== undefined) {
1022          // If property was created, "remove it" by setting value to `undefined`.
1023          element[eventName] = undefined;
1024        }
1025        element.removeAttribute(eventName);
1026      }
1027
1028      return isSupported;
1029    }
1030    return inner;
1031  })();
1032
1033
1034  ModernizrProto.hasEvent = hasEvent;
1035
1036/*!
1037{
1038  "name": "CSS Calc",
1039  "property": "csscalc",
1040  "caniuse": "calc",
1041  "tags": ["css"],
1042  "builderAliases": ["css_calc"],
1043  "authors": ["@calvein"]
1044}
1045!*/
1046/* DOC
1047Method of allowing calculated values for length units. For example:
1048
1049```css
1050//lem {
1051  width: calc(100% - 3em);
1052}
1053```
1054*/
1055
1056  Modernizr.addTest('csscalc', function() {
1057    var prop = 'width:';
1058    var value = 'calc(10px);';
1059    var el = createElement('a');
1060
1061    el.style.cssText = prop + prefixes.join(value + prop);
1062
1063    return !!el.style.length;
1064  });
1065
1066/*!
1067{
1068  "name": "CSS position: sticky",
1069  "property": "csspositionsticky",
1070  "tags": ["css"],
1071  "builderAliases": ["css_positionsticky"],
1072  "notes": [{
1073    "name": "Chrome bug report",
1074    "href":"https://code.google.com/p/chromium/issues/detail?id=322972"
1075  }],
1076  "warnings": [ "using position:sticky on anything but top aligned elements is buggy in Chrome < 37 and iOS <=7+" ]
1077}
1078!*/
1079
1080  // Sticky positioning - constrains an element to be positioned inside the
1081  // intersection of its container box, and the viewport.
1082  Modernizr.addTest('csspositionsticky', function() {
1083    var prop = 'position:';
1084    var value = 'sticky';
1085    var el = createElement('a');
1086    var mStyle = el.style;
1087
1088    mStyle.cssText = prop + prefixes.join(value + ';' + prop).slice(0, -prop.length);
1089
1090    return mStyle.position.indexOf(value) !== -1;
1091  });
1092
1093/*!
1094{
1095  "name": "CSS Font rem Units",
1096  "caniuse": "rem",
1097  "authors": ["nsfmc"],
1098  "property": "cssremunit",
1099  "tags": ["css"],
1100  "builderAliases": ["css_remunit"],
1101  "notes": [{
1102    "name": "W3C Spec",
1103    "href": "https://www.w3.org/TR/css3-values/#relative0"
1104  },{
1105    "name": "Font Size with rem by Jonathan Snook",
1106    "href": "http://snook.ca/archives/html_and_css/font-size-with-rem"
1107  }]
1108}
1109!*/
1110
1111  // "The 'rem' unit ('root em') is relative to the computed
1112  // value of the 'font-size' value of the root element."
1113  // you can test by checking if the prop was ditched
1114
1115  Modernizr.addTest('cssremunit', function() {
1116    var style = createElement('a').style;
1117    try {
1118      style.fontSize = '3rem';
1119    }
1120    catch (e) {}
1121    return (/rem/).test(style.fontSize);
1122  });
1123
1124/*!
1125{
1126  "name": "sizes attribute",
1127  "async": true,
1128  "property": "sizes",
1129  "tags": ["image"],
1130  "authors": ["Mat Marquis"],
1131  "notes": [{
1132    "name": "Spec",
1133    "href": "http://picture.responsiveimages.org/#parse-sizes-attr"
1134    },{
1135    "name": "Usage Details",
1136    "href": "http://ericportis.com/posts/2014/srcset-sizes/"
1137    }]
1138}
1139!*/
1140/* DOC
1141Test for the `sizes` attribute on images
1142*/
1143
1144  Modernizr.addAsyncTest(function() {
1145    var width1, width2, test;
1146    var image = createElement('img');
1147    // in a perfect world this would be the test...
1148    var isSizes = 'sizes' in image;
1149
1150    // ... but we need to deal with Safari 9...
1151    if (!isSizes && ('srcset' in  image)) {
1152      width2 = 'data:image/gif;base64,R0lGODlhAgABAPAAAP///wAAACH5BAAAAAAALAAAAAACAAEAAAICBAoAOw==';
1153      width1 = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
1154
1155      test = function() {
1156        addTest('sizes', image.width == 2);
1157      };
1158
1159      image.onload = test;
1160      image.onerror = test;
1161      image.setAttribute('sizes', '9px');
1162
1163      image.srcset = width1 + ' 1w,' + width2 + ' 8w';
1164      image.src = width1;
1165    } else {
1166      addTest('sizes', isSizes);
1167    }
1168  });
1169
1170/*!
1171{
1172  "name": "srcset attribute",
1173  "property": "srcset",
1174  "tags": ["image"],
1175  "notes": [{
1176    "name": "Smashing Magazine Article",
1177    "href": "https://en.wikipedia.org/wiki/APNG"
1178    },{
1179    "name": "Generate multi-resolution images for srcset with Grunt",
1180    "href": "https://addyosmani.com/blog/generate-multi-resolution-images-for-srcset-with-grunt/"
1181    }]
1182}
1183!*/
1184/* DOC
1185Test for the srcset attribute of images
1186*/
1187
1188  Modernizr.addTest('srcset', 'srcset' in createElement('img'));
1189
1190/*!
1191{
1192  "name": "[hidden] Attribute",
1193  "property": "hidden",
1194  "tags": ["dom"],
1195  "notes": [{
1196    "name": "WHATWG: The hidden attribute",
1197    "href": "https://developers.whatwg.org/editing.html#the-hidden-attribute"
1198  }, {
1199    "name": "original implementation of detect code",
1200    "href": "https://github.com/aFarkas/html5shiv/blob/bf4fcc4/src/html5shiv.js#L38"
1201  }],
1202  "polyfills": ["html5shiv"],
1203  "authors": ["Ron Waldon (@jokeyrhyme)"]
1204}
1205!*/
1206/* DOC
1207Does the browser support the HTML5 [hidden] attribute?
1208*/
1209
1210  Modernizr.addTest('hidden', 'hidden' in createElement('a'));
1211
1212
1213
1214  /**
1215   * contains checks to see if a string contains another string
1216   *
1217   * @access private
1218   * @function contains
1219   * @param {string} str - The string we want to check for substrings
1220   * @param {string} substr - The substring we want to search the first string for
1221   * @returns {boolean}
1222   */
1223
1224  function contains(str, substr) {
1225    return !!~('' + str).indexOf(substr);
1226  }
1227
1228  ;
1229/*!
1230{
1231  "name": "CSS HSLA Colors",
1232  "caniuse": "css3-colors",
1233  "property": "hsla",
1234  "tags": ["css"]
1235}
1236!*/
1237
1238  Modernizr.addTest('hsla', function() {
1239    var style = createElement('a').style;
1240    style.cssText = 'background-color:hsla(120,40%,100%,.5)';
1241    return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla');
1242  });
1243
1244/*!
1245{
1246  "name": "CSS Supports",
1247  "property": "supports",
1248  "caniuse": "css-featurequeries",
1249  "tags": ["css"],
1250  "builderAliases": ["css_supports"],
1251  "notes": [{
1252    "name": "W3 Spec",
1253    "href": "http://dev.w3.org/csswg/css3-conditional/#at-supports"
1254  },{
1255    "name": "Related Github Issue",
1256    "href": "https://github.com/Modernizr/Modernizr/issues/648"
1257  },{
1258    "name": "W3 Info",
1259    "href": "http://dev.w3.org/csswg/css3-conditional/#the-csssupportsrule-interface"
1260  }]
1261}
1262!*/
1263
1264  var newSyntax = 'CSS' in window && 'supports' in window.CSS;
1265  var oldSyntax = 'supportsCSS' in window;
1266  Modernizr.addTest('supports', newSyntax || oldSyntax);
1267
1268
1269  var cssomPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.split(' ') : []);
1270  ModernizrProto._cssomPrefixes = cssomPrefixes;
1271
1272
1273  /**
1274   * atRule returns a given CSS property at-rule (eg @keyframes), possibly in
1275   * some prefixed form, or false, in the case of an unsupported rule
1276   *
1277   * @memberof Modernizr
1278   * @name Modernizr.atRule
1279   * @optionName Modernizr.atRule()
1280   * @optionProp atRule
1281   * @access public
1282   * @function atRule
1283   * @param {string} prop - String name of the @-rule to test for
1284   * @returns {string|boolean} The string representing the (possibly prefixed)
1285   * valid version of the @-rule, or `false` when it is unsupported.
1286   * @example
1287   * ```js
1288   *  var keyframes = Modernizr.atRule('@keyframes');
1289   *
1290   *  if (keyframes) {
1291   *    // keyframes are supported
1292   *    // could be `@-webkit-keyframes` or `@keyframes`
1293   *  } else {
1294   *    // keyframes === `false`
1295   *  }
1296   * ```
1297   *
1298   */
1299
1300  var atRule = function(prop) {
1301    var length = prefixes.length;
1302    var cssrule = window.CSSRule;
1303    var rule;
1304
1305    if (typeof cssrule === 'undefined') {
1306      return undefined;
1307    }
1308
1309    if (!prop) {
1310      return false;
1311    }
1312
1313    // remove literal @ from beginning of provided property
1314    prop = prop.replace(/^@/, '');
1315
1316    // CSSRules use underscores instead of dashes
1317    rule = prop.replace(/-/g, '_').toUpperCase() + '_RULE';
1318
1319    if (rule in cssrule) {
1320      return '@' + prop;
1321    }
1322
1323    for (var i = 0; i < length; i++) {
1324      // prefixes gives us something like -o-, and we want O_
1325      var prefix = prefixes[i];
1326      var thisRule = prefix.toUpperCase() + '_' + rule;
1327
1328      if (thisRule in cssrule) {
1329        return '@-' + prefix.toLowerCase() + '-' + prop;
1330      }
1331    }
1332
1333    return false;
1334  };
1335
1336  ModernizrProto.atRule = atRule;
1337
1338
1339
1340  /**
1341   * getBody returns the body of a document, or an element that can stand in for
1342   * the body if a real body does not exist
1343   *
1344   * @access private
1345   * @function getBody
1346   * @returns {HTMLElement|SVGElement} Returns the real body of a document, or an
1347   * artificially created element that stands in for the body
1348   */
1349
1350  function getBody() {
1351    // After page load injecting a fake body doesn't work so check if body exists
1352    var body = document.body;
1353
1354    if (!body) {
1355      // Can't use the real body create a fake one.
1356      body = createElement(isSVG ? 'svg' : 'body');
1357      body.fake = true;
1358    }
1359
1360    return body;
1361  }
1362
1363  ;
1364
1365  /**
1366   * injectElementWithStyles injects an element with style element and some CSS rules
1367   *
1368   * @access private
1369   * @function injectElementWithStyles
1370   * @param {string} rule - String representing a css rule
1371   * @param {function} callback - A function that is used to test the injected element
1372   * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
1373   * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
1374   * @returns {boolean}
1375   */
1376
1377  function injectElementWithStyles(rule, callback, nodes, testnames) {
1378    var mod = 'modernizr';
1379    var style;
1380    var ret;
1381    var node;
1382    var docOverflow;
1383    var div = createElement('div');
1384    var body = getBody();
1385
1386    if (parseInt(nodes, 10)) {
1387      // In order not to give false positives we create a node for each test
1388      // This also allows the method to scale for unspecified uses
1389      while (nodes--) {
1390        node = createElement('div');
1391        node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
1392        div.appendChild(node);
1393      }
1394    }
1395
1396    style = createElement('style');
1397    style.type = 'text/css';
1398    style.id = 's' + mod;
1399
1400    // 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.
1401    // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
1402    (!body.fake ? div : body).appendChild(style);
1403    body.appendChild(div);
1404
1405    if (style.styleSheet) {
1406      style.styleSheet.cssText = rule;
1407    } else {
1408      style.appendChild(document.createTextNode(rule));
1409    }
1410    div.id = mod;
1411
1412    if (body.fake) {
1413      //avoid crashing IE8, if background image is used
1414      body.style.background = '';
1415      //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
1416      body.style.overflow = 'hidden';
1417      docOverflow = docElement.style.overflow;
1418      docElement.style.overflow = 'hidden';
1419      docElement.appendChild(body);
1420    }
1421
1422    ret = callback(div, rule);
1423    // If this is done after page load we don't want to remove the body so check if body exists
1424    if (body.fake) {
1425      body.parentNode.removeChild(body);
1426      docElement.style.overflow = docOverflow;
1427      // Trigger layout so kinetic scrolling isn't disabled in iOS6+
1428      // eslint-disable-next-line
1429      docElement.offsetHeight;
1430    } else {
1431      div.parentNode.removeChild(div);
1432    }
1433
1434    return !!ret;
1435
1436  }
1437
1438  ;
1439
1440  /**
1441   * Modernizr.mq tests a given media query, live against the current state of the window
1442   * adapted from matchMedia polyfill by Scott Jehl and Paul Irish
1443   * gist.github.com/786768
1444   *
1445   * @memberof Modernizr
1446   * @name Modernizr.mq
1447   * @optionName Modernizr.mq()
1448   * @optionProp mq
1449   * @access public
1450   * @function mq
1451   * @param {string} mq - String of the media query we want to test
1452   * @returns {boolean}
1453   * @example
1454   * Modernizr.mq allows for you to programmatically check if the current browser
1455   * window state matches a media query.
1456   *
1457   * ```js
1458   *  var query = Modernizr.mq('(min-width: 900px)');
1459   *
1460   *  if (query) {
1461   *    // the browser window is larger than 900px
1462   *  }
1463   * ```
1464   *
1465   * Only valid media queries are supported, therefore you must always include values
1466   * with your media query
1467   *
1468   * ```js
1469   * // good
1470   *  Modernizr.mq('(min-width: 900px)');
1471   *
1472   * // bad
1473   *  Modernizr.mq('min-width');
1474   * ```
1475   *
1476   * If you would just like to test that media queries are supported in general, use
1477   *
1478   * ```js
1479   *  Modernizr.mq('only all'); // true if MQ are supported, false if not
1480   * ```
1481   *
1482   *
1483   * Note that if the browser does not support media queries (e.g. old IE) mq will
1484   * always return false.
1485   */
1486
1487  var mq = (function() {
1488    var matchMedia = window.matchMedia || window.msMatchMedia;
1489    if (matchMedia) {
1490      return function(mq) {
1491        var mql = matchMedia(mq);
1492        return mql && mql.matches || false;
1493      };
1494    }
1495
1496    return function(mq) {
1497      var bool = false;
1498
1499      injectElementWithStyles('@media ' + mq + ' { #modernizr { position: absolute; } }', function(node) {
1500        bool = (window.getComputedStyle ?
1501                window.getComputedStyle(node, null) :
1502                node.currentStyle).position == 'absolute';
1503      });
1504
1505      return bool;
1506    };
1507  })();
1508
1509
1510  ModernizrProto.mq = mq;
1511
1512
1513/*!
1514{
1515  "name": "CSS Media Queries",
1516  "caniuse": "css-mediaqueries",
1517  "property": "mediaqueries",
1518  "tags": ["css"],
1519  "builderAliases": ["css_mediaqueries"]
1520}
1521!*/
1522
1523  Modernizr.addTest('mediaqueries', mq('only all'));
1524
1525
1526  /**
1527   * testStyles injects an element with style element and some CSS rules
1528   *
1529   * @memberof Modernizr
1530   * @name Modernizr.testStyles
1531   * @optionName Modernizr.testStyles()
1532   * @optionProp testStyles
1533   * @access public
1534   * @function testStyles
1535   * @param {string} rule - String representing a css rule
1536   * @param {function} callback - A function that is used to test the injected element
1537   * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
1538   * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
1539   * @returns {boolean}
1540   * @example
1541   *
1542   * `Modernizr.testStyles` takes a CSS rule and injects it onto the current page
1543   * along with (possibly multiple) DOM elements. This lets you check for features
1544   * 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).
1545   *
1546   * ```js
1547   * Modernizr.testStyles('#modernizr { width: 9px; color: papayawhip; }', function(elem, rule) {
1548   *   // elem is the first DOM node in the page (by default #modernizr)
1549   *   // rule is the first argument you supplied - the CSS rule in string form
1550   *
1551   *   addTest('widthworks', elem.style.width === '9px')
1552   * });
1553   * ```
1554   *
1555   * If your test requires multiple nodes, you can include a third argument
1556   * indicating how many additional div elements to include on the page. The
1557   * additional nodes are injected as children of the `elem` that is returned as
1558   * the first argument to the callback.
1559   *
1560   * ```js
1561   * Modernizr.testStyles('#modernizr {width: 1px}; #modernizr2 {width: 2px}', function(elem) {
1562   *   document.getElementById('modernizr').style.width === '1px'; // true
1563   *   document.getElementById('modernizr2').style.width === '2px'; // true
1564   *   elem.firstChild === document.getElementById('modernizr2'); // true
1565   * }, 1);
1566   * ```
1567   *
1568   * By default, all of the additional elements have an ID of `modernizr[n]`, where
1569   * `n` is its index (e.g. the first additional, second overall is `#modernizr2`,
1570   * the second additional is `#modernizr3`, etc.).
1571   * If you want to have more meaningful IDs for your function, you can provide
1572   * them as the fourth argument, as an array of strings
1573   *
1574   * ```js
1575   * Modernizr.testStyles('#foo {width: 10px}; #bar {height: 20px}', function(elem) {
1576   *   elem.firstChild === document.getElementById('foo'); // true
1577   *   elem.lastChild === document.getElementById('bar'); // true
1578   * }, 2, ['foo', 'bar']);
1579   * ```
1580   *
1581   */
1582
1583  var testStyles = ModernizrProto.testStyles = injectElementWithStyles;
1584
1585/*!
1586{
1587  "name": "Touch Events",
1588  "property": "touchevents",
1589  "caniuse" : "touch",
1590  "tags": ["media", "attribute"],
1591  "notes": [{
1592    "name": "Touch Events spec",
1593    "href": "https://www.w3.org/TR/2013/WD-touch-events-20130124/"
1594  }],
1595  "warnings": [
1596    "Indicates if the browser supports the Touch Events spec, and does not necessarily reflect a touchscreen device"
1597  ],
1598  "knownBugs": [
1599    "False-positive on some configurations of Nokia N900",
1600    "False-positive on some BlackBerry 6.0 builds – https://github.com/Modernizr/Modernizr/issues/372#issuecomment-3112695"
1601  ]
1602}
1603!*/
1604/* DOC
1605Indicates if the browser supports the W3C Touch Events API.
1606
1607This *does not* necessarily reflect a touchscreen device:
1608
1609* Older touchscreen devices only emulate mouse events
1610* Modern IE touch devices implement the Pointer Events API instead: use `Modernizr.pointerevents` to detect support for that
1611* Some browsers & OS setups may enable touch APIs when no touchscreen is connected
1612* Future browsers may implement other event models for touch interactions
1613
1614See this article: [You Can't Detect A Touchscreen](http://www.stucox.com/blog/you-cant-detect-a-touchscreen/).
1615
1616It's recommended to bind both mouse and touch/pointer events simultaneously – see [this HTML5 Rocks tutorial](http://www.html5rocks.com/en/mobile/touchandmouse/).
1617
1618This test will also return `true` for Firefox 4 Multitouch support.
1619*/
1620
1621  // Chrome (desktop) used to lie about its support on this, but that has since been rectified: http://crbug.com/36415
1622  Modernizr.addTest('touchevents', function() {
1623    var bool;
1624    if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
1625      bool = true;
1626    } else {
1627      // include the 'heartz' as a way to have a non matching MQ to help terminate the join
1628      // https://git.io/vznFH
1629      var query = ['@media (', prefixes.join('touch-enabled),('), 'heartz', ')', '{#modernizr{top:9px;position:absolute}}'].join('');
1630      testStyles(query, function(node) {
1631        bool = node.offsetTop === 9;
1632      });
1633    }
1634    return bool;
1635  });
1636
1637/*!
1638{
1639  "name": "@font-face",
1640  "property": "fontface",
1641  "authors": ["Diego Perini", "Mat Marquis"],
1642  "tags": ["css"],
1643  "knownBugs": [
1644    "False Positive: WebOS https://github.com/Modernizr/Modernizr/issues/342",
1645    "False Postive: WP7 https://github.com/Modernizr/Modernizr/issues/538"
1646  ],
1647  "notes": [{
1648    "name": "@font-face detection routine by Diego Perini",
1649    "href": "http://javascript.nwbox.com/CSSSupport/"
1650  },{
1651    "name": "Filament Group @font-face compatibility research",
1652    "href": "https://docs.google.com/presentation/d/1n4NyG4uPRjAA8zn_pSQ_
1652Ket0RhcWC6QlZ6LMjKeECo0/edit#slide=id.p"
1653  },{
1654    "name": "Filament Grunticon/@font-face device testing results",
1655    "href": "https://docs.google.com/spreadsheet/ccc?key=0Ag5_yGvxpINRdHFYeUJPNnZMWUZKR2ItMEpRTXZPdUE#gid=0"
1656  },{
1657    "name": "CSS fonts on Android",
1658    "href": "https://stackoverflow.com/questions/3200069/css-fonts-on-android"
1659  },{
1660    "name": "@font-face and Android",
1661    "href": "http://archivist.incutio.com/viewlist/css-discuss/115960"
1662  }]
1663}
1664!*/
1665
1666  var blacklist = (function() {
1667    var ua = navigator.userAgent;
1668    var webos = ua.match(/w(eb)?osbrowser/gi);
1669    var wppre8 = ua.match(/windows phone/gi) && ua.match(/iemobile\/([0-9])+/gi) && parseFloat(RegExp.$1) >= 9;
1670    return webos || wppre8;
1671  }());
1672  if (blacklist) {
1673    Modernizr.addTest('fontface', false);
1674  } else {
1675    testStyles('@font-face {font-family:"font";src:url("https://")}', function(node, rule) {
1676      var style = document.getElementById('smodernizr');
1677      var sheet = style.sheet || style.styleSheet;
1678      var cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : '';
1679      var bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0;
1680      Modernizr.addTest('fontface', bool);
1681    });
1682  }
1683;
1684
1685  /**
1686   * fnBind is a super small [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) polyfill.
1687   *
1688   * @access private
1689   * @function fnBind
1690   * @param {function} fn - a function you want to change `this` reference to
1691   * @param {object} that - the `this` you want to call the function with
1692   * @returns {function} The wrapped version of the supplied function
1693   */
1694
1695  function fnBind(fn, that) {
1696    return function() {
1697      return fn.apply(that, arguments);
1698    };
1699  }
1700
1701  ;
1702
1703  /**
1704   * testDOMProps is a generic DOM property test; if a browser supports
1705   *   a certain property, it won't return undefined for it.
1706   *
1707   * @access private
1708   * @function testDOMProps
1709   * @param {array.<string>} props - An array of properties to test for
1710   * @param {object} obj - An object or Element you want to use to test the parameters again
1711   * @param {boolean|object} elem - An Element to bind the property lookup again. Use `false` to prevent the check
1712   * @returns {false|*} returns false if the prop is unsupported, otherwise the value that is supported
1713   */
1714  function testDOMProps(props, obj, elem) {
1715    var item;
1716
1717    for (var i in props) {
1718      if (props[i] in obj) {
1719
1720        // return the property name as a string
1721        if (elem === false) {
1722          return props[i];
1723        }
1724
1725        item = obj[props[i]];
1726
1727        // let's bind a function
1728        if (is(item, 'function')) {
1729          // bind to obj unless overriden
1730          return fnBind(item, elem || obj);
1731        }
1732
1733        // return the unbound function or obj or value
1734        return item;
1735      }
1736    }
1737    return false;
1738  }
1739
1740  ;
1741
1742  /**
1743   * Create our "modernizr" element that we do most feature tests on.
1744   *
1745   * @access private
1746   */
1747
1748  var modElem = {
1749    elem: createElement('modernizr')
1750  };
1751
1752  // Clean up this element
1753  Modernizr._q.push(function() {
1754    delete modElem.elem;
1755  });
1756
1757
1758
1759  var mStyle = {
1760    style: modElem.elem.style
1761  };
1762
1763  // kill ref for gc, must happen before mod.elem is removed, so we unshift on to
1764  // the front of the queue.
1765  Modernizr._q.unshift(function() {
1766    delete mStyle.style;
1767  });
1768
1769
1770
1771  /**
1772   * domToCSS takes a camelCase string and converts it to kebab-case
1773   * e.g. boxSizing -> box-sizing
1774   *
1775   * @access private
1776   * @function domToCSS
1777   * @param {string} name - String name of camelCase prop we want to convert
1778   * @returns {string} The kebab-case version of the supplied name
1779   */
1780
1781  function domToCSS(name) {
1782    return name.replace(/([A-Z])/g, function(str, m1) {
1783      return '-' + m1.toLowerCase();
1784    }).replace(/^ms-/, '-ms-');
1785  }
1786  ;
1787
1788
1789  /**
1790   * wrapper around getComputedStyle, to fix issues with Firefox returning null when
1791   * called inside of a hidden iframe
1792   *
1793   * @access private
1794   * @function computedStyle
1795   * @param {HTMLElement|SVGElement} - The element we want to find the computed styles of
1796   * @param {string|null} [pseudoSelector]- An optional pseudo element selector (e.g. :before), of null if none
1797   * @returns {CSSStyleDeclaration}
1798   */
1799
1800  function computedStyle(elem, pseudo, prop) {
1801    var result;
1802
1803    if ('getComputedStyle' in window) {
1804      result = getComputedStyle.call(window, elem, pseudo);
1805      var console = window.console;
1806
1807      if (result !== null) {
1808        if (prop) {
1809          result = result.getPropertyValue(prop);
1810        }
1811      } else {
1812        if (console) {
1813          var method = console.error ? 'error' : 'log';
1814          console[method].call(console, 'getComputedStyle returning null, its possible modernizr test results are inaccurate');
1815        }
1816      }
1817    } else {
1818      result = !pseudo && elem.currentStyle && elem.currentStyle[prop];
1819    }
1820
1821    return result;
1822  }
1823
1824  ;
1825
1826  /**
1827   * nativeTestProps allows for us to use native feature detection functionality if available.
1828   * some prefixed form, or false, in the case of an unsupported rule
1829   *
1830   * @access private
1831   * @function nativeTestProps
1832   * @param {array} props - An array of property names
1833   * @param {string} value - A string representing the value we want to check via @supports
1834   * @returns {boolean|undefined} A boolean when @supports exists, undefined otherwise
1835   */
1836
1837  // Accepts a list of property names and a single value
1838  // Returns `undefined` if native detection not available
1839  function nativeTestProps(props, value) {
1840    var i = props.length;
1841    // Start with the JS API: http://www.w3.org/TR/css3-conditional/#the-css-interface
1842    if ('CSS' in window && 'supports' in window.CSS) {
1843      // Try every prefixed variant of the property
1844      while (i--) {
1845        if (window.CSS.supports(domToCSS(props[i]), value)) {
1846          return true;
1847        }
1848      }
1849      return false;
1850    }
1851    // Otherwise fall back to at-rule (for Opera 12.x)
1852    else if ('CSSSupportsRule' in window) {
1853      // Build a condition string for every prefixed variant
1854      var conditionText = [];
1855      while (i--) {
1856        conditionText.push('(' + domToCSS(props[i]) + ':' + value + ')');
1857      }
1858      conditionText = conditionText.join(' or ');
1859      return injectElementWithStyles('@supports (' + conditionText + ') { #modernizr { position: absolute; } }', function(node) {
1860        return computedStyle(node, null, 'position') == 'absolute';
1861      });
1862    }
1863    return undefined;
1864  }
1865  ;
1866
1867  // testProps is a generic CSS / DOM property test.
1868
1869  // In testing support for a given CSS property, it's legit to test:
1870  //    `elem.style[styleName] !== undefined`
1871  // If the property is supported it will return an empty string,
1872  // if unsupported it will return undefined.
1873
1874  // We'll take advantage of this quick test and skip setting a style
1875  // on our modernizr element, but instead just testing undefined vs
1876  // empty string.
1877
1878  // Property names can be provided in either camelCase or kebab-case.
1879
1880  function testProps(props, prefixed, value, skipValueTest) {
1881    skipValueTest = is(skipValueTest, 'undefined') ? false : skipValueTest;
1882
1883    // Try native detect first
1884    if (!is(value, 'undefined')) {
1885      var result = nativeTestProps(props, value);
1886      if (!is(result, 'undefined')) {
1887        return result;
1888      }
1889    }
1890
1891    // Otherwise do it properly
1892    var afterInit, i, propsLength, prop, before;
1893
1894    // If we don't have a style element, that means we're running async or after
1895    // the core tests, so we'll need to create our own elements to use
1896
1897    // inside of an SVG element, in certain browsers, the `style` element is only
1898    // defined for valid tags. Therefore, if `modernizr` does not have one, we
1899    // fall back to a less used element and hope for the best.
1900    // for strict XHTML browsers the hardly used samp element is used
1901    var elems = ['modernizr', 'tspan', 'samp'];
1902    while (!mStyle.style && elems.length) {
1903      afterInit = true;
1904      mStyle.modElem = createElement(elems.shift());
1905      mStyle.style = mStyle.modElem.style;
1906    }
1907
1908    // Delete the objects if we created them.
1909    function cleanElems() {
1910      if (afterInit) {
1911        delete mStyle.style;
1912        delete mStyle.modElem;
1913      }
1914    }
1915
1916    propsLength = props.length;
1917    for (i = 0; i < propsLength; i++) {
1918      prop = props[i];
1919      before = mStyle.style[prop];
1920
1921      if (contains(prop, '-')) {
1922        prop = cssToDOM(prop);
1923      }
1924
1925      if (mStyle.style[prop] !== undefined) {
1926
1927        // If value to test has been passed in, do a set-and-check test.
1928        // 0 (integer) is a valid property value, so check that `value` isn't
1929        // undefined, rather than just checking it's truthy.
1930        if (!skipValueTest && !is(value, 'undefined')) {
1931
1932          // Needs a try catch block because of old IE. This is slow, but will
1933          // be avoided in most cases because `skipValueTest` will be used.
1934          try {
1935            mStyle.style[prop] = value;
1936          } catch (e) {}
1937
1938          // If the property value has changed, we assume the value used is
1939          // supported. If `value` is empty string, it'll fail here (because
1940          // it hasn't changed), which matches how browsers have implemented
1941          // CSS.supports()
1942          if (mStyle.style[prop] != before) {
1943            cleanElems();
1944            return prefixed == 'pfx' ? prop : true;
1945          }
1946        }
1947        // Otherwise just return true, or the property name if this is a
1948        // `prefixed()` call
1949        else {
1950          cleanElems();
1951          return prefixed == 'pfx' ? prop : true;
1952        }
1953      }
1954    }
1955    cleanElems();
1956    return false;
1957  }
1958
1959  ;
1960
1961  /**
1962   * testProp() investigates whether a given style property is recognized
1963   * Property names can be provided in either camelCase or kebab-case.
1964   *
1965   * @memberof Modernizr
1966   * @name Modernizr.testProp
1967   * @access public
1968   * @optionName Modernizr.testProp()
1969   * @optionProp testProp
1970   * @function testProp
1971   * @param {string} prop - Name of the CSS property to check
1972   * @param {string} [value] - Name of the CSS value to check
1973   * @param {boolean} [useValue] - Whether or not to check the value if @supports isn't supported
1974   * @returns {boolean}
1975   * @example
1976   *
1977   * Just like [testAllProps](#modernizr-testallprops), only it does not check any vendor prefixed
1978   * version of the string.
1979   *
1980   * Note that the property name must be provided in camelCase (e.g. boxSizing not box-sizing)
1981   *
1982   * ```js
1983   * Modernizr.testProp('pointerEvents')  // true
1984   * ```
1985   *
1986   * You can also provide a value as an optional second argument to check if a
1987   * specific value is supported
1988   *
1989   * ```js
1990   * Modernizr.testProp('pointerEvents', 'none') // true
1991   * Modernizr.testProp('pointerEvents', 'penguin') // false
1992   * ```
1993   */
1994
1995  var testProp = ModernizrProto.testProp = function(prop, value, useValue) {
1996    return testProps([prop], undefined, value, useValue);
1997  };
1998
1999
2000  /**
2001   * testPropsAll tests a list of DOM properties we want to check against.
2002   * We specify literally ALL possible (known and/or likely) properties on
2003   * the element including the non-vendor prefixed one, for forward-
2004   * compatibility.
2005   *
2006   * @access private
2007   * @function testPropsAll
2008   * @param {string} prop - A string of the property to test for
2009   * @param {string|object} [prefixed] - An object to check the prefixed properties on. Use a string to skip
2010   * @param {HTMLElement|SVGElement} [elem] - An element used to test the property and value against
2011   * @param {string} [value] - A string of a css value
2012   * @param {boolean} [skipValueTest] - An boolean representing if you want to test if value sticks when set
2013   * @returns {false|string} returns the string version of the property, or false if it is unsupported
2014   */
2015  function testPropsAll(prop, prefixed, elem, value, skipValueTest) {
2016
2017    var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
2018      props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
2019
2020    // did they call .prefixed('boxSizing') or are we just testing a prop?
2021    if (is(prefixed, 'string') || is(prefixed, 'undefined')) {
2022      return testProps(props, prefixed, value, skipValueTest);
2023
2024      // otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
2025    } else {
2026      props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
2027      return testDOMProps(props, prefixed, elem);
2028    }
2029  }
2030
2031  // Modernizr.testAllProps() investigates whether a given style property,
2032  // or any of its vendor-prefixed variants, is recognized
2033  //
2034  // Note that the property names must be provided in the camelCase variant.
2035  // Modernizr.testAllProps('boxSizing')
2036  ModernizrProto.testAllProps = testPropsAll;
2037
2038
2039
2040  /**
2041   * prefixed returns the prefixed or nonprefixed property name variant of your input
2042   *
2043   * @memberof Modernizr
2044   * @name Modernizr.prefixed
2045   * @optionName Modernizr.prefixed()
2046   * @optionProp prefixed
2047   * @access public
2048   * @function prefixed
2049   * @param {string} prop - String name of the property to test for
2050   * @param {object} [obj] - An object to test for the prefixed properties on
2051   * @param {HTMLElement} [elem] - An element used to test specific properties against
2052   * @returns {string|false} The string representing the (possibly prefixed) valid
2053   * version of the property, or `false` when it is unsupported.
2054   * @example
2055   *
2056   * Modernizr.prefixed takes a string css value in the DOM style camelCase (as
2057   * opposed to the css style kebab-case) form and returns the (possibly prefixed)
2058   * version of that property that the browser actually supports.
2059   *
2060   * For example, in older Firefox...
2061   * ```js
2062   * prefixed('boxSizing')
2063   * ```
2064   * returns 'MozBoxSizing'
2065   *
2066   * In newer Firefox, as well as any other browser that support the unprefixed
2067   * version would simply return `boxSizing`. Any browser that does not support
2068   * the property at all, it will return `false`.
2069   *
2070   * By default, prefixed is checked against a DOM element. If you want to check
2071   * for a property on another object, just pass it as a second argument
2072   *
2073   * ```js
2074   * var rAF = prefixed('requestAnimationFrame', window);
2075   *
2076   * raf(function() {
2077   *  renderFunction();
2078   * })
2079   * ```
2080   *
2081   * Note that this will return _the actual function_ - not the name of the function.
2082   * If you need the actual name of the property, pass in `false` as a third argument
2083   *
2084   * ```js
2085   * var rAFProp = prefixed('requestAnimationFrame', window, false);
2086   *
2087   * rafProp === 'WebkitRequestAnimationFrame' // in older webkit
2088   * ```
2089   *
2090   * One common use case for prefixed is if you're trying to determine which transition
2091   * end event to bind to, you might do something like...
2092   * ```js
2093   * var transEndEventNames = {
2094   *     'WebkitTransition' : 'webkitTransitionEnd', * Saf 6, Android Browser
2095   *     'MozTransition'    : 'transitionend',       * only for FF < 15
2096   *     'transition'       : 'transitionend'        * IE10, Opera, Chrome, FF 15+, Saf 7+
2097   * };
2098   *
2099   * var transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
2100   * ```
2101   *
2102   * If you want a similar lookup, but in kebab-case, you can use [prefixedCSS](#modernizr-prefixedcss).
2103   */
2104
2105  var prefixed = ModernizrProto.prefixed = function(prop, obj, elem) {
2106    if (prop.indexOf('@') === 0) {
2107      return atRule(prop);
2108    }
2109
2110    if (prop.indexOf('-') != -1) {
2111      // Convert kebab-case to camelCase
2112      prop = cssToDOM(prop);
2113    }
2114    if (!obj) {
2115      return testPropsAll(prop, 'pfx');
2116    } else {
2117      // Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame'
2118      return testPropsAll(prop, obj, elem);
2119    }
2120  };
2121
2122
2123/*!
2124{
2125  "name": "CSS Object Fit",
2126  "caniuse": "object-fit",
2127  "property": "objectfit",
2128  "tags": ["css"],
2129  "builderAliases": ["css_objectfit"],
2130  "notes": [{
2131    "name": "Opera Article on Object Fit",
2132    "href": "https://dev.opera.com/articles/css3-object-fit-object-position/"
2133  }]
2134}
2135!*/
2136
2137  Modernizr.addTest('objectfit', !!prefixed('objectFit'), {aliases: ['object-fit']});
2138
2139
2140  /**
2141   * testAllProps determines whether a given CSS property is supported in the browser
2142   *
2143   * @memberof Modernizr
2144   * @name Modernizr.testAllProps
2145   * @optionName Modernizr.testAllProps()
2146   * @optionProp testAllProps
2147   * @access public
2148   * @function testAllProps
2149   * @param {string} prop - String naming the property to test (either camelCase or kebab-case)
2150   * @param {string} [value] - String of the value to test
2151   * @param {boolean} [skipValueTest=false] - Whether to skip testing that the value is supported when using non-native detection
2152   * @example
2153   *
2154   * testAllProps determines whether a given CSS property, in some prefixed form,
2155   * is supported by the browser.
2156   *
2157   * ```js
2158   * testAllProps('boxSizing')  // true
2159   * ```
2160   *
2161   * It can optionally be given a CSS value in string form to test if a property
2162   * value is valid
2163   *
2164   * ```js
2165   * testAllProps('display', 'block') // true
2166   * testAllProps('display', 'penguin') // false
2167   * ```
2168   *
2169   * A boolean can be passed as a third parameter to skip the value check when
2170   * native detection (@supports) isn't available.
2171   *
2172   * ```js
2173   * testAllProps('shapeOutside', 'content-box', true);
2174   * ```
2175   */
2176
2177  function testAllProps(prop, value, skipValueTest) {
2178    return testPropsAll(prop, undefined, undefined, value, skipValueTest);
2179  }
2180  ModernizrProto.testAllProps = testAllProps;
2181
2182/*!
2183{
2184  "name": "CSS Animations",
2185  "property": "cssanimations",
2186  "caniuse": "css-animation",
2187  "polyfills": ["transformie", "csssandpaper"],
2188  "tags": ["css"],
2189  "warnings": ["Android < 4 will pass this test, but can only animate a single property at a time"],
2190  "notes": [{
2191    "name" : "Article: 'Dispelling the Android CSS animation myths'",
2192    "href": "https://goo.gl/OGw5Gm"
2193  }]
2194}
2195!*/
2196/* DOC
2197Detects whether or not elements can be animated using CSS
2198*/
2199
2200  Modernizr.addTest('cssanimations', testAllProps('animationName', 'a', true));
2201
2202/*!
2203{
2204  "name": "Flexbox",
2205  "property": "flexbox",
2206  "caniuse": "flexbox",
2207  "tags": ["css"],
2208  "notes": [{
2209    "name": "The _new_ flexbox",
2210    "href": "http://dev.w3.org/csswg/css3-flexbox"
2211  }],
2212  "warnings": [
2213    "A `true` result for this detect does not imply that the `flex-wrap` property is supported; see the `flexwrap` detect."
2214  ]
2215}
2216!*/
2217/* DOC
2218Detects support for the Flexible Box Layout model, a.k.a. Flexbox, which allows easy manipulation of layout order and sizing within a container.
2219*/
2220
2221  Modernizr.addTest('flexbox', testAllProps('flexBasis', '1px', true));
2222
2223/*!
2224{
2225  "name": "CSS Transforms",
2226  "property": "csstransforms",
2227  "caniuse": "transforms2d",
2228  "tags": ["css"]
2229}
2230!*/
2231
2232  Modernizr.addTest('csstransforms', function() {
2233    // Android < 3.0 is buggy, so we sniff and blacklist
2234    // http://git.io/hHzL7w
2235    return navigator.userAgent.indexOf('Android 2.') === -1 &&
2236           testAllProps('transform', 'scale(1)', true);
2237  });
2238
2239/*!
2240{
2241  "name": "CSS Transforms 3D",
2242  "property": "csstransforms3d",
2243  "caniuse": "transforms3d",
2244  "tags": ["css"],
2245  "warnings": [
2246    "Chrome may occassionally fail this test on some systems; more info: https://code.google.com/p/chromium/issues/detail?id=129004"
2247  ]
2248}
2249!*/
2250
2251  Modernizr.addTest('csstransforms3d', function() {
2252    return !!testAllProps('perspective', '1px', true);
2253  });
2254
2255/*!
2256{
2257  "name": "CSS Transitions",
2258  "property": "csstransitions",
2259  "caniuse": "css-transitions",
2260  "tags": ["css"]
2261}
2262!*/
2263
2264  Modernizr.addTest('csstransitions', testAllProps('transition', 'all', true));
2265
2266
2267  // Run each test
2268  testRunner();
2269
2270  // Remove the "no-js" class if it exists
2271  setClasses(classes);
2272
2273  delete ModernizrProto.addTest;
2274  delete ModernizrProto.addAsyncTest;
2275
2276  // Run the things that are supposed to run after the tests
2277  for (var i = 0; i < Modernizr._q.length; i++) {
2278    Modernizr._q[i]();
2279  }
2280
2281  // Leak Modernizr namespace
2282  window.Modernizr = Modernizr;
2283
2284
2285;
2286
2287})(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.